aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-12-18 07:00:22 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-12-18 08:06:47 -0500
commitb35a28af0a64a1e8e389bc009b76253256d8fe7b (patch)
treef4f7113bb7654d8b8dc732ed099e7aaa0cf4e905
parentc2151433847e88ba05c6bb539d9397ea90d755e6 (diff)
ASoC: Add initial WM8955 CODEC driver
The WM8955 is a low power, high quality stereo DAC with integrated headphone and loudspeaker amplifiers, designed to reduce external component requirements in portable digital audio applications. This is an initial driver implementing support for the majority of the functionality in the device, currently OUT3 is not supported. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r--include/sound/wm8955.h26
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/wm8955.c1151
-rw-r--r--sound/soc/codecs/wm8955.h489
5 files changed, 1672 insertions, 0 deletions
diff --git a/include/sound/wm8955.h b/include/sound/wm8955.h
new file mode 100644
index 000000000000..5074ef499f40
--- /dev/null
+++ b/include/sound/wm8955.h
@@ -0,0 +1,26 @@
1/*
2 * Platform data for WM8955
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 it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#ifndef __WM8955_PDATA_H__
16#define __WM8955_PDATA_H__
17
18struct wm8955_pdata {
19 /* Configure LOUT2/ROUT2 to drive a speaker */
20 unsigned int out2_speaker:1;
21
22 /* Configure MONOIN+/- in differential mode */
23 unsigned int monoin_diff:1;
24};
25
26#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 691abe7df087..62ff26a08a2f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -52,6 +52,7 @@ config SND_SOC_ALL_CODECS
52 select SND_SOC_WM8903 if I2C 52 select SND_SOC_WM8903 if I2C
53 select SND_SOC_WM8904 if I2C 53 select SND_SOC_WM8904 if I2C
54 select SND_SOC_WM8940 if I2C 54 select SND_SOC_WM8940 if I2C
55 select SND_SOC_WM8955 if I2C
55 select SND_SOC_WM8960 if I2C 56 select SND_SOC_WM8960 if I2C
56 select SND_SOC_WM8961 if I2C 57 select SND_SOC_WM8961 if I2C
57 select SND_SOC_WM8971 if I2C 58 select SND_SOC_WM8971 if I2C
@@ -214,6 +215,9 @@ config SND_SOC_WM8904
214config SND_SOC_WM8940 215config SND_SOC_WM8940
215 tristate 216 tristate
216 217
218config SND_SOC_WM8955
219 tristate
220
217config SND_SOC_WM8960 221config SND_SOC_WM8960
218 tristate 222 tristate
219 223
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c0fd3c86edad..ea9835412e6a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ snd-soc-wm8900-objs := wm8900.o
39snd-soc-wm8903-objs := wm8903.o 39snd-soc-wm8903-objs := wm8903.o
40snd-soc-wm8904-objs := wm8904.o 40snd-soc-wm8904-objs := wm8904.o
41snd-soc-wm8940-objs := wm8940.o 41snd-soc-wm8940-objs := wm8940.o
42snd-soc-wm8955-objs := wm8955.o
42snd-soc-wm8960-objs := wm8960.o 43snd-soc-wm8960-objs := wm8960.o
43snd-soc-wm8961-objs := wm8961.o 44snd-soc-wm8961-objs := wm8961.o
44snd-soc-wm8971-objs := wm8971.o 45snd-soc-wm8971-objs := wm8971.o
@@ -97,6 +98,7 @@ obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
97obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o 98obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
98obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o 99obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o
99obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o 100obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o
101obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o
100obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o 102obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
101obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o 103obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
102obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o 104obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
new file mode 100644
index 000000000000..615dab2b62ef
--- /dev/null
+++ b/sound/soc/codecs/wm8955.c
@@ -0,0 +1,1151 @@
1/*
2 * wm8955.c -- WM8955 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/platform_device.h>
20#include <linux/regulator/consumer.h>
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/soc.h>
25#include <sound/soc-dapm.h>
26#include <sound/initval.h>
27#include <sound/tlv.h>
28#include <sound/wm8955.h>
29
30#include "wm8955.h"
31
32static struct snd_soc_codec *wm8955_codec;
33struct snd_soc_codec_device soc_codec_dev_wm8955;
34
35#define WM8955_NUM_SUPPLIES 4
36static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
37 "DCVDD",
38 "DBVDD",
39 "HPVDD",
40 "AVDD",
41};
42
43/* codec private data */
44struct wm8955_priv {
45 struct snd_soc_codec codec;
46 u16 reg_cache[WM8955_MAX_REGISTER + 1];
47
48 unsigned int mclk_rate;
49
50 int deemph;
51 int fs;
52
53 struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
54
55 struct wm8955_pdata *pdata;
56};
57
58static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
59 0x0000, /* R0 */
60 0x0000, /* R1 */
61 0x0079, /* R2 - LOUT1 volume */
62 0x0079, /* R3 - ROUT1 volume */
63 0x0000, /* R4 */
64 0x0008, /* R5 - DAC Control */
65 0x0000, /* R6 */
66 0x000A, /* R7 - Audio Interface */
67 0x0000, /* R8 - Sample Rate */
68 0x0000, /* R9 */
69 0x00FF, /* R10 - Left DAC volume */
70 0x00FF, /* R11 - Right DAC volume */
71 0x000F, /* R12 - Bass control */
72 0x000F, /* R13 - Treble control */
73 0x0000, /* R14 */
74 0x0000, /* R15 - Reset */
75 0x0000, /* R16 */
76 0x0000, /* R17 */
77 0x0000, /* R18 */
78 0x0000, /* R19 */
79 0x0000, /* R20 */
80 0x0000, /* R21 */
81 0x0000, /* R22 */
82 0x00C1, /* R23 - Additional control (1) */
83 0x0000, /* R24 - Additional control (2) */
84 0x0000, /* R25 - Power Management (1) */
85 0x0000, /* R26 - Power Management (2) */
86 0x0000, /* R27 - Additional Control (3) */
87 0x0000, /* R28 */
88 0x0000, /* R29 */
89 0x0000, /* R30 */
90 0x0000, /* R31 */
91 0x0000, /* R32 */
92 0x0000, /* R33 */
93 0x0050, /* R34 - Left out Mix (1) */
94 0x0050, /* R35 - Left out Mix (2) */
95 0x0050, /* R36 - Right out Mix (1) */
96 0x0050, /* R37 - Right Out Mix (2) */
97 0x0050, /* R38 - Mono out Mix (1) */
98 0x0050, /* R39 - Mono out Mix (2) */
99 0x0079, /* R40 - LOUT2 volume */
100 0x0079, /* R41 - ROUT2 volume */
101 0x0079, /* R42 - MONOOUT volume */
102 0x0000, /* R43 - Clocking / PLL */
103 0x0103, /* R44 - PLL Control 1 */
104 0x0024, /* R45 - PLL Control 2 */
105 0x01BA, /* R46 - PLL Control 3 */
106 0x0000, /* R47 */
107 0x0000, /* R48 */
108 0x0000, /* R49 */
109 0x0000, /* R50 */
110 0x0000, /* R51 */
111 0x0000, /* R52 */
112 0x0000, /* R53 */
113 0x0000, /* R54 */
114 0x0000, /* R55 */
115 0x0000, /* R56 */
116 0x0000, /* R57 */
117 0x0000, /* R58 */
118 0x0000, /* R59 - PLL Control 4 */
119};
120
121static int wm8955_reset(struct snd_soc_codec *codec)
122{
123 return snd_soc_write(codec, WM8955_RESET, 0);
124}
125
126struct pll_factors {
127 int n;
128 int k;
129 int outdiv;
130};
131
132/* The size in bits of the FLL divide multiplied by 10
133 * to allow rounding later */
134#define FIXED_FLL_SIZE ((1 << 22) * 10)
135
136static int wm8995_pll_factors(struct device *dev,
137 int Fref, int Fout, struct pll_factors *pll)
138{
139 u64 Kpart;
140 unsigned int K, Ndiv, Nmod, target;
141
142 dev_dbg(dev, "Fref=%u Fout=%u\n", Fref, Fout);
143
144 /* The oscilator should run at should be 90-100MHz, and
145 * there's a divide by 4 plus an optional divide by 2 in the
146 * output path to generate the system clock. The clock table
147 * is sortd so we should always generate a suitable target. */
148 target = Fout * 4;
149 if (target < 90000000) {
150 pll->outdiv = 1;
151 target *= 2;
152 } else {
153 pll->outdiv = 0;
154 }
155
156 WARN_ON(target < 90000000 || target > 100000000);
157
158 dev_dbg(dev, "Fvco=%dHz\n", target);
159
160 /* Now, calculate N.K */
161 Ndiv = target / Fref;
162
163 pll->n = Ndiv;
164 Nmod = target % Fref;
165 dev_dbg(dev, "Nmod=%d\n", Nmod);
166
167 /* Calculate fractional part - scale up so we can round. */
168 Kpart = FIXED_FLL_SIZE * (long long)Nmod;
169
170 do_div(Kpart, Fref);
171
172 K = Kpart & 0xFFFFFFFF;
173
174 if ((K % 10) >= 5)
175 K += 5;
176
177 /* Move down to proper range now rounding is done */
178 pll->k = K / 10;
179
180 dev_dbg(dev, "N=%x K=%x OUTDIV=%x\n", pll->n, pll->k, pll->outdiv);
181
182 return 0;
183}
184
185/* Lookup table specifiying SRATE (table 25 in datasheet); some of the
186 * output frequencies have been rounded to the standard frequencies
187 * they are intended to match where the error is slight. */
188static struct {
189 int mclk;
190 int fs;
191 int usb;
192 int sr;
193} clock_cfgs[] = {
194 { 18432000, 8000, 0, 3, },
195 { 18432000, 12000, 0, 9, },
196 { 18432000, 16000, 0, 11, },
197 { 18432000, 24000, 0, 29, },
198 { 18432000, 32000, 0, 13, },
199 { 18432000, 48000, 0, 1, },
200 { 18432000, 96000, 0, 15, },
201
202 { 16934400, 8018, 0, 19, },
203 { 16934400, 11025, 0, 25, },
204 { 16934400, 22050, 0, 27, },
205 { 16934400, 44100, 0, 17, },
206 { 16934400, 88200, 0, 31, },
207
208 { 12000000, 8000, 1, 2, },
209 { 12000000, 11025, 1, 25, },
210 { 12000000, 12000, 1, 8, },
211 { 12000000, 16000, 1, 10, },
212 { 12000000, 22050, 1, 27, },
213 { 12000000, 24000, 1, 28, },
214 { 12000000, 32000, 1, 12, },
215 { 12000000, 44100, 1, 17, },
216 { 12000000, 48000, 1, 0, },
217 { 12000000, 88200, 1, 31, },
218 { 12000000, 96000, 1, 14, },
219
220 { 12288000, 8000, 0, 2, },
221 { 12288000, 12000, 0, 8, },
222 { 12288000, 16000, 0, 10, },
223 { 12288000, 24000, 0, 28, },
224 { 12288000, 32000, 0, 12, },
225 { 12288000, 48000, 0, 0, },
226 { 12288000, 96000, 0, 14, },
227
228 { 12289600, 8018, 0, 18, },
229 { 12289600, 11025, 0, 24, },
230 { 12289600, 22050, 0, 26, },
231 { 11289600, 44100, 0, 16, },
232 { 11289600, 88200, 0, 31, },
233};
234
235static int wm8955_configure_clocking(struct snd_soc_codec *codec)
236{
237 struct wm8955_priv *wm8955 = codec->private_data;
238 int i, ret, val;
239 int clocking = 0;
240 int srate = 0;
241 int sr = -1;
242 struct pll_factors pll;
243
244 /* If we're not running a sample rate currently just pick one */
245 if (wm8955->fs == 0)
246 wm8955->fs = 8000;
247
248 /* Can we generate an exact output? */
249 for (i = 0; i < ARRAY_SIZE(clock_cfgs); i++) {
250 if (wm8955->fs != clock_cfgs[i].fs)
251 continue;
252 sr = i;
253
254 if (wm8955->mclk_rate == clock_cfgs[i].mclk)
255 break;
256 }
257
258 /* We should never get here with an unsupported sample rate */
259 if (sr == -1) {
260 dev_err(codec->dev, "Sample rate %dHz unsupported\n",
261 wm8955->fs);
262 WARN_ON(sr == -1);
263 return -EINVAL;
264 }
265
266 if (i == ARRAY_SIZE(clock_cfgs)) {
267 /* If we can't generate the right clock from MCLK then
268 * we should configure the PLL to supply us with an
269 * appropriate clock.
270 */
271 clocking |= WM8955_MCLKSEL;
272
273 /* Use the last divider configuration we saw for the
274 * sample rate. */
275 ret = wm8995_pll_factors(codec->dev, wm8955->mclk_rate,
276 clock_cfgs[sr].mclk, &pll);
277 if (ret != 0) {
278 dev_err(codec->dev,
279 "Unable to generate %dHz from %dHz MCLK\n",
280 wm8955->fs, wm8955->mclk_rate);
281 return -EINVAL;
282 }
283
284 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_1,
285 WM8955_N_MASK | WM8955_K_21_18_MASK,
286 (pll.n << WM8955_N_SHIFT) |
287 pll.k >> 18);
288 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
289 WM8955_K_17_9_MASK,
290 (pll.k >> 9) & WM8955_K_17_9_MASK);
291 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
292 WM8955_K_8_0_MASK,
293 pll.k & WM8955_K_8_0_MASK);
294 if (pll.k)
295 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4,
296 WM8955_KEN, WM8955_KEN);
297 else
298 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4,
299 WM8955_KEN, 0);
300
301 if (pll.outdiv)
302 val = WM8955_PLL_RB | WM8955_PLLOUTDIV2;
303 else
304 val = WM8955_PLL_RB;
305
306 /* Now start the PLL running */
307 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
308 WM8955_PLL_RB | WM8955_PLLOUTDIV2, val);
309 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
310 WM8955_PLLEN, WM8955_PLLEN);
311 }
312
313 srate = clock_cfgs[sr].usb | (clock_cfgs[sr].sr << WM8955_SR_SHIFT);
314
315 snd_soc_update_bits(codec, WM8955_SAMPLE_RATE,
316 WM8955_USB | WM8955_SR_MASK, srate);
317 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
318 WM8955_MCLKSEL, clocking);
319
320 return 0;
321}
322
323static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
324 struct snd_kcontrol *kcontrol, int event)
325{
326 struct snd_soc_codec *codec = w->codec;
327 int ret = 0;
328
329 /* Always disable the clocks - if we're doing reconfiguration this
330 * avoids misclocking.
331 */
332 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
333 WM8955_DIGENB, 0);
334 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
335 WM8955_PLL_RB | WM8955_PLLEN, 0);
336
337 switch (event) {
338 case SND_SOC_DAPM_POST_PMD:
339 break;
340 case SND_SOC_DAPM_PRE_PMU:
341 ret = wm8955_configure_clocking(codec);
342 break;
343 default:
344 ret = -EINVAL;
345 break;
346 }
347
348 return ret;
349}
350
351static int deemph_settings[] = { 0, 32000, 44100, 48000 };
352
353static int wm8955_set_deemph(struct snd_soc_codec *codec)
354{
355 struct wm8955_priv *wm8955 = codec->private_data;
356 int val, i, best;
357
358 /* If we're using deemphasis select the nearest available sample
359 * rate.
360 */
361 if (wm8955->deemph) {
362 best = 1;
363 for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
364 if (abs(deemph_settings[i] - wm8955->fs) <
365 abs(deemph_settings[best] - wm8955->fs))
366 best = i;
367 }
368
369 val = best << WM8955_DEEMPH_SHIFT;
370 } else {
371 val = 0;
372 }
373
374 dev_dbg(codec->dev, "Set deemphasis %d\n", val);
375
376 return snd_soc_update_bits(codec, WM8955_DAC_CONTROL,
377 WM8955_DEEMPH_MASK, val);
378}
379
380static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
381 struct snd_ctl_elem_value *ucontrol)
382{
383 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
384 struct wm8955_priv *wm8955 = codec->private_data;
385
386 return wm8955->deemph;
387}
388
389static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
390 struct snd_ctl_elem_value *ucontrol)
391{
392 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
393 struct wm8955_priv *wm8955 = codec->private_data;
394 int deemph = ucontrol->value.enumerated.item[0];
395
396 if (deemph > 1)
397 return -EINVAL;
398
399 wm8955->deemph = deemph;
400
401 return wm8955_set_deemph(codec);
402}
403
404static const char *bass_mode_text[] = {
405 "Linear", "Adaptive",
406};
407
408static const struct soc_enum bass_mode =
409 SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text);
410
411static const char *bass_cutoff_text[] = {
412 "Low", "High"
413};
414
415static const struct soc_enum bass_cutoff =
416 SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text);
417
418static const char *treble_cutoff_text[] = {
419 "High", "Low"
420};
421
422static const struct soc_enum treble_cutoff =
423 SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text);
424
425static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
426static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0);
427static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
428static const DECLARE_TLV_DB_SCALE(mono_tlv, -2100, 300, 0);
429static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
430static const DECLARE_TLV_DB_SCALE(treble_tlv, -1200, 150, 1);
431
432static const struct snd_kcontrol_new wm8955_snd_controls[] = {
433SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8955_LEFT_DAC_VOLUME,
434 WM8955_RIGHT_DAC_VOLUME, 0, 255, 0, digital_tlv),
435SOC_SINGLE_TLV("Playback Attenuation Volume", WM8955_DAC_CONTROL, 7, 1, 1,
436 atten_tlv),
437SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
438 wm8955_get_deemph, wm8955_put_deemph),
439
440SOC_ENUM("Bass Mode", bass_mode),
441SOC_ENUM("Bass Cutoff", bass_cutoff),
442SOC_SINGLE("Bass Volume", WM8955_BASS_CONTROL, 0, 15, 1),
443
444SOC_ENUM("Treble Cutoff", treble_cutoff),
445SOC_SINGLE_TLV("Treble Volume", WM8955_TREBLE_CONTROL, 0, 14, 1, treble_tlv),
446
447SOC_SINGLE_TLV("Left Bypass Volume", WM8955_LEFT_OUT_MIX_1, 4, 7, 1,
448 bypass_tlv),
449SOC_SINGLE_TLV("Left Mono Volume", WM8955_LEFT_OUT_MIX_2, 4, 7, 1,
450 bypass_tlv),
451
452SOC_SINGLE_TLV("Right Mono Volume", WM8955_RIGHT_OUT_MIX_1, 4, 7, 1,
453 bypass_tlv),
454SOC_SINGLE_TLV("Right Bypass Volume", WM8955_RIGHT_OUT_MIX_2, 4, 7, 1,
455 bypass_tlv),
456
457/* Not a stereo pair so they line up with the DAPM switches */
458SOC_SINGLE_TLV("Mono Left Bypass Volume", WM8955_MONO_OUT_MIX_1, 4, 7, 1,
459 mono_tlv),
460SOC_SINGLE_TLV("Mono Right Bypass Volume", WM8955_MONO_OUT_MIX_2, 4, 7, 1,
461 mono_tlv),
462
463SOC_DOUBLE_R_TLV("Headphone Volume", WM8955_LOUT1_VOLUME,
464 WM8955_ROUT1_VOLUME, 0, 127, 0, out_tlv),
465SOC_DOUBLE_R("Headphone ZC Switch", WM8955_LOUT1_VOLUME,
466 WM8955_ROUT1_VOLUME, 7, 1, 0),
467
468SOC_DOUBLE_R_TLV("Speaker Volume", WM8955_LOUT2_VOLUME,
469 WM8955_ROUT2_VOLUME, 0, 127, 0, out_tlv),
470SOC_DOUBLE_R("Speaker ZC Switch", WM8955_LOUT2_VOLUME,
471 WM8955_ROUT2_VOLUME, 7, 1, 0),
472
473SOC_SINGLE_TLV("Mono Volume", WM8955_MONOOUT_VOLUME, 0, 127, 0, out_tlv),
474SOC_SINGLE("Mono ZC Switch", WM8955_MONOOUT_VOLUME, 7, 1, 0),
475};
476
477static const struct snd_kcontrol_new lmixer[] = {
478SOC_DAPM_SINGLE("Playback Switch", WM8955_LEFT_OUT_MIX_1, 8, 1, 0),
479SOC_DAPM_SINGLE("Bypass Switch", WM8955_LEFT_OUT_MIX_1, 7, 1, 0),
480SOC_DAPM_SINGLE("Right Playback Switch", WM8955_LEFT_OUT_MIX_2, 8, 1, 0),
481SOC_DAPM_SINGLE("Mono Switch", WM8955_LEFT_OUT_MIX_2, 7, 1, 0),
482};
483
484static const struct snd_kcontrol_new rmixer[] = {
485SOC_DAPM_SINGLE("Left Playback Switch", WM8955_RIGHT_OUT_MIX_1, 8, 1, 0),
486SOC_DAPM_SINGLE("Mono Switch", WM8955_RIGHT_OUT_MIX_1, 7, 1, 0),
487SOC_DAPM_SINGLE("Playback Switch", WM8955_RIGHT_OUT_MIX_2, 8, 1, 0),
488SOC_DAPM_SINGLE("Bypass Switch", WM8955_RIGHT_OUT_MIX_2, 7, 1, 0),
489};
490
491static const struct snd_kcontrol_new mmixer[] = {
492SOC_DAPM_SINGLE("Left Playback Switch", WM8955_MONO_OUT_MIX_1, 8, 1, 0),
493SOC_DAPM_SINGLE("Left Bypass Switch", WM8955_MONO_OUT_MIX_1, 7, 1, 0),
494SOC_DAPM_SINGLE("Right Playback Switch", WM8955_MONO_OUT_MIX_2, 8, 1, 0),
495SOC_DAPM_SINGLE("Right Bypass Switch", WM8955_MONO_OUT_MIX_2, 7, 1, 0),
496};
497
498static const struct snd_soc_dapm_widget wm8955_dapm_widgets[] = {
499SND_SOC_DAPM_INPUT("MONOIN-"),
500SND_SOC_DAPM_INPUT("MONOIN+"),
501SND_SOC_DAPM_INPUT("LINEINR"),
502SND_SOC_DAPM_INPUT("LINEINL"),
503
504SND_SOC_DAPM_PGA("Mono Input", SND_SOC_NOPM, 0, 0, NULL, 0),
505
506SND_SOC_DAPM_SUPPLY("SYSCLK", WM8955_POWER_MANAGEMENT_1, 0, 1, wm8955_sysclk,
507 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
508SND_SOC_DAPM_SUPPLY("TSDEN", WM8955_ADDITIONAL_CONTROL_1, 8, 0, NULL, 0),
509
510SND_SOC_DAPM_DAC("DACL", "Playback", WM8955_POWER_MANAGEMENT_2, 8, 0),
511SND_SOC_DAPM_DAC("DACR", "Playback", WM8955_POWER_MANAGEMENT_2, 7, 0),
512
513SND_SOC_DAPM_PGA("LOUT1 PGA", WM8955_POWER_MANAGEMENT_2, 6, 0, NULL, 0),
514SND_SOC_DAPM_PGA("ROUT1 PGA", WM8955_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
515SND_SOC_DAPM_PGA("LOUT2 PGA", WM8955_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
516SND_SOC_DAPM_PGA("ROUT2 PGA", WM8955_POWER_MANAGEMENT_2, 3, 0, NULL, 0),
517SND_SOC_DAPM_PGA("MOUT PGA", WM8955_POWER_MANAGEMENT_2, 2, 0, NULL, 0),
518SND_SOC_DAPM_PGA("OUT3 PGA", WM8955_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
519
520/* The names are chosen to make the control names nice */
521SND_SOC_DAPM_MIXER("Left", SND_SOC_NOPM, 0, 0,
522 lmixer, ARRAY_SIZE(lmixer)),
523SND_SOC_DAPM_MIXER("Right", SND_SOC_NOPM, 0, 0,
524 rmixer, ARRAY_SIZE(rmixer)),
525SND_SOC_DAPM_MIXER("Mono", SND_SOC_NOPM, 0, 0,
526 mmixer, ARRAY_SIZE(mmixer)),
527
528SND_SOC_DAPM_OUTPUT("LOUT1"),
529SND_SOC_DAPM_OUTPUT("ROUT1"),
530SND_SOC_DAPM_OUTPUT("LOUT2"),
531SND_SOC_DAPM_OUTPUT("ROUT2"),
532SND_SOC_DAPM_OUTPUT("MONOOUT"),
533SND_SOC_DAPM_OUTPUT("OUT3"),
534};
535
536static const struct snd_soc_dapm_route wm8955_intercon[] = {
537 { "DACL", NULL, "SYSCLK" },
538 { "DACR", NULL, "SYSCLK" },
539
540 { "Mono Input", NULL, "MONOIN-" },
541 { "Mono Input", NULL, "MONOIN+" },
542
543 { "Left", "Playback Switch", "DACL" },
544 { "Left", "Right Playback Switch", "DACR" },
545 { "Left", "Bypass Switch", "LINEINL" },
546 { "Left", "Mono Switch", "Mono Input" },
547
548 { "Right", "Playback Switch", "DACR" },
549 { "Right", "Left Playback Switch", "DACL" },
550 { "Right", "Bypass Switch", "LINEINR" },
551 { "Right", "Mono Switch", "Mono Input" },
552
553 { "Mono", "Left Playback Switch", "DACL" },
554 { "Mono", "Right Playback Switch", "DACR" },
555 { "Mono", "Left Bypass Switch", "LINEINL" },
556 { "Mono", "Right Bypass Switch", "LINEINR" },
557
558 { "LOUT1 PGA", NULL, "Left" },
559 { "LOUT1", NULL, "TSDEN" },
560 { "LOUT1", NULL, "LOUT1 PGA" },
561
562 { "ROUT1 PGA", NULL, "Right" },
563 { "ROUT1", NULL, "TSDEN" },
564 { "ROUT1", NULL, "ROUT1 PGA" },
565
566 { "LOUT2 PGA", NULL, "Left" },
567 { "LOUT2", NULL, "TSDEN" },
568 { "LOUT2", NULL, "LOUT2 PGA" },
569
570 { "ROUT2 PGA", NULL, "Right" },
571 { "ROUT2", NULL, "TSDEN" },
572 { "ROUT2", NULL, "ROUT2 PGA" },
573
574 { "MOUT PGA", NULL, "Mono" },
575 { "MONOOUT", NULL, "MOUT PGA" },
576
577 /* OUT3 not currently implemented */
578 { "OUT3", NULL, "OUT3 PGA" },
579};
580
581static int wm8955_add_widgets(struct snd_soc_codec *codec)
582{
583 snd_soc_add_controls(codec, wm8955_snd_controls,
584 ARRAY_SIZE(wm8955_snd_controls));
585
586 snd_soc_dapm_new_controls(codec, wm8955_dapm_widgets,
587 ARRAY_SIZE(wm8955_dapm_widgets));
588
589 snd_soc_dapm_add_routes(codec, wm8955_intercon,
590 ARRAY_SIZE(wm8955_intercon));
591
592 return 0;
593}
594
595static int wm8955_hw_params(struct snd_pcm_substream *substream,
596 struct snd_pcm_hw_params *params,
597 struct snd_soc_dai *dai)
598{
599 struct snd_soc_codec *codec = dai->codec;
600 struct wm8955_priv *wm8955 = codec->private_data;
601 int ret;
602 int wl;
603
604 switch (params_format(params)) {
605 case SNDRV_PCM_FORMAT_S16_LE:
606 wl = 0;
607 break;
608 case SNDRV_PCM_FORMAT_S20_3LE:
609 wl = 0x4;
610 break;
611 case SNDRV_PCM_FORMAT_S24_LE:
612 wl = 0x8;
613 break;
614 case SNDRV_PCM_FORMAT_S32_LE:
615 wl = 0xc;
616 break;
617 default:
618 return -EINVAL;
619 }
620 snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE,
621 WM8955_WL_MASK, wl);
622
623 wm8955->fs = params_rate(params);
624 wm8955_set_deemph(codec);
625
626 /* If the chip is clocked then disable the clocks and force a
627 * reconfiguration, otherwise DAPM will power up the
628 * clocks for us later. */
629 ret = snd_soc_read(codec, WM8955_POWER_MANAGEMENT_1);
630 if (ret < 0)
631 return ret;
632 if (ret & WM8955_DIGENB) {
633 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
634 WM8955_DIGENB, 0);
635 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
636 WM8955_PLL_RB | WM8955_PLLEN, 0);
637
638 wm8955_configure_clocking(codec);
639 }
640
641 return 0;
642}
643
644
645static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id,
646 unsigned int freq, int dir)
647{
648 struct snd_soc_codec *codec = dai->codec;
649 struct wm8955_priv *priv = codec->private_data;
650 int div;
651
652 switch (clk_id) {
653 case WM8955_CLK_MCLK:
654 if (freq > 15000000) {
655 priv->mclk_rate = freq /= 2;
656 div = WM8955_MCLKDIV2;
657 } else {
658 priv->mclk_rate = freq;
659 div = 0;
660 }
661
662 snd_soc_update_bits(codec, WM8955_SAMPLE_RATE,
663 WM8955_MCLKDIV2, div);
664 break;
665
666 default:
667 return -EINVAL;
668 }
669
670 dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
671
672 return 0;
673}
674
675static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
676{
677 struct snd_soc_codec *codec = dai->codec;
678 u16 aif = 0;
679
680 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
681 case SND_SOC_DAIFMT_CBS_CFS:
682 break;
683 case SND_SOC_DAIFMT_CBM_CFM:
684 aif |= WM8955_MS;
685 break;
686 default:
687 return -EINVAL;
688 }
689
690 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
691 case SND_SOC_DAIFMT_DSP_B:
692 aif |= WM8955_LRP;
693 case SND_SOC_DAIFMT_DSP_A:
694 aif |= 0x3;
695 break;
696 case SND_SOC_DAIFMT_I2S:
697 aif |= 0x2;
698 break;
699 case SND_SOC_DAIFMT_RIGHT_J:
700 break;
701 case SND_SOC_DAIFMT_LEFT_J:
702 aif |= 0x1;
703 break;
704 default:
705 return -EINVAL;
706 }
707
708 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
709 case SND_SOC_DAIFMT_DSP_A:
710 case SND_SOC_DAIFMT_DSP_B:
711 /* frame inversion not valid for DSP modes */
712 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
713 case SND_SOC_DAIFMT_NB_NF:
714 break;
715 case SND_SOC_DAIFMT_IB_NF:
716 aif |= WM8955_BCLKINV;
717 break;
718 default:
719 return -EINVAL;
720 }
721 break;
722
723 case SND_SOC_DAIFMT_I2S:
724 case SND_SOC_DAIFMT_RIGHT_J:
725 case SND_SOC_DAIFMT_LEFT_J:
726 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
727 case SND_SOC_DAIFMT_NB_NF:
728 break;
729 case SND_SOC_DAIFMT_IB_IF:
730 aif |= WM8955_BCLKINV | WM8955_LRP;
731 break;
732 case SND_SOC_DAIFMT_IB_NF:
733 aif |= WM8955_BCLKINV;
734 break;
735 case SND_SOC_DAIFMT_NB_IF:
736 aif |= WM8955_LRP;
737 break;
738 default:
739 return -EINVAL;
740 }
741 break;
742 default:
743 return -EINVAL;
744 }
745
746 snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE,
747 WM8955_MS | WM8955_FORMAT_MASK | WM8955_BCLKINV |
748 WM8955_LRP, aif);
749
750 return 0;
751}
752
753
754static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute)
755{
756 struct snd_soc_codec *codec = codec_dai->codec;
757 int val;
758
759 if (mute)
760 val = WM8955_DACMU;
761 else
762 val = 0;
763
764 snd_soc_update_bits(codec, WM8955_DAC_CONTROL, WM8955_DACMU, val);
765
766 return 0;
767}
768
769static int wm8955_set_bias_level(struct snd_soc_codec *codec,
770 enum snd_soc_bias_level level)
771{
772 struct wm8955_priv *wm8955 = codec->private_data;
773 int ret, i;
774
775 switch (level) {
776 case SND_SOC_BIAS_ON:
777 break;
778
779 case SND_SOC_BIAS_PREPARE:
780 /* VMID resistance 2*50k */
781 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
782 WM8955_VMIDSEL_MASK,
783 0x1 << WM8955_VMIDSEL_SHIFT);
784
785 /* Default bias current */
786 snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1,
787 WM8955_VSEL_MASK,
788 0x2 << WM8955_VSEL_SHIFT);
789 break;
790
791 case SND_SOC_BIAS_STANDBY:
792 if (codec->bias_level == SND_SOC_BIAS_OFF) {
793 ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
794 wm8955->supplies);
795 if (ret != 0) {
796 dev_err(codec->dev,
797 "Failed to enable supplies: %d\n",
798 ret);
799 return ret;
800 }
801
802 /* Sync back cached values if they're
803 * different from the hardware default.
804 */
805 for (i = 0; i < ARRAY_SIZE(wm8955->reg_cache); i++) {
806 if (i == WM8955_RESET)
807 continue;
808
809 if (wm8955->reg_cache[i] == wm8955_reg[i])
810 continue;
811
812 snd_soc_write(codec, i, wm8955->reg_cache[i]);
813 }
814
815 /* Enable VREF and VMID */
816 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
817 WM8955_VREF |
818 WM8955_VMIDSEL_MASK,
819 WM8955_VREF |
820 0x3 << WM8955_VREF_SHIFT);
821
822 /* Let VMID ramp */
823 msleep(500);
824
825 /* High resistance VROI to maintain outputs */
826 snd_soc_update_bits(codec,
827 WM8955_ADDITIONAL_CONTROL_3,
828 WM8955_VROI, WM8955_VROI);
829 }
830
831 /* Maintain VMID with 2*250k */
832 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
833 WM8955_VMIDSEL_MASK,
834 0x2 << WM8955_VMIDSEL_SHIFT);
835
836 /* Minimum bias current */
837 snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1,
838 WM8955_VSEL_MASK, 0);
839 break;
840
841 case SND_SOC_BIAS_OFF:
842 /* Low resistance VROI to help discharge */
843 snd_soc_update_bits(codec,
844 WM8955_ADDITIONAL_CONTROL_3,
845 WM8955_VROI, 0);
846
847 /* Turn off VMID and VREF */
848 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
849 WM8955_VREF |
850 WM8955_VMIDSEL_MASK, 0);
851
852 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies),
853 wm8955->supplies);
854 break;
855 }
856 codec->bias_level = level;
857 return 0;
858}
859
860#define WM8955_RATES SNDRV_PCM_RATE_8000_96000
861
862#define WM8955_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
863 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
864
865static struct snd_soc_dai_ops wm8955_dai_ops = {
866 .set_sysclk = wm8955_set_sysclk,
867 .set_fmt = wm8955_set_fmt,
868 .hw_params = wm8955_hw_params,
869 .digital_mute = wm8955_digital_mute,
870};
871
872struct snd_soc_dai wm8955_dai = {
873 .name = "WM8955",
874 .playback = {
875 .stream_name = "Playback",
876 .channels_min = 2,
877 .channels_max = 2,
878 .rates = WM8955_RATES,
879 .formats = WM8955_FORMATS,
880 },
881 .ops = &wm8955_dai_ops,
882};
883EXPORT_SYMBOL_GPL(wm8955_dai);
884
885#ifdef CONFIG_PM
886static int wm8955_suspend(struct platform_device *pdev, pm_message_t state)
887{
888 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
889 struct snd_soc_codec *codec = socdev->card->codec;
890
891 wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
892
893 return 0;
894}
895
896static int wm8955_resume(struct platform_device *pdev)
897{
898 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
899 struct snd_soc_codec *codec = socdev->card->codec;
900
901 wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
902
903 return 0;
904}
905#else
906#define wm8955_suspend NULL
907#define wm8955_resume NULL
908#endif
909
910static int wm8955_probe(struct platform_device *pdev)
911{
912 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
913 struct snd_soc_codec *codec;
914 int ret = 0;
915
916 if (wm8955_codec == NULL) {
917 dev_err(&pdev->dev, "Codec device not registered\n");
918 return -ENODEV;
919 }
920
921 socdev->card->codec = wm8955_codec;
922 codec = wm8955_codec;
923
924 /* register pcms */
925 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
926 if (ret < 0) {
927 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
928 goto pcm_err;
929 }
930
931 wm8955_add_widgets(codec);
932
933 return ret;
934
935pcm_err:
936 return ret;
937}
938
939static int wm8955_remove(struct platform_device *pdev)
940{
941 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
942
943 snd_soc_free_pcms(socdev);
944 snd_soc_dapm_free(socdev);
945
946 return 0;
947}
948
949struct snd_soc_codec_device soc_codec_dev_wm8955 = {
950 .probe = wm8955_probe,
951 .remove = wm8955_remove,
952 .suspend = wm8955_suspend,
953 .resume = wm8955_resume,
954};
955EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955);
956
957static int wm8955_register(struct wm8955_priv *wm8955,
958 enum snd_soc_control_type control)
959{
960 int ret;
961 struct snd_soc_codec *codec = &wm8955->codec;
962 int i;
963
964 if (wm8955_codec) {
965 dev_err(codec->dev, "Another WM8955 is registered\n");
966 return -EINVAL;
967 }
968
969 mutex_init(&codec->mutex);
970 INIT_LIST_HEAD(&codec->dapm_widgets);
971 INIT_LIST_HEAD(&codec->dapm_paths);
972
973 codec->private_data = wm8955;
974 codec->name = "WM8955";
975 codec->owner = THIS_MODULE;
976 codec->bias_level = SND_SOC_BIAS_OFF;
977 codec->set_bias_level = wm8955_set_bias_level;
978 codec->dai = &wm8955_dai;
979 codec->num_dai = 1;
980 codec->reg_cache_size = WM8955_MAX_REGISTER;
981 codec->reg_cache = &wm8955->reg_cache;
982
983 memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg));
984
985 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
986 if (ret != 0) {
987 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
988 goto err;
989 }
990
991 for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
992 wm8955->supplies[i].supply = wm8955_supply_names[i];
993
994 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),
995 wm8955->supplies);
996 if (ret != 0) {
997 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
998 goto err;
999 }
1000
1001 ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
1002 wm8955->supplies);
1003 if (ret != 0) {
1004 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
1005 goto err_get;
1006 }
1007
1008 ret = wm8955_reset(codec);
1009 if (ret < 0) {
1010 dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
1011 goto err_enable;
1012 }
1013
1014 wm8955_dai.dev = codec->dev;
1015
1016 /* Change some default settings - latch VU and enable ZC */
1017 wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
1018 wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
1019 wm8955->reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC;
1020 wm8955->reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC;
1021 wm8955->reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC;
1022 wm8955->reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC;
1023 wm8955->reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC;
1024
1025 /* Also enable adaptive bass boost by default */
1026 wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
1027
1028 /* Set platform data values */
1029 if (wm8955->pdata) {
1030 if (wm8955->pdata->out2_speaker)
1031 wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
1032 |= WM8955_ROUT2INV;
1033
1034 if (wm8955->pdata->monoin_diff)
1035 wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
1036 |= WM8955_DMEN;
1037 }
1038
1039 wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1040
1041 /* Bias level configuration will have done an extra enable */
1042 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1043
1044 wm8955_codec = codec;
1045
1046 ret = snd_soc_register_codec(codec);
1047 if (ret != 0) {
1048 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
1049 return ret;
1050 }
1051
1052 ret = snd_soc_register_dai(&wm8955_dai);
1053 if (ret != 0) {
1054 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
1055 snd_soc_unregister_codec(codec);
1056 return ret;
1057 }
1058
1059 return 0;
1060
1061err_enable:
1062 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1063err_get:
1064 regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1065err:
1066 kfree(wm8955);
1067 return ret;
1068}
1069
1070static void wm8955_unregister(struct wm8955_priv *wm8955)
1071{
1072 wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF);
1073 regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1074 snd_soc_unregister_dai(&wm8955_dai);
1075 snd_soc_unregister_codec(&wm8955->codec);
1076 kfree(wm8955);
1077 wm8955_codec = NULL;
1078}
1079
1080#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1081static __devinit int wm8955_i2c_probe(struct i2c_client *i2c,
1082 const struct i2c_device_id *id)
1083{
1084 struct wm8955_priv *wm8955;
1085 struct snd_soc_codec *codec;
1086
1087 wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL);
1088 if (wm8955 == NULL)
1089 return -ENOMEM;
1090
1091 codec = &wm8955->codec;
1092 codec->hw_write = (hw_write_t)i2c_master_send;
1093
1094 i2c_set_clientdata(i2c, wm8955);
1095 codec->control_data = i2c;
1096 wm8955->pdata = i2c->dev.platform_data;
1097
1098 codec->dev = &i2c->dev;
1099
1100 return wm8955_register(wm8955, SND_SOC_I2C);
1101}
1102
1103static __devexit int wm8955_i2c_remove(struct i2c_client *client)
1104{
1105 struct wm8955_priv *wm8955 = i2c_get_clientdata(client);
1106 wm8955_unregister(wm8955);
1107 return 0;
1108}
1109
1110static const struct i2c_device_id wm8955_i2c_id[] = {
1111 { "wm8955", 0 },
1112 { }
1113};
1114MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
1115
1116static struct i2c_driver wm8955_i2c_driver = {
1117 .driver = {
1118 .name = "wm8955",
1119 .owner = THIS_MODULE,
1120 },
1121 .probe = wm8955_i2c_probe,
1122 .remove = __devexit_p(wm8955_i2c_remove),
1123 .id_table = wm8955_i2c_id,
1124};
1125#endif
1126
1127static int __init wm8955_modinit(void)
1128{
1129 int ret;
1130#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1131 ret = i2c_add_driver(&wm8955_i2c_driver);
1132 if (ret != 0) {
1133 printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n",
1134 ret);
1135 }
1136#endif
1137 return 0;
1138}
1139module_init(wm8955_modinit);
1140
1141static void __exit wm8955_exit(void)
1142{
1143#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1144 i2c_del_driver(&wm8955_i2c_driver);
1145#endif
1146}
1147module_exit(wm8955_exit);
1148
1149MODULE_DESCRIPTION("ASoC WM8955 driver");
1150MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1151MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8955.h b/sound/soc/codecs/wm8955.h
new file mode 100644
index 000000000000..ae349c8531f6
--- /dev/null
+++ b/sound/soc/codecs/wm8955.h
@@ -0,0 +1,489 @@
1/*
2 * wm8955.h -- WM8904 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 _WM8955_H
14#define _WM8955_H
15
16#define WM8955_CLK_MCLK 1
17
18extern struct snd_soc_dai wm8955_dai;
19extern struct snd_soc_codec_device soc_codec_dev_wm8955;
20
21/*
22 * Register values.
23 */
24#define WM8955_LOUT1_VOLUME 0x02
25#define WM8955_ROUT1_VOLUME 0x03
26#define WM8955_DAC_CONTROL 0x05
27#define WM8955_AUDIO_INTERFACE 0x07
28#define WM8955_SAMPLE_RATE 0x08
29#define WM8955_LEFT_DAC_VOLUME 0x0A
30#define WM8955_RIGHT_DAC_VOLUME 0x0B
31#define WM8955_BASS_CONTROL 0x0C
32#define WM8955_TREBLE_CONTROL 0x0D
33#define WM8955_RESET 0x0F
34#define WM8955_ADDITIONAL_CONTROL_1 0x17
35#define WM8955_ADDITIONAL_CONTROL_2 0x18
36#define WM8955_POWER_MANAGEMENT_1 0x19
37#define WM8955_POWER_MANAGEMENT_2 0x1A
38#define WM8955_ADDITIONAL_CONTROL_3 0x1B
39#define WM8955_LEFT_OUT_MIX_1 0x22
40#define WM8955_LEFT_OUT_MIX_2 0x23
41#define WM8955_RIGHT_OUT_MIX_1 0x24
42#define WM8955_RIGHT_OUT_MIX_2 0x25
43#define WM8955_MONO_OUT_MIX_1 0x26
44#define WM8955_MONO_OUT_MIX_2 0x27
45#define WM8955_LOUT2_VOLUME 0x28
46#define WM8955_ROUT2_VOLUME 0x29
47#define WM8955_MONOOUT_VOLUME 0x2A
48#define WM8955_CLOCKING_PLL 0x2B
49#define WM8955_PLL_CONTROL_1 0x2C
50#define WM8955_PLL_CONTROL_2 0x2D
51#define WM8955_PLL_CONTROL_3 0x2E
52#define WM8955_PLL_CONTROL_4 0x3B
53
54#define WM8955_REGISTER_COUNT 29
55#define WM8955_MAX_REGISTER 0x3B
56
57/*
58 * Field Definitions.
59 */
60
61/*
62 * R2 (0x02) - LOUT1 volume
63 */
64#define WM8955_LO1VU 0x0100 /* LO1VU */
65#define WM8955_LO1VU_MASK 0x0100 /* LO1VU */
66#define WM8955_LO1VU_SHIFT 8 /* LO1VU */
67#define WM8955_LO1VU_WIDTH 1 /* LO1VU */
68#define WM8955_LO1ZC 0x0080 /* LO1ZC */
69#define WM8955_LO1ZC_MASK 0x0080 /* LO1ZC */
70#define WM8955_LO1ZC_SHIFT 7 /* LO1ZC */
71#define WM8955_LO1ZC_WIDTH 1 /* LO1ZC */
72#define WM8955_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */
73#define WM8955_LOUTVOL_SHIFT 0 /* LOUTVOL - [6:0] */
74#define WM8955_LOUTVOL_WIDTH 7 /* LOUTVOL - [6:0] */
75
76/*
77 * R3 (0x03) - ROUT1 volume
78 */
79#define WM8955_RO1VU 0x0100 /* RO1VU */
80#define WM8955_RO1VU_MASK 0x0100 /* RO1VU */
81#define WM8955_RO1VU_SHIFT 8 /* RO1VU */
82#define WM8955_RO1VU_WIDTH 1 /* RO1VU */
83#define WM8955_RO1ZC 0x0080 /* RO1ZC */
84#define WM8955_RO1ZC_MASK 0x0080 /* RO1ZC */
85#define WM8955_RO1ZC_SHIFT 7 /* RO1ZC */
86#define WM8955_RO1ZC_WIDTH 1 /* RO1ZC */
87#define WM8955_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */
88#define WM8955_ROUTVOL_SHIFT 0 /* ROUTVOL - [6:0] */
89#define WM8955_ROUTVOL_WIDTH 7 /* ROUTVOL - [6:0] */
90
91/*
92 * R5 (0x05) - DAC Control
93 */
94#define WM8955_DAT 0x0080 /* DAT */
95#define WM8955_DAT_MASK 0x0080 /* DAT */
96#define WM8955_DAT_SHIFT 7 /* DAT */
97#define WM8955_DAT_WIDTH 1 /* DAT */
98#define WM8955_DACMU 0x0008 /* DACMU */
99#define WM8955_DACMU_MASK 0x0008 /* DACMU */
100#define WM8955_DACMU_SHIFT 3 /* DACMU */
101#define WM8955_DACMU_WIDTH 1 /* DACMU */
102#define WM8955_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */
103#define WM8955_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */
104#define WM8955_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */
105
106/*
107 * R7 (0x07) - Audio Interface
108 */
109#define WM8955_BCLKINV 0x0080 /* BCLKINV */
110#define WM8955_BCLKINV_MASK 0x0080 /* BCLKINV */
111#define WM8955_BCLKINV_SHIFT 7 /* BCLKINV */
112#define WM8955_BCLKINV_WIDTH 1 /* BCLKINV */
113#define WM8955_MS 0x0040 /* MS */
114#define WM8955_MS_MASK 0x0040 /* MS */
115#define WM8955_MS_SHIFT 6 /* MS */
116#define WM8955_MS_WIDTH 1 /* MS */
117#define WM8955_LRSWAP 0x0020 /* LRSWAP */
118#define WM8955_LRSWAP_MASK 0x0020 /* LRSWAP */
119#define WM8955_LRSWAP_SHIFT 5 /* LRSWAP */
120#define WM8955_LRSWAP_WIDTH 1 /* LRSWAP */
121#define WM8955_LRP 0x0010 /* LRP */
122#define WM8955_LRP_MASK 0x0010 /* LRP */
123#define WM8955_LRP_SHIFT 4 /* LRP */
124#define WM8955_LRP_WIDTH 1 /* LRP */
125#define WM8955_WL_MASK 0x000C /* WL - [3:2] */
126#define WM8955_WL_SHIFT 2 /* WL - [3:2] */
127#define WM8955_WL_WIDTH 2 /* WL - [3:2] */
128#define WM8955_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */
129#define WM8955_FORMAT_SHIFT 0 /* FORMAT - [1:0] */
130#define WM8955_FORMAT_WIDTH 2 /* FORMAT - [1:0] */
131
132/*
133 * R8 (0x08) - Sample Rate
134 */
135#define WM8955_BCLKDIV2 0x0080 /* BCLKDIV2 */
136#define WM8955_BCLKDIV2_MASK 0x0080 /* BCLKDIV2 */
137#define WM8955_BCLKDIV2_SHIFT 7 /* BCLKDIV2 */
138#define WM8955_BCLKDIV2_WIDTH 1 /* BCLKDIV2 */
139#define WM8955_MCLKDIV2 0x0040 /* MCLKDIV2 */
140#define WM8955_MCLKDIV2_MASK 0x0040 /* MCLKDIV2 */
141#define WM8955_MCLKDIV2_SHIFT 6 /* MCLKDIV2 */
142#define WM8955_MCLKDIV2_WIDTH 1 /* MCLKDIV2 */
143#define WM8955_SR_MASK 0x003E /* SR - [5:1] */
144#define WM8955_SR_SHIFT 1 /* SR - [5:1] */
145#define WM8955_SR_WIDTH 5 /* SR - [5:1] */
146#define WM8955_USB 0x0001 /* USB */
147#define WM8955_USB_MASK 0x0001 /* USB */
148#define WM8955_USB_SHIFT 0 /* USB */
149#define WM8955_USB_WIDTH 1 /* USB */
150
151/*
152 * R10 (0x0A) - Left DAC volume
153 */
154#define WM8955_LDVU 0x0100 /* LDVU */
155#define WM8955_LDVU_MASK 0x0100 /* LDVU */
156#define WM8955_LDVU_SHIFT 8 /* LDVU */
157#define WM8955_LDVU_WIDTH 1 /* LDVU */
158#define WM8955_LDACVOL_MASK 0x00FF /* LDACVOL - [7:0] */
159#define WM8955_LDACVOL_SHIFT 0 /* LDACVOL - [7:0] */
160#define WM8955_LDACVOL_WIDTH 8 /* LDACVOL - [7:0] */
161
162/*
163 * R11 (0x0B) - Right DAC volume
164 */
165#define WM8955_RDVU 0x0100 /* RDVU */
166#define WM8955_RDVU_MASK 0x0100 /* RDVU */
167#define WM8955_RDVU_SHIFT 8 /* RDVU */
168#define WM8955_RDVU_WIDTH 1 /* RDVU */
169#define WM8955_RDACVOL_MASK 0x00FF /* RDACVOL - [7:0] */
170#define WM8955_RDACVOL_SHIFT 0 /* RDACVOL - [7:0] */
171#define WM8955_RDACVOL_WIDTH 8 /* RDACVOL - [7:0] */
172
173/*
174 * R12 (0x0C) - Bass control
175 */
176#define WM8955_BB 0x0080 /* BB */
177#define WM8955_BB_MASK 0x0080 /* BB */
178#define WM8955_BB_SHIFT 7 /* BB */
179#define WM8955_BB_WIDTH 1 /* BB */
180#define WM8955_BC 0x0040 /* BC */
181#define WM8955_BC_MASK 0x0040 /* BC */
182#define WM8955_BC_SHIFT 6 /* BC */
183#define WM8955_BC_WIDTH 1 /* BC */
184#define WM8955_BASS_MASK 0x000F /* BASS - [3:0] */
185#define WM8955_BASS_SHIFT 0 /* BASS - [3:0] */
186#define WM8955_BASS_WIDTH 4 /* BASS - [3:0] */
187
188/*
189 * R13 (0x0D) - Treble control
190 */
191#define WM8955_TC 0x0040 /* TC */
192#define WM8955_TC_MASK 0x0040 /* TC */
193#define WM8955_TC_SHIFT 6 /* TC */
194#define WM8955_TC_WIDTH 1 /* TC */
195#define WM8955_TRBL_MASK 0x000F /* TRBL - [3:0] */
196#define WM8955_TRBL_SHIFT 0 /* TRBL - [3:0] */
197#define WM8955_TRBL_WIDTH 4 /* TRBL - [3:0] */
198
199/*
200 * R15 (0x0F) - Reset
201 */
202#define WM8955_RESET_MASK 0x01FF /* RESET - [8:0] */
203#define WM8955_RESET_SHIFT 0 /* RESET - [8:0] */
204#define WM8955_RESET_WIDTH 9 /* RESET - [8:0] */
205
206/*
207 * R23 (0x17) - Additional control (1)
208 */
209#define WM8955_TSDEN 0x0100 /* TSDEN */
210#define WM8955_TSDEN_MASK 0x0100 /* TSDEN */
211#define WM8955_TSDEN_SHIFT 8 /* TSDEN */
212#define WM8955_TSDEN_WIDTH 1 /* TSDEN */
213#define WM8955_VSEL_MASK 0x00C0 /* VSEL - [7:6] */
214#define WM8955_VSEL_SHIFT 6 /* VSEL - [7:6] */
215#define WM8955_VSEL_WIDTH 2 /* VSEL - [7:6] */
216#define WM8955_DMONOMIX_MASK 0x0030 /* DMONOMIX - [5:4] */
217#define WM8955_DMONOMIX_SHIFT 4 /* DMONOMIX - [5:4] */
218#define WM8955_DMONOMIX_WIDTH 2 /* DMONOMIX - [5:4] */
219#define WM8955_DACINV 0x0002 /* DACINV */
220#define WM8955_DACINV_MASK 0x0002 /* DACINV */
221#define WM8955_DACINV_SHIFT 1 /* DACINV */
222#define WM8955_DACINV_WIDTH 1 /* DACINV */
223#define WM8955_TOEN 0x0001 /* TOEN */
224#define WM8955_TOEN_MASK 0x0001 /* TOEN */
225#define WM8955_TOEN_SHIFT 0 /* TOEN */
226#define WM8955_TOEN_WIDTH 1 /* TOEN */
227
228/*
229 * R24 (0x18) - Additional control (2)
230 */
231#define WM8955_OUT3SW_MASK 0x0180 /* OUT3SW - [8:7] */
232#define WM8955_OUT3SW_SHIFT 7 /* OUT3SW - [8:7] */
233#define WM8955_OUT3SW_WIDTH 2 /* OUT3SW - [8:7] */
234#define WM8955_ROUT2INV 0x0010 /* ROUT2INV */
235#define WM8955_ROUT2INV_MASK 0x0010 /* ROUT2INV */
236#define WM8955_ROUT2INV_SHIFT 4 /* ROUT2INV */
237#define WM8955_ROUT2INV_WIDTH 1 /* ROUT2INV */
238#define WM8955_DACOSR 0x0001 /* DACOSR */
239#define WM8955_DACOSR_MASK 0x0001 /* DACOSR */
240#define WM8955_DACOSR_SHIFT 0 /* DACOSR */
241#define WM8955_DACOSR_WIDTH 1 /* DACOSR */
242
243/*
244 * R25 (0x19) - Power Management (1)
245 */
246#define WM8955_VMIDSEL_MASK 0x0180 /* VMIDSEL - [8:7] */
247#define WM8955_VMIDSEL_SHIFT 7 /* VMIDSEL - [8:7] */
248#define WM8955_VMIDSEL_WIDTH 2 /* VMIDSEL - [8:7] */
249#define WM8955_VREF 0x0040 /* VREF */
250#define WM8955_VREF_MASK 0x0040 /* VREF */
251#define WM8955_VREF_SHIFT 6 /* VREF */
252#define WM8955_VREF_WIDTH 1 /* VREF */
253#define WM8955_DIGENB 0x0001 /* DIGENB */
254#define WM8955_DIGENB_MASK 0x0001 /* DIGENB */
255#define WM8955_DIGENB_SHIFT 0 /* DIGENB */
256#define WM8955_DIGENB_WIDTH 1 /* DIGENB */
257
258/*
259 * R26 (0x1A) - Power Management (2)
260 */
261#define WM8955_DACL 0x0100 /* DACL */
262#define WM8955_DACL_MASK 0x0100 /* DACL */
263#define WM8955_DACL_SHIFT 8 /* DACL */
264#define WM8955_DACL_WIDTH 1 /* DACL */
265#define WM8955_DACR 0x0080 /* DACR */
266#define WM8955_DACR_MASK 0x0080 /* DACR */
267#define WM8955_DACR_SHIFT 7 /* DACR */
268#define WM8955_DACR_WIDTH 1 /* DACR */
269#define WM8955_LOUT1 0x0040 /* LOUT1 */
270#define WM8955_LOUT1_MASK 0x0040 /* LOUT1 */
271#define WM8955_LOUT1_SHIFT 6 /* LOUT1 */
272#define WM8955_LOUT1_WIDTH 1 /* LOUT1 */
273#define WM8955_ROUT1 0x0020 /* ROUT1 */
274#define WM8955_ROUT1_MASK 0x0020 /* ROUT1 */
275#define WM8955_ROUT1_SHIFT 5 /* ROUT1 */
276#define WM8955_ROUT1_WIDTH 1 /* ROUT1 */
277#define WM8955_LOUT2 0x0010 /* LOUT2 */
278#define WM8955_LOUT2_MASK 0x0010 /* LOUT2 */
279#define WM8955_LOUT2_SHIFT 4 /* LOUT2 */
280#define WM8955_LOUT2_WIDTH 1 /* LOUT2 */
281#define WM8955_ROUT2 0x0008 /* ROUT2 */
282#define WM8955_ROUT2_MASK 0x0008 /* ROUT2 */
283#define WM8955_ROUT2_SHIFT 3 /* ROUT2 */
284#define WM8955_ROUT2_WIDTH 1 /* ROUT2 */
285#define WM8955_MONO 0x0004 /* MONO */
286#define WM8955_MONO_MASK 0x0004 /* MONO */
287#define WM8955_MONO_SHIFT 2 /* MONO */
288#define WM8955_MONO_WIDTH 1 /* MONO */
289#define WM8955_OUT3 0x0002 /* OUT3 */
290#define WM8955_OUT3_MASK 0x0002 /* OUT3 */
291#define WM8955_OUT3_SHIFT 1 /* OUT3 */
292#define WM8955_OUT3_WIDTH 1 /* OUT3 */
293
294/*
295 * R27 (0x1B) - Additional Control (3)
296 */
297#define WM8955_VROI 0x0040 /* VROI */
298#define WM8955_VROI_MASK 0x0040 /* VROI */
299#define WM8955_VROI_SHIFT 6 /* VROI */
300#define WM8955_VROI_WIDTH 1 /* VROI */
301
302/*
303 * R34 (0x22) - Left out Mix (1)
304 */
305#define WM8955_LD2LO 0x0100 /* LD2LO */
306#define WM8955_LD2LO_MASK 0x0100 /* LD2LO */
307#define WM8955_LD2LO_SHIFT 8 /* LD2LO */
308#define WM8955_LD2LO_WIDTH 1 /* LD2LO */
309#define WM8955_LI2LO 0x0080 /* LI2LO */
310#define WM8955_LI2LO_MASK 0x0080 /* LI2LO */
311#define WM8955_LI2LO_SHIFT 7 /* LI2LO */
312#define WM8955_LI2LO_WIDTH 1 /* LI2LO */
313#define WM8955_LI2LOVOL_MASK 0x0070 /* LI2LOVOL - [6:4] */
314#define WM8955_LI2LOVOL_SHIFT 4 /* LI2LOVOL - [6:4] */
315#define WM8955_LI2LOVOL_WIDTH 3 /* LI2LOVOL - [6:4] */
316
317/*
318 * R35 (0x23) - Left out Mix (2)
319 */
320#define WM8955_RD2LO 0x0100 /* RD2LO */
321#define WM8955_RD2LO_MASK 0x0100 /* RD2LO */
322#define WM8955_RD2LO_SHIFT 8 /* RD2LO */
323#define WM8955_RD2LO_WIDTH 1 /* RD2LO */
324#define WM8955_RI2LO 0x0080 /* RI2LO */
325#define WM8955_RI2LO_MASK 0x0080 /* RI2LO */
326#define WM8955_RI2LO_SHIFT 7 /* RI2LO */
327#define WM8955_RI2LO_WIDTH 1 /* RI2LO */
328#define WM8955_RI2LOVOL_MASK 0x0070 /* RI2LOVOL - [6:4] */
329#define WM8955_RI2LOVOL_SHIFT 4 /* RI2LOVOL - [6:4] */
330#define WM8955_RI2LOVOL_WIDTH 3 /* RI2LOVOL - [6:4] */
331
332/*
333 * R36 (0x24) - Right out Mix (1)
334 */
335#define WM8955_LD2RO 0x0100 /* LD2RO */
336#define WM8955_LD2RO_MASK 0x0100 /* LD2RO */
337#define WM8955_LD2RO_SHIFT 8 /* LD2RO */
338#define WM8955_LD2RO_WIDTH 1 /* LD2RO */
339#define WM8955_LI2RO 0x0080 /* LI2RO */
340#define WM8955_LI2RO_MASK 0x0080 /* LI2RO */
341#define WM8955_LI2RO_SHIFT 7 /* LI2RO */
342#define WM8955_LI2RO_WIDTH 1 /* LI2RO */
343#define WM8955_LI2ROVOL_MASK 0x0070 /* LI2ROVOL - [6:4] */
344#define WM8955_LI2ROVOL_SHIFT 4 /* LI2ROVOL - [6:4] */
345#define WM8955_LI2ROVOL_WIDTH 3 /* LI2ROVOL - [6:4] */
346
347/*
348 * R37 (0x25) - Right Out Mix (2)
349 */
350#define WM8955_RD2RO 0x0100 /* RD2RO */
351#define WM8955_RD2RO_MASK 0x0100 /* RD2RO */
352#define WM8955_RD2RO_SHIFT 8 /* RD2RO */
353#define WM8955_RD2RO_WIDTH 1 /* RD2RO */
354#define WM8955_RI2RO 0x0080 /* RI2RO */
355#define WM8955_RI2RO_MASK 0x0080 /* RI2RO */
356#define WM8955_RI2RO_SHIFT 7 /* RI2RO */
357#define WM8955_RI2RO_WIDTH 1 /* RI2RO */
358#define WM8955_RI2ROVOL_MASK 0x0070 /* RI2ROVOL - [6:4] */
359#define WM8955_RI2ROVOL_SHIFT 4 /* RI2ROVOL - [6:4] */
360#define WM8955_RI2ROVOL_WIDTH 3 /* RI2ROVOL - [6:4] */
361
362/*
363 * R38 (0x26) - Mono out Mix (1)
364 */
365#define WM8955_LD2MO 0x0100 /* LD2MO */
366#define WM8955_LD2MO_MASK 0x0100 /* LD2MO */
367#define WM8955_LD2MO_SHIFT 8 /* LD2MO */
368#define WM8955_LD2MO_WIDTH 1 /* LD2MO */
369#define WM8955_LI2MO 0x0080 /* LI2MO */
370#define WM8955_LI2MO_MASK 0x0080 /* LI2MO */
371#define WM8955_LI2MO_SHIFT 7 /* LI2MO */
372#define WM8955_LI2MO_WIDTH 1 /* LI2MO */
373#define WM8955_LI2MOVOL_MASK 0x0070 /* LI2MOVOL - [6:4] */
374#define WM8955_LI2MOVOL_SHIFT 4 /* LI2MOVOL - [6:4] */
375#define WM8955_LI2MOVOL_WIDTH 3 /* LI2MOVOL - [6:4] */
376#define WM8955_DMEN 0x0001 /* DMEN */
377#define WM8955_DMEN_MASK 0x0001 /* DMEN */
378#define WM8955_DMEN_SHIFT 0 /* DMEN */
379#define WM8955_DMEN_WIDTH 1 /* DMEN */
380
381/*
382 * R39 (0x27) - Mono out Mix (2)
383 */
384#define WM8955_RD2MO 0x0100 /* RD2MO */
385#define WM8955_RD2MO_MASK 0x0100 /* RD2MO */
386#define WM8955_RD2MO_SHIFT 8 /* RD2MO */
387#define WM8955_RD2MO_WIDTH 1 /* RD2MO */
388#define WM8955_RI2MO 0x0080 /* RI2MO */
389#define WM8955_RI2MO_MASK 0x0080 /* RI2MO */
390#define WM8955_RI2MO_SHIFT 7 /* RI2MO */
391#define WM8955_RI2MO_WIDTH 1 /* RI2MO */
392#define WM8955_RI2MOVOL_MASK 0x0070 /* RI2MOVOL - [6:4] */
393#define WM8955_RI2MOVOL_SHIFT 4 /* RI2MOVOL - [6:4] */
394#define WM8955_RI2MOVOL_WIDTH 3 /* RI2MOVOL - [6:4] */
395
396/*
397 * R40 (0x28) - LOUT2 volume
398 */
399#define WM8955_LO2VU 0x0100 /* LO2VU */
400#define WM8955_LO2VU_MASK 0x0100 /* LO2VU */
401#define WM8955_LO2VU_SHIFT 8 /* LO2VU */
402#define WM8955_LO2VU_WIDTH 1 /* LO2VU */
403#define WM8955_LO2ZC 0x0080 /* LO2ZC */
404#define WM8955_LO2ZC_MASK 0x0080 /* LO2ZC */
405#define WM8955_LO2ZC_SHIFT 7 /* LO2ZC */
406#define WM8955_LO2ZC_WIDTH 1 /* LO2ZC */
407#define WM8955_LOUT2VOL_MASK 0x007F /* LOUT2VOL - [6:0] */
408#define WM8955_LOUT2VOL_SHIFT 0 /* LOUT2VOL - [6:0] */
409#define WM8955_LOUT2VOL_WIDTH 7 /* LOUT2VOL - [6:0] */
410
411/*
412 * R41 (0x29) - ROUT2 volume
413 */
414#define WM8955_RO2VU 0x0100 /* RO2VU */
415#define WM8955_RO2VU_MASK 0x0100 /* RO2VU */
416#define WM8955_RO2VU_SHIFT 8 /* RO2VU */
417#define WM8955_RO2VU_WIDTH 1 /* RO2VU */
418#define WM8955_RO2ZC 0x0080 /* RO2ZC */
419#define WM8955_RO2ZC_MASK 0x0080 /* RO2ZC */
420#define WM8955_RO2ZC_SHIFT 7 /* RO2ZC */
421#define WM8955_RO2ZC_WIDTH 1 /* RO2ZC */
422#define WM8955_ROUT2VOL_MASK 0x007F /* ROUT2VOL - [6:0] */
423#define WM8955_ROUT2VOL_SHIFT 0 /* ROUT2VOL - [6:0] */
424#define WM8955_ROUT2VOL_WIDTH 7 /* ROUT2VOL - [6:0] */
425
426/*
427 * R42 (0x2A) - MONOOUT volume
428 */
429#define WM8955_MOZC 0x0080 /* MOZC */
430#define WM8955_MOZC_MASK 0x0080 /* MOZC */
431#define WM8955_MOZC_SHIFT 7 /* MOZC */
432#define WM8955_MOZC_WIDTH 1 /* MOZC */
433#define WM8955_MOUTVOL_MASK 0x007F /* MOUTVOL - [6:0] */
434#define WM8955_MOUTVOL_SHIFT 0 /* MOUTVOL - [6:0] */
435#define WM8955_MOUTVOL_WIDTH 7 /* MOUTVOL - [6:0] */
436
437/*
438 * R43 (0x2B) - Clocking / PLL
439 */
440#define WM8955_MCLKSEL 0x0100 /* MCLKSEL */
441#define WM8955_MCLKSEL_MASK 0x0100 /* MCLKSEL */
442#define WM8955_MCLKSEL_SHIFT 8 /* MCLKSEL */
443#define WM8955_MCLKSEL_WIDTH 1 /* MCLKSEL */
444#define WM8955_PLLOUTDIV2 0x0020 /* PLLOUTDIV2 */
445#define WM8955_PLLOUTDIV2_MASK 0x0020 /* PLLOUTDIV2 */
446#define WM8955_PLLOUTDIV2_SHIFT 5 /* PLLOUTDIV2 */
447#define WM8955_PLLOUTDIV2_WIDTH 1 /* PLLOUTDIV2 */
448#define WM8955_PLL_RB 0x0010 /* PLL_RB */
449#define WM8955_PLL_RB_MASK 0x0010 /* PLL_RB */
450#define WM8955_PLL_RB_SHIFT 4 /* PLL_RB */
451#define WM8955_PLL_RB_WIDTH 1 /* PLL_RB */
452#define WM8955_PLLEN 0x0008 /* PLLEN */
453#define WM8955_PLLEN_MASK 0x0008 /* PLLEN */
454#define WM8955_PLLEN_SHIFT 3 /* PLLEN */
455#define WM8955_PLLEN_WIDTH 1 /* PLLEN */
456
457/*
458 * R44 (0x2C) - PLL Control 1
459 */
460#define WM8955_N_MASK 0x01E0 /* N - [8:5] */
461#define WM8955_N_SHIFT 5 /* N - [8:5] */
462#define WM8955_N_WIDTH 4 /* N - [8:5] */
463#define WM8955_K_21_18_MASK 0x000F /* K(21:18) - [3:0] */
464#define WM8955_K_21_18_SHIFT 0 /* K(21:18) - [3:0] */
465#define WM8955_K_21_18_WIDTH 4 /* K(21:18) - [3:0] */
466
467/*
468 * R45 (0x2D) - PLL Control 2
469 */
470#define WM8955_K_17_9_MASK 0x01FF /* K(17:9) - [8:0] */
471#define WM8955_K_17_9_SHIFT 0 /* K(17:9) - [8:0] */
472#define WM8955_K_17_9_WIDTH 9 /* K(17:9) - [8:0] */
473
474/*
475 * R46 (0x2E) - PLL Control 3
476 */
477#define WM8955_K_8_0_MASK 0x01FF /* K(8:0) - [8:0] */
478#define WM8955_K_8_0_SHIFT 0 /* K(8:0) - [8:0] */
479#define WM8955_K_8_0_WIDTH 9 /* K(8:0) - [8:0] */
480
481/*
482 * R59 (0x3B) - PLL Control 4
483 */
484#define WM8955_KEN 0x0080 /* KEN */
485#define WM8955_KEN_MASK 0x0080 /* KEN */
486#define WM8955_KEN_SHIFT 7 /* KEN */
487#define WM8955_KEN_WIDTH 1 /* KEN */
488
489#endif