⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wm9705.c

📁 Wolfson9712和Wolfson9705的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
   1 /*

   2  * wm9705.c  --  ALSA Soc WM9705 codec support

   3  *

   4  * Copyright 2008 Ian Molton <spyro@f2s.com>

   5  *

   6  *  This program is free software; you can redistribute  it and/or modify it

   7  *  under  the terms of  the GNU General  Public License as published by the

   8  *  Free Software Foundation; Version 2 of the  License only.

   9  *

  10  */

  11 

  12 #include <linux/init.h>

  13 #include <linux/module.h>

  14 #include <linux/kernel.h>

  15 #include <linux/device.h>

  16 #include <sound/core.h>

  17 #include <sound/pcm.h>

  18 #include <sound/ac97_codec.h>

  19 #include <sound/initval.h>

  20 #include <sound/soc.h>

  21 #include <sound/soc-dapm.h>

  22 

  23 #include "wm9705.h"

  24 

  25 /*

  26  * WM9705 register cache

  27  */

  28 static const u16 wm9705_reg[] = {

  29         0x6150, 0x8000, 0x8000, 0x8000, /* 0x0  */

  30         0x0000, 0x8000, 0x8008, 0x8008, /* 0x8  */

  31         0x8808, 0x8808, 0x8808, 0x8808, /* 0x10 */

  32         0x8808, 0x0000, 0x8000, 0x0000, /* 0x18 */

  33         0x0000, 0x0000, 0x0000, 0x000f, /* 0x20 */

  34         0x0605, 0x0000, 0xbb80, 0x0000, /* 0x28 */

  35         0x0000, 0xbb80, 0x0000, 0x0000, /* 0x30 */

  36         0x0000, 0x2000, 0x0000, 0x0000, /* 0x38 */

  37         0x0000, 0x0000, 0x0000, 0x0000, /* 0x40 */

  38         0x0000, 0x0000, 0x0000, 0x0000, /* 0x48 */

  39         0x0000, 0x0000, 0x0000, 0x0000, /* 0x50 */

  40         0x0000, 0x0000, 0x0000, 0x0000, /* 0x58 */

  41         0x0000, 0x0000, 0x0000, 0x0000, /* 0x60 */

  42         0x0000, 0x0000, 0x0000, 0x0000, /* 0x68 */

  43         0x0000, 0x0808, 0x0000, 0x0006, /* 0x70 */

  44         0x0000, 0x0000, 0x574d, 0x4c05, /* 0x78 */

  45 };

  46 

  47 static const struct snd_kcontrol_new wm9705_snd_ac97_controls[] = {

  48         SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),

  49         SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1),

  50         SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),

  51         SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),

  52         SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),

  53         SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1),

  54         SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),

  55         SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),

  56         SOC_SINGLE("PCBeep Playback Volume", AC97_PC_BEEP, 1, 15, 1),

  57         SOC_SINGLE("Phone Playback Volume", AC97_PHONE, 0, 31, 1),

  58         SOC_DOUBLE("Line Playback Volume", AC97_LINE, 8, 0, 31, 1),

  59         SOC_DOUBLE("CD Playback Volume", AC97_CD, 8, 0, 31, 1),

  60         SOC_SINGLE("Mic Playback Volume", AC97_MIC, 0, 31, 1),

  61         SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 6, 1, 0),

  62         SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0),

  63         SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),

  64 };

  65 

  66 static const char *wm9705_mic[] = {"Mic 1", "Mic 2"};

  67 static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC",

  68         "Line", "Stereo Mix", "Mono Mix", "Phone"};

  69 

  70 static const struct soc_enum wm9705_enum_mic =

  71         SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic);

  72 static const struct soc_enum wm9705_enum_rec_l =

  73         SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel);

  74 static const struct soc_enum wm9705_enum_rec_r =

  75         SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel);

  76 

  77 /* Headphone Mixer */

  78 static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = {

  79         SOC_DAPM_SINGLE("PCBeep Playback Switch", AC97_PC_BEEP, 15, 1, 1),

  80         SOC_DAPM_SINGLE("CD Playback Switch", AC97_CD, 15, 1, 1),

  81         SOC_DAPM_SINGLE("Mic Playback Switch", AC97_MIC, 15, 1, 1),

  82         SOC_DAPM_SINGLE("Phone Playback Switch", AC97_PHONE, 15, 1, 1),

  83         SOC_DAPM_SINGLE("Line Playback Switch", AC97_LINE, 15, 1, 1),

  84 };

  85 

  86 /* Mic source */

  87 static const struct snd_kcontrol_new wm9705_mic_src_controls =

  88         SOC_DAPM_ENUM("Route", wm9705_enum_mic);

  89 

  90 /* Capture source */

  91 static const struct snd_kcontrol_new wm9705_capture_selectl_controls =

  92         SOC_DAPM_ENUM("Route", wm9705_enum_rec_l);

  93 static const struct snd_kcontrol_new wm9705_capture_selectr_controls =

  94         SOC_DAPM_ENUM("Route", wm9705_enum_rec_r);

  95 

  96 /* DAPM widgets */

  97 static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = {

  98         SND_SOC_DAPM_MUX("Mic Source", SND_SOC_NOPM, 0, 0,

  99                 &wm9705_mic_src_controls),

 100         SND_SOC_DAPM_MUX("Left Capture Source", SND_SOC_NOPM, 0, 0,

 101                 &wm9705_capture_selectl_controls),

 102         SND_SOC_DAPM_MUX("Right Capture Source", SND_SOC_NOPM, 0, 0,

 103                 &wm9705_capture_selectr_controls),

 104         SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",

 105                 SND_SOC_NOPM, 0, 0),

 106         SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",

 107                 SND_SOC_NOPM, 0, 0),

 108         SND_SOC_DAPM_MIXER_NAMED_CTL("HP Mixer", SND_SOC_NOPM, 0, 0,

 109                 &wm9705_hp_mixer_controls[0],

 110                 ARRAY_SIZE(wm9705_hp_mixer_controls)),

 111         SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),

 112         SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0),

 113         SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0),

 114         SND_SOC_DAPM_PGA("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 115         SND_SOC_DAPM_PGA("Speaker PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 116         SND_SOC_DAPM_PGA("Line PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 117         SND_SOC_DAPM_PGA("Line out PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 118         SND_SOC_DAPM_PGA("Mono PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 119         SND_SOC_DAPM_PGA("Phone PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 120         SND_SOC_DAPM_PGA("Mic PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 121         SND_SOC_DAPM_PGA("PCBEEP PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 122         SND_SOC_DAPM_PGA("CD PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 123         SND_SOC_DAPM_PGA("ADC PGA", SND_SOC_NOPM, 0, 0, NULL, 0),

 124         SND_SOC_DAPM_OUTPUT("HPOUTL"),

 125         SND_SOC_DAPM_OUTPUT("HPOUTR"),

 126         SND_SOC_DAPM_OUTPUT("LOUT"),

 127         SND_SOC_DAPM_OUTPUT("ROUT"),

 128         SND_SOC_DAPM_OUTPUT("MONOOUT"),

 129         SND_SOC_DAPM_INPUT("PHONE"),

 130         SND_SOC_DAPM_INPUT("LINEINL"),

 131         SND_SOC_DAPM_INPUT("LINEINR"),

 132         SND_SOC_DAPM_INPUT("CDINL"),

 133         SND_SOC_DAPM_INPUT("CDINR"),

 134         SND_SOC_DAPM_INPUT("PCBEEP"),

 135         SND_SOC_DAPM_INPUT("MIC1"),

 136         SND_SOC_DAPM_INPUT("MIC2"),

 137 };

 138 

 139 /* Audio map

 140  * WM9705 has no switches to disable the route from the inputs to the HP mixer

 141  * so in order to prevent active inputs from forcing the audio outputs to be

 142  * constantly enabled, we use the mutes on those inputs to simulate such

 143  * controls.

 144  */

 145 static const struct snd_soc_dapm_route audio_map[] = {

 146         /* HP mixer */

 147         {"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},

 148         {"HP Mixer", "CD Playback Switch", "CD PGA"},

 149         {"HP Mixer", "Mic Playback Switch", "Mic PGA"},

 150         {"HP Mixer", "Phone Playback Switch", "Phone PGA"},

 151         {"HP Mixer", "Line Playback Switch", "Line PGA"},

 152         {"HP Mixer", NULL, "Left DAC"},

 153         {"HP Mixer", NULL, "Right DAC"},

 154 

 155         /* mono mixer */

 156         {"Mono Mixer", NULL, "HP Mixer"},

 157 

 158         /* outputs */

 159         {"Headphone PGA", NULL, "HP Mixer"},

 160         {"HPOUTL", NULL, "Headphone PGA"},

 161         {"HPOUTR", NULL, "Headphone PGA"},

 162         {"Line out PGA", NULL, "HP Mixer"},

 163         {"LOUT", NULL, "Line out PGA"},

 164         {"ROUT", NULL, "Line out PGA"},

 165         {"Mono PGA", NULL, "Mono Mixer"},

 166         {"MONOOUT", NULL, "Mono PGA"},

 167 

 168         /* inputs */

 169         {"CD PGA", NULL, "CDINL"},

 170         {"CD PGA", NULL, "CDINR"},

 171         {"Line PGA", NULL, "LINEINL"},

 172         {"Line PGA", NULL, "LINEINR"},

 173         {"Phone PGA", NULL, "PHONE"},

 174         {"Mic Source", "Mic 1", "MIC1"},

 175         {"Mic Source", "Mic 2", "MIC2"},

 176         {"Mic PGA", NULL, "Mic Source"},

 177         {"PCBEEP PGA", NULL, "PCBEEP"},

 178 

 179         /* Left capture selector */

 180         {"Left Capture Source", "Mic", "Mic Source"},

 181         {"Left Capture Source", "CD", "CDINL"},

 182         {"Left Capture Source", "Line", "LINEINL"},

 183         {"Left Capture Source", "Stereo Mix", "HP Mixer"},

 184         {"Left Capture Source", "Mono Mix", "HP Mixer"},

 185         {"Left Capture Source", "Phone", "PHONE"},

 186 

 187         /* Right capture source */

 188         {"Right Capture Source", "Mic", "Mic Source"},

 189         {"Right Capture Source", "CD", "CDINR"},

 190         {"Right Capture Source", "Line", "LINEINR"},

 191         {"Right Capture Source", "Stereo Mix", "HP Mixer"},

 192         {"Right Capture Source", "Mono Mix", "HP Mixer"},

 193         {"Right Capture Source", "Phone", "PHONE"},

 194 

 195         {"ADC PGA", NULL, "Left Capture Source"},

 196         {"ADC PGA", NULL, "Right Capture Source"},

 197 

 198         /* ADC's */

 199         {"Left ADC",  NULL, "ADC PGA"},

 200         {"Right ADC", NULL, "ADC PGA"},

 201 };

 202 

 203 static int wm9705_add_widgets(struct snd_soc_codec *codec)

 204 {

 205         snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets,

 206                                         ARRAY_SIZE(wm9705_dapm_widgets));

 207         snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));

 208         snd_soc_dapm_new_widgets(codec);

 209 

 210         return 0;

 211 }

 212 

 213 /* We use a register cache to enhance read performance. */

 214 static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)

 215 {

 216         u16 *cache = codec->reg_cache;

 217 

 218         switch (reg) {

 219         case AC97_RESET:

 220         case AC97_VENDOR_ID1:

 221         case AC97_VENDOR_ID2:

 222                 return soc_ac97_ops.read(codec->ac97, reg);

 223         default:

 224                 reg = reg >> 1;

 225 

 226                 if (reg >= (ARRAY_SIZE(wm9705_reg)))

 227                         return -EIO;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -