aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c138
-rw-r--r--sound/soc/blackfin/Kconfig23
-rw-r--r--sound/soc/blackfin/Makefile6
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c10
-rw-r--r--sound/soc/blackfin/bf5xx-ad1938.c142
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c8
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c330
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.h21
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c343
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.h14
-rw-r--r--sound/soc/codecs/Kconfig20
-rw-r--r--sound/soc/codecs/Makefile14
-rw-r--r--sound/soc/codecs/ad1938.c668
-rw-r--r--sound/soc/codecs/ad1938.h100
-rw-r--r--sound/soc/codecs/cs4270.c27
-rw-r--r--sound/soc/codecs/cx20442.c501
-rw-r--r--sound/soc/codecs/cx20442.h20
-rw-r--r--sound/soc/codecs/max9877.c308
-rw-r--r--sound/soc/codecs/max9877.h37
-rw-r--r--sound/soc/codecs/spdif_transciever.c3
-rw-r--r--sound/soc/codecs/stac9766.c4
-rw-r--r--sound/soc/codecs/tlv320aic3x.c11
-rw-r--r--sound/soc/codecs/wm8400.c9
-rw-r--r--sound/soc/codecs/wm8510.c1
-rw-r--r--sound/soc/codecs/wm8731.c18
-rw-r--r--sound/soc/codecs/wm8753.c6
-rw-r--r--sound/soc/codecs/wm8776.c781
-rw-r--r--sound/soc/codecs/wm8776.h51
-rw-r--r--sound/soc/codecs/wm8993.c2206
-rw-r--r--sound/soc/codecs/wm8993.h2132
-rw-r--r--sound/soc/codecs/wm9081.c8
-rw-r--r--sound/soc/davinci/Kconfig13
-rw-r--r--sound/soc/davinci/Makefile3
-rw-r--r--sound/soc/davinci/davinci-evm.c102
-rw-r--r--sound/soc/davinci/davinci-i2s.c135
-rw-r--r--sound/soc/davinci/davinci-mcasp.c874
-rw-r--r--sound/soc/davinci/davinci-mcasp.h55
-rw-r--r--sound/soc/davinci/davinci-pcm.c6
-rw-r--r--sound/soc/davinci/davinci-pcm.h18
-rw-r--r--sound/soc/fsl/mpc5200_dma.c18
-rw-r--r--sound/soc/fsl/mpc5200_dma.h1
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c20
-rw-r--r--sound/soc/omap/Kconfig8
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/ams-delta.c646
-rw-r--r--sound/soc/omap/omap-mcbsp.c10
-rw-r--r--sound/soc/omap/omap-pcm.c2
-rw-r--r--sound/soc/omap/sdp3430.c9
-rw-r--r--sound/soc/pxa/palm27x.c204
-rw-r--r--sound/soc/s3c24xx/Kconfig13
-rw-r--r--sound/soc/s3c24xx/Makefile2
-rw-r--r--sound/soc/s3c24xx/neo1973_gta02_wm8753.c498
-rw-r--r--sound/soc/soc-core.c9
-rw-r--r--sound/soc/soc-dapm.c7
-rw-r--r--sound/soc/soc-jack.c24
55 files changed, 10224 insertions, 415 deletions
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 173a239a541c..130b12118d4f 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -56,30 +56,14 @@
56 56
57#define MCLK_RATE 12000000 57#define MCLK_RATE 12000000
58 58
59static struct clk *mclk; 59/*
60 60 * As shipped the board does not have inputs. However, it is relatively
61static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) 61 * straightforward to modify the board to hook them up so support is left
62{ 62 * in the driver.
63 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 63 */
64 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 64#undef ENABLE_MIC_INPUT
65 int ret;
66
67 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
68 MCLK_RATE, SND_SOC_CLOCK_IN);
69 if (ret < 0) {
70 clk_disable(mclk);
71 return ret;
72 }
73
74 return 0;
75}
76
77static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream)
78{
79 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
80 65
81 dev_dbg(rtd->socdev->dev, "shutdown"); 66static struct clk *mclk;
82}
83 67
84static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, 68static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
85 struct snd_pcm_hw_params *params) 69 struct snd_pcm_hw_params *params)
@@ -87,102 +71,17 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
87 struct snd_soc_pcm_runtime *rtd = substream->private_data; 71 struct snd_soc_pcm_runtime *rtd = substream->private_data;
88 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 72 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
89 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 73 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
90 struct atmel_ssc_info *ssc_p = cpu_dai->private_data;
91 struct ssc_device *ssc = ssc_p->ssc;
92 int ret; 74 int ret;
93 75
94 unsigned int rate;
95 int cmr_div, period;
96
97 if (ssc == NULL) {
98 printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n");
99 return -EINVAL;
100 }
101
102 /* set codec DAI configuration */ 76 /* set codec DAI configuration */
103 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | 77 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
104 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 78 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
105 if (ret < 0) 79 if (ret < 0)
106 return ret; 80 return ret;
107 81
108 /* set cpu DAI configuration */ 82 /* set cpu DAI configuration */
109 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 83 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
110 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 84 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
111 if (ret < 0)
112 return ret;
113
114 /*
115 * The SSC clock dividers depend on the sample rate. The CMR.DIV
116 * field divides the system master clock MCK to drive the SSC TK
117 * signal which provides the codec BCLK. The TCMR.PERIOD and
118 * RCMR.PERIOD fields further divide the BCLK signal to drive
119 * the SSC TF and RF signals which provide the codec DACLRC and
120 * ADCLRC clocks.
121 *
122 * The dividers were determined through trial and error, where a
123 * CMR.DIV value is chosen such that the resulting BCLK value is
124 * divisible, or almost divisible, by (2 * sample rate), and then
125 * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
126 */
127 rate = params_rate(params);
128
129 switch (rate) {
130 case 8000:
131 cmr_div = 55; /* BCLK = 133MHz/(2*55) = 1.209MHz */
132 period = 74; /* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */
133 break;
134 case 11025:
135 cmr_div = 67; /* BCLK = 133MHz/(2*60) = 1.108MHz */
136 period = 45; /* LRC = BCLK/(2*(49+1)) = 11083,3Hz */
137 break;
138 case 16000:
139 cmr_div = 63; /* BCLK = 133MHz/(2*63) = 1.055MHz */
140 period = 32; /* LRC = BCLK/(2*(32+1)) = 15993,2Hz */
141 break;
142 case 22050:
143 cmr_div = 52; /* BCLK = 133MHz/(2*52) = 1.278MHz */
144 period = 28; /* LRC = BCLK/(2*(28+1)) = 22049Hz */
145 break;
146 case 32000:
147 cmr_div = 66; /* BCLK = 133MHz/(2*66) = 1.007MHz */
148 period = 15; /* LRC = BCLK/(2*(15+1)) = 31486,742Hz */
149 break;
150 case 44100:
151 cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */
152 period = 25; /* LRC = BCLK/(2*(25+1)) = 44098Hz */
153 break;
154 case 48000:
155 cmr_div = 33; /* BCLK = 133MHz/(2*33) = 2.015MHz */
156 period = 20; /* LRC = BCLK/(2*(20+1)) = 47979,79Hz */
157 break;
158 case 88200:
159 cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */
160 period = 12; /* LRC = BCLK/(2*(12+1)) = 88196Hz */
161 break;
162 case 96000:
163 cmr_div = 23; /* BCLK = 133MHz/(2*23) = 2.891MHz */
164 period = 14; /* LRC = BCLK/(2*(14+1)) = 96376Hz */
165 break;
166 default:
167 printk(KERN_WARNING "unsupported rate %d"
168 " on at91sam9g20ek board\n", rate);
169 return -EINVAL;
170 }
171
172 /* set the MCK divider for BCLK */
173 ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div);
174 if (ret < 0)
175 return ret;
176
177 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
178 /* set the BCLK divider for DACLRC */
179 ret = snd_soc_dai_set_clkdiv(cpu_dai,
180 ATMEL_SSC_TCMR_PERIOD, period);
181 } else {
182 /* set the BCLK divider for ADCLRC */
183 ret = snd_soc_dai_set_clkdiv(cpu_dai,
184 ATMEL_SSC_RCMR_PERIOD, period);
185 }
186 if (ret < 0) 85 if (ret < 0)
187 return ret; 86 return ret;
188 87
@@ -190,9 +89,7 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
190} 89}
191 90
192static struct snd_soc_ops at91sam9g20ek_ops = { 91static struct snd_soc_ops at91sam9g20ek_ops = {
193 .startup = at91sam9g20ek_startup,
194 .hw_params = at91sam9g20ek_hw_params, 92 .hw_params = at91sam9g20ek_hw_params,
195 .shutdown = at91sam9g20ek_shutdown,
196}; 93};
197 94
198static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, 95static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
@@ -241,10 +138,20 @@ static const struct snd_soc_dapm_route intercon[] = {
241 */ 138 */
242static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) 139static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
243{ 140{
141 struct snd_soc_dai *codec_dai = &codec->dai[0];
142 int ret;
143
244 printk(KERN_DEBUG 144 printk(KERN_DEBUG
245 "at91sam9g20ek_wm8731 " 145 "at91sam9g20ek_wm8731 "
246 ": at91sam9g20ek_wm8731_init() called\n"); 146 ": at91sam9g20ek_wm8731_init() called\n");
247 147
148 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
149 MCLK_RATE, SND_SOC_CLOCK_IN);
150 if (ret < 0) {
151 printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
152 return ret;
153 }
154
248 /* Add specific widgets */ 155 /* Add specific widgets */
249 snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets, 156 snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets,
250 ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); 157 ARRAY_SIZE(at91sam9g20ek_dapm_widgets));
@@ -255,8 +162,13 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
255 snd_soc_dapm_nc_pin(codec, "RLINEIN"); 162 snd_soc_dapm_nc_pin(codec, "RLINEIN");
256 snd_soc_dapm_nc_pin(codec, "LLINEIN"); 163 snd_soc_dapm_nc_pin(codec, "LLINEIN");
257 164
258 /* always connected */ 165#ifdef ENABLE_MIC_INPUT
259 snd_soc_dapm_enable_pin(codec, "Int Mic"); 166 snd_soc_dapm_enable_pin(codec, "Int Mic");
167#else
168 snd_soc_dapm_nc_pin(codec, "Int Mic");
169#endif
170
171 /* always connected */
260 snd_soc_dapm_enable_pin(codec, "Ext Spk"); 172 snd_soc_dapm_enable_pin(codec, "Ext Spk");
261 173
262 snd_soc_dapm_sync(codec); 174 snd_soc_dapm_sync(codec);
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 811596f4c092..8a4de4de30f2 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -7,6 +7,15 @@ config SND_BF5XX_I2S
7 mode (supports single stereo In/Out). 7 mode (supports single stereo In/Out).
8 You will also need to select the audio interfaces to support below. 8 You will also need to select the audio interfaces to support below.
9 9
10config SND_BF5XX_TDM
11 tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip"
12 depends on (BLACKFIN && SND_SOC)
13 help
14 Say Y or M if you want to add support for codecs attached to
15 the Blackfin SPORT (synchronous serial ports) interface in TDM
16 mode.
17 You will also need to select the audio interfaces to support below.
18
10config SND_BF5XX_SOC_SSM2602 19config SND_BF5XX_SOC_SSM2602
11 tristate "SoC SSM2602 Audio support for BF52x ezkit" 20 tristate "SoC SSM2602 Audio support for BF52x ezkit"
12 depends on SND_BF5XX_I2S 21 depends on SND_BF5XX_I2S
@@ -69,6 +78,10 @@ config SND_BF5XX_SOC_I2S
69 tristate 78 tristate
70 select SND_BF5XX_SOC_SPORT 79 select SND_BF5XX_SOC_SPORT
71 80
81config SND_BF5XX_SOC_TDM
82 tristate
83 select SND_BF5XX_SOC_SPORT
84
72config SND_BF5XX_SOC_AC97 85config SND_BF5XX_SOC_AC97
73 tristate 86 tristate
74 select AC97_BUS 87 select AC97_BUS
@@ -83,9 +96,17 @@ config SND_BF5XX_SOC_AD1980
83 help 96 help
84 Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. 97 Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
85 98
99config SND_BF5XX_SOC_AD1938
100 tristate "SoC AD1938 Audio support for Blackfin"
101 depends on SND_BF5XX_TDM
102 select SND_BF5XX_SOC_TDM
103 select SND_SOC_AD1938
104 help
105 Say Y if you want to add support for AD1938 codec on Blackfin.
106
86config SND_BF5XX_SPORT_NUM 107config SND_BF5XX_SPORT_NUM
87 int "Set a SPORT for Sound chip" 108 int "Set a SPORT for Sound chip"
88 depends on (SND_BF5XX_I2S || SND_BF5XX_AC97) 109 depends on (SND_BF5XX_I2S || SND_BF5XX_AC97 || SND_BF5XX_TDM)
89 range 0 3 if BF54x 110 range 0 3 if BF54x
90 range 0 1 if !BF54x 111 range 0 1 if !BF54x
91 default 0 112 default 0
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index 97bb37a6359c..f4d760741fab 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -1,21 +1,27 @@
1# Blackfin Platform Support 1# Blackfin Platform Support
2snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o 2snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
3snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o 3snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
4snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o
4snd-soc-bf5xx-sport-objs := bf5xx-sport.o 5snd-soc-bf5xx-sport-objs := bf5xx-sport.o
5snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o 6snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
6snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o 7snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
8snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o
7 9
8obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o 10obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
9obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o 11obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
12obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o
10obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o 13obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
11obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o 14obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
12obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o 15obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
16obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o
13 17
14# Blackfin Machine Support 18# Blackfin Machine Support
15snd-ad1980-objs := bf5xx-ad1980.o 19snd-ad1980-objs := bf5xx-ad1980.o
16snd-ssm2602-objs := bf5xx-ssm2602.o 20snd-ssm2602-objs := bf5xx-ssm2602.o
17snd-ad73311-objs := bf5xx-ad73311.o 21snd-ad73311-objs := bf5xx-ad73311.o
22snd-ad1938-objs := bf5xx-ad1938.o
18 23
19obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o 24obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
20obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o 25obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
21obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o 26obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
27obj-$(CONFIG_SND_BF5XX_SOC_AD1938) += snd-ad1938.o
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index b1ed423fabd5..2758b9017a7f 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -277,28 +277,24 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
277 if (!dai->active) 277 if (!dai->active)
278 return 0; 278 return 0;
279 279
280 ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); 280 ret = sport_set_multichannel(sport, 16, 0x1F, 1);
281 if (ret) { 281 if (ret) {
282 pr_err("SPORT is busy!\n"); 282 pr_err("SPORT is busy!\n");
283 return -EBUSY; 283 return -EBUSY;
284 } 284 }
285 285
286 ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); 286 ret = sport_config_rx(sport, IRFS, 0xF, 0, (16*16-1));
287 if (ret) { 287 if (ret) {
288 pr_err("SPORT is busy!\n"); 288 pr_err("SPORT is busy!\n");
289 return -EBUSY; 289 return -EBUSY;
290 } 290 }
291 291
292 ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); 292 ret = sport_config_tx(sport, ITFS, 0xF, 0, (16*16-1));
293 if (ret) { 293 if (ret) {
294 pr_err("SPORT is busy!\n"); 294 pr_err("SPORT is busy!\n");
295 return -EBUSY; 295 return -EBUSY;
296 } 296 }
297 297
298 if (dai->capture.active)
299 sport_rx_start(sport);
300 if (dai->playback.active)
301 sport_tx_start(sport);
302 return 0; 298 return 0;
303} 299}
304 300
diff --git a/sound/soc/blackfin/bf5xx-ad1938.c b/sound/soc/blackfin/bf5xx-ad1938.c
new file mode 100644
index 000000000000..08269e91810c
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ad1938.c
@@ -0,0 +1,142 @@
1/*
2 * File: sound/soc/blackfin/bf5xx-ad1938.c
3 * Author: Barry Song <Barry.Song@analog.com>
4 *
5 * Created: Thur June 4 2009
6 * Description: Board driver for ad1938 sound chip
7 *
8 * Bugs: Enter bugs at http://blackfin.uclinux.org/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see the file COPYING, or write
22 * to the Free Software Foundation, Inc.,
23 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/device.h>
29#include <sound/core.h>
30#include <sound/pcm.h>
31#include <sound/soc.h>
32#include <sound/soc-dapm.h>
33#include <sound/pcm_params.h>
34
35#include <asm/blackfin.h>
36#include <asm/cacheflush.h>
37#include <asm/irq.h>
38#include <asm/dma.h>
39#include <asm/portmux.h>
40
41#include "../codecs/ad1938.h"
42#include "bf5xx-sport.h"
43
44#include "bf5xx-tdm-pcm.h"
45#include "bf5xx-tdm.h"
46
47static struct snd_soc_card bf5xx_ad1938;
48
49static int bf5xx_ad1938_startup(struct snd_pcm_substream *substream)
50{
51 struct snd_soc_pcm_runtime *rtd = substream->private_data;
52 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
53
54 cpu_dai->private_data = sport_handle;
55 return 0;
56}
57
58static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream,
59 struct snd_pcm_hw_params *params)
60{
61 struct snd_soc_pcm_runtime *rtd = substream->private_data;
62 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
63 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
64 int ret = 0;
65 /* set cpu DAI configuration */
66 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
67 SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
68 if (ret < 0)
69 return ret;
70
71 /* set codec DAI configuration */
72 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
73 SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
74 if (ret < 0)
75 return ret;
76
77 /* set codec DAI slots, 8 channels, all channels are enabled */
78 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 8);
79 if (ret < 0)
80 return ret;
81
82 return 0;
83}
84
85static struct snd_soc_ops bf5xx_ad1938_ops = {
86 .startup = bf5xx_ad1938_startup,
87 .hw_params = bf5xx_ad1938_hw_params,
88};
89
90static struct snd_soc_dai_link bf5xx_ad1938_dai = {
91 .name = "ad1938",
92 .stream_name = "AD1938",
93 .cpu_dai = &bf5xx_tdm_dai,
94 .codec_dai = &ad1938_dai,
95 .ops = &bf5xx_ad1938_ops,
96};
97
98static struct snd_soc_card bf5xx_ad1938 = {
99 .name = "bf5xx_ad1938",
100 .platform = &bf5xx_tdm_soc_platform,
101 .dai_link = &bf5xx_ad1938_dai,
102 .num_links = 1,
103};
104
105static struct snd_soc_device bf5xx_ad1938_snd_devdata = {
106 .card = &bf5xx_ad1938,
107 .codec_dev = &soc_codec_dev_ad1938,
108};
109
110static struct platform_device *bfxx_ad1938_snd_device;
111
112static int __init bf5xx_ad1938_init(void)
113{
114 int ret;
115
116 bfxx_ad1938_snd_device = platform_device_alloc("soc-audio", -1);
117 if (!bfxx_ad1938_snd_device)
118 return -ENOMEM;
119
120 platform_set_drvdata(bfxx_ad1938_snd_device, &bf5xx_ad1938_snd_devdata);
121 bf5xx_ad1938_snd_devdata.dev = &bfxx_ad1938_snd_device->dev;
122 ret = platform_device_add(bfxx_ad1938_snd_device);
123
124 if (ret)
125 platform_device_put(bfxx_ad1938_snd_device);
126
127 return ret;
128}
129
130static void __exit bf5xx_ad1938_exit(void)
131{
132 platform_device_unregister(bfxx_ad1938_snd_device);
133}
134
135module_init(bf5xx_ad1938_init);
136module_exit(bf5xx_ad1938_exit);
137
138/* Module information */
139MODULE_AUTHOR("Barry Song");
140MODULE_DESCRIPTION("ALSA SoC AD1938 board driver");
141MODULE_LICENSE("GPL");
142
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index af06904bab0f..876abade27e1 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -259,22 +259,18 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
259 if (!dai->active) 259 if (!dai->active)
260 return 0; 260 return 0;
261 261
262 ret = sport_config_rx(sport_handle, RFSR | RCKFE, RSFSE|0x1f, 0, 0); 262 ret = sport_config_rx(sport, RFSR | RCKFE, RSFSE|0x1f, 0, 0);
263 if (ret) { 263 if (ret) {
264 pr_err("SPORT is busy!\n"); 264 pr_err("SPORT is busy!\n");
265 return -EBUSY; 265 return -EBUSY;
266 } 266 }
267 267
268 ret = sport_config_tx(sport_handle, TFSR | TCKFE, TSFSE|0x1f, 0, 0); 268 ret = sport_config_tx(sport, TFSR | TCKFE, TSFSE|0x1f, 0, 0);
269 if (ret) { 269 if (ret) {
270 pr_err("SPORT is busy!\n"); 270 pr_err("SPORT is busy!\n");
271 return -EBUSY; 271 return -EBUSY;
272 } 272 }
273 273
274 if (dai->capture.active)
275 sport_rx_start(sport);
276 if (dai->playback.active)
277 sport_tx_start(sport);
278 return 0; 274 return 0;
279} 275}
280 276
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
new file mode 100644
index 000000000000..ccb5e823bd18
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c
@@ -0,0 +1,330 @@
1/*
2 * File: sound/soc/blackfin/bf5xx-tdm-pcm.c
3 * Author: Barry Song <Barry.Song@analog.com>
4 *
5 * Created: Tue June 06 2009
6 * Description: DMA driver for tdm codec
7 *
8 * Modified:
9 * Copyright 2009 Analog Devices Inc.
10 *
11 * Bugs: Enter bugs at http://blackfin.uclinux.org/
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see the file COPYING, or write
25 * to the Free Software Foundation, Inc.,
26 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 */
28
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/platform_device.h>
32#include <linux/slab.h>
33#include <linux/dma-mapping.h>
34
35#include <sound/core.h>
36#include <sound/pcm.h>
37#include <sound/pcm_params.h>
38#include <sound/soc.h>
39
40#include <asm/dma.h>
41
42#include "bf5xx-tdm-pcm.h"
43#include "bf5xx-tdm.h"
44#include "bf5xx-sport.h"
45
46#define PCM_BUFFER_MAX 0x10000
47#define FRAGMENT_SIZE_MIN (4*1024)
48#define FRAGMENTS_MIN 2
49#define FRAGMENTS_MAX 32
50
51static void bf5xx_dma_irq(void *data)
52{
53 struct snd_pcm_substream *pcm = data;
54 snd_pcm_period_elapsed(pcm);
55}
56
57static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
58 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
59 SNDRV_PCM_INFO_RESUME),
60 .formats = SNDRV_PCM_FMTBIT_S32_LE,
61 .rates = SNDRV_PCM_RATE_48000,
62 .channels_min = 2,
63 .channels_max = 8,
64 .buffer_bytes_max = PCM_BUFFER_MAX,
65 .period_bytes_min = FRAGMENT_SIZE_MIN,
66 .period_bytes_max = PCM_BUFFER_MAX/2,
67 .periods_min = FRAGMENTS_MIN,
68 .periods_max = FRAGMENTS_MAX,
69};
70
71static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
72 struct snd_pcm_hw_params *params)
73{
74 size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
75 snd_pcm_lib_malloc_pages(substream, size * 4);
76
77 return 0;
78}
79
80static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
81{
82 snd_pcm_lib_free_pages(substream);
83
84 return 0;
85}
86
87static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
88{
89 struct snd_pcm_runtime *runtime = substream->runtime;
90 struct sport_device *sport = runtime->private_data;
91 int fragsize_bytes = frames_to_bytes(runtime, runtime->period_size);
92
93 fragsize_bytes /= runtime->channels;
94 /* inflate the fragsize to match the dma width of SPORT */
95 fragsize_bytes *= 8;
96
97 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
98 sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
99 sport_config_tx_dma(sport, runtime->dma_area,
100 runtime->periods, fragsize_bytes);
101 } else {
102 sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
103 sport_config_rx_dma(sport, runtime->dma_area,
104 runtime->periods, fragsize_bytes);
105 }
106
107 return 0;
108}
109
110static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
111{
112 struct snd_pcm_runtime *runtime = substream->runtime;
113 struct sport_device *sport = runtime->private_data;
114 int ret = 0;
115
116 switch (cmd) {
117 case SNDRV_PCM_TRIGGER_START:
118 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
119 sport_tx_start(sport);
120 else
121 sport_rx_start(sport);
122 break;
123 case SNDRV_PCM_TRIGGER_STOP:
124 case SNDRV_PCM_TRIGGER_SUSPEND:
125 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
126 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
127 sport_tx_stop(sport);
128 else
129 sport_rx_stop(sport);
130 break;
131 default:
132 ret = -EINVAL;
133 }
134
135 return ret;
136}
137
138static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
139{
140 struct snd_pcm_runtime *runtime = substream->runtime;
141 struct sport_device *sport = runtime->private_data;
142 unsigned int diff;
143 snd_pcm_uframes_t frames;
144
145 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
146 diff = sport_curr_offset_tx(sport);
147 frames = diff / (8*4); /* 32 bytes per frame */
148 } else {
149 diff = sport_curr_offset_rx(sport);
150 frames = diff / (8*4);
151 }
152 return frames;
153}
154
155static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
156{
157 struct snd_pcm_runtime *runtime = substream->runtime;
158 int ret = 0;
159
160 snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
161
162 ret = snd_pcm_hw_constraint_integer(runtime,
163 SNDRV_PCM_HW_PARAM_PERIODS);
164 if (ret < 0)
165 goto out;
166
167 if (sport_handle != NULL)
168 runtime->private_data = sport_handle;
169 else {
170 pr_err("sport_handle is NULL\n");
171 ret = -ENODEV;
172 }
173out:
174 return ret;
175}
176
177static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
178 snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
179{
180 unsigned int *src;
181 unsigned int *dst;
182 int i;
183
184 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
185 src = buf;
186 dst = (unsigned int *)substream->runtime->dma_area;
187
188 dst += pos * 8;
189 while (count--) {
190 for (i = 0; i < substream->runtime->channels; i++)
191 *(dst + i) = *src++;
192 dst += 8;
193 }
194 } else {
195 src = (unsigned int *)substream->runtime->dma_area;
196 dst = buf;
197
198 src += pos * 8;
199 while (count--) {
200 for (i = 0; i < substream->runtime->channels; i++)
201 *dst++ = *(src+i);
202 src += 8;
203 }
204 }
205
206 return 0;
207}
208
209static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
210 int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
211{
212 unsigned char *buf = substream->runtime->dma_area;
213 buf += pos * 8 * 4;
214 memset(buf, '\0', count * 8 * 4);
215
216 return 0;
217}
218
219
220struct snd_pcm_ops bf5xx_pcm_tdm_ops = {
221 .open = bf5xx_pcm_open,
222 .ioctl = snd_pcm_lib_ioctl,
223 .hw_params = bf5xx_pcm_hw_params,
224 .hw_free = bf5xx_pcm_hw_free,
225 .prepare = bf5xx_pcm_prepare,
226 .trigger = bf5xx_pcm_trigger,
227 .pointer = bf5xx_pcm_pointer,
228 .copy = bf5xx_pcm_copy,
229 .silence = bf5xx_pcm_silence,
230};
231
232static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
233{
234 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
235 struct snd_dma_buffer *buf = &substream->dma_buffer;
236 size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
237
238 buf->dev.type = SNDRV_DMA_TYPE_DEV;
239 buf->dev.dev = pcm->card->dev;
240 buf->private_data = NULL;
241 buf->area = dma_alloc_coherent(pcm->card->dev, size * 4,
242 &buf->addr, GFP_KERNEL);
243 if (!buf->area) {
244 pr_err("Failed to allocate dma memory \
245 Please increase uncached DMA memory region\n");
246 return -ENOMEM;
247 }
248 buf->bytes = size;
249
250 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
251 sport_handle->tx_buf = buf->area;
252 else
253 sport_handle->rx_buf = buf->area;
254
255 return 0;
256}
257
258static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
259{
260 struct snd_pcm_substream *substream;
261 struct snd_dma_buffer *buf;
262 int stream;
263
264 for (stream = 0; stream < 2; stream++) {
265 substream = pcm->streams[stream].substream;
266 if (!substream)
267 continue;
268
269 buf = &substream->dma_buffer;
270 if (!buf->area)
271 continue;
272 dma_free_coherent(NULL, buf->bytes, buf->area, 0);
273 buf->area = NULL;
274 }
275 if (sport_handle)
276 sport_done(sport_handle);
277}
278
279static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
280
281static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
282 struct snd_pcm *pcm)
283{
284 int ret = 0;
285
286 if (!card->dev->dma_mask)
287 card->dev->dma_mask = &bf5xx_pcm_dmamask;
288 if (!card->dev->coherent_dma_mask)
289 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
290
291 if (dai->playback.channels_min) {
292 ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
293 SNDRV_PCM_STREAM_PLAYBACK);
294 if (ret)
295 goto out;
296 }
297
298 if (dai->capture.channels_min) {
299 ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
300 SNDRV_PCM_STREAM_CAPTURE);
301 if (ret)
302 goto out;
303 }
304out:
305 return ret;
306}
307
308struct snd_soc_platform bf5xx_tdm_soc_platform = {
309 .name = "bf5xx-audio",
310 .pcm_ops = &bf5xx_pcm_tdm_ops,
311 .pcm_new = bf5xx_pcm_tdm_new,
312 .pcm_free = bf5xx_pcm_free_dma_buffers,
313};
314EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
315
316static int __init bfin_pcm_tdm_init(void)
317{
318 return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
319}
320module_init(bfin_pcm_tdm_init);
321
322static void __exit bfin_pcm_tdm_exit(void)
323{
324 snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
325}
326module_exit(bfin_pcm_tdm_exit);
327
328MODULE_AUTHOR("Barry Song");
329MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
330MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h
new file mode 100644
index 000000000000..ddc5047df88c
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.h
@@ -0,0 +1,21 @@
1/*
2 * sound/soc/blackfin/bf5xx-tdm-pcm.h -- ALSA PCM interface for the Blackfin
3 *
4 * Copyright 2009 Analog Device Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef _BF5XX_TDM_PCM_H
12#define _BF5XX_TDM_PCM_H
13
14struct bf5xx_pcm_dma_params {
15 char *name; /* stream identifier */
16};
17
18/* platform data */
19extern struct snd_soc_platform bf5xx_tdm_soc_platform;
20
21#endif
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
new file mode 100644
index 000000000000..3096badf09a5
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -0,0 +1,343 @@
1/*
2 * File: sound/soc/blackfin/bf5xx-tdm.c
3 * Author: Barry Song <Barry.Song@analog.com>
4 *
5 * Created: Thurs June 04 2009
6 * Description: Blackfin I2S(TDM) CPU DAI driver
7 * Even though TDM mode can be as part of I2S DAI, but there
8 * are so much difference in configuration and data flow,
9 * it's very ugly to integrate I2S and TDM into a module
10 *
11 * Modified:
12 * Copyright 2009 Analog Devices Inc.
13 *
14 * Bugs: Enter bugs at http://blackfin.uclinux.org/
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see the file COPYING, or write
28 * to the Free Software Foundation, Inc.,
29 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
31
32#include <linux/init.h>
33#include <linux/module.h>
34#include <linux/device.h>
35#include <sound/core.h>
36#include <sound/pcm.h>
37#include <sound/pcm_params.h>
38#include <sound/initval.h>
39#include <sound/soc.h>
40
41#include <asm/irq.h>
42#include <asm/portmux.h>
43#include <linux/mutex.h>
44#include <linux/gpio.h>
45
46#include "bf5xx-sport.h"
47#include "bf5xx-tdm.h"
48
49struct bf5xx_tdm_port {
50 u16 tcr1;
51 u16 rcr1;
52 u16 tcr2;
53 u16 rcr2;
54 int configured;
55};
56
57static struct bf5xx_tdm_port bf5xx_tdm;
58static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
59
60static struct sport_param sport_params[2] = {
61 {
62 .dma_rx_chan = CH_SPORT0_RX,
63 .dma_tx_chan = CH_SPORT0_TX,
64 .err_irq = IRQ_SPORT0_ERROR,
65 .regs = (struct sport_register *)SPORT0_TCR1,
66 },
67 {
68 .dma_rx_chan = CH_SPORT1_RX,
69 .dma_tx_chan = CH_SPORT1_TX,
70 .err_irq = IRQ_SPORT1_ERROR,
71 .regs = (struct sport_register *)SPORT1_TCR1,
72 }
73};
74
75/*
76 * Setting the TFS pin selector for SPORT 0 based on whether the selected
77 * port id F or G. If the port is F then no conflict should exist for the
78 * TFS. When Port G is selected and EMAC then there is a conflict between
79 * the PHY interrupt line and TFS. Current settings prevent the conflict
80 * by ignoring the TFS pin when Port G is selected. This allows both
81 * ssm2602 using Port G and EMAC concurrently.
82 */
83#ifdef CONFIG_BF527_SPORT0_PORTF
84#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
85#else
86#define LOCAL_SPORT0_TFS (0)
87#endif
88
89static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
90 P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
91 {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
92 P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
93
94static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
95 unsigned int fmt)
96{
97 int ret = 0;
98
99 /* interface format:support TDM,slave mode */
100 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
101 case SND_SOC_DAIFMT_DSP_A:
102 break;
103 default:
104 printk(KERN_ERR "%s: Unknown DAI format type\n", __func__);
105 ret = -EINVAL;
106 break;
107 }
108
109 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
110 case SND_SOC_DAIFMT_CBM_CFM:
111 break;
112 case SND_SOC_DAIFMT_CBS_CFS:
113 case SND_SOC_DAIFMT_CBM_CFS:
114 case SND_SOC_DAIFMT_CBS_CFM:
115 ret = -EINVAL;
116 break;
117 default:
118 printk(KERN_ERR "%s: Unknown DAI master type\n", __func__);
119 ret = -EINVAL;
120 break;
121 }
122
123 return ret;
124}
125
126static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
127 struct snd_pcm_hw_params *params,
128 struct snd_soc_dai *dai)
129{
130 int ret = 0;
131
132 bf5xx_tdm.tcr2 &= ~0x1f;
133 bf5xx_tdm.rcr2 &= ~0x1f;
134 switch (params_format(params)) {
135 case SNDRV_PCM_FORMAT_S32_LE:
136 bf5xx_tdm.tcr2 |= 31;
137 bf5xx_tdm.rcr2 |= 31;
138 sport_handle->wdsize = 4;
139 break;
140 /* at present, we only support 32bit transfer */
141 default:
142 pr_err("not supported PCM format yet\n");
143 return -EINVAL;
144 break;
145 }
146
147 if (!bf5xx_tdm.configured) {
148 /*
149 * TX and RX are not independent,they are enabled at the
150 * same time, even if only one side is running. So, we
151 * need to configure both of them at the time when the first
152 * stream is opened.
153 *
154 * CPU DAI:slave mode.
155 */
156 ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1,
157 bf5xx_tdm.rcr2, 0, 0);
158 if (ret) {
159 pr_err("SPORT is busy!\n");
160 return -EBUSY;
161 }
162
163 ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1,
164 bf5xx_tdm.tcr2, 0, 0);
165 if (ret) {
166 pr_err("SPORT is busy!\n");
167 return -EBUSY;
168 }
169
170 bf5xx_tdm.configured = 1;
171 }
172
173 return 0;
174}
175
176static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
177 struct snd_soc_dai *dai)
178{
179 /* No active stream, SPORT is allowed to be configured again. */
180 if (!dai->active)
181 bf5xx_tdm.configured = 0;
182}
183
184#ifdef CONFIG_PM
185static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
186{
187 struct sport_device *sport =
188 (struct sport_device *)dai->private_data;
189
190 if (!dai->active)
191 return 0;
192 if (dai->capture.active)
193 sport_rx_stop(sport);
194 if (dai->playback.active)
195 sport_tx_stop(sport);
196 return 0;
197}
198
199static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
200{
201 int ret;
202 struct sport_device *sport =
203 (struct sport_device *)dai->private_data;
204
205 if (!dai->active)
206 return 0;
207
208 ret = sport_set_multichannel(sport, 8, 0xFF, 1);
209 if (ret) {
210 pr_err("SPORT is busy!\n");
211 ret = -EBUSY;
212 }
213
214 ret = sport_config_rx(sport, IRFS, 0x1F, 0, 0);
215 if (ret) {
216 pr_err("SPORT is busy!\n");
217 ret = -EBUSY;
218 }
219
220 ret = sport_config_tx(sport, ITFS, 0x1F, 0, 0);
221 if (ret) {
222 pr_err("SPORT is busy!\n");
223 ret = -EBUSY;
224 }
225
226 return 0;
227}
228
229#else
230#define bf5xx_tdm_suspend NULL
231#define bf5xx_tdm_resume NULL
232#endif
233
234static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
235 .hw_params = bf5xx_tdm_hw_params,
236 .set_fmt = bf5xx_tdm_set_dai_fmt,
237 .shutdown = bf5xx_tdm_shutdown,
238};
239
240struct snd_soc_dai bf5xx_tdm_dai = {
241 .name = "bf5xx-tdm",
242 .id = 0,
243 .suspend = bf5xx_tdm_suspend,
244 .resume = bf5xx_tdm_resume,
245 .playback = {
246 .channels_min = 2,
247 .channels_max = 8,
248 .rates = SNDRV_PCM_RATE_48000,
249 .formats = SNDRV_PCM_FMTBIT_S32_LE,},
250 .capture = {
251 .channels_min = 2,
252 .channels_max = 8,
253 .rates = SNDRV_PCM_RATE_48000,
254 .formats = SNDRV_PCM_FMTBIT_S32_LE,},
255 .ops = &bf5xx_tdm_dai_ops,
256};
257EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
258
259static int __devinit bfin_tdm_probe(struct platform_device *pdev)
260{
261 int ret = 0;
262
263 if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
264 pr_err("Requesting Peripherals failed\n");
265 return -EFAULT;
266 }
267
268 /* request DMA for SPORT */
269 sport_handle = sport_init(&sport_params[sport_num], 4, \
270 8 * sizeof(u32), NULL);
271 if (!sport_handle) {
272 peripheral_free_list(&sport_req[sport_num][0]);
273 return -ENODEV;
274 }
275
276 /* SPORT works in TDM mode */
277 ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
278 if (ret) {
279 pr_err("SPORT is busy!\n");
280 ret = -EBUSY;
281 goto sport_config_err;
282 }
283
284 ret = sport_config_rx(sport_handle, IRFS, 0x1F, 0, 0);
285 if (ret) {
286 pr_err("SPORT is busy!\n");
287 ret = -EBUSY;
288 goto sport_config_err;
289 }
290
291 ret = sport_config_tx(sport_handle, ITFS, 0x1F, 0, 0);
292 if (ret) {
293 pr_err("SPORT is busy!\n");
294 ret = -EBUSY;
295 goto sport_config_err;
296 }
297
298 ret = snd_soc_register_dai(&bf5xx_tdm_dai);
299 if (ret) {
300 pr_err("Failed to register DAI: %d\n", ret);
301 goto sport_config_err;
302 }
303 return 0;
304
305sport_config_err:
306 peripheral_free_list(&sport_req[sport_num][0]);
307 return ret;
308}
309
310static int __devexit bfin_tdm_remove(struct platform_device *pdev)
311{
312 peripheral_free_list(&sport_req[sport_num][0]);
313 snd_soc_unregister_dai(&bf5xx_tdm_dai);
314
315 return 0;
316}
317
318static struct platform_driver bfin_tdm_driver = {
319 .probe = bfin_tdm_probe,
320 .remove = __devexit_p(bfin_tdm_remove),
321 .driver = {
322 .name = "bfin-tdm",
323 .owner = THIS_MODULE,
324 },
325};
326
327static int __init bfin_tdm_init(void)
328{
329 return platform_driver_register(&bfin_tdm_driver);
330}
331module_init(bfin_tdm_init);
332
333static void __exit bfin_tdm_exit(void)
334{
335 platform_driver_unregister(&bfin_tdm_driver);
336}
337module_exit(bfin_tdm_exit);
338
339/* Module information */
340MODULE_AUTHOR("Barry Song");
341MODULE_DESCRIPTION("TDM driver for ADI Blackfin");
342MODULE_LICENSE("GPL");
343
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h
new file mode 100644
index 000000000000..618ec3d90cd4
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-tdm.h
@@ -0,0 +1,14 @@
1/*
2 * sound/soc/blackfin/bf5xx-tdm.h
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef _BF5XX_TDM_H
10#define _BF5XX_TDM_H
11
12extern struct snd_soc_dai bf5xx_tdm_dai;
13
14#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 68ea5b6648df..31a6d2111ed0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -12,11 +12,13 @@ config SND_SOC_ALL_CODECS
12 tristate "Build all ASoC CODEC drivers" 12 tristate "Build all ASoC CODEC drivers"
13 select SND_SOC_L3 13 select SND_SOC_L3
14 select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS 14 select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
15 select SND_SOC_AD1938 if SPI_MASTER
15 select SND_SOC_AD1980 if SND_SOC_AC97_BUS 16 select SND_SOC_AD1980 if SND_SOC_AC97_BUS
16 select SND_SOC_AD73311 if I2C 17 select SND_SOC_AD73311 if I2C
17 select SND_SOC_AK4104 if SPI_MASTER 18 select SND_SOC_AK4104 if SPI_MASTER
18 select SND_SOC_AK4535 if I2C 19 select SND_SOC_AK4535 if I2C
19 select SND_SOC_CS4270 if I2C 20 select SND_SOC_CS4270 if I2C
21 select SND_SOC_MAX9877 if I2C
20 select SND_SOC_PCM3008 22 select SND_SOC_PCM3008
21 select SND_SOC_SPDIF 23 select SND_SOC_SPDIF
22 select SND_SOC_SSM2602 if I2C 24 select SND_SOC_SSM2602 if I2C
@@ -36,6 +38,7 @@ config SND_SOC_ALL_CODECS
36 select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI 38 select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
37 select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI 39 select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
38 select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI 40 select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
41 select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
39 select SND_SOC_WM8900 if I2C 42 select SND_SOC_WM8900 if I2C
40 select SND_SOC_WM8903 if I2C 43 select SND_SOC_WM8903 if I2C
41 select SND_SOC_WM8940 if I2C 44 select SND_SOC_WM8940 if I2C
@@ -44,6 +47,7 @@ config SND_SOC_ALL_CODECS
44 select SND_SOC_WM8971 if I2C 47 select SND_SOC_WM8971 if I2C
45 select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI 48 select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
46 select SND_SOC_WM8990 if I2C 49 select SND_SOC_WM8990 if I2C
50 select SND_SOC_WM8993 if I2C
47 select SND_SOC_WM9081 if I2C 51 select SND_SOC_WM9081 if I2C
48 select SND_SOC_WM9705 if SND_SOC_AC97_BUS 52 select SND_SOC_WM9705 if SND_SOC_AC97_BUS
49 select SND_SOC_WM9712 if SND_SOC_AC97_BUS 53 select SND_SOC_WM9712 if SND_SOC_AC97_BUS
@@ -64,6 +68,9 @@ config SND_SOC_AC97_CODEC
64 tristate 68 tristate
65 select SND_AC97_CODEC 69 select SND_AC97_CODEC
66 70
71config SND_SOC_AD1938
72 tristate
73
67config SND_SOC_AD1980 74config SND_SOC_AD1980
68 tristate 75 tristate
69 76
@@ -88,6 +95,9 @@ config SND_SOC_CS4270_VD33_ERRATA
88 bool 95 bool
89 depends on SND_SOC_CS4270 96 depends on SND_SOC_CS4270
90 97
98config SND_SOC_CX20442
99 tristate
100
91config SND_SOC_L3 101config SND_SOC_L3
92 tristate 102 tristate
93 103
@@ -149,6 +159,9 @@ config SND_SOC_WM8750
149config SND_SOC_WM8753 159config SND_SOC_WM8753
150 tristate 160 tristate
151 161
162config SND_SOC_WM8776
163 tristate
164
152config SND_SOC_WM8900 165config SND_SOC_WM8900
153 tristate 166 tristate
154 167
@@ -173,6 +186,9 @@ config SND_SOC_WM8988
173config SND_SOC_WM8990 186config SND_SOC_WM8990
174 tristate 187 tristate
175 188
189config SND_SOC_WM8993
190 tristate
191
176config SND_SOC_WM9081 192config SND_SOC_WM9081
177 tristate 193 tristate
178 194
@@ -184,3 +200,7 @@ config SND_SOC_WM9712
184 200
185config SND_SOC_WM9713 201config SND_SOC_WM9713
186 tristate 202 tristate
203
204# Amp
205config SND_SOC_MAX9877
206 tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8ce28a34e8e9..78dce5d3fa22 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,9 +1,11 @@
1snd-soc-ac97-objs := ac97.o 1snd-soc-ac97-objs := ac97.o
2snd-soc-ad1938-objs := ad1938.o
2snd-soc-ad1980-objs := ad1980.o 3snd-soc-ad1980-objs := ad1980.o
3snd-soc-ad73311-objs := ad73311.o 4snd-soc-ad73311-objs := ad73311.o
4snd-soc-ak4104-objs := ak4104.o 5snd-soc-ak4104-objs := ak4104.o
5snd-soc-ak4535-objs := ak4535.o 6snd-soc-ak4535-objs := ak4535.o
6snd-soc-cs4270-objs := cs4270.o 7snd-soc-cs4270-objs := cs4270.o
8snd-soc-cx20442-objs := cx20442.o
7snd-soc-l3-objs := l3.o 9snd-soc-l3-objs := l3.o
8snd-soc-pcm3008-objs := pcm3008.o 10snd-soc-pcm3008-objs := pcm3008.o
9snd-soc-spdif-objs := spdif_transciever.o 11snd-soc-spdif-objs := spdif_transciever.o
@@ -24,6 +26,7 @@ snd-soc-wm8728-objs := wm8728.o
24snd-soc-wm8731-objs := wm8731.o 26snd-soc-wm8731-objs := wm8731.o
25snd-soc-wm8750-objs := wm8750.o 27snd-soc-wm8750-objs := wm8750.o
26snd-soc-wm8753-objs := wm8753.o 28snd-soc-wm8753-objs := wm8753.o
29snd-soc-wm8776-objs := wm8776.o
27snd-soc-wm8900-objs := wm8900.o 30snd-soc-wm8900-objs := wm8900.o
28snd-soc-wm8903-objs := wm8903.o 31snd-soc-wm8903-objs := wm8903.o
29snd-soc-wm8940-objs := wm8940.o 32snd-soc-wm8940-objs := wm8940.o
@@ -32,17 +35,23 @@ snd-soc-wm8961-objs := wm8961.o
32snd-soc-wm8971-objs := wm8971.o 35snd-soc-wm8971-objs := wm8971.o
33snd-soc-wm8988-objs := wm8988.o 36snd-soc-wm8988-objs := wm8988.o
34snd-soc-wm8990-objs := wm8990.o 37snd-soc-wm8990-objs := wm8990.o
38snd-soc-wm8993-objs := wm8993.o
35snd-soc-wm9081-objs := wm9081.o 39snd-soc-wm9081-objs := wm9081.o
36snd-soc-wm9705-objs := wm9705.o 40snd-soc-wm9705-objs := wm9705.o
37snd-soc-wm9712-objs := wm9712.o 41snd-soc-wm9712-objs := wm9712.o
38snd-soc-wm9713-objs := wm9713.o 42snd-soc-wm9713-objs := wm9713.o
39 43
44# Amp
45snd-soc-max9877-objs := max9877.o
46
40obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o 47obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
48obj-$(CONFIG_SND_SOC_AD1938) += snd-soc-ad1938.o
41obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o 49obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
42obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o 50obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
43obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o 51obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
44obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o 52obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
45obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o 53obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
54obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
46obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o 55obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
47obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o 56obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
48obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o 57obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
@@ -63,6 +72,7 @@ obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
63obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o 72obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
64obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o 73obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
65obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o 74obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
75obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
66obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o 76obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
67obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o 77obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
68obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o 78obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
@@ -71,7 +81,11 @@ obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
71obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o 81obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
72obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o 82obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
73obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o 83obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
84obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
74obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o 85obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
75obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o 86obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
76obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o 87obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
77obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o 88obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
89
90# Amp
91obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c
new file mode 100644
index 000000000000..aafda743fc8f
--- /dev/null
+++ b/sound/soc/codecs/ad1938.c
@@ -0,0 +1,668 @@
1/*
2 * File: sound/soc/codecs/ad1938.c
3 * Author: Barry Song <Barry.Song@analog.com>
4 *
5 * Created: June 04 2009
6 * Description: Driver for AD1938 sound chip
7 *
8 * Modified:
9 * Copyright 2009 Analog Devices Inc.
10 *
11 * Bugs: Enter bugs at http://blackfin.uclinux.org/
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see the file COPYING, or write
25 * to the Free Software Foundation, Inc.,
26 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 */
28
29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/version.h>
32#include <linux/kernel.h>
33#include <linux/device.h>
34#include <sound/core.h>
35#include <sound/pcm.h>
36#include <sound/pcm_params.h>
37#include <sound/initval.h>
38#include <sound/soc.h>
39#include <sound/tlv.h>
40#include <sound/soc-dapm.h>
41#include <linux/spi/spi.h>
42#include "ad1938.h"
43
44/* codec private data */
45struct ad1938_priv {
46 struct snd_soc_codec codec;
47 u8 reg_cache[AD1938_NUM_REGS];
48};
49
50static struct snd_soc_codec *ad1938_codec;
51struct snd_soc_codec_device soc_codec_dev_ad1938;
52static int ad1938_register(struct ad1938_priv *ad1938);
53static void ad1938_unregister(struct ad1938_priv *ad1938);
54
55/*
56 * AD1938 volume/mute/de-emphasis etc. controls
57 */
58static const char *ad1938_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
59
60static const struct soc_enum ad1938_deemp_enum =
61 SOC_ENUM_SINGLE(AD1938_DAC_CTRL2, 1, 4, ad1938_deemp);
62
63static const struct snd_kcontrol_new ad1938_snd_controls[] = {
64 /* DAC volume control */
65 SOC_DOUBLE_R("DAC1 Volume", AD1938_DAC_L1_VOL,
66 AD1938_DAC_R1_VOL, 0, 0xFF, 1),
67 SOC_DOUBLE_R("DAC2 Volume", AD1938_DAC_L2_VOL,
68 AD1938_DAC_R2_VOL, 0, 0xFF, 1),
69 SOC_DOUBLE_R("DAC3 Volume", AD1938_DAC_L3_VOL,
70 AD1938_DAC_R3_VOL, 0, 0xFF, 1),
71 SOC_DOUBLE_R("DAC4 Volume", AD1938_DAC_L4_VOL,
72 AD1938_DAC_R4_VOL, 0, 0xFF, 1),
73
74 /* ADC switch control */
75 SOC_DOUBLE("ADC1 Switch", AD1938_ADC_CTRL0, AD1938_ADCL1_MUTE,
76 AD1938_ADCR1_MUTE, 1, 1),
77 SOC_DOUBLE("ADC2 Switch", AD1938_ADC_CTRL0, AD1938_ADCL2_MUTE,
78 AD1938_ADCR2_MUTE, 1, 1),
79
80 /* DAC switch control */
81 SOC_DOUBLE("DAC1 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL1_MUTE,
82 AD1938_DACR1_MUTE, 1, 1),
83 SOC_DOUBLE("DAC2 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL2_MUTE,
84 AD1938_DACR2_MUTE, 1, 1),
85 SOC_DOUBLE("DAC3 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL3_MUTE,
86 AD1938_DACR3_MUTE, 1, 1),
87 SOC_DOUBLE("DAC4 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL4_MUTE,
88 AD1938_DACR4_MUTE, 1, 1),
89
90 /* ADC high-pass filter */
91 SOC_SINGLE("ADC High Pass Filter Switch", AD1938_ADC_CTRL0,
92 AD1938_ADC_HIGHPASS_FILTER, 1, 0),
93
94 /* DAC de-emphasis */
95 SOC_ENUM("Playback Deemphasis", ad1938_deemp_enum),
96};
97
98static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
99 SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1),
100 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
101 SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0),
102};
103
104static const struct snd_soc_dapm_route audio_paths[] = {
105 { "DAC", NULL, "ADC_PWR" },
106 { "ADC", NULL, "ADC_PWR" },
107};
108
109/*
110 * DAI ops entries
111 */
112
113static int ad1938_mute(struct snd_soc_dai *dai, int mute)
114{
115 struct snd_soc_codec *codec = dai->codec;
116 int reg;
117
118 reg = codec->read(codec, AD1938_DAC_CTRL2);
119 reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg &
120 (~AD1938_DAC_MASTER_MUTE);
121 codec->write(codec, AD1938_DAC_CTRL2, reg);
122
123 return 0;
124}
125
126static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd)
127{
128 int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0);
129 reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg |
130 AD1938_PLL_POWERDOWN;
131 codec->write(codec, AD1938_PLL_CLK_CTRL0, reg);
132
133 return 0;
134}
135
136static int ad1938_set_tdm_slot(struct snd_soc_dai *dai,
137 unsigned int mask, int slots)
138{
139 struct snd_soc_codec *codec = dai->codec;
140 int dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
141 int adc_reg = codec->read(codec, AD1938_ADC_CTRL2);
142
143 dac_reg &= ~AD1938_DAC_CHAN_MASK;
144 adc_reg &= ~AD1938_ADC_CHAN_MASK;
145
146 switch (slots) {
147 case 2:
148 dac_reg |= AD1938_DAC_2_CHANNELS << AD1938_DAC_CHAN_SHFT;
149 adc_reg |= AD1938_ADC_2_CHANNELS << AD1938_ADC_CHAN_SHFT;
150 break;
151 case 4:
152 dac_reg |= AD1938_DAC_4_CHANNELS << AD1938_DAC_CHAN_SHFT;
153 adc_reg |= AD1938_ADC_4_CHANNELS << AD1938_ADC_CHAN_SHFT;
154 break;
155 case 8:
156 dac_reg |= AD1938_DAC_8_CHANNELS << AD1938_DAC_CHAN_SHFT;
157 adc_reg |= AD1938_ADC_8_CHANNELS << AD1938_ADC_CHAN_SHFT;
158 break;
159 case 16:
160 dac_reg |= AD1938_DAC_16_CHANNELS << AD1938_DAC_CHAN_SHFT;
161 adc_reg |= AD1938_ADC_16_CHANNELS << AD1938_ADC_CHAN_SHFT;
162 break;
163 default:
164 return -EINVAL;
165 }
166
167 codec->write(codec, AD1938_DAC_CTRL1, dac_reg);
168 codec->write(codec, AD1938_ADC_CTRL2, adc_reg);
169
170 return 0;
171}
172
173static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,
174 unsigned int fmt)
175{
176 struct snd_soc_codec *codec = codec_dai->codec;
177 int adc_reg, dac_reg;
178
179 adc_reg = codec->read(codec, AD1938_ADC_CTRL2);
180 dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
181
182 /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
183 * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
184 */
185 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
186 case SND_SOC_DAIFMT_I2S:
187 adc_reg &= ~AD1938_ADC_SERFMT_MASK;
188 adc_reg |= AD1938_ADC_SERFMT_TDM;
189 break;
190 case SND_SOC_DAIFMT_DSP_A:
191 adc_reg &= ~AD1938_ADC_SERFMT_MASK;
192 adc_reg |= AD1938_ADC_SERFMT_AUX;
193 break;
194 default:
195 return -EINVAL;
196 }
197
198 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
199 case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
200 adc_reg &= ~AD1938_ADC_LEFT_HIGH;
201 adc_reg &= ~AD1938_ADC_BCLK_INV;
202 dac_reg &= ~AD1938_DAC_LEFT_HIGH;
203 dac_reg &= ~AD1938_DAC_BCLK_INV;
204 break;
205 case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
206 adc_reg |= AD1938_ADC_LEFT_HIGH;
207 adc_reg &= ~AD1938_ADC_BCLK_INV;
208 dac_reg |= AD1938_DAC_LEFT_HIGH;
209 dac_reg &= ~AD1938_DAC_BCLK_INV;
210 break;
211 case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
212 adc_reg &= ~AD1938_ADC_LEFT_HIGH;
213 adc_reg |= AD1938_ADC_BCLK_INV;
214 dac_reg &= ~AD1938_DAC_LEFT_HIGH;
215 dac_reg |= AD1938_DAC_BCLK_INV;
216 break;
217
218 case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
219 adc_reg |= AD1938_ADC_LEFT_HIGH;
220 adc_reg |= AD1938_ADC_BCLK_INV;
221 dac_reg |= AD1938_DAC_LEFT_HIGH;
222 dac_reg |= AD1938_DAC_BCLK_INV;
223 break;
224 default:
225 return -EINVAL;
226 }
227
228 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
229 case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
230 adc_reg |= AD1938_ADC_LCR_MASTER;
231 adc_reg |= AD1938_ADC_BCLK_MASTER;
232 dac_reg |= AD1938_DAC_LCR_MASTER;
233 dac_reg |= AD1938_DAC_BCLK_MASTER;
234 break;
235 case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
236 adc_reg |= AD1938_ADC_LCR_MASTER;
237 adc_reg &= ~AD1938_ADC_BCLK_MASTER;
238 dac_reg |= AD1938_DAC_LCR_MASTER;
239 dac_reg &= ~AD1938_DAC_BCLK_MASTER;
240 break;
241 case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
242 adc_reg &= ~AD1938_ADC_LCR_MASTER;
243 adc_reg |= AD1938_ADC_BCLK_MASTER;
244 dac_reg &= ~AD1938_DAC_LCR_MASTER;
245 dac_reg |= AD1938_DAC_BCLK_MASTER;
246 break;
247 case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
248 adc_reg &= ~AD1938_ADC_LCR_MASTER;
249 adc_reg &= ~AD1938_ADC_BCLK_MASTER;
250 dac_reg &= ~AD1938_DAC_LCR_MASTER;
251 dac_reg &= ~AD1938_DAC_BCLK_MASTER;
252 break;
253 default:
254 return -EINVAL;
255 }
256
257 codec->write(codec, AD1938_ADC_CTRL2, adc_reg);
258 codec->write(codec, AD1938_DAC_CTRL1, dac_reg);
259
260 return 0;
261}
262
263static int ad1938_hw_params(struct snd_pcm_substream *substream,
264 struct snd_pcm_hw_params *params,
265 struct snd_soc_dai *dai)
266{
267 int word_len = 0, reg = 0;
268
269 struct snd_soc_pcm_runtime *rtd = substream->private_data;
270 struct snd_soc_device *socdev = rtd->socdev;
271 struct snd_soc_codec *codec = socdev->card->codec;
272
273 /* bit size */
274 switch (params_format(params)) {
275 case SNDRV_PCM_FORMAT_S16_LE:
276 word_len = 3;
277 break;
278 case SNDRV_PCM_FORMAT_S20_3LE:
279 word_len = 1;
280 break;
281 case SNDRV_PCM_FORMAT_S24_LE:
282 case SNDRV_PCM_FORMAT_S32_LE:
283 word_len = 0;
284 break;
285 }
286
287 reg = codec->read(codec, AD1938_DAC_CTRL2);
288 reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len;
289 codec->write(codec, AD1938_DAC_CTRL2, reg);
290
291 reg = codec->read(codec, AD1938_ADC_CTRL1);
292 reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len;
293 codec->write(codec, AD1938_ADC_CTRL1, reg);
294
295 return 0;
296}
297
298static int ad1938_set_bias_level(struct snd_soc_codec *codec,
299 enum snd_soc_bias_level level)
300{
301 switch (level) {
302 case SND_SOC_BIAS_ON:
303 ad1938_pll_powerctrl(codec, 1);
304 break;
305 case SND_SOC_BIAS_PREPARE:
306 break;
307 case SND_SOC_BIAS_STANDBY:
308 case SND_SOC_BIAS_OFF:
309 ad1938_pll_powerctrl(codec, 0);
310 break;
311 }
312 codec->bias_level = level;
313 return 0;
314}
315
316/*
317 * interface to read/write ad1938 register
318 */
319
320#define AD1938_SPI_ADDR 0x4
321#define AD1938_SPI_READ 0x1
322#define AD1938_SPI_BUFLEN 3
323
324/*
325 * write to the ad1938 register space
326 */
327
328static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg,
329 unsigned int value)
330{
331 u8 *reg_cache = codec->reg_cache;
332 int ret = 0;
333
334 if (value != reg_cache[reg]) {
335 uint8_t buf[AD1938_SPI_BUFLEN];
336 struct spi_transfer t = {
337 .tx_buf = buf,
338 .len = AD1938_SPI_BUFLEN,
339 };
340 struct spi_message m;
341
342 buf[0] = AD1938_SPI_ADDR << 1;
343 buf[1] = reg;
344 buf[2] = value;
345 spi_message_init(&m);
346 spi_message_add_tail(&t, &m);
347 ret = spi_sync(codec->control_data, &m);
348 if (ret == 0)
349 reg_cache[reg] = value;
350 }
351
352 return ret;
353}
354
355/*
356 * read from the ad1938 register space cache
357 */
358
359static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec,
360 unsigned int reg)
361{
362 u8 *reg_cache = codec->reg_cache;
363
364 if (reg >= codec->reg_cache_size)
365 return -EINVAL;
366
367 return reg_cache[reg];
368}
369
370/*
371 * read from the ad1938 register space
372 */
373
374static unsigned int ad1938_read_reg(struct snd_soc_codec *codec,
375 unsigned int reg)
376{
377 char w_buf[AD1938_SPI_BUFLEN];
378 char r_buf[AD1938_SPI_BUFLEN];
379 int ret;
380
381 struct spi_transfer t = {
382 .tx_buf = w_buf,
383 .rx_buf = r_buf,
384 .len = AD1938_SPI_BUFLEN,
385 };
386 struct spi_message m;
387
388 w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ;
389 w_buf[1] = reg;
390 w_buf[2] = 0;
391
392 spi_message_init(&m);
393 spi_message_add_tail(&t, &m);
394 ret = spi_sync(codec->control_data, &m);
395 if (ret == 0)
396 return r_buf[2];
397 else
398 return -EIO;
399}
400
401static int ad1938_fill_cache(struct snd_soc_codec *codec)
402{
403 int i;
404 u8 *reg_cache = codec->reg_cache;
405 struct spi_device *spi = codec->control_data;
406
407 for (i = 0; i < codec->reg_cache_size; i++) {
408 int ret = ad1938_read_reg(codec, i);
409 if (ret == -EIO) {
410 dev_err(&spi->dev, "AD1938 SPI read failure\n");
411 return ret;
412 }
413 reg_cache[i] = ret;
414 }
415
416 return 0;
417}
418
419static int __devinit ad1938_spi_probe(struct spi_device *spi)
420{
421 struct snd_soc_codec *codec;
422 struct ad1938_priv *ad1938;
423
424 ad1938 = kzalloc(sizeof(struct ad1938_priv), GFP_KERNEL);
425 if (ad1938 == NULL)
426 return -ENOMEM;
427
428 codec = &ad1938->codec;
429 codec->control_data = spi;
430 codec->dev = &spi->dev;
431
432 dev_set_drvdata(&spi->dev, ad1938);
433
434 return ad1938_register(ad1938);
435}
436
437static int __devexit ad1938_spi_remove(struct spi_device *spi)
438{
439 struct ad1938_priv *ad1938 = dev_get_drvdata(&spi->dev);
440
441 ad1938_unregister(ad1938);
442 return 0;
443}
444
445static struct spi_driver ad1938_spi_driver = {
446 .driver = {
447 .name = "ad1938-spi",
448 .bus = &spi_bus_type,
449 .owner = THIS_MODULE,
450 },
451 .probe = ad1938_spi_probe,
452 .remove = __devexit_p(ad1938_spi_remove),
453};
454
455static struct snd_soc_dai_ops ad1938_dai_ops = {
456 .hw_params = ad1938_hw_params,
457 .digital_mute = ad1938_mute,
458 .set_tdm_slot = ad1938_set_tdm_slot,
459 .set_fmt = ad1938_set_dai_fmt,
460};
461
462/* codec DAI instance */
463struct snd_soc_dai ad1938_dai = {
464 .name = "AD1938",
465 .playback = {
466 .stream_name = "Playback",
467 .channels_min = 2,
468 .channels_max = 8,
469 .rates = SNDRV_PCM_RATE_48000,
470 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
471 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
472 },
473 .capture = {
474 .stream_name = "Capture",
475 .channels_min = 2,
476 .channels_max = 4,
477 .rates = SNDRV_PCM_RATE_48000,
478 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
479 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
480 },
481 .ops = &ad1938_dai_ops,
482};
483EXPORT_SYMBOL_GPL(ad1938_dai);
484
485static int ad1938_register(struct ad1938_priv *ad1938)
486{
487 int ret;
488 struct snd_soc_codec *codec = &ad1938->codec;
489
490 if (ad1938_codec) {
491 dev_err(codec->dev, "Another ad1938 is registered\n");
492 return -EINVAL;
493 }
494
495 mutex_init(&codec->mutex);
496 INIT_LIST_HEAD(&codec->dapm_widgets);
497 INIT_LIST_HEAD(&codec->dapm_paths);
498 codec->private_data = ad1938;
499 codec->reg_cache = ad1938->reg_cache;
500 codec->reg_cache_size = AD1938_NUM_REGS;
501 codec->name = "AD1938";
502 codec->owner = THIS_MODULE;
503 codec->dai = &ad1938_dai;
504 codec->num_dai = 1;
505 codec->write = ad1938_write_reg;
506 codec->read = ad1938_read_reg_cache;
507 INIT_LIST_HEAD(&codec->dapm_widgets);
508 INIT_LIST_HEAD(&codec->dapm_paths);
509
510 ad1938_dai.dev = codec->dev;
511 ad1938_codec = codec;
512
513 /* default setting for ad1938 */
514
515 /* unmute dac channels */
516 codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0);
517 /* de-emphasis: 48kHz, powedown dac */
518 codec->write(codec, AD1938_DAC_CTRL2, 0x1A);
519 /* powerdown dac, dac in tdm mode */
520 codec->write(codec, AD1938_DAC_CTRL0, 0x41);
521 /* high-pass filter enable */
522 codec->write(codec, AD1938_ADC_CTRL0, 0x3);
523 /* sata delay=1, adc aux mode */
524 codec->write(codec, AD1938_ADC_CTRL1, 0x43);
525 /* pll input: mclki/xi */
526 codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D);
527 codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04);
528
529 ad1938_fill_cache(codec);
530
531 ret = snd_soc_register_codec(codec);
532 if (ret != 0) {
533 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
534 return ret;
535 }
536
537 ret = snd_soc_register_dai(&ad1938_dai);
538 if (ret != 0) {
539 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
540 snd_soc_unregister_codec(codec);
541 return ret;
542 }
543
544 return 0;
545}
546
547static void ad1938_unregister(struct ad1938_priv *ad1938)
548{
549 ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF);
550 snd_soc_unregister_dai(&ad1938_dai);
551 snd_soc_unregister_codec(&ad1938->codec);
552 kfree(ad1938);
553 ad1938_codec = NULL;
554}
555
556static int ad1938_probe(struct platform_device *pdev)
557{
558 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
559 struct snd_soc_codec *codec;
560 int ret = 0;
561
562 if (ad1938_codec == NULL) {
563 dev_err(&pdev->dev, "Codec device not registered\n");
564 return -ENODEV;
565 }
566
567 socdev->card->codec = ad1938_codec;
568 codec = ad1938_codec;
569
570 /* register pcms */
571 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
572 if (ret < 0) {
573 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
574 goto pcm_err;
575 }
576
577 snd_soc_add_controls(codec, ad1938_snd_controls,
578 ARRAY_SIZE(ad1938_snd_controls));
579 snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets,
580 ARRAY_SIZE(ad1938_dapm_widgets));
581 snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
582 snd_soc_dapm_new_widgets(codec);
583
584 ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
585
586 ret = snd_soc_init_card(socdev);
587 if (ret < 0) {
588 dev_err(codec->dev, "failed to register card: %d\n", ret);
589 goto card_err;
590 }
591
592 return ret;
593
594card_err:
595 snd_soc_free_pcms(socdev);
596 snd_soc_dapm_free(socdev);
597pcm_err:
598 return ret;
599}
600
601/* power down chip */
602static int ad1938_remove(struct platform_device *pdev)
603{
604 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
605
606 snd_soc_free_pcms(socdev);
607 snd_soc_dapm_free(socdev);
608
609 return 0;
610}
611
612#ifdef CONFIG_PM
613static int ad1938_suspend(struct platform_device *pdev,
614 pm_message_t state)
615{
616 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
617 struct snd_soc_codec *codec = socdev->card->codec;
618
619 ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF);
620 return 0;
621}
622
623static int ad1938_resume(struct platform_device *pdev)
624{
625 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
626 struct snd_soc_codec *codec = socdev->card->codec;
627
628 if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
629 ad1938_set_bias_level(codec, SND_SOC_BIAS_ON);
630
631 return 0;
632}
633#else
634#define ad1938_suspend NULL
635#define ad1938_resume NULL
636#endif
637
638struct snd_soc_codec_device soc_codec_dev_ad1938 = {
639 .probe = ad1938_probe,
640 .remove = ad1938_remove,
641 .suspend = ad1938_suspend,
642 .resume = ad1938_resume,
643};
644EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938);
645
646static int __init ad1938_init(void)
647{
648 int ret;
649
650 ret = spi_register_driver(&ad1938_spi_driver);
651 if (ret != 0) {
652 printk(KERN_ERR "Failed to register ad1938 SPI driver: %d\n",
653 ret);
654 }
655
656 return ret;
657}
658module_init(ad1938_init);
659
660static void __exit ad1938_exit(void)
661{
662 spi_unregister_driver(&ad1938_spi_driver);
663}
664module_exit(ad1938_exit);
665
666MODULE_DESCRIPTION("ASoC ad1938 driver");
667MODULE_AUTHOR("Barry Song ");
668MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad1938.h b/sound/soc/codecs/ad1938.h
new file mode 100644
index 000000000000..fe3c48cd2d5b
--- /dev/null
+++ b/sound/soc/codecs/ad1938.h
@@ -0,0 +1,100 @@
1/*
2 * File: sound/soc/codecs/ad1836.h
3 * Based on:
4 * Author: Barry Song <Barry.Song@analog.com>
5 *
6 * Created: May 25, 2009
7 * Description: definitions for AD1938 registers
8 *
9 * Modified:
10 *
11 * Bugs: Enter bugs at http://blackfin.uclinux.org/
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see the file COPYING, or write
25 * to the Free Software Foundation, Inc.,
26 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 */
28
29#ifndef __AD1938_H__
30#define __AD1938_H__
31
32#define AD1938_PLL_CLK_CTRL0 0
33#define AD1938_PLL_POWERDOWN 0x01
34#define AD1938_PLL_CLK_CTRL1 1
35#define AD1938_DAC_CTRL0 2
36#define AD1938_DAC_POWERDOWN 0x01
37#define AD1938_DAC_SERFMT_MASK 0xC0
38#define AD1938_DAC_SERFMT_STEREO (0 << 6)
39#define AD1938_DAC_SERFMT_TDM (1 << 6)
40#define AD1938_DAC_CTRL1 3
41#define AD1938_DAC_2_CHANNELS 0
42#define AD1938_DAC_4_CHANNELS 1
43#define AD1938_DAC_8_CHANNELS 2
44#define AD1938_DAC_16_CHANNELS 3
45#define AD1938_DAC_CHAN_SHFT 1
46#define AD1938_DAC_CHAN_MASK (3 << AD1938_DAC_CHAN_SHFT)
47#define AD1938_DAC_LCR_MASTER (1 << 4)
48#define AD1938_DAC_BCLK_MASTER (1 << 5)
49#define AD1938_DAC_LEFT_HIGH (1 << 3)
50#define AD1938_DAC_BCLK_INV (1 << 7)
51#define AD1938_DAC_CTRL2 4
52#define AD1938_DAC_WORD_LEN_MASK 0xC
53#define AD1938_DAC_MASTER_MUTE 1
54#define AD1938_DAC_CHNL_MUTE 5
55#define AD1938_DACL1_MUTE 0
56#define AD1938_DACR1_MUTE 1
57#define AD1938_DACL2_MUTE 2
58#define AD1938_DACR2_MUTE 3
59#define AD1938_DACL3_MUTE 4
60#define AD1938_DACR3_MUTE 5
61#define AD1938_DACL4_MUTE 6
62#define AD1938_DACR4_MUTE 7
63#define AD1938_DAC_L1_VOL 6
64#define AD1938_DAC_R1_VOL 7
65#define AD1938_DAC_L2_VOL 8
66#define AD1938_DAC_R2_VOL 9
67#define AD1938_DAC_L3_VOL 10
68#define AD1938_DAC_R3_VOL 11
69#define AD1938_DAC_L4_VOL 12
70#define AD1938_DAC_R4_VOL 13
71#define AD1938_ADC_CTRL0 14
72#define AD1938_ADC_POWERDOWN 0x01
73#define AD1938_ADC_HIGHPASS_FILTER 1
74#define AD1938_ADCL1_MUTE 2
75#define AD1938_ADCR1_MUTE 3
76#define AD1938_ADCL2_MUTE 4
77#define AD1938_ADCR2_MUTE 5
78#define AD1938_ADC_CTRL1 15
79#define AD1938_ADC_SERFMT_MASK 0x60
80#define AD1938_ADC_SERFMT_STEREO (0 << 5)
81#define AD1938_ADC_SERFMT_TDM (1 << 2)
82#define AD1938_ADC_SERFMT_AUX (2 << 5)
83#define AD1938_ADC_WORD_LEN_MASK 0x3
84#define AD1938_ADC_CTRL2 16
85#define AD1938_ADC_2_CHANNELS 0
86#define AD1938_ADC_4_CHANNELS 1
87#define AD1938_ADC_8_CHANNELS 2
88#define AD1938_ADC_16_CHANNELS 3
89#define AD1938_ADC_CHAN_SHFT 4
90#define AD1938_ADC_CHAN_MASK (3 << AD1938_ADC_CHAN_SHFT)
91#define AD1938_ADC_LCR_MASTER (1 << 3)
92#define AD1938_ADC_BCLK_MASTER (1 << 6)
93#define AD1938_ADC_LEFT_HIGH (1 << 2)
94#define AD1938_ADC_BCLK_INV (1 << 1)
95
96#define AD1938_NUM_REGS 17
97
98extern struct snd_soc_dai ad1938_dai;
99extern struct snd_soc_codec_device soc_codec_dev_ad1938;
100#endif
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index a32b8226c8a4..ca1e24a8f12a 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -806,15 +806,30 @@ static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
806{ 806{
807 struct cs4270_private *cs4270 = i2c_get_clientdata(client); 807 struct cs4270_private *cs4270 = i2c_get_clientdata(client);
808 struct snd_soc_codec *codec = &cs4270->codec; 808 struct snd_soc_codec *codec = &cs4270->codec;
809 int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
810 809
811 return snd_soc_write(codec, CS4270_PWRCTL, reg); 810 return snd_soc_suspend_device(codec->dev);
812} 811}
813 812
814static int cs4270_i2c_resume(struct i2c_client *client) 813static int cs4270_i2c_resume(struct i2c_client *client)
815{ 814{
816 struct cs4270_private *cs4270 = i2c_get_clientdata(client); 815 struct cs4270_private *cs4270 = i2c_get_clientdata(client);
817 struct snd_soc_codec *codec = &cs4270->codec; 816 struct snd_soc_codec *codec = &cs4270->codec;
817
818 return snd_soc_resume_device(codec->dev);
819}
820
821static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
822{
823 struct snd_soc_codec *codec = cs4270_codec;
824 int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
825
826 return snd_soc_write(codec, CS4270_PWRCTL, reg);
827}
828
829static int cs4270_soc_resume(struct platform_device *pdev)
830{
831 struct snd_soc_codec *codec = cs4270_codec;
832 struct i2c_client *i2c_client = codec->control_data;
818 int reg; 833 int reg;
819 834
820 /* In case the device was put to hard reset during sleep, we need to 835 /* In case the device was put to hard reset during sleep, we need to
@@ -825,7 +840,7 @@ static int cs4270_i2c_resume(struct i2c_client *client)
825 for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) { 840 for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) {
826 u8 val = snd_soc_read(codec, reg); 841 u8 val = snd_soc_read(codec, reg);
827 842
828 if (i2c_smbus_write_byte_data(client, reg, val)) { 843 if (i2c_smbus_write_byte_data(i2c_client, reg, val)) {
829 dev_err(codec->dev, "i2c write failed\n"); 844 dev_err(codec->dev, "i2c write failed\n");
830 return -EIO; 845 return -EIO;
831 } 846 }
@@ -840,6 +855,8 @@ static int cs4270_i2c_resume(struct i2c_client *client)
840#else 855#else
841#define cs4270_i2c_suspend NULL 856#define cs4270_i2c_suspend NULL
842#define cs4270_i2c_resume NULL 857#define cs4270_i2c_resume NULL
858#define cs4270_soc_suspend NULL
859#define cs4270_soc_resume NULL
843#endif /* CONFIG_PM */ 860#endif /* CONFIG_PM */
844 861
845/* 862/*
@@ -868,7 +885,9 @@ static struct i2c_driver cs4270_i2c_driver = {
868 */ 885 */
869struct snd_soc_codec_device soc_codec_device_cs4270 = { 886struct snd_soc_codec_device soc_codec_device_cs4270 = {
870 .probe = cs4270_probe, 887 .probe = cs4270_probe,
871 .remove = cs4270_remove 888 .remove = cs4270_remove,
889 .suspend = cs4270_soc_suspend,
890 .resume = cs4270_soc_resume,
872}; 891};
873EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); 892EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
874 893
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
new file mode 100644
index 000000000000..38eac9c866e1
--- /dev/null
+++ b/sound/soc/codecs/cx20442.c
@@ -0,0 +1,501 @@
1/*
2 * cx20442.c -- CX20442 ALSA Soc Audio driver
3 *
4 * Copyright 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
5 *
6 * Initially based on sound/soc/codecs/wm8400.c
7 * Copyright 2008, 2009 Wolfson Microelectronics PLC.
8 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/tty.h>
17
18#include <sound/core.h>
19#include <sound/initval.h>
20#include <sound/soc-dapm.h>
21
22#include "cx20442.h"
23
24
25struct cx20442_priv {
26 struct snd_soc_codec codec;
27 u8 reg_cache[1];
28};
29
30#define CX20442_PM 0x0
31
32#define CX20442_TELIN 0
33#define CX20442_TELOUT 1
34#define CX20442_MIC 2
35#define CX20442_SPKOUT 3
36#define CX20442_AGC 4
37
38static const struct snd_soc_dapm_widget cx20442_dapm_widgets[] = {
39 SND_SOC_DAPM_OUTPUT("TELOUT"),
40 SND_SOC_DAPM_OUTPUT("SPKOUT"),
41 SND_SOC_DAPM_OUTPUT("AGCOUT"),
42
43 SND_SOC_DAPM_MIXER("SPKOUT Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
44
45 SND_SOC_DAPM_PGA("TELOUT Amp", CX20442_PM, CX20442_TELOUT, 0, NULL, 0),
46 SND_SOC_DAPM_PGA("SPKOUT Amp", CX20442_PM, CX20442_SPKOUT, 0, NULL, 0),
47 SND_SOC_DAPM_PGA("SPKOUT AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0),
48
49 SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
50 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
51
52 SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
53
54 SND_SOC_DAPM_MICBIAS("TELIN Bias", CX20442_PM, CX20442_TELIN, 0),
55 SND_SOC_DAPM_MICBIAS("MIC Bias", CX20442_PM, CX20442_MIC, 0),
56
57 SND_SOC_DAPM_PGA("MIC AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0),
58
59 SND_SOC_DAPM_INPUT("TELIN"),
60 SND_SOC_DAPM_INPUT("MIC"),
61 SND_SOC_DAPM_INPUT("AGCIN"),
62};
63
64static const struct snd_soc_dapm_route cx20442_audio_map[] = {
65 {"TELOUT", NULL, "TELOUT Amp"},
66
67 {"SPKOUT", NULL, "SPKOUT Mixer"},
68 {"SPKOUT Mixer", NULL, "SPKOUT Amp"},
69
70 {"TELOUT Amp", NULL, "DAC"},
71 {"SPKOUT Amp", NULL, "DAC"},
72
73 {"SPKOUT Mixer", NULL, "SPKOUT AGC"},
74 {"SPKOUT AGC", NULL, "AGCIN"},
75
76 {"AGCOUT", NULL, "MIC AGC"},
77 {"MIC AGC", NULL, "MIC"},
78
79 {"MIC Bias", NULL, "MIC"},
80 {"Input Mixer", NULL, "MIC Bias"},
81
82 {"TELIN Bias", NULL, "TELIN"},
83 {"Input Mixer", NULL, "TELIN Bias"},
84
85 {"ADC", NULL, "Input Mixer"},
86};
87
88static int cx20442_add_widgets(struct snd_soc_codec *codec)
89{
90 snd_soc_dapm_new_controls(codec, cx20442_dapm_widgets,
91 ARRAY_SIZE(cx20442_dapm_widgets));
92
93 snd_soc_dapm_add_routes(codec, cx20442_audio_map,
94 ARRAY_SIZE(cx20442_audio_map));
95
96 snd_soc_dapm_new_widgets(codec);
97 return 0;
98}
99
100static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
101 unsigned int reg)
102{
103 u8 *reg_cache = codec->reg_cache;
104
105 if (reg >= codec->reg_cache_size)
106 return -EINVAL;
107
108 return reg_cache[reg];
109}
110
111enum v253_vls {
112 V253_VLS_NONE = 0,
113 V253_VLS_T,
114 V253_VLS_L,
115 V253_VLS_LT,
116 V253_VLS_S,
117 V253_VLS_ST,
118 V253_VLS_M,
119 V253_VLS_MST,
120 V253_VLS_S1,
121 V253_VLS_S1T,
122 V253_VLS_MS1T,
123 V253_VLS_M1,
124 V253_VLS_M1ST,
125 V253_VLS_M1S1T,
126 V253_VLS_H,
127 V253_VLS_HT,
128 V253_VLS_MS,
129 V253_VLS_MS1,
130 V253_VLS_M1S,
131 V253_VLS_M1S1,
132 V253_VLS_TEST,
133};
134
135static int cx20442_pm_to_v253_vls(u8 value)
136{
137 switch (value & ~(1 << CX20442_AGC)) {
138 case 0:
139 return V253_VLS_T;
140 case (1 << CX20442_SPKOUT):
141 case (1 << CX20442_MIC):
142 case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC):
143 return V253_VLS_M1S1;
144 case (1 << CX20442_TELOUT):
145 case (1 << CX20442_TELIN):
146 case (1 << CX20442_TELOUT) | (1 << CX20442_TELIN):
147 return V253_VLS_L;
148 case (1 << CX20442_TELOUT) | (1 << CX20442_MIC):
149 return V253_VLS_NONE;
150 }
151 return -EINVAL;
152}
153static int cx20442_pm_to_v253_vsp(u8 value)
154{
155 switch (value & ~(1 << CX20442_AGC)) {
156 case (1 << CX20442_SPKOUT):
157 case (1 << CX20442_MIC):
158 case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC):
159 return (bool)(value & (1 << CX20442_AGC));
160 }
161 return (value & (1 << CX20442_AGC)) ? -EINVAL : 0;
162}
163
164static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
165 unsigned int value)
166{
167 u8 *reg_cache = codec->reg_cache;
168 int vls, vsp, old, len;
169 char buf[18];
170
171 if (reg >= codec->reg_cache_size)
172 return -EINVAL;
173
174 /* hw_write and control_data pointers required for talking to the modem
175 * are expected to be set by the line discipline initialization code */
176 if (!codec->hw_write || !codec->control_data)
177 return -EIO;
178
179 old = reg_cache[reg];
180 reg_cache[reg] = value;
181
182 vls = cx20442_pm_to_v253_vls(value);
183 if (vls < 0)
184 return vls;
185
186 vsp = cx20442_pm_to_v253_vsp(value);
187 if (vsp < 0)
188 return vsp;
189
190 if ((vls == V253_VLS_T) ||
191 (vls == cx20442_pm_to_v253_vls(old))) {
192 if (vsp == cx20442_pm_to_v253_vsp(old))
193 return 0;
194 len = snprintf(buf, ARRAY_SIZE(buf), "at+vsp=%d\r", vsp);
195 } else if (vsp == cx20442_pm_to_v253_vsp(old))
196 len = snprintf(buf, ARRAY_SIZE(buf), "at+vls=%d\r", vls);
197 else
198 len = snprintf(buf, ARRAY_SIZE(buf),
199 "at+vls=%d;+vsp=%d\r", vls, vsp);
200
201 if (unlikely(len > (ARRAY_SIZE(buf) - 1)))
202 return -ENOMEM;
203
204 dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
205 if (codec->hw_write(codec->control_data, buf, len) != len)
206 return -EIO;
207
208 return 0;
209}
210
211
212/* Moved up here as line discipline referres it during initialization */
213static struct snd_soc_codec *cx20442_codec;
214
215
216/*
217 * Line discpline related code
218 *
219 * Any of the callback functions below can be used in two ways:
220 * 1) registerd by a machine driver as one of line discipline operations,
221 * 2) called from a machine's provided line discipline callback function
222 * in case when extra machine specific code must be run as well.
223 */
224
225/* Modem init: echo off, digital speaker off, quiet off, voice mode */
226static const char *v253_init = "ate0m0q0+fclass=8\r";
227
228/* Line discipline .open() */
229static int v253_open(struct tty_struct *tty)
230{
231 struct snd_soc_codec *codec = cx20442_codec;
232 int ret, len = strlen(v253_init);
233
234 /* Doesn't make sense without write callback */
235 if (!tty->ops->write)
236 return -EINVAL;
237
238 /* Pass the codec structure address for use by other ldisc callbacks */
239 tty->disc_data = codec;
240
241 if (tty->ops->write(tty, v253_init, len) != len) {
242 ret = -EIO;
243 goto err;
244 }
245 /* Actual setup will be performed after the modem responds. */
246 return 0;
247err:
248 tty->disc_data = NULL;
249 return ret;
250}
251
252/* Line discipline .close() */
253static void v253_close(struct tty_struct *tty)
254{
255 struct snd_soc_codec *codec = tty->disc_data;
256
257 tty->disc_data = NULL;
258
259 if (!codec)
260 return;
261
262 /* Prevent the codec driver from further accessing the modem */
263 codec->hw_write = NULL;
264 codec->control_data = NULL;
265 codec->pop_time = 0;
266}
267
268/* Line discipline .hangup() */
269static int v253_hangup(struct tty_struct *tty)
270{
271 v253_close(tty);
272 return 0;
273}
274
275/* Line discipline .receive_buf() */
276static void v253_receive(struct tty_struct *tty,
277 const unsigned char *cp, char *fp, int count)
278{
279 struct snd_soc_codec *codec = tty->disc_data;
280
281 if (!codec)
282 return;
283
284 if (!codec->control_data) {
285 /* First modem response, complete setup procedure */
286
287 /* Set up codec driver access to modem controls */
288 codec->control_data = tty;
289 codec->hw_write = (hw_write_t)tty->ops->write;
290 codec->pop_time = 1;
291 }
292}
293
294/* Line discipline .write_wakeup() */
295static void v253_wakeup(struct tty_struct *tty)
296{
297}
298
299struct tty_ldisc_ops v253_ops = {
300 .magic = TTY_LDISC_MAGIC,
301 .name = "cx20442",
302 .owner = THIS_MODULE,
303 .open = v253_open,
304 .close = v253_close,
305 .hangup = v253_hangup,
306 .receive_buf = v253_receive,
307 .write_wakeup = v253_wakeup,
308};
309EXPORT_SYMBOL_GPL(v253_ops);
310
311
312/*
313 * Codec DAI
314 */
315
316struct snd_soc_dai cx20442_dai = {
317 .name = "CX20442",
318 .playback = {
319 .stream_name = "Playback",
320 .channels_min = 1,
321 .channels_max = 1,
322 .rates = SNDRV_PCM_RATE_8000,
323 .formats = SNDRV_PCM_FMTBIT_S16_LE,
324 },
325 .capture = {
326 .stream_name = "Capture",
327 .channels_min = 1,
328 .channels_max = 1,
329 .rates = SNDRV_PCM_RATE_8000,
330 .formats = SNDRV_PCM_FMTBIT_S16_LE,
331 },
332};
333EXPORT_SYMBOL_GPL(cx20442_dai);
334
335static int cx20442_codec_probe(struct platform_device *pdev)
336{
337 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
338 struct snd_soc_codec *codec;
339 int ret;
340
341 if (!cx20442_codec) {
342 dev_err(&pdev->dev, "cx20442 not yet discovered\n");
343 return -ENODEV;
344 }
345 codec = cx20442_codec;
346
347 socdev->card->codec = codec;
348
349 /* register pcms */
350 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
351 if (ret < 0) {
352 dev_err(&pdev->dev, "failed to create pcms\n");
353 goto pcm_err;
354 }
355
356 cx20442_add_widgets(codec);
357
358 ret = snd_soc_init_card(socdev);
359 if (ret < 0) {
360 dev_err(&pdev->dev, "failed to register card\n");
361 goto card_err;
362 }
363
364 return ret;
365
366card_err:
367 snd_soc_free_pcms(socdev);
368 snd_soc_dapm_free(socdev);
369pcm_err:
370 return ret;
371}
372
373/* power down chip */
374static int cx20442_codec_remove(struct platform_device *pdev)
375{
376 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
377
378 snd_soc_free_pcms(socdev);
379 snd_soc_dapm_free(socdev);
380
381 return 0;
382}
383
384struct snd_soc_codec_device cx20442_codec_dev = {
385 .probe = cx20442_codec_probe,
386 .remove = cx20442_codec_remove,
387};
388EXPORT_SYMBOL_GPL(cx20442_codec_dev);
389
390static int cx20442_register(struct cx20442_priv *cx20442)
391{
392 struct snd_soc_codec *codec = &cx20442->codec;
393 int ret;
394
395 mutex_init(&codec->mutex);
396 INIT_LIST_HEAD(&codec->dapm_widgets);
397 INIT_LIST_HEAD(&codec->dapm_paths);
398
399 codec->name = "CX20442";
400 codec->owner = THIS_MODULE;
401 codec->private_data = cx20442;
402
403 codec->dai = &cx20442_dai;
404 codec->num_dai = 1;
405
406 codec->reg_cache = &cx20442->reg_cache;
407 codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache);
408 codec->read = cx20442_read_reg_cache;
409 codec->write = cx20442_write;
410
411 codec->bias_level = SND_SOC_BIAS_OFF;
412
413 cx20442_dai.dev = codec->dev;
414
415 cx20442_codec = codec;
416
417 ret = snd_soc_register_codec(codec);
418 if (ret != 0) {
419 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
420 goto err;
421 }
422
423 ret = snd_soc_register_dai(&cx20442_dai);
424 if (ret != 0) {
425 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
426 goto err_codec;
427 }
428
429 return 0;
430
431err_codec:
432 snd_soc_unregister_codec(codec);
433err:
434 cx20442_codec = NULL;
435 kfree(cx20442);
436 return ret;
437}
438
439static void cx20442_unregister(struct cx20442_priv *cx20442)
440{
441 snd_soc_unregister_dai(&cx20442_dai);
442 snd_soc_unregister_codec(&cx20442->codec);
443
444 cx20442_codec = NULL;
445 kfree(cx20442);
446}
447
448static int cx20442_platform_probe(struct platform_device *pdev)
449{
450 struct cx20442_priv *cx20442;
451 struct snd_soc_codec *codec;
452
453 cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
454 if (cx20442 == NULL)
455 return -ENOMEM;
456
457 codec = &cx20442->codec;
458
459 codec->control_data = NULL;
460 codec->hw_write = NULL;
461 codec->pop_time = 0;
462
463 codec->dev = &pdev->dev;
464 platform_set_drvdata(pdev, cx20442);
465
466 return cx20442_register(cx20442);
467}
468
469static int __exit cx20442_platform_remove(struct platform_device *pdev)
470{
471 struct cx20442_priv *cx20442 = platform_get_drvdata(pdev);
472
473 cx20442_unregister(cx20442);
474 return 0;
475}
476
477static struct platform_driver cx20442_platform_driver = {
478 .driver = {
479 .name = "cx20442",
480 .owner = THIS_MODULE,
481 },
482 .probe = cx20442_platform_probe,
483 .remove = __exit_p(cx20442_platform_remove),
484};
485
486static int __init cx20442_init(void)
487{
488 return platform_driver_register(&cx20442_platform_driver);
489}
490module_init(cx20442_init);
491
492static void __exit cx20442_exit(void)
493{
494 platform_driver_unregister(&cx20442_platform_driver);
495}
496module_exit(cx20442_exit);
497
498MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
499MODULE_AUTHOR("Janusz Krzysztofik");
500MODULE_LICENSE("GPL");
501MODULE_ALIAS("platform:cx20442");
diff --git a/sound/soc/codecs/cx20442.h b/sound/soc/codecs/cx20442.h
new file mode 100644
index 000000000000..688a5eb62e17
--- /dev/null
+++ b/sound/soc/codecs/cx20442.h
@@ -0,0 +1,20 @@
1/*
2 * cx20442.h -- audio driver for CX20442
3 *
4 * Copyright 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
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; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 */
12
13#ifndef _CX20442_CODEC_H
14#define _CX20442_CODEC_H
15
16extern struct snd_soc_dai cx20442_dai;
17extern struct snd_soc_codec_device cx20442_codec_dev;
18extern struct tty_ldisc_ops v253_ops;
19
20#endif
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
new file mode 100644
index 000000000000..9e7e964a5fa3
--- /dev/null
+++ b/sound/soc/codecs/max9877.c
@@ -0,0 +1,308 @@
1/*
2 * max9877.c -- amp driver for max9877
3 *
4 * Copyright (C) 2009 Samsung Electronics Co.Ltd
5 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/i2c.h>
17#include <sound/soc.h>
18#include <sound/tlv.h>
19
20#include "max9877.h"
21
22static struct i2c_client *i2c;
23
24static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 };
25
26static void max9877_write_regs(void)
27{
28 unsigned int i;
29 u8 data[6];
30
31 data[0] = MAX9877_INPUT_MODE;
32 for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
33 data[i + 1] = max9877_regs[i];
34
35 if (i2c_master_send(i2c, data, 6) != 6)
36 dev_err(&i2c->dev, "i2c write failed\n");
37}
38
39static int max9877_get_reg(struct snd_kcontrol *kcontrol,
40 struct snd_ctl_elem_value *ucontrol)
41{
42 struct soc_mixer_control *mc =
43 (struct soc_mixer_control *)kcontrol->private_value;
44 unsigned int reg = mc->reg;
45 unsigned int shift = mc->shift;
46 unsigned int mask = mc->max;
47 unsigned int invert = mc->invert;
48
49 ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask;
50
51 if (invert)
52 ucontrol->value.integer.value[0] =
53 mask - ucontrol->value.integer.value[0];
54
55 return 0;
56}
57
58static int max9877_set_reg(struct snd_kcontrol *kcontrol,
59 struct snd_ctl_elem_value *ucontrol)
60{
61 struct soc_mixer_control *mc =
62 (struct soc_mixer_control *)kcontrol->private_value;
63 unsigned int reg = mc->reg;
64 unsigned int shift = mc->shift;
65 unsigned int mask = mc->max;
66 unsigned int invert = mc->invert;
67 unsigned int val = (ucontrol->value.integer.value[0] & mask);
68
69 if (invert)
70 val = mask - val;
71
72 if (((max9877_regs[reg] >> shift) & mask) == val)
73 return 0;
74
75 max9877_regs[reg] &= ~(mask << shift);
76 max9877_regs[reg] |= val << shift;
77 max9877_write_regs();
78
79 return 1;
80}
81
82static int max9877_get_2reg(struct snd_kcontrol *kcontrol,
83 struct snd_ctl_elem_value *ucontrol)
84{
85 struct soc_mixer_control *mc =
86 (struct soc_mixer_control *)kcontrol->private_value;
87 unsigned int reg = mc->reg;
88 unsigned int reg2 = mc->rreg;
89 unsigned int shift = mc->shift;
90 unsigned int mask = mc->max;
91
92 ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask;
93 ucontrol->value.integer.value[1] = (max9877_regs[reg2] >> shift) & mask;
94
95 return 0;
96}
97
98static int max9877_set_2reg(struct snd_kcontrol *kcontrol,
99 struct snd_ctl_elem_value *ucontrol)
100{
101 struct soc_mixer_control *mc =
102 (struct soc_mixer_control *)kcontrol->private_value;
103 unsigned int reg = mc->reg;
104 unsigned int reg2 = mc->rreg;
105 unsigned int shift = mc->shift;
106 unsigned int mask = mc->max;
107 unsigned int val = (ucontrol->value.integer.value[0] & mask);
108 unsigned int val2 = (ucontrol->value.integer.value[1] & mask);
109 unsigned int change = 1;
110
111 if (((max9877_regs[reg] >> shift) & mask) == val)
112 change = 0;
113
114 if (((max9877_regs[reg2] >> shift) & mask) == val2)
115 change = 0;
116
117 if (change) {
118 max9877_regs[reg] &= ~(mask << shift);
119 max9877_regs[reg] |= val << shift;
120 max9877_regs[reg2] &= ~(mask << shift);
121 max9877_regs[reg2] |= val2 << shift;
122 max9877_write_regs();
123 }
124
125 return change;
126}
127
128static int max9877_get_out_mode(struct snd_kcontrol *kcontrol,
129 struct snd_ctl_elem_value *ucontrol)
130{
131 u8 value = max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK;
132
133 if (value)
134 value -= 1;
135
136 ucontrol->value.integer.value[0] = value;
137 return 0;
138}
139
140static int max9877_set_out_mode(struct snd_kcontrol *kcontrol,
141 struct snd_ctl_elem_value *ucontrol)
142{
143 u8 value = ucontrol->value.integer.value[0];
144
145 value += 1;
146
147 if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value)
148 return 0;
149
150 max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OUTMODE_MASK;
151 max9877_regs[MAX9877_OUTPUT_MODE] |= value;
152 max9877_write_regs();
153 return 1;
154}
155
156static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol,
157 struct snd_ctl_elem_value *ucontrol)
158{
159 u8 value = (max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK);
160
161 value = value >> MAX9877_OSC_OFFSET;
162
163 ucontrol->value.integer.value[0] = value;
164 return 0;
165}
166
167static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol,
168 struct snd_ctl_elem_value *ucontrol)
169{
170 u8 value = ucontrol->value.integer.value[0];
171
172 value = value << MAX9877_OSC_OFFSET;
173 if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value)
174 return 0;
175
176 max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OSC_MASK;
177 max9877_regs[MAX9877_OUTPUT_MODE] |= value;
178 max9877_write_regs();
179 return 1;
180}
181
182static const unsigned int max9877_pgain_tlv[] = {
183 TLV_DB_RANGE_HEAD(2),
184 0, 1, TLV_DB_SCALE_ITEM(0, 900, 0),
185 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0),
186};
187
188static const unsigned int max9877_output_tlv[] = {
189 TLV_DB_RANGE_HEAD(4),
190 0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
191 8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
192 16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
193 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0),
194};
195
196static const char *max9877_out_mode[] = {
197 "INA -> SPK",
198 "INA -> HP",
199 "INA -> SPK and HP",
200 "INB -> SPK",
201 "INB -> HP",
202 "INB -> SPK and HP",
203 "INA + INB -> SPK",
204 "INA + INB -> HP",
205 "INA + INB -> SPK and HP",
206};
207
208static const char *max9877_osc_mode[] = {
209 "1176KHz",
210 "1100KHz",
211 "700KHz",
212};
213
214static const struct soc_enum max9877_enum[] = {
215 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode),
216 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
217};
218
219static const struct snd_kcontrol_new max9877_controls[] = {
220 SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume",
221 MAX9877_INPUT_MODE, 0, 2, 0,
222 max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
223 SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume",
224 MAX9877_INPUT_MODE, 2, 2, 0,
225 max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
226 SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume",
227 MAX9877_SPK_VOLUME, 0, 31, 0,
228 max9877_get_reg, max9877_set_reg, max9877_output_tlv),
229 SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume",
230 MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
231 max9877_get_2reg, max9877_set_2reg, max9877_output_tlv),
232 SOC_SINGLE_EXT("MAX9877 INB Stereo Switch",
233 MAX9877_INPUT_MODE, 4, 1, 1,
234 max9877_get_reg, max9877_set_reg),
235 SOC_SINGLE_EXT("MAX9877 INA Stereo Switch",
236 MAX9877_INPUT_MODE, 5, 1, 1,
237 max9877_get_reg, max9877_set_reg),
238 SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch",
239 MAX9877_INPUT_MODE, 6, 1, 0,
240 max9877_get_reg, max9877_set_reg),
241 SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch",
242 MAX9877_OUTPUT_MODE, 6, 1, 0,
243 max9877_get_reg, max9877_set_reg),
244 SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch",
245 MAX9877_OUTPUT_MODE, 7, 1, 1,
246 max9877_get_reg, max9877_set_reg),
247 SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0],
248 max9877_get_out_mode, max9877_set_out_mode),
249 SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1],
250 max9877_get_osc_mode, max9877_set_osc_mode),
251};
252
253/* This function is called from ASoC machine driver */
254int max9877_add_controls(struct snd_soc_codec *codec)
255{
256 return snd_soc_add_controls(codec, max9877_controls,
257 ARRAY_SIZE(max9877_controls));
258}
259EXPORT_SYMBOL_GPL(max9877_add_controls);
260
261static int __devinit max9877_i2c_probe(struct i2c_client *client,
262 const struct i2c_device_id *id)
263{
264 i2c = client;
265
266 max9877_write_regs();
267
268 return 0;
269}
270
271static __devexit int max9877_i2c_remove(struct i2c_client *client)
272{
273 i2c = NULL;
274
275 return 0;
276}
277
278static const struct i2c_device_id max9877_i2c_id[] = {
279 { "max9877", 0 },
280 { }
281};
282MODULE_DEVICE_TABLE(i2c, max9877_i2c_id);
283
284static struct i2c_driver max9877_i2c_driver = {
285 .driver = {
286 .name = "max9877",
287 .owner = THIS_MODULE,
288 },
289 .probe = max9877_i2c_probe,
290 .remove = __devexit_p(max9877_i2c_remove),
291 .id_table = max9877_i2c_id,
292};
293
294static int __init max9877_init(void)
295{
296 return i2c_add_driver(&max9877_i2c_driver);
297}
298module_init(max9877_init);
299
300static void __exit max9877_exit(void)
301{
302 i2c_del_driver(&max9877_i2c_driver);
303}
304module_exit(max9877_exit);
305
306MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
307MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
308MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9877.h b/sound/soc/codecs/max9877.h
new file mode 100644
index 000000000000..6da72290ac58
--- /dev/null
+++ b/sound/soc/codecs/max9877.h
@@ -0,0 +1,37 @@
1/*
2 * max9877.h -- amp driver for max9877
3 *
4 * Copyright (C) 2009 Samsung Electronics Co.Ltd
5 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#ifndef _MAX9877_H
15#define _MAX9877_H
16
17#define MAX9877_INPUT_MODE 0x00
18#define MAX9877_SPK_VOLUME 0x01
19#define MAX9877_HPL_VOLUME 0x02
20#define MAX9877_HPR_VOLUME 0x03
21#define MAX9877_OUTPUT_MODE 0x04
22
23/* MAX9877_INPUT_MODE */
24#define MAX9877_INB (1 << 4)
25#define MAX9877_INA (1 << 5)
26#define MAX9877_ZCD (1 << 6)
27
28/* MAX9877_OUTPUT_MODE */
29#define MAX9877_OUTMODE_MASK (15 << 0)
30#define MAX9877_OSC_MASK (3 << 4)
31#define MAX9877_OSC_OFFSET 4
32#define MAX9877_BYPASS (1 << 6)
33#define MAX9877_SHDN (1 << 7)
34
35extern int max9877_add_controls(struct snd_soc_codec *codec);
36
37#endif
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index 218b33adad90..a63191141052 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -21,6 +21,8 @@
21 21
22#include "spdif_transciever.h" 22#include "spdif_transciever.h"
23 23
24MODULE_LICENSE("GPL");
25
24#define STUB_RATES SNDRV_PCM_RATE_8000_96000 26#define STUB_RATES SNDRV_PCM_RATE_8000_96000
25#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE 27#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
26 28
@@ -34,6 +36,7 @@ struct snd_soc_dai dit_stub_dai = {
34 .formats = STUB_FORMATS, 36 .formats = STUB_FORMATS,
35 }, 37 },
36}; 38};
39EXPORT_SYMBOL_GPL(dit_stub_dai);
37 40
38static int spdif_dit_probe(struct platform_device *pdev) 41static int spdif_dit_probe(struct platform_device *pdev)
39{ 42{
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 8ad4b7b3e3ba..befc6488c39a 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -149,7 +149,7 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
149 stac9766_ac97_write(codec, AC97_INT_PAGING, 1); 149 stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
150 return 0; 150 return 0;
151 } 151 }
152 if (reg / 2 > ARRAY_SIZE(stac9766_reg)) 152 if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
153 return -EIO; 153 return -EIO;
154 154
155 soc_ac97_ops.write(codec->ac97, reg, val); 155 soc_ac97_ops.write(codec->ac97, reg, val);
@@ -168,7 +168,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
168 stac9766_ac97_write(codec, AC97_INT_PAGING, 1); 168 stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
169 return val; 169 return val;
170 } 170 }
171 if (reg / 2 > ARRAY_SIZE(stac9766_reg)) 171 if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
172 return -EIO; 172 return -EIO;
173 173
174 if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || 174 if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 0cf401fec807..126b15b18aeb 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -767,6 +767,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
767 int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; 767 int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
768 u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; 768 u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
769 u16 pll_d = 1; 769 u16 pll_d = 1;
770 u8 reg;
770 771
771 /* select data word length */ 772 /* select data word length */
772 data = 773 data =
@@ -801,8 +802,16 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
801 pll_q &= 0xf; 802 pll_q &= 0xf;
802 aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); 803 aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
803 aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); 804 aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
804 } else 805 /* disable PLL if it is bypassed */
806 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
807 aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
808
809 } else {
805 aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); 810 aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
811 /* enable PLL when it is used */
812 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
813 aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
814 }
806 815
807 /* Route Left DAC to left channel input and 816 /* Route Left DAC to left channel input and
808 * right DAC to right channel input */ 817 * right DAC to right channel input */
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 0bf903f27564..b9ef4d915221 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -1022,10 +1022,15 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
1022 if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out) 1022 if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out)
1023 return 0; 1023 return 0;
1024 1024
1025 if (freq_out != 0) { 1025 if (freq_out) {
1026 ret = fll_factors(wm8400, &factors, freq_in, freq_out); 1026 ret = fll_factors(wm8400, &factors, freq_in, freq_out);
1027 if (ret != 0) 1027 if (ret != 0)
1028 return ret; 1028 return ret;
1029 } else {
1030 /* Bodge GCC 4.4.0 uninitialised variable warning - it
1031 * doesn't seem capable of working out that we exit if
1032 * freq_out is 0 before any of the uses. */
1033 memset(&factors, 0, sizeof(factors));
1029 } 1034 }
1030 1035
1031 wm8400->fll_out = freq_out; 1036 wm8400->fll_out = freq_out;
@@ -1040,7 +1045,7 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
1040 reg &= ~WM8400_FLL_OSC_ENA; 1045 reg &= ~WM8400_FLL_OSC_ENA;
1041 wm8400_write(codec, WM8400_FLL_CONTROL_1, reg); 1046 wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
1042 1047
1043 if (freq_out == 0) 1048 if (!freq_out)
1044 return 0; 1049 return 0;
1045 1050
1046 reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK); 1051 reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index bcd6a40171dc..060d5d06ba95 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -529,6 +529,7 @@ struct snd_soc_dai wm8510_dai = {
529 .rates = WM8510_RATES, 529 .rates = WM8510_RATES,
530 .formats = WM8510_FORMATS,}, 530 .formats = WM8510_FORMATS,},
531 .ops = &wm8510_dai_ops, 531 .ops = &wm8510_dai_ops,
532 .symmetric_rates = 1,
532}; 533};
533EXPORT_SYMBOL_GPL(wm8510_dai); 534EXPORT_SYMBOL_GPL(wm8510_dai);
534 535
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 6232afd907ef..2b980ccb6032 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -26,6 +26,7 @@
26#include <sound/soc.h> 26#include <sound/soc.h>
27#include <sound/soc-dapm.h> 27#include <sound/soc-dapm.h>
28#include <sound/initval.h> 28#include <sound/initval.h>
29#include <sound/tlv.h>
29 30
30#include "wm8731.h" 31#include "wm8731.h"
31 32
@@ -65,20 +66,26 @@ static const struct soc_enum wm8731_enum[] = {
65 SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph), 66 SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
66}; 67};
67 68
69static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
70static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0);
71static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
72
68static const struct snd_kcontrol_new wm8731_snd_controls[] = { 73static const struct snd_kcontrol_new wm8731_snd_controls[] = {
69 74
70SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, 75SOC_DOUBLE_R_TLV("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
71 0, 127, 0), 76 0, 127, 0, out_tlv),
72SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, 77SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
73 7, 1, 0), 78 7, 1, 0),
74 79
75SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0), 80SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0,
81 in_tlv),
76SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), 82SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
77 83
78SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0), 84SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
79SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1), 85SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1),
80 86
81SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1), 87SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
88 sidetone_tlv),
82 89
83SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1), 90SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
84SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), 91SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
@@ -409,6 +416,7 @@ struct snd_soc_dai wm8731_dai = {
409 .rates = WM8731_RATES, 416 .rates = WM8731_RATES,
410 .formats = WM8731_FORMATS,}, 417 .formats = WM8731_FORMATS,},
411 .ops = &wm8731_dai_ops, 418 .ops = &wm8731_dai_ops,
419 .symmetric_rates = 1,
412}; 420};
413EXPORT_SYMBOL_GPL(wm8731_dai); 421EXPORT_SYMBOL_GPL(wm8731_dai);
414 422
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 370f7df03628..d80d414cfbbd 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -79,7 +79,7 @@ static const u16 wm8753_reg[] = {
79 0x0097, 0x0097, 0x0000, 0x0004, 79 0x0097, 0x0097, 0x0000, 0x0004,
80 0x0000, 0x0083, 0x0024, 0x01ba, 80 0x0000, 0x0083, 0x0024, 0x01ba,
81 0x0000, 0x0083, 0x0024, 0x01ba, 81 0x0000, 0x0083, 0x0024, 0x01ba,
82 0x0000, 0x0000 82 0x0000, 0x0000, 0x0000
83}; 83};
84 84
85/* codec private data */ 85/* codec private data */
@@ -1660,11 +1660,11 @@ static int wm8753_register(struct wm8753_priv *wm8753)
1660 codec->set_bias_level = wm8753_set_bias_level; 1660 codec->set_bias_level = wm8753_set_bias_level;
1661 codec->dai = wm8753_dai; 1661 codec->dai = wm8753_dai;
1662 codec->num_dai = 2; 1662 codec->num_dai = 2;
1663 codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache); 1663 codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
1664 codec->reg_cache = &wm8753->reg_cache; 1664 codec->reg_cache = &wm8753->reg_cache;
1665 codec->private_data = wm8753; 1665 codec->private_data = wm8753;
1666 1666
1667 memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache)); 1667 memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
1668 INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); 1668 INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
1669 1669
1670 ret = wm8753_reset(codec); 1670 ret = wm8753_reset(codec);
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
new file mode 100644
index 000000000000..ee12bf824a40
--- /dev/null
+++ b/sound/soc/codecs/wm8776.c
@@ -0,0 +1,781 @@
1/*
2 * wm8776.c -- WM8776 ALSA SoC Audio driver
3 *
4 * Copyright 2009 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * TODO: Input ALC/limiter support
13 */
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/init.h>
18#include <linux/delay.h>
19#include <linux/pm.h>
20#include <linux/i2c.h>
21#include <linux/platform_device.h>
22#include <linux/spi/spi.h>
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/soc.h>
27#include <sound/soc-dapm.h>
28#include <sound/initval.h>
29#include <sound/tlv.h>
30
31#include "wm8776.h"
32
33static struct snd_soc_codec *wm8776_codec;
34struct snd_soc_codec_device soc_codec_dev_wm8776;
35
36/* codec private data */
37struct wm8776_priv {
38 struct snd_soc_codec codec;
39 u16 reg_cache[WM8776_CACHEREGNUM];
40 int sysclk[2];
41};
42
43#ifdef CONFIG_SPI_MASTER
44static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
45#endif
46
47static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
48 0x79, 0x79, 0x79, 0xff, 0xff, /* 4 */
49 0xff, 0x00, 0x90, 0x00, 0x00, /* 9 */
50 0x22, 0x22, 0x22, 0x08, 0xcf, /* 14 */
51 0xcf, 0x7b, 0x00, 0x32, 0x00, /* 19 */
52 0xa6, 0x01, 0x01
53};
54
55/*
56 * read wm8776 register cache
57 */
58static inline unsigned int wm8776_read_reg_cache(struct snd_soc_codec *codec,
59 unsigned int reg)
60{
61 u16 *cache = codec->reg_cache;
62 if (reg >= WM8776_CACHEREGNUM)
63 return -1;
64 return cache[reg];
65}
66
67/*
68 * write wm8776 register cache
69 */
70static inline void wm8776_write_reg_cache(struct snd_soc_codec *codec,
71 u16 reg, unsigned int value)
72{
73 u16 *cache = codec->reg_cache;
74 if (reg >= WM8776_CACHEREGNUM)
75 return;
76 cache[reg] = value;
77}
78
79/*
80 * write to the WM8776 register space
81 */
82static int wm8776_write(struct snd_soc_codec *codec, unsigned int reg,
83 unsigned int value)
84{
85 u8 data[2];
86
87 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
88 data[1] = value & 0x00ff;
89
90 wm8776_write_reg_cache(codec, reg, value);
91 if (codec->hw_write(codec->control_data, data, 2) == 2)
92 return 0;
93 else
94 return -EIO;
95}
96
97static int wm8776_reset(struct snd_soc_codec *codec)
98{
99 return wm8776_write(codec, WM8776_RESET, 0);
100}
101
102static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1);
103static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
104static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1);
105
106static const struct snd_kcontrol_new wm8776_snd_controls[] = {
107SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8776_HPLVOL, WM8776_HPRVOL,
108 0, 127, 0, hp_tlv),
109SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8776_DACLVOL, WM8776_DACRVOL,
110 0, 255, 0, dac_tlv),
111SOC_SINGLE("Digital Playback ZC Switch", WM8776_DACCTRL1, 0, 1, 0),
112
113SOC_SINGLE("Deemphasis Switch", WM8776_DACCTRL2, 0, 1, 0),
114
115SOC_DOUBLE_R_TLV("Capture Volume", WM8776_ADCLVOL, WM8776_ADCRVOL,
116 0, 255, 0, adc_tlv),
117SOC_DOUBLE("Capture Switch", WM8776_ADCMUX, 7, 6, 1, 1),
118SOC_DOUBLE_R("Capture ZC Switch", WM8776_ADCLVOL, WM8776_ADCRVOL, 8, 1, 0),
119SOC_SINGLE("Capture HPF Switch", WM8776_ADCIFCTRL, 8, 1, 1),
120};
121
122static const struct snd_kcontrol_new inmix_controls[] = {
123SOC_DAPM_SINGLE("AIN1 Switch", WM8776_ADCMUX, 0, 1, 0),
124SOC_DAPM_SINGLE("AIN2 Switch", WM8776_ADCMUX, 1, 1, 0),
125SOC_DAPM_SINGLE("AIN3 Switch", WM8776_ADCMUX, 2, 1, 0),
126SOC_DAPM_SINGLE("AIN4 Switch", WM8776_ADCMUX, 3, 1, 0),
127SOC_DAPM_SINGLE("AIN5 Switch", WM8776_ADCMUX, 4, 1, 0),
128};
129
130static const struct snd_kcontrol_new outmix_controls[] = {
131SOC_DAPM_SINGLE("DAC Switch", WM8776_OUTMUX, 0, 1, 0),
132SOC_DAPM_SINGLE("AUX Switch", WM8776_OUTMUX, 1, 1, 0),
133SOC_DAPM_SINGLE("Bypass Switch", WM8776_OUTMUX, 2, 1, 0),
134};
135
136static const struct snd_soc_dapm_widget wm8776_dapm_widgets[] = {
137SND_SOC_DAPM_INPUT("AUX"),
138SND_SOC_DAPM_INPUT("AUX"),
139
140SND_SOC_DAPM_INPUT("AIN1"),
141SND_SOC_DAPM_INPUT("AIN2"),
142SND_SOC_DAPM_INPUT("AIN3"),
143SND_SOC_DAPM_INPUT("AIN4"),
144SND_SOC_DAPM_INPUT("AIN5"),
145
146SND_SOC_DAPM_MIXER("Input Mixer", WM8776_PWRDOWN, 6, 1,
147 inmix_controls, ARRAY_SIZE(inmix_controls)),
148
149SND_SOC_DAPM_ADC("ADC", "Capture", WM8776_PWRDOWN, 1, 1),
150SND_SOC_DAPM_DAC("DAC", "Playback", WM8776_PWRDOWN, 2, 1),
151
152SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
153 outmix_controls, ARRAY_SIZE(outmix_controls)),
154
155SND_SOC_DAPM_PGA("Headphone PGA", WM8776_PWRDOWN, 3, 1, NULL, 0),
156
157SND_SOC_DAPM_OUTPUT("VOUT"),
158
159SND_SOC_DAPM_OUTPUT("HPOUTL"),
160SND_SOC_DAPM_OUTPUT("HPOUTR"),
161};
162
163static const struct snd_soc_dapm_route routes[] = {
164 { "Input Mixer", "AIN1 Switch", "AIN1" },
165 { "Input Mixer", "AIN2 Switch", "AIN2" },
166 { "Input Mixer", "AIN3 Switch", "AIN3" },
167 { "Input Mixer", "AIN4 Switch", "AIN4" },
168 { "Input Mixer", "AIN5 Switch", "AIN5" },
169
170 { "ADC", NULL, "Input Mixer" },
171
172 { "Output Mixer", "DAC Switch", "DAC" },
173 { "Output Mixer", "AUX Switch", "AUX" },
174 { "Output Mixer", "Bypass Switch", "Input Mixer" },
175
176 { "VOUT", NULL, "Output Mixer" },
177
178 { "Headphone PGA", NULL, "Output Mixer" },
179
180 { "HPOUTL", NULL, "Headphone PGA" },
181 { "HPOUTR", NULL, "Headphone PGA" },
182};
183
184static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
185{
186 struct snd_soc_codec *codec = dai->codec;
187 int reg, iface, master;
188
189 switch (dai->id) {
190 case WM8776_DAI_DAC:
191 reg = WM8776_DACIFCTRL;
192 master = 0x80;
193 break;
194 case WM8776_DAI_ADC:
195 reg = WM8776_ADCIFCTRL;
196 master = 0x100;
197 break;
198 default:
199 return -EINVAL;
200 }
201
202 iface = 0;
203
204 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
205 case SND_SOC_DAIFMT_CBM_CFM:
206 break;
207 case SND_SOC_DAIFMT_CBS_CFS:
208 master = 0;
209 break;
210 default:
211 return -EINVAL;
212 }
213
214 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
215 case SND_SOC_DAIFMT_I2S:
216 iface |= 0x0002;
217 break;
218 case SND_SOC_DAIFMT_RIGHT_J:
219 break;
220 case SND_SOC_DAIFMT_LEFT_J:
221 iface |= 0x0001;
222 break;
223 /* FIXME: CHECK A/B */
224 case SND_SOC_DAIFMT_DSP_A:
225 iface |= 0x0003;
226 break;
227 case SND_SOC_DAIFMT_DSP_B:
228 iface |= 0x0007;
229 break;
230 default:
231 return -EINVAL;
232 }
233
234 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
235 case SND_SOC_DAIFMT_NB_NF:
236 break;
237 case SND_SOC_DAIFMT_IB_IF:
238 iface |= 0x00c;
239 break;
240 case SND_SOC_DAIFMT_IB_NF:
241 iface |= 0x008;
242 break;
243 case SND_SOC_DAIFMT_NB_IF:
244 iface |= 0x004;
245 break;
246 default:
247 return -EINVAL;
248 }
249
250 /* Finally, write out the values */
251 snd_soc_update_bits(codec, reg, 0xf, iface);
252 snd_soc_update_bits(codec, WM8776_MSTRCTRL, 0x180, master);
253
254 return 0;
255}
256
257static int mclk_ratios[] = {
258 128,
259 192,
260 256,
261 384,
262 512,
263 768,
264};
265
266static int wm8776_hw_params(struct snd_pcm_substream *substream,
267 struct snd_pcm_hw_params *params,
268 struct snd_soc_dai *dai)
269{
270 struct snd_soc_codec *codec = dai->codec;
271 struct wm8776_priv *wm8776 = codec->private_data;
272 int iface_reg, iface;
273 int ratio_shift, master;
274 int i;
275
276 iface = 0;
277
278 switch (dai->id) {
279 case WM8776_DAI_DAC:
280 iface_reg = WM8776_DACIFCTRL;
281 master = 0x80;
282 ratio_shift = 4;
283 break;
284 case WM8776_DAI_ADC:
285 iface_reg = WM8776_ADCIFCTRL;
286 master = 0x100;
287 ratio_shift = 0;
288 break;
289 default:
290 return -EINVAL;
291 }
292
293
294 /* Set word length */
295 switch (params_format(params)) {
296 case SNDRV_PCM_FORMAT_S16_LE:
297 break;
298 case SNDRV_PCM_FORMAT_S20_3LE:
299 iface |= 0x10;
300 break;
301 case SNDRV_PCM_FORMAT_S24_LE:
302 iface |= 0x20;
303 break;
304 case SNDRV_PCM_FORMAT_S32_LE:
305 iface |= 0x30;
306 break;
307 }
308
309 /* Only need to set MCLK/LRCLK ratio if we're master */
310 if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
311 for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
312 if (wm8776->sysclk[dai->id] / params_rate(params)
313 == mclk_ratios[i])
314 break;
315 }
316
317 if (i == ARRAY_SIZE(mclk_ratios)) {
318 dev_err(codec->dev,
319 "Unable to configure MCLK ratio %d/%d\n",
320 wm8776->sysclk[dai->id], params_rate(params));
321 return -EINVAL;
322 }
323
324 dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]);
325
326 snd_soc_update_bits(codec, WM8776_MSTRCTRL,
327 0x7 << ratio_shift, i << ratio_shift);
328 } else {
329 dev_dbg(codec->dev, "DAI in slave mode\n");
330 }
331
332 snd_soc_update_bits(codec, iface_reg, 0x30, iface);
333
334 return 0;
335}
336
337static int wm8776_mute(struct snd_soc_dai *dai, int mute)
338{
339 struct snd_soc_codec *codec = dai->codec;
340
341 return snd_soc_write(codec, WM8776_DACMUTE, !!mute);
342}
343
344static int wm8776_set_sysclk(struct snd_soc_dai *dai,
345 int clk_id, unsigned int freq, int dir)
346{
347 struct snd_soc_codec *codec = dai->codec;
348 struct wm8776_priv *wm8776 = codec->private_data;
349
350 BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
351
352 wm8776->sysclk[dai->id] = freq;
353
354 return 0;
355}
356
357static int wm8776_set_bias_level(struct snd_soc_codec *codec,
358 enum snd_soc_bias_level level)
359{
360 switch (level) {
361 case SND_SOC_BIAS_ON:
362 break;
363 case SND_SOC_BIAS_PREPARE:
364 break;
365 case SND_SOC_BIAS_STANDBY:
366 if (codec->bias_level == SND_SOC_BIAS_OFF) {
367 /* Disable the global powerdown; DAPM does the rest */
368 snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0);
369 }
370
371 break;
372 case SND_SOC_BIAS_OFF:
373 snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 1);
374 break;
375 }
376
377 codec->bias_level = level;
378 return 0;
379}
380
381#define WM8776_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
382 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
383 SNDRV_PCM_RATE_96000)
384
385
386#define WM8776_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
387 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
388
389static struct snd_soc_dai_ops wm8776_dac_ops = {
390 .digital_mute = wm8776_mute,
391 .hw_params = wm8776_hw_params,
392 .set_fmt = wm8776_set_fmt,
393 .set_sysclk = wm8776_set_sysclk,
394};
395
396static struct snd_soc_dai_ops wm8776_adc_ops = {
397 .hw_params = wm8776_hw_params,
398 .set_fmt = wm8776_set_fmt,
399 .set_sysclk = wm8776_set_sysclk,
400};
401
402struct snd_soc_dai wm8776_dai[] = {
403 {
404 .name = "WM8776 Playback",
405 .id = WM8776_DAI_DAC,
406 .playback = {
407 .stream_name = "Playback",
408 .channels_min = 2,
409 .channels_max = 2,
410 .rates = WM8776_RATES,
411 .formats = WM8776_FORMATS,
412 },
413 .ops = &wm8776_dac_ops,
414 },
415 {
416 .name = "WM8776 Capture",
417 .id = WM8776_DAI_ADC,
418 .capture = {
419 .stream_name = "Capture",
420 .channels_min = 2,
421 .channels_max = 2,
422 .rates = WM8776_RATES,
423 .formats = WM8776_FORMATS,
424 },
425 .ops = &wm8776_adc_ops,
426 },
427};
428EXPORT_SYMBOL_GPL(wm8776_dai);
429
430#ifdef CONFIG_PM
431static int wm8776_suspend(struct platform_device *pdev, pm_message_t state)
432{
433 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
434 struct snd_soc_codec *codec = socdev->card->codec;
435
436 wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
437
438 return 0;
439}
440
441static int wm8776_resume(struct platform_device *pdev)
442{
443 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
444 struct snd_soc_codec *codec = socdev->card->codec;
445 int i;
446 u8 data[2];
447 u16 *cache = codec->reg_cache;
448
449 /* Sync reg_cache with the hardware */
450 for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) {
451 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
452 data[1] = cache[i] & 0x00ff;
453 codec->hw_write(codec->control_data, data, 2);
454 }
455
456 wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
457
458 return 0;
459}
460#else
461#define wm8776_suspend NULL
462#define wm8776_resume NULL
463#endif
464
465static int wm8776_probe(struct platform_device *pdev)
466{
467 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
468 struct snd_soc_codec *codec;
469 int ret = 0;
470
471 if (wm8776_codec == NULL) {
472 dev_err(&pdev->dev, "Codec device not registered\n");
473 return -ENODEV;
474 }
475
476 socdev->card->codec = wm8776_codec;
477 codec = wm8776_codec;
478
479 /* register pcms */
480 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
481 if (ret < 0) {
482 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
483 goto pcm_err;
484 }
485
486 snd_soc_add_controls(codec, wm8776_snd_controls,
487 ARRAY_SIZE(wm8776_snd_controls));
488 snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
489 ARRAY_SIZE(wm8776_dapm_widgets));
490 snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
491
492 ret = snd_soc_init_card(socdev);
493 if (ret < 0) {
494 dev_err(codec->dev, "failed to register card: %d\n", ret);
495 goto card_err;
496 }
497
498 return ret;
499
500card_err:
501 snd_soc_free_pcms(socdev);
502 snd_soc_dapm_free(socdev);
503pcm_err:
504 return ret;
505}
506
507/* power down chip */
508static int wm8776_remove(struct platform_device *pdev)
509{
510 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
511
512 snd_soc_free_pcms(socdev);
513 snd_soc_dapm_free(socdev);
514
515 return 0;
516}
517
518struct snd_soc_codec_device soc_codec_dev_wm8776 = {
519 .probe = wm8776_probe,
520 .remove = wm8776_remove,
521 .suspend = wm8776_suspend,
522 .resume = wm8776_resume,
523};
524EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
525
526static int wm8776_register(struct wm8776_priv *wm8776)
527{
528 int ret, i;
529 struct snd_soc_codec *codec = &wm8776->codec;
530
531 if (wm8776_codec) {
532 dev_err(codec->dev, "Another WM8776 is registered\n");
533 ret = -EINVAL;
534 goto err;
535 }
536
537 mutex_init(&codec->mutex);
538 INIT_LIST_HEAD(&codec->dapm_widgets);
539 INIT_LIST_HEAD(&codec->dapm_paths);
540
541 codec->private_data = wm8776;
542 codec->name = "WM8776";
543 codec->owner = THIS_MODULE;
544 codec->read = wm8776_read_reg_cache;
545 codec->write = wm8776_write;
546 codec->bias_level = SND_SOC_BIAS_OFF;
547 codec->set_bias_level = wm8776_set_bias_level;
548 codec->dai = wm8776_dai;
549 codec->num_dai = ARRAY_SIZE(wm8776_dai);
550 codec->reg_cache_size = WM8776_CACHEREGNUM;
551 codec->reg_cache = &wm8776->reg_cache;
552
553 memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
554
555 for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
556 wm8776_dai[i].dev = codec->dev;
557
558 ret = wm8776_reset(codec);
559 if (ret < 0) {
560 dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
561 goto err;
562 }
563
564 wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
565
566 /* Latch the update bits; right channel only since we always
567 * update both. */
568 snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
569 snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
570
571 wm8776_codec = codec;
572
573 ret = snd_soc_register_codec(codec);
574 if (ret != 0) {
575 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
576 goto err;
577 }
578
579 ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
580 if (ret != 0) {
581 dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
582 goto err_codec;
583 }
584
585 return 0;
586
587err_codec:
588 snd_soc_unregister_codec(codec);
589err:
590 kfree(wm8776);
591 return ret;
592}
593
594static void wm8776_unregister(struct wm8776_priv *wm8776)
595{
596 wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
597 snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
598 snd_soc_unregister_codec(&wm8776->codec);
599 kfree(wm8776);
600 wm8776_codec = NULL;
601}
602
603#if defined(CONFIG_SPI_MASTER)
604static int wm8776_spi_write(struct spi_device *spi, const char *data, int len)
605{
606 struct spi_transfer t;
607 struct spi_message m;
608 u8 msg[2];
609
610 if (len <= 0)
611 return 0;
612
613 msg[0] = data[0];
614 msg[1] = data[1];
615
616 spi_message_init(&m);
617 memset(&t, 0, (sizeof t));
618
619 t.tx_buf = &msg[0];
620 t.len = len;
621
622 spi_message_add_tail(&t, &m);
623 spi_sync(spi, &m);
624
625 return len;
626}
627
628static int __devinit wm8776_spi_probe(struct spi_device *spi)
629{
630 struct snd_soc_codec *codec;
631 struct wm8776_priv *wm8776;
632
633 wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
634 if (wm8776 == NULL)
635 return -ENOMEM;
636
637 codec = &wm8776->codec;
638 codec->control_data = spi;
639 codec->hw_write = (hw_write_t)wm8776_spi_write;
640 codec->dev = &spi->dev;
641
642 dev_set_drvdata(&spi->dev, wm8776);
643
644 return wm8776_register(wm8776);
645}
646
647static int __devexit wm8776_spi_remove(struct spi_device *spi)
648{
649 struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev);
650
651 wm8776_unregister(wm8776);
652
653 return 0;
654}
655
656#ifdef CONFIG_PM
657static int wm8776_spi_suspend(struct spi_device *spi, pm_message_t msg)
658{
659 return snd_soc_suspend_device(&spi->dev);
660}
661
662static int wm8776_spi_resume(struct spi_device *spi)
663{
664 return snd_soc_resume_device(&spi->dev);
665}
666#else
667#define wm8776_spi_suspend NULL
668#define wm8776_spi_resume NULL
669#endif
670
671static struct spi_driver wm8776_spi_driver = {
672 .driver = {
673 .name = "wm8776",
674 .bus = &spi_bus_type,
675 .owner = THIS_MODULE,
676 },
677 .probe = wm8776_spi_probe,
678 .suspend = wm8776_spi_suspend,
679 .resume = wm8776_spi_resume,
680 .remove = __devexit_p(wm8776_spi_remove),
681};
682#endif /* CONFIG_SPI_MASTER */
683
684#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
685static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
686 const struct i2c_device_id *id)
687{
688 struct wm8776_priv *wm8776;
689 struct snd_soc_codec *codec;
690
691 wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
692 if (wm8776 == NULL)
693 return -ENOMEM;
694
695 codec = &wm8776->codec;
696 codec->hw_write = (hw_write_t)i2c_master_send;
697
698 i2c_set_clientdata(i2c, wm8776);
699 codec->control_data = i2c;
700
701 codec->dev = &i2c->dev;
702
703 return wm8776_register(wm8776);
704}
705
706static __devexit int wm8776_i2c_remove(struct i2c_client *client)
707{
708 struct wm8776_priv *wm8776 = i2c_get_clientdata(client);
709 wm8776_unregister(wm8776);
710 return 0;
711}
712
713#ifdef CONFIG_PM
714static int wm8776_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
715{
716 return snd_soc_suspend_device(&i2c->dev);
717}
718
719static int wm8776_i2c_resume(struct i2c_client *i2c)
720{
721 return snd_soc_resume_device(&i2c->dev);
722}
723#else
724#define wm8776_i2c_suspend NULL
725#define wm8776_i2c_resume NULL
726#endif
727
728static const struct i2c_device_id wm8776_i2c_id[] = {
729 { "wm8776", 0 },
730 { }
731};
732MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
733
734static struct i2c_driver wm8776_i2c_driver = {
735 .driver = {
736 .name = "wm8776",
737 .owner = THIS_MODULE,
738 },
739 .probe = wm8776_i2c_probe,
740 .remove = __devexit_p(wm8776_i2c_remove),
741 .suspend = wm8776_i2c_suspend,
742 .resume = wm8776_i2c_resume,
743 .id_table = wm8776_i2c_id,
744};
745#endif
746
747static int __init wm8776_modinit(void)
748{
749 int ret;
750#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
751 ret = i2c_add_driver(&wm8776_i2c_driver);
752 if (ret != 0) {
753 printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n",
754 ret);
755 }
756#endif
757#if defined(CONFIG_SPI_MASTER)
758 ret = spi_register_driver(&wm8776_spi_driver);
759 if (ret != 0) {
760 printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n",
761 ret);
762 }
763#endif
764 return 0;
765}
766module_init(wm8776_modinit);
767
768static void __exit wm8776_exit(void)
769{
770#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
771 i2c_del_driver(&wm8776_i2c_driver);
772#endif
773#if defined(CONFIG_SPI_MASTER)
774 spi_unregister_driver(&wm8776_spi_driver);
775#endif
776}
777module_exit(wm8776_exit);
778
779MODULE_DESCRIPTION("ASoC WM8776 driver");
780MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
781MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8776.h b/sound/soc/codecs/wm8776.h
new file mode 100644
index 000000000000..6606d25d2d83
--- /dev/null
+++ b/sound/soc/codecs/wm8776.h
@@ -0,0 +1,51 @@
1/*
2 * wm8776.h -- WM8776 ASoC driver
3 *
4 * Copyright 2009 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef _WM8776_H
14#define _WM8776_H
15
16/* Registers */
17
18#define WM8776_HPLVOL 0x00
19#define WM8776_HPRVOL 0x01
20#define WM8776_HPMASTER 0x02
21#define WM8776_DACLVOL 0x03
22#define WM8776_DACRVOL 0x04
23#define WM8776_DACMASTER 0x05
24#define WM8776_PHASESWAP 0x06
25#define WM8776_DACCTRL1 0x07
26#define WM8776_DACMUTE 0x08
27#define WM8776_DACCTRL2 0x09
28#define WM8776_DACIFCTRL 0x0a
29#define WM8776_ADCIFCTRL 0x0b
30#define WM8776_MSTRCTRL 0x0c
31#define WM8776_PWRDOWN 0x0d
32#define WM8776_ADCLVOL 0x0e
33#define WM8776_ADCRVOL 0x0f
34#define WM8776_ALCCTRL1 0x10
35#define WM8776_ALCCTRL2 0x11
36#define WM8776_ALCCTRL3 0x12
37#define WM8776_NOISEGATE 0x13
38#define WM8776_LIMITER 0x14
39#define WM8776_ADCMUX 0x15
40#define WM8776_OUTMUX 0x16
41#define WM8776_RESET 0x17
42
43#define WM8776_CACHEREGNUM 0x17
44
45#define WM8776_DAI_DAC 0
46#define WM8776_DAI_ADC 1
47
48extern struct snd_soc_dai wm8776_dai[];
49extern struct snd_soc_codec_device soc_codec_dev_wm8776;
50
51#endif
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
new file mode 100644
index 000000000000..e246ca079897
--- /dev/null
+++ b/sound/soc/codecs/wm8993.c
@@ -0,0 +1,2206 @@
1/*
2 * wm8993.c -- WM8993 ALSA SoC audio driver
3 *
4 * Copyright 2009 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/init.h>
16#include <linux/delay.h>
17#include <linux/pm.h>
18#include <linux/i2c.h>
19#include <linux/spi/spi.h>
20#include <sound/core.h>
21#include <sound/pcm.h>
22#include <sound/pcm_params.h>
23#include <sound/tlv.h>
24#include <sound/soc.h>
25#include <sound/soc-dapm.h>
26#include <sound/initval.h>
27#include <sound/wm8993.h>
28
29#include "wm8993.h"
30
31static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = {
32 0x8993, /* R0 - Software Reset */
33 0x0000, /* R1 - Power Management (1) */
34 0x6000, /* R2 - Power Management (2) */
35 0x0000, /* R3 - Power Management (3) */
36 0x4050, /* R4 - Audio Interface (1) */
37 0x4000, /* R5 - Audio Interface (2) */
38 0x01C8, /* R6 - Clocking 1 */
39 0x0000, /* R7 - Clocking 2 */
40 0x0000, /* R8 - Audio Interface (3) */
41 0x0040, /* R9 - Audio Interface (4) */
42 0x0004, /* R10 - DAC CTRL */
43 0x00C0, /* R11 - Left DAC Digital Volume */
44 0x00C0, /* R12 - Right DAC Digital Volume */
45 0x0000, /* R13 - Digital Side Tone */
46 0x0300, /* R14 - ADC CTRL */
47 0x00C0, /* R15 - Left ADC Digital Volume */
48 0x00C0, /* R16 - Right ADC Digital Volume */
49 0x0000, /* R17 */
50 0x0000, /* R18 - GPIO CTRL 1 */
51 0x0010, /* R19 - GPIO1 */
52 0x0000, /* R20 - IRQ_DEBOUNCE */
53 0x0000, /* R21 */
54 0x8000, /* R22 - GPIOCTRL 2 */
55 0x0800, /* R23 - GPIO_POL */
56 0x008B, /* R24 - Left Line Input 1&2 Volume */
57 0x008B, /* R25 - Left Line Input 3&4 Volume */
58 0x008B, /* R26 - Right Line Input 1&2 Volume */
59 0x008B, /* R27 - Right Line Input 3&4 Volume */
60 0x006D, /* R28 - Left Output Volume */
61 0x006D, /* R29 - Right Output Volume */
62 0x0066, /* R30 - Line Outputs Volume */
63 0x0020, /* R31 - HPOUT2 Volume */
64 0x0079, /* R32 - Left OPGA Volume */
65 0x0079, /* R33 - Right OPGA Volume */
66 0x0003, /* R34 - SPKMIXL Attenuation */
67 0x0003, /* R35 - SPKMIXR Attenuation */
68 0x0011, /* R36 - SPKOUT Mixers */
69 0x0100, /* R37 - SPKOUT Boost */
70 0x0079, /* R38 - Speaker Volume Left */
71 0x0079, /* R39 - Speaker Volume Right */
72 0x0000, /* R40 - Input Mixer2 */
73 0x0000, /* R41 - Input Mixer3 */
74 0x0000, /* R42 - Input Mixer4 */
75 0x0000, /* R43 - Input Mixer5 */
76 0x0000, /* R44 - Input Mixer6 */
77 0x0000, /* R45 - Output Mixer1 */
78 0x0000, /* R46 - Output Mixer2 */
79 0x0000, /* R47 - Output Mixer3 */
80 0x0000, /* R48 - Output Mixer4 */
81 0x0000, /* R49 - Output Mixer5 */
82 0x0000, /* R50 - Output Mixer6 */
83 0x0000, /* R51 - HPOUT2 Mixer */
84 0x0000, /* R52 - Line Mixer1 */
85 0x0000, /* R53 - Line Mixer2 */
86 0x0000, /* R54 - Speaker Mixer */
87 0x0000, /* R55 - Additional Control */
88 0x0000, /* R56 - AntiPOP1 */
89 0x0000, /* R57 - AntiPOP2 */
90 0x0000, /* R58 - MICBIAS */
91 0x0000, /* R59 */
92 0x0000, /* R60 - FLL Control 1 */
93 0x0000, /* R61 - FLL Control 2 */
94 0x0000, /* R62 - FLL Control 3 */
95 0x2EE0, /* R63 - FLL Control 4 */
96 0x0002, /* R64 - FLL Control 5 */
97 0x2287, /* R65 - Clocking 3 */
98 0x025F, /* R66 - Clocking 4 */
99 0x0000, /* R67 - MW Slave Control */
100 0x0000, /* R68 */
101 0x0002, /* R69 - Bus Control 1 */
102 0x0000, /* R70 - Write Sequencer 0 */
103 0x0000, /* R71 - Write Sequencer 1 */
104 0x0000, /* R72 - Write Sequencer 2 */
105 0x0000, /* R73 - Write Sequencer 3 */
106 0x0000, /* R74 - Write Sequencer 4 */
107 0x0000, /* R75 - Write Sequencer 5 */
108 0x1F25, /* R76 - Charge Pump 1 */
109 0x0000, /* R77 */
110 0x0000, /* R78 */
111 0x0000, /* R79 */
112 0x0000, /* R80 */
113 0x0000, /* R81 - Class W 0 */
114 0x0000, /* R82 */
115 0x0000, /* R83 */
116 0x0000, /* R84 - DC Servo 0 */
117 0x054A, /* R85 - DC Servo 1 */
118 0x0000, /* R86 */
119 0x0000, /* R87 - DC Servo 3 */
120 0x0000, /* R88 - DC Servo Readback 0 */
121 0x0000, /* R89 - DC Servo Readback 1 */
122 0x0000, /* R90 - DC Servo Readback 2 */
123 0x0000, /* R91 */
124 0x0000, /* R92 */
125 0x0000, /* R93 */
126 0x0000, /* R94 */
127 0x0000, /* R95 */
128 0x0100, /* R96 - Analogue HP 0 */
129 0x0000, /* R97 */
130 0x0000, /* R98 - EQ1 */
131 0x000C, /* R99 - EQ2 */
132 0x000C, /* R100 - EQ3 */
133 0x000C, /* R101 - EQ4 */
134 0x000C, /* R102 - EQ5 */
135 0x000C, /* R103 - EQ6 */
136 0x0FCA, /* R104 - EQ7 */
137 0x0400, /* R105 - EQ8 */
138 0x00D8, /* R106 - EQ9 */
139 0x1EB5, /* R107 - EQ10 */
140 0xF145, /* R108 - EQ11 */
141 0x0B75, /* R109 - EQ12 */
142 0x01C5, /* R110 - EQ13 */
143 0x1C58, /* R111 - EQ14 */
144 0xF373, /* R112 - EQ15 */
145 0x0A54, /* R113 - EQ16 */
146 0x0558, /* R114 - EQ17 */
147 0x168E, /* R115 - EQ18 */
148 0xF829, /* R116 - EQ19 */
149 0x07AD, /* R117 - EQ20 */
150 0x1103, /* R118 - EQ21 */
151 0x0564, /* R119 - EQ22 */
152 0x0559, /* R120 - EQ23 */
153 0x4000, /* R121 - EQ24 */
154 0x0000, /* R122 - Digital Pulls */
155 0x0F08, /* R123 - DRC Control 1 */
156 0x0000, /* R124 - DRC Control 2 */
157 0x0080, /* R125 - DRC Control 3 */
158 0x0000, /* R126 - DRC Control 4 */
159};
160
161static struct {
162 int ratio;
163 int clk_sys_rate;
164} clk_sys_rates[] = {
165 { 64, 0 },
166 { 128, 1 },
167 { 192, 2 },
168 { 256, 3 },
169 { 384, 4 },
170 { 512, 5 },
171 { 768, 6 },
172 { 1024, 7 },
173 { 1408, 8 },
174 { 1536, 9 },
175};
176
177static struct {
178 int rate;
179 int sample_rate;
180} sample_rates[] = {
181 { 8000, 0 },
182 { 11025, 1 },
183 { 12000, 1 },
184 { 16000, 2 },
185 { 22050, 3 },
186 { 24000, 3 },
187 { 32000, 4 },
188 { 44100, 5 },
189 { 48000, 5 },
190};
191
192static struct {
193 int div; /* *10 due to .5s */
194 int bclk_div;
195} bclk_divs[] = {
196 { 10, 0 },
197 { 15, 1 },
198 { 20, 2 },
199 { 30, 3 },
200 { 40, 4 },
201 { 55, 5 },
202 { 60, 6 },
203 { 80, 7 },
204 { 110, 8 },
205 { 120, 9 },
206 { 160, 10 },
207 { 220, 11 },
208 { 240, 12 },
209 { 320, 13 },
210 { 440, 14 },
211 { 480, 15 },
212};
213
214struct wm8993_priv {
215 u16 reg_cache[WM8993_REGISTER_COUNT];
216 struct wm8993_platform_data pdata;
217 struct snd_soc_codec codec;
218 int master;
219 int sysclk_source;
220 unsigned int mclk_rate;
221 unsigned int sysclk_rate;
222 unsigned int fs;
223 unsigned int bclk;
224 int class_w_users;
225 unsigned int fll_fref;
226 unsigned int fll_fout;
227};
228
229static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg)
230{
231 struct i2c_msg xfer[2];
232 u16 data;
233 int ret;
234 struct i2c_client *i2c = codec->control_data;
235
236 /* Write register */
237 xfer[0].addr = i2c->addr;
238 xfer[0].flags = 0;
239 xfer[0].len = 1;
240 xfer[0].buf = &reg;
241
242 /* Read data */
243 xfer[1].addr = i2c->addr;
244 xfer[1].flags = I2C_M_RD;
245 xfer[1].len = 2;
246 xfer[1].buf = (u8 *)&data;
247
248 ret = i2c_transfer(i2c->adapter, xfer, 2);
249 if (ret != 2) {
250 dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret);
251 return 0;
252 }
253
254 return (data >> 8) | ((data & 0xff) << 8);
255}
256
257static int wm8993_volatile(unsigned int reg)
258{
259 switch (reg) {
260 case WM8993_SOFTWARE_RESET:
261 case WM8993_DC_SERVO_0:
262 case WM8993_DC_SERVO_READBACK_0:
263 case WM8993_DC_SERVO_READBACK_1:
264 case WM8993_DC_SERVO_READBACK_2:
265 return 1;
266 default:
267 return 0;
268 }
269}
270
271static unsigned int wm8993_read(struct snd_soc_codec *codec,
272 unsigned int reg)
273{
274 u16 *reg_cache = codec->reg_cache;
275
276 BUG_ON(reg > WM8993_MAX_REGISTER);
277
278 if (wm8993_volatile(reg))
279 return wm8993_read_hw(codec, reg);
280 else
281 return reg_cache[reg];
282}
283
284static int wm8993_write(struct snd_soc_codec *codec, unsigned int reg,
285 unsigned int value)
286{
287 u16 *reg_cache = codec->reg_cache;
288 u8 data[3];
289 int ret;
290
291 BUG_ON(reg > WM8993_MAX_REGISTER);
292
293 /* data is
294 * D15..D9 WM8993 register offset
295 * D8...D0 register data
296 */
297 data[0] = reg;
298 data[1] = value >> 8;
299 data[2] = value & 0x00ff;
300
301 if (!wm8993_volatile(reg))
302 reg_cache[reg] = value;
303
304 ret = codec->hw_write(codec->control_data, data, 3);
305
306 if (ret == 3)
307 return 0;
308 if (ret < 0)
309 return ret;
310 return -EIO;
311}
312
313struct _fll_div {
314 u16 fll_fratio;
315 u16 fll_outdiv;
316 u16 fll_clk_ref_div;
317 u16 n;
318 u16 k;
319};
320
321/* The size in bits of the FLL divide multiplied by 10
322 * to allow rounding later */
323#define FIXED_FLL_SIZE ((1 << 16) * 10)
324
325static struct {
326 unsigned int min;
327 unsigned int max;
328 u16 fll_fratio;
329 int ratio;
330} fll_fratios[] = {
331 { 0, 64000, 4, 16 },
332 { 64000, 128000, 3, 8 },
333 { 128000, 256000, 2, 4 },
334 { 256000, 1000000, 1, 2 },
335 { 1000000, 13500000, 0, 1 },
336};
337
338static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
339 unsigned int Fout)
340{
341 u64 Kpart;
342 unsigned int K, Ndiv, Nmod, target;
343 unsigned int div;
344 int i;
345
346 /* Fref must be <=13.5MHz */
347 div = 1;
348 fll_div->fll_clk_ref_div = 0;
349 while ((Fref / div) > 13500000) {
350 div *= 2;
351 fll_div->fll_clk_ref_div++;
352
353 if (div > 8) {
354 pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
355 Fref);
356 return -EINVAL;
357 }
358 }
359
360 pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
361
362 /* Apply the division for our remaining calculations */
363 Fref /= div;
364
365 /* Fvco should be 90-100MHz; don't check the upper bound */
366 div = 0;
367 target = Fout * 2;
368 while (target < 90000000) {
369 div++;
370 target *= 2;
371 if (div > 7) {
372 pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
373 Fout);
374 return -EINVAL;
375 }
376 }
377 fll_div->fll_outdiv = div;
378
379 pr_debug("Fvco=%dHz\n", target);
380
381 /* Find an appropraite FLL_FRATIO and factor it out of the target */
382 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
383 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
384 fll_div->fll_fratio = fll_fratios[i].fll_fratio;
385 target /= fll_fratios[i].ratio;
386 break;
387 }
388 }
389 if (i == ARRAY_SIZE(fll_fratios)) {
390 pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
391 return -EINVAL;
392 }
393
394 /* Now, calculate N.K */
395 Ndiv = target / Fref;
396
397 fll_div->n = Ndiv;
398 Nmod = target % Fref;
399 pr_debug("Nmod=%d\n", Nmod);
400
401 /* Calculate fractional part - scale up so we can round. */
402 Kpart = FIXED_FLL_SIZE * (long long)Nmod;
403
404 do_div(Kpart, Fref);
405
406 K = Kpart & 0xFFFFFFFF;
407
408 if ((K % 10) >= 5)
409 K += 5;
410
411 /* Move down to proper range now rounding is done */
412 fll_div->k = K / 10;
413
414 pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
415 fll_div->n, fll_div->k,
416 fll_div->fll_fratio, fll_div->fll_outdiv,
417 fll_div->fll_clk_ref_div);
418
419 return 0;
420}
421
422static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id,
423 unsigned int Fref, unsigned int Fout)
424{
425 struct snd_soc_codec *codec = dai->codec;
426 struct wm8993_priv *wm8993 = codec->private_data;
427 u16 reg1, reg4, reg5;
428 struct _fll_div fll_div;
429 int ret;
430
431 /* Any change? */
432 if (Fref == wm8993->fll_fref && Fout == wm8993->fll_fout)
433 return 0;
434
435 /* Disable the FLL */
436 if (Fout == 0) {
437 dev_dbg(codec->dev, "FLL disabled\n");
438 wm8993->fll_fref = 0;
439 wm8993->fll_fout = 0;
440
441 reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1);
442 reg1 &= ~WM8993_FLL_ENA;
443 wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
444
445 return 0;
446 }
447
448 ret = fll_factors(&fll_div, Fref, Fout);
449 if (ret != 0)
450 return ret;
451
452 reg5 = wm8993_read(codec, WM8993_FLL_CONTROL_5);
453 reg5 &= ~WM8993_FLL_CLK_SRC_MASK;
454
455 switch (fll_id) {
456 case WM8993_FLL_MCLK:
457 break;
458
459 case WM8993_FLL_LRCLK:
460 reg5 |= 1;
461 break;
462
463 case WM8993_FLL_BCLK:
464 reg5 |= 2;
465 break;
466
467 default:
468 dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
469 return -EINVAL;
470 }
471
472 /* Any FLL configuration change requires that the FLL be
473 * disabled first. */
474 reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1);
475 reg1 &= ~WM8993_FLL_ENA;
476 wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
477
478 /* Apply the configuration */
479 if (fll_div.k)
480 reg1 |= WM8993_FLL_FRAC_MASK;
481 else
482 reg1 &= ~WM8993_FLL_FRAC_MASK;
483 wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
484
485 wm8993_write(codec, WM8993_FLL_CONTROL_2,
486 (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) |
487 (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT));
488 wm8993_write(codec, WM8993_FLL_CONTROL_3, fll_div.k);
489
490 reg4 = wm8993_read(codec, WM8993_FLL_CONTROL_4);
491 reg4 &= ~WM8993_FLL_N_MASK;
492 reg4 |= fll_div.n << WM8993_FLL_N_SHIFT;
493 wm8993_write(codec, WM8993_FLL_CONTROL_4, reg4);
494
495 reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK;
496 reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
497 wm8993_write(codec, WM8993_FLL_CONTROL_5, reg5);
498
499 /* Enable the FLL */
500 wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
501
502 dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
503
504 wm8993->fll_fref = Fref;
505 wm8993->fll_fout = Fout;
506
507 return 0;
508}
509
510static int configure_clock(struct snd_soc_codec *codec)
511{
512 struct wm8993_priv *wm8993 = codec->private_data;
513 unsigned int reg;
514
515 /* This should be done on init() for bypass paths */
516 switch (wm8993->sysclk_source) {
517 case WM8993_SYSCLK_MCLK:
518 dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate);
519
520 reg = wm8993_read(codec, WM8993_CLOCKING_2);
521 reg &= ~WM8993_SYSCLK_SRC;
522 if (wm8993->mclk_rate > 13500000) {
523 reg |= WM8993_MCLK_DIV;
524 wm8993->sysclk_rate = wm8993->mclk_rate / 2;
525 } else {
526 reg &= ~WM8993_MCLK_DIV;
527 wm8993->sysclk_rate = wm8993->mclk_rate;
528 }
529 reg &= ~WM8993_MCLK_DIV;
530 reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC);
531 wm8993_write(codec, WM8993_CLOCKING_2, reg);
532 break;
533
534 case WM8993_SYSCLK_FLL:
535 dev_dbg(codec->dev, "Using %dHz FLL clock\n",
536 wm8993->fll_fout);
537
538 reg = wm8993_read(codec, WM8993_CLOCKING_2);
539 reg |= WM8993_SYSCLK_SRC;
540 if (wm8993->fll_fout > 13500000) {
541 reg |= WM8993_MCLK_DIV;
542 wm8993->sysclk_rate = wm8993->fll_fout / 2;
543 } else {
544 reg &= ~WM8993_MCLK_DIV;
545 wm8993->sysclk_rate = wm8993->fll_fout;
546 }
547 wm8993_write(codec, WM8993_CLOCKING_2, reg);
548 break;
549
550 default:
551 dev_err(codec->dev, "System clock not configured\n");
552 return -EINVAL;
553 }
554
555 dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8993->sysclk_rate);
556
557 return 0;
558}
559
560static void wait_for_dc_servo(struct snd_soc_codec *codec, int mask)
561{
562 unsigned int reg;
563 int count = 0;
564
565 dev_dbg(codec->dev, "Waiting for DC servo...\n");
566 do {
567 count++;
568 msleep(1);
569 reg = wm8993_read(codec, WM8993_DC_SERVO_READBACK_0);
570 dev_dbg(codec->dev, "DC servo status: %x\n", reg);
571 } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK)
572 != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000);
573
574 if ((reg & WM8993_DCS_CAL_COMPLETE_MASK)
575 != WM8993_DCS_CAL_COMPLETE_MASK)
576 dev_err(codec->dev, "Timed out waiting for DC Servo\n");
577}
578
579static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0);
580static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0);
581static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1);
582static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
583static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0);
584static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0);
585static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
586static const unsigned int drc_max_tlv[] = {
587 TLV_DB_RANGE_HEAD(4),
588 0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
589 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0),
590};
591static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
592static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -1800, 300, 0);
593static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
594static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
595static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
596static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
597static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
598static const DECLARE_TLV_DB_SCALE(spkmix_tlv, -300, 300, 0);
599static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
600static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
601static const unsigned int spkboost_tlv[] = {
602 TLV_DB_RANGE_HEAD(7),
603 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
604 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
605};
606static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);
607
608static const char *speaker_ref_text[] = {
609 "SPKVDD/2",
610 "VMID",
611};
612
613static const struct soc_enum speaker_ref =
614 SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text);
615
616static const char *speaker_mode_text[] = {
617 "Class D",
618 "Class AB",
619};
620
621static const struct soc_enum speaker_mode =
622 SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text);
623
624static const char *dac_deemph_text[] = {
625 "None",
626 "32kHz",
627 "44.1kHz",
628 "48kHz",
629};
630
631static const struct soc_enum dac_deemph =
632 SOC_ENUM_SINGLE(WM8993_DAC_CTRL, 4, 4, dac_deemph_text);
633
634static const char *adc_hpf_text[] = {
635 "Hi-Fi",
636 "Voice 1",
637 "Voice 2",
638 "Voice 3",
639};
640
641static const struct soc_enum adc_hpf =
642 SOC_ENUM_SINGLE(WM8993_ADC_CTRL, 5, 4, adc_hpf_text);
643
644static const char *drc_path_text[] = {
645 "ADC",
646 "DAC"
647};
648
649static const struct soc_enum drc_path =
650 SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 14, 2, drc_path_text);
651
652static const char *drc_r0_text[] = {
653 "1",
654 "1/2",
655 "1/4",
656 "1/8",
657 "1/16",
658 "0",
659};
660
661static const struct soc_enum drc_r0 =
662 SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 8, 6, drc_r0_text);
663
664static const char *drc_r1_text[] = {
665 "1",
666 "1/2",
667 "1/4",
668 "1/8",
669 "0",
670};
671
672static const struct soc_enum drc_r1 =
673 SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_4, 13, 5, drc_r1_text);
674
675static const char *drc_attack_text[] = {
676 "Reserved",
677 "181us",
678 "363us",
679 "726us",
680 "1.45ms",
681 "2.9ms",
682 "5.8ms",
683 "11.6ms",
684 "23.2ms",
685 "46.4ms",
686 "92.8ms",
687 "185.6ms",
688};
689
690static const struct soc_enum drc_attack =
691 SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 12, 12, drc_attack_text);
692
693static const char *drc_decay_text[] = {
694 "186ms",
695 "372ms",
696 "743ms",
697 "1.49s",
698 "2.97ms",
699 "5.94ms",
700 "11.89ms",
701 "23.78ms",
702 "47.56ms",
703};
704
705static const struct soc_enum drc_decay =
706 SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 8, 9, drc_decay_text);
707
708static const char *drc_ff_text[] = {
709 "5 samples",
710 "9 samples",
711};
712
713static const struct soc_enum drc_ff =
714 SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 7, 2, drc_ff_text);
715
716static const char *drc_qr_rate_text[] = {
717 "0.725ms",
718 "1.45ms",
719 "5.8ms",
720};
721
722static const struct soc_enum drc_qr_rate =
723 SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 0, 3, drc_qr_rate_text);
724
725static const char *drc_smooth_text[] = {
726 "Low",
727 "Medium",
728 "High",
729};
730
731static const struct soc_enum drc_smooth =
732 SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 4, 3, drc_smooth_text);
733
734
735/*
736 * Update the DC servo calibration on gain changes
737 */
738static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
739 struct snd_ctl_elem_value *ucontrol)
740{
741 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
742 int ret;
743
744 ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
745
746 /* Only need to do this if the outputs are active */
747 if (wm8993_read(codec, WM8993_POWER_MANAGEMENT_1)
748 & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
749 snd_soc_update_bits(codec,
750 WM8993_DC_SERVO_0,
751 WM8993_DCS_TRIG_SINGLE_0 |
752 WM8993_DCS_TRIG_SINGLE_1,
753 WM8993_DCS_TRIG_SINGLE_0 |
754 WM8993_DCS_TRIG_SINGLE_1);
755
756 return ret;
757}
758
759static const struct snd_kcontrol_new wm8993_snd_controls[] = {
760SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
761 inpga_tlv),
762SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
763SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 0),
764
765SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
766 inpga_tlv),
767SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
768SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 0),
769
770
771SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
772 inpga_tlv),
773SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
774SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 0),
775
776SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
777 inpga_tlv),
778SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
779SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 0),
780
781SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
782 inmix_sw_tlv),
783SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0,
784 inmix_sw_tlv),
785SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0,
786 inmix_tlv),
787SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv),
788SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0,
789 inmix_tlv),
790
791SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0,
792 inmix_sw_tlv),
793SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0,
794 inmix_sw_tlv),
795SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0,
796 inmix_tlv),
797SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv),
798SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0,
799 inmix_tlv),
800
801SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE,
802 5, 9, 12, 0, sidetone_tlv),
803
804SOC_SINGLE("DRC Switch", WM8993_DRC_CONTROL_1, 15, 1, 0),
805SOC_ENUM("DRC Path", drc_path),
806SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8993_DRC_CONTROL_2,
807 2, 60, 1, drc_comp_threash),
808SOC_SINGLE_TLV("DRC Compressor Amplitude Volume", WM8993_DRC_CONTROL_3,
809 11, 30, 1, drc_comp_amp),
810SOC_ENUM("DRC R0", drc_r0),
811SOC_ENUM("DRC R1", drc_r1),
812SOC_SINGLE_TLV("DRC Minimum Volume", WM8993_DRC_CONTROL_1, 2, 3, 1,
813 drc_min_tlv),
814SOC_SINGLE_TLV("DRC Maximum Volume", WM8993_DRC_CONTROL_1, 0, 3, 0,
815 drc_max_tlv),
816SOC_ENUM("DRC Attack Rate", drc_attack),
817SOC_ENUM("DRC Decay Rate", drc_decay),
818SOC_ENUM("DRC FF Delay", drc_ff),
819SOC_SINGLE("DRC Anti-clip Switch", WM8993_DRC_CONTROL_1, 9, 1, 0),
820SOC_SINGLE("DRC Quick Release Switch", WM8993_DRC_CONTROL_1, 10, 1, 0),
821SOC_SINGLE_TLV("DRC Quick Release Volume", WM8993_DRC_CONTROL_3, 2, 3, 0,
822 drc_qr_tlv),
823SOC_ENUM("DRC Quick Release Rate", drc_qr_rate),
824SOC_SINGLE("DRC Smoothing Switch", WM8993_DRC_CONTROL_1, 11, 1, 0),
825SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8993_DRC_CONTROL_1, 8, 1, 0),
826SOC_ENUM("DRC Smoothing Hysteresis Threashold", drc_smooth),
827SOC_SINGLE_TLV("DRC Startup Volume", WM8993_DRC_CONTROL_4, 8, 18, 0,
828 drc_startup_tlv),
829
830SOC_SINGLE("EQ Switch", WM8993_EQ1, 0, 1, 0),
831
832SOC_DOUBLE_R_TLV("Capture Volume", WM8993_LEFT_ADC_DIGITAL_VOLUME,
833 WM8993_RIGHT_ADC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv),
834SOC_SINGLE("ADC High Pass Filter Switch", WM8993_ADC_CTRL, 8, 1, 0),
835SOC_ENUM("ADC High Pass Filter Mode", adc_hpf),
836
837SOC_DOUBLE_R_TLV("Playback Volume", WM8993_LEFT_DAC_DIGITAL_VOLUME,
838 WM8993_RIGHT_DAC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv),
839SOC_SINGLE_TLV("Playback Boost Volume", WM8993_AUDIO_INTERFACE_2, 10, 3, 0,
840 dac_boost_tlv),
841SOC_ENUM("DAC Deemphasis", dac_deemph),
842
843SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1,
844 outmix_tlv),
845SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1,
846 outmix_tlv),
847SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1,
848 outmix_tlv),
849SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1,
850 outmix_tlv),
851SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1,
852 outmix_tlv),
853SOC_SINGLE_TLV("Left Output Mixer Right Input Volume",
854 WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv),
855SOC_SINGLE_TLV("Left Output Mixer Left Input Volume",
856 WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv),
857SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1,
858 outmix_tlv),
859
860SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume",
861 WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
862SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume",
863 WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv),
864SOC_SINGLE_TLV("Right Output Mixer IN1L Volume",
865 WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv),
866SOC_SINGLE_TLV("Right Output Mixer IN1R Volume",
867 WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv),
868SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume",
869 WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv),
870SOC_SINGLE_TLV("Right Output Mixer Left Input Volume",
871 WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv),
872SOC_SINGLE_TLV("Right Output Mixer Right Input Volume",
873 WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
874SOC_SINGLE_TLV("Right Output Mixer DAC Volume",
875 WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv),
876
877SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME,
878 WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv),
879SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME,
880 WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0),
881SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME,
882 WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0),
883
884SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1),
885SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv),
886
887SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION,
888 5, 1, 1, spkmix_tlv),
889SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION,
890 4, 1, 1, spkmix_tlv),
891SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION,
892 3, 1, 1, spkmix_tlv),
893SOC_SINGLE_TLV("SPKL DAC Volume", WM8993_SPKMIXL_ATTENUATION,
894 2, 1, 1, spkmix_tlv),
895
896SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION,
897 5, 1, 1, spkmix_tlv),
898SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION,
899 4, 1, 1, spkmix_tlv),
900SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION,
901 3, 1, 1, spkmix_tlv),
902SOC_SINGLE_TLV("SPKR DAC Volume", WM8993_SPKMIXR_ATTENUATION,
903 2, 1, 1, spkmix_tlv),
904
905SOC_DOUBLE_R_TLV("Speaker Mixer Volume",
906 WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION,
907 0, 3, 1, spkmixout_tlv),
908SOC_DOUBLE_R_TLV("Speaker Volume",
909 WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
910 0, 63, 0, outpga_tlv),
911SOC_DOUBLE_R("Speaker Switch",
912 WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
913 6, 1, 0),
914SOC_DOUBLE_R("Speaker ZC Switch",
915 WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
916 7, 1, 0),
917SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 0, 3, 7, 0,
918 spkboost_tlv),
919SOC_ENUM("Speaker Reference", speaker_ref),
920SOC_ENUM("Speaker Mode", speaker_mode),
921
922{
923 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Volume",
924 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
925 SNDRV_CTL_ELEM_ACCESS_READWRITE,
926 .tlv.p = outpga_tlv,
927 .info = snd_soc_info_volsw_2r,
928 .get = snd_soc_get_volsw_2r, .put = wm8993_put_dc_servo,
929 .private_value = (unsigned long)&(struct soc_mixer_control) {
930 .reg = WM8993_LEFT_OUTPUT_VOLUME,
931 .rreg = WM8993_RIGHT_OUTPUT_VOLUME,
932 .shift = 0, .max = 63
933 },
934},
935SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
936 WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
937SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
938 WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
939
940SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1),
941SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1),
942SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1,
943 line_tlv),
944
945SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1),
946SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1),
947SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
948 line_tlv),
949};
950
951static const struct snd_kcontrol_new wm8993_eq_controls[] = {
952SOC_SINGLE_TLV("EQ1 Volume", WM8993_EQ2, 0, 24, 0, eq_tlv),
953SOC_SINGLE_TLV("EQ2 Volume", WM8993_EQ3, 0, 24, 0, eq_tlv),
954SOC_SINGLE_TLV("EQ3 Volume", WM8993_EQ4, 0, 24, 0, eq_tlv),
955SOC_SINGLE_TLV("EQ4 Volume", WM8993_EQ5, 0, 24, 0, eq_tlv),
956SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv),
957};
958
959static int wm8993_earpiece_event(struct snd_soc_dapm_widget *w,
960 struct snd_kcontrol *control, int event)
961{
962 struct snd_soc_codec *codec = w->codec;
963 u16 reg = wm8993_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
964
965 switch (event) {
966 case SND_SOC_DAPM_PRE_PMU:
967 reg |= WM8993_HPOUT2_IN_ENA;
968 wm8993_write(codec, WM8993_ANTIPOP1, reg);
969 udelay(50);
970 break;
971
972 case SND_SOC_DAPM_POST_PMD:
973 wm8993_write(codec, WM8993_ANTIPOP1, reg);
974 break;
975
976 default:
977 BUG();
978 break;
979 }
980
981 return 0;
982}
983
984static int clk_sys_event(struct snd_soc_dapm_widget *w,
985 struct snd_kcontrol *kcontrol, int event)
986{
987 struct snd_soc_codec *codec = w->codec;
988
989 switch (event) {
990 case SND_SOC_DAPM_PRE_PMU:
991 return configure_clock(codec);
992
993 case SND_SOC_DAPM_POST_PMD:
994 break;
995 }
996
997 return 0;
998}
999
1000/*
1001 * When used with DAC outputs only the WM8993 charge pump supports
1002 * operation in class W mode, providing very low power consumption
1003 * when used with digital sources. Enable and disable this mode
1004 * automatically depending on the mixer configuration.
1005 *
1006 * Currently the only supported paths are the direct DAC->headphone
1007 * paths (which provide minimum power consumption anyway).
1008 */
1009static int wm8993_class_w_put(struct snd_kcontrol *kcontrol,
1010 struct snd_ctl_elem_value *ucontrol)
1011{
1012 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1013 struct snd_soc_codec *codec = widget->codec;
1014 struct wm8993_priv *wm8993 = codec->private_data;
1015 int ret;
1016
1017 /* Turn it off if we're using the main output mixer */
1018 if (ucontrol->value.integer.value[0] == 0) {
1019 if (wm8993->class_w_users == 0) {
1020 dev_dbg(codec->dev, "Disabling Class W\n");
1021 snd_soc_update_bits(codec, WM8993_CLASS_W_0,
1022 WM8993_CP_DYN_FREQ |
1023 WM8993_CP_DYN_V,
1024 0);
1025 }
1026 wm8993->class_w_users++;
1027 }
1028
1029 /* Implement the change */
1030 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1031
1032 /* Enable it if we're using the direct DAC path */
1033 if (ucontrol->value.integer.value[0] == 1) {
1034 if (wm8993->class_w_users == 1) {
1035 dev_dbg(codec->dev, "Enabling Class W\n");
1036 snd_soc_update_bits(codec, WM8993_CLASS_W_0,
1037 WM8993_CP_DYN_FREQ |
1038 WM8993_CP_DYN_V,
1039 WM8993_CP_DYN_FREQ |
1040 WM8993_CP_DYN_V);
1041 }
1042 wm8993->class_w_users--;
1043 }
1044
1045 dev_dbg(codec->dev, "Indirect DAC use count now %d\n",
1046 wm8993->class_w_users);
1047
1048 return ret;
1049}
1050
1051#define SOC_DAPM_ENUM_W(xname, xenum) \
1052{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1053 .info = snd_soc_info_enum_double, \
1054 .get = snd_soc_dapm_get_enum_double, \
1055 .put = wm8993_class_w_put, \
1056 .private_value = (unsigned long)&xenum }
1057
1058static int hp_event(struct snd_soc_dapm_widget *w,
1059 struct snd_kcontrol *kcontrol, int event)
1060{
1061 struct snd_soc_codec *codec = w->codec;
1062 unsigned int reg = wm8993_read(codec, WM8993_ANALOGUE_HP_0);
1063
1064 switch (event) {
1065 case SND_SOC_DAPM_POST_PMU:
1066 snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
1067 WM8993_CP_ENA, WM8993_CP_ENA);
1068
1069 msleep(5);
1070
1071 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
1072 WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
1073 WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);
1074
1075 reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
1076 wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg);
1077
1078 /* Start the DC servo */
1079 snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
1080 WM8993_DCS_ENA_CHAN_0 |
1081 WM8993_DCS_ENA_CHAN_1 |
1082 WM8993_DCS_TRIG_STARTUP_1 |
1083 WM8993_DCS_TRIG_STARTUP_0,
1084 WM8993_DCS_ENA_CHAN_0 |
1085 WM8993_DCS_ENA_CHAN_1 |
1086 WM8993_DCS_TRIG_STARTUP_1 |
1087 WM8993_DCS_TRIG_STARTUP_0);
1088 wait_for_dc_servo(codec, WM8993_DCS_TRIG_STARTUP_0 |
1089 WM8993_DCS_TRIG_STARTUP_1);
1090 snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
1091 WM8993_DCS_TIMER_PERIOD_01_MASK, 0xa);
1092
1093 reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
1094 WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
1095 wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg);
1096 break;
1097
1098 case SND_SOC_DAPM_PRE_PMD:
1099 reg &= ~(WM8993_HPOUT1L_RMV_SHORT |
1100 WM8993_HPOUT1L_DLY |
1101 WM8993_HPOUT1L_OUTP |
1102 WM8993_HPOUT1R_RMV_SHORT |
1103 WM8993_HPOUT1R_DLY |
1104 WM8993_HPOUT1R_OUTP);
1105
1106 snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
1107 WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
1108 snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
1109 WM8993_DCS_ENA_CHAN_0 |
1110 WM8993_DCS_ENA_CHAN_1, 0);
1111
1112 wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg);
1113 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
1114 WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
1115 0);
1116
1117 snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
1118 WM8993_CP_ENA, 0);
1119 break;
1120 }
1121
1122 return 0;
1123}
1124
1125static const struct snd_kcontrol_new in1l_pga[] = {
1126SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
1127SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
1128};
1129
1130static const struct snd_kcontrol_new in1r_pga[] = {
1131SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0),
1132SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0),
1133};
1134
1135static const struct snd_kcontrol_new in2l_pga[] = {
1136SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0),
1137SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0),
1138};
1139
1140static const struct snd_kcontrol_new in2r_pga[] = {
1141SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0),
1142SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0),
1143};
1144
1145static const struct snd_kcontrol_new mixinl[] = {
1146SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0),
1147SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0),
1148};
1149
1150static const struct snd_kcontrol_new mixinr[] = {
1151SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0),
1152SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
1153};
1154
1155static const struct snd_kcontrol_new left_output_mixer[] = {
1156SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
1157SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
1158SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
1159SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
1160SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
1161SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
1162SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
1163SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
1164};
1165
1166static const struct snd_kcontrol_new right_output_mixer[] = {
1167SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
1168SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
1169SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
1170SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
1171SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
1172SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
1173SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
1174SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
1175};
1176
1177static const struct snd_kcontrol_new earpiece_mixer[] = {
1178SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0),
1179SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0),
1180SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0),
1181};
1182
1183static const struct snd_kcontrol_new left_speaker_mixer[] = {
1184SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0),
1185SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0),
1186SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 3, 1, 0),
1187SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 6, 1, 0),
1188};
1189
1190static const struct snd_kcontrol_new right_speaker_mixer[] = {
1191SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 6, 1, 0),
1192SOC_DAPM_SINGLE("IN1RP Switch", WM8993_SPEAKER_MIXER, 4, 1, 0),
1193SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0),
1194SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0),
1195};
1196
1197static const struct snd_kcontrol_new left_speaker_boost[] = {
1198SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0),
1199SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0),
1200SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0),
1201};
1202
1203static const struct snd_kcontrol_new right_speaker_boost[] = {
1204SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0),
1205SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0),
1206SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0),
1207};
1208
1209static const char *hp_mux_text[] = {
1210 "Mixer",
1211 "DAC",
1212};
1213
1214static const struct soc_enum hpl_enum =
1215 SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
1216
1217static const struct snd_kcontrol_new hpl_mux =
1218 SOC_DAPM_ENUM_W("Left Headphone Mux", hpl_enum);
1219
1220static const struct soc_enum hpr_enum =
1221 SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
1222
1223static const struct snd_kcontrol_new hpr_mux =
1224 SOC_DAPM_ENUM_W("Right Headphone Mux", hpr_enum);
1225
1226static const struct snd_kcontrol_new line1_mix[] = {
1227SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0),
1228SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0),
1229SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
1230};
1231
1232static const struct snd_kcontrol_new line1n_mix[] = {
1233SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0),
1234SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0),
1235};
1236
1237static const struct snd_kcontrol_new line1p_mix[] = {
1238SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
1239};
1240
1241static const struct snd_kcontrol_new line2_mix[] = {
1242SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0),
1243SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0),
1244SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
1245};
1246
1247static const struct snd_kcontrol_new line2n_mix[] = {
1248SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
1249SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
1250};
1251
1252static const struct snd_kcontrol_new line2p_mix[] = {
1253SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
1254};
1255
1256static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = {
1257SND_SOC_DAPM_INPUT("IN1LN"),
1258SND_SOC_DAPM_INPUT("IN1LP"),
1259SND_SOC_DAPM_INPUT("IN2LN"),
1260SND_SOC_DAPM_INPUT("IN2LP/VXRN"),
1261SND_SOC_DAPM_INPUT("IN1RN"),
1262SND_SOC_DAPM_INPUT("IN1RP"),
1263SND_SOC_DAPM_INPUT("IN2RN"),
1264SND_SOC_DAPM_INPUT("IN2RP/VXRP"),
1265
1266SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event,
1267 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1268SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0),
1269SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0),
1270
1271SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0),
1272SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0),
1273
1274SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
1275 in1l_pga, ARRAY_SIZE(in1l_pga)),
1276SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
1277 in1r_pga, ARRAY_SIZE(in1r_pga)),
1278
1279SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
1280 in2l_pga, ARRAY_SIZE(in2l_pga)),
1281SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
1282 in2r_pga, ARRAY_SIZE(in2r_pga)),
1283
1284/* Dummy widgets to represent differential paths */
1285SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
1286
1287SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
1288 mixinl, ARRAY_SIZE(mixinl)),
1289SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
1290 mixinr, ARRAY_SIZE(mixinr)),
1291
1292SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0),
1293SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0),
1294
1295SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0),
1296SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0),
1297
1298SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0,
1299 left_output_mixer, ARRAY_SIZE(left_output_mixer)),
1300SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
1301 right_output_mixer, ARRAY_SIZE(right_output_mixer)),
1302
1303SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
1304SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
1305
1306SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
1307 earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
1308SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0,
1309 NULL, 0, wm8993_earpiece_event,
1310 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1311
1312SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0,
1313 left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
1314SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0,
1315 right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
1316
1317SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
1318 left_speaker_boost, ARRAY_SIZE(left_speaker_boost)),
1319SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
1320 right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
1321
1322SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
1323 NULL, 0),
1324SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
1325 NULL, 0),
1326
1327SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
1328SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
1329SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0,
1330 NULL, 0,
1331 hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
1332
1333SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
1334 line1_mix, ARRAY_SIZE(line1_mix)),
1335SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
1336 line2_mix, ARRAY_SIZE(line2_mix)),
1337
1338SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0,
1339 line1n_mix, ARRAY_SIZE(line1n_mix)),
1340SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0,
1341 line1p_mix, ARRAY_SIZE(line1p_mix)),
1342SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
1343 line2n_mix, ARRAY_SIZE(line2n_mix)),
1344SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
1345 line2p_mix, ARRAY_SIZE(line2p_mix)),
1346
1347SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
1348 NULL, 0),
1349SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
1350 NULL, 0),
1351SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
1352 NULL, 0),
1353SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
1354 NULL, 0),
1355
1356SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
1357SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
1358SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
1359SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
1360SND_SOC_DAPM_OUTPUT("HPOUT1L"),
1361SND_SOC_DAPM_OUTPUT("HPOUT1R"),
1362SND_SOC_DAPM_OUTPUT("HPOUT2P"),
1363SND_SOC_DAPM_OUTPUT("HPOUT2N"),
1364SND_SOC_DAPM_OUTPUT("LINEOUT1P"),
1365SND_SOC_DAPM_OUTPUT("LINEOUT1N"),
1366SND_SOC_DAPM_OUTPUT("LINEOUT2P"),
1367SND_SOC_DAPM_OUTPUT("LINEOUT2N"),
1368};
1369
1370static const struct snd_soc_dapm_route routes[] = {
1371 { "IN1L PGA", "IN1LP Switch", "IN1LP" },
1372 { "IN1L PGA", "IN1LN Switch", "IN1LN" },
1373
1374 { "IN1R PGA", "IN1RP Switch", "IN1RP" },
1375 { "IN1R PGA", "IN1RN Switch", "IN1RN" },
1376
1377 { "IN2L PGA", "IN2LP Switch", "IN2LP/VXRN" },
1378 { "IN2L PGA", "IN2LN Switch", "IN2LN" },
1379
1380 { "IN2R PGA", "IN2RP Switch", "IN2RP/VXRP" },
1381 { "IN2R PGA", "IN2RN Switch", "IN2RN" },
1382
1383 { "Direct Voice", NULL, "IN2LP/VXRN" },
1384 { "Direct Voice", NULL, "IN2RP/VXRP" },
1385
1386 { "MIXINL", "IN1L Switch", "IN1L PGA" },
1387 { "MIXINL", "IN2L Switch", "IN2L PGA" },
1388 { "MIXINL", NULL, "Direct Voice" },
1389 { "MIXINL", NULL, "IN1LP" },
1390 { "MIXINL", NULL, "Left Output Mixer" },
1391
1392 { "MIXINR", "IN1R Switch", "IN1R PGA" },
1393 { "MIXINR", "IN2R Switch", "IN2R PGA" },
1394 { "MIXINR", NULL, "Direct Voice" },
1395 { "MIXINR", NULL, "IN1RP" },
1396 { "MIXINR", NULL, "Right Output Mixer" },
1397
1398 { "ADCL", NULL, "MIXINL" },
1399 { "ADCL", NULL, "CLK_SYS" },
1400 { "ADCL", NULL, "CLK_DSP" },
1401 { "ADCR", NULL, "MIXINR" },
1402 { "ADCR", NULL, "CLK_SYS" },
1403 { "ADCR", NULL, "CLK_DSP" },
1404
1405 { "DACL", NULL, "CLK_SYS" },
1406 { "DACL", NULL, "CLK_DSP" },
1407 { "DACR", NULL, "CLK_SYS" },
1408 { "DACR", NULL, "CLK_DSP" },
1409
1410 { "Left Output Mixer", "Left Input Switch", "MIXINL" },
1411 { "Left Output Mixer", "Right Input Switch", "MIXINR" },
1412 { "Left Output Mixer", "IN2RN Switch", "IN2RN" },
1413 { "Left Output Mixer", "IN2LN Switch", "IN2LN" },
1414 { "Left Output Mixer", "IN2LP Switch", "IN2LP/VXRN" },
1415 { "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
1416 { "Left Output Mixer", "IN1R Switch", "IN1R PGA" },
1417 { "Left Output Mixer", "DAC Switch", "DACL" },
1418
1419 { "Right Output Mixer", "Left Input Switch", "MIXINL" },
1420 { "Right Output Mixer", "Right Input Switch", "MIXINR" },
1421 { "Right Output Mixer", "IN2LN Switch", "IN2LN" },
1422 { "Right Output Mixer", "IN2RN Switch", "IN2RN" },
1423 { "Right Output Mixer", "IN2RP Switch", "IN2RP/VXRP" },
1424 { "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
1425 { "Right Output Mixer", "IN1R Switch", "IN1R PGA" },
1426 { "Right Output Mixer", "DAC Switch", "DACR" },
1427
1428 { "Left Output PGA", NULL, "Left Output Mixer" },
1429 { "Left Output PGA", NULL, "CLK_SYS" },
1430 { "Left Output PGA", NULL, "TOCLK" },
1431
1432 { "Right Output PGA", NULL, "Right Output Mixer" },
1433 { "Right Output PGA", NULL, "CLK_SYS" },
1434 { "Right Output PGA", NULL, "TOCLK" },
1435
1436 { "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" },
1437 { "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
1438 { "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },
1439
1440 { "Earpiece Driver", NULL, "Earpiece Mixer" },
1441 { "HPOUT2N", NULL, "Earpiece Driver" },
1442 { "HPOUT2P", NULL, "Earpiece Driver" },
1443
1444 { "SPKL", "Input Switch", "MIXINL" },
1445 { "SPKL", "IN1LP Switch", "IN1LP" },
1446 { "SPKL", "Output Switch", "Left Output Mixer" },
1447 { "SPKL", "DAC Switch", "DACL" },
1448 { "SPKL", NULL, "CLK_SYS" },
1449 { "SPKL", NULL, "TOCLK" },
1450
1451 { "SPKR", "Input Switch", "MIXINR" },
1452 { "SPKR", "IN1RP Switch", "IN1RP" },
1453 { "SPKR", "Output Switch", "Right Output Mixer" },
1454 { "SPKR", "DAC Switch", "DACR" },
1455 { "SPKR", NULL, "CLK_SYS" },
1456 { "SPKR", NULL, "TOCLK" },
1457
1458 { "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
1459 { "SPKL Boost", "SPKL Switch", "SPKL" },
1460 { "SPKL Boost", "SPKR Switch", "SPKR" },
1461
1462 { "SPKR Boost", "Direct Voice Switch", "Direct Voice" },
1463 { "SPKR Boost", "SPKR Switch", "SPKR" },
1464 { "SPKR Boost", "SPKL Switch", "SPKL" },
1465
1466 { "SPKL Driver", NULL, "SPKL Boost" },
1467 { "SPKL Driver", NULL, "CLK_SYS" },
1468
1469 { "SPKR Driver", NULL, "SPKR Boost" },
1470 { "SPKR Driver", NULL, "CLK_SYS" },
1471
1472 { "SPKOUTLP", NULL, "SPKL Driver" },
1473 { "SPKOUTLN", NULL, "SPKL Driver" },
1474 { "SPKOUTRP", NULL, "SPKR Driver" },
1475 { "SPKOUTRN", NULL, "SPKR Driver" },
1476
1477 { "Left Headphone Mux", "DAC", "DACL" },
1478 { "Left Headphone Mux", "Mixer", "Left Output Mixer" },
1479 { "Right Headphone Mux", "DAC", "DACR" },
1480 { "Right Headphone Mux", "Mixer", "Right Output Mixer" },
1481
1482 { "Headphone PGA", NULL, "Left Headphone Mux" },
1483 { "Headphone PGA", NULL, "Right Headphone Mux" },
1484 { "Headphone PGA", NULL, "CLK_SYS" },
1485 { "Headphone PGA", NULL, "TOCLK" },
1486
1487 { "HPOUT1L", NULL, "Headphone PGA" },
1488 { "HPOUT1R", NULL, "Headphone PGA" },
1489
1490 { "LINEOUT1N", NULL, "LINEOUT1N Driver" },
1491 { "LINEOUT1P", NULL, "LINEOUT1P Driver" },
1492 { "LINEOUT2N", NULL, "LINEOUT2N Driver" },
1493 { "LINEOUT2P", NULL, "LINEOUT2P Driver" },
1494};
1495
1496static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
1497 { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
1498 { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
1499 { "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" },
1500
1501 { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
1502 { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
1503};
1504
1505static const struct snd_soc_dapm_route lineout1_se_routes[] = {
1506 { "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" },
1507 { "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" },
1508
1509 { "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" },
1510
1511 { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
1512 { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
1513};
1514
1515static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
1516 { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
1517 { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
1518 { "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" },
1519
1520 { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
1521 { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
1522};
1523
1524static const struct snd_soc_dapm_route lineout2_se_routes[] = {
1525 { "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" },
1526 { "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" },
1527
1528 { "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" },
1529
1530 { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
1531 { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
1532};
1533
1534static int wm8993_set_bias_level(struct snd_soc_codec *codec,
1535 enum snd_soc_bias_level level)
1536{
1537 struct wm8993_priv *wm8993 = codec->private_data;
1538
1539 switch (level) {
1540 case SND_SOC_BIAS_ON:
1541 case SND_SOC_BIAS_PREPARE:
1542 /* VMID=2*40k */
1543 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
1544 WM8993_VMID_SEL_MASK, 0x2);
1545 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2,
1546 WM8993_TSHUT_ENA, WM8993_TSHUT_ENA);
1547 break;
1548
1549 case SND_SOC_BIAS_STANDBY:
1550 if (codec->bias_level == SND_SOC_BIAS_OFF) {
1551 /* Bring up VMID with fast soft start */
1552 snd_soc_update_bits(codec, WM8993_ANTIPOP2,
1553 WM8993_STARTUP_BIAS_ENA |
1554 WM8993_VMID_BUF_ENA |
1555 WM8993_VMID_RAMP_MASK |
1556 WM8993_BIAS_SRC,
1557 WM8993_STARTUP_BIAS_ENA |
1558 WM8993_VMID_BUF_ENA |
1559 WM8993_VMID_RAMP_MASK |
1560 WM8993_BIAS_SRC);
1561
1562 /* If either line output is single ended we
1563 * need the VMID buffer */
1564 if (!wm8993->pdata.lineout1_diff ||
1565 !wm8993->pdata.lineout2_diff)
1566 snd_soc_update_bits(codec, WM8993_ANTIPOP1,
1567 WM8993_LINEOUT_VMID_BUF_ENA,
1568 WM8993_LINEOUT_VMID_BUF_ENA);
1569
1570 /* VMID=2*40k */
1571 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
1572 WM8993_VMID_SEL_MASK |
1573 WM8993_BIAS_ENA,
1574 WM8993_BIAS_ENA | 0x2);
1575 msleep(32);
1576
1577 /* Switch to normal bias */
1578 snd_soc_update_bits(codec, WM8993_ANTIPOP2,
1579 WM8993_BIAS_SRC |
1580 WM8993_STARTUP_BIAS_ENA, 0);
1581 }
1582
1583 /* VMID=2*240k */
1584 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
1585 WM8993_VMID_SEL_MASK, 0x4);
1586
1587 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2,
1588 WM8993_TSHUT_ENA, 0);
1589 break;
1590
1591 case SND_SOC_BIAS_OFF:
1592 snd_soc_update_bits(codec, WM8993_ANTIPOP1,
1593 WM8993_LINEOUT_VMID_BUF_ENA, 0);
1594
1595 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
1596 WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA,
1597 0);
1598 break;
1599 }
1600
1601 codec->bias_level = level;
1602
1603 return 0;
1604}
1605
1606static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai,
1607 int clk_id, unsigned int freq, int dir)
1608{
1609 struct snd_soc_codec *codec = codec_dai->codec;
1610 struct wm8993_priv *wm8993 = codec->private_data;
1611
1612 switch (clk_id) {
1613 case WM8993_SYSCLK_MCLK:
1614 wm8993->mclk_rate = freq;
1615 case WM8993_SYSCLK_FLL:
1616 wm8993->sysclk_source = clk_id;
1617 break;
1618
1619 default:
1620 return -EINVAL;
1621 }
1622
1623 return 0;
1624}
1625
1626static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
1627 unsigned int fmt)
1628{
1629 struct snd_soc_codec *codec = dai->codec;
1630 struct wm8993_priv *wm8993 = codec->private_data;
1631 unsigned int aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1);
1632 unsigned int aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4);
1633
1634 aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV |
1635 WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK);
1636 aif4 &= ~WM8993_LRCLK_DIR;
1637
1638 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1639 case SND_SOC_DAIFMT_CBS_CFS:
1640 wm8993->master = 0;
1641 break;
1642 case SND_SOC_DAIFMT_CBS_CFM:
1643 aif4 |= WM8993_LRCLK_DIR;
1644 wm8993->master = 1;
1645 break;
1646 case SND_SOC_DAIFMT_CBM_CFS:
1647 aif1 |= WM8993_BCLK_DIR;
1648 wm8993->master = 1;
1649 break;
1650 case SND_SOC_DAIFMT_CBM_CFM:
1651 aif1 |= WM8993_BCLK_DIR;
1652 aif4 |= WM8993_LRCLK_DIR;
1653 wm8993->master = 1;
1654 break;
1655 default:
1656 return -EINVAL;
1657 }
1658
1659 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1660 case SND_SOC_DAIFMT_DSP_B:
1661 aif1 |= WM8993_AIF_LRCLK_INV;
1662 case SND_SOC_DAIFMT_DSP_A:
1663 aif1 |= 0x18;
1664 break;
1665 case SND_SOC_DAIFMT_I2S:
1666 aif1 |= 0x10;
1667 break;
1668 case SND_SOC_DAIFMT_RIGHT_J:
1669 break;
1670 case SND_SOC_DAIFMT_LEFT_J:
1671 aif1 |= 0x8;
1672 break;
1673 default:
1674 return -EINVAL;
1675 }
1676
1677 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1678 case SND_SOC_DAIFMT_DSP_A:
1679 case SND_SOC_DAIFMT_DSP_B:
1680 /* frame inversion not valid for DSP modes */
1681 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1682 case SND_SOC_DAIFMT_NB_NF:
1683 break;
1684 case SND_SOC_DAIFMT_IB_NF:
1685 aif1 |= WM8993_AIF_BCLK_INV;
1686 break;
1687 default:
1688 return -EINVAL;
1689 }
1690 break;
1691
1692 case SND_SOC_DAIFMT_I2S:
1693 case SND_SOC_DAIFMT_RIGHT_J:
1694 case SND_SOC_DAIFMT_LEFT_J:
1695 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1696 case SND_SOC_DAIFMT_NB_NF:
1697 break;
1698 case SND_SOC_DAIFMT_IB_IF:
1699 aif1 |= WM8993_AIF_BCLK_INV | WM8993_AIF_LRCLK_INV;
1700 break;
1701 case SND_SOC_DAIFMT_IB_NF:
1702 aif1 |= WM8993_AIF_BCLK_INV;
1703 break;
1704 case SND_SOC_DAIFMT_NB_IF:
1705 aif1 |= WM8993_AIF_LRCLK_INV;
1706 break;
1707 default:
1708 return -EINVAL;
1709 }
1710 break;
1711 default:
1712 return -EINVAL;
1713 }
1714
1715 wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
1716 wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
1717
1718 return 0;
1719}
1720
1721static int wm8993_hw_params(struct snd_pcm_substream *substream,
1722 struct snd_pcm_hw_params *params,
1723 struct snd_soc_dai *dai)
1724{
1725 struct snd_soc_codec *codec = dai->codec;
1726 struct wm8993_priv *wm8993 = codec->private_data;
1727 int ret, i, best, best_val, cur_val;
1728 unsigned int clocking1, clocking3, aif1, aif4;
1729
1730 clocking1 = wm8993_read(codec, WM8993_CLOCKING_1);
1731 clocking1 &= ~WM8993_BCLK_DIV_MASK;
1732
1733 clocking3 = wm8993_read(codec, WM8993_CLOCKING_3);
1734 clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK);
1735
1736 aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1);
1737 aif1 &= ~WM8993_AIF_WL_MASK;
1738
1739 aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4);
1740 aif4 &= ~WM8993_LRCLK_RATE_MASK;
1741
1742 /* What BCLK do we need? */
1743 wm8993->fs = params_rate(params);
1744 wm8993->bclk = 2 * wm8993->fs;
1745 switch (params_format(params)) {
1746 case SNDRV_PCM_FORMAT_S16_LE:
1747 wm8993->bclk *= 16;
1748 break;
1749 case SNDRV_PCM_FORMAT_S20_3LE:
1750 wm8993->bclk *= 20;
1751 aif1 |= 0x8;
1752 break;
1753 case SNDRV_PCM_FORMAT_S24_LE:
1754 wm8993->bclk *= 24;
1755 aif1 |= 0x10;
1756 break;
1757 case SNDRV_PCM_FORMAT_S32_LE:
1758 wm8993->bclk *= 32;
1759 aif1 |= 0x18;
1760 break;
1761 default:
1762 return -EINVAL;
1763 }
1764
1765 dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk);
1766
1767 ret = configure_clock(codec);
1768 if (ret != 0)
1769 return ret;
1770
1771 /* Select nearest CLK_SYS_RATE */
1772 best = 0;
1773 best_val = abs((wm8993->sysclk_rate / clk_sys_rates[0].ratio)
1774 - wm8993->fs);
1775 for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
1776 cur_val = abs((wm8993->sysclk_rate /
1777 clk_sys_rates[i].ratio) - wm8993->fs);;
1778 if (cur_val < best_val) {
1779 best = i;
1780 best_val = cur_val;
1781 }
1782 }
1783 dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
1784 clk_sys_rates[best].ratio);
1785 clocking3 |= (clk_sys_rates[best].clk_sys_rate
1786 << WM8993_CLK_SYS_RATE_SHIFT);
1787
1788 /* SAMPLE_RATE */
1789 best = 0;
1790 best_val = abs(wm8993->fs - sample_rates[0].rate);
1791 for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
1792 /* Closest match */
1793 cur_val = abs(wm8993->fs - sample_rates[i].rate);
1794 if (cur_val < best_val) {
1795 best = i;
1796 best_val = cur_val;
1797 }
1798 }
1799 dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
1800 sample_rates[best].rate);
1801 clocking3 |= (sample_rates[best].sample_rate
1802 << WM8993_SAMPLE_RATE_SHIFT);
1803
1804 /* BCLK_DIV */
1805 best = 0;
1806 best_val = INT_MAX;
1807 for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
1808 cur_val = ((wm8993->sysclk_rate * 10) / bclk_divs[i].div)
1809 - wm8993->bclk;
1810 if (cur_val < 0) /* Table is sorted */
1811 break;
1812 if (cur_val < best_val) {
1813 best = i;
1814 best_val = cur_val;
1815 }
1816 }
1817 wm8993->bclk = (wm8993->sysclk_rate * 10) / bclk_divs[best].div;
1818 dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
1819 bclk_divs[best].div, wm8993->bclk);
1820 clocking1 |= bclk_divs[best].bclk_div << WM8993_BCLK_DIV_SHIFT;
1821
1822 /* LRCLK is a simple fraction of BCLK */
1823 dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs);
1824 aif4 |= wm8993->bclk / wm8993->fs;
1825
1826 wm8993_write(codec, WM8993_CLOCKING_1, clocking1);
1827 wm8993_write(codec, WM8993_CLOCKING_3, clocking3);
1828 wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
1829 wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
1830
1831 /* ReTune Mobile? */
1832 if (wm8993->pdata.num_retune_configs) {
1833 u16 eq1 = wm8993_read(codec, WM8993_EQ1);
1834 struct wm8993_retune_mobile_setting *s;
1835
1836 best = 0;
1837 best_val = abs(wm8993->pdata.retune_configs[0].rate
1838 - wm8993->fs);
1839 for (i = 0; i < wm8993->pdata.num_retune_configs; i++) {
1840 cur_val = abs(wm8993->pdata.retune_configs[i].rate
1841 - wm8993->fs);
1842 if (cur_val < best_val) {
1843 best_val = cur_val;
1844 best = i;
1845 }
1846 }
1847 s = &wm8993->pdata.retune_configs[best];
1848
1849 dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n",
1850 s->name, s->rate);
1851
1852 /* Disable EQ while we reconfigure */
1853 snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, 0);
1854
1855 for (i = 1; i < ARRAY_SIZE(s->config); i++)
1856 wm8993_write(codec, WM8993_EQ1 + i, s->config[i]);
1857
1858 snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, eq1);
1859 }
1860
1861 return 0;
1862}
1863
1864static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1865{
1866 struct snd_soc_codec *codec = codec_dai->codec;
1867 unsigned int reg;
1868
1869 reg = wm8993_read(codec, WM8993_DAC_CTRL);
1870
1871 if (mute)
1872 reg |= WM8993_DAC_MUTE;
1873 else
1874 reg &= ~WM8993_DAC_MUTE;
1875
1876 wm8993_write(codec, WM8993_DAC_CTRL, reg);
1877
1878 return 0;
1879}
1880
1881static struct snd_soc_dai_ops wm8993_ops = {
1882 .set_sysclk = wm8993_set_sysclk,
1883 .set_fmt = wm8993_set_dai_fmt,
1884 .hw_params = wm8993_hw_params,
1885 .digital_mute = wm8993_digital_mute,
1886 .set_pll = wm8993_set_fll,
1887};
1888
1889#define WM8993_RATES SNDRV_PCM_RATE_8000_48000
1890
1891#define WM8993_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
1892 SNDRV_PCM_FMTBIT_S20_3LE |\
1893 SNDRV_PCM_FMTBIT_S24_LE |\
1894 SNDRV_PCM_FMTBIT_S32_LE)
1895
1896struct snd_soc_dai wm8993_dai = {
1897 .name = "WM8993",
1898 .playback = {
1899 .stream_name = "Playback",
1900 .channels_min = 1,
1901 .channels_max = 2,
1902 .rates = WM8993_RATES,
1903 .formats = WM8993_FORMATS,
1904 },
1905 .capture = {
1906 .stream_name = "Capture",
1907 .channels_min = 1,
1908 .channels_max = 2,
1909 .rates = WM8993_RATES,
1910 .formats = WM8993_FORMATS,
1911 },
1912 .ops = &wm8993_ops,
1913 .symmetric_rates = 1,
1914};
1915EXPORT_SYMBOL_GPL(wm8993_dai);
1916
1917static struct snd_soc_codec *wm8993_codec;
1918
1919static int wm8993_probe(struct platform_device *pdev)
1920{
1921 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1922 struct snd_soc_codec *codec;
1923 struct wm8993_priv *wm8993;
1924 int ret = 0;
1925
1926 if (!wm8993_codec) {
1927 dev_err(&pdev->dev, "I2C device not yet probed\n");
1928 goto err;
1929 }
1930
1931 socdev->card->codec = wm8993_codec;
1932 codec = wm8993_codec;
1933 wm8993 = codec->private_data;
1934
1935 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1936 if (ret < 0) {
1937 dev_err(codec->dev, "failed to create pcms\n");
1938 goto err;
1939 }
1940
1941 snd_soc_add_controls(codec, wm8993_snd_controls,
1942 ARRAY_SIZE(wm8993_snd_controls));
1943 if (wm8993->pdata.num_retune_configs != 0) {
1944 dev_dbg(codec->dev, "Using ReTune Mobile\n");
1945 } else {
1946 dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n");
1947 snd_soc_add_controls(codec, wm8993_eq_controls,
1948 ARRAY_SIZE(wm8993_eq_controls));
1949 }
1950
1951 snd_soc_dapm_new_controls(codec, wm8993_dapm_widgets,
1952 ARRAY_SIZE(wm8993_dapm_widgets));
1953
1954 snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
1955
1956 if (wm8993->pdata.lineout1_diff)
1957 snd_soc_dapm_add_routes(codec,
1958 lineout1_diff_routes,
1959 ARRAY_SIZE(lineout1_diff_routes));
1960 else
1961 snd_soc_dapm_add_routes(codec,
1962 lineout1_se_routes,
1963 ARRAY_SIZE(lineout1_se_routes));
1964
1965 if (wm8993->pdata.lineout2_diff)
1966 snd_soc_dapm_add_routes(codec,
1967 lineout2_diff_routes,
1968 ARRAY_SIZE(lineout2_diff_routes));
1969 else
1970 snd_soc_dapm_add_routes(codec,
1971 lineout2_se_routes,
1972 ARRAY_SIZE(lineout2_se_routes));
1973
1974 snd_soc_dapm_new_widgets(codec);
1975
1976 ret = snd_soc_init_card(socdev);
1977 if (ret < 0) {
1978 dev_err(codec->dev, "failed to register card\n");
1979 goto card_err;
1980 }
1981
1982 return ret;
1983
1984card_err:
1985 snd_soc_free_pcms(socdev);
1986 snd_soc_dapm_free(socdev);
1987err:
1988 return ret;
1989}
1990
1991static int wm8993_remove(struct platform_device *pdev)
1992{
1993 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1994
1995 snd_soc_free_pcms(socdev);
1996 snd_soc_dapm_free(socdev);
1997
1998 return 0;
1999}
2000
2001struct snd_soc_codec_device soc_codec_dev_wm8993 = {
2002 .probe = wm8993_probe,
2003 .remove = wm8993_remove,
2004};
2005EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);
2006
2007static int wm8993_i2c_probe(struct i2c_client *i2c,
2008 const struct i2c_device_id *id)
2009{
2010 struct wm8993_priv *wm8993;
2011 struct snd_soc_codec *codec;
2012 unsigned int val;
2013 int ret;
2014
2015 if (wm8993_codec) {
2016 dev_err(&i2c->dev, "A WM8993 is already registered\n");
2017 return -EINVAL;
2018 }
2019
2020 wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL);
2021 if (wm8993 == NULL)
2022 return -ENOMEM;
2023
2024 codec = &wm8993->codec;
2025 if (i2c->dev.platform_data)
2026 memcpy(&wm8993->pdata, i2c->dev.platform_data,
2027 sizeof(wm8993->pdata));
2028
2029 mutex_init(&codec->mutex);
2030 INIT_LIST_HEAD(&codec->dapm_widgets);
2031 INIT_LIST_HEAD(&codec->dapm_paths);
2032
2033 codec->name = "WM8993";
2034 codec->read = wm8993_read;
2035 codec->write = wm8993_write;
2036 codec->hw_write = (hw_write_t)i2c_master_send;
2037 codec->reg_cache = wm8993->reg_cache;
2038 codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache);
2039 codec->bias_level = SND_SOC_BIAS_OFF;
2040 codec->set_bias_level = wm8993_set_bias_level;
2041 codec->dai = &wm8993_dai;
2042 codec->num_dai = 1;
2043 codec->private_data = wm8993;
2044
2045 memcpy(wm8993->reg_cache, wm8993_reg_defaults,
2046 sizeof(wm8993->reg_cache));
2047
2048 i2c_set_clientdata(i2c, wm8993);
2049 codec->control_data = i2c;
2050 wm8993_codec = codec;
2051
2052 codec->dev = &i2c->dev;
2053
2054 val = wm8993_read_hw(codec, WM8993_SOFTWARE_RESET);
2055 if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
2056 dev_err(codec->dev, "Invalid ID register value %x\n", val);
2057 ret = -EINVAL;
2058 goto err;
2059 }
2060
2061 ret = wm8993_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
2062 if (ret != 0)
2063 goto err;
2064
2065 /* By default we're using the output mixers */
2066 wm8993->class_w_users = 2;
2067
2068 /* Latch volume update bits and default ZC on */
2069 snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
2070 WM8993_IN1_VU, WM8993_IN1_VU);
2071 snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
2072 WM8993_IN1_VU, WM8993_IN1_VU);
2073 snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
2074 WM8993_IN2_VU, WM8993_IN2_VU);
2075 snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
2076 WM8993_IN2_VU, WM8993_IN2_VU);
2077
2078 snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
2079 WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
2080
2081 snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
2082 WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC);
2083 snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
2084 WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
2085 WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
2086
2087 snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
2088 WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC);
2089 snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
2090 WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
2091 WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
2092
2093 snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
2094 WM8993_DAC_VU, WM8993_DAC_VU);
2095 snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
2096 WM8993_ADC_VU, WM8993_ADC_VU);
2097
2098 /* Manualy manage the HPOUT sequencing for independent stereo
2099 * control. */
2100 snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
2101 WM8993_HPOUT1_AUTO_PU, 0);
2102
2103 /* Use automatic clock configuration */
2104 snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
2105
2106 if (!wm8993->pdata.lineout1_diff)
2107 snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
2108 WM8993_LINEOUT1_MODE,
2109 WM8993_LINEOUT1_MODE);
2110 if (!wm8993->pdata.lineout2_diff)
2111 snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
2112 WM8993_LINEOUT2_MODE,
2113 WM8993_LINEOUT2_MODE);
2114
2115 if (wm8993->pdata.lineout1fb)
2116 snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
2117 WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
2118
2119 if (wm8993->pdata.lineout2fb)
2120 snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
2121 WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
2122
2123 /* Apply the microphone bias/detection configuration - the
2124 * platform data is directly applicable to the register. */
2125 snd_soc_update_bits(codec, WM8993_MICBIAS,
2126 WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
2127 WM8993_MICB1_LVL | WM8993_MICB2_LVL,
2128 wm8993->pdata.jd_scthr << WM8993_JD_SCTHR_SHIFT |
2129 wm8993->pdata.jd_thr << WM8993_JD_THR_SHIFT |
2130 wm8993->pdata.micbias1_lvl |
2131 wm8993->pdata.micbias1_lvl << 1);
2132
2133 ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
2134 if (ret != 0)
2135 goto err;
2136
2137 wm8993_dai.dev = codec->dev;
2138
2139 ret = snd_soc_register_dai(&wm8993_dai);
2140 if (ret != 0)
2141 goto err_bias;
2142
2143 ret = snd_soc_register_codec(codec);
2144
2145 return 0;
2146
2147err_bias:
2148 wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
2149err:
2150 wm8993_codec = NULL;
2151 kfree(wm8993);
2152 return ret;
2153}
2154
2155static int wm8993_i2c_remove(struct i2c_client *client)
2156{
2157 struct wm8993_priv *wm8993 = i2c_get_clientdata(client);
2158
2159 snd_soc_unregister_codec(&wm8993->codec);
2160 snd_soc_unregister_dai(&wm8993_dai);
2161
2162 wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF);
2163 kfree(wm8993);
2164
2165 return 0;
2166}
2167
2168static const struct i2c_device_id wm8993_i2c_id[] = {
2169 { "wm8993", 0 },
2170 { }
2171};
2172MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
2173
2174static struct i2c_driver wm8993_i2c_driver = {
2175 .driver = {
2176 .name = "WM8993",
2177 .owner = THIS_MODULE,
2178 },
2179 .probe = wm8993_i2c_probe,
2180 .remove = wm8993_i2c_remove,
2181 .id_table = wm8993_i2c_id,
2182};
2183
2184
2185static int __init wm8993_modinit(void)
2186{
2187 int ret;
2188
2189 ret = i2c_add_driver(&wm8993_i2c_driver);
2190 if (ret != 0)
2191 pr_err("WM8993: Unable to register I2C driver: %d\n", ret);
2192
2193 return ret;
2194}
2195module_init(wm8993_modinit);
2196
2197static void __exit wm8993_exit(void)
2198{
2199 i2c_del_driver(&wm8993_i2c_driver);
2200}
2201module_exit(wm8993_exit);
2202
2203
2204MODULE_DESCRIPTION("ASoC WM8993 driver");
2205MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2206MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8993.h b/sound/soc/codecs/wm8993.h
new file mode 100644
index 000000000000..30e71ca88dad
--- /dev/null
+++ b/sound/soc/codecs/wm8993.h
@@ -0,0 +1,2132 @@
1#ifndef WM8993_H
2#define WM8993_H
3
4extern struct snd_soc_dai wm8993_dai;
5extern struct snd_soc_codec_device soc_codec_dev_wm8993;
6
7#define WM8993_SYSCLK_MCLK 1
8#define WM8993_SYSCLK_FLL 2
9
10#define WM8993_FLL_MCLK 1
11#define WM8993_FLL_BCLK 2
12#define WM8993_FLL_LRCLK 3
13
14/*
15 * Register values.
16 */
17#define WM8993_SOFTWARE_RESET 0x00
18#define WM8993_POWER_MANAGEMENT_1 0x01
19#define WM8993_POWER_MANAGEMENT_2 0x02
20#define WM8993_POWER_MANAGEMENT_3 0x03
21#define WM8993_AUDIO_INTERFACE_1 0x04
22#define WM8993_AUDIO_INTERFACE_2 0x05
23#define WM8993_CLOCKING_1 0x06
24#define WM8993_CLOCKING_2 0x07
25#define WM8993_AUDIO_INTERFACE_3 0x08
26#define WM8993_AUDIO_INTERFACE_4 0x09
27#define WM8993_DAC_CTRL 0x0A
28#define WM8993_LEFT_DAC_DIGITAL_VOLUME 0x0B
29#define WM8993_RIGHT_DAC_DIGITAL_VOLUME 0x0C
30#define WM8993_DIGITAL_SIDE_TONE 0x0D
31#define WM8993_ADC_CTRL 0x0E
32#define WM8993_LEFT_ADC_DIGITAL_VOLUME 0x0F
33#define WM8993_RIGHT_ADC_DIGITAL_VOLUME 0x10
34#define WM8993_GPIO_CTRL_1 0x12
35#define WM8993_GPIO1 0x13
36#define WM8993_IRQ_DEBOUNCE 0x14
37#define WM8993_GPIOCTRL_2 0x16
38#define WM8993_GPIO_POL 0x17
39#define WM8993_LEFT_LINE_INPUT_1_2_VOLUME 0x18
40#define WM8993_LEFT_LINE_INPUT_3_4_VOLUME 0x19
41#define WM8993_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A
42#define WM8993_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B
43#define WM8993_LEFT_OUTPUT_VOLUME 0x1C
44#define WM8993_RIGHT_OUTPUT_VOLUME 0x1D
45#define WM8993_LINE_OUTPUTS_VOLUME 0x1E
46#define WM8993_HPOUT2_VOLUME 0x1F
47#define WM8993_LEFT_OPGA_VOLUME 0x20
48#define WM8993_RIGHT_OPGA_VOLUME 0x21
49#define WM8993_SPKMIXL_ATTENUATION 0x22
50#define WM8993_SPKMIXR_ATTENUATION 0x23
51#define WM8993_SPKOUT_MIXERS 0x24
52#define WM8993_SPKOUT_BOOST 0x25
53#define WM8993_SPEAKER_VOLUME_LEFT 0x26
54#define WM8993_SPEAKER_VOLUME_RIGHT 0x27
55#define WM8993_INPUT_MIXER2 0x28
56#define WM8993_INPUT_MIXER3 0x29
57#define WM8993_INPUT_MIXER4 0x2A
58#define WM8993_INPUT_MIXER5 0x2B
59#define WM8993_INPUT_MIXER6 0x2C
60#define WM8993_OUTPUT_MIXER1 0x2D
61#define WM8993_OUTPUT_MIXER2 0x2E
62#define WM8993_OUTPUT_MIXER3 0x2F
63#define WM8993_OUTPUT_MIXER4 0x30
64#define WM8993_OUTPUT_MIXER5 0x31
65#define WM8993_OUTPUT_MIXER6 0x32
66#define WM8993_HPOUT2_MIXER 0x33
67#define WM8993_LINE_MIXER1 0x34
68#define WM8993_LINE_MIXER2 0x35
69#define WM8993_SPEAKER_MIXER 0x36
70#define WM8993_ADDITIONAL_CONTROL 0x37
71#define WM8993_ANTIPOP1 0x38
72#define WM8993_ANTIPOP2 0x39
73#define WM8993_MICBIAS 0x3A
74#define WM8993_FLL_CONTROL_1 0x3C
75#define WM8993_FLL_CONTROL_2 0x3D
76#define WM8993_FLL_CONTROL_3 0x3E
77#define WM8993_FLL_CONTROL_4 0x3F
78#define WM8993_FLL_CONTROL_5 0x40
79#define WM8993_CLOCKING_3 0x41
80#define WM8993_CLOCKING_4 0x42
81#define WM8993_MW_SLAVE_CONTROL 0x43
82#define WM8993_BUS_CONTROL_1 0x45
83#define WM8993_WRITE_SEQUENCER_0 0x46
84#define WM8993_WRITE_SEQUENCER_1 0x47
85#define WM8993_WRITE_SEQUENCER_2 0x48
86#define WM8993_WRITE_SEQUENCER_3 0x49
87#define WM8993_WRITE_SEQUENCER_4 0x4A
88#define WM8993_WRITE_SEQUENCER_5 0x4B
89#define WM8993_CHARGE_PUMP_1 0x4C
90#define WM8993_CLASS_W_0 0x51
91#define WM8993_DC_SERVO_0 0x54
92#define WM8993_DC_SERVO_1 0x55
93#define WM8993_DC_SERVO_3 0x57
94#define WM8993_DC_SERVO_READBACK_0 0x58
95#define WM8993_DC_SERVO_READBACK_1 0x59
96#define WM8993_DC_SERVO_READBACK_2 0x5A
97#define WM8993_ANALOGUE_HP_0 0x60
98#define WM8993_EQ1 0x62
99#define WM8993_EQ2 0x63
100#define WM8993_EQ3 0x64
101#define WM8993_EQ4 0x65
102#define WM8993_EQ5 0x66
103#define WM8993_EQ6 0x67
104#define WM8993_EQ7 0x68
105#define WM8993_EQ8 0x69
106#define WM8993_EQ9 0x6A
107#define WM8993_EQ10 0x6B
108#define WM8993_EQ11 0x6C
109#define WM8993_EQ12 0x6D
110#define WM8993_EQ13 0x6E
111#define WM8993_EQ14 0x6F
112#define WM8993_EQ15 0x70
113#define WM8993_EQ16 0x71
114#define WM8993_EQ17 0x72
115#define WM8993_EQ18 0x73
116#define WM8993_EQ19 0x74
117#define WM8993_EQ20 0x75
118#define WM8993_EQ21 0x76
119#define WM8993_EQ22 0x77
120#define WM8993_EQ23 0x78
121#define WM8993_EQ24 0x79
122#define WM8993_DIGITAL_PULLS 0x7A
123#define WM8993_DRC_CONTROL_1 0x7B
124#define WM8993_DRC_CONTROL_2 0x7C
125#define WM8993_DRC_CONTROL_3 0x7D
126#define WM8993_DRC_CONTROL_4 0x7E
127
128#define WM8993_REGISTER_COUNT 0x7F
129#define WM8993_MAX_REGISTER 0x7E
130
131/*
132 * Field Definitions.
133 */
134
135/*
136 * R0 (0x00) - Software Reset
137 */
138#define WM8993_SW_RESET_MASK 0xFFFF /* SW_RESET - [15:0] */
139#define WM8993_SW_RESET_SHIFT 0 /* SW_RESET - [15:0] */
140#define WM8993_SW_RESET_WIDTH 16 /* SW_RESET - [15:0] */
141
142/*
143 * R1 (0x01) - Power Management (1)
144 */
145#define WM8993_SPKOUTR_ENA 0x2000 /* SPKOUTR_ENA */
146#define WM8993_SPKOUTR_ENA_MASK 0x2000 /* SPKOUTR_ENA */
147#define WM8993_SPKOUTR_ENA_SHIFT 13 /* SPKOUTR_ENA */
148#define WM8993_SPKOUTR_ENA_WIDTH 1 /* SPKOUTR_ENA */
149#define WM8993_SPKOUTL_ENA 0x1000 /* SPKOUTL_ENA */
150#define WM8993_SPKOUTL_ENA_MASK 0x1000 /* SPKOUTL_ENA */
151#define WM8993_SPKOUTL_ENA_SHIFT 12 /* SPKOUTL_ENA */
152#define WM8993_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
153#define WM8993_HPOUT2_ENA 0x0800 /* HPOUT2_ENA */
154#define WM8993_HPOUT2_ENA_MASK 0x0800 /* HPOUT2_ENA */
155#define WM8993_HPOUT2_ENA_SHIFT 11 /* HPOUT2_ENA */
156#define WM8993_HPOUT2_ENA_WIDTH 1 /* HPOUT2_ENA */
157#define WM8993_HPOUT1L_ENA 0x0200 /* HPOUT1L_ENA */
158#define WM8993_HPOUT1L_ENA_MASK 0x0200 /* HPOUT1L_ENA */
159#define WM8993_HPOUT1L_ENA_SHIFT 9 /* HPOUT1L_ENA */
160#define WM8993_HPOUT1L_ENA_WIDTH 1 /* HPOUT1L_ENA */
161#define WM8993_HPOUT1R_ENA 0x0100 /* HPOUT1R_ENA */
162#define WM8993_HPOUT1R_ENA_MASK 0x0100 /* HPOUT1R_ENA */
163#define WM8993_HPOUT1R_ENA_SHIFT 8 /* HPOUT1R_ENA */
164#define WM8993_HPOUT1R_ENA_WIDTH 1 /* HPOUT1R_ENA */
165#define WM8993_MICB2_ENA 0x0020 /* MICB2_ENA */
166#define WM8993_MICB2_ENA_MASK 0x0020 /* MICB2_ENA */
167#define WM8993_MICB2_ENA_SHIFT 5 /* MICB2_ENA */
168#define WM8993_MICB2_ENA_WIDTH 1 /* MICB2_ENA */
169#define WM8993_MICB1_ENA 0x0010 /* MICB1_ENA */
170#define WM8993_MICB1_ENA_MASK 0x0010 /* MICB1_ENA */
171#define WM8993_MICB1_ENA_SHIFT 4 /* MICB1_ENA */
172#define WM8993_MICB1_ENA_WIDTH 1 /* MICB1_ENA */
173#define WM8993_VMID_SEL_MASK 0x0006 /* VMID_SEL - [2:1] */
174#define WM8993_VMID_SEL_SHIFT 1 /* VMID_SEL - [2:1] */
175#define WM8993_VMID_SEL_WIDTH 2 /* VMID_SEL - [2:1] */
176#define WM8993_BIAS_ENA 0x0001 /* BIAS_ENA */
177#define WM8993_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */
178#define WM8993_BIAS_ENA_SHIFT 0 /* BIAS_ENA */
179#define WM8993_BIAS_ENA_WIDTH 1 /* BIAS_ENA */
180
181/*
182 * R2 (0x02) - Power Management (2)
183 */
184#define WM8993_TSHUT_ENA 0x4000 /* TSHUT_ENA */
185#define WM8993_TSHUT_ENA_MASK 0x4000 /* TSHUT_ENA */
186#define WM8993_TSHUT_ENA_SHIFT 14 /* TSHUT_ENA */
187#define WM8993_TSHUT_ENA_WIDTH 1 /* TSHUT_ENA */
188#define WM8993_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */
189#define WM8993_TSHUT_OPDIS_MASK 0x2000 /* TSHUT_OPDIS */
190#define WM8993_TSHUT_OPDIS_SHIFT 13 /* TSHUT_OPDIS */
191#define WM8993_TSHUT_OPDIS_WIDTH 1 /* TSHUT_OPDIS */
192#define WM8993_OPCLK_ENA 0x0800 /* OPCLK_ENA */
193#define WM8993_OPCLK_ENA_MASK 0x0800 /* OPCLK_ENA */
194#define WM8993_OPCLK_ENA_SHIFT 11 /* OPCLK_ENA */
195#define WM8993_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */
196#define WM8993_MIXINL_ENA 0x0200 /* MIXINL_ENA */
197#define WM8993_MIXINL_ENA_MASK 0x0200 /* MIXINL_ENA */
198#define WM8993_MIXINL_ENA_SHIFT 9 /* MIXINL_ENA */
199#define WM8993_MIXINL_ENA_WIDTH 1 /* MIXINL_ENA */
200#define WM8993_MIXINR_ENA 0x0100 /* MIXINR_ENA */
201#define WM8993_MIXINR_ENA_MASK 0x0100 /* MIXINR_ENA */
202#define WM8993_MIXINR_ENA_SHIFT 8 /* MIXINR_ENA */
203#define WM8993_MIXINR_ENA_WIDTH 1 /* MIXINR_ENA */
204#define WM8993_IN2L_ENA 0x0080 /* IN2L_ENA */
205#define WM8993_IN2L_ENA_MASK 0x0080 /* IN2L_ENA */
206#define WM8993_IN2L_ENA_SHIFT 7 /* IN2L_ENA */
207#define WM8993_IN2L_ENA_WIDTH 1 /* IN2L_ENA */
208#define WM8993_IN1L_ENA 0x0040 /* IN1L_ENA */
209#define WM8993_IN1L_ENA_MASK 0x0040 /* IN1L_ENA */
210#define WM8993_IN1L_ENA_SHIFT 6 /* IN1L_ENA */
211#define WM8993_IN1L_ENA_WIDTH 1 /* IN1L_ENA */
212#define WM8993_IN2R_ENA 0x0020 /* IN2R_ENA */
213#define WM8993_IN2R_ENA_MASK 0x0020 /* IN2R_ENA */
214#define WM8993_IN2R_ENA_SHIFT 5 /* IN2R_ENA */
215#define WM8993_IN2R_ENA_WIDTH 1 /* IN2R_ENA */
216#define WM8993_IN1R_ENA 0x0010 /* IN1R_ENA */
217#define WM8993_IN1R_ENA_MASK 0x0010 /* IN1R_ENA */
218#define WM8993_IN1R_ENA_SHIFT 4 /* IN1R_ENA */
219#define WM8993_IN1R_ENA_WIDTH 1 /* IN1R_ENA */
220#define WM8993_ADCL_ENA 0x0002 /* ADCL_ENA */
221#define WM8993_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */
222#define WM8993_ADCL_ENA_SHIFT 1 /* ADCL_ENA */
223#define WM8993_ADCL_ENA_WIDTH 1 /* ADCL_ENA */
224#define WM8993_ADCR_ENA 0x0001 /* ADCR_ENA */
225#define WM8993_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */
226#define WM8993_ADCR_ENA_SHIFT 0 /* ADCR_ENA */
227#define WM8993_ADCR_ENA_WIDTH 1 /* ADCR_ENA */
228
229/*
230 * R3 (0x03) - Power Management (3)
231 */
232#define WM8993_LINEOUT1N_ENA 0x2000 /* LINEOUT1N_ENA */
233#define WM8993_LINEOUT1N_ENA_MASK 0x2000 /* LINEOUT1N_ENA */
234#define WM8993_LINEOUT1N_ENA_SHIFT 13 /* LINEOUT1N_ENA */
235#define WM8993_LINEOUT1N_ENA_WIDTH 1 /* LINEOUT1N_ENA */
236#define WM8993_LINEOUT1P_ENA 0x1000 /* LINEOUT1P_ENA */
237#define WM8993_LINEOUT1P_ENA_MASK 0x1000 /* LINEOUT1P_ENA */
238#define WM8993_LINEOUT1P_ENA_SHIFT 12 /* LINEOUT1P_ENA */
239#define WM8993_LINEOUT1P_ENA_WIDTH 1 /* LINEOUT1P_ENA */
240#define WM8993_LINEOUT2N_ENA 0x0800 /* LINEOUT2N_ENA */
241#define WM8993_LINEOUT2N_ENA_MASK 0x0800 /* LINEOUT2N_ENA */
242#define WM8993_LINEOUT2N_ENA_SHIFT 11 /* LINEOUT2N_ENA */
243#define WM8993_LINEOUT2N_ENA_WIDTH 1 /* LINEOUT2N_ENA */
244#define WM8993_LINEOUT2P_ENA 0x0400 /* LINEOUT2P_ENA */
245#define WM8993_LINEOUT2P_ENA_MASK 0x0400 /* LINEOUT2P_ENA */
246#define WM8993_LINEOUT2P_ENA_SHIFT 10 /* LINEOUT2P_ENA */
247#define WM8993_LINEOUT2P_ENA_WIDTH 1 /* LINEOUT2P_ENA */
248#define WM8993_SPKRVOL_ENA 0x0200 /* SPKRVOL_ENA */
249#define WM8993_SPKRVOL_ENA_MASK 0x0200 /* SPKRVOL_ENA */
250#define WM8993_SPKRVOL_ENA_SHIFT 9 /* SPKRVOL_ENA */
251#define WM8993_SPKRVOL_ENA_WIDTH 1 /* SPKRVOL_ENA */
252#define WM8993_SPKLVOL_ENA 0x0100 /* SPKLVOL_ENA */
253#define WM8993_SPKLVOL_ENA_MASK 0x0100 /* SPKLVOL_ENA */
254#define WM8993_SPKLVOL_ENA_SHIFT 8 /* SPKLVOL_ENA */
255#define WM8993_SPKLVOL_ENA_WIDTH 1 /* SPKLVOL_ENA */
256#define WM8993_MIXOUTLVOL_ENA 0x0080 /* MIXOUTLVOL_ENA */
257#define WM8993_MIXOUTLVOL_ENA_MASK 0x0080 /* MIXOUTLVOL_ENA */
258#define WM8993_MIXOUTLVOL_ENA_SHIFT 7 /* MIXOUTLVOL_ENA */
259#define WM8993_MIXOUTLVOL_ENA_WIDTH 1 /* MIXOUTLVOL_ENA */
260#define WM8993_MIXOUTRVOL_ENA 0x0040 /* MIXOUTRVOL_ENA */
261#define WM8993_MIXOUTRVOL_ENA_MASK 0x0040 /* MIXOUTRVOL_ENA */
262#define WM8993_MIXOUTRVOL_ENA_SHIFT 6 /* MIXOUTRVOL_ENA */
263#define WM8993_MIXOUTRVOL_ENA_WIDTH 1 /* MIXOUTRVOL_ENA */
264#define WM8993_MIXOUTL_ENA 0x0020 /* MIXOUTL_ENA */
265#define WM8993_MIXOUTL_ENA_MASK 0x0020 /* MIXOUTL_ENA */
266#define WM8993_MIXOUTL_ENA_SHIFT 5 /* MIXOUTL_ENA */
267#define WM8993_MIXOUTL_ENA_WIDTH 1 /* MIXOUTL_ENA */
268#define WM8993_MIXOUTR_ENA 0x0010 /* MIXOUTR_ENA */
269#define WM8993_MIXOUTR_ENA_MASK 0x0010 /* MIXOUTR_ENA */
270#define WM8993_MIXOUTR_ENA_SHIFT 4 /* MIXOUTR_ENA */
271#define WM8993_MIXOUTR_ENA_WIDTH 1 /* MIXOUTR_ENA */
272#define WM8993_DACL_ENA 0x0002 /* DACL_ENA */
273#define WM8993_DACL_ENA_MASK 0x0002 /* DACL_ENA */
274#define WM8993_DACL_ENA_SHIFT 1 /* DACL_ENA */
275#define WM8993_DACL_ENA_WIDTH 1 /* DACL_ENA */
276#define WM8993_DACR_ENA 0x0001 /* DACR_ENA */
277#define WM8993_DACR_ENA_MASK 0x0001 /* DACR_ENA */
278#define WM8993_DACR_ENA_SHIFT 0 /* DACR_ENA */
279#define WM8993_DACR_ENA_WIDTH 1 /* DACR_ENA */
280
281/*
282 * R4 (0x04) - Audio Interface (1)
283 */
284#define WM8993_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */
285#define WM8993_AIFADCL_SRC_MASK 0x8000 /* AIFADCL_SRC */
286#define WM8993_AIFADCL_SRC_SHIFT 15 /* AIFADCL_SRC */
287#define WM8993_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */
288#define WM8993_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */
289#define WM8993_AIFADCR_SRC_MASK 0x4000 /* AIFADCR_SRC */
290#define WM8993_AIFADCR_SRC_SHIFT 14 /* AIFADCR_SRC */
291#define WM8993_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */
292#define WM8993_AIFADC_TDM 0x2000 /* AIFADC_TDM */
293#define WM8993_AIFADC_TDM_MASK 0x2000 /* AIFADC_TDM */
294#define WM8993_AIFADC_TDM_SHIFT 13 /* AIFADC_TDM */
295#define WM8993_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */
296#define WM8993_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */
297#define WM8993_AIFADC_TDM_CHAN_MASK 0x1000 /* AIFADC_TDM_CHAN */
298#define WM8993_AIFADC_TDM_CHAN_SHIFT 12 /* AIFADC_TDM_CHAN */
299#define WM8993_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */
300#define WM8993_BCLK_DIR 0x0200 /* BCLK_DIR */
301#define WM8993_BCLK_DIR_MASK 0x0200 /* BCLK_DIR */
302#define WM8993_BCLK_DIR_SHIFT 9 /* BCLK_DIR */
303#define WM8993_BCLK_DIR_WIDTH 1 /* BCLK_DIR */
304#define WM8993_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */
305#define WM8993_AIF_BCLK_INV_MASK 0x0100 /* AIF_BCLK_INV */
306#define WM8993_AIF_BCLK_INV_SHIFT 8 /* AIF_BCLK_INV */
307#define WM8993_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */
308#define WM8993_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */
309#define WM8993_AIF_LRCLK_INV_MASK 0x0080 /* AIF_LRCLK_INV */
310#define WM8993_AIF_LRCLK_INV_SHIFT 7 /* AIF_LRCLK_INV */
311#define WM8993_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */
312#define WM8993_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */
313#define WM8993_AIF_WL_SHIFT 5 /* AIF_WL - [6:5] */
314#define WM8993_AIF_WL_WIDTH 2 /* AIF_WL - [6:5] */
315#define WM8993_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */
316#define WM8993_AIF_FMT_SHIFT 3 /* AIF_FMT - [4:3] */
317#define WM8993_AIF_FMT_WIDTH 2 /* AIF_FMT - [4:3] */
318
319/*
320 * R5 (0x05) - Audio Interface (2)
321 */
322#define WM8993_AIFDACL_SRC 0x8000 /* AIFDACL_SRC */
323#define WM8993_AIFDACL_SRC_MASK 0x8000 /* AIFDACL_SRC */
324#define WM8993_AIFDACL_SRC_SHIFT 15 /* AIFDACL_SRC */
325#define WM8993_AIFDACL_SRC_WIDTH 1 /* AIFDACL_SRC */
326#define WM8993_AIFDACR_SRC 0x4000 /* AIFDACR_SRC */
327#define WM8993_AIFDACR_SRC_MASK 0x4000 /* AIFDACR_SRC */
328#define WM8993_AIFDACR_SRC_SHIFT 14 /* AIFDACR_SRC */
329#define WM8993_AIFDACR_SRC_WIDTH 1 /* AIFDACR_SRC */
330#define WM8993_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */
331#define WM8993_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */
332#define WM8993_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */
333#define WM8993_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */
334#define WM8993_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */
335#define WM8993_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */
336#define WM8993_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */
337#define WM8993_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */
338#define WM8993_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST - [11:10] */
339#define WM8993_DAC_BOOST_SHIFT 10 /* DAC_BOOST - [11:10] */
340#define WM8993_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [11:10] */
341#define WM8993_DAC_COMP 0x0010 /* DAC_COMP */
342#define WM8993_DAC_COMP_MASK 0x0010 /* DAC_COMP */
343#define WM8993_DAC_COMP_SHIFT 4 /* DAC_COMP */
344#define WM8993_DAC_COMP_WIDTH 1 /* DAC_COMP */
345#define WM8993_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */
346#define WM8993_DAC_COMPMODE_MASK 0x0008 /* DAC_COMPMODE */
347#define WM8993_DAC_COMPMODE_SHIFT 3 /* DAC_COMPMODE */
348#define WM8993_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */
349#define WM8993_ADC_COMP 0x0004 /* ADC_COMP */
350#define WM8993_ADC_COMP_MASK 0x0004 /* ADC_COMP */
351#define WM8993_ADC_COMP_SHIFT 2 /* ADC_COMP */
352#define WM8993_ADC_COMP_WIDTH 1 /* ADC_COMP */
353#define WM8993_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */
354#define WM8993_ADC_COMPMODE_MASK 0x0002 /* ADC_COMPMODE */
355#define WM8993_ADC_COMPMODE_SHIFT 1 /* ADC_COMPMODE */
356#define WM8993_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */
357#define WM8993_LOOPBACK 0x0001 /* LOOPBACK */
358#define WM8993_LOOPBACK_MASK 0x0001 /* LOOPBACK */
359#define WM8993_LOOPBACK_SHIFT 0 /* LOOPBACK */
360#define WM8993_LOOPBACK_WIDTH 1 /* LOOPBACK */
361
362/*
363 * R6 (0x06) - Clocking 1
364 */
365#define WM8993_TOCLK_RATE 0x8000 /* TOCLK_RATE */
366#define WM8993_TOCLK_RATE_MASK 0x8000 /* TOCLK_RATE */
367#define WM8993_TOCLK_RATE_SHIFT 15 /* TOCLK_RATE */
368#define WM8993_TOCLK_RATE_WIDTH 1 /* TOCLK_RATE */
369#define WM8993_TOCLK_ENA 0x4000 /* TOCLK_ENA */
370#define WM8993_TOCLK_ENA_MASK 0x4000 /* TOCLK_ENA */
371#define WM8993_TOCLK_ENA_SHIFT 14 /* TOCLK_ENA */
372#define WM8993_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */
373#define WM8993_OPCLK_DIV_MASK 0x1E00 /* OPCLK_DIV - [12:9] */
374#define WM8993_OPCLK_DIV_SHIFT 9 /* OPCLK_DIV - [12:9] */
375#define WM8993_OPCLK_DIV_WIDTH 4 /* OPCLK_DIV - [12:9] */
376#define WM8993_DCLK_DIV_MASK 0x01C0 /* DCLK_DIV - [8:6] */
377#define WM8993_DCLK_DIV_SHIFT 6 /* DCLK_DIV - [8:6] */
378#define WM8993_DCLK_DIV_WIDTH 3 /* DCLK_DIV - [8:6] */
379#define WM8993_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */
380#define WM8993_BCLK_DIV_SHIFT 1 /* BCLK_DIV - [4:1] */
381#define WM8993_BCLK_DIV_WIDTH 4 /* BCLK_DIV - [4:1] */
382
383/*
384 * R7 (0x07) - Clocking 2
385 */
386#define WM8993_MCLK_SRC 0x8000 /* MCLK_SRC */
387#define WM8993_MCLK_SRC_MASK 0x8000 /* MCLK_SRC */
388#define WM8993_MCLK_SRC_SHIFT 15 /* MCLK_SRC */
389#define WM8993_MCLK_SRC_WIDTH 1 /* MCLK_SRC */
390#define WM8993_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */
391#define WM8993_SYSCLK_SRC_MASK 0x4000 /* SYSCLK_SRC */
392#define WM8993_SYSCLK_SRC_SHIFT 14 /* SYSCLK_SRC */
393#define WM8993_SYSCLK_SRC_WIDTH 1 /* SYSCLK_SRC */
394#define WM8993_MCLK_DIV 0x1000 /* MCLK_DIV */
395#define WM8993_MCLK_DIV_MASK 0x1000 /* MCLK_DIV */
396#define WM8993_MCLK_DIV_SHIFT 12 /* MCLK_DIV */
397#define WM8993_MCLK_DIV_WIDTH 1 /* MCLK_DIV */
398#define WM8993_MCLK_INV 0x0400 /* MCLK_INV */
399#define WM8993_MCLK_INV_MASK 0x0400 /* MCLK_INV */
400#define WM8993_MCLK_INV_SHIFT 10 /* MCLK_INV */
401#define WM8993_MCLK_INV_WIDTH 1 /* MCLK_INV */
402#define WM8993_ADC_DIV_MASK 0x00E0 /* ADC_DIV - [7:5] */
403#define WM8993_ADC_DIV_SHIFT 5 /* ADC_DIV - [7:5] */
404#define WM8993_ADC_DIV_WIDTH 3 /* ADC_DIV - [7:5] */
405#define WM8993_DAC_DIV_MASK 0x001C /* DAC_DIV - [4:2] */
406#define WM8993_DAC_DIV_SHIFT 2 /* DAC_DIV - [4:2] */
407#define WM8993_DAC_DIV_WIDTH 3 /* DAC_DIV - [4:2] */
408
409/*
410 * R8 (0x08) - Audio Interface (3)
411 */
412#define WM8993_AIF_MSTR1 0x8000 /* AIF_MSTR1 */
413#define WM8993_AIF_MSTR1_MASK 0x8000 /* AIF_MSTR1 */
414#define WM8993_AIF_MSTR1_SHIFT 15 /* AIF_MSTR1 */
415#define WM8993_AIF_MSTR1_WIDTH 1 /* AIF_MSTR1 */
416
417/*
418 * R9 (0x09) - Audio Interface (4)
419 */
420#define WM8993_AIF_TRIS 0x2000 /* AIF_TRIS */
421#define WM8993_AIF_TRIS_MASK 0x2000 /* AIF_TRIS */
422#define WM8993_AIF_TRIS_SHIFT 13 /* AIF_TRIS */
423#define WM8993_AIF_TRIS_WIDTH 1 /* AIF_TRIS */
424#define WM8993_LRCLK_DIR 0x0800 /* LRCLK_DIR */
425#define WM8993_LRCLK_DIR_MASK 0x0800 /* LRCLK_DIR */
426#define WM8993_LRCLK_DIR_SHIFT 11 /* LRCLK_DIR */
427#define WM8993_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */
428#define WM8993_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */
429#define WM8993_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */
430#define WM8993_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */
431
432/*
433 * R10 (0x0A) - DAC CTRL
434 */
435#define WM8993_DAC_OSR128 0x2000 /* DAC_OSR128 */
436#define WM8993_DAC_OSR128_MASK 0x2000 /* DAC_OSR128 */
437#define WM8993_DAC_OSR128_SHIFT 13 /* DAC_OSR128 */
438#define WM8993_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */
439#define WM8993_DAC_MONO 0x0200 /* DAC_MONO */
440#define WM8993_DAC_MONO_MASK 0x0200 /* DAC_MONO */
441#define WM8993_DAC_MONO_SHIFT 9 /* DAC_MONO */
442#define WM8993_DAC_MONO_WIDTH 1 /* DAC_MONO */
443#define WM8993_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */
444#define WM8993_DAC_SB_FILT_MASK 0x0100 /* DAC_SB_FILT */
445#define WM8993_DAC_SB_FILT_SHIFT 8 /* DAC_SB_FILT */
446#define WM8993_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */
447#define WM8993_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */
448#define WM8993_DAC_MUTERATE_MASK 0x0080 /* DAC_MUTERATE */
449#define WM8993_DAC_MUTERATE_SHIFT 7 /* DAC_MUTERATE */
450#define WM8993_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */
451#define WM8993_DAC_UNMUTE_RAMP 0x0040 /* DAC_UNMUTE_RAMP */
452#define WM8993_DAC_UNMUTE_RAMP_MASK 0x0040 /* DAC_UNMUTE_RAMP */
453#define WM8993_DAC_UNMUTE_RAMP_SHIFT 6 /* DAC_UNMUTE_RAMP */
454#define WM8993_DAC_UNMUTE_RAMP_WIDTH 1 /* DAC_UNMUTE_RAMP */
455#define WM8993_DEEMPH_MASK 0x0030 /* DEEMPH - [5:4] */
456#define WM8993_DEEMPH_SHIFT 4 /* DEEMPH - [5:4] */
457#define WM8993_DEEMPH_WIDTH 2 /* DEEMPH - [5:4] */
458#define WM8993_DAC_MUTE 0x0004 /* DAC_MUTE */
459#define WM8993_DAC_MUTE_MASK 0x0004 /* DAC_MUTE */
460#define WM8993_DAC_MUTE_SHIFT 2 /* DAC_MUTE */
461#define WM8993_DAC_MUTE_WIDTH 1 /* DAC_MUTE */
462#define WM8993_DACL_DATINV 0x0002 /* DACL_DATINV */
463#define WM8993_DACL_DATINV_MASK 0x0002 /* DACL_DATINV */
464#define WM8993_DACL_DATINV_SHIFT 1 /* DACL_DATINV */
465#define WM8993_DACL_DATINV_WIDTH 1 /* DACL_DATINV */
466#define WM8993_DACR_DATINV 0x0001 /* DACR_DATINV */
467#define WM8993_DACR_DATINV_MASK 0x0001 /* DACR_DATINV */
468#define WM8993_DACR_DATINV_SHIFT 0 /* DACR_DATINV */
469#define WM8993_DACR_DATINV_WIDTH 1 /* DACR_DATINV */
470
471/*
472 * R11 (0x0B) - Left DAC Digital Volume
473 */
474#define WM8993_DAC_VU 0x0100 /* DAC_VU */
475#define WM8993_DAC_VU_MASK 0x0100 /* DAC_VU */
476#define WM8993_DAC_VU_SHIFT 8 /* DAC_VU */
477#define WM8993_DAC_VU_WIDTH 1 /* DAC_VU */
478#define WM8993_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */
479#define WM8993_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */
480#define WM8993_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */
481
482/*
483 * R12 (0x0C) - Right DAC Digital Volume
484 */
485#define WM8993_DAC_VU 0x0100 /* DAC_VU */
486#define WM8993_DAC_VU_MASK 0x0100 /* DAC_VU */
487#define WM8993_DAC_VU_SHIFT 8 /* DAC_VU */
488#define WM8993_DAC_VU_WIDTH 1 /* DAC_VU */
489#define WM8993_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */
490#define WM8993_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */
491#define WM8993_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */
492
493/*
494 * R13 (0x0D) - Digital Side Tone
495 */
496#define WM8993_ADCL_DAC_SVOL_MASK 0x1E00 /* ADCL_DAC_SVOL - [12:9] */
497#define WM8993_ADCL_DAC_SVOL_SHIFT 9 /* ADCL_DAC_SVOL - [12:9] */
498#define WM8993_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [12:9] */
499#define WM8993_ADCR_DAC_SVOL_MASK 0x01E0 /* ADCR_DAC_SVOL - [8:5] */
500#define WM8993_ADCR_DAC_SVOL_SHIFT 5 /* ADCR_DAC_SVOL - [8:5] */
501#define WM8993_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [8:5] */
502#define WM8993_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */
503#define WM8993_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */
504#define WM8993_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */
505#define WM8993_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */
506#define WM8993_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */
507#define WM8993_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */
508
509/*
510 * R14 (0x0E) - ADC CTRL
511 */
512#define WM8993_ADC_OSR128 0x0200 /* ADC_OSR128 */
513#define WM8993_ADC_OSR128_MASK 0x0200 /* ADC_OSR128 */
514#define WM8993_ADC_OSR128_SHIFT 9 /* ADC_OSR128 */
515#define WM8993_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */
516#define WM8993_ADC_HPF 0x0100 /* ADC_HPF */
517#define WM8993_ADC_HPF_MASK 0x0100 /* ADC_HPF */
518#define WM8993_ADC_HPF_SHIFT 8 /* ADC_HPF */
519#define WM8993_ADC_HPF_WIDTH 1 /* ADC_HPF */
520#define WM8993_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */
521#define WM8993_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */
522#define WM8993_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */
523#define WM8993_ADCL_DATINV 0x0002 /* ADCL_DATINV */
524#define WM8993_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */
525#define WM8993_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */
526#define WM8993_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */
527#define WM8993_ADCR_DATINV 0x0001 /* ADCR_DATINV */
528#define WM8993_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */
529#define WM8993_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */
530#define WM8993_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */
531
532/*
533 * R15 (0x0F) - Left ADC Digital Volume
534 */
535#define WM8993_ADC_VU 0x0100 /* ADC_VU */
536#define WM8993_ADC_VU_MASK 0x0100 /* ADC_VU */
537#define WM8993_ADC_VU_SHIFT 8 /* ADC_VU */
538#define WM8993_ADC_VU_WIDTH 1 /* ADC_VU */
539#define WM8993_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */
540#define WM8993_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */
541#define WM8993_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */
542
543/*
544 * R16 (0x10) - Right ADC Digital Volume
545 */
546#define WM8993_ADC_VU 0x0100 /* ADC_VU */
547#define WM8993_ADC_VU_MASK 0x0100 /* ADC_VU */
548#define WM8993_ADC_VU_SHIFT 8 /* ADC_VU */
549#define WM8993_ADC_VU_WIDTH 1 /* ADC_VU */
550#define WM8993_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */
551#define WM8993_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */
552#define WM8993_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */
553
554/*
555 * R18 (0x12) - GPIO CTRL 1
556 */
557#define WM8993_JD2_SC_EINT 0x8000 /* JD2_SC_EINT */
558#define WM8993_JD2_SC_EINT_MASK 0x8000 /* JD2_SC_EINT */
559#define WM8993_JD2_SC_EINT_SHIFT 15 /* JD2_SC_EINT */
560#define WM8993_JD2_SC_EINT_WIDTH 1 /* JD2_SC_EINT */
561#define WM8993_JD2_EINT 0x4000 /* JD2_EINT */
562#define WM8993_JD2_EINT_MASK 0x4000 /* JD2_EINT */
563#define WM8993_JD2_EINT_SHIFT 14 /* JD2_EINT */
564#define WM8993_JD2_EINT_WIDTH 1 /* JD2_EINT */
565#define WM8993_WSEQ_EINT 0x2000 /* WSEQ_EINT */
566#define WM8993_WSEQ_EINT_MASK 0x2000 /* WSEQ_EINT */
567#define WM8993_WSEQ_EINT_SHIFT 13 /* WSEQ_EINT */
568#define WM8993_WSEQ_EINT_WIDTH 1 /* WSEQ_EINT */
569#define WM8993_IRQ 0x1000 /* IRQ */
570#define WM8993_IRQ_MASK 0x1000 /* IRQ */
571#define WM8993_IRQ_SHIFT 12 /* IRQ */
572#define WM8993_IRQ_WIDTH 1 /* IRQ */
573#define WM8993_TEMPOK_EINT 0x0800 /* TEMPOK_EINT */
574#define WM8993_TEMPOK_EINT_MASK 0x0800 /* TEMPOK_EINT */
575#define WM8993_TEMPOK_EINT_SHIFT 11 /* TEMPOK_EINT */
576#define WM8993_TEMPOK_EINT_WIDTH 1 /* TEMPOK_EINT */
577#define WM8993_JD1_SC_EINT 0x0400 /* JD1_SC_EINT */
578#define WM8993_JD1_SC_EINT_MASK 0x0400 /* JD1_SC_EINT */
579#define WM8993_JD1_SC_EINT_SHIFT 10 /* JD1_SC_EINT */
580#define WM8993_JD1_SC_EINT_WIDTH 1 /* JD1_SC_EINT */
581#define WM8993_JD1_EINT 0x0200 /* JD1_EINT */
582#define WM8993_JD1_EINT_MASK 0x0200 /* JD1_EINT */
583#define WM8993_JD1_EINT_SHIFT 9 /* JD1_EINT */
584#define WM8993_JD1_EINT_WIDTH 1 /* JD1_EINT */
585#define WM8993_FLL_LOCK_EINT 0x0100 /* FLL_LOCK_EINT */
586#define WM8993_FLL_LOCK_EINT_MASK 0x0100 /* FLL_LOCK_EINT */
587#define WM8993_FLL_LOCK_EINT_SHIFT 8 /* FLL_LOCK_EINT */
588#define WM8993_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */
589#define WM8993_GPI8_EINT 0x0080 /* GPI8_EINT */
590#define WM8993_GPI8_EINT_MASK 0x0080 /* GPI8_EINT */
591#define WM8993_GPI8_EINT_SHIFT 7 /* GPI8_EINT */
592#define WM8993_GPI8_EINT_WIDTH 1 /* GPI8_EINT */
593#define WM8993_GPI7_EINT 0x0040 /* GPI7_EINT */
594#define WM8993_GPI7_EINT_MASK 0x0040 /* GPI7_EINT */
595#define WM8993_GPI7_EINT_SHIFT 6 /* GPI7_EINT */
596#define WM8993_GPI7_EINT_WIDTH 1 /* GPI7_EINT */
597#define WM8993_GPIO1_EINT 0x0001 /* GPIO1_EINT */
598#define WM8993_GPIO1_EINT_MASK 0x0001 /* GPIO1_EINT */
599#define WM8993_GPIO1_EINT_SHIFT 0 /* GPIO1_EINT */
600#define WM8993_GPIO1_EINT_WIDTH 1 /* GPIO1_EINT */
601
602/*
603 * R19 (0x13) - GPIO1
604 */
605#define WM8993_GPIO1_PU 0x0020 /* GPIO1_PU */
606#define WM8993_GPIO1_PU_MASK 0x0020 /* GPIO1_PU */
607#define WM8993_GPIO1_PU_SHIFT 5 /* GPIO1_PU */
608#define WM8993_GPIO1_PU_WIDTH 1 /* GPIO1_PU */
609#define WM8993_GPIO1_PD 0x0010 /* GPIO1_PD */
610#define WM8993_GPIO1_PD_MASK 0x0010 /* GPIO1_PD */
611#define WM8993_GPIO1_PD_SHIFT 4 /* GPIO1_PD */
612#define WM8993_GPIO1_PD_WIDTH 1 /* GPIO1_PD */
613#define WM8993_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */
614#define WM8993_GPIO1_SEL_SHIFT 0 /* GPIO1_SEL - [3:0] */
615#define WM8993_GPIO1_SEL_WIDTH 4 /* GPIO1_SEL - [3:0] */
616
617/*
618 * R20 (0x14) - IRQ_DEBOUNCE
619 */
620#define WM8993_JD2_SC_DB 0x8000 /* JD2_SC_DB */
621#define WM8993_JD2_SC_DB_MASK 0x8000 /* JD2_SC_DB */
622#define WM8993_JD2_SC_DB_SHIFT 15 /* JD2_SC_DB */
623#define WM8993_JD2_SC_DB_WIDTH 1 /* JD2_SC_DB */
624#define WM8993_JD2_DB 0x4000 /* JD2_DB */
625#define WM8993_JD2_DB_MASK 0x4000 /* JD2_DB */
626#define WM8993_JD2_DB_SHIFT 14 /* JD2_DB */
627#define WM8993_JD2_DB_WIDTH 1 /* JD2_DB */
628#define WM8993_WSEQ_DB 0x2000 /* WSEQ_DB */
629#define WM8993_WSEQ_DB_MASK 0x2000 /* WSEQ_DB */
630#define WM8993_WSEQ_DB_SHIFT 13 /* WSEQ_DB */
631#define WM8993_WSEQ_DB_WIDTH 1 /* WSEQ_DB */
632#define WM8993_TEMPOK_DB 0x0800 /* TEMPOK_DB */
633#define WM8993_TEMPOK_DB_MASK 0x0800 /* TEMPOK_DB */
634#define WM8993_TEMPOK_DB_SHIFT 11 /* TEMPOK_DB */
635#define WM8993_TEMPOK_DB_WIDTH 1 /* TEMPOK_DB */
636#define WM8993_JD1_SC_DB 0x0400 /* JD1_SC_DB */
637#define WM8993_JD1_SC_DB_MASK 0x0400 /* JD1_SC_DB */
638#define WM8993_JD1_SC_DB_SHIFT 10 /* JD1_SC_DB */
639#define WM8993_JD1_SC_DB_WIDTH 1 /* JD1_SC_DB */
640#define WM8993_JD1_DB 0x0200 /* JD1_DB */
641#define WM8993_JD1_DB_MASK 0x0200 /* JD1_DB */
642#define WM8993_JD1_DB_SHIFT 9 /* JD1_DB */
643#define WM8993_JD1_DB_WIDTH 1 /* JD1_DB */
644#define WM8993_FLL_LOCK_DB 0x0100 /* FLL_LOCK_DB */
645#define WM8993_FLL_LOCK_DB_MASK 0x0100 /* FLL_LOCK_DB */
646#define WM8993_FLL_LOCK_DB_SHIFT 8 /* FLL_LOCK_DB */
647#define WM8993_FLL_LOCK_DB_WIDTH 1 /* FLL_LOCK_DB */
648#define WM8993_GPI8_DB 0x0080 /* GPI8_DB */
649#define WM8993_GPI8_DB_MASK 0x0080 /* GPI8_DB */
650#define WM8993_GPI8_DB_SHIFT 7 /* GPI8_DB */
651#define WM8993_GPI8_DB_WIDTH 1 /* GPI8_DB */
652#define WM8993_GPI7_DB 0x0008 /* GPI7_DB */
653#define WM8993_GPI7_DB_MASK 0x0008 /* GPI7_DB */
654#define WM8993_GPI7_DB_SHIFT 3 /* GPI7_DB */
655#define WM8993_GPI7_DB_WIDTH 1 /* GPI7_DB */
656#define WM8993_GPIO1_DB 0x0001 /* GPIO1_DB */
657#define WM8993_GPIO1_DB_MASK 0x0001 /* GPIO1_DB */
658#define WM8993_GPIO1_DB_SHIFT 0 /* GPIO1_DB */
659#define WM8993_GPIO1_DB_WIDTH 1 /* GPIO1_DB */
660
661/*
662 * R22 (0x16) - GPIOCTRL 2
663 */
664#define WM8993_IM_JD2_EINT 0x2000 /* IM_JD2_EINT */
665#define WM8993_IM_JD2_EINT_MASK 0x2000 /* IM_JD2_EINT */
666#define WM8993_IM_JD2_EINT_SHIFT 13 /* IM_JD2_EINT */
667#define WM8993_IM_JD2_EINT_WIDTH 1 /* IM_JD2_EINT */
668#define WM8993_IM_JD2_SC_EINT 0x1000 /* IM_JD2_SC_EINT */
669#define WM8993_IM_JD2_SC_EINT_MASK 0x1000 /* IM_JD2_SC_EINT */
670#define WM8993_IM_JD2_SC_EINT_SHIFT 12 /* IM_JD2_SC_EINT */
671#define WM8993_IM_JD2_SC_EINT_WIDTH 1 /* IM_JD2_SC_EINT */
672#define WM8993_IM_TEMPOK_EINT 0x0800 /* IM_TEMPOK_EINT */
673#define WM8993_IM_TEMPOK_EINT_MASK 0x0800 /* IM_TEMPOK_EINT */
674#define WM8993_IM_TEMPOK_EINT_SHIFT 11 /* IM_TEMPOK_EINT */
675#define WM8993_IM_TEMPOK_EINT_WIDTH 1 /* IM_TEMPOK_EINT */
676#define WM8993_IM_JD1_SC_EINT 0x0400 /* IM_JD1_SC_EINT */
677#define WM8993_IM_JD1_SC_EINT_MASK 0x0400 /* IM_JD1_SC_EINT */
678#define WM8993_IM_JD1_SC_EINT_SHIFT 10 /* IM_JD1_SC_EINT */
679#define WM8993_IM_JD1_SC_EINT_WIDTH 1 /* IM_JD1_SC_EINT */
680#define WM8993_IM_JD1_EINT 0x0200 /* IM_JD1_EINT */
681#define WM8993_IM_JD1_EINT_MASK 0x0200 /* IM_JD1_EINT */
682#define WM8993_IM_JD1_EINT_SHIFT 9 /* IM_JD1_EINT */
683#define WM8993_IM_JD1_EINT_WIDTH 1 /* IM_JD1_EINT */
684#define WM8993_IM_FLL_LOCK_EINT 0x0100 /* IM_FLL_LOCK_EINT */
685#define WM8993_IM_FLL_LOCK_EINT_MASK 0x0100 /* IM_FLL_LOCK_EINT */
686#define WM8993_IM_FLL_LOCK_EINT_SHIFT 8 /* IM_FLL_LOCK_EINT */
687#define WM8993_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */
688#define WM8993_IM_GPI8_EINT 0x0040 /* IM_GPI8_EINT */
689#define WM8993_IM_GPI8_EINT_MASK 0x0040 /* IM_GPI8_EINT */
690#define WM8993_IM_GPI8_EINT_SHIFT 6 /* IM_GPI8_EINT */
691#define WM8993_IM_GPI8_EINT_WIDTH 1 /* IM_GPI8_EINT */
692#define WM8993_IM_GPIO1_EINT 0x0020 /* IM_GPIO1_EINT */
693#define WM8993_IM_GPIO1_EINT_MASK 0x0020 /* IM_GPIO1_EINT */
694#define WM8993_IM_GPIO1_EINT_SHIFT 5 /* IM_GPIO1_EINT */
695#define WM8993_IM_GPIO1_EINT_WIDTH 1 /* IM_GPIO1_EINT */
696#define WM8993_GPI8_ENA 0x0010 /* GPI8_ENA */
697#define WM8993_GPI8_ENA_MASK 0x0010 /* GPI8_ENA */
698#define WM8993_GPI8_ENA_SHIFT 4 /* GPI8_ENA */
699#define WM8993_GPI8_ENA_WIDTH 1 /* GPI8_ENA */
700#define WM8993_IM_GPI7_EINT 0x0004 /* IM_GPI7_EINT */
701#define WM8993_IM_GPI7_EINT_MASK 0x0004 /* IM_GPI7_EINT */
702#define WM8993_IM_GPI7_EINT_SHIFT 2 /* IM_GPI7_EINT */
703#define WM8993_IM_GPI7_EINT_WIDTH 1 /* IM_GPI7_EINT */
704#define WM8993_IM_WSEQ_EINT 0x0002 /* IM_WSEQ_EINT */
705#define WM8993_IM_WSEQ_EINT_MASK 0x0002 /* IM_WSEQ_EINT */
706#define WM8993_IM_WSEQ_EINT_SHIFT 1 /* IM_WSEQ_EINT */
707#define WM8993_IM_WSEQ_EINT_WIDTH 1 /* IM_WSEQ_EINT */
708#define WM8993_GPI7_ENA 0x0001 /* GPI7_ENA */
709#define WM8993_GPI7_ENA_MASK 0x0001 /* GPI7_ENA */
710#define WM8993_GPI7_ENA_SHIFT 0 /* GPI7_ENA */
711#define WM8993_GPI7_ENA_WIDTH 1 /* GPI7_ENA */
712
713/*
714 * R23 (0x17) - GPIO_POL
715 */
716#define WM8993_JD2_SC_POL 0x8000 /* JD2_SC_POL */
717#define WM8993_JD2_SC_POL_MASK 0x8000 /* JD2_SC_POL */
718#define WM8993_JD2_SC_POL_SHIFT 15 /* JD2_SC_POL */
719#define WM8993_JD2_SC_POL_WIDTH 1 /* JD2_SC_POL */
720#define WM8993_JD2_POL 0x4000 /* JD2_POL */
721#define WM8993_JD2_POL_MASK 0x4000 /* JD2_POL */
722#define WM8993_JD2_POL_SHIFT 14 /* JD2_POL */
723#define WM8993_JD2_POL_WIDTH 1 /* JD2_POL */
724#define WM8993_WSEQ_POL 0x2000 /* WSEQ_POL */
725#define WM8993_WSEQ_POL_MASK 0x2000 /* WSEQ_POL */
726#define WM8993_WSEQ_POL_SHIFT 13 /* WSEQ_POL */
727#define WM8993_WSEQ_POL_WIDTH 1 /* WSEQ_POL */
728#define WM8993_IRQ_POL 0x1000 /* IRQ_POL */
729#define WM8993_IRQ_POL_MASK 0x1000 /* IRQ_POL */
730#define WM8993_IRQ_POL_SHIFT 12 /* IRQ_POL */
731#define WM8993_IRQ_POL_WIDTH 1 /* IRQ_POL */
732#define WM8993_TEMPOK_POL 0x0800 /* TEMPOK_POL */
733#define WM8993_TEMPOK_POL_MASK 0x0800 /* TEMPOK_POL */
734#define WM8993_TEMPOK_POL_SHIFT 11 /* TEMPOK_POL */
735#define WM8993_TEMPOK_POL_WIDTH 1 /* TEMPOK_POL */
736#define WM8993_JD1_SC_POL 0x0400 /* JD1_SC_POL */
737#define WM8993_JD1_SC_POL_MASK 0x0400 /* JD1_SC_POL */
738#define WM8993_JD1_SC_POL_SHIFT 10 /* JD1_SC_POL */
739#define WM8993_JD1_SC_POL_WIDTH 1 /* JD1_SC_POL */
740#define WM8993_JD1_POL 0x0200 /* JD1_POL */
741#define WM8993_JD1_POL_MASK 0x0200 /* JD1_POL */
742#define WM8993_JD1_POL_SHIFT 9 /* JD1_POL */
743#define WM8993_JD1_POL_WIDTH 1 /* JD1_POL */
744#define WM8993_FLL_LOCK_POL 0x0100 /* FLL_LOCK_POL */
745#define WM8993_FLL_LOCK_POL_MASK 0x0100 /* FLL_LOCK_POL */
746#define WM8993_FLL_LOCK_POL_SHIFT 8 /* FLL_LOCK_POL */
747#define WM8993_FLL_LOCK_POL_WIDTH 1 /* FLL_LOCK_POL */
748#define WM8993_GPI8_POL 0x0080 /* GPI8_POL */
749#define WM8993_GPI8_POL_MASK 0x0080 /* GPI8_POL */
750#define WM8993_GPI8_POL_SHIFT 7 /* GPI8_POL */
751#define WM8993_GPI8_POL_WIDTH 1 /* GPI8_POL */
752#define WM8993_GPI7_POL 0x0040 /* GPI7_POL */
753#define WM8993_GPI7_POL_MASK 0x0040 /* GPI7_POL */
754#define WM8993_GPI7_POL_SHIFT 6 /* GPI7_POL */
755#define WM8993_GPI7_POL_WIDTH 1 /* GPI7_POL */
756#define WM8993_GPIO1_POL 0x0001 /* GPIO1_POL */
757#define WM8993_GPIO1_POL_MASK 0x0001 /* GPIO1_POL */
758#define WM8993_GPIO1_POL_SHIFT 0 /* GPIO1_POL */
759#define WM8993_GPIO1_POL_WIDTH 1 /* GPIO1_POL */
760
761/*
762 * R24 (0x18) - Left Line Input 1&2 Volume
763 */
764#define WM8993_IN1_VU 0x0100 /* IN1_VU */
765#define WM8993_IN1_VU_MASK 0x0100 /* IN1_VU */
766#define WM8993_IN1_VU_SHIFT 8 /* IN1_VU */
767#define WM8993_IN1_VU_WIDTH 1 /* IN1_VU */
768#define WM8993_IN1L_MUTE 0x0080 /* IN1L_MUTE */
769#define WM8993_IN1L_MUTE_MASK 0x0080 /* IN1L_MUTE */
770#define WM8993_IN1L_MUTE_SHIFT 7 /* IN1L_MUTE */
771#define WM8993_IN1L_MUTE_WIDTH 1 /* IN1L_MUTE */
772#define WM8993_IN1L_ZC 0x0040 /* IN1L_ZC */
773#define WM8993_IN1L_ZC_MASK 0x0040 /* IN1L_ZC */
774#define WM8993_IN1L_ZC_SHIFT 6 /* IN1L_ZC */
775#define WM8993_IN1L_ZC_WIDTH 1 /* IN1L_ZC */
776#define WM8993_IN1L_VOL_MASK 0x001F /* IN1L_VOL - [4:0] */
777#define WM8993_IN1L_VOL_SHIFT 0 /* IN1L_VOL - [4:0] */
778#define WM8993_IN1L_VOL_WIDTH 5 /* IN1L_VOL - [4:0] */
779
780/*
781 * R25 (0x19) - Left Line Input 3&4 Volume
782 */
783#define WM8993_IN2_VU 0x0100 /* IN2_VU */
784#define WM8993_IN2_VU_MASK 0x0100 /* IN2_VU */
785#define WM8993_IN2_VU_SHIFT 8 /* IN2_VU */
786#define WM8993_IN2_VU_WIDTH 1 /* IN2_VU */
787#define WM8993_IN2L_MUTE 0x0080 /* IN2L_MUTE */
788#define WM8993_IN2L_MUTE_MASK 0x0080 /* IN2L_MUTE */
789#define WM8993_IN2L_MUTE_SHIFT 7 /* IN2L_MUTE */
790#define WM8993_IN2L_MUTE_WIDTH 1 /* IN2L_MUTE */
791#define WM8993_IN2L_ZC 0x0040 /* IN2L_ZC */
792#define WM8993_IN2L_ZC_MASK 0x0040 /* IN2L_ZC */
793#define WM8993_IN2L_ZC_SHIFT 6 /* IN2L_ZC */
794#define WM8993_IN2L_ZC_WIDTH 1 /* IN2L_ZC */
795#define WM8993_IN2L_VOL_MASK 0x001F /* IN2L_VOL - [4:0] */
796#define WM8993_IN2L_VOL_SHIFT 0 /* IN2L_VOL - [4:0] */
797#define WM8993_IN2L_VOL_WIDTH 5 /* IN2L_VOL - [4:0] */
798
799/*
800 * R26 (0x1A) - Right Line Input 1&2 Volume
801 */
802#define WM8993_IN1_VU 0x0100 /* IN1_VU */
803#define WM8993_IN1_VU_MASK 0x0100 /* IN1_VU */
804#define WM8993_IN1_VU_SHIFT 8 /* IN1_VU */
805#define WM8993_IN1_VU_WIDTH 1 /* IN1_VU */
806#define WM8993_IN1R_MUTE 0x0080 /* IN1R_MUTE */
807#define WM8993_IN1R_MUTE_MASK 0x0080 /* IN1R_MUTE */
808#define WM8993_IN1R_MUTE_SHIFT 7 /* IN1R_MUTE */
809#define WM8993_IN1R_MUTE_WIDTH 1 /* IN1R_MUTE */
810#define WM8993_IN1R_ZC 0x0040 /* IN1R_ZC */
811#define WM8993_IN1R_ZC_MASK 0x0040 /* IN1R_ZC */
812#define WM8993_IN1R_ZC_SHIFT 6 /* IN1R_ZC */
813#define WM8993_IN1R_ZC_WIDTH 1 /* IN1R_ZC */
814#define WM8993_IN1R_VOL_MASK 0x001F /* IN1R_VOL - [4:0] */
815#define WM8993_IN1R_VOL_SHIFT 0 /* IN1R_VOL - [4:0] */
816#define WM8993_IN1R_VOL_WIDTH 5 /* IN1R_VOL - [4:0] */
817
818/*
819 * R27 (0x1B) - Right Line Input 3&4 Volume
820 */
821#define WM8993_IN2_VU 0x0100 /* IN2_VU */
822#define WM8993_IN2_VU_MASK 0x0100 /* IN2_VU */
823#define WM8993_IN2_VU_SHIFT 8 /* IN2_VU */
824#define WM8993_IN2_VU_WIDTH 1 /* IN2_VU */
825#define WM8993_IN2R_MUTE 0x0080 /* IN2R_MUTE */
826#define WM8993_IN2R_MUTE_MASK 0x0080 /* IN2R_MUTE */
827#define WM8993_IN2R_MUTE_SHIFT 7 /* IN2R_MUTE */
828#define WM8993_IN2R_MUTE_WIDTH 1 /* IN2R_MUTE */
829#define WM8993_IN2R_ZC 0x0040 /* IN2R_ZC */
830#define WM8993_IN2R_ZC_MASK 0x0040 /* IN2R_ZC */
831#define WM8993_IN2R_ZC_SHIFT 6 /* IN2R_ZC */
832#define WM8993_IN2R_ZC_WIDTH 1 /* IN2R_ZC */
833#define WM8993_IN2R_VOL_MASK 0x001F /* IN2R_VOL - [4:0] */
834#define WM8993_IN2R_VOL_SHIFT 0 /* IN2R_VOL - [4:0] */
835#define WM8993_IN2R_VOL_WIDTH 5 /* IN2R_VOL - [4:0] */
836
837/*
838 * R28 (0x1C) - Left Output Volume
839 */
840#define WM8993_HPOUT1_VU 0x0100 /* HPOUT1_VU */
841#define WM8993_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */
842#define WM8993_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */
843#define WM8993_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */
844#define WM8993_HPOUT1L_ZC 0x0080 /* HPOUT1L_ZC */
845#define WM8993_HPOUT1L_ZC_MASK 0x0080 /* HPOUT1L_ZC */
846#define WM8993_HPOUT1L_ZC_SHIFT 7 /* HPOUT1L_ZC */
847#define WM8993_HPOUT1L_ZC_WIDTH 1 /* HPOUT1L_ZC */
848#define WM8993_HPOUT1L_MUTE_N 0x0040 /* HPOUT1L_MUTE_N */
849#define WM8993_HPOUT1L_MUTE_N_MASK 0x0040 /* HPOUT1L_MUTE_N */
850#define WM8993_HPOUT1L_MUTE_N_SHIFT 6 /* HPOUT1L_MUTE_N */
851#define WM8993_HPOUT1L_MUTE_N_WIDTH 1 /* HPOUT1L_MUTE_N */
852#define WM8993_HPOUT1L_VOL_MASK 0x003F /* HPOUT1L_VOL - [5:0] */
853#define WM8993_HPOUT1L_VOL_SHIFT 0 /* HPOUT1L_VOL - [5:0] */
854#define WM8993_HPOUT1L_VOL_WIDTH 6 /* HPOUT1L_VOL - [5:0] */
855
856/*
857 * R29 (0x1D) - Right Output Volume
858 */
859#define WM8993_HPOUT1_VU 0x0100 /* HPOUT1_VU */
860#define WM8993_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */
861#define WM8993_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */
862#define WM8993_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */
863#define WM8993_HPOUT1R_ZC 0x0080 /* HPOUT1R_ZC */
864#define WM8993_HPOUT1R_ZC_MASK 0x0080 /* HPOUT1R_ZC */
865#define WM8993_HPOUT1R_ZC_SHIFT 7 /* HPOUT1R_ZC */
866#define WM8993_HPOUT1R_ZC_WIDTH 1 /* HPOUT1R_ZC */
867#define WM8993_HPOUT1R_MUTE_N 0x0040 /* HPOUT1R_MUTE_N */
868#define WM8993_HPOUT1R_MUTE_N_MASK 0x0040 /* HPOUT1R_MUTE_N */
869#define WM8993_HPOUT1R_MUTE_N_SHIFT 6 /* HPOUT1R_MUTE_N */
870#define WM8993_HPOUT1R_MUTE_N_WIDTH 1 /* HPOUT1R_MUTE_N */
871#define WM8993_HPOUT1R_VOL_MASK 0x003F /* HPOUT1R_VOL - [5:0] */
872#define WM8993_HPOUT1R_VOL_SHIFT 0 /* HPOUT1R_VOL - [5:0] */
873#define WM8993_HPOUT1R_VOL_WIDTH 6 /* HPOUT1R_VOL - [5:0] */
874
875/*
876 * R30 (0x1E) - Line Outputs Volume
877 */
878#define WM8993_LINEOUT1N_MUTE 0x0040 /* LINEOUT1N_MUTE */
879#define WM8993_LINEOUT1N_MUTE_MASK 0x0040 /* LINEOUT1N_MUTE */
880#define WM8993_LINEOUT1N_MUTE_SHIFT 6 /* LINEOUT1N_MUTE */
881#define WM8993_LINEOUT1N_MUTE_WIDTH 1 /* LINEOUT1N_MUTE */
882#define WM8993_LINEOUT1P_MUTE 0x0020 /* LINEOUT1P_MUTE */
883#define WM8993_LINEOUT1P_MUTE_MASK 0x0020 /* LINEOUT1P_MUTE */
884#define WM8993_LINEOUT1P_MUTE_SHIFT 5 /* LINEOUT1P_MUTE */
885#define WM8993_LINEOUT1P_MUTE_WIDTH 1 /* LINEOUT1P_MUTE */
886#define WM8993_LINEOUT1_VOL 0x0010 /* LINEOUT1_VOL */
887#define WM8993_LINEOUT1_VOL_MASK 0x0010 /* LINEOUT1_VOL */
888#define WM8993_LINEOUT1_VOL_SHIFT 4 /* LINEOUT1_VOL */
889#define WM8993_LINEOUT1_VOL_WIDTH 1 /* LINEOUT1_VOL */
890#define WM8993_LINEOUT2N_MUTE 0x0004 /* LINEOUT2N_MUTE */
891#define WM8993_LINEOUT2N_MUTE_MASK 0x0004 /* LINEOUT2N_MUTE */
892#define WM8993_LINEOUT2N_MUTE_SHIFT 2 /* LINEOUT2N_MUTE */
893#define WM8993_LINEOUT2N_MUTE_WIDTH 1 /* LINEOUT2N_MUTE */
894#define WM8993_LINEOUT2P_MUTE 0x0002 /* LINEOUT2P_MUTE */
895#define WM8993_LINEOUT2P_MUTE_MASK 0x0002 /* LINEOUT2P_MUTE */
896#define WM8993_LINEOUT2P_MUTE_SHIFT 1 /* LINEOUT2P_MUTE */
897#define WM8993_LINEOUT2P_MUTE_WIDTH 1 /* LINEOUT2P_MUTE */
898#define WM8993_LINEOUT2_VOL 0x0001 /* LINEOUT2_VOL */
899#define WM8993_LINEOUT2_VOL_MASK 0x0001 /* LINEOUT2_VOL */
900#define WM8993_LINEOUT2_VOL_SHIFT 0 /* LINEOUT2_VOL */
901#define WM8993_LINEOUT2_VOL_WIDTH 1 /* LINEOUT2_VOL */
902
903/*
904 * R31 (0x1F) - HPOUT2 Volume
905 */
906#define WM8993_HPOUT2_MUTE 0x0020 /* HPOUT2_MUTE */
907#define WM8993_HPOUT2_MUTE_MASK 0x0020 /* HPOUT2_MUTE */
908#define WM8993_HPOUT2_MUTE_SHIFT 5 /* HPOUT2_MUTE */
909#define WM8993_HPOUT2_MUTE_WIDTH 1 /* HPOUT2_MUTE */
910#define WM8993_HPOUT2_VOL 0x0010 /* HPOUT2_VOL */
911#define WM8993_HPOUT2_VOL_MASK 0x0010 /* HPOUT2_VOL */
912#define WM8993_HPOUT2_VOL_SHIFT 4 /* HPOUT2_VOL */
913#define WM8993_HPOUT2_VOL_WIDTH 1 /* HPOUT2_VOL */
914
915/*
916 * R32 (0x20) - Left OPGA Volume
917 */
918#define WM8993_MIXOUT_VU 0x0100 /* MIXOUT_VU */
919#define WM8993_MIXOUT_VU_MASK 0x0100 /* MIXOUT_VU */
920#define WM8993_MIXOUT_VU_SHIFT 8 /* MIXOUT_VU */
921#define WM8993_MIXOUT_VU_WIDTH 1 /* MIXOUT_VU */
922#define WM8993_MIXOUTL_ZC 0x0080 /* MIXOUTL_ZC */
923#define WM8993_MIXOUTL_ZC_MASK 0x0080 /* MIXOUTL_ZC */
924#define WM8993_MIXOUTL_ZC_SHIFT 7 /* MIXOUTL_ZC */
925#define WM8993_MIXOUTL_ZC_WIDTH 1 /* MIXOUTL_ZC */
926#define WM8993_MIXOUTL_MUTE_N 0x0040 /* MIXOUTL_MUTE_N */
927#define WM8993_MIXOUTL_MUTE_N_MASK 0x0040 /* MIXOUTL_MUTE_N */
928#define WM8993_MIXOUTL_MUTE_N_SHIFT 6 /* MIXOUTL_MUTE_N */
929#define WM8993_MIXOUTL_MUTE_N_WIDTH 1 /* MIXOUTL_MUTE_N */
930#define WM8993_MIXOUTL_VOL_MASK 0x003F /* MIXOUTL_VOL - [5:0] */
931#define WM8993_MIXOUTL_VOL_SHIFT 0 /* MIXOUTL_VOL - [5:0] */
932#define WM8993_MIXOUTL_VOL_WIDTH 6 /* MIXOUTL_VOL - [5:0] */
933
934/*
935 * R33 (0x21) - Right OPGA Volume
936 */
937#define WM8993_MIXOUT_VU 0x0100 /* MIXOUT_VU */
938#define WM8993_MIXOUT_VU_MASK 0x0100 /* MIXOUT_VU */
939#define WM8993_MIXOUT_VU_SHIFT 8 /* MIXOUT_VU */
940#define WM8993_MIXOUT_VU_WIDTH 1 /* MIXOUT_VU */
941#define WM8993_MIXOUTR_ZC 0x0080 /* MIXOUTR_ZC */
942#define WM8993_MIXOUTR_ZC_MASK 0x0080 /* MIXOUTR_ZC */
943#define WM8993_MIXOUTR_ZC_SHIFT 7 /* MIXOUTR_ZC */
944#define WM8993_MIXOUTR_ZC_WIDTH 1 /* MIXOUTR_ZC */
945#define WM8993_MIXOUTR_MUTE_N 0x0040 /* MIXOUTR_MUTE_N */
946#define WM8993_MIXOUTR_MUTE_N_MASK 0x0040 /* MIXOUTR_MUTE_N */
947#define WM8993_MIXOUTR_MUTE_N_SHIFT 6 /* MIXOUTR_MUTE_N */
948#define WM8993_MIXOUTR_MUTE_N_WIDTH 1 /* MIXOUTR_MUTE_N */
949#define WM8993_MIXOUTR_VOL_MASK 0x003F /* MIXOUTR_VOL - [5:0] */
950#define WM8993_MIXOUTR_VOL_SHIFT 0 /* MIXOUTR_VOL - [5:0] */
951#define WM8993_MIXOUTR_VOL_WIDTH 6 /* MIXOUTR_VOL - [5:0] */
952
953/*
954 * R34 (0x22) - SPKMIXL Attenuation
955 */
956#define WM8993_MIXINL_SPKMIXL_VOL 0x0020 /* MIXINL_SPKMIXL_VOL */
957#define WM8993_MIXINL_SPKMIXL_VOL_MASK 0x0020 /* MIXINL_SPKMIXL_VOL */
958#define WM8993_MIXINL_SPKMIXL_VOL_SHIFT 5 /* MIXINL_SPKMIXL_VOL */
959#define WM8993_MIXINL_SPKMIXL_VOL_WIDTH 1 /* MIXINL_SPKMIXL_VOL */
960#define WM8993_IN1LP_SPKMIXL_VOL 0x0010 /* IN1LP_SPKMIXL_VOL */
961#define WM8993_IN1LP_SPKMIXL_VOL_MASK 0x0010 /* IN1LP_SPKMIXL_VOL */
962#define WM8993_IN1LP_SPKMIXL_VOL_SHIFT 4 /* IN1LP_SPKMIXL_VOL */
963#define WM8993_IN1LP_SPKMIXL_VOL_WIDTH 1 /* IN1LP_SPKMIXL_VOL */
964#define WM8993_MIXOUTL_SPKMIXL_VOL 0x0008 /* MIXOUTL_SPKMIXL_VOL */
965#define WM8993_MIXOUTL_SPKMIXL_VOL_MASK 0x0008 /* MIXOUTL_SPKMIXL_VOL */
966#define WM8993_MIXOUTL_SPKMIXL_VOL_SHIFT 3 /* MIXOUTL_SPKMIXL_VOL */
967#define WM8993_MIXOUTL_SPKMIXL_VOL_WIDTH 1 /* MIXOUTL_SPKMIXL_VOL */
968#define WM8993_DACL_SPKMIXL_VOL 0x0004 /* DACL_SPKMIXL_VOL */
969#define WM8993_DACL_SPKMIXL_VOL_MASK 0x0004 /* DACL_SPKMIXL_VOL */
970#define WM8993_DACL_SPKMIXL_VOL_SHIFT 2 /* DACL_SPKMIXL_VOL */
971#define WM8993_DACL_SPKMIXL_VOL_WIDTH 1 /* DACL_SPKMIXL_VOL */
972#define WM8993_SPKMIXL_VOL_MASK 0x0003 /* SPKMIXL_VOL - [1:0] */
973#define WM8993_SPKMIXL_VOL_SHIFT 0 /* SPKMIXL_VOL - [1:0] */
974#define WM8993_SPKMIXL_VOL_WIDTH 2 /* SPKMIXL_VOL - [1:0] */
975
976/*
977 * R35 (0x23) - SPKMIXR Attenuation
978 */
979#define WM8993_SPKOUT_CLASSAB_MODE 0x0100 /* SPKOUT_CLASSAB_MODE */
980#define WM8993_SPKOUT_CLASSAB_MODE_MASK 0x0100 /* SPKOUT_CLASSAB_MODE */
981#define WM8993_SPKOUT_CLASSAB_MODE_SHIFT 8 /* SPKOUT_CLASSAB_MODE */
982#define WM8993_SPKOUT_CLASSAB_MODE_WIDTH 1 /* SPKOUT_CLASSAB_MODE */
983#define WM8993_MIXINR_SPKMIXR_VOL 0x0020 /* MIXINR_SPKMIXR_VOL */
984#define WM8993_MIXINR_SPKMIXR_VOL_MASK 0x0020 /* MIXINR_SPKMIXR_VOL */
985#define WM8993_MIXINR_SPKMIXR_VOL_SHIFT 5 /* MIXINR_SPKMIXR_VOL */
986#define WM8993_MIXINR_SPKMIXR_VOL_WIDTH 1 /* MIXINR_SPKMIXR_VOL */
987#define WM8993_IN1RP_SPKMIXR_VOL 0x0010 /* IN1RP_SPKMIXR_VOL */
988#define WM8993_IN1RP_SPKMIXR_VOL_MASK 0x0010 /* IN1RP_SPKMIXR_VOL */
989#define WM8993_IN1RP_SPKMIXR_VOL_SHIFT 4 /* IN1RP_SPKMIXR_VOL */
990#define WM8993_IN1RP_SPKMIXR_VOL_WIDTH 1 /* IN1RP_SPKMIXR_VOL */
991#define WM8993_MIXOUTR_SPKMIXR_VOL 0x0008 /* MIXOUTR_SPKMIXR_VOL */
992#define WM8993_MIXOUTR_SPKMIXR_VOL_MASK 0x0008 /* MIXOUTR_SPKMIXR_VOL */
993#define WM8993_MIXOUTR_SPKMIXR_VOL_SHIFT 3 /* MIXOUTR_SPKMIXR_VOL */
994#define WM8993_MIXOUTR_SPKMIXR_VOL_WIDTH 1 /* MIXOUTR_SPKMIXR_VOL */
995#define WM8993_DACR_SPKMIXR_VOL 0x0004 /* DACR_SPKMIXR_VOL */
996#define WM8993_DACR_SPKMIXR_VOL_MASK 0x0004 /* DACR_SPKMIXR_VOL */
997#define WM8993_DACR_SPKMIXR_VOL_SHIFT 2 /* DACR_SPKMIXR_VOL */
998#define WM8993_DACR_SPKMIXR_VOL_WIDTH 1 /* DACR_SPKMIXR_VOL */
999#define WM8993_SPKMIXR_VOL_MASK 0x0003 /* SPKMIXR_VOL - [1:0] */
1000#define WM8993_SPKMIXR_VOL_SHIFT 0 /* SPKMIXR_VOL - [1:0] */
1001#define WM8993_SPKMIXR_VOL_WIDTH 2 /* SPKMIXR_VOL - [1:0] */
1002
1003/*
1004 * R36 (0x24) - SPKOUT Mixers
1005 */
1006#define WM8993_VRX_TO_SPKOUTL 0x0020 /* VRX_TO_SPKOUTL */
1007#define WM8993_VRX_TO_SPKOUTL_MASK 0x0020 /* VRX_TO_SPKOUTL */
1008#define WM8993_VRX_TO_SPKOUTL_SHIFT 5 /* VRX_TO_SPKOUTL */
1009#define WM8993_VRX_TO_SPKOUTL_WIDTH 1 /* VRX_TO_SPKOUTL */
1010#define WM8993_SPKMIXL_TO_SPKOUTL 0x0010 /* SPKMIXL_TO_SPKOUTL */
1011#define WM8993_SPKMIXL_TO_SPKOUTL_MASK 0x0010 /* SPKMIXL_TO_SPKOUTL */
1012#define WM8993_SPKMIXL_TO_SPKOUTL_SHIFT 4 /* SPKMIXL_TO_SPKOUTL */
1013#define WM8993_SPKMIXL_TO_SPKOUTL_WIDTH 1 /* SPKMIXL_TO_SPKOUTL */
1014#define WM8993_SPKMIXR_TO_SPKOUTL 0x0008 /* SPKMIXR_TO_SPKOUTL */
1015#define WM8993_SPKMIXR_TO_SPKOUTL_MASK 0x0008 /* SPKMIXR_TO_SPKOUTL */
1016#define WM8993_SPKMIXR_TO_SPKOUTL_SHIFT 3 /* SPKMIXR_TO_SPKOUTL */
1017#define WM8993_SPKMIXR_TO_SPKOUTL_WIDTH 1 /* SPKMIXR_TO_SPKOUTL */
1018#define WM8993_VRX_TO_SPKOUTR 0x0004 /* VRX_TO_SPKOUTR */
1019#define WM8993_VRX_TO_SPKOUTR_MASK 0x0004 /* VRX_TO_SPKOUTR */
1020#define WM8993_VRX_TO_SPKOUTR_SHIFT 2 /* VRX_TO_SPKOUTR */
1021#define WM8993_VRX_TO_SPKOUTR_WIDTH 1 /* VRX_TO_SPKOUTR */
1022#define WM8993_SPKMIXL_TO_SPKOUTR 0x0002 /* SPKMIXL_TO_SPKOUTR */
1023#define WM8993_SPKMIXL_TO_SPKOUTR_MASK 0x0002 /* SPKMIXL_TO_SPKOUTR */
1024#define WM8993_SPKMIXL_TO_SPKOUTR_SHIFT 1 /* SPKMIXL_TO_SPKOUTR */
1025#define WM8993_SPKMIXL_TO_SPKOUTR_WIDTH 1 /* SPKMIXL_TO_SPKOUTR */
1026#define WM8993_SPKMIXR_TO_SPKOUTR 0x0001 /* SPKMIXR_TO_SPKOUTR */
1027#define WM8993_SPKMIXR_TO_SPKOUTR_MASK 0x0001 /* SPKMIXR_TO_SPKOUTR */
1028#define WM8993_SPKMIXR_TO_SPKOUTR_SHIFT 0 /* SPKMIXR_TO_SPKOUTR */
1029#define WM8993_SPKMIXR_TO_SPKOUTR_WIDTH 1 /* SPKMIXR_TO_SPKOUTR */
1030
1031/*
1032 * R37 (0x25) - SPKOUT Boost
1033 */
1034#define WM8993_SPKOUTL_BOOST_MASK 0x0038 /* SPKOUTL_BOOST - [5:3] */
1035#define WM8993_SPKOUTL_BOOST_SHIFT 3 /* SPKOUTL_BOOST - [5:3] */
1036#define WM8993_SPKOUTL_BOOST_WIDTH 3 /* SPKOUTL_BOOST - [5:3] */
1037#define WM8993_SPKOUTR_BOOST_MASK 0x0007 /* SPKOUTR_BOOST - [2:0] */
1038#define WM8993_SPKOUTR_BOOST_SHIFT 0 /* SPKOUTR_BOOST - [2:0] */
1039#define WM8993_SPKOUTR_BOOST_WIDTH 3 /* SPKOUTR_BOOST - [2:0] */
1040
1041/*
1042 * R38 (0x26) - Speaker Volume Left
1043 */
1044#define WM8993_SPKOUT_VU 0x0100 /* SPKOUT_VU */
1045#define WM8993_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */
1046#define WM8993_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */
1047#define WM8993_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */
1048#define WM8993_SPKOUTL_ZC 0x0080 /* SPKOUTL_ZC */
1049#define WM8993_SPKOUTL_ZC_MASK 0x0080 /* SPKOUTL_ZC */
1050#define WM8993_SPKOUTL_ZC_SHIFT 7 /* SPKOUTL_ZC */
1051#define WM8993_SPKOUTL_ZC_WIDTH 1 /* SPKOUTL_ZC */
1052#define WM8993_SPKOUTL_MUTE_N 0x0040 /* SPKOUTL_MUTE_N */
1053#define WM8993_SPKOUTL_MUTE_N_MASK 0x0040 /* SPKOUTL_MUTE_N */
1054#define WM8993_SPKOUTL_MUTE_N_SHIFT 6 /* SPKOUTL_MUTE_N */
1055#define WM8993_SPKOUTL_MUTE_N_WIDTH 1 /* SPKOUTL_MUTE_N */
1056#define WM8993_SPKOUTL_VOL_MASK 0x003F /* SPKOUTL_VOL - [5:0] */
1057#define WM8993_SPKOUTL_VOL_SHIFT 0 /* SPKOUTL_VOL - [5:0] */
1058#define WM8993_SPKOUTL_VOL_WIDTH 6 /* SPKOUTL_VOL - [5:0] */
1059
1060/*
1061 * R39 (0x27) - Speaker Volume Right
1062 */
1063#define WM8993_SPKOUT_VU 0x0100 /* SPKOUT_VU */
1064#define WM8993_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */
1065#define WM8993_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */
1066#define WM8993_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */
1067#define WM8993_SPKOUTR_ZC 0x0080 /* SPKOUTR_ZC */
1068#define WM8993_SPKOUTR_ZC_MASK 0x0080 /* SPKOUTR_ZC */
1069#define WM8993_SPKOUTR_ZC_SHIFT 7 /* SPKOUTR_ZC */
1070#define WM8993_SPKOUTR_ZC_WIDTH 1 /* SPKOUTR_ZC */
1071#define WM8993_SPKOUTR_MUTE_N 0x0040 /* SPKOUTR_MUTE_N */
1072#define WM8993_SPKOUTR_MUTE_N_MASK 0x0040 /* SPKOUTR_MUTE_N */
1073#define WM8993_SPKOUTR_MUTE_N_SHIFT 6 /* SPKOUTR_MUTE_N */
1074#define WM8993_SPKOUTR_MUTE_N_WIDTH 1 /* SPKOUTR_MUTE_N */
1075#define WM8993_SPKOUTR_VOL_MASK 0x003F /* SPKOUTR_VOL - [5:0] */
1076#define WM8993_SPKOUTR_VOL_SHIFT 0 /* SPKOUTR_VOL - [5:0] */
1077#define WM8993_SPKOUTR_VOL_WIDTH 6 /* SPKOUTR_VOL - [5:0] */
1078
1079/*
1080 * R40 (0x28) - Input Mixer2
1081 */
1082#define WM8993_IN2LP_TO_IN2L 0x0080 /* IN2LP_TO_IN2L */
1083#define WM8993_IN2LP_TO_IN2L_MASK 0x0080 /* IN2LP_TO_IN2L */
1084#define WM8993_IN2LP_TO_IN2L_SHIFT 7 /* IN2LP_TO_IN2L */
1085#define WM8993_IN2LP_TO_IN2L_WIDTH 1 /* IN2LP_TO_IN2L */
1086#define WM8993_IN2LN_TO_IN2L 0x0040 /* IN2LN_TO_IN2L */
1087#define WM8993_IN2LN_TO_IN2L_MASK 0x0040 /* IN2LN_TO_IN2L */
1088#define WM8993_IN2LN_TO_IN2L_SHIFT 6 /* IN2LN_TO_IN2L */
1089#define WM8993_IN2LN_TO_IN2L_WIDTH 1 /* IN2LN_TO_IN2L */
1090#define WM8993_IN1LP_TO_IN1L 0x0020 /* IN1LP_TO_IN1L */
1091#define WM8993_IN1LP_TO_IN1L_MASK 0x0020 /* IN1LP_TO_IN1L */
1092#define WM8993_IN1LP_TO_IN1L_SHIFT 5 /* IN1LP_TO_IN1L */
1093#define WM8993_IN1LP_TO_IN1L_WIDTH 1 /* IN1LP_TO_IN1L */
1094#define WM8993_IN1LN_TO_IN1L 0x0010 /* IN1LN_TO_IN1L */
1095#define WM8993_IN1LN_TO_IN1L_MASK 0x0010 /* IN1LN_TO_IN1L */
1096#define WM8993_IN1LN_TO_IN1L_SHIFT 4 /* IN1LN_TO_IN1L */
1097#define WM8993_IN1LN_TO_IN1L_WIDTH 1 /* IN1LN_TO_IN1L */
1098#define WM8993_IN2RP_TO_IN2R 0x0008 /* IN2RP_TO_IN2R */
1099#define WM8993_IN2RP_TO_IN2R_MASK 0x0008 /* IN2RP_TO_IN2R */
1100#define WM8993_IN2RP_TO_IN2R_SHIFT 3 /* IN2RP_TO_IN2R */
1101#define WM8993_IN2RP_TO_IN2R_WIDTH 1 /* IN2RP_TO_IN2R */
1102#define WM8993_IN2RN_TO_IN2R 0x0004 /* IN2RN_TO_IN2R */
1103#define WM8993_IN2RN_TO_IN2R_MASK 0x0004 /* IN2RN_TO_IN2R */
1104#define WM8993_IN2RN_TO_IN2R_SHIFT 2 /* IN2RN_TO_IN2R */
1105#define WM8993_IN2RN_TO_IN2R_WIDTH 1 /* IN2RN_TO_IN2R */
1106#define WM8993_IN1RP_TO_IN1R 0x0002 /* IN1RP_TO_IN1R */
1107#define WM8993_IN1RP_TO_IN1R_MASK 0x0002 /* IN1RP_TO_IN1R */
1108#define WM8993_IN1RP_TO_IN1R_SHIFT 1 /* IN1RP_TO_IN1R */
1109#define WM8993_IN1RP_TO_IN1R_WIDTH 1 /* IN1RP_TO_IN1R */
1110#define WM8993_IN1RN_TO_IN1R 0x0001 /* IN1RN_TO_IN1R */
1111#define WM8993_IN1RN_TO_IN1R_MASK 0x0001 /* IN1RN_TO_IN1R */
1112#define WM8993_IN1RN_TO_IN1R_SHIFT 0 /* IN1RN_TO_IN1R */
1113#define WM8993_IN1RN_TO_IN1R_WIDTH 1 /* IN1RN_TO_IN1R */
1114
1115/*
1116 * R41 (0x29) - Input Mixer3
1117 */
1118#define WM8993_IN2L_TO_MIXINL 0x0100 /* IN2L_TO_MIXINL */
1119#define WM8993_IN2L_TO_MIXINL_MASK 0x0100 /* IN2L_TO_MIXINL */
1120#define WM8993_IN2L_TO_MIXINL_SHIFT 8 /* IN2L_TO_MIXINL */
1121#define WM8993_IN2L_TO_MIXINL_WIDTH 1 /* IN2L_TO_MIXINL */
1122#define WM8993_IN2L_MIXINL_VOL 0x0080 /* IN2L_MIXINL_VOL */
1123#define WM8993_IN2L_MIXINL_VOL_MASK 0x0080 /* IN2L_MIXINL_VOL */
1124#define WM8993_IN2L_MIXINL_VOL_SHIFT 7 /* IN2L_MIXINL_VOL */
1125#define WM8993_IN2L_MIXINL_VOL_WIDTH 1 /* IN2L_MIXINL_VOL */
1126#define WM8993_IN1L_TO_MIXINL 0x0020 /* IN1L_TO_MIXINL */
1127#define WM8993_IN1L_TO_MIXINL_MASK 0x0020 /* IN1L_TO_MIXINL */
1128#define WM8993_IN1L_TO_MIXINL_SHIFT 5 /* IN1L_TO_MIXINL */
1129#define WM8993_IN1L_TO_MIXINL_WIDTH 1 /* IN1L_TO_MIXINL */
1130#define WM8993_IN1L_MIXINL_VOL 0x0010 /* IN1L_MIXINL_VOL */
1131#define WM8993_IN1L_MIXINL_VOL_MASK 0x0010 /* IN1L_MIXINL_VOL */
1132#define WM8993_IN1L_MIXINL_VOL_SHIFT 4 /* IN1L_MIXINL_VOL */
1133#define WM8993_IN1L_MIXINL_VOL_WIDTH 1 /* IN1L_MIXINL_VOL */
1134#define WM8993_MIXOUTL_MIXINL_VOL_MASK 0x0007 /* MIXOUTL_MIXINL_VOL - [2:0] */
1135#define WM8993_MIXOUTL_MIXINL_VOL_SHIFT 0 /* MIXOUTL_MIXINL_VOL - [2:0] */
1136#define WM8993_MIXOUTL_MIXINL_VOL_WIDTH 3 /* MIXOUTL_MIXINL_VOL - [2:0] */
1137
1138/*
1139 * R42 (0x2A) - Input Mixer4
1140 */
1141#define WM8993_IN2R_TO_MIXINR 0x0100 /* IN2R_TO_MIXINR */
1142#define WM8993_IN2R_TO_MIXINR_MASK 0x0100 /* IN2R_TO_MIXINR */
1143#define WM8993_IN2R_TO_MIXINR_SHIFT 8 /* IN2R_TO_MIXINR */
1144#define WM8993_IN2R_TO_MIXINR_WIDTH 1 /* IN2R_TO_MIXINR */
1145#define WM8993_IN2R_MIXINR_VOL 0x0080 /* IN2R_MIXINR_VOL */
1146#define WM8993_IN2R_MIXINR_VOL_MASK 0x0080 /* IN2R_MIXINR_VOL */
1147#define WM8993_IN2R_MIXINR_VOL_SHIFT 7 /* IN2R_MIXINR_VOL */
1148#define WM8993_IN2R_MIXINR_VOL_WIDTH 1 /* IN2R_MIXINR_VOL */
1149#define WM8993_IN1R_TO_MIXINR 0x0020 /* IN1R_TO_MIXINR */
1150#define WM8993_IN1R_TO_MIXINR_MASK 0x0020 /* IN1R_TO_MIXINR */
1151#define WM8993_IN1R_TO_MIXINR_SHIFT 5 /* IN1R_TO_MIXINR */
1152#define WM8993_IN1R_TO_MIXINR_WIDTH 1 /* IN1R_TO_MIXINR */
1153#define WM8993_IN1R_MIXINR_VOL 0x0010 /* IN1R_MIXINR_VOL */
1154#define WM8993_IN1R_MIXINR_VOL_MASK 0x0010 /* IN1R_MIXINR_VOL */
1155#define WM8993_IN1R_MIXINR_VOL_SHIFT 4 /* IN1R_MIXINR_VOL */
1156#define WM8993_IN1R_MIXINR_VOL_WIDTH 1 /* IN1R_MIXINR_VOL */
1157#define WM8993_MIXOUTR_MIXINR_VOL_MASK 0x0007 /* MIXOUTR_MIXINR_VOL - [2:0] */
1158#define WM8993_MIXOUTR_MIXINR_VOL_SHIFT 0 /* MIXOUTR_MIXINR_VOL - [2:0] */
1159#define WM8993_MIXOUTR_MIXINR_VOL_WIDTH 3 /* MIXOUTR_MIXINR_VOL - [2:0] */
1160
1161/*
1162 * R43 (0x2B) - Input Mixer5
1163 */
1164#define WM8993_IN1LP_MIXINL_VOL_MASK 0x01C0 /* IN1LP_MIXINL_VOL - [8:6] */
1165#define WM8993_IN1LP_MIXINL_VOL_SHIFT 6 /* IN1LP_MIXINL_VOL - [8:6] */
1166#define WM8993_IN1LP_MIXINL_VOL_WIDTH 3 /* IN1LP_MIXINL_VOL - [8:6] */
1167#define WM8993_VRX_MIXINL_VOL_MASK 0x0007 /* VRX_MIXINL_VOL - [2:0] */
1168#define WM8993_VRX_MIXINL_VOL_SHIFT 0 /* VRX_MIXINL_VOL - [2:0] */
1169#define WM8993_VRX_MIXINL_VOL_WIDTH 3 /* VRX_MIXINL_VOL - [2:0] */
1170
1171/*
1172 * R44 (0x2C) - Input Mixer6
1173 */
1174#define WM8993_IN1RP_MIXINR_VOL_MASK 0x01C0 /* IN1RP_MIXINR_VOL - [8:6] */
1175#define WM8993_IN1RP_MIXINR_VOL_SHIFT 6 /* IN1RP_MIXINR_VOL - [8:6] */
1176#define WM8993_IN1RP_MIXINR_VOL_WIDTH 3 /* IN1RP_MIXINR_VOL - [8:6] */
1177#define WM8993_VRX_MIXINR_VOL_MASK 0x0007 /* VRX_MIXINR_VOL - [2:0] */
1178#define WM8993_VRX_MIXINR_VOL_SHIFT 0 /* VRX_MIXINR_VOL - [2:0] */
1179#define WM8993_VRX_MIXINR_VOL_WIDTH 3 /* VRX_MIXINR_VOL - [2:0] */
1180
1181/*
1182 * R45 (0x2D) - Output Mixer1
1183 */
1184#define WM8993_DACL_TO_HPOUT1L 0x0100 /* DACL_TO_HPOUT1L */
1185#define WM8993_DACL_TO_HPOUT1L_MASK 0x0100 /* DACL_TO_HPOUT1L */
1186#define WM8993_DACL_TO_HPOUT1L_SHIFT 8 /* DACL_TO_HPOUT1L */
1187#define WM8993_DACL_TO_HPOUT1L_WIDTH 1 /* DACL_TO_HPOUT1L */
1188#define WM8993_MIXINR_TO_MIXOUTL 0x0080 /* MIXINR_TO_MIXOUTL */
1189#define WM8993_MIXINR_TO_MIXOUTL_MASK 0x0080 /* MIXINR_TO_MIXOUTL */
1190#define WM8993_MIXINR_TO_MIXOUTL_SHIFT 7 /* MIXINR_TO_MIXOUTL */
1191#define WM8993_MIXINR_TO_MIXOUTL_WIDTH 1 /* MIXINR_TO_MIXOUTL */
1192#define WM8993_MIXINL_TO_MIXOUTL 0x0040 /* MIXINL_TO_MIXOUTL */
1193#define WM8993_MIXINL_TO_MIXOUTL_MASK 0x0040 /* MIXINL_TO_MIXOUTL */
1194#define WM8993_MIXINL_TO_MIXOUTL_SHIFT 6 /* MIXINL_TO_MIXOUTL */
1195#define WM8993_MIXINL_TO_MIXOUTL_WIDTH 1 /* MIXINL_TO_MIXOUTL */
1196#define WM8993_IN2RN_TO_MIXOUTL 0x0020 /* IN2RN_TO_MIXOUTL */
1197#define WM8993_IN2RN_TO_MIXOUTL_MASK 0x0020 /* IN2RN_TO_MIXOUTL */
1198#define WM8993_IN2RN_TO_MIXOUTL_SHIFT 5 /* IN2RN_TO_MIXOUTL */
1199#define WM8993_IN2RN_TO_MIXOUTL_WIDTH 1 /* IN2RN_TO_MIXOUTL */
1200#define WM8993_IN2LN_TO_MIXOUTL 0x0010 /* IN2LN_TO_MIXOUTL */
1201#define WM8993_IN2LN_TO_MIXOUTL_MASK 0x0010 /* IN2LN_TO_MIXOUTL */
1202#define WM8993_IN2LN_TO_MIXOUTL_SHIFT 4 /* IN2LN_TO_MIXOUTL */
1203#define WM8993_IN2LN_TO_MIXOUTL_WIDTH 1 /* IN2LN_TO_MIXOUTL */
1204#define WM8993_IN1R_TO_MIXOUTL 0x0008 /* IN1R_TO_MIXOUTL */
1205#define WM8993_IN1R_TO_MIXOUTL_MASK 0x0008 /* IN1R_TO_MIXOUTL */
1206#define WM8993_IN1R_TO_MIXOUTL_SHIFT 3 /* IN1R_TO_MIXOUTL */
1207#define WM8993_IN1R_TO_MIXOUTL_WIDTH 1 /* IN1R_TO_MIXOUTL */
1208#define WM8993_IN1L_TO_MIXOUTL 0x0004 /* IN1L_TO_MIXOUTL */
1209#define WM8993_IN1L_TO_MIXOUTL_MASK 0x0004 /* IN1L_TO_MIXOUTL */
1210#define WM8993_IN1L_TO_MIXOUTL_SHIFT 2 /* IN1L_TO_MIXOUTL */
1211#define WM8993_IN1L_TO_MIXOUTL_WIDTH 1 /* IN1L_TO_MIXOUTL */
1212#define WM8993_IN2LP_TO_MIXOUTL 0x0002 /* IN2LP_TO_MIXOUTL */
1213#define WM8993_IN2LP_TO_MIXOUTL_MASK 0x0002 /* IN2LP_TO_MIXOUTL */
1214#define WM8993_IN2LP_TO_MIXOUTL_SHIFT 1 /* IN2LP_TO_MIXOUTL */
1215#define WM8993_IN2LP_TO_MIXOUTL_WIDTH 1 /* IN2LP_TO_MIXOUTL */
1216#define WM8993_DACL_TO_MIXOUTL 0x0001 /* DACL_TO_MIXOUTL */
1217#define WM8993_DACL_TO_MIXOUTL_MASK 0x0001 /* DACL_TO_MIXOUTL */
1218#define WM8993_DACL_TO_MIXOUTL_SHIFT 0 /* DACL_TO_MIXOUTL */
1219#define WM8993_DACL_TO_MIXOUTL_WIDTH 1 /* DACL_TO_MIXOUTL */
1220
1221/*
1222 * R46 (0x2E) - Output Mixer2
1223 */
1224#define WM8993_DACR_TO_HPOUT1R 0x0100 /* DACR_TO_HPOUT1R */
1225#define WM8993_DACR_TO_HPOUT1R_MASK 0x0100 /* DACR_TO_HPOUT1R */
1226#define WM8993_DACR_TO_HPOUT1R_SHIFT 8 /* DACR_TO_HPOUT1R */
1227#define WM8993_DACR_TO_HPOUT1R_WIDTH 1 /* DACR_TO_HPOUT1R */
1228#define WM8993_MIXINL_TO_MIXOUTR 0x0080 /* MIXINL_TO_MIXOUTR */
1229#define WM8993_MIXINL_TO_MIXOUTR_MASK 0x0080 /* MIXINL_TO_MIXOUTR */
1230#define WM8993_MIXINL_TO_MIXOUTR_SHIFT 7 /* MIXINL_TO_MIXOUTR */
1231#define WM8993_MIXINL_TO_MIXOUTR_WIDTH 1 /* MIXINL_TO_MIXOUTR */
1232#define WM8993_MIXINR_TO_MIXOUTR 0x0040 /* MIXINR_TO_MIXOUTR */
1233#define WM8993_MIXINR_TO_MIXOUTR_MASK 0x0040 /* MIXINR_TO_MIXOUTR */
1234#define WM8993_MIXINR_TO_MIXOUTR_SHIFT 6 /* MIXINR_TO_MIXOUTR */
1235#define WM8993_MIXINR_TO_MIXOUTR_WIDTH 1 /* MIXINR_TO_MIXOUTR */
1236#define WM8993_IN2LN_TO_MIXOUTR 0x0020 /* IN2LN_TO_MIXOUTR */
1237#define WM8993_IN2LN_TO_MIXOUTR_MASK 0x0020 /* IN2LN_TO_MIXOUTR */
1238#define WM8993_IN2LN_TO_MIXOUTR_SHIFT 5 /* IN2LN_TO_MIXOUTR */
1239#define WM8993_IN2LN_TO_MIXOUTR_WIDTH 1 /* IN2LN_TO_MIXOUTR */
1240#define WM8993_IN2RN_TO_MIXOUTR 0x0010 /* IN2RN_TO_MIXOUTR */
1241#define WM8993_IN2RN_TO_MIXOUTR_MASK 0x0010 /* IN2RN_TO_MIXOUTR */
1242#define WM8993_IN2RN_TO_MIXOUTR_SHIFT 4 /* IN2RN_TO_MIXOUTR */
1243#define WM8993_IN2RN_TO_MIXOUTR_WIDTH 1 /* IN2RN_TO_MIXOUTR */
1244#define WM8993_IN1L_TO_MIXOUTR 0x0008 /* IN1L_TO_MIXOUTR */
1245#define WM8993_IN1L_TO_MIXOUTR_MASK 0x0008 /* IN1L_TO_MIXOUTR */
1246#define WM8993_IN1L_TO_MIXOUTR_SHIFT 3 /* IN1L_TO_MIXOUTR */
1247#define WM8993_IN1L_TO_MIXOUTR_WIDTH 1 /* IN1L_TO_MIXOUTR */
1248#define WM8993_IN1R_TO_MIXOUTR 0x0004 /* IN1R_TO_MIXOUTR */
1249#define WM8993_IN1R_TO_MIXOUTR_MASK 0x0004 /* IN1R_TO_MIXOUTR */
1250#define WM8993_IN1R_TO_MIXOUTR_SHIFT 2 /* IN1R_TO_MIXOUTR */
1251#define WM8993_IN1R_TO_MIXOUTR_WIDTH 1 /* IN1R_TO_MIXOUTR */
1252#define WM8993_IN2RP_TO_MIXOUTR 0x0002 /* IN2RP_TO_MIXOUTR */
1253#define WM8993_IN2RP_TO_MIXOUTR_MASK 0x0002 /* IN2RP_TO_MIXOUTR */
1254#define WM8993_IN2RP_TO_MIXOUTR_SHIFT 1 /* IN2RP_TO_MIXOUTR */
1255#define WM8993_IN2RP_TO_MIXOUTR_WIDTH 1 /* IN2RP_TO_MIXOUTR */
1256#define WM8993_DACR_TO_MIXOUTR 0x0001 /* DACR_TO_MIXOUTR */
1257#define WM8993_DACR_TO_MIXOUTR_MASK 0x0001 /* DACR_TO_MIXOUTR */
1258#define WM8993_DACR_TO_MIXOUTR_SHIFT 0 /* DACR_TO_MIXOUTR */
1259#define WM8993_DACR_TO_MIXOUTR_WIDTH 1 /* DACR_TO_MIXOUTR */
1260
1261/*
1262 * R47 (0x2F) - Output Mixer3
1263 */
1264#define WM8993_IN2LP_MIXOUTL_VOL_MASK 0x0E00 /* IN2LP_MIXOUTL_VOL - [11:9] */
1265#define WM8993_IN2LP_MIXOUTL_VOL_SHIFT 9 /* IN2LP_MIXOUTL_VOL - [11:9] */
1266#define WM8993_IN2LP_MIXOUTL_VOL_WIDTH 3 /* IN2LP_MIXOUTL_VOL - [11:9] */
1267#define WM8993_IN2LN_MIXOUTL_VOL_MASK 0x01C0 /* IN2LN_MIXOUTL_VOL - [8:6] */
1268#define WM8993_IN2LN_MIXOUTL_VOL_SHIFT 6 /* IN2LN_MIXOUTL_VOL - [8:6] */
1269#define WM8993_IN2LN_MIXOUTL_VOL_WIDTH 3 /* IN2LN_MIXOUTL_VOL - [8:6] */
1270#define WM8993_IN1R_MIXOUTL_VOL_MASK 0x0038 /* IN1R_MIXOUTL_VOL - [5:3] */
1271#define WM8993_IN1R_MIXOUTL_VOL_SHIFT 3 /* IN1R_MIXOUTL_VOL - [5:3] */
1272#define WM8993_IN1R_MIXOUTL_VOL_WIDTH 3 /* IN1R_MIXOUTL_VOL - [5:3] */
1273#define WM8993_IN1L_MIXOUTL_VOL_MASK 0x0007 /* IN1L_MIXOUTL_VOL - [2:0] */
1274#define WM8993_IN1L_MIXOUTL_VOL_SHIFT 0 /* IN1L_MIXOUTL_VOL - [2:0] */
1275#define WM8993_IN1L_MIXOUTL_VOL_WIDTH 3 /* IN1L_MIXOUTL_VOL - [2:0] */
1276
1277/*
1278 * R48 (0x30) - Output Mixer4
1279 */
1280#define WM8993_IN2RP_MIXOUTR_VOL_MASK 0x0E00 /* IN2RP_MIXOUTR_VOL - [11:9] */
1281#define WM8993_IN2RP_MIXOUTR_VOL_SHIFT 9 /* IN2RP_MIXOUTR_VOL - [11:9] */
1282#define WM8993_IN2RP_MIXOUTR_VOL_WIDTH 3 /* IN2RP_MIXOUTR_VOL - [11:9] */
1283#define WM8993_IN2RN_MIXOUTR_VOL_MASK 0x01C0 /* IN2RN_MIXOUTR_VOL - [8:6] */
1284#define WM8993_IN2RN_MIXOUTR_VOL_SHIFT 6 /* IN2RN_MIXOUTR_VOL - [8:6] */
1285#define WM8993_IN2RN_MIXOUTR_VOL_WIDTH 3 /* IN2RN_MIXOUTR_VOL - [8:6] */
1286#define WM8993_IN1L_MIXOUTR_VOL_MASK 0x0038 /* IN1L_MIXOUTR_VOL - [5:3] */
1287#define WM8993_IN1L_MIXOUTR_VOL_SHIFT 3 /* IN1L_MIXOUTR_VOL - [5:3] */
1288#define WM8993_IN1L_MIXOUTR_VOL_WIDTH 3 /* IN1L_MIXOUTR_VOL - [5:3] */
1289#define WM8993_IN1R_MIXOUTR_VOL_MASK 0x0007 /* IN1R_MIXOUTR_VOL - [2:0] */
1290#define WM8993_IN1R_MIXOUTR_VOL_SHIFT 0 /* IN1R_MIXOUTR_VOL - [2:0] */
1291#define WM8993_IN1R_MIXOUTR_VOL_WIDTH 3 /* IN1R_MIXOUTR_VOL - [2:0] */
1292
1293/*
1294 * R49 (0x31) - Output Mixer5
1295 */
1296#define WM8993_DACL_MIXOUTL_VOL_MASK 0x0E00 /* DACL_MIXOUTL_VOL - [11:9] */
1297#define WM8993_DACL_MIXOUTL_VOL_SHIFT 9 /* DACL_MIXOUTL_VOL - [11:9] */
1298#define WM8993_DACL_MIXOUTL_VOL_WIDTH 3 /* DACL_MIXOUTL_VOL - [11:9] */
1299#define WM8993_IN2RN_MIXOUTL_VOL_MASK 0x01C0 /* IN2RN_MIXOUTL_VOL - [8:6] */
1300#define WM8993_IN2RN_MIXOUTL_VOL_SHIFT 6 /* IN2RN_MIXOUTL_VOL - [8:6] */
1301#define WM8993_IN2RN_MIXOUTL_VOL_WIDTH 3 /* IN2RN_MIXOUTL_VOL - [8:6] */
1302#define WM8993_MIXINR_MIXOUTL_VOL_MASK 0x0038 /* MIXINR_MIXOUTL_VOL - [5:3] */
1303#define WM8993_MIXINR_MIXOUTL_VOL_SHIFT 3 /* MIXINR_MIXOUTL_VOL - [5:3] */
1304#define WM8993_MIXINR_MIXOUTL_VOL_WIDTH 3 /* MIXINR_MIXOUTL_VOL - [5:3] */
1305#define WM8993_MIXINL_MIXOUTL_VOL_MASK 0x0007 /* MIXINL_MIXOUTL_VOL - [2:0] */
1306#define WM8993_MIXINL_MIXOUTL_VOL_SHIFT 0 /* MIXINL_MIXOUTL_VOL - [2:0] */
1307#define WM8993_MIXINL_MIXOUTL_VOL_WIDTH 3 /* MIXINL_MIXOUTL_VOL - [2:0] */
1308
1309/*
1310 * R50 (0x32) - Output Mixer6
1311 */
1312#define WM8993_DACR_MIXOUTR_VOL_MASK 0x0E00 /* DACR_MIXOUTR_VOL - [11:9] */
1313#define WM8993_DACR_MIXOUTR_VOL_SHIFT 9 /* DACR_MIXOUTR_VOL - [11:9] */
1314#define WM8993_DACR_MIXOUTR_VOL_WIDTH 3 /* DACR_MIXOUTR_VOL - [11:9] */
1315#define WM8993_IN2LN_MIXOUTR_VOL_MASK 0x01C0 /* IN2LN_MIXOUTR_VOL - [8:6] */
1316#define WM8993_IN2LN_MIXOUTR_VOL_SHIFT 6 /* IN2LN_MIXOUTR_VOL - [8:6] */
1317#define WM8993_IN2LN_MIXOUTR_VOL_WIDTH 3 /* IN2LN_MIXOUTR_VOL - [8:6] */
1318#define WM8993_MIXINL_MIXOUTR_VOL_MASK 0x0038 /* MIXINL_MIXOUTR_VOL - [5:3] */
1319#define WM8993_MIXINL_MIXOUTR_VOL_SHIFT 3 /* MIXINL_MIXOUTR_VOL - [5:3] */
1320#define WM8993_MIXINL_MIXOUTR_VOL_WIDTH 3 /* MIXINL_MIXOUTR_VOL - [5:3] */
1321#define WM8993_MIXINR_MIXOUTR_VOL_MASK 0x0007 /* MIXINR_MIXOUTR_VOL - [2:0] */
1322#define WM8993_MIXINR_MIXOUTR_VOL_SHIFT 0 /* MIXINR_MIXOUTR_VOL - [2:0] */
1323#define WM8993_MIXINR_MIXOUTR_VOL_WIDTH 3 /* MIXINR_MIXOUTR_VOL - [2:0] */
1324
1325/*
1326 * R51 (0x33) - HPOUT2 Mixer
1327 */
1328#define WM8993_VRX_TO_HPOUT2 0x0020 /* VRX_TO_HPOUT2 */
1329#define WM8993_VRX_TO_HPOUT2_MASK 0x0020 /* VRX_TO_HPOUT2 */
1330#define WM8993_VRX_TO_HPOUT2_SHIFT 5 /* VRX_TO_HPOUT2 */
1331#define WM8993_VRX_TO_HPOUT2_WIDTH 1 /* VRX_TO_HPOUT2 */
1332#define WM8993_MIXOUTLVOL_TO_HPOUT2 0x0010 /* MIXOUTLVOL_TO_HPOUT2 */
1333#define WM8993_MIXOUTLVOL_TO_HPOUT2_MASK 0x0010 /* MIXOUTLVOL_TO_HPOUT2 */
1334#define WM8993_MIXOUTLVOL_TO_HPOUT2_SHIFT 4 /* MIXOUTLVOL_TO_HPOUT2 */
1335#define WM8993_MIXOUTLVOL_TO_HPOUT2_WIDTH 1 /* MIXOUTLVOL_TO_HPOUT2 */
1336#define WM8993_MIXOUTRVOL_TO_HPOUT2 0x0008 /* MIXOUTRVOL_TO_HPOUT2 */
1337#define WM8993_MIXOUTRVOL_TO_HPOUT2_MASK 0x0008 /* MIXOUTRVOL_TO_HPOUT2 */
1338#define WM8993_MIXOUTRVOL_TO_HPOUT2_SHIFT 3 /* MIXOUTRVOL_TO_HPOUT2 */
1339#define WM8993_MIXOUTRVOL_TO_HPOUT2_WIDTH 1 /* MIXOUTRVOL_TO_HPOUT2 */
1340
1341/*
1342 * R52 (0x34) - Line Mixer1
1343 */
1344#define WM8993_MIXOUTL_TO_LINEOUT1N 0x0040 /* MIXOUTL_TO_LINEOUT1N */
1345#define WM8993_MIXOUTL_TO_LINEOUT1N_MASK 0x0040 /* MIXOUTL_TO_LINEOUT1N */
1346#define WM8993_MIXOUTL_TO_LINEOUT1N_SHIFT 6 /* MIXOUTL_TO_LINEOUT1N */
1347#define WM8993_MIXOUTL_TO_LINEOUT1N_WIDTH 1 /* MIXOUTL_TO_LINEOUT1N */
1348#define WM8993_MIXOUTR_TO_LINEOUT1N 0x0020 /* MIXOUTR_TO_LINEOUT1N */
1349#define WM8993_MIXOUTR_TO_LINEOUT1N_MASK 0x0020 /* MIXOUTR_TO_LINEOUT1N */
1350#define WM8993_MIXOUTR_TO_LINEOUT1N_SHIFT 5 /* MIXOUTR_TO_LINEOUT1N */
1351#define WM8993_MIXOUTR_TO_LINEOUT1N_WIDTH 1 /* MIXOUTR_TO_LINEOUT1N */
1352#define WM8993_LINEOUT1_MODE 0x0010 /* LINEOUT1_MODE */
1353#define WM8993_LINEOUT1_MODE_MASK 0x0010 /* LINEOUT1_MODE */
1354#define WM8993_LINEOUT1_MODE_SHIFT 4 /* LINEOUT1_MODE */
1355#define WM8993_LINEOUT1_MODE_WIDTH 1 /* LINEOUT1_MODE */
1356#define WM8993_IN1R_TO_LINEOUT1P 0x0004 /* IN1R_TO_LINEOUT1P */
1357#define WM8993_IN1R_TO_LINEOUT1P_MASK 0x0004 /* IN1R_TO_LINEOUT1P */
1358#define WM8993_IN1R_TO_LINEOUT1P_SHIFT 2 /* IN1R_TO_LINEOUT1P */
1359#define WM8993_IN1R_TO_LINEOUT1P_WIDTH 1 /* IN1R_TO_LINEOUT1P */
1360#define WM8993_IN1L_TO_LINEOUT1P 0x0002 /* IN1L_TO_LINEOUT1P */
1361#define WM8993_IN1L_TO_LINEOUT1P_MASK 0x0002 /* IN1L_TO_LINEOUT1P */
1362#define WM8993_IN1L_TO_LINEOUT1P_SHIFT 1 /* IN1L_TO_LINEOUT1P */
1363#define WM8993_IN1L_TO_LINEOUT1P_WIDTH 1 /* IN1L_TO_LINEOUT1P */
1364#define WM8993_MIXOUTL_TO_LINEOUT1P 0x0001 /* MIXOUTL_TO_LINEOUT1P */
1365#define WM8993_MIXOUTL_TO_LINEOUT1P_MASK 0x0001 /* MIXOUTL_TO_LINEOUT1P */
1366#define WM8993_MIXOUTL_TO_LINEOUT1P_SHIFT 0 /* MIXOUTL_TO_LINEOUT1P */
1367#define WM8993_MIXOUTL_TO_LINEOUT1P_WIDTH 1 /* MIXOUTL_TO_LINEOUT1P */
1368
1369/*
1370 * R53 (0x35) - Line Mixer2
1371 */
1372#define WM8993_MIXOUTR_TO_LINEOUT2N 0x0040 /* MIXOUTR_TO_LINEOUT2N */
1373#define WM8993_MIXOUTR_TO_LINEOUT2N_MASK 0x0040 /* MIXOUTR_TO_LINEOUT2N */
1374#define WM8993_MIXOUTR_TO_LINEOUT2N_SHIFT 6 /* MIXOUTR_TO_LINEOUT2N */
1375#define WM8993_MIXOUTR_TO_LINEOUT2N_WIDTH 1 /* MIXOUTR_TO_LINEOUT2N */
1376#define WM8993_MIXOUTL_TO_LINEOUT2N 0x0020 /* MIXOUTL_TO_LINEOUT2N */
1377#define WM8993_MIXOUTL_TO_LINEOUT2N_MASK 0x0020 /* MIXOUTL_TO_LINEOUT2N */
1378#define WM8993_MIXOUTL_TO_LINEOUT2N_SHIFT 5 /* MIXOUTL_TO_LINEOUT2N */
1379#define WM8993_MIXOUTL_TO_LINEOUT2N_WIDTH 1 /* MIXOUTL_TO_LINEOUT2N */
1380#define WM8993_LINEOUT2_MODE 0x0010 /* LINEOUT2_MODE */
1381#define WM8993_LINEOUT2_MODE_MASK 0x0010 /* LINEOUT2_MODE */
1382#define WM8993_LINEOUT2_MODE_SHIFT 4 /* LINEOUT2_MODE */
1383#define WM8993_LINEOUT2_MODE_WIDTH 1 /* LINEOUT2_MODE */
1384#define WM8993_IN1L_TO_LINEOUT2P 0x0004 /* IN1L_TO_LINEOUT2P */
1385#define WM8993_IN1L_TO_LINEOUT2P_MASK 0x0004 /* IN1L_TO_LINEOUT2P */
1386#define WM8993_IN1L_TO_LINEOUT2P_SHIFT 2 /* IN1L_TO_LINEOUT2P */
1387#define WM8993_IN1L_TO_LINEOUT2P_WIDTH 1 /* IN1L_TO_LINEOUT2P */
1388#define WM8993_IN1R_TO_LINEOUT2P 0x0002 /* IN1R_TO_LINEOUT2P */
1389#define WM8993_IN1R_TO_LINEOUT2P_MASK 0x0002 /* IN1R_TO_LINEOUT2P */
1390#define WM8993_IN1R_TO_LINEOUT2P_SHIFT 1 /* IN1R_TO_LINEOUT2P */
1391#define WM8993_IN1R_TO_LINEOUT2P_WIDTH 1 /* IN1R_TO_LINEOUT2P */
1392#define WM8993_MIXOUTR_TO_LINEOUT2P 0x0001 /* MIXOUTR_TO_LINEOUT2P */
1393#define WM8993_MIXOUTR_TO_LINEOUT2P_MASK 0x0001 /* MIXOUTR_TO_LINEOUT2P */
1394#define WM8993_MIXOUTR_TO_LINEOUT2P_SHIFT 0 /* MIXOUTR_TO_LINEOUT2P */
1395#define WM8993_MIXOUTR_TO_LINEOUT2P_WIDTH 1 /* MIXOUTR_TO_LINEOUT2P */
1396
1397/*
1398 * R54 (0x36) - Speaker Mixer
1399 */
1400#define WM8993_SPKAB_REF_SEL 0x0100 /* SPKAB_REF_SEL */
1401#define WM8993_SPKAB_REF_SEL_MASK 0x0100 /* SPKAB_REF_SEL */
1402#define WM8993_SPKAB_REF_SEL_SHIFT 8 /* SPKAB_REF_SEL */
1403#define WM8993_SPKAB_REF_SEL_WIDTH 1 /* SPKAB_REF_SEL */
1404#define WM8993_MIXINL_TO_SPKMIXL 0x0080 /* MIXINL_TO_SPKMIXL */
1405#define WM8993_MIXINL_TO_SPKMIXL_MASK 0x0080 /* MIXINL_TO_SPKMIXL */
1406#define WM8993_MIXINL_TO_SPKMIXL_SHIFT 7 /* MIXINL_TO_SPKMIXL */
1407#define WM8993_MIXINL_TO_SPKMIXL_WIDTH 1 /* MIXINL_TO_SPKMIXL */
1408#define WM8993_MIXINR_TO_SPKMIXR 0x0040 /* MIXINR_TO_SPKMIXR */
1409#define WM8993_MIXINR_TO_SPKMIXR_MASK 0x0040 /* MIXINR_TO_SPKMIXR */
1410#define WM8993_MIXINR_TO_SPKMIXR_SHIFT 6 /* MIXINR_TO_SPKMIXR */
1411#define WM8993_MIXINR_TO_SPKMIXR_WIDTH 1 /* MIXINR_TO_SPKMIXR */
1412#define WM8993_IN1LP_TO_SPKMIXL 0x0020 /* IN1LP_TO_SPKMIXL */
1413#define WM8993_IN1LP_TO_SPKMIXL_MASK 0x0020 /* IN1LP_TO_SPKMIXL */
1414#define WM8993_IN1LP_TO_SPKMIXL_SHIFT 5 /* IN1LP_TO_SPKMIXL */
1415#define WM8993_IN1LP_TO_SPKMIXL_WIDTH 1 /* IN1LP_TO_SPKMIXL */
1416#define WM8993_IN1RP_TO_SPKMIXR 0x0010 /* IN1RP_TO_SPKMIXR */
1417#define WM8993_IN1RP_TO_SPKMIXR_MASK 0x0010 /* IN1RP_TO_SPKMIXR */
1418#define WM8993_IN1RP_TO_SPKMIXR_SHIFT 4 /* IN1RP_TO_SPKMIXR */
1419#define WM8993_IN1RP_TO_SPKMIXR_WIDTH 1 /* IN1RP_TO_SPKMIXR */
1420#define WM8993_MIXOUTL_TO_SPKMIXL 0x0008 /* MIXOUTL_TO_SPKMIXL */
1421#define WM8993_MIXOUTL_TO_SPKMIXL_MASK 0x0008 /* MIXOUTL_TO_SPKMIXL */
1422#define WM8993_MIXOUTL_TO_SPKMIXL_SHIFT 3 /* MIXOUTL_TO_SPKMIXL */
1423#define WM8993_MIXOUTL_TO_SPKMIXL_WIDTH 1 /* MIXOUTL_TO_SPKMIXL */
1424#define WM8993_MIXOUTR_TO_SPKMIXR 0x0004 /* MIXOUTR_TO_SPKMIXR */
1425#define WM8993_MIXOUTR_TO_SPKMIXR_MASK 0x0004 /* MIXOUTR_TO_SPKMIXR */
1426#define WM8993_MIXOUTR_TO_SPKMIXR_SHIFT 2 /* MIXOUTR_TO_SPKMIXR */
1427#define WM8993_MIXOUTR_TO_SPKMIXR_WIDTH 1 /* MIXOUTR_TO_SPKMIXR */
1428#define WM8993_DACL_TO_SPKMIXL 0x0002 /* DACL_TO_SPKMIXL */
1429#define WM8993_DACL_TO_SPKMIXL_MASK 0x0002 /* DACL_TO_SPKMIXL */
1430#define WM8993_DACL_TO_SPKMIXL_SHIFT 1 /* DACL_TO_SPKMIXL */
1431#define WM8993_DACL_TO_SPKMIXL_WIDTH 1 /* DACL_TO_SPKMIXL */
1432#define WM8993_DACR_TO_SPKMIXR 0x0001 /* DACR_TO_SPKMIXR */
1433#define WM8993_DACR_TO_SPKMIXR_MASK 0x0001 /* DACR_TO_SPKMIXR */
1434#define WM8993_DACR_TO_SPKMIXR_SHIFT 0 /* DACR_TO_SPKMIXR */
1435#define WM8993_DACR_TO_SPKMIXR_WIDTH 1 /* DACR_TO_SPKMIXR */
1436
1437/*
1438 * R55 (0x37) - Additional Control
1439 */
1440#define WM8993_LINEOUT1_FB 0x0080 /* LINEOUT1_FB */
1441#define WM8993_LINEOUT1_FB_MASK 0x0080 /* LINEOUT1_FB */
1442#define WM8993_LINEOUT1_FB_SHIFT 7 /* LINEOUT1_FB */
1443#define WM8993_LINEOUT1_FB_WIDTH 1 /* LINEOUT1_FB */
1444#define WM8993_LINEOUT2_FB 0x0040 /* LINEOUT2_FB */
1445#define WM8993_LINEOUT2_FB_MASK 0x0040 /* LINEOUT2_FB */
1446#define WM8993_LINEOUT2_FB_SHIFT 6 /* LINEOUT2_FB */
1447#define WM8993_LINEOUT2_FB_WIDTH 1 /* LINEOUT2_FB */
1448#define WM8993_VROI 0x0001 /* VROI */
1449#define WM8993_VROI_MASK 0x0001 /* VROI */
1450#define WM8993_VROI_SHIFT 0 /* VROI */
1451#define WM8993_VROI_WIDTH 1 /* VROI */
1452
1453/*
1454 * R56 (0x38) - AntiPOP1
1455 */
1456#define WM8993_LINEOUT_VMID_BUF_ENA 0x0080 /* LINEOUT_VMID_BUF_ENA */
1457#define WM8993_LINEOUT_VMID_BUF_ENA_MASK 0x0080 /* LINEOUT_VMID_BUF_ENA */
1458#define WM8993_LINEOUT_VMID_BUF_ENA_SHIFT 7 /* LINEOUT_VMID_BUF_ENA */
1459#define WM8993_LINEOUT_VMID_BUF_ENA_WIDTH 1 /* LINEOUT_VMID_BUF_ENA */
1460#define WM8993_HPOUT2_IN_ENA 0x0040 /* HPOUT2_IN_ENA */
1461#define WM8993_HPOUT2_IN_ENA_MASK 0x0040 /* HPOUT2_IN_ENA */
1462#define WM8993_HPOUT2_IN_ENA_SHIFT 6 /* HPOUT2_IN_ENA */
1463#define WM8993_HPOUT2_IN_ENA_WIDTH 1 /* HPOUT2_IN_ENA */
1464#define WM8993_LINEOUT1_DISCH 0x0020 /* LINEOUT1_DISCH */
1465#define WM8993_LINEOUT1_DISCH_MASK 0x0020 /* LINEOUT1_DISCH */
1466#define WM8993_LINEOUT1_DISCH_SHIFT 5 /* LINEOUT1_DISCH */
1467#define WM8993_LINEOUT1_DISCH_WIDTH 1 /* LINEOUT1_DISCH */
1468#define WM8993_LINEOUT2_DISCH 0x0010 /* LINEOUT2_DISCH */
1469#define WM8993_LINEOUT2_DISCH_MASK 0x0010 /* LINEOUT2_DISCH */
1470#define WM8993_LINEOUT2_DISCH_SHIFT 4 /* LINEOUT2_DISCH */
1471#define WM8993_LINEOUT2_DISCH_WIDTH 1 /* LINEOUT2_DISCH */
1472
1473/*
1474 * R57 (0x39) - AntiPOP2
1475 */
1476#define WM8993_VMID_RAMP_MASK 0x0060 /* VMID_RAMP - [6:5] */
1477#define WM8993_VMID_RAMP_SHIFT 5 /* VMID_RAMP - [6:5] */
1478#define WM8993_VMID_RAMP_WIDTH 2 /* VMID_RAMP - [6:5] */
1479#define WM8993_VMID_BUF_ENA 0x0008 /* VMID_BUF_ENA */
1480#define WM8993_VMID_BUF_ENA_MASK 0x0008 /* VMID_BUF_ENA */
1481#define WM8993_VMID_BUF_ENA_SHIFT 3 /* VMID_BUF_ENA */
1482#define WM8993_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */
1483#define WM8993_STARTUP_BIAS_ENA 0x0004 /* STARTUP_BIAS_ENA */
1484#define WM8993_STARTUP_BIAS_ENA_MASK 0x0004 /* STARTUP_BIAS_ENA */
1485#define WM8993_STARTUP_BIAS_ENA_SHIFT 2 /* STARTUP_BIAS_ENA */
1486#define WM8993_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */
1487#define WM8993_BIAS_SRC 0x0002 /* BIAS_SRC */
1488#define WM8993_BIAS_SRC_MASK 0x0002 /* BIAS_SRC */
1489#define WM8993_BIAS_SRC_SHIFT 1 /* BIAS_SRC */
1490#define WM8993_BIAS_SRC_WIDTH 1 /* BIAS_SRC */
1491#define WM8993_VMID_DISCH 0x0001 /* VMID_DISCH */
1492#define WM8993_VMID_DISCH_MASK 0x0001 /* VMID_DISCH */
1493#define WM8993_VMID_DISCH_SHIFT 0 /* VMID_DISCH */
1494#define WM8993_VMID_DISCH_WIDTH 1 /* VMID_DISCH */
1495
1496/*
1497 * R58 (0x3A) - MICBIAS
1498 */
1499#define WM8993_JD_SCTHR_MASK 0x00C0 /* JD_SCTHR - [7:6] */
1500#define WM8993_JD_SCTHR_SHIFT 6 /* JD_SCTHR - [7:6] */
1501#define WM8993_JD_SCTHR_WIDTH 2 /* JD_SCTHR - [7:6] */
1502#define WM8993_JD_THR_MASK 0x0030 /* JD_THR - [5:4] */
1503#define WM8993_JD_THR_SHIFT 4 /* JD_THR - [5:4] */
1504#define WM8993_JD_THR_WIDTH 2 /* JD_THR - [5:4] */
1505#define WM8993_JD_ENA 0x0004 /* JD_ENA */
1506#define WM8993_JD_ENA_MASK 0x0004 /* JD_ENA */
1507#define WM8993_JD_ENA_SHIFT 2 /* JD_ENA */
1508#define WM8993_JD_ENA_WIDTH 1 /* JD_ENA */
1509#define WM8993_MICB2_LVL 0x0002 /* MICB2_LVL */
1510#define WM8993_MICB2_LVL_MASK 0x0002 /* MICB2_LVL */
1511#define WM8993_MICB2_LVL_SHIFT 1 /* MICB2_LVL */
1512#define WM8993_MICB2_LVL_WIDTH 1 /* MICB2_LVL */
1513#define WM8993_MICB1_LVL 0x0001 /* MICB1_LVL */
1514#define WM8993_MICB1_LVL_MASK 0x0001 /* MICB1_LVL */
1515#define WM8993_MICB1_LVL_SHIFT 0 /* MICB1_LVL */
1516#define WM8993_MICB1_LVL_WIDTH 1 /* MICB1_LVL */
1517
1518/*
1519 * R60 (0x3C) - FLL Control 1
1520 */
1521#define WM8993_FLL_FRAC 0x0004 /* FLL_FRAC */
1522#define WM8993_FLL_FRAC_MASK 0x0004 /* FLL_FRAC */
1523#define WM8993_FLL_FRAC_SHIFT 2 /* FLL_FRAC */
1524#define WM8993_FLL_FRAC_WIDTH 1 /* FLL_FRAC */
1525#define WM8993_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */
1526#define WM8993_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */
1527#define WM8993_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */
1528#define WM8993_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */
1529#define WM8993_FLL_ENA 0x0001 /* FLL_ENA */
1530#define WM8993_FLL_ENA_MASK 0x0001 /* FLL_ENA */
1531#define WM8993_FLL_ENA_SHIFT 0 /* FLL_ENA */
1532#define WM8993_FLL_ENA_WIDTH 1 /* FLL_ENA */
1533
1534/*
1535 * R61 (0x3D) - FLL Control 2
1536 */
1537#define WM8993_FLL_OUTDIV_MASK 0x0700 /* FLL_OUTDIV - [10:8] */
1538#define WM8993_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [10:8] */
1539#define WM8993_FLL_OUTDIV_WIDTH 3 /* FLL_OUTDIV - [10:8] */
1540#define WM8993_FLL_CTRL_RATE_MASK 0x0070 /* FLL_CTRL_RATE - [6:4] */
1541#define WM8993_FLL_CTRL_RATE_SHIFT 4 /* FLL_CTRL_RATE - [6:4] */
1542#define WM8993_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [6:4] */
1543#define WM8993_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */
1544#define WM8993_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */
1545#define WM8993_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */
1546
1547/*
1548 * R62 (0x3E) - FLL Control 3
1549 */
1550#define WM8993_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */
1551#define WM8993_FLL_K_SHIFT 0 /* FLL_K - [15:0] */
1552#define WM8993_FLL_K_WIDTH 16 /* FLL_K - [15:0] */
1553
1554/*
1555 * R63 (0x3F) - FLL Control 4
1556 */
1557#define WM8993_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */
1558#define WM8993_FLL_N_SHIFT 5 /* FLL_N - [14:5] */
1559#define WM8993_FLL_N_WIDTH 10 /* FLL_N - [14:5] */
1560#define WM8993_FLL_GAIN_MASK 0x000F /* FLL_GAIN - [3:0] */
1561#define WM8993_FLL_GAIN_SHIFT 0 /* FLL_GAIN - [3:0] */
1562#define WM8993_FLL_GAIN_WIDTH 4 /* FLL_GAIN - [3:0] */
1563
1564/*
1565 * R64 (0x40) - FLL Control 5
1566 */
1567#define WM8993_FLL_FRC_NCO_VAL_MASK 0x1F80 /* FLL_FRC_NCO_VAL - [12:7] */
1568#define WM8993_FLL_FRC_NCO_VAL_SHIFT 7 /* FLL_FRC_NCO_VAL - [12:7] */
1569#define WM8993_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [12:7] */
1570#define WM8993_FLL_FRC_NCO 0x0040 /* FLL_FRC_NCO */
1571#define WM8993_FLL_FRC_NCO_MASK 0x0040 /* FLL_FRC_NCO */
1572#define WM8993_FLL_FRC_NCO_SHIFT 6 /* FLL_FRC_NCO */
1573#define WM8993_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */
1574#define WM8993_FLL_CLK_REF_DIV_MASK 0x0018 /* FLL_CLK_REF_DIV - [4:3] */
1575#define WM8993_FLL_CLK_REF_DIV_SHIFT 3 /* FLL_CLK_REF_DIV - [4:3] */
1576#define WM8993_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [4:3] */
1577#define WM8993_FLL_CLK_SRC_MASK 0x0003 /* FLL_CLK_SRC - [1:0] */
1578#define WM8993_FLL_CLK_SRC_SHIFT 0 /* FLL_CLK_SRC - [1:0] */
1579#define WM8993_FLL_CLK_SRC_WIDTH 2 /* FLL_CLK_SRC - [1:0] */
1580
1581/*
1582 * R65 (0x41) - Clocking 3
1583 */
1584#define WM8993_CLK_DCS_DIV_MASK 0x3C00 /* CLK_DCS_DIV - [13:10] */
1585#define WM8993_CLK_DCS_DIV_SHIFT 10 /* CLK_DCS_DIV - [13:10] */
1586#define WM8993_CLK_DCS_DIV_WIDTH 4 /* CLK_DCS_DIV - [13:10] */
1587#define WM8993_SAMPLE_RATE_MASK 0x0380 /* SAMPLE_RATE - [9:7] */
1588#define WM8993_SAMPLE_RATE_SHIFT 7 /* SAMPLE_RATE - [9:7] */
1589#define WM8993_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [9:7] */
1590#define WM8993_CLK_SYS_RATE_MASK 0x001E /* CLK_SYS_RATE - [4:1] */
1591#define WM8993_CLK_SYS_RATE_SHIFT 1 /* CLK_SYS_RATE - [4:1] */
1592#define WM8993_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [4:1] */
1593#define WM8993_CLK_DSP_ENA 0x0001 /* CLK_DSP_ENA */
1594#define WM8993_CLK_DSP_ENA_MASK 0x0001 /* CLK_DSP_ENA */
1595#define WM8993_CLK_DSP_ENA_SHIFT 0 /* CLK_DSP_ENA */
1596#define WM8993_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */
1597
1598/*
1599 * R66 (0x42) - Clocking 4
1600 */
1601#define WM8993_DAC_DIV4 0x0200 /* DAC_DIV4 */
1602#define WM8993_DAC_DIV4_MASK 0x0200 /* DAC_DIV4 */
1603#define WM8993_DAC_DIV4_SHIFT 9 /* DAC_DIV4 */
1604#define WM8993_DAC_DIV4_WIDTH 1 /* DAC_DIV4 */
1605#define WM8993_CLK_256K_DIV_MASK 0x007E /* CLK_256K_DIV - [6:1] */
1606#define WM8993_CLK_256K_DIV_SHIFT 1 /* CLK_256K_DIV - [6:1] */
1607#define WM8993_CLK_256K_DIV_WIDTH 6 /* CLK_256K_DIV - [6:1] */
1608#define WM8993_SR_MODE 0x0001 /* SR_MODE */
1609#define WM8993_SR_MODE_MASK 0x0001 /* SR_MODE */
1610#define WM8993_SR_MODE_SHIFT 0 /* SR_MODE */
1611#define WM8993_SR_MODE_WIDTH 1 /* SR_MODE */
1612
1613/*
1614 * R67 (0x43) - MW Slave Control
1615 */
1616#define WM8993_MASK_WRITE_ENA 0x0001 /* MASK_WRITE_ENA */
1617#define WM8993_MASK_WRITE_ENA_MASK 0x0001 /* MASK_WRITE_ENA */
1618#define WM8993_MASK_WRITE_ENA_SHIFT 0 /* MASK_WRITE_ENA */
1619#define WM8993_MASK_WRITE_ENA_WIDTH 1 /* MASK_WRITE_ENA */
1620
1621/*
1622 * R69 (0x45) - Bus Control 1
1623 */
1624#define WM8993_CLK_SYS_ENA 0x0002 /* CLK_SYS_ENA */
1625#define WM8993_CLK_SYS_ENA_MASK 0x0002 /* CLK_SYS_ENA */
1626#define WM8993_CLK_SYS_ENA_SHIFT 1 /* CLK_SYS_ENA */
1627#define WM8993_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */
1628
1629/*
1630 * R70 (0x46) - Write Sequencer 0
1631 */
1632#define WM8993_WSEQ_ENA 0x0100 /* WSEQ_ENA */
1633#define WM8993_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */
1634#define WM8993_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */
1635#define WM8993_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */
1636#define WM8993_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */
1637#define WM8993_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */
1638#define WM8993_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */
1639
1640/*
1641 * R71 (0x47) - Write Sequencer 1
1642 */
1643#define WM8993_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */
1644#define WM8993_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */
1645#define WM8993_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */
1646#define WM8993_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */
1647#define WM8993_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */
1648#define WM8993_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */
1649#define WM8993_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */
1650#define WM8993_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */
1651#define WM8993_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */
1652
1653/*
1654 * R72 (0x48) - Write Sequencer 2
1655 */
1656#define WM8993_WSEQ_EOS 0x4000 /* WSEQ_EOS */
1657#define WM8993_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */
1658#define WM8993_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */
1659#define WM8993_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */
1660#define WM8993_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */
1661#define WM8993_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */
1662#define WM8993_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */
1663#define WM8993_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */
1664#define WM8993_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */
1665#define WM8993_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */
1666
1667/*
1668 * R73 (0x49) - Write Sequencer 3
1669 */
1670#define WM8993_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */
1671#define WM8993_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */
1672#define WM8993_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */
1673#define WM8993_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */
1674#define WM8993_WSEQ_START 0x0100 /* WSEQ_START */
1675#define WM8993_WSEQ_START_MASK 0x0100 /* WSEQ_START */
1676#define WM8993_WSEQ_START_SHIFT 8 /* WSEQ_START */
1677#define WM8993_WSEQ_START_WIDTH 1 /* WSEQ_START */
1678#define WM8993_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */
1679#define WM8993_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */
1680#define WM8993_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */
1681
1682/*
1683 * R74 (0x4A) - Write Sequencer 4
1684 */
1685#define WM8993_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */
1686#define WM8993_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */
1687#define WM8993_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */
1688#define WM8993_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */
1689
1690/*
1691 * R75 (0x4B) - Write Sequencer 5
1692 */
1693#define WM8993_WSEQ_CURRENT_INDEX_MASK 0x003F /* WSEQ_CURRENT_INDEX - [5:0] */
1694#define WM8993_WSEQ_CURRENT_INDEX_SHIFT 0 /* WSEQ_CURRENT_INDEX - [5:0] */
1695#define WM8993_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [5:0] */
1696
1697/*
1698 * R76 (0x4C) - Charge Pump 1
1699 */
1700#define WM8993_CP_ENA 0x8000 /* CP_ENA */
1701#define WM8993_CP_ENA_MASK 0x8000 /* CP_ENA */
1702#define WM8993_CP_ENA_SHIFT 15 /* CP_ENA */
1703#define WM8993_CP_ENA_WIDTH 1 /* CP_ENA */
1704
1705/*
1706 * R81 (0x51) - Class W 0
1707 */
1708#define WM8993_CP_DYN_FREQ 0x0002 /* CP_DYN_FREQ */
1709#define WM8993_CP_DYN_FREQ_MASK 0x0002 /* CP_DYN_FREQ */
1710#define WM8993_CP_DYN_FREQ_SHIFT 1 /* CP_DYN_FREQ */
1711#define WM8993_CP_DYN_FREQ_WIDTH 1 /* CP_DYN_FREQ */
1712#define WM8993_CP_DYN_V 0x0001 /* CP_DYN_V */
1713#define WM8993_CP_DYN_V_MASK 0x0001 /* CP_DYN_V */
1714#define WM8993_CP_DYN_V_SHIFT 0 /* CP_DYN_V */
1715#define WM8993_CP_DYN_V_WIDTH 1 /* CP_DYN_V */
1716
1717/*
1718 * R84 (0x54) - DC Servo 0
1719 */
1720#define WM8993_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */
1721#define WM8993_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */
1722#define WM8993_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */
1723#define WM8993_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */
1724#define WM8993_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */
1725#define WM8993_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */
1726#define WM8993_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */
1727#define WM8993_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */
1728#define WM8993_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */
1729#define WM8993_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */
1730#define WM8993_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */
1731#define WM8993_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */
1732#define WM8993_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */
1733#define WM8993_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */
1734#define WM8993_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */
1735#define WM8993_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */
1736#define WM8993_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */
1737#define WM8993_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */
1738#define WM8993_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */
1739#define WM8993_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */
1740#define WM8993_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */
1741#define WM8993_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */
1742#define WM8993_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */
1743#define WM8993_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */
1744#define WM8993_DCS_TRIG_DAC_WR_1 0x0008 /* DCS_TRIG_DAC_WR_1 */
1745#define WM8993_DCS_TRIG_DAC_WR_1_MASK 0x0008 /* DCS_TRIG_DAC_WR_1 */
1746#define WM8993_DCS_TRIG_DAC_WR_1_SHIFT 3 /* DCS_TRIG_DAC_WR_1 */
1747#define WM8993_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */
1748#define WM8993_DCS_TRIG_DAC_WR_0 0x0004 /* DCS_TRIG_DAC_WR_0 */
1749#define WM8993_DCS_TRIG_DAC_WR_0_MASK 0x0004 /* DCS_TRIG_DAC_WR_0 */
1750#define WM8993_DCS_TRIG_DAC_WR_0_SHIFT 2 /* DCS_TRIG_DAC_WR_0 */
1751#define WM8993_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */
1752#define WM8993_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */
1753#define WM8993_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */
1754#define WM8993_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */
1755#define WM8993_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */
1756#define WM8993_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */
1757#define WM8993_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */
1758#define WM8993_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */
1759#define WM8993_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */
1760
1761/*
1762 * R85 (0x55) - DC Servo 1
1763 */
1764#define WM8993_DCS_SERIES_NO_01_MASK 0x0FE0 /* DCS_SERIES_NO_01 - [11:5] */
1765#define WM8993_DCS_SERIES_NO_01_SHIFT 5 /* DCS_SERIES_NO_01 - [11:5] */
1766#define WM8993_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [11:5] */
1767#define WM8993_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */
1768#define WM8993_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */
1769#define WM8993_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */
1770
1771/*
1772 * R87 (0x57) - DC Servo 3
1773 */
1774#define WM8993_DCS_DAC_WR_VAL_1_MASK 0xFF00 /* DCS_DAC_WR_VAL_1 - [15:8] */
1775#define WM8993_DCS_DAC_WR_VAL_1_SHIFT 8 /* DCS_DAC_WR_VAL_1 - [15:8] */
1776#define WM8993_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [15:8] */
1777#define WM8993_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */
1778#define WM8993_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */
1779#define WM8993_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */
1780
1781/*
1782 * R88 (0x58) - DC Servo Readback 0
1783 */
1784#define WM8993_DCS_DATAPATH_BUSY 0x4000 /* DCS_DATAPATH_BUSY */
1785#define WM8993_DCS_DATAPATH_BUSY_MASK 0x4000 /* DCS_DATAPATH_BUSY */
1786#define WM8993_DCS_DATAPATH_BUSY_SHIFT 14 /* DCS_DATAPATH_BUSY */
1787#define WM8993_DCS_DATAPATH_BUSY_WIDTH 1 /* DCS_DATAPATH_BUSY */
1788#define WM8993_DCS_CHANNEL_MASK 0x3000 /* DCS_CHANNEL - [13:12] */
1789#define WM8993_DCS_CHANNEL_SHIFT 12 /* DCS_CHANNEL - [13:12] */
1790#define WM8993_DCS_CHANNEL_WIDTH 2 /* DCS_CHANNEL - [13:12] */
1791#define WM8993_DCS_CAL_COMPLETE_MASK 0x0300 /* DCS_CAL_COMPLETE - [9:8] */
1792#define WM8993_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [9:8] */
1793#define WM8993_DCS_CAL_COMPLETE_WIDTH 2 /* DCS_CAL_COMPLETE - [9:8] */
1794#define WM8993_DCS_DAC_WR_COMPLETE_MASK 0x0030 /* DCS_DAC_WR_COMPLETE - [5:4] */
1795#define WM8993_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [5:4] */
1796#define WM8993_DCS_DAC_WR_COMPLETE_WIDTH 2 /* DCS_DAC_WR_COMPLETE - [5:4] */
1797#define WM8993_DCS_STARTUP_COMPLETE_MASK 0x0003 /* DCS_STARTUP_COMPLETE - [1:0] */
1798#define WM8993_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [1:0] */
1799#define WM8993_DCS_STARTUP_COMPLETE_WIDTH 2 /* DCS_STARTUP_COMPLETE - [1:0] */
1800
1801/*
1802 * R89 (0x59) - DC Servo Readback 1
1803 */
1804#define WM8993_DCS_INTEG_CHAN_1_MASK 0x00FF /* DCS_INTEG_CHAN_1 - [7:0] */
1805#define WM8993_DCS_INTEG_CHAN_1_SHIFT 0 /* DCS_INTEG_CHAN_1 - [7:0] */
1806#define WM8993_DCS_INTEG_CHAN_1_WIDTH 8 /* DCS_INTEG_CHAN_1 - [7:0] */
1807
1808/*
1809 * R90 (0x5A) - DC Servo Readback 2
1810 */
1811#define WM8993_DCS_INTEG_CHAN_0_MASK 0x00FF /* DCS_INTEG_CHAN_0 - [7:0] */
1812#define WM8993_DCS_INTEG_CHAN_0_SHIFT 0 /* DCS_INTEG_CHAN_0 - [7:0] */
1813#define WM8993_DCS_INTEG_CHAN_0_WIDTH 8 /* DCS_INTEG_CHAN_0 - [7:0] */
1814
1815/*
1816 * R96 (0x60) - Analogue HP 0
1817 */
1818#define WM8993_HPOUT1_AUTO_PU 0x0100 /* HPOUT1_AUTO_PU */
1819#define WM8993_HPOUT1_AUTO_PU_MASK 0x0100 /* HPOUT1_AUTO_PU */
1820#define WM8993_HPOUT1_AUTO_PU_SHIFT 8 /* HPOUT1_AUTO_PU */
1821#define WM8993_HPOUT1_AUTO_PU_WIDTH 1 /* HPOUT1_AUTO_PU */
1822#define WM8993_HPOUT1L_RMV_SHORT 0x0080 /* HPOUT1L_RMV_SHORT */
1823#define WM8993_HPOUT1L_RMV_SHORT_MASK 0x0080 /* HPOUT1L_RMV_SHORT */
1824#define WM8993_HPOUT1L_RMV_SHORT_SHIFT 7 /* HPOUT1L_RMV_SHORT */
1825#define WM8993_HPOUT1L_RMV_SHORT_WIDTH 1 /* HPOUT1L_RMV_SHORT */
1826#define WM8993_HPOUT1L_OUTP 0x0040 /* HPOUT1L_OUTP */
1827#define WM8993_HPOUT1L_OUTP_MASK 0x0040 /* HPOUT1L_OUTP */
1828#define WM8993_HPOUT1L_OUTP_SHIFT 6 /* HPOUT1L_OUTP */
1829#define WM8993_HPOUT1L_OUTP_WIDTH 1 /* HPOUT1L_OUTP */
1830#define WM8993_HPOUT1L_DLY 0x0020 /* HPOUT1L_DLY */
1831#define WM8993_HPOUT1L_DLY_MASK 0x0020 /* HPOUT1L_DLY */
1832#define WM8993_HPOUT1L_DLY_SHIFT 5 /* HPOUT1L_DLY */
1833#define WM8993_HPOUT1L_DLY_WIDTH 1 /* HPOUT1L_DLY */
1834#define WM8993_HPOUT1R_RMV_SHORT 0x0008 /* HPOUT1R_RMV_SHORT */
1835#define WM8993_HPOUT1R_RMV_SHORT_MASK 0x0008 /* HPOUT1R_RMV_SHORT */
1836#define WM8993_HPOUT1R_RMV_SHORT_SHIFT 3 /* HPOUT1R_RMV_SHORT */
1837#define WM8993_HPOUT1R_RMV_SHORT_WIDTH 1 /* HPOUT1R_RMV_SHORT */
1838#define WM8993_HPOUT1R_OUTP 0x0004 /* HPOUT1R_OUTP */
1839#define WM8993_HPOUT1R_OUTP_MASK 0x0004 /* HPOUT1R_OUTP */
1840#define WM8993_HPOUT1R_OUTP_SHIFT 2 /* HPOUT1R_OUTP */
1841#define WM8993_HPOUT1R_OUTP_WIDTH 1 /* HPOUT1R_OUTP */
1842#define WM8993_HPOUT1R_DLY 0x0002 /* HPOUT1R_DLY */
1843#define WM8993_HPOUT1R_DLY_MASK 0x0002 /* HPOUT1R_DLY */
1844#define WM8993_HPOUT1R_DLY_SHIFT 1 /* HPOUT1R_DLY */
1845#define WM8993_HPOUT1R_DLY_WIDTH 1 /* HPOUT1R_DLY */
1846
1847/*
1848 * R98 (0x62) - EQ1
1849 */
1850#define WM8993_EQ_ENA 0x0001 /* EQ_ENA */
1851#define WM8993_EQ_ENA_MASK 0x0001 /* EQ_ENA */
1852#define WM8993_EQ_ENA_SHIFT 0 /* EQ_ENA */
1853#define WM8993_EQ_ENA_WIDTH 1 /* EQ_ENA */
1854
1855/*
1856 * R99 (0x63) - EQ2
1857 */
1858#define WM8993_EQ_B1_GAIN_MASK 0x001F /* EQ_B1_GAIN - [4:0] */
1859#define WM8993_EQ_B1_GAIN_SHIFT 0 /* EQ_B1_GAIN - [4:0] */
1860#define WM8993_EQ_B1_GAIN_WIDTH 5 /* EQ_B1_GAIN - [4:0] */
1861
1862/*
1863 * R100 (0x64) - EQ3
1864 */
1865#define WM8993_EQ_B2_GAIN_MASK 0x001F /* EQ_B2_GAIN - [4:0] */
1866#define WM8993_EQ_B2_GAIN_SHIFT 0 /* EQ_B2_GAIN - [4:0] */
1867#define WM8993_EQ_B2_GAIN_WIDTH 5 /* EQ_B2_GAIN - [4:0] */
1868
1869/*
1870 * R101 (0x65) - EQ4
1871 */
1872#define WM8993_EQ_B3_GAIN_MASK 0x001F /* EQ_B3_GAIN - [4:0] */
1873#define WM8993_EQ_B3_GAIN_SHIFT 0 /* EQ_B3_GAIN - [4:0] */
1874#define WM8993_EQ_B3_GAIN_WIDTH 5 /* EQ_B3_GAIN - [4:0] */
1875
1876/*
1877 * R102 (0x66) - EQ5
1878 */
1879#define WM8993_EQ_B4_GAIN_MASK 0x001F /* EQ_B4_GAIN - [4:0] */
1880#define WM8993_EQ_B4_GAIN_SHIFT 0 /* EQ_B4_GAIN - [4:0] */
1881#define WM8993_EQ_B4_GAIN_WIDTH 5 /* EQ_B4_GAIN - [4:0] */
1882
1883/*
1884 * R103 (0x67) - EQ6
1885 */
1886#define WM8993_EQ_B5_GAIN_MASK 0x001F /* EQ_B5_GAIN - [4:0] */
1887#define WM8993_EQ_B5_GAIN_SHIFT 0 /* EQ_B5_GAIN - [4:0] */
1888#define WM8993_EQ_B5_GAIN_WIDTH 5 /* EQ_B5_GAIN - [4:0] */
1889
1890/*
1891 * R104 (0x68) - EQ7
1892 */
1893#define WM8993_EQ_B1_A_MASK 0xFFFF /* EQ_B1_A - [15:0] */
1894#define WM8993_EQ_B1_A_SHIFT 0 /* EQ_B1_A - [15:0] */
1895#define WM8993_EQ_B1_A_WIDTH 16 /* EQ_B1_A - [15:0] */
1896
1897/*
1898 * R105 (0x69) - EQ8
1899 */
1900#define WM8993_EQ_B1_B_MASK 0xFFFF /* EQ_B1_B - [15:0] */
1901#define WM8993_EQ_B1_B_SHIFT 0 /* EQ_B1_B - [15:0] */
1902#define WM8993_EQ_B1_B_WIDTH 16 /* EQ_B1_B - [15:0] */
1903
1904/*
1905 * R106 (0x6A) - EQ9
1906 */
1907#define WM8993_EQ_B1_PG_MASK 0xFFFF /* EQ_B1_PG - [15:0] */
1908#define WM8993_EQ_B1_PG_SHIFT 0 /* EQ_B1_PG - [15:0] */
1909#define WM8993_EQ_B1_PG_WIDTH 16 /* EQ_B1_PG - [15:0] */
1910
1911/*
1912 * R107 (0x6B) - EQ10
1913 */
1914#define WM8993_EQ_B2_A_MASK 0xFFFF /* EQ_B2_A - [15:0] */
1915#define WM8993_EQ_B2_A_SHIFT 0 /* EQ_B2_A - [15:0] */
1916#define WM8993_EQ_B2_A_WIDTH 16 /* EQ_B2_A - [15:0] */
1917
1918/*
1919 * R108 (0x6C) - EQ11
1920 */
1921#define WM8993_EQ_B2_B_MASK 0xFFFF /* EQ_B2_B - [15:0] */
1922#define WM8993_EQ_B2_B_SHIFT 0 /* EQ_B2_B - [15:0] */
1923#define WM8993_EQ_B2_B_WIDTH 16 /* EQ_B2_B - [15:0] */
1924
1925/*
1926 * R109 (0x6D) - EQ12
1927 */
1928#define WM8993_EQ_B2_C_MASK 0xFFFF /* EQ_B2_C - [15:0] */
1929#define WM8993_EQ_B2_C_SHIFT 0 /* EQ_B2_C - [15:0] */
1930#define WM8993_EQ_B2_C_WIDTH 16 /* EQ_B2_C - [15:0] */
1931
1932/*
1933 * R110 (0x6E) - EQ13
1934 */
1935#define WM8993_EQ_B2_PG_MASK 0xFFFF /* EQ_B2_PG - [15:0] */
1936#define WM8993_EQ_B2_PG_SHIFT 0 /* EQ_B2_PG - [15:0] */
1937#define WM8993_EQ_B2_PG_WIDTH 16 /* EQ_B2_PG - [15:0] */
1938
1939/*
1940 * R111 (0x6F) - EQ14
1941 */
1942#define WM8993_EQ_B3_A_MASK 0xFFFF /* EQ_B3_A - [15:0] */
1943#define WM8993_EQ_B3_A_SHIFT 0 /* EQ_B3_A - [15:0] */
1944#define WM8993_EQ_B3_A_WIDTH 16 /* EQ_B3_A - [15:0] */
1945
1946/*
1947 * R112 (0x70) - EQ15
1948 */
1949#define WM8993_EQ_B3_B_MASK 0xFFFF /* EQ_B3_B - [15:0] */
1950#define WM8993_EQ_B3_B_SHIFT 0 /* EQ_B3_B - [15:0] */
1951#define WM8993_EQ_B3_B_WIDTH 16 /* EQ_B3_B - [15:0] */
1952
1953/*
1954 * R113 (0x71) - EQ16
1955 */
1956#define WM8993_EQ_B3_C_MASK 0xFFFF /* EQ_B3_C - [15:0] */
1957#define WM8993_EQ_B3_C_SHIFT 0 /* EQ_B3_C - [15:0] */
1958#define WM8993_EQ_B3_C_WIDTH 16 /* EQ_B3_C - [15:0] */
1959
1960/*
1961 * R114 (0x72) - EQ17
1962 */
1963#define WM8993_EQ_B3_PG_MASK 0xFFFF /* EQ_B3_PG - [15:0] */
1964#define WM8993_EQ_B3_PG_SHIFT 0 /* EQ_B3_PG - [15:0] */
1965#define WM8993_EQ_B3_PG_WIDTH 16 /* EQ_B3_PG - [15:0] */
1966
1967/*
1968 * R115 (0x73) - EQ18
1969 */
1970#define WM8993_EQ_B4_A_MASK 0xFFFF /* EQ_B4_A - [15:0] */
1971#define WM8993_EQ_B4_A_SHIFT 0 /* EQ_B4_A - [15:0] */
1972#define WM8993_EQ_B4_A_WIDTH 16 /* EQ_B4_A - [15:0] */
1973
1974/*
1975 * R116 (0x74) - EQ19
1976 */
1977#define WM8993_EQ_B4_B_MASK 0xFFFF /* EQ_B4_B - [15:0] */
1978#define WM8993_EQ_B4_B_SHIFT 0 /* EQ_B4_B - [15:0] */
1979#define WM8993_EQ_B4_B_WIDTH 16 /* EQ_B4_B - [15:0] */
1980
1981/*
1982 * R117 (0x75) - EQ20
1983 */
1984#define WM8993_EQ_B4_C_MASK 0xFFFF /* EQ_B4_C - [15:0] */
1985#define WM8993_EQ_B4_C_SHIFT 0 /* EQ_B4_C - [15:0] */
1986#define WM8993_EQ_B4_C_WIDTH 16 /* EQ_B4_C - [15:0] */
1987
1988/*
1989 * R118 (0x76) - EQ21
1990 */
1991#define WM8993_EQ_B4_PG_MASK 0xFFFF /* EQ_B4_PG - [15:0] */
1992#define WM8993_EQ_B4_PG_SHIFT 0 /* EQ_B4_PG - [15:0] */
1993#define WM8993_EQ_B4_PG_WIDTH 16 /* EQ_B4_PG - [15:0] */
1994
1995/*
1996 * R119 (0x77) - EQ22
1997 */
1998#define WM8993_EQ_B5_A_MASK 0xFFFF /* EQ_B5_A - [15:0] */
1999#define WM8993_EQ_B5_A_SHIFT 0 /* EQ_B5_A - [15:0] */
2000#define WM8993_EQ_B5_A_WIDTH 16 /* EQ_B5_A - [15:0] */
2001
2002/*
2003 * R120 (0x78) - EQ23
2004 */
2005#define WM8993_EQ_B5_B_MASK 0xFFFF /* EQ_B5_B - [15:0] */
2006#define WM8993_EQ_B5_B_SHIFT 0 /* EQ_B5_B - [15:0] */
2007#define WM8993_EQ_B5_B_WIDTH 16 /* EQ_B5_B - [15:0] */
2008
2009/*
2010 * R121 (0x79) - EQ24
2011 */
2012#define WM8993_EQ_B5_PG_MASK 0xFFFF /* EQ_B5_PG - [15:0] */
2013#define WM8993_EQ_B5_PG_SHIFT 0 /* EQ_B5_PG - [15:0] */
2014#define WM8993_EQ_B5_PG_WIDTH 16 /* EQ_B5_PG - [15:0] */
2015
2016/*
2017 * R122 (0x7A) - Digital Pulls
2018 */
2019#define WM8993_MCLK_PU 0x0080 /* MCLK_PU */
2020#define WM8993_MCLK_PU_MASK 0x0080 /* MCLK_PU */
2021#define WM8993_MCLK_PU_SHIFT 7 /* MCLK_PU */
2022#define WM8993_MCLK_PU_WIDTH 1 /* MCLK_PU */
2023#define WM8993_MCLK_PD 0x0040 /* MCLK_PD */
2024#define WM8993_MCLK_PD_MASK 0x0040 /* MCLK_PD */
2025#define WM8993_MCLK_PD_SHIFT 6 /* MCLK_PD */
2026#define WM8993_MCLK_PD_WIDTH 1 /* MCLK_PD */
2027#define WM8993_DACDAT_PU 0x0020 /* DACDAT_PU */
2028#define WM8993_DACDAT_PU_MASK 0x0020 /* DACDAT_PU */
2029#define WM8993_DACDAT_PU_SHIFT 5 /* DACDAT_PU */
2030#define WM8993_DACDAT_PU_WIDTH 1 /* DACDAT_PU */
2031#define WM8993_DACDAT_PD 0x0010 /* DACDAT_PD */
2032#define WM8993_DACDAT_PD_MASK 0x0010 /* DACDAT_PD */
2033#define WM8993_DACDAT_PD_SHIFT 4 /* DACDAT_PD */
2034#define WM8993_DACDAT_PD_WIDTH 1 /* DACDAT_PD */
2035#define WM8993_LRCLK_PU 0x0008 /* LRCLK_PU */
2036#define WM8993_LRCLK_PU_MASK 0x0008 /* LRCLK_PU */
2037#define WM8993_LRCLK_PU_SHIFT 3 /* LRCLK_PU */
2038#define WM8993_LRCLK_PU_WIDTH 1 /* LRCLK_PU */
2039#define WM8993_LRCLK_PD 0x0004 /* LRCLK_PD */
2040#define WM8993_LRCLK_PD_MASK 0x0004 /* LRCLK_PD */
2041#define WM8993_LRCLK_PD_SHIFT 2 /* LRCLK_PD */
2042#define WM8993_LRCLK_PD_WIDTH 1 /* LRCLK_PD */
2043#define WM8993_BCLK_PU 0x0002 /* BCLK_PU */
2044#define WM8993_BCLK_PU_MASK 0x0002 /* BCLK_PU */
2045#define WM8993_BCLK_PU_SHIFT 1 /* BCLK_PU */
2046#define WM8993_BCLK_PU_WIDTH 1 /* BCLK_PU */
2047#define WM8993_BCLK_PD 0x0001 /* BCLK_PD */
2048#define WM8993_BCLK_PD_MASK 0x0001 /* BCLK_PD */
2049#define WM8993_BCLK_PD_SHIFT 0 /* BCLK_PD */
2050#define WM8993_BCLK_PD_WIDTH 1 /* BCLK_PD */
2051
2052/*
2053 * R123 (0x7B) - DRC Control 1
2054 */
2055#define WM8993_DRC_ENA 0x8000 /* DRC_ENA */
2056#define WM8993_DRC_ENA_MASK 0x8000 /* DRC_ENA */
2057#define WM8993_DRC_ENA_SHIFT 15 /* DRC_ENA */
2058#define WM8993_DRC_ENA_WIDTH 1 /* DRC_ENA */
2059#define WM8993_DRC_DAC_PATH 0x4000 /* DRC_DAC_PATH */
2060#define WM8993_DRC_DAC_PATH_MASK 0x4000 /* DRC_DAC_PATH */
2061#define WM8993_DRC_DAC_PATH_SHIFT 14 /* DRC_DAC_PATH */
2062#define WM8993_DRC_DAC_PATH_WIDTH 1 /* DRC_DAC_PATH */
2063#define WM8993_DRC_SMOOTH_ENA 0x0800 /* DRC_SMOOTH_ENA */
2064#define WM8993_DRC_SMOOTH_ENA_MASK 0x0800 /* DRC_SMOOTH_ENA */
2065#define WM8993_DRC_SMOOTH_ENA_SHIFT 11 /* DRC_SMOOTH_ENA */
2066#define WM8993_DRC_SMOOTH_ENA_WIDTH 1 /* DRC_SMOOTH_ENA */
2067#define WM8993_DRC_QR_ENA 0x0400 /* DRC_QR_ENA */
2068#define WM8993_DRC_QR_ENA_MASK 0x0400 /* DRC_QR_ENA */
2069#define WM8993_DRC_QR_ENA_SHIFT 10 /* DRC_QR_ENA */
2070#define WM8993_DRC_QR_ENA_WIDTH 1 /* DRC_QR_ENA */
2071#define WM8993_DRC_ANTICLIP_ENA 0x0200 /* DRC_ANTICLIP_ENA */
2072#define WM8993_DRC_ANTICLIP_ENA_MASK 0x0200 /* DRC_ANTICLIP_ENA */
2073#define WM8993_DRC_ANTICLIP_ENA_SHIFT 9 /* DRC_ANTICLIP_ENA */
2074#define WM8993_DRC_ANTICLIP_ENA_WIDTH 1 /* DRC_ANTICLIP_ENA */
2075#define WM8993_DRC_HYST_ENA 0x0100 /* DRC_HYST_ENA */
2076#define WM8993_DRC_HYST_ENA_MASK 0x0100 /* DRC_HYST_ENA */
2077#define WM8993_DRC_HYST_ENA_SHIFT 8 /* DRC_HYST_ENA */
2078#define WM8993_DRC_HYST_ENA_WIDTH 1 /* DRC_HYST_ENA */
2079#define WM8993_DRC_THRESH_HYST_MASK 0x0030 /* DRC_THRESH_HYST - [5:4] */
2080#define WM8993_DRC_THRESH_HYST_SHIFT 4 /* DRC_THRESH_HYST - [5:4] */
2081#define WM8993_DRC_THRESH_HYST_WIDTH 2 /* DRC_THRESH_HYST - [5:4] */
2082#define WM8993_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */
2083#define WM8993_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */
2084#define WM8993_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */
2085#define WM8993_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */
2086#define WM8993_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */
2087#define WM8993_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */
2088
2089/*
2090 * R124 (0x7C) - DRC Control 2
2091 */
2092#define WM8993_DRC_ATTACK_RATE_MASK 0xF000 /* DRC_ATTACK_RATE - [15:12] */
2093#define WM8993_DRC_ATTACK_RATE_SHIFT 12 /* DRC_ATTACK_RATE - [15:12] */
2094#define WM8993_DRC_ATTACK_RATE_WIDTH 4 /* DRC_ATTACK_RATE - [15:12] */
2095#define WM8993_DRC_DECAY_RATE_MASK 0x0F00 /* DRC_DECAY_RATE - [11:8] */
2096#define WM8993_DRC_DECAY_RATE_SHIFT 8 /* DRC_DECAY_RATE - [11:8] */
2097#define WM8993_DRC_DECAY_RATE_WIDTH 4 /* DRC_DECAY_RATE - [11:8] */
2098#define WM8993_DRC_THRESH_COMP_MASK 0x00FC /* DRC_THRESH_COMP - [7:2] */
2099#define WM8993_DRC_THRESH_COMP_SHIFT 2 /* DRC_THRESH_COMP - [7:2] */
2100#define WM8993_DRC_THRESH_COMP_WIDTH 6 /* DRC_THRESH_COMP - [7:2] */
2101
2102/*
2103 * R125 (0x7D) - DRC Control 3
2104 */
2105#define WM8993_DRC_AMP_COMP_MASK 0xF800 /* DRC_AMP_COMP - [15:11] */
2106#define WM8993_DRC_AMP_COMP_SHIFT 11 /* DRC_AMP_COMP - [15:11] */
2107#define WM8993_DRC_AMP_COMP_WIDTH 5 /* DRC_AMP_COMP - [15:11] */
2108#define WM8993_DRC_R0_SLOPE_COMP_MASK 0x0700 /* DRC_R0_SLOPE_COMP - [10:8] */
2109#define WM8993_DRC_R0_SLOPE_COMP_SHIFT 8 /* DRC_R0_SLOPE_COMP - [10:8] */
2110#define WM8993_DRC_R0_SLOPE_COMP_WIDTH 3 /* DRC_R0_SLOPE_COMP - [10:8] */
2111#define WM8993_DRC_FF_DELAY 0x0080 /* DRC_FF_DELAY */
2112#define WM8993_DRC_FF_DELAY_MASK 0x0080 /* DRC_FF_DELAY */
2113#define WM8993_DRC_FF_DELAY_SHIFT 7 /* DRC_FF_DELAY */
2114#define WM8993_DRC_FF_DELAY_WIDTH 1 /* DRC_FF_DELAY */
2115#define WM8993_DRC_THRESH_QR_MASK 0x000C /* DRC_THRESH_QR - [3:2] */
2116#define WM8993_DRC_THRESH_QR_SHIFT 2 /* DRC_THRESH_QR - [3:2] */
2117#define WM8993_DRC_THRESH_QR_WIDTH 2 /* DRC_THRESH_QR - [3:2] */
2118#define WM8993_DRC_RATE_QR_MASK 0x0003 /* DRC_RATE_QR - [1:0] */
2119#define WM8993_DRC_RATE_QR_SHIFT 0 /* DRC_RATE_QR - [1:0] */
2120#define WM8993_DRC_RATE_QR_WIDTH 2 /* DRC_RATE_QR - [1:0] */
2121
2122/*
2123 * R126 (0x7E) - DRC Control 4
2124 */
2125#define WM8993_DRC_R1_SLOPE_COMP_MASK 0xE000 /* DRC_R1_SLOPE_COMP - [15:13] */
2126#define WM8993_DRC_R1_SLOPE_COMP_SHIFT 13 /* DRC_R1_SLOPE_COMP - [15:13] */
2127#define WM8993_DRC_R1_SLOPE_COMP_WIDTH 3 /* DRC_R1_SLOPE_COMP - [15:13] */
2128#define WM8993_DRC_STARTUP_GAIN_MASK 0x1F00 /* DRC_STARTUP_GAIN - [12:8] */
2129#define WM8993_DRC_STARTUP_GAIN_SHIFT 8 /* DRC_STARTUP_GAIN - [12:8] */
2130#define WM8993_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [12:8] */
2131
2132#endif
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index dc383c29cce5..1f51dd542a46 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -642,6 +642,10 @@ static int configure_clock(struct snd_soc_codec *codec)
642 target > 3000000) 642 target > 3000000)
643 break; 643 break;
644 } 644 }
645
646 if (i == ARRAY_SIZE(clk_sys_rates))
647 return -EINVAL;
648
645 } else if (wm9081->fs) { 649 } else if (wm9081->fs) {
646 for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) { 650 for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
647 new_sysclk = clk_sys_rates[i].ratio 651 new_sysclk = clk_sys_rates[i].ratio
@@ -649,6 +653,10 @@ static int configure_clock(struct snd_soc_codec *codec)
649 if (new_sysclk > 3000000) 653 if (new_sysclk > 3000000)
650 break; 654 break;
651 } 655 }
656
657 if (i == ARRAY_SIZE(clk_sys_rates))
658 return -EINVAL;
659
652 } else { 660 } else {
653 new_sysclk = 12288000; 661 new_sysclk = 12288000;
654 } 662 }
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 411a710be660..6802dd5e4731 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -9,6 +9,9 @@ config SND_DAVINCI_SOC
9config SND_DAVINCI_SOC_I2S 9config SND_DAVINCI_SOC_I2S
10 tristate 10 tristate
11 11
12config SND_DAVINCI_SOC_MCASP
13 tristate
14
12config SND_DAVINCI_SOC_EVM 15config SND_DAVINCI_SOC_EVM
13 tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM" 16 tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM"
14 depends on SND_DAVINCI_SOC 17 depends on SND_DAVINCI_SOC
@@ -19,6 +22,16 @@ config SND_DAVINCI_SOC_EVM
19 Say Y if you want to add support for SoC audio on TI 22 Say Y if you want to add support for SoC audio on TI
20 DaVinci DM6446 or DM355 EVM platforms. 23 DaVinci DM6446 or DM355 EVM platforms.
21 24
25config SND_DM6467_SOC_EVM
26 tristate "SoC Audio support for DaVinci DM6467 EVM"
27 depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM
28 select SND_DAVINCI_SOC_MCASP
29 select SND_SOC_TLV320AIC3X
30 select SND_SOC_SPDIF
31
32 help
33 Say Y if you want to add support for SoC audio on TI
34
22config SND_DAVINCI_SOC_SFFSDR 35config SND_DAVINCI_SOC_SFFSDR
23 tristate "SoC Audio support for SFFSDR" 36 tristate "SoC Audio support for SFFSDR"
24 depends on SND_DAVINCI_SOC && MACH_SFFSDR 37 depends on SND_DAVINCI_SOC && MACH_SFFSDR
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
index ca8bae1fc3f6..67be54f3a3a5 100644
--- a/sound/soc/davinci/Makefile
+++ b/sound/soc/davinci/Makefile
@@ -1,13 +1,16 @@
1# DAVINCI Platform Support 1# DAVINCI Platform Support
2snd-soc-davinci-objs := davinci-pcm.o 2snd-soc-davinci-objs := davinci-pcm.o
3snd-soc-davinci-i2s-objs := davinci-i2s.o 3snd-soc-davinci-i2s-objs := davinci-i2s.o
4snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
4 5
5obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o 6obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
6obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o 7obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
8obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
7 9
8# DAVINCI Machine Support 10# DAVINCI Machine Support
9snd-soc-evm-objs := davinci-evm.o 11snd-soc-evm-objs := davinci-evm.o
10snd-soc-sffsdr-objs := davinci-sffsdr.o 12snd-soc-sffsdr-objs := davinci-sffsdr.o
11 13
12obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o 14obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
15obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
13obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o 16obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 58fd1cbedd88..f3bb6f60f205 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -27,9 +27,10 @@
27#include <mach/mux.h> 27#include <mach/mux.h>
28 28
29#include "../codecs/tlv320aic3x.h" 29#include "../codecs/tlv320aic3x.h"
30#include "../codecs/spdif_transciever.h"
30#include "davinci-pcm.h" 31#include "davinci-pcm.h"
31#include "davinci-i2s.h" 32#include "davinci-i2s.h"
32 33#include "davinci-mcasp.h"
33 34
34#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ 35#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
35 SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) 36 SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
@@ -43,7 +44,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
43 unsigned sysclk; 44 unsigned sysclk;
44 45
45 /* ASP1 on DM355 EVM is clocked by an external oscillator */ 46 /* ASP1 on DM355 EVM is clocked by an external oscillator */
46 if (machine_is_davinci_dm355_evm()) 47 if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm())
47 sysclk = 27000000; 48 sysclk = 27000000;
48 49
49 /* ASP0 in DM6446 EVM is clocked by U55, as configured by 50 /* ASP0 in DM6446 EVM is clocked by U55, as configured by
@@ -144,6 +145,24 @@ static struct snd_soc_dai_link evm_dai = {
144 .ops = &evm_ops, 145 .ops = &evm_ops,
145}; 146};
146 147
148static struct snd_soc_dai_link dm6467_evm_dai[] = {
149 {
150 .name = "TLV320AIC3X",
151 .stream_name = "AIC3X",
152 .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
153 .codec_dai = &aic3x_dai,
154 .init = evm_aic3x_init,
155 .ops = &evm_ops,
156 },
157 {
158 .name = "McASP",
159 .stream_name = "spdif",
160 .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
161 .codec_dai = &dit_stub_dai,
162 .ops = &evm_ops,
163 },
164};
165
147/* davinci-evm audio machine driver */ 166/* davinci-evm audio machine driver */
148static struct snd_soc_card snd_soc_card_evm = { 167static struct snd_soc_card snd_soc_card_evm = {
149 .name = "DaVinci EVM", 168 .name = "DaVinci EVM",
@@ -152,12 +171,26 @@ static struct snd_soc_card snd_soc_card_evm = {
152 .num_links = 1, 171 .num_links = 1,
153}; 172};
154 173
174/* davinci dm6467 evm audio machine driver */
175static struct snd_soc_card dm6467_snd_soc_card_evm = {
176 .name = "DaVinci DM6467 EVM",
177 .platform = &davinci_soc_platform,
178 .dai_link = dm6467_evm_dai,
179 .num_links = ARRAY_SIZE(dm6467_evm_dai),
180};
181
155/* evm audio private data */ 182/* evm audio private data */
156static struct aic3x_setup_data evm_aic3x_setup = { 183static struct aic3x_setup_data evm_aic3x_setup = {
157 .i2c_bus = 1, 184 .i2c_bus = 1,
158 .i2c_address = 0x1b, 185 .i2c_address = 0x1b,
159}; 186};
160 187
188/* dm6467 evm audio private data */
189static struct aic3x_setup_data dm6467_evm_aic3x_setup = {
190 .i2c_bus = 1,
191 .i2c_address = 0x18,
192};
193
161/* evm audio subsystem */ 194/* evm audio subsystem */
162static struct snd_soc_device evm_snd_devdata = { 195static struct snd_soc_device evm_snd_devdata = {
163 .card = &snd_soc_card_evm, 196 .card = &snd_soc_card_evm,
@@ -165,60 +198,30 @@ static struct snd_soc_device evm_snd_devdata = {
165 .codec_data = &evm_aic3x_setup, 198 .codec_data = &evm_aic3x_setup,
166}; 199};
167 200
168/* DM6446 EVM uses ASP0; line-out is a pair of RCA jacks */ 201/* evm audio subsystem */
169static struct resource evm_snd_resources[] = { 202static struct snd_soc_device dm6467_evm_snd_devdata = {
170 { 203 .card = &dm6467_snd_soc_card_evm,
171 .start = DAVINCI_ASP0_BASE, 204 .codec_dev = &soc_codec_dev_aic3x,
172 .end = DAVINCI_ASP0_BASE + SZ_8K - 1, 205 .codec_data = &dm6467_evm_aic3x_setup,
173 .flags = IORESOURCE_MEM,
174 },
175};
176
177static struct evm_snd_platform_data evm_snd_data = {
178 .tx_dma_ch = DAVINCI_DMA_ASP0_TX,
179 .rx_dma_ch = DAVINCI_DMA_ASP0_RX,
180};
181
182/* DM335 EVM uses ASP1; line-out is a stereo mini-jack */
183static struct resource dm335evm_snd_resources[] = {
184 {
185 .start = DAVINCI_ASP1_BASE,
186 .end = DAVINCI_ASP1_BASE + SZ_8K - 1,
187 .flags = IORESOURCE_MEM,
188 },
189};
190
191static struct evm_snd_platform_data dm335evm_snd_data = {
192 .tx_dma_ch = DAVINCI_DMA_ASP1_TX,
193 .rx_dma_ch = DAVINCI_DMA_ASP1_RX,
194}; 206};
195 207
196static struct platform_device *evm_snd_device; 208static struct platform_device *evm_snd_device;
197 209
198static int __init evm_init(void) 210static int __init evm_init(void)
199{ 211{
200 struct resource *resources; 212 struct snd_soc_device *evm_snd_dev_data;
201 unsigned num_resources;
202 struct evm_snd_platform_data *data;
203 int index; 213 int index;
204 int ret; 214 int ret;
205 215
206 if (machine_is_davinci_evm()) { 216 if (machine_is_davinci_evm()) {
207 davinci_cfg_reg(DM644X_MCBSP); 217 evm_snd_dev_data = &evm_snd_devdata;
208
209 resources = evm_snd_resources;
210 num_resources = ARRAY_SIZE(evm_snd_resources);
211 data = &evm_snd_data;
212 index = 0; 218 index = 0;
213 } else if (machine_is_davinci_dm355_evm()) { 219 } else if (machine_is_davinci_dm355_evm()) {
214 /* we don't use ASP1 IRQs, or we'd need to mux them ... */ 220 evm_snd_dev_data = &evm_snd_devdata;
215 davinci_cfg_reg(DM355_EVT8_ASP1_TX);
216 davinci_cfg_reg(DM355_EVT9_ASP1_RX);
217
218 resources = dm335evm_snd_resources;
219 num_resources = ARRAY_SIZE(dm335evm_snd_resources);
220 data = &dm335evm_snd_data;
221 index = 1; 221 index = 1;
222 } else if (machine_is_davinci_dm6467_evm()) {
223 evm_snd_dev_data = &dm6467_evm_snd_devdata;
224 index = 0;
222 } else 225 } else
223 return -EINVAL; 226 return -EINVAL;
224 227
@@ -226,17 +229,8 @@ static int __init evm_init(void)
226 if (!evm_snd_device) 229 if (!evm_snd_device)
227 return -ENOMEM; 230 return -ENOMEM;
228 231
229 platform_set_drvdata(evm_snd_device, &evm_snd_devdata); 232 platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
230 evm_snd_devdata.dev = &evm_snd_device->dev; 233 evm_snd_dev_data->dev = &evm_snd_device->dev;
231 platform_device_add_data(evm_snd_device, data, sizeof(*data));
232
233 ret = platform_device_add_resources(evm_snd_device, resources,
234 num_resources);
235 if (ret) {
236 platform_device_put(evm_snd_device);
237 return ret;
238 }
239
240 ret = platform_device_add(evm_snd_device); 234 ret = platform_device_add(evm_snd_device);
241 if (ret) 235 if (ret)
242 platform_device_put(evm_snd_device); 236 platform_device_put(evm_snd_device);
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 88ccef79a5eb..2a56fb78f67a 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -22,6 +22,8 @@
22#include <sound/initval.h> 22#include <sound/initval.h>
23#include <sound/soc.h> 23#include <sound/soc.h>
24 24
25#include <mach/asp.h>
26
25#include "davinci-pcm.h" 27#include "davinci-pcm.h"
26 28
27 29
@@ -351,9 +353,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
351 struct snd_pcm_hw_params *params, 353 struct snd_pcm_hw_params *params,
352 struct snd_soc_dai *dai) 354 struct snd_soc_dai *dai)
353{ 355{
354 struct snd_soc_pcm_runtime *rtd = substream->private_data; 356 struct davinci_pcm_dma_params *dma_params = dai->dma_data;
355 struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; 357 struct davinci_mcbsp_dev *dev = dai->private_data;
356 struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
357 struct snd_interval *i = NULL; 358 struct snd_interval *i = NULL;
358 int mcbsp_word_length; 359 int mcbsp_word_length;
359 unsigned int rcr, xcr, srgr; 360 unsigned int rcr, xcr, srgr;
@@ -423,8 +424,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
423static int davinci_i2s_prepare(struct snd_pcm_substream *substream, 424static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
424 struct snd_soc_dai *dai) 425 struct snd_soc_dai *dai)
425{ 426{
426 struct snd_soc_pcm_runtime *rtd = substream->private_data; 427 struct davinci_mcbsp_dev *dev = dai->private_data;
427 struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
428 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 428 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
429 davinci_mcbsp_stop(dev, playback); 429 davinci_mcbsp_stop(dev, playback);
430 if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) { 430 if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) {
@@ -437,8 +437,7 @@ static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
437static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 437static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
438 struct snd_soc_dai *dai) 438 struct snd_soc_dai *dai)
439{ 439{
440 struct snd_soc_pcm_runtime *rtd = substream->private_data; 440 struct davinci_mcbsp_dev *dev = dai->private_data;
441 struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
442 int ret = 0; 441 int ret = 0;
443 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 442 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
444 if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) 443 if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0)
@@ -464,21 +463,46 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
464static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, 463static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
465 struct snd_soc_dai *dai) 464 struct snd_soc_dai *dai)
466{ 465{
467 struct snd_soc_pcm_runtime *rtd = substream->private_data; 466 struct davinci_mcbsp_dev *dev = dai->private_data;
468 struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
469 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 467 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
470 davinci_mcbsp_stop(dev, playback); 468 davinci_mcbsp_stop(dev, playback);
471} 469}
472 470
473static int davinci_i2s_probe(struct platform_device *pdev, 471#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
474 struct snd_soc_dai *dai) 472
473static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
474 .startup = davinci_i2s_startup,
475 .shutdown = davinci_i2s_shutdown,
476 .prepare = davinci_i2s_prepare,
477 .trigger = davinci_i2s_trigger,
478 .hw_params = davinci_i2s_hw_params,
479 .set_fmt = davinci_i2s_set_dai_fmt,
480
481};
482
483struct snd_soc_dai davinci_i2s_dai = {
484 .name = "davinci-i2s",
485 .id = 0,
486 .playback = {
487 .channels_min = 2,
488 .channels_max = 2,
489 .rates = DAVINCI_I2S_RATES,
490 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
491 .capture = {
492 .channels_min = 2,
493 .channels_max = 2,
494 .rates = DAVINCI_I2S_RATES,
495 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
496 .ops = &davinci_i2s_dai_ops,
497
498};
499EXPORT_SYMBOL_GPL(davinci_i2s_dai);
500
501static int davinci_i2s_probe(struct platform_device *pdev)
475{ 502{
476 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 503 struct snd_platform_data *pdata = pdev->dev.platform_data;
477 struct snd_soc_card *card = socdev->card;
478 struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai;
479 struct davinci_mcbsp_dev *dev; 504 struct davinci_mcbsp_dev *dev;
480 struct resource *mem, *ioarea; 505 struct resource *mem, *ioarea, *res;
481 struct evm_snd_platform_data *pdata;
482 int ret; 506 int ret;
483 507
484 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 508 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -500,8 +524,6 @@ static int davinci_i2s_probe(struct platform_device *pdev,
500 goto err_release_region; 524 goto err_release_region;
501 } 525 }
502 526
503 cpu_dai->private_data = dev;
504
505 dev->clk = clk_get(&pdev->dev, NULL); 527 dev->clk = clk_get(&pdev->dev, NULL);
506 if (IS_ERR(dev->clk)) { 528 if (IS_ERR(dev->clk)) {
507 ret = -ENODEV; 529 ret = -ENODEV;
@@ -510,18 +532,37 @@ static int davinci_i2s_probe(struct platform_device *pdev,
510 clk_enable(dev->clk); 532 clk_enable(dev->clk);
511 533
512 dev->base = (void __iomem *)IO_ADDRESS(mem->start); 534 dev->base = (void __iomem *)IO_ADDRESS(mem->start);
513 pdata = pdev->dev.platform_data;
514 535
515 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &davinci_i2s_pcm_out; 536 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &davinci_i2s_pcm_out;
516 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = pdata->tx_dma_ch;
517 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->dma_addr = 537 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->dma_addr =
518 (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DXR_REG); 538 (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DXR_REG);
519 539
520 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &davinci_i2s_pcm_in; 540 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &davinci_i2s_pcm_in;
521 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = pdata->rx_dma_ch;
522 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->dma_addr = 541 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->dma_addr =
523 (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DRR_REG); 542 (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DRR_REG);
524 543
544 /* first TX, then RX */
545 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
546 if (!res) {
547 dev_err(&pdev->dev, "no DMA resource\n");
548 ret = -ENXIO;
549 goto err_free_mem;
550 }
551 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = res->start;
552
553 res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
554 if (!res) {
555 dev_err(&pdev->dev, "no DMA resource\n");
556 ret = -ENXIO;
557 goto err_free_mem;
558 }
559 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = res->start;
560
561 davinci_i2s_dai.private_data = dev;
562 ret = snd_soc_register_dai(&davinci_i2s_dai);
563 if (ret != 0)
564 goto err_free_mem;
565
525 return 0; 566 return 0;
526 567
527err_free_mem: 568err_free_mem:
@@ -532,64 +573,40 @@ err_release_region:
532 return ret; 573 return ret;
533} 574}
534 575
535static void davinci_i2s_remove(struct platform_device *pdev, 576static int davinci_i2s_remove(struct platform_device *pdev)
536 struct snd_soc_dai *dai)
537{ 577{
538 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 578 struct davinci_mcbsp_dev *dev = davinci_i2s_dai.private_data;
539 struct snd_soc_card *card = socdev->card;
540 struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai;
541 struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
542 struct resource *mem; 579 struct resource *mem;
543 580
581 snd_soc_unregister_dai(&davinci_i2s_dai);
544 clk_disable(dev->clk); 582 clk_disable(dev->clk);
545 clk_put(dev->clk); 583 clk_put(dev->clk);
546 dev->clk = NULL; 584 dev->clk = NULL;
547
548 kfree(dev); 585 kfree(dev);
549
550 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 586 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
551 release_mem_region(mem->start, (mem->end - mem->start) + 1); 587 release_mem_region(mem->start, (mem->end - mem->start) + 1);
552}
553
554#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
555 588
556static struct snd_soc_dai_ops davinci_i2s_dai_ops = { 589 return 0;
557 .startup = davinci_i2s_startup, 590}
558 .shutdown = davinci_i2s_shutdown,
559 .prepare = davinci_i2s_prepare,
560 .trigger = davinci_i2s_trigger,
561 .hw_params = davinci_i2s_hw_params,
562 .set_fmt = davinci_i2s_set_dai_fmt,
563};
564 591
565struct snd_soc_dai davinci_i2s_dai = { 592static struct platform_driver davinci_mcbsp_driver = {
566 .name = "davinci-i2s", 593 .probe = davinci_i2s_probe,
567 .id = 0, 594 .remove = davinci_i2s_remove,
568 .probe = davinci_i2s_probe, 595 .driver = {
569 .remove = davinci_i2s_remove, 596 .name = "davinci-asp",
570 .playback = { 597 .owner = THIS_MODULE,
571 .channels_min = 2, 598 },
572 .channels_max = 2,
573 .rates = DAVINCI_I2S_RATES,
574 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
575 .capture = {
576 .channels_min = 2,
577 .channels_max = 2,
578 .rates = DAVINCI_I2S_RATES,
579 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
580 .ops = &davinci_i2s_dai_ops,
581}; 599};
582EXPORT_SYMBOL_GPL(davinci_i2s_dai);
583 600
584static int __init davinci_i2s_init(void) 601static int __init davinci_i2s_init(void)
585{ 602{
586 return snd_soc_register_dai(&davinci_i2s_dai); 603 return platform_driver_register(&davinci_mcbsp_driver);
587} 604}
588module_init(davinci_i2s_init); 605module_init(davinci_i2s_init);
589 606
590static void __exit davinci_i2s_exit(void) 607static void __exit davinci_i2s_exit(void)
591{ 608{
592 snd_soc_unregister_dai(&davinci_i2s_dai); 609 platform_driver_unregister(&davinci_mcbsp_driver);
593} 610}
594module_exit(davinci_i2s_exit); 611module_exit(davinci_i2s_exit);
595 612
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
new file mode 100644
index 000000000000..f0c034771062
--- /dev/null
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -0,0 +1,874 @@
1/*
2 * ALSA SoC McASP Audio Layer for TI DAVINCI processor
3 *
4 * Multi-channel Audio Serial Port Driver
5 *
6 * Author: Nirmal Pandey <n-pandey@ti.com>,
7 * Suresh Rajashekara <suresh.r@ti.com>
8 * Steve Chen <schen@.mvista.com>
9 *
10 * Copyright: (C) 2009 MontaVista Software, Inc., <source@mvista.com>
11 * Copyright: (C) 2009 Texas Instruments, India
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
18#include <linux/init.h>
19#include <linux/module.h>
20#include <linux/device.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/clk.h>
24
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include <sound/pcm_params.h>
28#include <sound/initval.h>
29#include <sound/soc.h>
30
31#include "davinci-pcm.h"
32#include "davinci-mcasp.h"
33
34/*
35 * McASP register definitions
36 */
37#define DAVINCI_MCASP_PID_REG 0x00
38#define DAVINCI_MCASP_PWREMUMGT_REG 0x04
39
40#define DAVINCI_MCASP_PFUNC_REG 0x10
41#define DAVINCI_MCASP_PDIR_REG 0x14
42#define DAVINCI_MCASP_PDOUT_REG 0x18
43#define DAVINCI_MCASP_PDSET_REG 0x1c
44
45#define DAVINCI_MCASP_PDCLR_REG 0x20
46
47#define DAVINCI_MCASP_TLGC_REG 0x30
48#define DAVINCI_MCASP_TLMR_REG 0x34
49
50#define DAVINCI_MCASP_GBLCTL_REG 0x44
51#define DAVINCI_MCASP_AMUTE_REG 0x48
52#define DAVINCI_MCASP_LBCTL_REG 0x4c
53
54#define DAVINCI_MCASP_TXDITCTL_REG 0x50
55
56#define DAVINCI_MCASP_GBLCTLR_REG 0x60
57#define DAVINCI_MCASP_RXMASK_REG 0x64
58#define DAVINCI_MCASP_RXFMT_REG 0x68
59#define DAVINCI_MCASP_RXFMCTL_REG 0x6c
60
61#define DAVINCI_MCASP_ACLKRCTL_REG 0x70
62#define DAVINCI_MCASP_AHCLKRCTL_REG 0x74
63#define DAVINCI_MCASP_RXTDM_REG 0x78
64#define DAVINCI_MCASP_EVTCTLR_REG 0x7c
65
66#define DAVINCI_MCASP_RXSTAT_REG 0x80
67#define DAVINCI_MCASP_RXTDMSLOT_REG 0x84
68#define DAVINCI_MCASP_RXCLKCHK_REG 0x88
69#define DAVINCI_MCASP_REVTCTL_REG 0x8c
70
71#define DAVINCI_MCASP_GBLCTLX_REG 0xa0
72#define DAVINCI_MCASP_TXMASK_REG 0xa4
73#define DAVINCI_MCASP_TXFMT_REG 0xa8
74#define DAVINCI_MCASP_TXFMCTL_REG 0xac
75
76#define DAVINCI_MCASP_ACLKXCTL_REG 0xb0
77#define DAVINCI_MCASP_AHCLKXCTL_REG 0xb4
78#define DAVINCI_MCASP_TXTDM_REG 0xb8
79#define DAVINCI_MCASP_EVTCTLX_REG 0xbc
80
81#define DAVINCI_MCASP_TXSTAT_REG 0xc0
82#define DAVINCI_MCASP_TXTDMSLOT_REG 0xc4
83#define DAVINCI_MCASP_TXCLKCHK_REG 0xc8
84#define DAVINCI_MCASP_XEVTCTL_REG 0xcc
85
86/* Left(even TDM Slot) Channel Status Register File */
87#define DAVINCI_MCASP_DITCSRA_REG 0x100
88/* Right(odd TDM slot) Channel Status Register File */
89#define DAVINCI_MCASP_DITCSRB_REG 0x118
90/* Left(even TDM slot) User Data Register File */
91#define DAVINCI_MCASP_DITUDRA_REG 0x130
92/* Right(odd TDM Slot) User Data Register File */
93#define DAVINCI_MCASP_DITUDRB_REG 0x148
94
95/* Serializer n Control Register */
96#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
97#define DAVINCI_MCASP_XRSRCTL_REG(n) (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
98 (n << 2))
99
100/* Transmit Buffer for Serializer n */
101#define DAVINCI_MCASP_TXBUF_REG 0x200
102/* Receive Buffer for Serializer n */
103#define DAVINCI_MCASP_RXBUF_REG 0x280
104
105
106/*
107 * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
108 * Register Bits
109 */
110#define MCASP_FREE BIT(0)
111#define MCASP_SOFT BIT(1)
112
113/*
114 * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
115 */
116#define AXR(n) (1<<n)
117#define PFUNC_AMUTE BIT(25)
118#define ACLKX BIT(26)
119#define AHCLKX BIT(27)
120#define AFSX BIT(28)
121#define ACLKR BIT(29)
122#define AHCLKR BIT(30)
123#define AFSR BIT(31)
124
125/*
126 * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
127 */
128#define AXR(n) (1<<n)
129#define PDIR_AMUTE BIT(25)
130#define ACLKX BIT(26)
131#define AHCLKX BIT(27)
132#define AFSX BIT(28)
133#define ACLKR BIT(29)
134#define AHCLKR BIT(30)
135#define AFSR BIT(31)
136
137/*
138 * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
139 */
140#define DITEN BIT(0) /* Transmit DIT mode enable/disable */
141#define VA BIT(2)
142#define VB BIT(3)
143
144/*
145 * DAVINCI_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits
146 */
147#define TXROT(val) (val)
148#define TXSEL BIT(3)
149#define TXSSZ(val) (val<<4)
150#define TXPBIT(val) (val<<8)
151#define TXPAD(val) (val<<13)
152#define TXORD BIT(15)
153#define FSXDLY(val) (val<<16)
154
155/*
156 * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
157 */
158#define RXROT(val) (val)
159#define RXSEL BIT(3)
160#define RXSSZ(val) (val<<4)
161#define RXPBIT(val) (val<<8)
162#define RXPAD(val) (val<<13)
163#define RXORD BIT(15)
164#define FSRDLY(val) (val<<16)
165
166/*
167 * DAVINCI_MCASP_TXFMCTL_REG - Transmit Frame Control Register Bits
168 */
169#define FSXPOL BIT(0)
170#define AFSXE BIT(1)
171#define FSXDUR BIT(4)
172#define FSXMOD(val) (val<<7)
173
174/*
175 * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
176 */
177#define FSRPOL BIT(0)
178#define AFSRE BIT(1)
179#define FSRDUR BIT(4)
180#define FSRMOD(val) (val<<7)
181
182/*
183 * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
184 */
185#define ACLKXDIV(val) (val)
186#define ACLKXE BIT(5)
187#define TX_ASYNC BIT(6)
188#define ACLKXPOL BIT(7)
189
190/*
191 * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits
192 */
193#define ACLKRDIV(val) (val)
194#define ACLKRE BIT(5)
195#define RX_ASYNC BIT(6)
196#define ACLKRPOL BIT(7)
197
198/*
199 * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control
200 * Register Bits
201 */
202#define AHCLKXDIV(val) (val)
203#define AHCLKXPOL BIT(14)
204#define AHCLKXE BIT(15)
205
206/*
207 * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control
208 * Register Bits
209 */
210#define AHCLKRDIV(val) (val)
211#define AHCLKRPOL BIT(14)
212#define AHCLKRE BIT(15)
213
214/*
215 * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits
216 */
217#define MODE(val) (val)
218#define DISMOD (val)(val<<2)
219#define TXSTATE BIT(4)
220#define RXSTATE BIT(5)
221
222/*
223 * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
224 */
225#define LBEN BIT(0)
226#define LBORD BIT(1)
227#define LBGENMODE(val) (val<<2)
228
229/*
230 * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
231 */
232#define TXTDMS(n) (1<<n)
233
234/*
235 * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
236 */
237#define RXTDMS(n) (1<<n)
238
239/*
240 * DAVINCI_MCASP_GBLCTL_REG - Global Control Register Bits
241 */
242#define RXCLKRST BIT(0) /* Receiver Clock Divider Reset */
243#define RXHCLKRST BIT(1) /* Receiver High Frequency Clock Divider */
244#define RXSERCLR BIT(2) /* Receiver Serializer Clear */
245#define RXSMRST BIT(3) /* Receiver State Machine Reset */
246#define RXFSRST BIT(4) /* Frame Sync Generator Reset */
247#define TXCLKRST BIT(8) /* Transmitter Clock Divider Reset */
248#define TXHCLKRST BIT(9) /* Transmitter High Frequency Clock Divider*/
249#define TXSERCLR BIT(10) /* Transmit Serializer Clear */
250#define TXSMRST BIT(11) /* Transmitter State Machine Reset */
251#define TXFSRST BIT(12) /* Frame Sync Generator Reset */
252
253/*
254 * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits
255 */
256#define MUTENA(val) (val)
257#define MUTEINPOL BIT(2)
258#define MUTEINENA BIT(3)
259#define MUTEIN BIT(4)
260#define MUTER BIT(5)
261#define MUTEX BIT(6)
262#define MUTEFSR BIT(7)
263#define MUTEFSX BIT(8)
264#define MUTEBADCLKR BIT(9)
265#define MUTEBADCLKX BIT(10)
266#define MUTERXDMAERR BIT(11)
267#define MUTETXDMAERR BIT(12)
268
269/*
270 * DAVINCI_MCASP_REVTCTL_REG - Receiver DMA Event Control Register bits
271 */
272#define RXDATADMADIS BIT(0)
273
274/*
275 * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits
276 */
277#define TXDATADMADIS BIT(0)
278
279#define DAVINCI_MCASP_NUM_SERIALIZER 16
280
281static inline void mcasp_set_bits(void __iomem *reg, u32 val)
282{
283 __raw_writel(__raw_readl(reg) | val, reg);
284}
285
286static inline void mcasp_clr_bits(void __iomem *reg, u32 val)
287{
288 __raw_writel((__raw_readl(reg) & ~(val)), reg);
289}
290
291static inline void mcasp_mod_bits(void __iomem *reg, u32 val, u32 mask)
292{
293 __raw_writel((__raw_readl(reg) & ~mask) | val, reg);
294}
295
296static inline void mcasp_set_reg(void __iomem *reg, u32 val)
297{
298 __raw_writel(val, reg);
299}
300
301static inline u32 mcasp_get_reg(void __iomem *reg)
302{
303 return (unsigned int)__raw_readl(reg);
304}
305
306static inline void mcasp_set_ctl_reg(void __iomem *regs, u32 val)
307{
308 int i = 0;
309
310 mcasp_set_bits(regs, val);
311
312 /* programming GBLCTL needs to read back from GBLCTL and verfiy */
313 /* loop count is to avoid the lock-up */
314 for (i = 0; i < 1000; i++) {
315 if ((mcasp_get_reg(regs) & val) == val)
316 break;
317 }
318
319 if (i == 1000 && ((mcasp_get_reg(regs) & val) != val))
320 printk(KERN_ERR "GBLCTL write error\n");
321}
322
323static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
324 struct snd_soc_dai *cpu_dai)
325{
326 struct davinci_audio_dev *dev = cpu_dai->private_data;
327 cpu_dai->dma_data = dev->dma_params[substream->stream];
328 return 0;
329}
330
331static void mcasp_start_rx(struct davinci_audio_dev *dev)
332{
333 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
334 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
335 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
336 mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0);
337
338 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
339 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
340 mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0);
341
342 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
343 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
344}
345
346static void mcasp_start_tx(struct davinci_audio_dev *dev)
347{
348 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
349 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
350 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
351 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
352
353 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
354 mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
355 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
356 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
357}
358
359static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
360{
361 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
362 mcasp_start_tx(dev);
363 else
364 mcasp_start_rx(dev);
365}
366
367static void mcasp_stop_rx(struct davinci_audio_dev *dev)
368{
369 mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, 0);
370 mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
371}
372
373static void mcasp_stop_tx(struct davinci_audio_dev *dev)
374{
375 mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, 0);
376 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
377}
378
379static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
380{
381 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
382 mcasp_stop_tx(dev);
383 else
384 mcasp_stop_rx(dev);
385}
386
387static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
388 unsigned int fmt)
389{
390 struct davinci_audio_dev *dev = cpu_dai->private_data;
391 void __iomem *base = dev->base;
392
393 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
394 case SND_SOC_DAIFMT_CBS_CFS:
395 /* codec is clock and frame slave */
396 mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
397 mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
398
399 mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
400 mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
401
402 mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26));
403 break;
404
405 case SND_SOC_DAIFMT_CBM_CFM:
406 /* codec is clock and frame master */
407 mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
408 mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
409
410 mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
411 mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
412
413 mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, (0x3f << 26));
414 break;
415
416 default:
417 return -EINVAL;
418 }
419
420 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
421 case SND_SOC_DAIFMT_IB_NF:
422 mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
423 mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
424
425 mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
426 mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
427 break;
428
429 case SND_SOC_DAIFMT_NB_IF:
430 mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
431 mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
432
433 mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
434 mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
435 break;
436
437 case SND_SOC_DAIFMT_IB_IF:
438 mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
439 mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
440
441 mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
442 mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
443 break;
444
445 case SND_SOC_DAIFMT_NB_NF:
446 mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
447 mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
448
449 mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
450 mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
451 break;
452
453 default:
454 return -EINVAL;
455 }
456
457 return 0;
458}
459
460static int davinci_config_channel_size(struct davinci_audio_dev *dev,
461 int channel_size)
462{
463 u32 fmt = 0;
464
465 switch (channel_size) {
466 case DAVINCI_AUDIO_WORD_8:
467 fmt = 0x03;
468 break;
469
470 case DAVINCI_AUDIO_WORD_12:
471 fmt = 0x05;
472 break;
473
474 case DAVINCI_AUDIO_WORD_16:
475 fmt = 0x07;
476 break;
477
478 case DAVINCI_AUDIO_WORD_20:
479 fmt = 0x09;
480 break;
481
482 case DAVINCI_AUDIO_WORD_24:
483 fmt = 0x0B;
484 break;
485
486 case DAVINCI_AUDIO_WORD_28:
487 fmt = 0x0D;
488 break;
489
490 case DAVINCI_AUDIO_WORD_32:
491 fmt = 0x0F;
492 break;
493
494 default:
495 return -EINVAL;
496 }
497
498 mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
499 RXSSZ(fmt), RXSSZ(0x0F));
500 mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
501 TXSSZ(fmt), TXSSZ(0x0F));
502 return 0;
503}
504
505static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
506{
507 int i;
508
509 /* Default configuration */
510 mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
511
512 /* All PINS as McASP */
513 mcasp_set_reg(dev->base + DAVINCI_MCASP_PFUNC_REG, 0x00000000);
514
515 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
516 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
517 mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG,
518 TXDATADMADIS);
519 } else {
520 mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
521 mcasp_clr_bits(dev->base + DAVINCI_MCASP_REVTCTL_REG,
522 RXDATADMADIS);
523 }
524
525 for (i = 0; i < dev->num_serializer; i++) {
526 mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
527 dev->serial_dir[i]);
528 if (dev->serial_dir[i] == TX_MODE)
529 mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
530 AXR(i));
531 else if (dev->serial_dir[i] == RX_MODE)
532 mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
533 AXR(i));
534 }
535}
536
537static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
538{
539 int i, active_slots;
540 u32 mask = 0;
541
542 active_slots = (dev->tdm_slots > 31) ? 32 : dev->tdm_slots;
543 for (i = 0; i < active_slots; i++)
544 mask |= (1 << i);
545
546 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
547 /* bit stream is MSB first with no delay */
548 /* DSP_B mode */
549 mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG,
550 AHCLKXE);
551 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask);
552 mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD);
553
554 if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32))
555 mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
556 FSXMOD(dev->tdm_slots), FSXMOD(0x1FF));
557 else
558 printk(KERN_ERR "playback tdm slot %d not supported\n",
559 dev->tdm_slots);
560
561 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0xFFFFFFFF);
562 mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
563 } else {
564 /* bit stream is MSB first with no delay */
565 /* DSP_B mode */
566 mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXORD);
567 mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG,
568 AHCLKRE);
569 mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask);
570
571 if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32))
572 mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG,
573 FSRMOD(dev->tdm_slots), FSRMOD(0x1FF));
574 else
575 printk(KERN_ERR "capture tdm slot %d not supported\n",
576 dev->tdm_slots);
577
578 mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, 0xFFFFFFFF);
579 mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
580 }
581}
582
583/* S/PDIF */
584static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
585{
586 /* Set the PDIR for Serialiser as output */
587 mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX);
588
589 /* TXMASK for 24 bits */
590 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF);
591
592 /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
593 and LSB first */
594 mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
595 TXROT(6) | TXSSZ(15));
596
597 /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
598 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
599 AFSXE | FSXMOD(0x180));
600
601 /* Set the TX tdm : for all the slots */
602 mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
603
604 /* Set the TX clock controls : div = 1 and internal */
605 mcasp_set_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG,
606 ACLKXE | TX_ASYNC);
607
608 mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
609
610 /* Only 44100 and 48000 are valid, both have the same setting */
611 mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
612
613 /* Enable the DIT */
614 mcasp_set_bits(dev->base + DAVINCI_MCASP_TXDITCTL_REG, DITEN);
615}
616
617static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
618 struct snd_pcm_hw_params *params,
619 struct snd_soc_dai *cpu_dai)
620{
621 struct davinci_audio_dev *dev = cpu_dai->private_data;
622 struct davinci_pcm_dma_params *dma_params =
623 dev->dma_params[substream->stream];
624 int word_length;
625
626 davinci_hw_common_param(dev, substream->stream);
627
628 if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
629 davinci_hw_dit_param(dev);
630 else
631 davinci_hw_param(dev, substream->stream);
632
633 switch (params_format(params)) {
634 case SNDRV_PCM_FORMAT_S8:
635 dma_params->data_type = 1;
636 word_length = DAVINCI_AUDIO_WORD_8;
637 break;
638
639 case SNDRV_PCM_FORMAT_S16_LE:
640 dma_params->data_type = 2;
641 word_length = DAVINCI_AUDIO_WORD_16;
642 break;
643
644 case SNDRV_PCM_FORMAT_S32_LE:
645 dma_params->data_type = 4;
646 word_length = DAVINCI_AUDIO_WORD_32;
647 break;
648
649 default:
650 printk(KERN_WARNING "davinci-mcasp: unsupported PCM format");
651 return -EINVAL;
652 }
653 davinci_config_channel_size(dev, word_length);
654
655 return 0;
656}
657
658static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
659 int cmd, struct snd_soc_dai *cpu_dai)
660{
661 struct snd_soc_pcm_runtime *rtd = substream->private_data;
662 struct davinci_audio_dev *dev = rtd->dai->cpu_dai->private_data;
663 int ret = 0;
664
665 switch (cmd) {
666 case SNDRV_PCM_TRIGGER_START:
667 case SNDRV_PCM_TRIGGER_RESUME:
668 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
669 davinci_mcasp_start(dev, substream->stream);
670 break;
671
672 case SNDRV_PCM_TRIGGER_STOP:
673 case SNDRV_PCM_TRIGGER_SUSPEND:
674 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
675 davinci_mcasp_stop(dev, substream->stream);
676 break;
677
678 default:
679 ret = -EINVAL;
680 }
681
682 return ret;
683}
684
685static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
686 .startup = davinci_mcasp_startup,
687 .trigger = davinci_mcasp_trigger,
688 .hw_params = davinci_mcasp_hw_params,
689 .set_fmt = davinci_mcasp_set_dai_fmt,
690
691};
692
693struct snd_soc_dai davinci_mcasp_dai[] = {
694 {
695 .name = "davinci-i2s",
696 .id = 0,
697 .playback = {
698 .channels_min = 2,
699 .channels_max = 2,
700 .rates = DAVINCI_MCASP_RATES,
701 .formats = SNDRV_PCM_FMTBIT_S8 |
702 SNDRV_PCM_FMTBIT_S16_LE |
703 SNDRV_PCM_FMTBIT_S32_LE,
704 },
705 .capture = {
706 .channels_min = 2,
707 .channels_max = 2,
708 .rates = DAVINCI_MCASP_RATES,
709 .formats = SNDRV_PCM_FMTBIT_S8 |
710 SNDRV_PCM_FMTBIT_S16_LE |
711 SNDRV_PCM_FMTBIT_S32_LE,
712 },
713 .ops = &davinci_mcasp_dai_ops,
714
715 },
716 {
717 .name = "davinci-dit",
718 .id = 1,
719 .playback = {
720 .channels_min = 1,
721 .channels_max = 384,
722 .rates = DAVINCI_MCASP_RATES,
723 .formats = SNDRV_PCM_FMTBIT_S16_LE,
724 },
725 .ops = &davinci_mcasp_dai_ops,
726 },
727
728};
729EXPORT_SYMBOL_GPL(davinci_mcasp_dai);
730
731static int davinci_mcasp_probe(struct platform_device *pdev)
732{
733 struct davinci_pcm_dma_params *dma_data;
734 struct resource *mem, *ioarea, *res;
735 struct snd_platform_data *pdata;
736 struct davinci_audio_dev *dev;
737 int count = 0;
738 int ret = 0;
739
740 dev = kzalloc(sizeof(struct davinci_audio_dev), GFP_KERNEL);
741 if (!dev)
742 return -ENOMEM;
743
744 dma_data = kzalloc(sizeof(struct davinci_pcm_dma_params) * 2,
745 GFP_KERNEL);
746 if (!dma_data) {
747 ret = -ENOMEM;
748 goto err_release_dev;
749 }
750
751 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
752 if (!mem) {
753 dev_err(&pdev->dev, "no mem resource?\n");
754 ret = -ENODEV;
755 goto err_release_data;
756 }
757
758 ioarea = request_mem_region(mem->start,
759 (mem->end - mem->start) + 1, pdev->name);
760 if (!ioarea) {
761 dev_err(&pdev->dev, "Audio region already claimed\n");
762 ret = -EBUSY;
763 goto err_release_data;
764 }
765
766 pdata = pdev->dev.platform_data;
767 dev->clk = clk_get(&pdev->dev, NULL);
768 if (IS_ERR(dev->clk)) {
769 ret = -ENODEV;
770 goto err_release_region;
771 }
772
773 clk_enable(dev->clk);
774
775 dev->base = (void __iomem *)IO_ADDRESS(mem->start);
776 dev->op_mode = pdata->op_mode;
777 dev->tdm_slots = pdata->tdm_slots;
778 dev->num_serializer = pdata->num_serializer;
779 dev->serial_dir = pdata->serial_dir;
780 dev->codec_fmt = pdata->codec_fmt;
781
782 dma_data[count].name = "I2S PCM Stereo out";
783 dma_data[count].eventq_no = pdata->eventq_no;
784 dma_data[count].dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
785 io_v2p(dev->base));
786 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &dma_data[count];
787
788 /* first TX, then RX */
789 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
790 if (!res) {
791 dev_err(&pdev->dev, "no DMA resource\n");
792 goto err_release_region;
793 }
794
795 dma_data[count].channel = res->start;
796 count++;
797 dma_data[count].name = "I2S PCM Stereo in";
798 dma_data[count].eventq_no = pdata->eventq_no;
799 dma_data[count].dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
800 io_v2p(dev->base));
801 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &dma_data[count];
802
803 res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
804 if (!res) {
805 dev_err(&pdev->dev, "no DMA resource\n");
806 goto err_release_region;
807 }
808
809 dma_data[count].channel = res->start;
810 davinci_mcasp_dai[pdev->id].private_data = dev;
811 davinci_mcasp_dai[pdev->id].dev = &pdev->dev;
812 ret = snd_soc_register_dai(&davinci_mcasp_dai[pdev->id]);
813
814 if (ret != 0)
815 goto err_release_region;
816 return 0;
817
818err_release_region:
819 release_mem_region(mem->start, (mem->end - mem->start) + 1);
820err_release_data:
821 kfree(dma_data);
822err_release_dev:
823 kfree(dev);
824
825 return ret;
826}
827
828static int davinci_mcasp_remove(struct platform_device *pdev)
829{
830 struct davinci_pcm_dma_params *dma_data;
831 struct davinci_audio_dev *dev;
832 struct resource *mem;
833
834 snd_soc_unregister_dai(&davinci_mcasp_dai[pdev->id]);
835 dev = davinci_mcasp_dai[pdev->id].private_data;
836 clk_disable(dev->clk);
837 clk_put(dev->clk);
838 dev->clk = NULL;
839
840 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
841 release_mem_region(mem->start, (mem->end - mem->start) + 1);
842
843 dma_data = dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
844 kfree(dma_data);
845 kfree(dev);
846
847 return 0;
848}
849
850static struct platform_driver davinci_mcasp_driver = {
851 .probe = davinci_mcasp_probe,
852 .remove = davinci_mcasp_remove,
853 .driver = {
854 .name = "davinci-mcasp",
855 .owner = THIS_MODULE,
856 },
857};
858
859static int __init davinci_mcasp_init(void)
860{
861 return platform_driver_register(&davinci_mcasp_driver);
862}
863module_init(davinci_mcasp_init);
864
865static void __exit davinci_mcasp_exit(void)
866{
867 platform_driver_unregister(&davinci_mcasp_driver);
868}
869module_exit(davinci_mcasp_exit);
870
871MODULE_AUTHOR("Steve Chen");
872MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
873MODULE_LICENSE("GPL");
874
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
new file mode 100644
index 000000000000..36b71047a06c
--- /dev/null
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -0,0 +1,55 @@
1/*
2 * ALSA SoC McASP Audio Layer for TI DAVINCI processor
3 *
4 * MCASP related definitions
5 *
6 * Author: Nirmal Pandey <n-pandey@ti.com>,
7 * Suresh Rajashekara <suresh.r@ti.com>
8 * Steve Chen <schen@.mvista.com>
9 *
10 * Copyright: (C) 2009 MontaVista Software, Inc., <source@mvista.com>
11 * Copyright: (C) 2009 Texas Instruments, India
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
18#ifndef DAVINCI_MCASP_H
19#define DAVINCI_MCASP_H
20
21#include <linux/io.h>
22#include <mach/asp.h>
23#include "davinci-pcm.h"
24
25extern struct snd_soc_dai davinci_mcasp_dai[];
26
27#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_96000
28#define DAVINCI_MCASP_I2S_DAI 0
29#define DAVINCI_MCASP_DIT_DAI 1
30
31enum {
32 DAVINCI_AUDIO_WORD_8 = 0,
33 DAVINCI_AUDIO_WORD_12,
34 DAVINCI_AUDIO_WORD_16,
35 DAVINCI_AUDIO_WORD_20,
36 DAVINCI_AUDIO_WORD_24,
37 DAVINCI_AUDIO_WORD_32,
38 DAVINCI_AUDIO_WORD_28, /* This is only valid for McASP */
39};
40
41struct davinci_audio_dev {
42 void __iomem *base;
43 int sample_rate;
44 struct clk *clk;
45 struct davinci_pcm_dma_params *dma_params[2];
46 unsigned int codec_fmt;
47
48 /* McASP specific data */
49 int tdm_slots;
50 u8 op_mode;
51 u8 num_serializer;
52 u8 *serial_dir;
53};
54
55#endif /* DAVINCI_MCASP_H */
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index a05996588489..ab43a539c11d 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -206,6 +206,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
206 /* Copy self-linked parameter RAM entry into master channel */ 206 /* Copy self-linked parameter RAM entry into master channel */
207 edma_read_slot(prtd->slave_lch, &temp); 207 edma_read_slot(prtd->slave_lch, &temp);
208 edma_write_slot(prtd->master_lch, &temp); 208 edma_write_slot(prtd->master_lch, &temp);
209 davinci_pcm_enqueue_dma(substream);
209 210
210 return 0; 211 return 0;
211} 212}
@@ -243,6 +244,11 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)
243 int ret = 0; 244 int ret = 0;
244 245
245 snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware); 246 snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware);
247 /* ensure that buffer size is a multiple of period size */
248 ret = snd_pcm_hw_constraint_integer(runtime,
249 SNDRV_PCM_HW_PARAM_PERIODS);
250 if (ret < 0)
251 return ret;
246 252
247 prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL); 253 prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL);
248 if (prtd == NULL) 254 if (prtd == NULL)
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index 62cb4eb07e34..eb4287faa3d5 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -12,17 +12,19 @@
12#ifndef _DAVINCI_PCM_H 12#ifndef _DAVINCI_PCM_H
13#define _DAVINCI_PCM_H 13#define _DAVINCI_PCM_H
14 14
15#include <mach/edma.h>
16#include <mach/asp.h>
17
18
15struct davinci_pcm_dma_params { 19struct davinci_pcm_dma_params {
16 char *name; /* stream identifier */ 20 char *name; /* stream identifier */
17 int channel; /* sync dma channel ID */ 21 int channel; /* sync dma channel ID */
18 dma_addr_t dma_addr; /* device physical address for DMA */ 22 dma_addr_t dma_addr; /* device physical address for DMA */
19 unsigned int data_type; /* xfer data type */ 23 enum dma_event_q eventq_no; /* event queue number */
24 unsigned char data_type; /* xfer data type */
25 unsigned char convert_mono_stereo;
20}; 26};
21 27
22struct evm_snd_platform_data {
23 int tx_dma_ch;
24 int rx_dma_ch;
25};
26 28
27extern struct snd_soc_platform davinci_soc_platform; 29extern struct snd_soc_platform davinci_soc_platform;
28 30
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index efec33a1c5bd..9ff62e3a9b1d 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -69,6 +69,23 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
69 69
70static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s) 70static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)
71{ 71{
72 if (s->appl_ptr > s->runtime->control->appl_ptr) {
73 /*
74 * In this case s->runtime->control->appl_ptr has wrapped around.
75 * Play the data to the end of the boundary, then wrap our own
76 * appl_ptr back around.
77 */
78 while (s->appl_ptr < s->runtime->boundary) {
79 if (bcom_queue_full(s->bcom_task))
80 return;
81
82 s->appl_ptr += s->period_size;
83
84 psc_dma_bcom_enqueue_next_buffer(s);
85 }
86 s->appl_ptr -= s->runtime->boundary;
87 }
88
72 while (s->appl_ptr < s->runtime->control->appl_ptr) { 89 while (s->appl_ptr < s->runtime->control->appl_ptr) {
73 90
74 if (bcom_queue_full(s->bcom_task)) 91 if (bcom_queue_full(s->bcom_task))
@@ -456,6 +473,7 @@ int mpc5200_audio_dma_create(struct of_device *op)
456 return -ENODEV; 473 return -ENODEV;
457 474
458 spin_lock_init(&psc_dma->lock); 475 spin_lock_init(&psc_dma->lock);
476 mutex_init(&psc_dma->mutex);
459 psc_dma->id = be32_to_cpu(*prop); 477 psc_dma->id = be32_to_cpu(*prop);
460 psc_dma->irq = irq; 478 psc_dma->irq = irq;
461 psc_dma->psc_regs = regs; 479 psc_dma->psc_regs = regs;
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index 2000803f06a7..8d396bb9d9fe 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -55,6 +55,7 @@ struct psc_dma {
55 unsigned int irq; 55 unsigned int irq;
56 struct device *dev; 56 struct device *dev;
57 spinlock_t lock; 57 spinlock_t lock;
58 struct mutex mutex;
58 u32 sicr; 59 u32 sicr;
59 uint sysclk; 60 uint sysclk;
60 int imr; 61 int imr;
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 794a247b3eb5..c4ae3e096bb9 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -12,6 +12,7 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/of_device.h> 13#include <linux/of_device.h>
14#include <linux/of_platform.h> 14#include <linux/of_platform.h>
15#include <linux/delay.h>
15 16
16#include <sound/pcm.h> 17#include <sound/pcm.h>
17#include <sound/pcm_params.h> 18#include <sound/pcm_params.h>
@@ -34,13 +35,20 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
34 int status; 35 int status;
35 unsigned int val; 36 unsigned int val;
36 37
38 mutex_lock(&psc_dma->mutex);
39
37 /* Wait for command send status zero = ready */ 40 /* Wait for command send status zero = ready */
38 status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & 41 status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
39 MPC52xx_PSC_SR_CMDSEND), 100, 0); 42 MPC52xx_PSC_SR_CMDSEND), 100, 0);
40 if (status == 0) { 43 if (status == 0) {
41 pr_err("timeout on ac97 bus (rdy)\n"); 44 pr_err("timeout on ac97 bus (rdy)\n");
45 mutex_unlock(&psc_dma->mutex);
42 return -ENODEV; 46 return -ENODEV;
43 } 47 }
48
49 /* Force clear the data valid bit */
50 in_be32(&psc_dma->psc_regs->ac97_data);
51
44 /* Send the read */ 52 /* Send the read */
45 out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24)); 53 out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
46 54
@@ -50,16 +58,19 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
50 if (status == 0) { 58 if (status == 0) {
51 pr_err("timeout on ac97 read (val) %x\n", 59 pr_err("timeout on ac97 read (val) %x\n",
52 in_be16(&psc_dma->psc_regs->sr_csr.status)); 60 in_be16(&psc_dma->psc_regs->sr_csr.status));
61 mutex_unlock(&psc_dma->mutex);
53 return -ENODEV; 62 return -ENODEV;
54 } 63 }
55 /* Get the data */ 64 /* Get the data */
56 val = in_be32(&psc_dma->psc_regs->ac97_data); 65 val = in_be32(&psc_dma->psc_regs->ac97_data);
57 if (((val >> 24) & 0x7f) != reg) { 66 if (((val >> 24) & 0x7f) != reg) {
58 pr_err("reg echo error on ac97 read\n"); 67 pr_err("reg echo error on ac97 read\n");
68 mutex_unlock(&psc_dma->mutex);
59 return -ENODEV; 69 return -ENODEV;
60 } 70 }
61 val = (val >> 8) & 0xffff; 71 val = (val >> 8) & 0xffff;
62 72
73 mutex_unlock(&psc_dma->mutex);
63 return (unsigned short) val; 74 return (unsigned short) val;
64} 75}
65 76
@@ -68,16 +79,21 @@ static void psc_ac97_write(struct snd_ac97 *ac97,
68{ 79{
69 int status; 80 int status;
70 81
82 mutex_lock(&psc_dma->mutex);
83
71 /* Wait for command status zero = ready */ 84 /* Wait for command status zero = ready */
72 status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & 85 status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
73 MPC52xx_PSC_SR_CMDSEND), 100, 0); 86 MPC52xx_PSC_SR_CMDSEND), 100, 0);
74 if (status == 0) { 87 if (status == 0) {
75 pr_err("timeout on ac97 bus (write)\n"); 88 pr_err("timeout on ac97 bus (write)\n");
76 return; 89 goto out;
77 } 90 }
78 /* Write data */ 91 /* Write data */
79 out_be32(&psc_dma->psc_regs->ac97_cmd, 92 out_be32(&psc_dma->psc_regs->ac97_cmd,
80 ((reg & 0x7f) << 24) | (val << 8)); 93 ((reg & 0x7f) << 24) | (val << 8));
94
95 out:
96 mutex_unlock(&psc_dma->mutex);
81} 97}
82 98
83static void psc_ac97_warm_reset(struct snd_ac97 *ac97) 99static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
@@ -97,7 +113,7 @@ static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
97 out_8(&regs->op1, MPC52xx_PSC_OP_RES); 113 out_8(&regs->op1, MPC52xx_PSC_OP_RES);
98 udelay(10); 114 udelay(10);
99 out_8(&regs->op0, MPC52xx_PSC_OP_RES); 115 out_8(&regs->op0, MPC52xx_PSC_OP_RES);
100 udelay(50); 116 msleep(1);
101 psc_ac97_warm_reset(ac97); 117 psc_ac97_warm_reset(ac97);
102} 118}
103 119
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index a5a90e594535..2dee9839be86 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -15,6 +15,14 @@ config SND_OMAP_SOC_N810
15 help 15 help
16 Say Y if you want to add support for SoC audio on Nokia N810. 16 Say Y if you want to add support for SoC audio on Nokia N810.
17 17
18config SND_OMAP_SOC_AMS_DELTA
19 tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
20 depends on SND_OMAP_SOC && MACH_AMS_DELTA
21 select SND_OMAP_SOC_MCBSP
22 select SND_SOC_CX20442
23 help
24 Say Y if you want to add support for SoC audio on Amstrad Delta.
25
18config SND_OMAP_SOC_OSK5912 26config SND_OMAP_SOC_OSK5912
19 tristate "SoC Audio support for omap osk5912" 27 tristate "SoC Audio support for omap osk5912"
20 depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C 28 depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index fefc48f02bd3..02d69471dcb5 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
7 7
8# OMAP Machine Support 8# OMAP Machine Support
9snd-soc-n810-objs := n810.o 9snd-soc-n810-objs := n810.o
10snd-soc-ams-delta-objs := ams-delta.o
10snd-soc-osk5912-objs := osk5912.o 11snd-soc-osk5912-objs := osk5912.o
11snd-soc-overo-objs := overo.o 12snd-soc-overo-objs := overo.o
12snd-soc-omap2evm-objs := omap2evm.o 13snd-soc-omap2evm-objs := omap2evm.o
@@ -17,6 +18,7 @@ snd-soc-omap3beagle-objs := omap3beagle.o
17snd-soc-zoom2-objs := zoom2.o 18snd-soc-zoom2-objs := zoom2.o
18 19
19obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o 20obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
21obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
20obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o 22obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
21obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o 23obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
22obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o 24obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
new file mode 100644
index 000000000000..4f35b1f18cb9
--- /dev/null
+++ b/sound/soc/omap/ams-delta.c
@@ -0,0 +1,646 @@
1/*
2 * ams-delta.c -- SoC audio for Amstrad E3 (Delta) videophone
3 *
4 * Copyright (C) 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
5 *
6 * Initially based on sound/soc/omap/osk5912.x
7 * Copyright (C) 2008 Mistral Solutions
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25#include <linux/gpio.h>
26#include <linux/spinlock.h>
27#include <linux/tty.h>
28
29#include <sound/soc-dapm.h>
30#include <sound/jack.h>
31
32#include <asm/mach-types.h>
33
34#include <mach/board-ams-delta.h>
35#include <mach/mcbsp.h>
36
37#include "omap-mcbsp.h"
38#include "omap-pcm.h"
39#include "../codecs/cx20442.h"
40
41
42/* Board specific DAPM widgets */
43 const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
44 /* Handset */
45 SND_SOC_DAPM_MIC("Mouthpiece", NULL),
46 SND_SOC_DAPM_HP("Earpiece", NULL),
47 /* Handsfree/Speakerphone */
48 SND_SOC_DAPM_MIC("Microphone", NULL),
49 SND_SOC_DAPM_SPK("Speaker", NULL),
50};
51
52/* How they are connected to codec pins */
53static const struct snd_soc_dapm_route ams_delta_audio_map[] = {
54 {"TELIN", NULL, "Mouthpiece"},
55 {"Earpiece", NULL, "TELOUT"},
56
57 {"MIC", NULL, "Microphone"},
58 {"Speaker", NULL, "SPKOUT"},
59};
60
61/*
62 * Controls, functional after the modem line discipline is activated.
63 */
64
65/* Virtual switch: audio input/output constellations */
66static const char *ams_delta_audio_mode[] =
67 {"Mixed", "Handset", "Handsfree", "Speakerphone"};
68
69/* Selection <-> pin translation */
70#define AMS_DELTA_MOUTHPIECE 0
71#define AMS_DELTA_EARPIECE 1
72#define AMS_DELTA_MICROPHONE 2
73#define AMS_DELTA_SPEAKER 3
74#define AMS_DELTA_AGC 4
75
76#define AMS_DELTA_MIXED ((1 << AMS_DELTA_EARPIECE) | \
77 (1 << AMS_DELTA_MICROPHONE))
78#define AMS_DELTA_HANDSET ((1 << AMS_DELTA_MOUTHPIECE) | \
79 (1 << AMS_DELTA_EARPIECE))
80#define AMS_DELTA_HANDSFREE ((1 << AMS_DELTA_MICROPHONE) | \
81 (1 << AMS_DELTA_SPEAKER))
82#define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC))
83
84unsigned short ams_delta_audio_mode_pins[] = {
85 AMS_DELTA_MIXED,
86 AMS_DELTA_HANDSET,
87 AMS_DELTA_HANDSFREE,
88 AMS_DELTA_SPEAKERPHONE,
89};
90
91static unsigned short ams_delta_audio_agc;
92
93static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
94 struct snd_ctl_elem_value *ucontrol)
95{
96 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
97 struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
98 unsigned short pins;
99 int pin, changed = 0;
100
101 /* Refuse any mode changes if we are not able to control the codec. */
102 if (!codec->control_data)
103 return -EUNATCH;
104
105 if (ucontrol->value.enumerated.item[0] >= control->max)
106 return -EINVAL;
107
108 mutex_lock(&codec->mutex);
109
110 /* Translate selection to bitmap */
111 pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]];
112
113 /* Setup pins after corresponding bits if changed */
114 pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE));
115 if (pin != snd_soc_dapm_get_pin_status(codec, "Mouthpiece")) {
116 changed = 1;
117 if (pin)
118 snd_soc_dapm_enable_pin(codec, "Mouthpiece");
119 else
120 snd_soc_dapm_disable_pin(codec, "Mouthpiece");
121 }
122 pin = !!(pins & (1 << AMS_DELTA_EARPIECE));
123 if (pin != snd_soc_dapm_get_pin_status(codec, "Earpiece")) {
124 changed = 1;
125 if (pin)
126 snd_soc_dapm_enable_pin(codec, "Earpiece");
127 else
128 snd_soc_dapm_disable_pin(codec, "Earpiece");
129 }
130 pin = !!(pins & (1 << AMS_DELTA_MICROPHONE));
131 if (pin != snd_soc_dapm_get_pin_status(codec, "Microphone")) {
132 changed = 1;
133 if (pin)
134 snd_soc_dapm_enable_pin(codec, "Microphone");
135 else
136 snd_soc_dapm_disable_pin(codec, "Microphone");
137 }
138 pin = !!(pins & (1 << AMS_DELTA_SPEAKER));
139 if (pin != snd_soc_dapm_get_pin_status(codec, "Speaker")) {
140 changed = 1;
141 if (pin)
142 snd_soc_dapm_enable_pin(codec, "Speaker");
143 else
144 snd_soc_dapm_disable_pin(codec, "Speaker");
145 }
146 pin = !!(pins & (1 << AMS_DELTA_AGC));
147 if (pin != ams_delta_audio_agc) {
148 ams_delta_audio_agc = pin;
149 changed = 1;
150 if (pin)
151 snd_soc_dapm_enable_pin(codec, "AGCIN");
152 else
153 snd_soc_dapm_disable_pin(codec, "AGCIN");
154 }
155 if (changed)
156 snd_soc_dapm_sync(codec);
157
158 mutex_unlock(&codec->mutex);
159
160 return changed;
161}
162
163static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
164 struct snd_ctl_elem_value *ucontrol)
165{
166 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
167 unsigned short pins, mode;
168
169 pins = ((snd_soc_dapm_get_pin_status(codec, "Mouthpiece") <<
170 AMS_DELTA_MOUTHPIECE) |
171 (snd_soc_dapm_get_pin_status(codec, "Earpiece") <<
172 AMS_DELTA_EARPIECE));
173 if (pins)
174 pins |= (snd_soc_dapm_get_pin_status(codec, "Microphone") <<
175 AMS_DELTA_MICROPHONE);
176 else
177 pins = ((snd_soc_dapm_get_pin_status(codec, "Microphone") <<
178 AMS_DELTA_MICROPHONE) |
179 (snd_soc_dapm_get_pin_status(codec, "Speaker") <<
180 AMS_DELTA_SPEAKER) |
181 (ams_delta_audio_agc << AMS_DELTA_AGC));
182
183 for (mode = 0; mode < ARRAY_SIZE(ams_delta_audio_mode); mode++)
184 if (pins == ams_delta_audio_mode_pins[mode])
185 break;
186
187 if (mode >= ARRAY_SIZE(ams_delta_audio_mode))
188 return -EINVAL;
189
190 ucontrol->value.enumerated.item[0] = mode;
191
192 return 0;
193}
194
195static const struct soc_enum ams_delta_audio_enum[] = {
196 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ams_delta_audio_mode),
197 ams_delta_audio_mode),
198};
199
200static const struct snd_kcontrol_new ams_delta_audio_controls[] = {
201 SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum[0],
202 ams_delta_get_audio_mode, ams_delta_set_audio_mode),
203};
204
205/* Hook switch */
206static struct snd_soc_jack ams_delta_hook_switch;
207static struct snd_soc_jack_gpio ams_delta_hook_switch_gpios[] = {
208 {
209 .gpio = 4,
210 .name = "hook_switch",
211 .report = SND_JACK_HEADSET,
212 .invert = 1,
213 .debounce_time = 150,
214 }
215};
216
217/* After we are able to control the codec over the modem,
218 * the hook switch can be used for dynamic DAPM reconfiguration. */
219static struct snd_soc_jack_pin ams_delta_hook_switch_pins[] = {
220 /* Handset */
221 {
222 .pin = "Mouthpiece",
223 .mask = SND_JACK_MICROPHONE,
224 },
225 {
226 .pin = "Earpiece",
227 .mask = SND_JACK_HEADPHONE,
228 },
229 /* Handsfree */
230 {
231 .pin = "Microphone",
232 .mask = SND_JACK_MICROPHONE,
233 .invert = 1,
234 },
235 {
236 .pin = "Speaker",
237 .mask = SND_JACK_HEADPHONE,
238 .invert = 1,
239 },
240};
241
242
243/*
244 * Modem line discipline, required for making above controls functional.
245 * Activated from userspace with ldattach, possibly invoked from udev rule.
246 */
247
248/* To actually apply any modem controlled configuration changes to the codec,
249 * we must connect codec DAI pins to the modem for a moment. Be carefull not
250 * to interfere with our digital mute function that shares the same hardware. */
251static struct timer_list cx81801_timer;
252static bool cx81801_cmd_pending;
253static bool ams_delta_muted;
254static DEFINE_SPINLOCK(ams_delta_lock);
255
256static void cx81801_timeout(unsigned long data)
257{
258 int muted;
259
260 spin_lock(&ams_delta_lock);
261 cx81801_cmd_pending = 0;
262 muted = ams_delta_muted;
263 spin_unlock(&ams_delta_lock);
264
265 /* Reconnect the codec DAI back from the modem to the CPU DAI
266 * only if digital mute still off */
267 if (!muted)
268 ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
269}
270
271/* Line discipline .open() */
272static int cx81801_open(struct tty_struct *tty)
273{
274 return v253_ops.open(tty);
275}
276
277/* Line discipline .close() */
278static void cx81801_close(struct tty_struct *tty)
279{
280 struct snd_soc_codec *codec = tty->disc_data;
281
282 del_timer_sync(&cx81801_timer);
283
284 v253_ops.close(tty);
285
286 /* Prevent the hook switch from further changing the DAPM pins */
287 INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
288
289 /* Revert back to default audio input/output constellation */
290 snd_soc_dapm_disable_pin(codec, "Mouthpiece");
291 snd_soc_dapm_enable_pin(codec, "Earpiece");
292 snd_soc_dapm_enable_pin(codec, "Microphone");
293 snd_soc_dapm_disable_pin(codec, "Speaker");
294 snd_soc_dapm_disable_pin(codec, "AGCIN");
295 snd_soc_dapm_sync(codec);
296}
297
298/* Line discipline .hangup() */
299static int cx81801_hangup(struct tty_struct *tty)
300{
301 cx81801_close(tty);
302 return 0;
303}
304
305/* Line discipline .recieve_buf() */
306static void cx81801_receive(struct tty_struct *tty,
307 const unsigned char *cp, char *fp, int count)
308{
309 struct snd_soc_codec *codec = tty->disc_data;
310 const unsigned char *c;
311 int apply, ret;
312
313 if (!codec->control_data) {
314 /* First modem response, complete setup procedure */
315
316 /* Initialize timer used for config pulse generation */
317 setup_timer(&cx81801_timer, cx81801_timeout, 0);
318
319 v253_ops.receive_buf(tty, cp, fp, count);
320
321 /* Link hook switch to DAPM pins */
322 ret = snd_soc_jack_add_pins(&ams_delta_hook_switch,
323 ARRAY_SIZE(ams_delta_hook_switch_pins),
324 ams_delta_hook_switch_pins);
325 if (ret)
326 dev_warn(codec->socdev->card->dev,
327 "Failed to link hook switch to DAPM pins, "
328 "will continue with hook switch unlinked.\n");
329
330 return;
331 }
332
333 v253_ops.receive_buf(tty, cp, fp, count);
334
335 for (c = &cp[count - 1]; c >= cp; c--) {
336 if (*c != '\r')
337 continue;
338 /* Complete modem response received, apply config to codec */
339
340 spin_lock_bh(&ams_delta_lock);
341 mod_timer(&cx81801_timer, jiffies + msecs_to_jiffies(150));
342 apply = !ams_delta_muted && !cx81801_cmd_pending;
343 cx81801_cmd_pending = 1;
344 spin_unlock_bh(&ams_delta_lock);
345
346 /* Apply config pulse by connecting the codec to the modem
347 * if not already done */
348 if (apply)
349 ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC,
350 AMS_DELTA_LATCH2_MODEM_CODEC);
351 break;
352 }
353}
354
355/* Line discipline .write_wakeup() */
356static void cx81801_wakeup(struct tty_struct *tty)
357{
358 v253_ops.write_wakeup(tty);
359}
360
361static struct tty_ldisc_ops cx81801_ops = {
362 .magic = TTY_LDISC_MAGIC,
363 .name = "cx81801",
364 .owner = THIS_MODULE,
365 .open = cx81801_open,
366 .close = cx81801_close,
367 .hangup = cx81801_hangup,
368 .receive_buf = cx81801_receive,
369 .write_wakeup = cx81801_wakeup,
370};
371
372
373/*
374 * Even if not very usefull, the sound card can still work without any of the
375 * above functonality activated. You can still control its audio input/output
376 * constellation and speakerphone gain from userspace by issueing AT commands
377 * over the modem port.
378 */
379
380static int ams_delta_hw_params(struct snd_pcm_substream *substream,
381 struct snd_pcm_hw_params *params)
382{
383 struct snd_soc_pcm_runtime *rtd = substream->private_data;
384
385 /* Set cpu DAI configuration */
386 return snd_soc_dai_set_fmt(rtd->dai->cpu_dai,
387 SND_SOC_DAIFMT_DSP_A |
388 SND_SOC_DAIFMT_NB_NF |
389 SND_SOC_DAIFMT_CBM_CFM);
390}
391
392static struct snd_soc_ops ams_delta_ops = {
393 .hw_params = ams_delta_hw_params,
394};
395
396
397/* Board specific codec bias level control */
398static int ams_delta_set_bias_level(struct snd_soc_card *card,
399 enum snd_soc_bias_level level)
400{
401 struct snd_soc_codec *codec = card->codec;
402
403 switch (level) {
404 case SND_SOC_BIAS_ON:
405 case SND_SOC_BIAS_PREPARE:
406 case SND_SOC_BIAS_STANDBY:
407 if (codec->bias_level == SND_SOC_BIAS_OFF)
408 ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
409 AMS_DELTA_LATCH2_MODEM_NRESET);
410 break;
411 case SND_SOC_BIAS_OFF:
412 if (codec->bias_level != SND_SOC_BIAS_OFF)
413 ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
414 0);
415 }
416 codec->bias_level = level;
417
418 return 0;
419}
420
421/* Digital mute implemented using modem/CPU multiplexer.
422 * Shares hardware with codec config pulse generation */
423static bool ams_delta_muted = 1;
424
425static int ams_delta_digital_mute(struct snd_soc_dai *dai, int mute)
426{
427 int apply;
428
429 if (ams_delta_muted == mute)
430 return 0;
431
432 spin_lock_bh(&ams_delta_lock);
433 ams_delta_muted = mute;
434 apply = !cx81801_cmd_pending;
435 spin_unlock_bh(&ams_delta_lock);
436
437 if (apply)
438 ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC,
439 mute ? AMS_DELTA_LATCH2_MODEM_CODEC : 0);
440 return 0;
441}
442
443/* Our codec DAI probably doesn't have its own .ops structure */
444static struct snd_soc_dai_ops ams_delta_dai_ops = {
445 .digital_mute = ams_delta_digital_mute,
446};
447
448/* Will be used if the codec ever has its own digital_mute function */
449static int ams_delta_startup(struct snd_pcm_substream *substream)
450{
451 return ams_delta_digital_mute(NULL, 0);
452}
453
454static void ams_delta_shutdown(struct snd_pcm_substream *substream)
455{
456 ams_delta_digital_mute(NULL, 1);
457}
458
459
460/*
461 * Card initialization
462 */
463
464static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
465{
466 struct snd_soc_dai *codec_dai = codec->dai;
467 struct snd_soc_card *card = codec->socdev->card;
468 int ret;
469 /* Codec is ready, now add/activate board specific controls */
470
471 /* Set up digital mute if not provided by the codec */
472 if (!codec_dai->ops) {
473 codec_dai->ops = &ams_delta_dai_ops;
474 } else if (!codec_dai->ops->digital_mute) {
475 codec_dai->ops->digital_mute = ams_delta_digital_mute;
476 } else {
477 ams_delta_ops.startup = ams_delta_startup;
478 ams_delta_ops.shutdown = ams_delta_shutdown;
479 }
480
481 /* Set codec bias level */
482 ams_delta_set_bias_level(card, SND_SOC_BIAS_STANDBY);
483
484 /* Add hook switch - can be used to control the codec from userspace
485 * even if line discipline fails */
486 ret = snd_soc_jack_new(card, "hook_switch",
487 SND_JACK_HEADSET, &ams_delta_hook_switch);
488 if (ret)
489 dev_warn(card->dev,
490 "Failed to allocate resources for hook switch, "
491 "will continue without one.\n");
492 else {
493 ret = snd_soc_jack_add_gpios(&ams_delta_hook_switch,
494 ARRAY_SIZE(ams_delta_hook_switch_gpios),
495 ams_delta_hook_switch_gpios);
496 if (ret)
497 dev_warn(card->dev,
498 "Failed to set up hook switch GPIO line, "
499 "will continue with hook switch inactive.\n");
500 }
501
502 /* Register optional line discipline for over the modem control */
503 ret = tty_register_ldisc(N_AMSDELTA, &cx81801_ops);
504 if (ret) {
505 dev_warn(card->dev,
506 "Failed to register line discipline, "
507 "will continue without any controls.\n");
508 return 0;
509 }
510
511 /* Add board specific DAPM widgets and routes */
512 ret = snd_soc_dapm_new_controls(codec, ams_delta_dapm_widgets,
513 ARRAY_SIZE(ams_delta_dapm_widgets));
514 if (ret) {
515 dev_warn(card->dev,
516 "Failed to register DAPM controls, "
517 "will continue without any.\n");
518 return 0;
519 }
520
521 ret = snd_soc_dapm_add_routes(codec, ams_delta_audio_map,
522 ARRAY_SIZE(ams_delta_audio_map));
523 if (ret) {
524 dev_warn(card->dev,
525 "Failed to set up DAPM routes, "
526 "will continue with codec default map.\n");
527 return 0;
528 }
529
530 /* Set up initial pin constellation */
531 snd_soc_dapm_disable_pin(codec, "Mouthpiece");
532 snd_soc_dapm_enable_pin(codec, "Earpiece");
533 snd_soc_dapm_enable_pin(codec, "Microphone");
534 snd_soc_dapm_disable_pin(codec, "Speaker");
535 snd_soc_dapm_disable_pin(codec, "AGCIN");
536 snd_soc_dapm_disable_pin(codec, "AGCOUT");
537 snd_soc_dapm_sync(codec);
538
539 /* Add virtual switch */
540 ret = snd_soc_add_controls(codec, ams_delta_audio_controls,
541 ARRAY_SIZE(ams_delta_audio_controls));
542 if (ret)
543 dev_warn(card->dev,
544 "Failed to register audio mode control, "
545 "will continue without it.\n");
546
547 return 0;
548}
549
550/* DAI glue - connects codec <--> CPU */
551static struct snd_soc_dai_link ams_delta_dai_link = {
552 .name = "CX20442",
553 .stream_name = "CX20442",
554 .cpu_dai = &omap_mcbsp_dai[0],
555 .codec_dai = &cx20442_dai,
556 .init = ams_delta_cx20442_init,
557 .ops = &ams_delta_ops,
558};
559
560/* Audio card driver */
561static struct snd_soc_card ams_delta_audio_card = {
562 .name = "AMS_DELTA",
563 .platform = &omap_soc_platform,
564 .dai_link = &ams_delta_dai_link,
565 .num_links = 1,
566 .set_bias_level = ams_delta_set_bias_level,
567};
568
569/* Audio subsystem */
570static struct snd_soc_device ams_delta_snd_soc_device = {
571 .card = &ams_delta_audio_card,
572 .codec_dev = &cx20442_codec_dev,
573};
574
575/* Module init/exit */
576static struct platform_device *ams_delta_audio_platform_device;
577static struct platform_device *cx20442_platform_device;
578
579static int __init ams_delta_module_init(void)
580{
581 int ret;
582
583 if (!(machine_is_ams_delta()))
584 return -ENODEV;
585
586 ams_delta_audio_platform_device =
587 platform_device_alloc("soc-audio", -1);
588 if (!ams_delta_audio_platform_device)
589 return -ENOMEM;
590
591 platform_set_drvdata(ams_delta_audio_platform_device,
592 &ams_delta_snd_soc_device);
593 ams_delta_snd_soc_device.dev = &ams_delta_audio_platform_device->dev;
594 *(unsigned int *)ams_delta_dai_link.cpu_dai->private_data = OMAP_MCBSP1;
595
596 ret = platform_device_add(ams_delta_audio_platform_device);
597 if (ret)
598 goto err;
599
600 /*
601 * Codec platform device could be registered from elsewhere (board?),
602 * but I do it here as it makes sense only if used with the card.
603 */
604 cx20442_platform_device = platform_device_register_simple("cx20442",
605 -1, NULL, 0);
606 return 0;
607err:
608 platform_device_put(ams_delta_audio_platform_device);
609 return ret;
610}
611module_init(ams_delta_module_init);
612
613static void __exit ams_delta_module_exit(void)
614{
615 struct snd_soc_codec *codec;
616 struct tty_struct *tty;
617
618 if (ams_delta_audio_card.codec) {
619 codec = ams_delta_audio_card.codec;
620
621 if (codec->control_data) {
622 tty = codec->control_data;
623
624 tty_hangup(tty);
625 }
626 }
627
628 if (tty_unregister_ldisc(N_AMSDELTA) != 0)
629 dev_warn(&ams_delta_audio_platform_device->dev,
630 "failed to unregister AMSDELTA line discipline\n");
631
632 snd_soc_jack_free_gpios(&ams_delta_hook_switch,
633 ARRAY_SIZE(ams_delta_hook_switch_gpios),
634 ams_delta_hook_switch_gpios);
635
636 /* Keep modem power on */
637 ams_delta_set_bias_level(&ams_delta_audio_card, SND_SOC_BIAS_STANDBY);
638
639 platform_device_unregister(cx20442_platform_device);
640 platform_device_unregister(ams_delta_audio_platform_device);
641}
642module_exit(ams_delta_module_exit);
643
644MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
645MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone");
646MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index a5d46a7b196a..6a837ffd5d0b 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -183,21 +183,21 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
183 struct snd_soc_pcm_runtime *rtd = substream->private_data; 183 struct snd_soc_pcm_runtime *rtd = substream->private_data;
184 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 184 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
185 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); 185 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
186 int err = 0; 186 int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
187 187
188 switch (cmd) { 188 switch (cmd) {
189 case SNDRV_PCM_TRIGGER_START: 189 case SNDRV_PCM_TRIGGER_START:
190 case SNDRV_PCM_TRIGGER_RESUME: 190 case SNDRV_PCM_TRIGGER_RESUME:
191 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 191 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
192 if (!mcbsp_data->active++) 192 mcbsp_data->active++;
193 omap_mcbsp_start(mcbsp_data->bus_id); 193 omap_mcbsp_start(mcbsp_data->bus_id, play, !play);
194 break; 194 break;
195 195
196 case SNDRV_PCM_TRIGGER_STOP: 196 case SNDRV_PCM_TRIGGER_STOP:
197 case SNDRV_PCM_TRIGGER_SUSPEND: 197 case SNDRV_PCM_TRIGGER_SUSPEND:
198 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 198 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
199 if (!--mcbsp_data->active) 199 omap_mcbsp_stop(mcbsp_data->bus_id, play, !play);
200 omap_mcbsp_stop(mcbsp_data->bus_id); 200 mcbsp_data->active--;
201 break; 201 break;
202 default: 202 default:
203 err = -EINVAL; 203 err = -EINVAL;
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 84a1950880eb..c3c931d4537a 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -330,7 +330,7 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
330 } 330 }
331} 331}
332 332
333int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, 333static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
334 struct snd_pcm *pcm) 334 struct snd_pcm *pcm)
335{ 335{
336 int ret = 0; 336 int ret = 0;
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index c51594d8fd13..f7e5b7488c35 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -24,6 +24,7 @@
24 24
25#include <linux/clk.h> 25#include <linux/clk.h>
26#include <linux/platform_device.h> 26#include <linux/platform_device.h>
27#include <linux/i2c/twl4030.h>
27#include <sound/core.h> 28#include <sound/core.h>
28#include <sound/pcm.h> 29#include <sound/pcm.h>
29#include <sound/soc.h> 30#include <sound/soc.h>
@@ -39,6 +40,9 @@
39#include "omap-pcm.h" 40#include "omap-pcm.h"
40#include "../codecs/twl4030.h" 41#include "../codecs/twl4030.h"
41 42
43#define TWL4030_INTBR_PMBR1 0x0D
44#define EXTMUTE(value) (value << 2)
45
42static struct snd_soc_card snd_soc_sdp3430; 46static struct snd_soc_card snd_soc_sdp3430;
43 47
44static int sdp3430_hw_params(struct snd_pcm_substream *substream, 48static int sdp3430_hw_params(struct snd_pcm_substream *substream,
@@ -280,6 +284,7 @@ static struct snd_soc_card snd_soc_sdp3430 = {
280static struct twl4030_setup_data twl4030_setup = { 284static struct twl4030_setup_data twl4030_setup = {
281 .ramp_delay_value = 3, 285 .ramp_delay_value = 3,
282 .sysclk = 26000, 286 .sysclk = 26000,
287 .hs_extmute = 1,
283}; 288};
284 289
285/* Audio subsystem */ 290/* Audio subsystem */
@@ -312,6 +317,10 @@ static int __init sdp3430_soc_init(void)
312 *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */ 317 *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
313 *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ 318 *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
314 319
320 /* Set TWL4030 GPIO6 as EXTMUTE signal */
321 twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, EXTMUTE(0x02),
322 TWL4030_MODULE_INTBR);
323
315 ret = platform_device_add(sdp3430_snd_device); 324 ret = platform_device_add(sdp3430_snd_device);
316 if (ret) 325 if (ret)
317 goto err1; 326 goto err1;
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index e6102fda0a7f..1f96e3227be5 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -17,13 +17,12 @@
17#include <linux/moduleparam.h> 17#include <linux/moduleparam.h>
18#include <linux/device.h> 18#include <linux/device.h>
19#include <linux/gpio.h> 19#include <linux/gpio.h>
20#include <linux/interrupt.h>
21#include <linux/irq.h>
22 20
23#include <sound/core.h> 21#include <sound/core.h>
24#include <sound/pcm.h> 22#include <sound/pcm.h>
25#include <sound/soc.h> 23#include <sound/soc.h>
26#include <sound/soc-dapm.h> 24#include <sound/soc-dapm.h>
25#include <sound/jack.h>
27 26
28#include <asm/mach-types.h> 27#include <asm/mach-types.h>
29#include <mach/audio.h> 28#include <mach/audio.h>
@@ -33,90 +32,31 @@
33#include "pxa2xx-pcm.h" 32#include "pxa2xx-pcm.h"
34#include "pxa2xx-ac97.h" 33#include "pxa2xx-ac97.h"
35 34
36static int palm27x_jack_func = 1; 35static struct snd_soc_jack hs_jack;
37static int palm27x_spk_func = 1;
38static int palm27x_ep_gpio = -1;
39 36
40static void palm27x_ext_control(struct snd_soc_codec *codec) 37/* Headphones jack detection DAPM pins */
41{ 38static struct snd_soc_jack_pin hs_jack_pins[] = {
42 if (!palm27x_spk_func) 39 {
43 snd_soc_dapm_enable_pin(codec, "Speaker"); 40 .pin = "Headphone Jack",
44 else 41 .mask = SND_JACK_HEADPHONE,
45 snd_soc_dapm_disable_pin(codec, "Speaker"); 42 },
46
47 if (!palm27x_jack_func)
48 snd_soc_dapm_enable_pin(codec, "Headphone Jack");
49 else
50 snd_soc_dapm_disable_pin(codec, "Headphone Jack");
51
52 snd_soc_dapm_sync(codec);
53}
54
55static int palm27x_startup(struct snd_pcm_substream *substream)
56{
57 struct snd_soc_pcm_runtime *rtd = substream->private_data;
58 struct snd_soc_codec *codec = rtd->socdev->card->codec;
59
60 /* check the jack status at stream startup */
61 palm27x_ext_control(codec);
62 return 0;
63}
64
65static struct snd_soc_ops palm27x_ops = {
66 .startup = palm27x_startup,
67}; 43};
68 44
69static irqreturn_t palm27x_interrupt(int irq, void *v) 45/* Headphones jack detection gpios */
70{ 46static struct snd_soc_jack_gpio hs_jack_gpios[] = {
71 palm27x_spk_func = gpio_get_value(palm27x_ep_gpio); 47 [0] = {
72 palm27x_jack_func = !palm27x_spk_func; 48 /* gpio is set on per-platform basis */
73 return IRQ_HANDLED; 49 .name = "hp-gpio",
74} 50 .report = SND_JACK_HEADPHONE,
75 51 .debounce_time = 200,
76static int palm27x_get_jack(struct snd_kcontrol *kcontrol, 52 },
77 struct snd_ctl_elem_value *ucontrol) 53};
78{
79 ucontrol->value.integer.value[0] = palm27x_jack_func;
80 return 0;
81}
82
83static int palm27x_set_jack(struct snd_kcontrol *kcontrol,
84 struct snd_ctl_elem_value *ucontrol)
85{
86 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
87
88 if (palm27x_jack_func == ucontrol->value.integer.value[0])
89 return 0;
90
91 palm27x_jack_func = ucontrol->value.integer.value[0];
92 palm27x_ext_control(codec);
93 return 1;
94}
95
96static int palm27x_get_spk(struct snd_kcontrol *kcontrol,
97 struct snd_ctl_elem_value *ucontrol)
98{
99 ucontrol->value.integer.value[0] = palm27x_spk_func;
100 return 0;
101}
102
103static int palm27x_set_spk(struct snd_kcontrol *kcontrol,
104 struct snd_ctl_elem_value *ucontrol)
105{
106 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
107
108 if (palm27x_spk_func == ucontrol->value.integer.value[0])
109 return 0;
110
111 palm27x_spk_func = ucontrol->value.integer.value[0];
112 palm27x_ext_control(codec);
113 return 1;
114}
115 54
116/* PalmTX machine dapm widgets */ 55/* Palm27x machine dapm widgets */
117static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = { 56static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = {
118 SND_SOC_DAPM_HP("Headphone Jack", NULL), 57 SND_SOC_DAPM_HP("Headphone Jack", NULL),
119 SND_SOC_DAPM_SPK("Speaker", NULL), 58 SND_SOC_DAPM_SPK("Ext. Speaker", NULL),
59 SND_SOC_DAPM_MIC("Ext. Microphone", NULL),
120}; 60};
121 61
122/* PalmTX audio map */ 62/* PalmTX audio map */
@@ -126,46 +66,66 @@ static const struct snd_soc_dapm_route audio_map[] = {
126 {"Headphone Jack", NULL, "HPOUTR"}, 66 {"Headphone Jack", NULL, "HPOUTR"},
127 67
128 /* ext speaker connected to ROUT2, LOUT2 */ 68 /* ext speaker connected to ROUT2, LOUT2 */
129 {"Speaker", NULL, "LOUT2"}, 69 {"Ext. Speaker", NULL, "LOUT2"},
130 {"Speaker", NULL, "ROUT2"}, 70 {"Ext. Speaker", NULL, "ROUT2"},
131};
132 71
133static const char *jack_function[] = {"Headphone", "Off"}; 72 /* mic connected to MIC1 */
134static const char *spk_function[] = {"On", "Off"}; 73 {"Ext. Microphone", NULL, "MIC1"},
135static const struct soc_enum palm27x_enum[] = {
136 SOC_ENUM_SINGLE_EXT(2, jack_function),
137 SOC_ENUM_SINGLE_EXT(2, spk_function),
138}; 74};
139 75
140static const struct snd_kcontrol_new palm27x_controls[] = { 76static struct snd_soc_card palm27x_asoc;
141 SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack,
142 palm27x_set_jack),
143 SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk,
144 palm27x_set_spk),
145};
146 77
147static int palm27x_ac97_init(struct snd_soc_codec *codec) 78static int palm27x_ac97_init(struct snd_soc_codec *codec)
148{ 79{
149 int err; 80 int err;
150 81
82 /* add palm27x specific widgets */
83 err = snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
84 ARRAY_SIZE(palm27x_dapm_widgets));
85 if (err)
86 return err;
87
88 /* set up palm27x specific audio path audio_map */
89 err = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
90 if (err)
91 return err;
92
93 /* connected pins */
94 if (machine_is_palmld())
95 snd_soc_dapm_enable_pin(codec, "MIC1");
96 snd_soc_dapm_enable_pin(codec, "HPOUTL");
97 snd_soc_dapm_enable_pin(codec, "HPOUTR");
98 snd_soc_dapm_enable_pin(codec, "LOUT2");
99 snd_soc_dapm_enable_pin(codec, "ROUT2");
100
101 /* not connected pins */
151 snd_soc_dapm_nc_pin(codec, "OUT3"); 102 snd_soc_dapm_nc_pin(codec, "OUT3");
152 snd_soc_dapm_nc_pin(codec, "MONOOUT"); 103 snd_soc_dapm_nc_pin(codec, "MONOOUT");
104 snd_soc_dapm_nc_pin(codec, "LINEINL");
105 snd_soc_dapm_nc_pin(codec, "LINEINR");
106 snd_soc_dapm_nc_pin(codec, "PCBEEP");
107 snd_soc_dapm_nc_pin(codec, "PHONE");
108 snd_soc_dapm_nc_pin(codec, "MIC2");
109
110 err = snd_soc_dapm_sync(codec);
111 if (err)
112 return err;
153 113
154 /* add palm27x specific controls */ 114 /* Jack detection API stuff */
155 err = snd_soc_add_controls(codec, palm27x_controls, 115 err = snd_soc_jack_new(&palm27x_asoc, "Headphone Jack",
156 ARRAY_SIZE(palm27x_controls)); 116 SND_JACK_HEADPHONE, &hs_jack);
157 if (err < 0) 117 if (err)
158 return err; 118 return err;
159 119
160 /* add palm27x specific widgets */ 120 err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
161 snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, 121 hs_jack_pins);
162 ARRAY_SIZE(palm27x_dapm_widgets)); 122 if (err)
123 return err;
163 124
164 /* set up palm27x specific audio path audio_map */ 125 err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
165 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 126 hs_jack_gpios);
166 127
167 snd_soc_dapm_sync(codec); 128 return err;
168 return 0;
169} 129}
170 130
171static struct snd_soc_dai_link palm27x_dai[] = { 131static struct snd_soc_dai_link palm27x_dai[] = {
@@ -175,14 +135,12 @@ static struct snd_soc_dai_link palm27x_dai[] = {
175 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], 135 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
176 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], 136 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
177 .init = palm27x_ac97_init, 137 .init = palm27x_ac97_init,
178 .ops = &palm27x_ops,
179}, 138},
180{ 139{
181 .name = "AC97 Aux", 140 .name = "AC97 Aux",
182 .stream_name = "AC97 Aux", 141 .stream_name = "AC97 Aux",
183 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], 142 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
184 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], 143 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
185 .ops = &palm27x_ops,
186}, 144},
187}; 145};
188 146
@@ -208,27 +166,17 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
208 machine_is_palmld() || machine_is_palmte2())) 166 machine_is_palmld() || machine_is_palmte2()))
209 return -ENODEV; 167 return -ENODEV;
210 168
211 if (pdev->dev.platform_data) 169 if (!pdev->dev.platform_data) {
212 palm27x_ep_gpio = ((struct palm27x_asoc_info *) 170 dev_err(&pdev->dev, "please supply platform_data\n");
213 (pdev->dev.platform_data))->jack_gpio; 171 return -ENODEV;
214 172 }
215 ret = gpio_request(palm27x_ep_gpio, "Headphone Jack");
216 if (ret)
217 return ret;
218 ret = gpio_direction_input(palm27x_ep_gpio);
219 if (ret)
220 goto err_alloc;
221 173
222 if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt, 174 hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *)
223 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 175 (pdev->dev.platform_data))->jack_gpio;
224 "Headphone jack", NULL))
225 goto err_alloc;
226 176
227 palm27x_snd_device = platform_device_alloc("soc-audio", -1); 177 palm27x_snd_device = platform_device_alloc("soc-audio", -1);
228 if (!palm27x_snd_device) { 178 if (!palm27x_snd_device)
229 ret = -ENOMEM; 179 return -ENOMEM;
230 goto err_dev;
231 }
232 180
233 platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata); 181 platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata);
234 palm27x_snd_devdata.dev = &palm27x_snd_device->dev; 182 palm27x_snd_devdata.dev = &palm27x_snd_device->dev;
@@ -241,18 +189,12 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
241 189
242put_device: 190put_device:
243 platform_device_put(palm27x_snd_device); 191 platform_device_put(palm27x_snd_device);
244err_dev:
245 free_irq(gpio_to_irq(palm27x_ep_gpio), NULL);
246err_alloc:
247 gpio_free(palm27x_ep_gpio);
248 192
249 return ret; 193 return ret;
250} 194}
251 195
252static int __devexit palm27x_asoc_remove(struct platform_device *pdev) 196static int __devexit palm27x_asoc_remove(struct platform_device *pdev)
253{ 197{
254 free_irq(gpio_to_irq(palm27x_ep_gpio), NULL);
255 gpio_free(palm27x_ep_gpio);
256 platform_device_unregister(palm27x_snd_device); 198 platform_device_unregister(palm27x_snd_device);
257 return 0; 199 return 0;
258} 200}
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index df494d1e346f..808de5c5caa7 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -38,6 +38,15 @@ config SND_S3C24XX_SOC_NEO1973_WM8753
38 Say Y if you want to add support for SoC audio on smdk2440 38 Say Y if you want to add support for SoC audio on smdk2440
39 with the WM8753. 39 with the WM8753.
40 40
41config SND_S3C24XX_SOC_NEO1973_GTA02_WM8753
42 tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)"
43 depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA02
44 select SND_S3C24XX_SOC_I2S
45 select SND_SOC_WM8753
46 help
47 This driver provides audio support for the Openmoko Neo FreeRunner
48 smartphone.
49
41config SND_S3C24XX_SOC_JIVE_WM8750 50config SND_S3C24XX_SOC_JIVE_WM8750
42 tristate "SoC I2S Audio support for Jive" 51 tristate "SoC I2S Audio support for Jive"
43 depends on SND_S3C24XX_SOC && MACH_JIVE 52 depends on SND_S3C24XX_SOC && MACH_JIVE
@@ -57,7 +66,7 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710
57 66
58config SND_S3C24XX_SOC_LN2440SBC_ALC650 67config SND_S3C24XX_SOC_LN2440SBC_ALC650
59 tristate "SoC AC97 Audio support for LN2440SBC - ALC650" 68 tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
60 depends on SND_S3C24XX_SOC 69 depends on SND_S3C24XX_SOC && ARCH_S3C2410
61 select SND_S3C2443_SOC_AC97 70 select SND_S3C2443_SOC_AC97
62 select SND_SOC_AC97_CODEC 71 select SND_SOC_AC97_CODEC
63 help 72 help
@@ -66,7 +75,7 @@ config SND_S3C24XX_SOC_LN2440SBC_ALC650
66 75
67config SND_S3C24XX_SOC_S3C24XX_UDA134X 76config SND_S3C24XX_SOC_S3C24XX_UDA134X
68 tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" 77 tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
69 depends on SND_S3C24XX_SOC 78 depends on SND_S3C24XX_SOC && ARCH_S3C2410
70 select SND_S3C24XX_SOC_I2S 79 select SND_S3C24XX_SOC_I2S
71 select SND_SOC_L3 80 select SND_SOC_L3
72 select SND_SOC_UDA134X 81 select SND_SOC_UDA134X
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 07a93a2ebe5f..eb219b016499 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -16,12 +16,14 @@ obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
16# S3C24XX Machine Support 16# S3C24XX Machine Support
17snd-soc-jive-wm8750-objs := jive_wm8750.o 17snd-soc-jive-wm8750-objs := jive_wm8750.o
18snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o 18snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
19snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o
19snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o 20snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
20snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o 21snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
21snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o 22snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
22 23
23obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o 24obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
24obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o 25obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
26obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
25obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o 27obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
26obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o 28obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
27obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o 29obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
new file mode 100644
index 000000000000..0c52e36ddd87
--- /dev/null
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -0,0 +1,498 @@
1/*
2 * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02)
3 *
4 * Copyright 2007 Openmoko Inc
5 * Author: Graeme Gregory <graeme@openmoko.org>
6 * Copyright 2007 Wolfson Microelectronics PLC.
7 * Author: Graeme Gregory <linux@wolfsonmicro.com>
8 * Copyright 2009 Wolfson Microelectronics
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/timer.h>
19#include <linux/interrupt.h>
20#include <linux/platform_device.h>
21#include <linux/gpio.h>
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/soc.h>
25#include <sound/soc-dapm.h>
26
27#include <asm/mach-types.h>
28
29#include <plat/regs-iis.h>
30
31#include <mach/regs-clock.h>
32#include <asm/io.h>
33#include <mach/gta02.h>
34#include "../codecs/wm8753.h"
35#include "s3c24xx-pcm.h"
36#include "s3c24xx-i2s.h"
37
38static struct snd_soc_card neo1973_gta02;
39
40static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
41 struct snd_pcm_hw_params *params)
42{
43 struct snd_soc_pcm_runtime *rtd = substream->private_data;
44 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
45 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
46 unsigned int pll_out = 0, bclk = 0;
47 int ret = 0;
48 unsigned long iis_clkrate;
49
50 iis_clkrate = s3c24xx_i2s_get_clockrate();
51
52 switch (params_rate(params)) {
53 case 8000:
54 case 16000:
55 pll_out = 12288000;
56 break;
57 case 48000:
58 bclk = WM8753_BCLK_DIV_4;
59 pll_out = 12288000;
60 break;
61 case 96000:
62 bclk = WM8753_BCLK_DIV_2;
63 pll_out = 12288000;
64 break;
65 case 11025:
66 bclk = WM8753_BCLK_DIV_16;
67 pll_out = 11289600;
68 break;
69 case 22050:
70 bclk = WM8753_BCLK_DIV_8;
71 pll_out = 11289600;
72 break;
73 case 44100:
74 bclk = WM8753_BCLK_DIV_4;
75 pll_out = 11289600;
76 break;
77 case 88200:
78 bclk = WM8753_BCLK_DIV_2;
79 pll_out = 11289600;
80 break;
81 }
82
83 /* set codec DAI configuration */
84 ret = snd_soc_dai_set_fmt(codec_dai,
85 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
86 SND_SOC_DAIFMT_CBM_CFM);
87 if (ret < 0)
88 return ret;
89
90 /* set cpu DAI configuration */
91 ret = snd_soc_dai_set_fmt(cpu_dai,
92 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
93 SND_SOC_DAIFMT_CBM_CFM);
94 if (ret < 0)
95 return ret;
96
97 /* set the codec system clock for DAC and ADC */
98 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
99 SND_SOC_CLOCK_IN);
100 if (ret < 0)
101 return ret;
102
103 /* set MCLK division for sample rate */
104 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
105 S3C2410_IISMOD_32FS);
106 if (ret < 0)
107 return ret;
108
109 /* set codec BCLK division for sample rate */
110 ret = snd_soc_dai_set_clkdiv(codec_dai,
111 WM8753_BCLKDIV, bclk);
112 if (ret < 0)
113 return ret;
114
115 /* set prescaler division for sample rate */
116 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
117 S3C24XX_PRESCALE(4, 4));
118 if (ret < 0)
119 return ret;
120
121 /* codec PLL input is PCLK/4 */
122 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1,
123 iis_clkrate / 4, pll_out);
124 if (ret < 0)
125 return ret;
126
127 return 0;
128}
129
130static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
131{
132 struct snd_soc_pcm_runtime *rtd = substream->private_data;
133 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
134
135 /* disable the PLL */
136 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
137}
138
139/*
140 * Neo1973 WM8753 HiFi DAI opserations.
141 */
142static struct snd_soc_ops neo1973_gta02_hifi_ops = {
143 .hw_params = neo1973_gta02_hifi_hw_params,
144 .hw_free = neo1973_gta02_hifi_hw_free,
145};
146
147static int neo1973_gta02_voice_hw_params(
148 struct snd_pcm_substream *substream,
149 struct snd_pcm_hw_params *params)
150{
151 struct snd_soc_pcm_runtime *rtd = substream->private_data;
152 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
153 unsigned int pcmdiv = 0;
154 int ret = 0;
155 unsigned long iis_clkrate;
156
157 iis_clkrate = s3c24xx_i2s_get_clockrate();
158
159 if (params_rate(params) != 8000)
160 return -EINVAL;
161 if (params_channels(params) != 1)
162 return -EINVAL;
163
164 pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
165
166 /* todo: gg check mode (DSP_B) against CSR datasheet */
167 /* set codec DAI configuration */
168 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
169 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
170 if (ret < 0)
171 return ret;
172
173 /* set the codec system clock for DAC and ADC */
174 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK,
175 12288000, SND_SOC_CLOCK_IN);
176 if (ret < 0)
177 return ret;
178
179 /* set codec PCM division for sample rate */
180 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV,
181 pcmdiv);
182 if (ret < 0)
183 return ret;
184
185 /* configue and enable PLL for 12.288MHz output */
186 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2,
187 iis_clkrate / 4, 12288000);
188 if (ret < 0)
189 return ret;
190
191 return 0;
192}
193
194static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
195{
196 struct snd_soc_pcm_runtime *rtd = substream->private_data;
197 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
198
199 /* disable the PLL */
200 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
201}
202
203static struct snd_soc_ops neo1973_gta02_voice_ops = {
204 .hw_params = neo1973_gta02_voice_hw_params,
205 .hw_free = neo1973_gta02_voice_hw_free,
206};
207
208#define LM4853_AMP 1
209#define LM4853_SPK 2
210
211static u8 lm4853_state;
212
213/* This has no effect, it exists only to maintain compatibility with
214 * existing ALSA state files.
215 */
216static int lm4853_set_state(struct snd_kcontrol *kcontrol,
217 struct snd_ctl_elem_value *ucontrol)
218{
219 int val = ucontrol->value.integer.value[0];
220
221 if (val)
222 lm4853_state |= LM4853_AMP;
223 else
224 lm4853_state &= ~LM4853_AMP;
225
226 return 0;
227}
228
229static int lm4853_get_state(struct snd_kcontrol *kcontrol,
230 struct snd_ctl_elem_value *ucontrol)
231{
232 ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP;
233
234 return 0;
235}
236
237static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
238 struct snd_ctl_elem_value *ucontrol)
239{
240 int val = ucontrol->value.integer.value[0];
241
242 if (val) {
243 lm4853_state |= LM4853_SPK;
244 gpio_set_value(GTA02_GPIO_HP_IN, 0);
245 } else {
246 lm4853_state &= ~LM4853_SPK;
247 gpio_set_value(GTA02_GPIO_HP_IN, 1);
248 }
249
250 return 0;
251}
252
253static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
254 struct snd_ctl_elem_value *ucontrol)
255{
256 ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1;
257
258 return 0;
259}
260
261static int lm4853_event(struct snd_soc_dapm_widget *w,
262 struct snd_kcontrol *k,
263 int event)
264{
265 gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(value));
266
267 return 0;
268}
269
270static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
271 SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
272 SND_SOC_DAPM_LINE("GSM Line Out", NULL),
273 SND_SOC_DAPM_LINE("GSM Line In", NULL),
274 SND_SOC_DAPM_MIC("Headset Mic", NULL),
275 SND_SOC_DAPM_MIC("Handset Mic", NULL),
276 SND_SOC_DAPM_SPK("Handset Spk", NULL),
277};
278
279
280/* example machine audio_mapnections */
281static const struct snd_soc_dapm_route audio_map[] = {
282
283 /* Connections to the lm4853 amp */
284 {"Stereo Out", NULL, "LOUT1"},
285 {"Stereo Out", NULL, "ROUT1"},
286
287 /* Connections to the GSM Module */
288 {"GSM Line Out", NULL, "MONO1"},
289 {"GSM Line Out", NULL, "MONO2"},
290 {"RXP", NULL, "GSM Line In"},
291 {"RXN", NULL, "GSM Line In"},
292
293 /* Connections to Headset */
294 {"MIC1", NULL, "Mic Bias"},
295 {"Mic Bias", NULL, "Headset Mic"},
296
297 /* Call Mic */
298 {"MIC2", NULL, "Mic Bias"},
299 {"MIC2N", NULL, "Mic Bias"},
300 {"Mic Bias", NULL, "Handset Mic"},
301
302 /* Call Speaker */
303 {"Handset Spk", NULL, "LOUT2"},
304 {"Handset Spk", NULL, "ROUT2"},
305
306 /* Connect the ALC pins */
307 {"ACIN", NULL, "ACOP"},
308};
309
310static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
311 SOC_DAPM_PIN_SWITCH("Stereo Out"),
312 SOC_DAPM_PIN_SWITCH("GSM Line Out"),
313 SOC_DAPM_PIN_SWITCH("GSM Line In"),
314 SOC_DAPM_PIN_SWITCH("Headset Mic"),
315 SOC_DAPM_PIN_SWITCH("Handset Mic"),
316 SOC_DAPM_PIN_SWITCH("Handset Spk"),
317
318 /* This has no effect, it exists only to maintain compatibility with
319 * existing ALSA state files.
320 */
321 SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0,
322 lm4853_get_state,
323 lm4853_set_state),
324 SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0,
325 lm4853_get_spk,
326 lm4853_set_spk),
327};
328
329/*
330 * This is an example machine initialisation for a wm8753 connected to a
331 * neo1973 GTA02.
332 */
333static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
334{
335 int err;
336
337 /* set up NC codec pins */
338 snd_soc_dapm_nc_pin(codec, "OUT3");
339 snd_soc_dapm_nc_pin(codec, "OUT4");
340 snd_soc_dapm_nc_pin(codec, "LINE1");
341 snd_soc_dapm_nc_pin(codec, "LINE2");
342
343 /* Add neo1973 gta02 specific widgets */
344 snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
345 ARRAY_SIZE(wm8753_dapm_widgets));
346
347 /* add neo1973 gta02 specific controls */
348 err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls,
349 ARRAY_SIZE(wm8753_neo1973_gta02_controls));
350
351 if (err < 0)
352 return err;
353
354 /* set up neo1973 gta02 specific audio path audio_map */
355 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
356
357 /* set endpoints to default off mode */
358 snd_soc_dapm_disable_pin(codec, "Stereo Out");
359 snd_soc_dapm_disable_pin(codec, "GSM Line Out");
360 snd_soc_dapm_disable_pin(codec, "GSM Line In");
361 snd_soc_dapm_disable_pin(codec, "Headset Mic");
362 snd_soc_dapm_disable_pin(codec, "Handset Mic");
363 snd_soc_dapm_disable_pin(codec, "Handset Spk");
364
365 snd_soc_dapm_sync(codec);
366
367 return 0;
368}
369
370/*
371 * BT Codec DAI
372 */
373static struct snd_soc_dai bt_dai = {
374 .name = "Bluetooth",
375 .id = 0,
376 .playback = {
377 .channels_min = 1,
378 .channels_max = 1,
379 .rates = SNDRV_PCM_RATE_8000,
380 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
381 .capture = {
382 .channels_min = 1,
383 .channels_max = 1,
384 .rates = SNDRV_PCM_RATE_8000,
385 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
386};
387
388static struct snd_soc_dai_link neo1973_gta02_dai[] = {
389{ /* Hifi Playback - for similatious use with voice below */
390 .name = "WM8753",
391 .stream_name = "WM8753 HiFi",
392 .cpu_dai = &s3c24xx_i2s_dai,
393 .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
394 .init = neo1973_gta02_wm8753_init,
395 .ops = &neo1973_gta02_hifi_ops,
396},
397{ /* Voice via BT */
398 .name = "Bluetooth",
399 .stream_name = "Voice",
400 .cpu_dai = &bt_dai,
401 .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
402 .ops = &neo1973_gta02_voice_ops,
403},
404};
405
406static struct snd_soc_card neo1973_gta02 = {
407 .name = "neo1973-gta02",
408 .platform = &s3c24xx_soc_platform,
409 .dai_link = neo1973_gta02_dai,
410 .num_links = ARRAY_SIZE(neo1973_gta02_dai),
411};
412
413static struct snd_soc_device neo1973_gta02_snd_devdata = {
414 .card = &neo1973_gta02,
415 .codec_dev = &soc_codec_dev_wm8753,
416};
417
418static struct platform_device *neo1973_gta02_snd_device;
419
420static int __init neo1973_gta02_init(void)
421{
422 int ret;
423
424 if (!machine_is_neo1973_gta02()) {
425 printk(KERN_INFO
426 "Only GTA02 is supported by this ASoC driver\n");
427 return -ENODEV;
428 }
429
430 /* register bluetooth DAI here */
431 ret = snd_soc_register_dai(&bt_dai);
432 if (ret)
433 return ret;
434
435 neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
436 if (!neo1973_gta02_snd_device)
437 return -ENOMEM;
438
439 platform_set_drvdata(neo1973_gta02_snd_device,
440 &neo1973_gta02_snd_devdata);
441 neo1973_gta02_snd_devdata.dev = &neo1973_gta02_snd_device->dev;
442 ret = platform_device_add(neo1973_gta02_snd_device);
443
444 if (ret) {
445 platform_device_put(neo1973_gta02_snd_device);
446 return ret;
447 }
448
449 /* Initialise GPIOs used by amp */
450 ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN");
451 if (ret) {
452 pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN);
453 goto err_unregister_device;
454 }
455
456 ret = gpio_direction_output(GTA02_GPIO_AMP_HP_IN, 1);
457 if (ret) {
458 pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
459 goto err_free_gpio_hp_in;
460 }
461
462 ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT");
463 if (ret) {
464 pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT);
465 goto err_free_gpio_hp_in;
466 }
467
468 ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1);
469 if (ret) {
470 pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT);
471 goto err_free_gpio_amp_shut;
472 }
473
474 return 0;
475
476err_free_gpio_amp_shut:
477 gpio_free(GTA02_GPIO_AMP_SHUT);
478err_free_gpio_hp_in:
479 gpio_free(GTA02_GPIO_HP_IN);
480err_unregister_device:
481 platform_device_unregister(neo1973_gta02_snd_device);
482 return ret;
483}
484module_init(neo1973_gta02_init);
485
486static void __exit neo1973_gta02_exit(void)
487{
488 snd_soc_unregister_dai(&bt_dai);
489 platform_device_unregister(neo1973_gta02_snd_device);
490 gpio_free(GTA02_GPIO_HP_IN);
491 gpio_free(GTA02_GPIO_AMP_SHUT);
492}
493module_exit(neo1973_gta02_exit);
494
495/* Module information */
496MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org");
497MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02");
498MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 8bf49a4e664a..fb8d7a766155 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -28,6 +28,7 @@
28#include <linux/bitops.h> 28#include <linux/bitops.h>
29#include <linux/debugfs.h> 29#include <linux/debugfs.h>
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31#include <sound/ac97_codec.h>
31#include <sound/core.h> 32#include <sound/core.h>
32#include <sound/pcm.h> 33#include <sound/pcm.h>
33#include <sound/pcm_params.h> 34#include <sound/pcm_params.h>
@@ -1155,6 +1156,9 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
1155 1156
1156 count += sprintf(buf, "%s registers\n", codec->name); 1157 count += sprintf(buf, "%s registers\n", codec->name);
1157 for (i = 0; i < codec->reg_cache_size; i += step) { 1158 for (i = 0; i < codec->reg_cache_size; i += step) {
1159 if (codec->readable_register && !codec->readable_register(i))
1160 continue;
1161
1158 count += sprintf(buf + count, "%2x: ", i); 1162 count += sprintf(buf + count, "%2x: ", i);
1159 if (count >= PAGE_SIZE - 1) 1163 if (count >= PAGE_SIZE - 1)
1160 break; 1164 break;
@@ -1461,8 +1465,11 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
1461 continue; 1465 continue;
1462 } 1466 }
1463 } 1467 }
1464 if (card->dai_link[i].codec_dai->ac97_control) 1468 if (card->dai_link[i].codec_dai->ac97_control) {
1465 ac97 = 1; 1469 ac97 = 1;
1470 snd_ac97_dev_add_pdata(codec->ac97,
1471 card->dai_link[i].cpu_dai->ac97_pdata);
1472 }
1466 } 1473 }
1467 snprintf(codec->card->shortname, sizeof(codec->card->shortname), 1474 snprintf(codec->card->shortname, sizeof(codec->card->shortname),
1468 "%s", card->name); 1475 "%s", card->name);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5157ec110cfa..c68c204a48ad 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -997,6 +997,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
997 pr_err("Failed to apply active bias: %d\n", ret); 997 pr_err("Failed to apply active bias: %d\n", ret);
998 } 998 }
999 999
1000 pop_dbg(codec->pop_time, "DAPM sequencing finished, waiting %dms\n",
1001 codec->pop_time);
1002
1000 return 0; 1003 return 0;
1001} 1004}
1002 1005
@@ -1290,8 +1293,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
1290 if (wsink->id == snd_soc_dapm_input) { 1293 if (wsink->id == snd_soc_dapm_input) {
1291 if (wsource->id == snd_soc_dapm_micbias || 1294 if (wsource->id == snd_soc_dapm_micbias ||
1292 wsource->id == snd_soc_dapm_mic || 1295 wsource->id == snd_soc_dapm_mic ||
1293 wsink->id == snd_soc_dapm_line || 1296 wsource->id == snd_soc_dapm_line ||
1294 wsink->id == snd_soc_dapm_output) 1297 wsource->id == snd_soc_dapm_output)
1295 wsink->ext = 1; 1298 wsink->ext = 1;
1296 } 1299 }
1297 if (wsource->id == snd_soc_dapm_output) { 1300 if (wsource->id == snd_soc_dapm_output) {
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 28346fb2e70c..1d455ab79490 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -73,14 +73,15 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
73 oldstatus = jack->status; 73 oldstatus = jack->status;
74 74
75 jack->status &= ~mask; 75 jack->status &= ~mask;
76 jack->status |= status; 76 jack->status |= status & mask;
77 77
78 /* The DAPM sync is expensive enough to be worth skipping */ 78 /* The DAPM sync is expensive enough to be worth skipping.
79 if (jack->status == oldstatus) 79 * However, empty mask means pin synchronization is desired. */
80 if (mask && (jack->status == oldstatus))
80 goto out; 81 goto out;
81 82
82 list_for_each_entry(pin, &jack->pins, list) { 83 list_for_each_entry(pin, &jack->pins, list) {
83 enable = pin->mask & status; 84 enable = pin->mask & jack->status;
84 85
85 if (pin->invert) 86 if (pin->invert)
86 enable = !enable; 87 enable = !enable;
@@ -220,6 +221,9 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
220 if (ret) 221 if (ret)
221 goto err; 222 goto err;
222 223
224 INIT_WORK(&gpios[i].work, gpio_work);
225 gpios[i].jack = jack;
226
223 ret = request_irq(gpio_to_irq(gpios[i].gpio), 227 ret = request_irq(gpio_to_irq(gpios[i].gpio),
224 gpio_handler, 228 gpio_handler,
225 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 229 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
@@ -228,8 +232,13 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
228 if (ret) 232 if (ret)
229 goto err; 233 goto err;
230 234
231 INIT_WORK(&gpios[i].work, gpio_work); 235#ifdef CONFIG_GPIO_SYSFS
232 gpios[i].jack = jack; 236 /* Expose GPIO value over sysfs for diagnostic purposes */
237 gpio_export(gpios[i].gpio, false);
238#endif
239
240 /* Update initial jack status */
241 snd_soc_jack_gpio_detect(&gpios[i]);
233 } 242 }
234 243
235 return 0; 244 return 0;
@@ -258,6 +267,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
258 int i; 267 int i;
259 268
260 for (i = 0; i < count; i++) { 269 for (i = 0; i < count; i++) {
270#ifdef CONFIG_GPIO_SYSFS
271 gpio_unexport(gpios[i].gpio);
272#endif
261 free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]); 273 free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
262 gpio_free(gpios[i].gpio); 274 gpio_free(gpios[i].gpio);
263 gpios[i].jack = NULL; 275 gpios[i].jack = NULL;