diff options
-rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8737.c | 713 | ||||
-rw-r--r-- | sound/soc/codecs/wm8737.h | 322 |
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 | |||
236 | config SND_SOC_WM8731 | 237 | config SND_SOC_WM8731 |
237 | tristate | 238 | tristate |
238 | 239 | ||
240 | config SND_SOC_WM8737 | ||
241 | tristate | ||
242 | |||
239 | config SND_SOC_WM8741 | 243 | config 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 | |||
39 | snd-soc-wm8727-objs := wm8727.o | 39 | snd-soc-wm8727-objs := wm8727.o |
40 | snd-soc-wm8728-objs := wm8728.o | 40 | snd-soc-wm8728-objs := wm8728.o |
41 | snd-soc-wm8731-objs := wm8731.o | 41 | snd-soc-wm8731-objs := wm8731.o |
42 | snd-soc-wm8737-objs := wm8737.o | ||
42 | snd-soc-wm8741-objs := wm8741.o | 43 | snd-soc-wm8741-objs := wm8741.o |
43 | snd-soc-wm8750-objs := wm8750.o | 44 | snd-soc-wm8750-objs := wm8750.o |
44 | snd-soc-wm8753-objs := wm8753.o | 45 | snd-soc-wm8753-objs := wm8753.o |
@@ -116,6 +117,7 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o | |||
116 | obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o | 117 | obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o |
117 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o | 118 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o |
118 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 119 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
120 | obj-$(CONFIG_SND_SOC_WM8737) += snd-soc-wm8737.o | ||
119 | obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o | 121 | obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o |
120 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 122 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
121 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 123 | obj-$(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 | ||
34 | static const char *wm8737_supply_names[WM8737_NUM_SUPPLIES] = { | ||
35 | "DCVDD", | ||
36 | "DBVDD", | ||
37 | "AVDD", | ||
38 | "MVDD", | ||
39 | }; | ||
40 | |||
41 | /* codec private data */ | ||
42 | struct 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 | |||
48 | static 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 | |||
66 | static int wm8737_reset(struct snd_soc_codec *codec) | ||
67 | { | ||
68 | return snd_soc_write(codec, WM8737_RESET, 0); | ||
69 | } | ||
70 | |||
71 | static 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 | }; | ||
78 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -9750, 50, 1); | ||
79 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -600, 600, 0); | ||
80 | static const DECLARE_TLV_DB_SCALE(ng_tlv, -7800, 600, 0); | ||
81 | |||
82 | static const char *micbias_enum_text[] = { | ||
83 | "25%", | ||
84 | "50%", | ||
85 | "75%", | ||
86 | "100%", | ||
87 | }; | ||
88 | |||
89 | static const struct soc_enum micbias_enum = | ||
90 | SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 0, 4, micbias_enum_text); | ||
91 | |||
92 | static const char *low_cutoff_text[] = { | ||
93 | "Low", "High" | ||
94 | }; | ||
95 | |||
96 | static const struct soc_enum low_3d = | ||
97 | SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 6, 2, low_cutoff_text); | ||
98 | |||
99 | static const char *high_cutoff_text[] = { | ||
100 | "High", "Low" | ||
101 | }; | ||
102 | |||
103 | static const struct soc_enum high_3d = | ||
104 | SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 5, 2, high_cutoff_text); | ||
105 | |||
106 | static const struct snd_kcontrol_new wm8737_snd_controls[] = { | ||
107 | SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R, | ||
108 | 6, 3, 0, micboost_tlv), | ||
109 | SOC_DOUBLE_R("Mic Boost Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R, | ||
110 | 4, 1, 0), | ||
111 | SOC_DOUBLE("Mic ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R, | ||
112 | 3, 1, 0), | ||
113 | |||
114 | SOC_DOUBLE_R_TLV("Capture Volume", WM8737_LEFT_PGA_VOLUME, | ||
115 | WM8737_RIGHT_PGA_VOLUME, 0, 255, 0, pga_tlv), | ||
116 | SOC_DOUBLE("Capture ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R, | ||
117 | 2, 1, 0), | ||
118 | |||
119 | SOC_DOUBLE("INPUT1 DC Bias Switch", WM8737_MISC_BIAS_CONTROL, 0, 1, 1, 0), | ||
120 | |||
121 | SOC_ENUM("Mic PGA Bias", micbias_enum), | ||
122 | SOC_SINGLE("ADC Low Power Switch", WM8737_ADC_CONTROL, 2, 1, 0), | ||
123 | SOC_SINGLE("High Pass Filter Switch", WM8737_ADC_CONTROL, 0, 1, 1), | ||
124 | SOC_DOUBLE("Polarity Invert Switch", WM8737_ADC_CONTROL, 5, 6, 1, 0), | ||
125 | |||
126 | SOC_SINGLE("3D Switch", WM8737_3D_ENHANCE, 0, 1, 0), | ||
127 | SOC_SINGLE("3D Depth", WM8737_3D_ENHANCE, 1, 15, 0), | ||
128 | SOC_ENUM("3D Low Cut-off", low_3d), | ||
129 | SOC_ENUM("3D High Cut-off", low_3d), | ||
130 | SOC_SINGLE_TLV("3D ADC Volume", WM8737_3D_ENHANCE, 7, 1, 1, adc_tlv), | ||
131 | |||
132 | SOC_SINGLE("Noise Gate Switch", WM8737_NOISE_GATE, 0, 1, 0), | ||
133 | SOC_SINGLE_TLV("Noise Gate Threshold Volume", WM8737_NOISE_GATE, 2, 7, 0, | ||
134 | ng_tlv), | ||
135 | }; | ||
136 | |||
137 | static const char *linsel_text[] = { | ||
138 | "LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC", | ||
139 | }; | ||
140 | |||
141 | static const struct soc_enum linsel_enum = | ||
142 | SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_L, 7, 4, linsel_text); | ||
143 | |||
144 | static const struct snd_kcontrol_new linsel_mux = | ||
145 | SOC_DAPM_ENUM("LINSEL", linsel_enum); | ||
146 | |||
147 | |||
148 | static const char *rinsel_text[] = { | ||
149 | "RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC", | ||
150 | }; | ||
151 | |||
152 | static const struct soc_enum rinsel_enum = | ||
153 | SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_R, 7, 4, rinsel_text); | ||
154 | |||
155 | static const struct snd_kcontrol_new rinsel_mux = | ||
156 | SOC_DAPM_ENUM("RINSEL", rinsel_enum); | ||
157 | |||
158 | static const char *bypass_text[] = { | ||
159 | "Direct", "Preamp" | ||
160 | }; | ||
161 | |||
162 | static const struct soc_enum lbypass_enum = | ||
163 | SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 2, 2, bypass_text); | ||
164 | |||
165 | static const struct snd_kcontrol_new lbypass_mux = | ||
166 | SOC_DAPM_ENUM("Left Bypass", lbypass_enum); | ||
167 | |||
168 | |||
169 | static const struct soc_enum rbypass_enum = | ||
170 | SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 3, 2, bypass_text); | ||
171 | |||
172 | static const struct snd_kcontrol_new rbypass_mux = | ||
173 | SOC_DAPM_ENUM("Left Bypass", rbypass_enum); | ||
174 | |||
175 | static const struct snd_soc_dapm_widget wm8737_dapm_widgets[] = { | ||
176 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
177 | SND_SOC_DAPM_INPUT("LINPUT2"), | ||
178 | SND_SOC_DAPM_INPUT("LINPUT3"), | ||
179 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
180 | SND_SOC_DAPM_INPUT("RINPUT2"), | ||
181 | SND_SOC_DAPM_INPUT("RINPUT3"), | ||
182 | SND_SOC_DAPM_INPUT("LACIN"), | ||
183 | SND_SOC_DAPM_INPUT("RACIN"), | ||
184 | |||
185 | SND_SOC_DAPM_MUX("LINSEL", SND_SOC_NOPM, 0, 0, &linsel_mux), | ||
186 | SND_SOC_DAPM_MUX("RINSEL", SND_SOC_NOPM, 0, 0, &rinsel_mux), | ||
187 | |||
188 | SND_SOC_DAPM_MUX("Left Preamp Mux", SND_SOC_NOPM, 0, 0, &lbypass_mux), | ||
189 | SND_SOC_DAPM_MUX("Right Preamp Mux", SND_SOC_NOPM, 0, 0, &rbypass_mux), | ||
190 | |||
191 | SND_SOC_DAPM_PGA("PGAL", WM8737_POWER_MANAGEMENT, 5, 0, NULL, 0), | ||
192 | SND_SOC_DAPM_PGA("PGAR", WM8737_POWER_MANAGEMENT, 4, 0, NULL, 0), | ||
193 | |||
194 | SND_SOC_DAPM_DAC("ADCL", NULL, WM8737_POWER_MANAGEMENT, 3, 0), | ||
195 | SND_SOC_DAPM_DAC("ADCR", NULL, WM8737_POWER_MANAGEMENT, 2, 0), | ||
196 | |||
197 | SND_SOC_DAPM_AIF_OUT("AIF", "Capture", 0, WM8737_POWER_MANAGEMENT, 6, 0), | ||
198 | }; | ||
199 | |||
200 | static 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 | |||
227 | static 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 */ | ||
239 | static 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 | |||
286 | static 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 | |||
342 | static 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 | |||
363 | static 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 | |||
414 | static 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 | |||
481 | static 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 | |||
487 | static 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 | ||
500 | static 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 | |||
506 | static 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 | |||
516 | static 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 | |||
567 | err_enable: | ||
568 | regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); | ||
569 | err_get: | ||
570 | regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); | ||
571 | |||
572 | return ret; | ||
573 | } | ||
574 | |||
575 | static 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 | |||
584 | static 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) | ||
597 | static __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 | |||
618 | static __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 | |||
625 | static const struct i2c_device_id wm8737_i2c_id[] = { | ||
626 | { "wm8737", 0 }, | ||
627 | { } | ||
628 | }; | ||
629 | MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id); | ||
630 | |||
631 | static 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) | ||
643 | static 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 | |||
662 | static 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 | |||
669 | static 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 | |||
679 | static 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 | } | ||
698 | module_init(wm8737_modinit); | ||
699 | |||
700 | static 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 | } | ||
709 | module_exit(wm8737_exit); | ||
710 | |||
711 | MODULE_DESCRIPTION("ASoC WM8737 driver"); | ||
712 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
713 | MODULE_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 | ||