diff options
-rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8523.c | 755 | ||||
-rw-r--r-- | sound/soc/codecs/wm8523.h | 160 |
4 files changed, 921 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 021dbdfa5b92..68ea5b6648df 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -30,6 +30,7 @@ config SND_SOC_ALL_CODECS | |||
30 | select SND_SOC_WM8350 if MFD_WM8350 | 30 | select SND_SOC_WM8350 if MFD_WM8350 |
31 | select SND_SOC_WM8400 if MFD_WM8400 | 31 | select SND_SOC_WM8400 if MFD_WM8400 |
32 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI | 32 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI |
33 | select SND_SOC_WM8523 if I2C | ||
33 | select SND_SOC_WM8580 if I2C | 34 | select SND_SOC_WM8580 if I2C |
34 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI | 35 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI |
35 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI | 36 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI |
@@ -130,6 +131,9 @@ config SND_SOC_WM8400 | |||
130 | config SND_SOC_WM8510 | 131 | config SND_SOC_WM8510 |
131 | tristate | 132 | tristate |
132 | 133 | ||
134 | config SND_SOC_WM8523 | ||
135 | tristate | ||
136 | |||
133 | config SND_SOC_WM8580 | 137 | config SND_SOC_WM8580 |
134 | tristate | 138 | tristate |
135 | 139 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index e520c2b7f0e0..8ce28a34e8e9 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -18,6 +18,7 @@ snd-soc-uda1380-objs := uda1380.o | |||
18 | snd-soc-wm8350-objs := wm8350.o | 18 | snd-soc-wm8350-objs := wm8350.o |
19 | snd-soc-wm8400-objs := wm8400.o | 19 | snd-soc-wm8400-objs := wm8400.o |
20 | snd-soc-wm8510-objs := wm8510.o | 20 | snd-soc-wm8510-objs := wm8510.o |
21 | snd-soc-wm8523-objs := wm8523.o | ||
21 | snd-soc-wm8580-objs := wm8580.o | 22 | snd-soc-wm8580-objs := wm8580.o |
22 | snd-soc-wm8728-objs := wm8728.o | 23 | snd-soc-wm8728-objs := wm8728.o |
23 | snd-soc-wm8731-objs := wm8731.o | 24 | snd-soc-wm8731-objs := wm8731.o |
@@ -56,6 +57,7 @@ obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | |||
56 | obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o | 57 | obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o |
57 | obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o | 58 | obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o |
58 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | 59 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o |
60 | obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o | ||
59 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o | 61 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o |
60 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o | 62 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o |
61 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 63 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c new file mode 100644 index 000000000000..3b499ae7ce6c --- /dev/null +++ b/sound/soc/codecs/wm8523.c | |||
@@ -0,0 +1,755 @@ | |||
1 | /* | ||
2 | * wm8523.c -- WM8523 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2009 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/tlv.h> | ||
29 | |||
30 | #include "wm8523.h" | ||
31 | |||
32 | static struct snd_soc_codec *wm8523_codec; | ||
33 | struct snd_soc_codec_device soc_codec_dev_wm8523; | ||
34 | |||
35 | #define WM8523_NUM_SUPPLIES 2 | ||
36 | static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = { | ||
37 | "AVDD", | ||
38 | "LINEVDD", | ||
39 | }; | ||
40 | |||
41 | #define WM8523_NUM_RATES 7 | ||
42 | |||
43 | /* codec private data */ | ||
44 | struct wm8523_priv { | ||
45 | struct snd_soc_codec codec; | ||
46 | u16 reg_cache[WM8523_REGISTER_COUNT]; | ||
47 | struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES]; | ||
48 | unsigned int sysclk; | ||
49 | unsigned int rate_constraint_list[WM8523_NUM_RATES]; | ||
50 | struct snd_pcm_hw_constraint_list rate_constraint; | ||
51 | }; | ||
52 | |||
53 | static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = { | ||
54 | 0x8523, /* R0 - DEVICE_ID */ | ||
55 | 0x0001, /* R1 - REVISION */ | ||
56 | 0x0000, /* R2 - PSCTRL1 */ | ||
57 | 0x1812, /* R3 - AIF_CTRL1 */ | ||
58 | 0x0000, /* R4 - AIF_CTRL2 */ | ||
59 | 0x0001, /* R5 - DAC_CTRL3 */ | ||
60 | 0x0190, /* R6 - DAC_GAINL */ | ||
61 | 0x0190, /* R7 - DAC_GAINR */ | ||
62 | 0x0000, /* R8 - ZERO_DETECT */ | ||
63 | }; | ||
64 | |||
65 | static int wm8523_volatile(unsigned int reg) | ||
66 | { | ||
67 | switch (reg) { | ||
68 | case WM8523_DEVICE_ID: | ||
69 | case WM8523_REVISION: | ||
70 | return 1; | ||
71 | default: | ||
72 | return 0; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static int wm8523_write(struct snd_soc_codec *codec, unsigned int reg, | ||
77 | unsigned int value) | ||
78 | { | ||
79 | struct wm8523_priv *wm8523 = codec->private_data; | ||
80 | u8 data[3]; | ||
81 | |||
82 | BUG_ON(reg > WM8523_MAX_REGISTER); | ||
83 | |||
84 | data[0] = reg; | ||
85 | data[1] = (value >> 8) & 0x00ff; | ||
86 | data[2] = value & 0x00ff; | ||
87 | |||
88 | if (!wm8523_volatile(reg)) | ||
89 | wm8523->reg_cache[reg] = value; | ||
90 | if (codec->hw_write(codec->control_data, data, 3) == 3) | ||
91 | return 0; | ||
92 | else | ||
93 | return -EIO; | ||
94 | } | ||
95 | |||
96 | static int wm8523_reset(struct snd_soc_codec *codec) | ||
97 | { | ||
98 | return wm8523_write(codec, WM8523_DEVICE_ID, 0); | ||
99 | } | ||
100 | |||
101 | static unsigned int wm8523_read_hw(struct snd_soc_codec *codec, u8 reg) | ||
102 | { | ||
103 | struct i2c_msg xfer[2]; | ||
104 | u16 data; | ||
105 | int ret; | ||
106 | struct i2c_client *i2c = codec->control_data; | ||
107 | |||
108 | /* Write register */ | ||
109 | xfer[0].addr = i2c->addr; | ||
110 | xfer[0].flags = 0; | ||
111 | xfer[0].len = 1; | ||
112 | xfer[0].buf = ® | ||
113 | |||
114 | /* Read data */ | ||
115 | xfer[1].addr = i2c->addr; | ||
116 | xfer[1].flags = I2C_M_RD; | ||
117 | xfer[1].len = 2; | ||
118 | xfer[1].buf = (u8 *)&data; | ||
119 | |||
120 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
121 | if (ret != 2) { | ||
122 | dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | return (data >> 8) | ((data & 0xff) << 8); | ||
127 | } | ||
128 | |||
129 | |||
130 | static unsigned int wm8523_read(struct snd_soc_codec *codec, | ||
131 | unsigned int reg) | ||
132 | { | ||
133 | u16 *reg_cache = codec->reg_cache; | ||
134 | |||
135 | BUG_ON(reg > WM8523_MAX_REGISTER); | ||
136 | |||
137 | if (wm8523_volatile(reg)) | ||
138 | return wm8523_read_hw(codec, reg); | ||
139 | else | ||
140 | return reg_cache[reg]; | ||
141 | } | ||
142 | |||
143 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0); | ||
144 | |||
145 | static const char *wm8523_zd_count_text[] = { | ||
146 | "1024", | ||
147 | "2048", | ||
148 | }; | ||
149 | |||
150 | static const struct soc_enum wm8523_zc_count = | ||
151 | SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text); | ||
152 | |||
153 | static const struct snd_kcontrol_new wm8523_snd_controls[] = { | ||
154 | SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR, | ||
155 | 0, 448, 0, dac_tlv), | ||
156 | SOC_SINGLE("ZC Switch", WM8523_DAC_CTRL3, 4, 1, 0), | ||
157 | SOC_SINGLE("Playback Deemphasis Switch", WM8523_AIF_CTRL1, 8, 1, 0), | ||
158 | SOC_DOUBLE("Playback Switch", WM8523_DAC_CTRL3, 2, 3, 1, 1), | ||
159 | SOC_SINGLE("Volume Ramp Up Switch", WM8523_DAC_CTRL3, 1, 1, 0), | ||
160 | SOC_SINGLE("Volume Ramp Down Switch", WM8523_DAC_CTRL3, 0, 1, 0), | ||
161 | SOC_ENUM("Zero Detect Count", wm8523_zc_count), | ||
162 | }; | ||
163 | |||
164 | static const struct snd_soc_dapm_widget wm8523_dapm_widgets[] = { | ||
165 | SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), | ||
166 | SND_SOC_DAPM_OUTPUT("LINEVOUTL"), | ||
167 | SND_SOC_DAPM_OUTPUT("LINEVOUTR"), | ||
168 | }; | ||
169 | |||
170 | static const struct snd_soc_dapm_route intercon[] = { | ||
171 | { "LINEVOUTL", NULL, "DAC" }, | ||
172 | { "LINEVOUTR", NULL, "DAC" }, | ||
173 | }; | ||
174 | |||
175 | static int wm8523_add_widgets(struct snd_soc_codec *codec) | ||
176 | { | ||
177 | snd_soc_dapm_new_controls(codec, wm8523_dapm_widgets, | ||
178 | ARRAY_SIZE(wm8523_dapm_widgets)); | ||
179 | |||
180 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
181 | |||
182 | snd_soc_dapm_new_widgets(codec); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static struct { | ||
187 | int value; | ||
188 | int ratio; | ||
189 | } lrclk_ratios[WM8523_NUM_RATES] = { | ||
190 | { 1, 128 }, | ||
191 | { 2, 192 }, | ||
192 | { 3, 256 }, | ||
193 | { 4, 384 }, | ||
194 | { 5, 512 }, | ||
195 | { 6, 768 }, | ||
196 | { 7, 1152 }, | ||
197 | }; | ||
198 | |||
199 | static int wm8523_startup(struct snd_pcm_substream *substream, | ||
200 | struct snd_soc_dai *dai) | ||
201 | { | ||
202 | struct snd_soc_codec *codec = dai->codec; | ||
203 | struct wm8523_priv *wm8523 = codec->private_data; | ||
204 | |||
205 | /* The set of sample rates that can be supported depends on the | ||
206 | * MCLK supplied to the CODEC - enforce this. | ||
207 | */ | ||
208 | if (!wm8523->sysclk) { | ||
209 | dev_err(codec->dev, | ||
210 | "No MCLK configured, call set_sysclk() on init\n"); | ||
211 | return -EINVAL; | ||
212 | } | ||
213 | |||
214 | return 0; | ||
215 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
216 | SNDRV_PCM_HW_PARAM_RATE, | ||
217 | &wm8523->rate_constraint); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int wm8523_hw_params(struct snd_pcm_substream *substream, | ||
223 | struct snd_pcm_hw_params *params, | ||
224 | struct snd_soc_dai *dai) | ||
225 | { | ||
226 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
227 | struct snd_soc_device *socdev = rtd->socdev; | ||
228 | struct snd_soc_codec *codec = socdev->card->codec; | ||
229 | struct wm8523_priv *wm8523 = codec->private_data; | ||
230 | int i; | ||
231 | u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); | ||
232 | u16 aifctrl2 = wm8523_read(codec, WM8523_AIF_CTRL2); | ||
233 | |||
234 | /* Find a supported LRCLK ratio */ | ||
235 | for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { | ||
236 | if (wm8523->sysclk / params_rate(params) == | ||
237 | lrclk_ratios[i].ratio) | ||
238 | break; | ||
239 | } | ||
240 | |||
241 | /* Should never happen, should be handled by constraints */ | ||
242 | if (i == ARRAY_SIZE(lrclk_ratios)) { | ||
243 | dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n", | ||
244 | wm8523->sysclk / params_rate(params)); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
248 | aifctrl2 &= ~WM8523_SR_MASK; | ||
249 | aifctrl2 |= lrclk_ratios[i].value; | ||
250 | |||
251 | aifctrl1 &= ~WM8523_WL_MASK; | ||
252 | switch (params_format(params)) { | ||
253 | case SNDRV_PCM_FORMAT_S16_LE: | ||
254 | break; | ||
255 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
256 | aifctrl1 |= 0x8; | ||
257 | break; | ||
258 | case SNDRV_PCM_FORMAT_S24_LE: | ||
259 | aifctrl1 |= 0x10; | ||
260 | break; | ||
261 | case SNDRV_PCM_FORMAT_S32_LE: | ||
262 | aifctrl1 |= 0x18; | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); | ||
267 | wm8523_write(codec, WM8523_AIF_CTRL2, aifctrl2); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int wm8523_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
273 | int clk_id, unsigned int freq, int dir) | ||
274 | { | ||
275 | struct snd_soc_codec *codec = codec_dai->codec; | ||
276 | struct wm8523_priv *wm8523 = codec->private_data; | ||
277 | unsigned int val; | ||
278 | int i; | ||
279 | |||
280 | wm8523->sysclk = freq; | ||
281 | |||
282 | wm8523->rate_constraint.count = 0; | ||
283 | for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { | ||
284 | val = freq / lrclk_ratios[i].ratio; | ||
285 | /* Check that it's a standard rate since core can't | ||
286 | * cope with others and having the odd rates confuses | ||
287 | * constraint matching. | ||
288 | */ | ||
289 | switch (val) { | ||
290 | case 8000: | ||
291 | case 11025: | ||
292 | case 16000: | ||
293 | case 22050: | ||
294 | case 32000: | ||
295 | case 44100: | ||
296 | case 48000: | ||
297 | case 64000: | ||
298 | case 88200: | ||
299 | case 96000: | ||
300 | case 176400: | ||
301 | case 192000: | ||
302 | dev_dbg(codec->dev, "Supported sample rate: %dHz\n", | ||
303 | val); | ||
304 | wm8523->rate_constraint_list[i] = val; | ||
305 | wm8523->rate_constraint.count++; | ||
306 | break; | ||
307 | default: | ||
308 | dev_dbg(codec->dev, "Skipping sample rate: %dHz\n", | ||
309 | val); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | /* Need at least one supported rate... */ | ||
314 | if (wm8523->rate_constraint.count == 0) | ||
315 | return -EINVAL; | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | |||
321 | static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
322 | unsigned int fmt) | ||
323 | { | ||
324 | struct snd_soc_codec *codec = codec_dai->codec; | ||
325 | u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); | ||
326 | |||
327 | aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK | | ||
328 | WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK); | ||
329 | |||
330 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
331 | case SND_SOC_DAIFMT_CBM_CFM: | ||
332 | aifctrl1 |= WM8523_AIF_MSTR; | ||
333 | break; | ||
334 | case SND_SOC_DAIFMT_CBS_CFS: | ||
335 | break; | ||
336 | default: | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
341 | case SND_SOC_DAIFMT_I2S: | ||
342 | aifctrl1 |= 0x0002; | ||
343 | break; | ||
344 | case SND_SOC_DAIFMT_RIGHT_J: | ||
345 | break; | ||
346 | case SND_SOC_DAIFMT_LEFT_J: | ||
347 | aifctrl1 |= 0x0001; | ||
348 | break; | ||
349 | case SND_SOC_DAIFMT_DSP_A: | ||
350 | aifctrl1 |= 0x0003; | ||
351 | break; | ||
352 | case SND_SOC_DAIFMT_DSP_B: | ||
353 | aifctrl1 |= 0x0023; | ||
354 | break; | ||
355 | default: | ||
356 | return -EINVAL; | ||
357 | } | ||
358 | |||
359 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
360 | case SND_SOC_DAIFMT_NB_NF: | ||
361 | break; | ||
362 | case SND_SOC_DAIFMT_IB_IF: | ||
363 | aifctrl1 |= WM8523_BCLK_INV | WM8523_LRCLK_INV; | ||
364 | break; | ||
365 | case SND_SOC_DAIFMT_IB_NF: | ||
366 | aifctrl1 |= WM8523_BCLK_INV; | ||
367 | break; | ||
368 | case SND_SOC_DAIFMT_NB_IF: | ||
369 | aifctrl1 |= WM8523_LRCLK_INV; | ||
370 | break; | ||
371 | default: | ||
372 | return -EINVAL; | ||
373 | } | ||
374 | |||
375 | wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int wm8523_set_bias_level(struct snd_soc_codec *codec, | ||
381 | enum snd_soc_bias_level level) | ||
382 | { | ||
383 | struct wm8523_priv *wm8523 = codec->private_data; | ||
384 | int ret, i; | ||
385 | |||
386 | switch (level) { | ||
387 | case SND_SOC_BIAS_ON: | ||
388 | break; | ||
389 | |||
390 | case SND_SOC_BIAS_PREPARE: | ||
391 | /* Full power on */ | ||
392 | snd_soc_update_bits(codec, WM8523_PSCTRL1, | ||
393 | WM8523_SYS_ENA_MASK, 3); | ||
394 | break; | ||
395 | |||
396 | case SND_SOC_BIAS_STANDBY: | ||
397 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
398 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), | ||
399 | wm8523->supplies); | ||
400 | if (ret != 0) { | ||
401 | dev_err(codec->dev, | ||
402 | "Failed to enable supplies: %d\n", | ||
403 | ret); | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | /* Initial power up */ | ||
408 | snd_soc_update_bits(codec, WM8523_PSCTRL1, | ||
409 | WM8523_SYS_ENA_MASK, 1); | ||
410 | |||
411 | /* Sync back default/cached values */ | ||
412 | for (i = WM8523_AIF_CTRL1; | ||
413 | i < WM8523_MAX_REGISTER; i++) | ||
414 | wm8523_write(codec, i, wm8523->reg_cache[i]); | ||
415 | |||
416 | |||
417 | msleep(100); | ||
418 | } | ||
419 | |||
420 | /* Power up to mute */ | ||
421 | snd_soc_update_bits(codec, WM8523_PSCTRL1, | ||
422 | WM8523_SYS_ENA_MASK, 2); | ||
423 | |||
424 | break; | ||
425 | |||
426 | case SND_SOC_BIAS_OFF: | ||
427 | /* The chip runs through the power down sequence for us. */ | ||
428 | snd_soc_update_bits(codec, WM8523_PSCTRL1, | ||
429 | WM8523_SYS_ENA_MASK, 0); | ||
430 | msleep(100); | ||
431 | |||
432 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), | ||
433 | wm8523->supplies); | ||
434 | break; | ||
435 | } | ||
436 | codec->bias_level = level; | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | #define WM8523_RATES SNDRV_PCM_RATE_8000_192000 | ||
441 | |||
442 | #define WM8523_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
443 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
444 | |||
445 | static struct snd_soc_dai_ops wm8523_dai_ops = { | ||
446 | .startup = wm8523_startup, | ||
447 | .hw_params = wm8523_hw_params, | ||
448 | .set_sysclk = wm8523_set_dai_sysclk, | ||
449 | .set_fmt = wm8523_set_dai_fmt, | ||
450 | }; | ||
451 | |||
452 | struct snd_soc_dai wm8523_dai = { | ||
453 | .name = "WM8523", | ||
454 | .playback = { | ||
455 | .stream_name = "Playback", | ||
456 | .channels_min = 2, /* Mono modes not yet supported */ | ||
457 | .channels_max = 2, | ||
458 | .rates = WM8523_RATES, | ||
459 | .formats = WM8523_FORMATS, | ||
460 | }, | ||
461 | .ops = &wm8523_dai_ops, | ||
462 | }; | ||
463 | EXPORT_SYMBOL_GPL(wm8523_dai); | ||
464 | |||
465 | #ifdef CONFIG_PM | ||
466 | static int wm8523_suspend(struct platform_device *pdev, pm_message_t state) | ||
467 | { | ||
468 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
469 | struct snd_soc_codec *codec = socdev->card->codec; | ||
470 | |||
471 | wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int wm8523_resume(struct platform_device *pdev) | ||
476 | { | ||
477 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
478 | struct snd_soc_codec *codec = socdev->card->codec; | ||
479 | |||
480 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | #else | ||
485 | #define wm8523_suspend NULL | ||
486 | #define wm8523_resume NULL | ||
487 | #endif | ||
488 | |||
489 | static int wm8523_probe(struct platform_device *pdev) | ||
490 | { | ||
491 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
492 | struct snd_soc_codec *codec; | ||
493 | int ret = 0; | ||
494 | |||
495 | if (wm8523_codec == NULL) { | ||
496 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
497 | return -ENODEV; | ||
498 | } | ||
499 | |||
500 | socdev->card->codec = wm8523_codec; | ||
501 | codec = wm8523_codec; | ||
502 | |||
503 | /* register pcms */ | ||
504 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
505 | if (ret < 0) { | ||
506 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
507 | goto pcm_err; | ||
508 | } | ||
509 | |||
510 | snd_soc_add_controls(codec, wm8523_snd_controls, | ||
511 | ARRAY_SIZE(wm8523_snd_controls)); | ||
512 | wm8523_add_widgets(codec); | ||
513 | ret = snd_soc_init_card(socdev); | ||
514 | if (ret < 0) { | ||
515 | dev_err(codec->dev, "failed to register card: %d\n", ret); | ||
516 | goto card_err; | ||
517 | } | ||
518 | |||
519 | return ret; | ||
520 | |||
521 | card_err: | ||
522 | snd_soc_free_pcms(socdev); | ||
523 | snd_soc_dapm_free(socdev); | ||
524 | pcm_err: | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | static int wm8523_remove(struct platform_device *pdev) | ||
529 | { | ||
530 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
531 | |||
532 | snd_soc_free_pcms(socdev); | ||
533 | snd_soc_dapm_free(socdev); | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | struct snd_soc_codec_device soc_codec_dev_wm8523 = { | ||
539 | .probe = wm8523_probe, | ||
540 | .remove = wm8523_remove, | ||
541 | .suspend = wm8523_suspend, | ||
542 | .resume = wm8523_resume, | ||
543 | }; | ||
544 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523); | ||
545 | |||
546 | static int wm8523_register(struct wm8523_priv *wm8523) | ||
547 | { | ||
548 | int ret; | ||
549 | struct snd_soc_codec *codec = &wm8523->codec; | ||
550 | int i; | ||
551 | |||
552 | if (wm8523_codec) { | ||
553 | dev_err(codec->dev, "Another WM8523 is registered\n"); | ||
554 | return -EINVAL; | ||
555 | } | ||
556 | |||
557 | mutex_init(&codec->mutex); | ||
558 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
559 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
560 | |||
561 | codec->private_data = wm8523; | ||
562 | codec->name = "WM8523"; | ||
563 | codec->owner = THIS_MODULE; | ||
564 | codec->read = wm8523_read; | ||
565 | codec->write = wm8523_write; | ||
566 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
567 | codec->set_bias_level = wm8523_set_bias_level; | ||
568 | codec->dai = &wm8523_dai; | ||
569 | codec->num_dai = 1; | ||
570 | codec->reg_cache_size = WM8523_REGISTER_COUNT; | ||
571 | codec->reg_cache = &wm8523->reg_cache; | ||
572 | |||
573 | wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; | ||
574 | wm8523->rate_constraint.count = | ||
575 | ARRAY_SIZE(wm8523->rate_constraint_list); | ||
576 | |||
577 | memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg)); | ||
578 | |||
579 | for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) | ||
580 | wm8523->supplies[i].supply = wm8523_supply_names[i]; | ||
581 | |||
582 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8523->supplies), | ||
583 | wm8523->supplies); | ||
584 | if (ret != 0) { | ||
585 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
586 | goto err; | ||
587 | } | ||
588 | |||
589 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), | ||
590 | wm8523->supplies); | ||
591 | if (ret != 0) { | ||
592 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
593 | goto err_get; | ||
594 | } | ||
595 | |||
596 | ret = wm8523_read(codec, WM8523_DEVICE_ID); | ||
597 | if (ret < 0) { | ||
598 | dev_err(codec->dev, "Failed to read ID register\n"); | ||
599 | goto err_enable; | ||
600 | } | ||
601 | if (ret != wm8523_reg[WM8523_DEVICE_ID]) { | ||
602 | dev_err(codec->dev, "Device is not a WM8523, ID is %x\n", ret); | ||
603 | ret = -EINVAL; | ||
604 | goto err_enable; | ||
605 | } | ||
606 | |||
607 | ret = wm8523_read(codec, WM8523_REVISION); | ||
608 | if (ret < 0) { | ||
609 | dev_err(codec->dev, "Failed to read revision register\n"); | ||
610 | goto err_enable; | ||
611 | } | ||
612 | dev_info(codec->dev, "revision %c\n", | ||
613 | (ret & WM8523_CHIP_REV_MASK) + 'A'); | ||
614 | |||
615 | ret = wm8523_reset(codec); | ||
616 | if (ret < 0) { | ||
617 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
618 | goto err_enable; | ||
619 | } | ||
620 | |||
621 | wm8523_dai.dev = codec->dev; | ||
622 | |||
623 | /* Change some default settings - latch VU and enable ZC */ | ||
624 | wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU; | ||
625 | wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC; | ||
626 | |||
627 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
628 | |||
629 | /* Bias level configuration will have done an extra enable */ | ||
630 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | ||
631 | |||
632 | wm8523_codec = codec; | ||
633 | |||
634 | ret = snd_soc_register_codec(codec); | ||
635 | if (ret != 0) { | ||
636 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
637 | return ret; | ||
638 | } | ||
639 | |||
640 | ret = snd_soc_register_dai(&wm8523_dai); | ||
641 | if (ret != 0) { | ||
642 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
643 | snd_soc_unregister_codec(codec); | ||
644 | return ret; | ||
645 | } | ||
646 | |||
647 | return 0; | ||
648 | |||
649 | err_enable: | ||
650 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | ||
651 | err_get: | ||
652 | regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | ||
653 | err: | ||
654 | kfree(wm8523); | ||
655 | return ret; | ||
656 | } | ||
657 | |||
658 | static void wm8523_unregister(struct wm8523_priv *wm8523) | ||
659 | { | ||
660 | wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF); | ||
661 | regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | ||
662 | snd_soc_unregister_dai(&wm8523_dai); | ||
663 | snd_soc_unregister_codec(&wm8523->codec); | ||
664 | kfree(wm8523); | ||
665 | wm8523_codec = NULL; | ||
666 | } | ||
667 | |||
668 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
669 | static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, | ||
670 | const struct i2c_device_id *id) | ||
671 | { | ||
672 | struct wm8523_priv *wm8523; | ||
673 | struct snd_soc_codec *codec; | ||
674 | |||
675 | wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL); | ||
676 | if (wm8523 == NULL) | ||
677 | return -ENOMEM; | ||
678 | |||
679 | codec = &wm8523->codec; | ||
680 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
681 | |||
682 | i2c_set_clientdata(i2c, wm8523); | ||
683 | codec->control_data = i2c; | ||
684 | |||
685 | codec->dev = &i2c->dev; | ||
686 | |||
687 | return wm8523_register(wm8523); | ||
688 | } | ||
689 | |||
690 | static __devexit int wm8523_i2c_remove(struct i2c_client *client) | ||
691 | { | ||
692 | struct wm8523_priv *wm8523 = i2c_get_clientdata(client); | ||
693 | wm8523_unregister(wm8523); | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | #ifdef CONFIG_PM | ||
698 | static int wm8523_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) | ||
699 | { | ||
700 | return snd_soc_suspend_device(&i2c->dev); | ||
701 | } | ||
702 | |||
703 | static int wm8523_i2c_resume(struct i2c_client *i2c) | ||
704 | { | ||
705 | return snd_soc_resume_device(&i2c->dev); | ||
706 | } | ||
707 | #else | ||
708 | #define wm8523_i2c_suspend NULL | ||
709 | #define wm8523_i2c_resume NULL | ||
710 | #endif | ||
711 | |||
712 | static const struct i2c_device_id wm8523_i2c_id[] = { | ||
713 | { "wm8523", 0 }, | ||
714 | { } | ||
715 | }; | ||
716 | MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id); | ||
717 | |||
718 | static struct i2c_driver wm8523_i2c_driver = { | ||
719 | .driver = { | ||
720 | .name = "WM8523", | ||
721 | .owner = THIS_MODULE, | ||
722 | }, | ||
723 | .probe = wm8523_i2c_probe, | ||
724 | .remove = __devexit_p(wm8523_i2c_remove), | ||
725 | .suspend = wm8523_i2c_suspend, | ||
726 | .resume = wm8523_i2c_resume, | ||
727 | .id_table = wm8523_i2c_id, | ||
728 | }; | ||
729 | #endif | ||
730 | |||
731 | static int __init wm8523_modinit(void) | ||
732 | { | ||
733 | int ret; | ||
734 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
735 | ret = i2c_add_driver(&wm8523_i2c_driver); | ||
736 | if (ret != 0) { | ||
737 | printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n", | ||
738 | ret); | ||
739 | } | ||
740 | #endif | ||
741 | return 0; | ||
742 | } | ||
743 | module_init(wm8523_modinit); | ||
744 | |||
745 | static void __exit wm8523_exit(void) | ||
746 | { | ||
747 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
748 | i2c_del_driver(&wm8523_i2c_driver); | ||
749 | #endif | ||
750 | } | ||
751 | module_exit(wm8523_exit); | ||
752 | |||
753 | MODULE_DESCRIPTION("ASoC WM8523 driver"); | ||
754 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
755 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8523.h b/sound/soc/codecs/wm8523.h new file mode 100644 index 000000000000..1aa9ce3e1357 --- /dev/null +++ b/sound/soc/codecs/wm8523.h | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * wm8523.h -- WM8423 ASoC driver | ||
3 | * | ||
4 | * Copyright 2009 Wolfson Microelectronics, plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * Based on wm8753.h | ||
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 version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _WM8523_H | ||
16 | #define _WM8523_H | ||
17 | |||
18 | /* | ||
19 | * Register values. | ||
20 | */ | ||
21 | #define WM8523_DEVICE_ID 0x00 | ||
22 | #define WM8523_REVISION 0x01 | ||
23 | #define WM8523_PSCTRL1 0x02 | ||
24 | #define WM8523_AIF_CTRL1 0x03 | ||
25 | #define WM8523_AIF_CTRL2 0x04 | ||
26 | #define WM8523_DAC_CTRL3 0x05 | ||
27 | #define WM8523_DAC_GAINL 0x06 | ||
28 | #define WM8523_DAC_GAINR 0x07 | ||
29 | #define WM8523_ZERO_DETECT 0x08 | ||
30 | |||
31 | #define WM8523_REGISTER_COUNT 9 | ||
32 | #define WM8523_MAX_REGISTER 0x08 | ||
33 | |||
34 | /* | ||
35 | * Field Definitions. | ||
36 | */ | ||
37 | |||
38 | /* | ||
39 | * R0 (0x00) - DEVICE_ID | ||
40 | */ | ||
41 | #define WM8523_CHIP_ID_MASK 0xFFFF /* CHIP_ID - [15:0] */ | ||
42 | #define WM8523_CHIP_ID_SHIFT 0 /* CHIP_ID - [15:0] */ | ||
43 | #define WM8523_CHIP_ID_WIDTH 16 /* CHIP_ID - [15:0] */ | ||
44 | |||
45 | /* | ||
46 | * R1 (0x01) - REVISION | ||
47 | */ | ||
48 | #define WM8523_CHIP_REV_MASK 0x0007 /* CHIP_REV - [2:0] */ | ||
49 | #define WM8523_CHIP_REV_SHIFT 0 /* CHIP_REV - [2:0] */ | ||
50 | #define WM8523_CHIP_REV_WIDTH 3 /* CHIP_REV - [2:0] */ | ||
51 | |||
52 | /* | ||
53 | * R2 (0x02) - PSCTRL1 | ||
54 | */ | ||
55 | #define WM8523_SYS_ENA_MASK 0x0003 /* SYS_ENA - [1:0] */ | ||
56 | #define WM8523_SYS_ENA_SHIFT 0 /* SYS_ENA - [1:0] */ | ||
57 | #define WM8523_SYS_ENA_WIDTH 2 /* SYS_ENA - [1:0] */ | ||
58 | |||
59 | /* | ||
60 | * R3 (0x03) - AIF_CTRL1 | ||
61 | */ | ||
62 | #define WM8523_TDM_MODE_MASK 0x1800 /* TDM_MODE - [12:11] */ | ||
63 | #define WM8523_TDM_MODE_SHIFT 11 /* TDM_MODE - [12:11] */ | ||
64 | #define WM8523_TDM_MODE_WIDTH 2 /* TDM_MODE - [12:11] */ | ||
65 | #define WM8523_TDM_SLOT_MASK 0x0600 /* TDM_SLOT - [10:9] */ | ||
66 | #define WM8523_TDM_SLOT_SHIFT 9 /* TDM_SLOT - [10:9] */ | ||
67 | #define WM8523_TDM_SLOT_WIDTH 2 /* TDM_SLOT - [10:9] */ | ||
68 | #define WM8523_DEEMPH 0x0100 /* DEEMPH */ | ||
69 | #define WM8523_DEEMPH_MASK 0x0100 /* DEEMPH */ | ||
70 | #define WM8523_DEEMPH_SHIFT 8 /* DEEMPH */ | ||
71 | #define WM8523_DEEMPH_WIDTH 1 /* DEEMPH */ | ||
72 | #define WM8523_AIF_MSTR 0x0080 /* AIF_MSTR */ | ||
73 | #define WM8523_AIF_MSTR_MASK 0x0080 /* AIF_MSTR */ | ||
74 | #define WM8523_AIF_MSTR_SHIFT 7 /* AIF_MSTR */ | ||
75 | #define WM8523_AIF_MSTR_WIDTH 1 /* AIF_MSTR */ | ||
76 | #define WM8523_LRCLK_INV 0x0040 /* LRCLK_INV */ | ||
77 | #define WM8523_LRCLK_INV_MASK 0x0040 /* LRCLK_INV */ | ||
78 | #define WM8523_LRCLK_INV_SHIFT 6 /* LRCLK_INV */ | ||
79 | #define WM8523_LRCLK_INV_WIDTH 1 /* LRCLK_INV */ | ||
80 | #define WM8523_BCLK_INV 0x0020 /* BCLK_INV */ | ||
81 | #define WM8523_BCLK_INV_MASK 0x0020 /* BCLK_INV */ | ||
82 | #define WM8523_BCLK_INV_SHIFT 5 /* BCLK_INV */ | ||
83 | #define WM8523_BCLK_INV_WIDTH 1 /* BCLK_INV */ | ||
84 | #define WM8523_WL_MASK 0x0018 /* WL - [4:3] */ | ||
85 | #define WM8523_WL_SHIFT 3 /* WL - [4:3] */ | ||
86 | #define WM8523_WL_WIDTH 2 /* WL - [4:3] */ | ||
87 | #define WM8523_FMT_MASK 0x0007 /* FMT - [2:0] */ | ||
88 | #define WM8523_FMT_SHIFT 0 /* FMT - [2:0] */ | ||
89 | #define WM8523_FMT_WIDTH 3 /* FMT - [2:0] */ | ||
90 | |||
91 | /* | ||
92 | * R4 (0x04) - AIF_CTRL2 | ||
93 | */ | ||
94 | #define WM8523_DAC_OP_MUX_MASK 0x00C0 /* DAC_OP_MUX - [7:6] */ | ||
95 | #define WM8523_DAC_OP_MUX_SHIFT 6 /* DAC_OP_MUX - [7:6] */ | ||
96 | #define WM8523_DAC_OP_MUX_WIDTH 2 /* DAC_OP_MUX - [7:6] */ | ||
97 | #define WM8523_BCLKDIV_MASK 0x0038 /* BCLKDIV - [5:3] */ | ||
98 | #define WM8523_BCLKDIV_SHIFT 3 /* BCLKDIV - [5:3] */ | ||
99 | #define WM8523_BCLKDIV_WIDTH 3 /* BCLKDIV - [5:3] */ | ||
100 | #define WM8523_SR_MASK 0x0007 /* SR - [2:0] */ | ||
101 | #define WM8523_SR_SHIFT 0 /* SR - [2:0] */ | ||
102 | #define WM8523_SR_WIDTH 3 /* SR - [2:0] */ | ||
103 | |||
104 | /* | ||
105 | * R5 (0x05) - DAC_CTRL3 | ||
106 | */ | ||
107 | #define WM8523_ZC 0x0010 /* ZC */ | ||
108 | #define WM8523_ZC_MASK 0x0010 /* ZC */ | ||
109 | #define WM8523_ZC_SHIFT 4 /* ZC */ | ||
110 | #define WM8523_ZC_WIDTH 1 /* ZC */ | ||
111 | #define WM8523_DACR 0x0008 /* DACR */ | ||
112 | #define WM8523_DACR_MASK 0x0008 /* DACR */ | ||
113 | #define WM8523_DACR_SHIFT 3 /* DACR */ | ||
114 | #define WM8523_DACR_WIDTH 1 /* DACR */ | ||
115 | #define WM8523_DACL 0x0004 /* DACL */ | ||
116 | #define WM8523_DACL_MASK 0x0004 /* DACL */ | ||
117 | #define WM8523_DACL_SHIFT 2 /* DACL */ | ||
118 | #define WM8523_DACL_WIDTH 1 /* DACL */ | ||
119 | #define WM8523_VOL_UP_RAMP 0x0002 /* VOL_UP_RAMP */ | ||
120 | #define WM8523_VOL_UP_RAMP_MASK 0x0002 /* VOL_UP_RAMP */ | ||
121 | #define WM8523_VOL_UP_RAMP_SHIFT 1 /* VOL_UP_RAMP */ | ||
122 | #define WM8523_VOL_UP_RAMP_WIDTH 1 /* VOL_UP_RAMP */ | ||
123 | #define WM8523_VOL_DOWN_RAMP 0x0001 /* VOL_DOWN_RAMP */ | ||
124 | #define WM8523_VOL_DOWN_RAMP_MASK 0x0001 /* VOL_DOWN_RAMP */ | ||
125 | #define WM8523_VOL_DOWN_RAMP_SHIFT 0 /* VOL_DOWN_RAMP */ | ||
126 | #define WM8523_VOL_DOWN_RAMP_WIDTH 1 /* VOL_DOWN_RAMP */ | ||
127 | |||
128 | /* | ||
129 | * R6 (0x06) - DAC_GAINL | ||
130 | */ | ||
131 | #define WM8523_DACL_VU 0x0200 /* DACL_VU */ | ||
132 | #define WM8523_DACL_VU_MASK 0x0200 /* DACL_VU */ | ||
133 | #define WM8523_DACL_VU_SHIFT 9 /* DACL_VU */ | ||
134 | #define WM8523_DACL_VU_WIDTH 1 /* DACL_VU */ | ||
135 | #define WM8523_DACL_VOL_MASK 0x01FF /* DACL_VOL - [8:0] */ | ||
136 | #define WM8523_DACL_VOL_SHIFT 0 /* DACL_VOL - [8:0] */ | ||
137 | #define WM8523_DACL_VOL_WIDTH 9 /* DACL_VOL - [8:0] */ | ||
138 | |||
139 | /* | ||
140 | * R7 (0x07) - DAC_GAINR | ||
141 | */ | ||
142 | #define WM8523_DACR_VU 0x0200 /* DACR_VU */ | ||
143 | #define WM8523_DACR_VU_MASK 0x0200 /* DACR_VU */ | ||
144 | #define WM8523_DACR_VU_SHIFT 9 /* DACR_VU */ | ||
145 | #define WM8523_DACR_VU_WIDTH 1 /* DACR_VU */ | ||
146 | #define WM8523_DACR_VOL_MASK 0x01FF /* DACR_VOL - [8:0] */ | ||
147 | #define WM8523_DACR_VOL_SHIFT 0 /* DACR_VOL - [8:0] */ | ||
148 | #define WM8523_DACR_VOL_WIDTH 9 /* DACR_VOL - [8:0] */ | ||
149 | |||
150 | /* | ||
151 | * R8 (0x08) - ZERO_DETECT | ||
152 | */ | ||
153 | #define WM8523_ZD_COUNT_MASK 0x0003 /* ZD_COUNT - [1:0] */ | ||
154 | #define WM8523_ZD_COUNT_SHIFT 0 /* ZD_COUNT - [1:0] */ | ||
155 | #define WM8523_ZD_COUNT_WIDTH 2 /* ZD_COUNT - [1:0] */ | ||
156 | |||
157 | extern struct snd_soc_dai wm8523_dai; | ||
158 | extern struct snd_soc_codec_device soc_codec_dev_wm8523; | ||
159 | |||
160 | #endif | ||