aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-11-23 14:31:18 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-11-24 06:33:12 -0500
commit2a9ae13a2641373d06e24f866c7427644c39bfea (patch)
tree55a703f403f6918a218d58b696e1eab1a4a83600 /sound
parenta1c1f770e3653bfcd5dd664d8471f70d220e19f3 (diff)
ASoC: Add initial WM8737 driver
The WM8737 is a low power, flexible stereo ADC designed for portable applications. This driver supports most of the functionality of the WM8737, though some features such as the ALC are not yet implemented. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/wm8737.c713
-rw-r--r--sound/soc/codecs/wm8737.h322
4 files changed, 1041 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6ebd3a685b2c..0f33db2be25a 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -55,6 +55,7 @@ config SND_SOC_ALL_CODECS
55 select SND_SOC_WM8727 55 select SND_SOC_WM8727
56 select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI 56 select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
57 select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI 57 select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
58 select SND_SOC_WM8737 if SND_SOC_I2C_AND_SPI
58 select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI 59 select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI
59 select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI 60 select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
60 select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI 61 select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
@@ -236,6 +237,9 @@ config SND_SOC_WM8728
236config SND_SOC_WM8731 237config SND_SOC_WM8731
237 tristate 238 tristate
238 239
240config SND_SOC_WM8737
241 tristate
242
239config SND_SOC_WM8741 243config SND_SOC_WM8741
240 tristate 244 tristate
241 245
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3469fab2863a..10e5e099334a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ snd-soc-wm8711-objs := wm8711.o
39snd-soc-wm8727-objs := wm8727.o 39snd-soc-wm8727-objs := wm8727.o
40snd-soc-wm8728-objs := wm8728.o 40snd-soc-wm8728-objs := wm8728.o
41snd-soc-wm8731-objs := wm8731.o 41snd-soc-wm8731-objs := wm8731.o
42snd-soc-wm8737-objs := wm8737.o
42snd-soc-wm8741-objs := wm8741.o 43snd-soc-wm8741-objs := wm8741.o
43snd-soc-wm8750-objs := wm8750.o 44snd-soc-wm8750-objs := wm8750.o
44snd-soc-wm8753-objs := wm8753.o 45snd-soc-wm8753-objs := wm8753.o
@@ -116,6 +117,7 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o
116obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o 117obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o
117obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o 118obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
118obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o 119obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
120obj-$(CONFIG_SND_SOC_WM8737) += snd-soc-wm8737.o
119obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o 121obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o
120obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o 122obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
121obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o 123obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
new file mode 100644
index 000000000000..a325fe60d26c
--- /dev/null
+++ b/sound/soc/codecs/wm8737.c
@@ -0,0 +1,713 @@
1/*
2 * wm8737.c -- WM8737 ALSA SoC Audio driver
3 *
4 * Copyright 2010 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 <linux/spi/spi.h>
22#include <linux/slab.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 "wm8737.h"
32
33#define WM8737_NUM_SUPPLIES 4
34static const char *wm8737_supply_names[WM8737_NUM_SUPPLIES] = {
35 "DCVDD",
36 "DBVDD",
37 "AVDD",
38 "MVDD",
39};
40
41/* codec private data */
42struct wm8737_priv {
43 enum snd_soc_control_type control_type;
44 struct regulator_bulk_data supplies[WM8737_NUM_SUPPLIES];
45 unsigned int mclk;
46};
47
48static const u16 wm8737_reg[WM8737_REGISTER_COUNT] = {
49 0x00C3, /* R0 - Left PGA volume */
50 0x00C3, /* R1 - Right PGA volume */
51 0x0007, /* R2 - AUDIO path L */
52 0x0007, /* R3 - AUDIO path R */
53 0x0000, /* R4 - 3D Enhance */
54 0x0000, /* R5 - ADC Control */
55 0x0000, /* R6 - Power Management */
56 0x000A, /* R7 - Audio Format */
57 0x0000, /* R8 - Clocking */
58 0x000F, /* R9 - MIC Preamp Control */
59 0x0003, /* R10 - Misc Bias Control */
60 0x0000, /* R11 - Noise Gate */
61 0x007C, /* R12 - ALC1 */
62 0x0000, /* R13 - ALC2 */
63 0x0032, /* R14 - ALC3 */
64};
65
66static int wm8737_reset(struct snd_soc_codec *codec)
67{
68 return snd_soc_write(codec, WM8737_RESET, 0);
69}
70
71static const unsigned int micboost_tlv[] = {
72 TLV_DB_RANGE_HEAD(4),
73 0, 0, TLV_DB_SCALE_ITEM(1300, 0, 0),
74 1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
75 2, 2, TLV_DB_SCALE_ITEM(2800, 0, 0),
76 3, 3, TLV_DB_SCALE_ITEM(3300, 0, 0),
77};
78static const DECLARE_TLV_DB_SCALE(pga_tlv, -9750, 50, 1);
79static const DECLARE_TLV_DB_SCALE(adc_tlv, -600, 600, 0);
80static const DECLARE_TLV_DB_SCALE(ng_tlv, -7800, 600, 0);
81
82static const char *micbias_enum_text[] = {
83 "25%",
84 "50%",
85 "75%",
86 "100%",
87};
88
89static const struct soc_enum micbias_enum =
90 SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 0, 4, micbias_enum_text);
91
92static const char *low_cutoff_text[] = {
93 "Low", "High"
94};
95
96static const struct soc_enum low_3d =
97 SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 6, 2, low_cutoff_text);
98
99static const char *high_cutoff_text[] = {
100 "High", "Low"
101};
102
103static const struct soc_enum high_3d =
104 SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 5, 2, high_cutoff_text);
105
106static const struct snd_kcontrol_new wm8737_snd_controls[] = {
107SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
108 6, 3, 0, micboost_tlv),
109SOC_DOUBLE_R("Mic Boost Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
110 4, 1, 0),
111SOC_DOUBLE("Mic ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
112 3, 1, 0),
113
114SOC_DOUBLE_R_TLV("Capture Volume", WM8737_LEFT_PGA_VOLUME,
115 WM8737_RIGHT_PGA_VOLUME, 0, 255, 0, pga_tlv),
116SOC_DOUBLE("Capture ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
117 2, 1, 0),
118
119SOC_DOUBLE("INPUT1 DC Bias Switch", WM8737_MISC_BIAS_CONTROL, 0, 1, 1, 0),
120
121SOC_ENUM("Mic PGA Bias", micbias_enum),
122SOC_SINGLE("ADC Low Power Switch", WM8737_ADC_CONTROL, 2, 1, 0),
123SOC_SINGLE("High Pass Filter Switch", WM8737_ADC_CONTROL, 0, 1, 1),
124SOC_DOUBLE("Polarity Invert Switch", WM8737_ADC_CONTROL, 5, 6, 1, 0),
125
126SOC_SINGLE("3D Switch", WM8737_3D_ENHANCE, 0, 1, 0),
127SOC_SINGLE("3D Depth", WM8737_3D_ENHANCE, 1, 15, 0),
128SOC_ENUM("3D Low Cut-off", low_3d),
129SOC_ENUM("3D High Cut-off", low_3d),
130SOC_SINGLE_TLV("3D ADC Volume", WM8737_3D_ENHANCE, 7, 1, 1, adc_tlv),
131
132SOC_SINGLE("Noise Gate Switch", WM8737_NOISE_GATE, 0, 1, 0),
133SOC_SINGLE_TLV("Noise Gate Threshold Volume", WM8737_NOISE_GATE, 2, 7, 0,
134 ng_tlv),
135};
136
137static const char *linsel_text[] = {
138 "LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC",
139};
140
141static const struct soc_enum linsel_enum =
142 SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_L, 7, 4, linsel_text);
143
144static const struct snd_kcontrol_new linsel_mux =
145 SOC_DAPM_ENUM("LINSEL", linsel_enum);
146
147
148static const char *rinsel_text[] = {
149 "RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC",
150};
151
152static const struct soc_enum rinsel_enum =
153 SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_R, 7, 4, rinsel_text);
154
155static const struct snd_kcontrol_new rinsel_mux =
156 SOC_DAPM_ENUM("RINSEL", rinsel_enum);
157
158static const char *bypass_text[] = {
159 "Direct", "Preamp"
160};
161
162static const struct soc_enum lbypass_enum =
163 SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 2, 2, bypass_text);
164
165static const struct snd_kcontrol_new lbypass_mux =
166 SOC_DAPM_ENUM("Left Bypass", lbypass_enum);
167
168
169static const struct soc_enum rbypass_enum =
170 SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 3, 2, bypass_text);
171
172static const struct snd_kcontrol_new rbypass_mux =
173 SOC_DAPM_ENUM("Left Bypass", rbypass_enum);
174
175static const struct snd_soc_dapm_widget wm8737_dapm_widgets[] = {
176SND_SOC_DAPM_INPUT("LINPUT1"),
177SND_SOC_DAPM_INPUT("LINPUT2"),
178SND_SOC_DAPM_INPUT("LINPUT3"),
179SND_SOC_DAPM_INPUT("RINPUT1"),
180SND_SOC_DAPM_INPUT("RINPUT2"),
181SND_SOC_DAPM_INPUT("RINPUT3"),
182SND_SOC_DAPM_INPUT("LACIN"),
183SND_SOC_DAPM_INPUT("RACIN"),
184
185SND_SOC_DAPM_MUX("LINSEL", SND_SOC_NOPM, 0, 0, &linsel_mux),
186SND_SOC_DAPM_MUX("RINSEL", SND_SOC_NOPM, 0, 0, &rinsel_mux),
187
188SND_SOC_DAPM_MUX("Left Preamp Mux", SND_SOC_NOPM, 0, 0, &lbypass_mux),
189SND_SOC_DAPM_MUX("Right Preamp Mux", SND_SOC_NOPM, 0, 0, &rbypass_mux),
190
191SND_SOC_DAPM_PGA("PGAL", WM8737_POWER_MANAGEMENT, 5, 0, NULL, 0),
192SND_SOC_DAPM_PGA("PGAR", WM8737_POWER_MANAGEMENT, 4, 0, NULL, 0),
193
194SND_SOC_DAPM_DAC("ADCL", NULL, WM8737_POWER_MANAGEMENT, 3, 0),
195SND_SOC_DAPM_DAC("ADCR", NULL, WM8737_POWER_MANAGEMENT, 2, 0),
196
197SND_SOC_DAPM_AIF_OUT("AIF", "Capture", 0, WM8737_POWER_MANAGEMENT, 6, 0),
198};
199
200static const struct snd_soc_dapm_route intercon[] = {
201 { "LINSEL", "LINPUT1", "LINPUT1" },
202 { "LINSEL", "LINPUT2", "LINPUT2" },
203 { "LINSEL", "LINPUT3", "LINPUT3" },
204 { "LINSEL", "LINPUT1 DC", "LINPUT1" },
205
206 { "RINSEL", "RINPUT1", "RINPUT1" },
207 { "RINSEL", "RINPUT2", "RINPUT2" },
208 { "RINSEL", "RINPUT3", "RINPUT3" },
209 { "RINSEL", "RINPUT1 DC", "RINPUT1" },
210
211 { "Left Preamp Mux", "Preamp", "LINSEL" },
212 { "Left Preamp Mux", "Direct", "LACIN" },
213
214 { "Right Preamp Mux", "Preamp", "RINSEL" },
215 { "Right Preamp Mux", "Direct", "RACIN" },
216
217 { "PGAL", NULL, "Left Preamp Mux" },
218 { "PGAR", NULL, "Right Preamp Mux" },
219
220 { "ADCL", NULL, "PGAL" },
221 { "ADCR", NULL, "PGAR" },
222
223 { "AIF", NULL, "ADCL" },
224 { "AIF", NULL, "ADCR" },
225};
226
227static int wm8737_add_widgets(struct snd_soc_codec *codec)
228{
229 struct snd_soc_dapm_context *dapm = &codec->dapm;
230
231 snd_soc_dapm_new_controls(dapm, wm8737_dapm_widgets,
232 ARRAY_SIZE(wm8737_dapm_widgets));
233 snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
234
235 return 0;
236}
237
238/* codec mclk clock divider coefficients */
239static const struct {
240 u32 mclk;
241 u32 rate;
242 u8 usb;
243 u8 sr;
244} coeff_div[] = {
245 { 12288000, 8000, 0, 0x4 },
246 { 12288000, 12000, 0, 0x8 },
247 { 12288000, 16000, 0, 0xa },
248 { 12288000, 24000, 0, 0x1c },
249 { 12288000, 32000, 0, 0xc },
250 { 12288000, 48000, 0, 0 },
251 { 12288000, 96000, 0, 0xe },
252
253 { 11289600, 8000, 0, 0x14 },
254 { 11289600, 11025, 0, 0x18 },
255 { 11289600, 22050, 0, 0x1a },
256 { 11289600, 44100, 0, 0x10 },
257 { 11289600, 88200, 0, 0x1e },
258
259 { 18432000, 8000, 0, 0x5 },
260 { 18432000, 12000, 0, 0x9 },
261 { 18432000, 16000, 0, 0xb },
262 { 18432000, 24000, 0, 0x1b },
263 { 18432000, 32000, 0, 0xd },
264 { 18432000, 48000, 0, 0x1 },
265 { 18432000, 96000, 0, 0x1f },
266
267 { 16934400, 8000, 0, 0x15 },
268 { 16934400, 11025, 0, 0x19 },
269 { 16934400, 22050, 0, 0x1b },
270 { 16934400, 44100, 0, 0x11 },
271 { 16934400, 88200, 0, 0x1f },
272
273 { 12000000, 8000, 1, 0x4 },
274 { 12000000, 11025, 1, 0x19 },
275 { 12000000, 12000, 1, 0x8 },
276 { 12000000, 16000, 1, 0xa },
277 { 12000000, 22050, 1, 0x1b },
278 { 12000000, 24000, 1, 0x1c },
279 { 12000000, 32000, 1, 0xc },
280 { 12000000, 44100, 1, 0x11 },
281 { 12000000, 48000, 1, 0x0 },
282 { 12000000, 88200, 1, 0x1f },
283 { 12000000, 96000, 1, 0xe },
284};
285
286static int wm8737_hw_params(struct snd_pcm_substream *substream,
287 struct snd_pcm_hw_params *params,
288 struct snd_soc_dai *dai)
289{
290 struct snd_soc_pcm_runtime *rtd = substream->private_data;
291 struct snd_soc_codec *codec = rtd->codec;
292 struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
293 int i;
294 u16 clocking = 0;
295 u16 af = 0;
296
297 for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
298 if (coeff_div[i].rate != params_rate(params))
299 continue;
300
301 if (coeff_div[i].mclk == wm8737->mclk)
302 break;
303
304 if (coeff_div[i].mclk == wm8737->mclk * 2) {
305 clocking |= WM8737_CLKDIV2;
306 break;
307 }
308 }
309
310 if (i == ARRAY_SIZE(coeff_div)) {
311 dev_err(codec->dev, "%dHz MCLK can't support %dHz\n",
312 wm8737->mclk, params_rate(params));
313 return -EINVAL;
314 }
315
316 clocking |= coeff_div[i].usb | (coeff_div[i].sr << WM8737_SR_SHIFT);
317
318 switch (params_format(params)) {
319 case SNDRV_PCM_FORMAT_S16_LE:
320 break;
321 case SNDRV_PCM_FORMAT_S20_3LE:
322 af |= 0x8;
323 break;
324 case SNDRV_PCM_FORMAT_S24_LE:
325 af |= 0x10;
326 break;
327 case SNDRV_PCM_FORMAT_S32_LE:
328 af |= 0x18;
329 break;
330 default:
331 return -EINVAL;
332 }
333
334 snd_soc_update_bits(codec, WM8737_AUDIO_FORMAT, WM8737_WL_MASK, af);
335 snd_soc_update_bits(codec, WM8737_CLOCKING,
336 WM8737_USB_MODE | WM8737_CLKDIV2 | WM8737_SR_MASK,
337 clocking);
338
339 return 0;
340}
341
342static int wm8737_set_dai_sysclk(struct snd_soc_dai *codec_dai,
343 int clk_id, unsigned int freq, int dir)
344{
345 struct snd_soc_codec *codec = codec_dai->codec;
346 struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
347 int i;
348
349 for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
350 if (freq == coeff_div[i].mclk ||
351 freq == coeff_div[i].mclk * 2) {
352 wm8737->mclk = freq;
353 return 0;
354 }
355 }
356
357 dev_err(codec->dev, "MCLK rate %dHz not supported\n", freq);
358
359 return -EINVAL;
360}
361
362
363static int wm8737_set_dai_fmt(struct snd_soc_dai *codec_dai,
364 unsigned int fmt)
365{
366 struct snd_soc_codec *codec = codec_dai->codec;
367 u16 af = 0;
368
369 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
370 case SND_SOC_DAIFMT_CBM_CFM:
371 af |= WM8737_MS;
372 break;
373 case SND_SOC_DAIFMT_CBS_CFS:
374 break;
375 default:
376 return -EINVAL;
377 }
378
379 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
380 case SND_SOC_DAIFMT_I2S:
381 af |= 0x2;
382 break;
383 case SND_SOC_DAIFMT_RIGHT_J:
384 break;
385 case SND_SOC_DAIFMT_LEFT_J:
386 af |= 0x1;
387 break;
388 case SND_SOC_DAIFMT_DSP_A:
389 af |= 0x3;
390 break;
391 case SND_SOC_DAIFMT_DSP_B:
392 af |= 0x13;
393 break;
394 default:
395 return -EINVAL;
396 }
397
398 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
399 case SND_SOC_DAIFMT_NB_NF:
400 break;
401 case SND_SOC_DAIFMT_NB_IF:
402 af |= WM8737_LRP;
403 break;
404 default:
405 return -EINVAL;
406 }
407
408 snd_soc_update_bits(codec, WM8737_AUDIO_FORMAT,
409 WM8737_FORMAT_MASK | WM8737_LRP | WM8737_MS, af);
410
411 return 0;
412}
413
414static int wm8737_set_bias_level(struct snd_soc_codec *codec,
415 enum snd_soc_bias_level level)
416{
417 struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
418 int ret;
419
420 switch (level) {
421 case SND_SOC_BIAS_ON:
422 break;
423
424 case SND_SOC_BIAS_PREPARE:
425 /* VMID at 2*75k */
426 snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
427 WM8737_VMIDSEL_MASK, 0);
428 break;
429
430 case SND_SOC_BIAS_STANDBY:
431 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
432 ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
433 wm8737->supplies);
434 if (ret != 0) {
435 dev_err(codec->dev,
436 "Failed to enable supplies: %d\n",
437 ret);
438 return ret;
439 }
440
441 snd_soc_cache_sync(codec);
442
443 /* Fast VMID ramp at 2*2.5k */
444 snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
445 WM8737_VMIDSEL_MASK, 0x4);
446
447 /* Bring VMID up */
448 snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
449 WM8737_VMID_MASK |
450 WM8737_VREF_MASK,
451 WM8737_VMID_MASK |
452 WM8737_VREF_MASK);
453
454 msleep(500);
455 }
456
457 /* VMID at 2*300k */
458 snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
459 WM8737_VMIDSEL_MASK, 2);
460
461 break;
462
463 case SND_SOC_BIAS_OFF:
464 snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
465 WM8737_VMID_MASK | WM8737_VREF_MASK, 0);
466
467 regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies),
468 wm8737->supplies);
469 break;
470 }
471
472 codec->dapm.bias_level = level;
473 return 0;
474}
475
476#define WM8737_RATES SNDRV_PCM_RATE_8000_96000
477
478#define WM8737_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
479 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
480
481static struct snd_soc_dai_ops wm8737_dai_ops = {
482 .hw_params = wm8737_hw_params,
483 .set_sysclk = wm8737_set_dai_sysclk,
484 .set_fmt = wm8737_set_dai_fmt,
485};
486
487static struct snd_soc_dai_driver wm8737_dai = {
488 .name = "wm8737",
489 .capture = {
490 .stream_name = "Capture",
491 .channels_min = 2, /* Mono modes not yet supported */
492 .channels_max = 2,
493 .rates = WM8737_RATES,
494 .formats = WM8737_FORMATS,
495 },
496 .ops = &wm8737_dai_ops,
497};
498
499#ifdef CONFIG_PM
500static int wm8737_suspend(struct snd_soc_codec *codec, pm_message_t state)
501{
502 wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
503 return 0;
504}
505
506static int wm8737_resume(struct snd_soc_codec *codec)
507{
508 wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
509 return 0;
510}
511#else
512#define wm8737_suspend NULL
513#define wm8737_resume NULL
514#endif
515
516static int wm8737_probe(struct snd_soc_codec *codec)
517{
518 struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
519 int ret, i;
520
521 codec->hw_write = (hw_write_t)i2c_master_send;
522 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8737->control_type);
523 if (ret != 0) {
524 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
525 return ret;
526 }
527
528 for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++)
529 wm8737->supplies[i].supply = wm8737_supply_names[i];
530
531 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8737->supplies),
532 wm8737->supplies);
533 if (ret != 0) {
534 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
535 return ret;
536 }
537
538 ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
539 wm8737->supplies);
540 if (ret != 0) {
541 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
542 goto err_get;
543 }
544
545 ret = wm8737_reset(codec);
546 if (ret < 0) {
547 dev_err(codec->dev, "Failed to issue reset\n");
548 goto err_enable;
549 }
550
551 snd_soc_update_bits(codec, WM8737_LEFT_PGA_VOLUME, WM8737_LVU,
552 WM8737_LVU);
553 snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
554 WM8737_RVU);
555
556 wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
557
558 /* Bias level configuration will have done an extra enable */
559 regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
560
561 snd_soc_add_controls(codec, wm8737_snd_controls,
562 ARRAY_SIZE(wm8737_snd_controls));
563 wm8737_add_widgets(codec);
564
565 return 0;
566
567err_enable:
568 regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
569err_get:
570 regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
571
572 return ret;
573}
574
575static int wm8737_remove(struct snd_soc_codec *codec)
576{
577 struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
578
579 wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
580 regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
581 return 0;
582}
583
584static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
585 .probe = wm8737_probe,
586 .remove = wm8737_remove,
587 .suspend = wm8737_suspend,
588 .resume = wm8737_resume,
589 .set_bias_level = wm8737_set_bias_level,
590
591 .reg_cache_size = WM8737_REGISTER_COUNT - 1, /* Skip reset */
592 .reg_word_size = sizeof(u16),
593 .reg_cache_default = wm8737_reg,
594};
595
596#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
597static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,
598 const struct i2c_device_id *id)
599{
600 struct wm8737_priv *wm8737;
601 int ret;
602
603 wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL);
604 if (wm8737 == NULL)
605 return -ENOMEM;
606
607 i2c_set_clientdata(i2c, wm8737);
608 wm8737->control_type = SND_SOC_I2C;
609
610 ret = snd_soc_register_codec(&i2c->dev,
611 &soc_codec_dev_wm8737, &wm8737_dai, 1);
612 if (ret < 0)
613 kfree(wm8737);
614 return ret;
615
616}
617
618static __devexit int wm8737_i2c_remove(struct i2c_client *client)
619{
620 snd_soc_unregister_codec(&client->dev);
621 kfree(i2c_get_clientdata(client));
622 return 0;
623}
624
625static const struct i2c_device_id wm8737_i2c_id[] = {
626 { "wm8737", 0 },
627 { }
628};
629MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id);
630
631static struct i2c_driver wm8737_i2c_driver = {
632 .driver = {
633 .name = "wm8737",
634 .owner = THIS_MODULE,
635 },
636 .probe = wm8737_i2c_probe,
637 .remove = __devexit_p(wm8737_i2c_remove),
638 .id_table = wm8737_i2c_id,
639};
640#endif
641
642#if defined(CONFIG_SPI_MASTER)
643static int __devinit wm8737_spi_probe(struct spi_device *spi)
644{
645 struct wm8737_priv *wm8737;
646 int ret;
647
648 wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL);
649 if (wm8737 == NULL)
650 return -ENOMEM;
651
652 wm8737->control_type = SND_SOC_SPI;
653 spi_set_drvdata(spi, wm8737);
654
655 ret = snd_soc_register_codec(&spi->dev,
656 &soc_codec_dev_wm8737, &wm8737_dai, 1);
657 if (ret < 0)
658 kfree(wm8737);
659 return ret;
660}
661
662static int __devexit wm8737_spi_remove(struct spi_device *spi)
663{
664 snd_soc_unregister_codec(&spi->dev);
665 kfree(spi_get_drvdata(spi));
666 return 0;
667}
668
669static struct spi_driver wm8737_spi_driver = {
670 .driver = {
671 .name = "wm8737",
672 .owner = THIS_MODULE,
673 },
674 .probe = wm8737_spi_probe,
675 .remove = __devexit_p(wm8737_spi_remove),
676};
677#endif /* CONFIG_SPI_MASTER */
678
679static int __init wm8737_modinit(void)
680{
681 int ret;
682#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
683 ret = i2c_add_driver(&wm8737_i2c_driver);
684 if (ret != 0) {
685 printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n",
686 ret);
687 }
688#endif
689#if defined(CONFIG_SPI_MASTER)
690 ret = spi_register_driver(&wm8737_spi_driver);
691 if (ret != 0) {
692 printk(KERN_ERR "Failed to register WM8737 SPI driver: %d\n",
693 ret);
694 }
695#endif
696 return 0;
697}
698module_init(wm8737_modinit);
699
700static void __exit wm8737_exit(void)
701{
702#if defined(CONFIG_SPI_MASTER)
703 spi_unregister_driver(&wm8737_spi_driver);
704#endif
705#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
706 i2c_del_driver(&wm8737_i2c_driver);
707#endif
708}
709module_exit(wm8737_exit);
710
711MODULE_DESCRIPTION("ASoC WM8737 driver");
712MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
713MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8737.h b/sound/soc/codecs/wm8737.h
new file mode 100644
index 000000000000..23d14c8ff6e7
--- /dev/null
+++ b/sound/soc/codecs/wm8737.h
@@ -0,0 +1,322 @@
1#ifndef _WM8737_H
2#define _WM8737_H
3
4/*
5 * wm8737.c -- WM8523 ALSA SoC Audio driver
6 *
7 * Copyright 2010 Wolfson Microelectronics plc
8 *
9 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16/*
17 * Register values.
18 */
19#define WM8737_LEFT_PGA_VOLUME 0x00
20#define WM8737_RIGHT_PGA_VOLUME 0x01
21#define WM8737_AUDIO_PATH_L 0x02
22#define WM8737_AUDIO_PATH_R 0x03
23#define WM8737_3D_ENHANCE 0x04
24#define WM8737_ADC_CONTROL 0x05
25#define WM8737_POWER_MANAGEMENT 0x06
26#define WM8737_AUDIO_FORMAT 0x07
27#define WM8737_CLOCKING 0x08
28#define WM8737_MIC_PREAMP_CONTROL 0x09
29#define WM8737_MISC_BIAS_CONTROL 0x0A
30#define WM8737_NOISE_GATE 0x0B
31#define WM8737_ALC1 0x0C
32#define WM8737_ALC2 0x0D
33#define WM8737_ALC3 0x0E
34#define WM8737_RESET 0x0F
35
36#define WM8737_REGISTER_COUNT 16
37#define WM8737_MAX_REGISTER 0x0F
38
39/*
40 * Field Definitions.
41 */
42
43/*
44 * R0 (0x00) - Left PGA volume
45 */
46#define WM8737_LVU 0x0100 /* LVU */
47#define WM8737_LVU_MASK 0x0100 /* LVU */
48#define WM8737_LVU_SHIFT 8 /* LVU */
49#define WM8737_LVU_WIDTH 1 /* LVU */
50#define WM8737_LINVOL_MASK 0x00FF /* LINVOL - [7:0] */
51#define WM8737_LINVOL_SHIFT 0 /* LINVOL - [7:0] */
52#define WM8737_LINVOL_WIDTH 8 /* LINVOL - [7:0] */
53
54/*
55 * R1 (0x01) - Right PGA volume
56 */
57#define WM8737_RVU 0x0100 /* RVU */
58#define WM8737_RVU_MASK 0x0100 /* RVU */
59#define WM8737_RVU_SHIFT 8 /* RVU */
60#define WM8737_RVU_WIDTH 1 /* RVU */
61#define WM8737_RINVOL_MASK 0x00FF /* RINVOL - [7:0] */
62#define WM8737_RINVOL_SHIFT 0 /* RINVOL - [7:0] */
63#define WM8737_RINVOL_WIDTH 8 /* RINVOL - [7:0] */
64
65/*
66 * R2 (0x02) - AUDIO path L
67 */
68#define WM8737_LINSEL_MASK 0x0180 /* LINSEL - [8:7] */
69#define WM8737_LINSEL_SHIFT 7 /* LINSEL - [8:7] */
70#define WM8737_LINSEL_WIDTH 2 /* LINSEL - [8:7] */
71#define WM8737_LMICBOOST_MASK 0x0060 /* LMICBOOST - [6:5] */
72#define WM8737_LMICBOOST_SHIFT 5 /* LMICBOOST - [6:5] */
73#define WM8737_LMICBOOST_WIDTH 2 /* LMICBOOST - [6:5] */
74#define WM8737_LMBE 0x0010 /* LMBE */
75#define WM8737_LMBE_MASK 0x0010 /* LMBE */
76#define WM8737_LMBE_SHIFT 4 /* LMBE */
77#define WM8737_LMBE_WIDTH 1 /* LMBE */
78#define WM8737_LMZC 0x0008 /* LMZC */
79#define WM8737_LMZC_MASK 0x0008 /* LMZC */
80#define WM8737_LMZC_SHIFT 3 /* LMZC */
81#define WM8737_LMZC_WIDTH 1 /* LMZC */
82#define WM8737_LPZC 0x0004 /* LPZC */
83#define WM8737_LPZC_MASK 0x0004 /* LPZC */
84#define WM8737_LPZC_SHIFT 2 /* LPZC */
85#define WM8737_LPZC_WIDTH 1 /* LPZC */
86#define WM8737_LZCTO_MASK 0x0003 /* LZCTO - [1:0] */
87#define WM8737_LZCTO_SHIFT 0 /* LZCTO - [1:0] */
88#define WM8737_LZCTO_WIDTH 2 /* LZCTO - [1:0] */
89
90/*
91 * R3 (0x03) - AUDIO path R
92 */
93#define WM8737_RINSEL_MASK 0x0180 /* RINSEL - [8:7] */
94#define WM8737_RINSEL_SHIFT 7 /* RINSEL - [8:7] */
95#define WM8737_RINSEL_WIDTH 2 /* RINSEL - [8:7] */
96#define WM8737_RMICBOOST_MASK 0x0060 /* RMICBOOST - [6:5] */
97#define WM8737_RMICBOOST_SHIFT 5 /* RMICBOOST - [6:5] */
98#define WM8737_RMICBOOST_WIDTH 2 /* RMICBOOST - [6:5] */
99#define WM8737_RMBE 0x0010 /* RMBE */
100#define WM8737_RMBE_MASK 0x0010 /* RMBE */
101#define WM8737_RMBE_SHIFT 4 /* RMBE */
102#define WM8737_RMBE_WIDTH 1 /* RMBE */
103#define WM8737_RMZC 0x0008 /* RMZC */
104#define WM8737_RMZC_MASK 0x0008 /* RMZC */
105#define WM8737_RMZC_SHIFT 3 /* RMZC */
106#define WM8737_RMZC_WIDTH 1 /* RMZC */
107#define WM8737_RPZC 0x0004 /* RPZC */
108#define WM8737_RPZC_MASK 0x0004 /* RPZC */
109#define WM8737_RPZC_SHIFT 2 /* RPZC */
110#define WM8737_RPZC_WIDTH 1 /* RPZC */
111#define WM8737_RZCTO_MASK 0x0003 /* RZCTO - [1:0] */
112#define WM8737_RZCTO_SHIFT 0 /* RZCTO - [1:0] */
113#define WM8737_RZCTO_WIDTH 2 /* RZCTO - [1:0] */
114
115/*
116 * R4 (0x04) - 3D Enhance
117 */
118#define WM8737_DIV2 0x0080 /* DIV2 */
119#define WM8737_DIV2_MASK 0x0080 /* DIV2 */
120#define WM8737_DIV2_SHIFT 7 /* DIV2 */
121#define WM8737_DIV2_WIDTH 1 /* DIV2 */
122#define WM8737_3DLC 0x0040 /* 3DLC */
123#define WM8737_3DLC_MASK 0x0040 /* 3DLC */
124#define WM8737_3DLC_SHIFT 6 /* 3DLC */
125#define WM8737_3DLC_WIDTH 1 /* 3DLC */
126#define WM8737_3DUC 0x0020 /* 3DUC */
127#define WM8737_3DUC_MASK 0x0020 /* 3DUC */
128#define WM8737_3DUC_SHIFT 5 /* 3DUC */
129#define WM8737_3DUC_WIDTH 1 /* 3DUC */
130#define WM8737_3DDEPTH_MASK 0x001E /* 3DDEPTH - [4:1] */
131#define WM8737_3DDEPTH_SHIFT 1 /* 3DDEPTH - [4:1] */
132#define WM8737_3DDEPTH_WIDTH 4 /* 3DDEPTH - [4:1] */
133#define WM8737_3DE 0x0001 /* 3DE */
134#define WM8737_3DE_MASK 0x0001 /* 3DE */
135#define WM8737_3DE_SHIFT 0 /* 3DE */
136#define WM8737_3DE_WIDTH 1 /* 3DE */
137
138/*
139 * R5 (0x05) - ADC Control
140 */
141#define WM8737_MONOMIX_MASK 0x0180 /* MONOMIX - [8:7] */
142#define WM8737_MONOMIX_SHIFT 7 /* MONOMIX - [8:7] */
143#define WM8737_MONOMIX_WIDTH 2 /* MONOMIX - [8:7] */
144#define WM8737_POLARITY_MASK 0x0060 /* POLARITY - [6:5] */
145#define WM8737_POLARITY_SHIFT 5 /* POLARITY - [6:5] */
146#define WM8737_POLARITY_WIDTH 2 /* POLARITY - [6:5] */
147#define WM8737_HPOR 0x0010 /* HPOR */
148#define WM8737_HPOR_MASK 0x0010 /* HPOR */
149#define WM8737_HPOR_SHIFT 4 /* HPOR */
150#define WM8737_HPOR_WIDTH 1 /* HPOR */
151#define WM8737_LP 0x0004 /* LP */
152#define WM8737_LP_MASK 0x0004 /* LP */
153#define WM8737_LP_SHIFT 2 /* LP */
154#define WM8737_LP_WIDTH 1 /* LP */
155#define WM8737_MONOUT 0x0002 /* MONOUT */
156#define WM8737_MONOUT_MASK 0x0002 /* MONOUT */
157#define WM8737_MONOUT_SHIFT 1 /* MONOUT */
158#define WM8737_MONOUT_WIDTH 1 /* MONOUT */
159#define WM8737_ADCHPD 0x0001 /* ADCHPD */
160#define WM8737_ADCHPD_MASK 0x0001 /* ADCHPD */
161#define WM8737_ADCHPD_SHIFT 0 /* ADCHPD */
162#define WM8737_ADCHPD_WIDTH 1 /* ADCHPD */
163
164/*
165 * R6 (0x06) - Power Management
166 */
167#define WM8737_VMID 0x0100 /* VMID */
168#define WM8737_VMID_MASK 0x0100 /* VMID */
169#define WM8737_VMID_SHIFT 8 /* VMID */
170#define WM8737_VMID_WIDTH 1 /* VMID */
171#define WM8737_VREF 0x0080 /* VREF */
172#define WM8737_VREF_MASK 0x0080 /* VREF */
173#define WM8737_VREF_SHIFT 7 /* VREF */
174#define WM8737_VREF_WIDTH 1 /* VREF */
175#define WM8737_AI 0x0040 /* AI */
176#define WM8737_AI_MASK 0x0040 /* AI */
177#define WM8737_AI_SHIFT 6 /* AI */
178#define WM8737_AI_WIDTH 1 /* AI */
179#define WM8737_PGL 0x0020 /* PGL */
180#define WM8737_PGL_MASK 0x0020 /* PGL */
181#define WM8737_PGL_SHIFT 5 /* PGL */
182#define WM8737_PGL_WIDTH 1 /* PGL */
183#define WM8737_PGR 0x0010 /* PGR */
184#define WM8737_PGR_MASK 0x0010 /* PGR */
185#define WM8737_PGR_SHIFT 4 /* PGR */
186#define WM8737_PGR_WIDTH 1 /* PGR */
187#define WM8737_ADL 0x0008 /* ADL */
188#define WM8737_ADL_MASK 0x0008 /* ADL */
189#define WM8737_ADL_SHIFT 3 /* ADL */
190#define WM8737_ADL_WIDTH 1 /* ADL */
191#define WM8737_ADR 0x0004 /* ADR */
192#define WM8737_ADR_MASK 0x0004 /* ADR */
193#define WM8737_ADR_SHIFT 2 /* ADR */
194#define WM8737_ADR_WIDTH 1 /* ADR */
195#define WM8737_MICBIAS_MASK 0x0003 /* MICBIAS - [1:0] */
196#define WM8737_MICBIAS_SHIFT 0 /* MICBIAS - [1:0] */
197#define WM8737_MICBIAS_WIDTH 2 /* MICBIAS - [1:0] */
198
199/*
200 * R7 (0x07) - Audio Format
201 */
202#define WM8737_SDODIS 0x0080 /* SDODIS */
203#define WM8737_SDODIS_MASK 0x0080 /* SDODIS */
204#define WM8737_SDODIS_SHIFT 7 /* SDODIS */
205#define WM8737_SDODIS_WIDTH 1 /* SDODIS */
206#define WM8737_MS 0x0040 /* MS */
207#define WM8737_MS_MASK 0x0040 /* MS */
208#define WM8737_MS_SHIFT 6 /* MS */
209#define WM8737_MS_WIDTH 1 /* MS */
210#define WM8737_LRP 0x0010 /* LRP */
211#define WM8737_LRP_MASK 0x0010 /* LRP */
212#define WM8737_LRP_SHIFT 4 /* LRP */
213#define WM8737_LRP_WIDTH 1 /* LRP */
214#define WM8737_WL_MASK 0x000C /* WL - [3:2] */
215#define WM8737_WL_SHIFT 2 /* WL - [3:2] */
216#define WM8737_WL_WIDTH 2 /* WL - [3:2] */
217#define WM8737_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */
218#define WM8737_FORMAT_SHIFT 0 /* FORMAT - [1:0] */
219#define WM8737_FORMAT_WIDTH 2 /* FORMAT - [1:0] */
220
221/*
222 * R8 (0x08) - Clocking
223 */
224#define WM8737_AUTODETECT 0x0080 /* AUTODETECT */
225#define WM8737_AUTODETECT_MASK 0x0080 /* AUTODETECT */
226#define WM8737_AUTODETECT_SHIFT 7 /* AUTODETECT */
227#define WM8737_AUTODETECT_WIDTH 1 /* AUTODETECT */
228#define WM8737_CLKDIV2 0x0040 /* CLKDIV2 */
229#define WM8737_CLKDIV2_MASK 0x0040 /* CLKDIV2 */
230#define WM8737_CLKDIV2_SHIFT 6 /* CLKDIV2 */
231#define WM8737_CLKDIV2_WIDTH 1 /* CLKDIV2 */
232#define WM8737_SR_MASK 0x003E /* SR - [5:1] */
233#define WM8737_SR_SHIFT 1 /* SR - [5:1] */
234#define WM8737_SR_WIDTH 5 /* SR - [5:1] */
235#define WM8737_USB_MODE 0x0001 /* USB MODE */
236#define WM8737_USB_MODE_MASK 0x0001 /* USB MODE */
237#define WM8737_USB_MODE_SHIFT 0 /* USB MODE */
238#define WM8737_USB_MODE_WIDTH 1 /* USB MODE */
239
240/*
241 * R9 (0x09) - MIC Preamp Control
242 */
243#define WM8737_RBYPEN 0x0008 /* RBYPEN */
244#define WM8737_RBYPEN_MASK 0x0008 /* RBYPEN */
245#define WM8737_RBYPEN_SHIFT 3 /* RBYPEN */
246#define WM8737_RBYPEN_WIDTH 1 /* RBYPEN */
247#define WM8737_LBYPEN 0x0004 /* LBYPEN */
248#define WM8737_LBYPEN_MASK 0x0004 /* LBYPEN */
249#define WM8737_LBYPEN_SHIFT 2 /* LBYPEN */
250#define WM8737_LBYPEN_WIDTH 1 /* LBYPEN */
251#define WM8737_MBCTRL_MASK 0x0003 /* MBCTRL - [1:0] */
252#define WM8737_MBCTRL_SHIFT 0 /* MBCTRL - [1:0] */
253#define WM8737_MBCTRL_WIDTH 2 /* MBCTRL - [1:0] */
254
255/*
256 * R10 (0x0A) - Misc Bias Control
257 */
258#define WM8737_VMIDSEL_MASK 0x000C /* VMIDSEL - [3:2] */
259#define WM8737_VMIDSEL_SHIFT 2 /* VMIDSEL - [3:2] */
260#define WM8737_VMIDSEL_WIDTH 2 /* VMIDSEL - [3:2] */
261#define WM8737_LINPUT1_DC_BIAS_ENABLE 0x0002 /* LINPUT1 DC BIAS ENABLE */
262#define WM8737_LINPUT1_DC_BIAS_ENABLE_MASK 0x0002 /* LINPUT1 DC BIAS ENABLE */
263#define WM8737_LINPUT1_DC_BIAS_ENABLE_SHIFT 1 /* LINPUT1 DC BIAS ENABLE */
264#define WM8737_LINPUT1_DC_BIAS_ENABLE_WIDTH 1 /* LINPUT1 DC BIAS ENABLE */
265#define WM8737_RINPUT1_DC_BIAS_ENABLE 0x0001 /* RINPUT1 DC BIAS ENABLE */
266#define WM8737_RINPUT1_DC_BIAS_ENABLE_MASK 0x0001 /* RINPUT1 DC BIAS ENABLE */
267#define WM8737_RINPUT1_DC_BIAS_ENABLE_SHIFT 0 /* RINPUT1 DC BIAS ENABLE */
268#define WM8737_RINPUT1_DC_BIAS_ENABLE_WIDTH 1 /* RINPUT1 DC BIAS ENABLE */
269
270/*
271 * R11 (0x0B) - Noise Gate
272 */
273#define WM8737_NGTH_MASK 0x001C /* NGTH - [4:2] */
274#define WM8737_NGTH_SHIFT 2 /* NGTH - [4:2] */
275#define WM8737_NGTH_WIDTH 3 /* NGTH - [4:2] */
276#define WM8737_NGAT 0x0001 /* NGAT */
277#define WM8737_NGAT_MASK 0x0001 /* NGAT */
278#define WM8737_NGAT_SHIFT 0 /* NGAT */
279#define WM8737_NGAT_WIDTH 1 /* NGAT */
280
281/*
282 * R12 (0x0C) - ALC1
283 */
284#define WM8737_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */
285#define WM8737_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */
286#define WM8737_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */
287#define WM8737_MAX_GAIN_MASK 0x0070 /* MAX GAIN - [6:4] */
288#define WM8737_MAX_GAIN_SHIFT 4 /* MAX GAIN - [6:4] */
289#define WM8737_MAX_GAIN_WIDTH 3 /* MAX GAIN - [6:4] */
290#define WM8737_ALCL_MASK 0x000F /* ALCL - [3:0] */
291#define WM8737_ALCL_SHIFT 0 /* ALCL - [3:0] */
292#define WM8737_ALCL_WIDTH 4 /* ALCL - [3:0] */
293
294/*
295 * R13 (0x0D) - ALC2
296 */
297#define WM8737_ALCZCE 0x0010 /* ALCZCE */
298#define WM8737_ALCZCE_MASK 0x0010 /* ALCZCE */
299#define WM8737_ALCZCE_SHIFT 4 /* ALCZCE */
300#define WM8737_ALCZCE_WIDTH 1 /* ALCZCE */
301#define WM8737_HLD_MASK 0x000F /* HLD - [3:0] */
302#define WM8737_HLD_SHIFT 0 /* HLD - [3:0] */
303#define WM8737_HLD_WIDTH 4 /* HLD - [3:0] */
304
305/*
306 * R14 (0x0E) - ALC3
307 */
308#define WM8737_DCY_MASK 0x00F0 /* DCY - [7:4] */
309#define WM8737_DCY_SHIFT 4 /* DCY - [7:4] */
310#define WM8737_DCY_WIDTH 4 /* DCY - [7:4] */
311#define WM8737_ATK_MASK 0x000F /* ATK - [3:0] */
312#define WM8737_ATK_SHIFT 0 /* ATK - [3:0] */
313#define WM8737_ATK_WIDTH 4 /* ATK - [3:0] */
314
315/*
316 * R15 (0x0F) - Reset
317 */
318#define WM8737_RESET_MASK 0x01FF /* RESET - [8:0] */
319#define WM8737_RESET_SHIFT 0 /* RESET - [8:0] */
320#define WM8737_RESET_WIDTH 9 /* RESET - [8:0] */
321
322#endif