aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenneth Kiraly <kiraly@lab126.com>2008-09-10 14:33:32 -0400
committerJaroslav Kysela <perex@perex.cz>2008-09-23 02:18:05 -0400
commit8bae3e2335132aadd29662694866a55d52bff850 (patch)
tree322b8869032d398d389e0a59ddeed6ea28bee897
parentf51ff9937bc6732ed5fc08088fdbe89ab8ed27c3 (diff)
sound: ASoC: Add WM8971 CODEC driver
The WM8971 is a low power, high quality stereo codec designed for portable digital audio applications. This driver was originally written by Kenneth Kiraly. While out of tree it has had updates to reflect current kernel APIs and coding standards from Graeme Gregory and Mark Brown. Signed-off-by: Kenneth Kiraly <kiraly@lab126.com> Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com> Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/wm8971.c942
-rw-r--r--sound/soc/codecs/wm8971.h64
4 files changed, 1012 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 27f2dfa7ca1a..e0b9869df0f1 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -16,6 +16,7 @@ config SND_SOC_ALL_CODECS
16 select SND_SOC_WM8753 16 select SND_SOC_WM8753
17 select SND_SOC_WM8900 17 select SND_SOC_WM8900
18 select SND_SOC_WM8903 18 select SND_SOC_WM8903
19 select SND_SOC_WM8971
19 select SND_SOC_WM8990 20 select SND_SOC_WM8990
20 help 21 help
21 Normally ASoC codec drivers are only built if a machine driver which 22 Normally ASoC codec drivers are only built if a machine driver which
@@ -89,6 +90,9 @@ config SND_SOC_WM8900
89config SND_SOC_WM8903 90config SND_SOC_WM8903
90 tristate 91 tristate
91 92
93config SND_SOC_WM8971
94 tristate
95
92config SND_SOC_WM8990 96config SND_SOC_WM8990
93 tristate 97 tristate
94 98
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c2b8783c07d1..f977978a3409 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -13,6 +13,7 @@ snd-soc-wm8750-objs := wm8750.o
13snd-soc-wm8753-objs := wm8753.o 13snd-soc-wm8753-objs := wm8753.o
14snd-soc-wm8900-objs := wm8900.o 14snd-soc-wm8900-objs := wm8900.o
15snd-soc-wm8903-objs := wm8903.o 15snd-soc-wm8903-objs := wm8903.o
16snd-soc-wm8971-objs := wm8971.o
16snd-soc-wm8990-objs := wm8990.o 17snd-soc-wm8990-objs := wm8990.o
17snd-soc-wm9712-objs := wm9712.o 18snd-soc-wm9712-objs := wm9712.o
18snd-soc-wm9713-objs := wm9713.o 19snd-soc-wm9713-objs := wm9713.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
32obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o 33obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
33obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o 34obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
34obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o 35obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
36obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
35obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o 37obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
36obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o 38obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
37obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o 39obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
new file mode 100644
index 000000000000..974a4cd0f3fd
--- /dev/null
+++ b/sound/soc/codecs/wm8971.c
@@ -0,0 +1,942 @@
1/*
2 * wm8971.c -- WM8971 ALSA SoC Audio driver
3 *
4 * Copyright 2005 Lab126, Inc.
5 *
6 * Author: Kenneth Kiraly <kiraly@lab126.com>
7 *
8 * Based on wm8753.c by Liam Girdwood
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/init.h>
19#include <linux/delay.h>
20#include <linux/pm.h>
21#include <linux/i2c.h>
22#include <linux/platform_device.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
30#include "wm8971.h"
31
32#define AUDIO_NAME "wm8971"
33#define WM8971_VERSION "0.9"
34
35#define WM8971_REG_COUNT 43
36
37static struct workqueue_struct *wm8971_workq = NULL;
38
39/* codec private data */
40struct wm8971_priv {
41 unsigned int sysclk;
42};
43
44/*
45 * wm8971 register cache
46 * We can't read the WM8971 register space when we
47 * are using 2 wire for device control, so we cache them instead.
48 */
49static const u16 wm8971_reg[] = {
50 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */
51 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */
52 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */
53 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */
54 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */
55 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */
56 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
57 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
58 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */
59 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */
60 0x0079, 0x0079, 0x0079, /* 40 */
61};
62
63static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec,
64 unsigned int reg)
65{
66 u16 *cache = codec->reg_cache;
67 if (reg < WM8971_REG_COUNT)
68 return cache[reg];
69
70 return -1;
71}
72
73static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec,
74 unsigned int reg, unsigned int value)
75{
76 u16 *cache = codec->reg_cache;
77 if (reg < WM8971_REG_COUNT)
78 cache[reg] = value;
79}
80
81static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg,
82 unsigned int value)
83{
84 u8 data[2];
85
86 /* data is
87 * D15..D9 WM8753 register offset
88 * D8...D0 register data
89 */
90 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
91 data[1] = value & 0x00ff;
92
93 wm8971_write_reg_cache (codec, reg, value);
94 if (codec->hw_write(codec->control_data, data, 2) == 2)
95 return 0;
96 else
97 return -EIO;
98}
99
100#define wm8971_reset(c) wm8971_write(c, WM8971_RESET, 0)
101
102/* WM8971 Controls */
103static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" };
104static const char *wm8971_bass_filter[] = { "130Hz @ 48kHz",
105 "200Hz @ 48kHz" };
106static const char *wm8971_treble[] = { "8kHz", "4kHz" };
107static const char *wm8971_alc_func[] = { "Off", "Right", "Left", "Stereo" };
108static const char *wm8971_ng_type[] = { "Constant PGA Gain",
109 "Mute ADC Output" };
110static const char *wm8971_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
111static const char *wm8971_mono_mux[] = {"Stereo", "Mono (Left)",
112 "Mono (Right)", "Digital Mono"};
113static const char *wm8971_dac_phase[] = { "Non Inverted", "Inverted" };
114static const char *wm8971_lline_mux[] = {"Line", "NC", "NC", "PGA",
115 "Differential"};
116static const char *wm8971_rline_mux[] = {"Line", "Mic", "NC", "PGA",
117 "Differential"};
118static const char *wm8971_lpga_sel[] = {"Line", "NC", "NC", "Differential"};
119static const char *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"};
120static const char *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert",
121 "L + R Invert"};
122
123static const struct soc_enum wm8971_enum[] = {
124 SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass), /* 0 */
125 SOC_ENUM_SINGLE(WM8971_BASS, 6, 2, wm8971_bass_filter),
126 SOC_ENUM_SINGLE(WM8971_TREBLE, 6, 2, wm8971_treble),
127 SOC_ENUM_SINGLE(WM8971_ALC1, 7, 4, wm8971_alc_func),
128 SOC_ENUM_SINGLE(WM8971_NGATE, 1, 2, wm8971_ng_type), /* 4 */
129 SOC_ENUM_SINGLE(WM8971_ADCDAC, 1, 4, wm8971_deemp),
130 SOC_ENUM_SINGLE(WM8971_ADCTL1, 4, 4, wm8971_mono_mux),
131 SOC_ENUM_SINGLE(WM8971_ADCTL1, 1, 2, wm8971_dac_phase),
132 SOC_ENUM_SINGLE(WM8971_LOUTM1, 0, 5, wm8971_lline_mux), /* 8 */
133 SOC_ENUM_SINGLE(WM8971_ROUTM1, 0, 5, wm8971_rline_mux),
134 SOC_ENUM_SINGLE(WM8971_LADCIN, 6, 4, wm8971_lpga_sel),
135 SOC_ENUM_SINGLE(WM8971_RADCIN, 6, 4, wm8971_rpga_sel),
136 SOC_ENUM_SINGLE(WM8971_ADCDAC, 5, 4, wm8971_adcpol), /* 12 */
137 SOC_ENUM_SINGLE(WM8971_ADCIN, 6, 4, wm8971_mono_mux),
138};
139
140static const struct snd_kcontrol_new wm8971_snd_controls[] = {
141 SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0),
142 SOC_DOUBLE_R("Capture ZC Switch", WM8971_LINVOL, WM8971_RINVOL,
143 6, 1, 0),
144 SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1),
145
146 SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8971_LOUT1V,
147 WM8971_ROUT1V, 7, 1, 0),
148 SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8971_LOUT2V,
149 WM8971_ROUT2V, 7, 1, 0),
150 SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0),
151
152 SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0),
153
154 SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1,
155 WM8971_LOUTM2, 4, 7, 1),
156 SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1,
157 WM8971_ROUTM2, 4, 7, 1),
158 SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1,
159 WM8971_MOUTM2, 4, 7, 1),
160
161 SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V,
162 WM8971_ROUT1V, 0, 127, 0),
163 SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V,
164 WM8971_ROUT2V, 0, 127, 0),
165
166 SOC_ENUM("Bass Boost", wm8971_enum[0]),
167 SOC_ENUM("Bass Filter", wm8971_enum[1]),
168 SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1),
169
170 SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0),
171 SOC_ENUM("Treble Cut-off", wm8971_enum[2]),
172
173 SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1),
174
175 SOC_SINGLE("ALC Target Volume", WM8971_ALC1, 0, 7, 0),
176 SOC_SINGLE("ALC Max Volume", WM8971_ALC1, 4, 7, 0),
177
178 SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0),
179 SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0),
180 SOC_ENUM("ALC Capture Function", wm8971_enum[3]),
181 SOC_SINGLE("ALC Capture ZC Switch", WM8971_ALC2, 7, 1, 0),
182 SOC_SINGLE("ALC Capture Hold Time", WM8971_ALC2, 0, 15, 0),
183 SOC_SINGLE("ALC Capture Decay Time", WM8971_ALC3, 4, 15, 0),
184 SOC_SINGLE("ALC Capture Attack Time", WM8971_ALC3, 0, 15, 0),
185 SOC_SINGLE("ALC Capture NG Threshold", WM8971_NGATE, 3, 31, 0),
186 SOC_ENUM("ALC Capture NG Type", wm8971_enum[4]),
187 SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0),
188
189 SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0),
190 SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0),
191
192 SOC_ENUM("Playback De-emphasis", wm8971_enum[5]),
193 SOC_ENUM("Playback Function", wm8971_enum[6]),
194 SOC_ENUM("Playback Phase", wm8971_enum[7]),
195
196 SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0),
197};
198
199/* add non-DAPM controls */
200static int wm8971_add_controls(struct snd_soc_codec *codec)
201{
202 int err, i;
203
204 for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) {
205 err = snd_ctl_add(codec->card,
206 snd_soc_cnew(&wm8971_snd_controls[i],
207 codec, NULL));
208 if (err < 0)
209 return err;
210 }
211 return 0;
212}
213
214/*
215 * DAPM Controls
216 */
217
218/* Left Mixer */
219static const struct snd_kcontrol_new wm8971_left_mixer_controls[] = {
220SOC_DAPM_SINGLE("Playback Switch", WM8971_LOUTM1, 8, 1, 0),
221SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_LOUTM1, 7, 1, 0),
222SOC_DAPM_SINGLE("Right Playback Switch", WM8971_LOUTM2, 8, 1, 0),
223SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_LOUTM2, 7, 1, 0),
224};
225
226/* Right Mixer */
227static const struct snd_kcontrol_new wm8971_right_mixer_controls[] = {
228SOC_DAPM_SINGLE("Left Playback Switch", WM8971_ROUTM1, 8, 1, 0),
229SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_ROUTM1, 7, 1, 0),
230SOC_DAPM_SINGLE("Playback Switch", WM8971_ROUTM2, 8, 1, 0),
231SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_ROUTM2, 7, 1, 0),
232};
233
234/* Mono Mixer */
235static const struct snd_kcontrol_new wm8971_mono_mixer_controls[] = {
236SOC_DAPM_SINGLE("Left Playback Switch", WM8971_MOUTM1, 8, 1, 0),
237SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_MOUTM1, 7, 1, 0),
238SOC_DAPM_SINGLE("Right Playback Switch", WM8971_MOUTM2, 8, 1, 0),
239SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0),
240};
241
242/* Left Line Mux */
243static const struct snd_kcontrol_new wm8971_left_line_controls =
244SOC_DAPM_ENUM("Route", wm8971_enum[8]);
245
246/* Right Line Mux */
247static const struct snd_kcontrol_new wm8971_right_line_controls =
248SOC_DAPM_ENUM("Route", wm8971_enum[9]);
249
250/* Left PGA Mux */
251static const struct snd_kcontrol_new wm8971_left_pga_controls =
252SOC_DAPM_ENUM("Route", wm8971_enum[10]);
253
254/* Right PGA Mux */
255static const struct snd_kcontrol_new wm8971_right_pga_controls =
256SOC_DAPM_ENUM("Route", wm8971_enum[11]);
257
258/* Mono ADC Mux */
259static const struct snd_kcontrol_new wm8971_monomux_controls =
260SOC_DAPM_ENUM("Route", wm8971_enum[13]);
261
262static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = {
263 SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
264 &wm8971_left_mixer_controls[0],
265 ARRAY_SIZE(wm8971_left_mixer_controls)),
266 SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
267 &wm8971_right_mixer_controls[0],
268 ARRAY_SIZE(wm8971_right_mixer_controls)),
269 SND_SOC_DAPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0,
270 &wm8971_mono_mixer_controls[0],
271 ARRAY_SIZE(wm8971_mono_mixer_controls)),
272
273 SND_SOC_DAPM_PGA("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0),
274 SND_SOC_DAPM_PGA("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0),
275 SND_SOC_DAPM_PGA("Right Out 1", WM8971_PWR2, 5, 0, NULL, 0),
276 SND_SOC_DAPM_PGA("Left Out 1", WM8971_PWR2, 6, 0, NULL, 0),
277 SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8971_PWR2, 7, 0),
278 SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0),
279 SND_SOC_DAPM_PGA("Mono Out 1", WM8971_PWR2, 2, 0, NULL, 0),
280
281 SND_SOC_DAPM_MICBIAS("Mic Bias", WM8971_PWR1, 1, 0),
282 SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0),
283 SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0),
284
285 SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0,
286 &wm8971_left_pga_controls),
287 SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0,
288 &wm8971_right_pga_controls),
289 SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
290 &wm8971_left_line_controls),
291 SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
292 &wm8971_right_line_controls),
293
294 SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
295 &wm8971_monomux_controls),
296 SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
297 &wm8971_monomux_controls),
298
299 SND_SOC_DAPM_OUTPUT("LOUT1"),
300 SND_SOC_DAPM_OUTPUT("ROUT1"),
301 SND_SOC_DAPM_OUTPUT("LOUT2"),
302 SND_SOC_DAPM_OUTPUT("ROUT2"),
303 SND_SOC_DAPM_OUTPUT("MONO"),
304
305 SND_SOC_DAPM_INPUT("LINPUT1"),
306 SND_SOC_DAPM_INPUT("RINPUT1"),
307 SND_SOC_DAPM_INPUT("MIC"),
308};
309
310static const struct snd_soc_dapm_route audio_map[] = {
311 /* left mixer */
312 {"Left Mixer", "Playback Switch", "Left DAC"},
313 {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
314 {"Left Mixer", "Right Playback Switch", "Right DAC"},
315 {"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
316
317 /* right mixer */
318 {"Right Mixer", "Left Playback Switch", "Left DAC"},
319 {"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
320 {"Right Mixer", "Playback Switch", "Right DAC"},
321 {"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
322
323 /* left out 1 */
324 {"Left Out 1", NULL, "Left Mixer"},
325 {"LOUT1", NULL, "Left Out 1"},
326
327 /* left out 2 */
328 {"Left Out 2", NULL, "Left Mixer"},
329 {"LOUT2", NULL, "Left Out 2"},
330
331 /* right out 1 */
332 {"Right Out 1", NULL, "Right Mixer"},
333 {"ROUT1", NULL, "Right Out 1"},
334
335 /* right out 2 */
336 {"Right Out 2", NULL, "Right Mixer"},
337 {"ROUT2", NULL, "Right Out 2"},
338
339 /* mono mixer */
340 {"Mono Mixer", "Left Playback Switch", "Left DAC"},
341 {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
342 {"Mono Mixer", "Right Playback Switch", "Right DAC"},
343 {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
344
345 /* mono out */
346 {"Mono Out", NULL, "Mono Mixer"},
347 {"MONO1", NULL, "Mono Out"},
348
349 /* Left Line Mux */
350 {"Left Line Mux", "Line", "LINPUT1"},
351 {"Left Line Mux", "PGA", "Left PGA Mux"},
352 {"Left Line Mux", "Differential", "Differential Mux"},
353
354 /* Right Line Mux */
355 {"Right Line Mux", "Line", "RINPUT1"},
356 {"Right Line Mux", "Mic", "MIC"},
357 {"Right Line Mux", "PGA", "Right PGA Mux"},
358 {"Right Line Mux", "Differential", "Differential Mux"},
359
360 /* Left PGA Mux */
361 {"Left PGA Mux", "Line", "LINPUT1"},
362 {"Left PGA Mux", "Differential", "Differential Mux"},
363
364 /* Right PGA Mux */
365 {"Right PGA Mux", "Line", "RINPUT1"},
366 {"Right PGA Mux", "Differential", "Differential Mux"},
367
368 /* Differential Mux */
369 {"Differential Mux", "Line", "LINPUT1"},
370 {"Differential Mux", "Line", "RINPUT1"},
371
372 /* Left ADC Mux */
373 {"Left ADC Mux", "Stereo", "Left PGA Mux"},
374 {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
375 {"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
376
377 /* Right ADC Mux */
378 {"Right ADC Mux", "Stereo", "Right PGA Mux"},
379 {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
380 {"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
381
382 /* ADC */
383 {"Left ADC", NULL, "Left ADC Mux"},
384 {"Right ADC", NULL, "Right ADC Mux"},
385};
386
387static int wm8971_add_widgets(struct snd_soc_codec *codec)
388{
389 snd_soc_dapm_new_controls(codec, wm8971_dapm_widgets,
390 ARRAY_SIZE(wm8971_dapm_widgets));
391
392 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
393
394 snd_soc_dapm_new_widgets(codec);
395
396 return 0;
397}
398
399struct _coeff_div {
400 u32 mclk;
401 u32 rate;
402 u16 fs;
403 u8 sr:5;
404 u8 usb:1;
405};
406
407/* codec hifi mclk clock divider coefficients */
408static const struct _coeff_div coeff_div[] = {
409 /* 8k */
410 {12288000, 8000, 1536, 0x6, 0x0},
411 {11289600, 8000, 1408, 0x16, 0x0},
412 {18432000, 8000, 2304, 0x7, 0x0},
413 {16934400, 8000, 2112, 0x17, 0x0},
414 {12000000, 8000, 1500, 0x6, 0x1},
415
416 /* 11.025k */
417 {11289600, 11025, 1024, 0x18, 0x0},
418 {16934400, 11025, 1536, 0x19, 0x0},
419 {12000000, 11025, 1088, 0x19, 0x1},
420
421 /* 16k */
422 {12288000, 16000, 768, 0xa, 0x0},
423 {18432000, 16000, 1152, 0xb, 0x0},
424 {12000000, 16000, 750, 0xa, 0x1},
425
426 /* 22.05k */
427 {11289600, 22050, 512, 0x1a, 0x0},
428 {16934400, 22050, 768, 0x1b, 0x0},
429 {12000000, 22050, 544, 0x1b, 0x1},
430
431 /* 32k */
432 {12288000, 32000, 384, 0xc, 0x0},
433 {18432000, 32000, 576, 0xd, 0x0},
434 {12000000, 32000, 375, 0xa, 0x1},
435
436 /* 44.1k */
437 {11289600, 44100, 256, 0x10, 0x0},
438 {16934400, 44100, 384, 0x11, 0x0},
439 {12000000, 44100, 272, 0x11, 0x1},
440
441 /* 48k */
442 {12288000, 48000, 256, 0x0, 0x0},
443 {18432000, 48000, 384, 0x1, 0x0},
444 {12000000, 48000, 250, 0x0, 0x1},
445
446 /* 88.2k */
447 {11289600, 88200, 128, 0x1e, 0x0},
448 {16934400, 88200, 192, 0x1f, 0x0},
449 {12000000, 88200, 136, 0x1f, 0x1},
450
451 /* 96k */
452 {12288000, 96000, 128, 0xe, 0x0},
453 {18432000, 96000, 192, 0xf, 0x0},
454 {12000000, 96000, 125, 0xe, 0x1},
455};
456
457static int get_coeff(int mclk, int rate)
458{
459 int i;
460
461 for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
462 if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
463 return i;
464 }
465 return -EINVAL;
466}
467
468static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai,
469 int clk_id, unsigned int freq, int dir)
470{
471 struct snd_soc_codec *codec = codec_dai->codec;
472 struct wm8971_priv *wm8971 = codec->private_data;
473
474 switch (freq) {
475 case 11289600:
476 case 12000000:
477 case 12288000:
478 case 16934400:
479 case 18432000:
480 wm8971->sysclk = freq;
481 return 0;
482 }
483 return -EINVAL;
484}
485
486static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai,
487 unsigned int fmt)
488{
489 struct snd_soc_codec *codec = codec_dai->codec;
490 u16 iface = 0;
491
492 /* set master/slave audio interface */
493 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
494 case SND_SOC_DAIFMT_CBM_CFM:
495 iface = 0x0040;
496 break;
497 case SND_SOC_DAIFMT_CBS_CFS:
498 break;
499 default:
500 return -EINVAL;
501 }
502
503 /* interface format */
504 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
505 case SND_SOC_DAIFMT_I2S:
506 iface |= 0x0002;
507 break;
508 case SND_SOC_DAIFMT_RIGHT_J:
509 break;
510 case SND_SOC_DAIFMT_LEFT_J:
511 iface |= 0x0001;
512 break;
513 case SND_SOC_DAIFMT_DSP_A:
514 iface |= 0x0003;
515 break;
516 case SND_SOC_DAIFMT_DSP_B:
517 iface |= 0x0013;
518 break;
519 default:
520 return -EINVAL;
521 }
522
523 /* clock inversion */
524 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
525 case SND_SOC_DAIFMT_NB_NF:
526 break;
527 case SND_SOC_DAIFMT_IB_IF:
528 iface |= 0x0090;
529 break;
530 case SND_SOC_DAIFMT_IB_NF:
531 iface |= 0x0080;
532 break;
533 case SND_SOC_DAIFMT_NB_IF:
534 iface |= 0x0010;
535 break;
536 default:
537 return -EINVAL;
538 }
539
540 wm8971_write(codec, WM8971_IFACE, iface);
541 return 0;
542}
543
544static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
545 struct snd_pcm_hw_params *params)
546{
547 struct snd_soc_pcm_runtime *rtd = substream->private_data;
548 struct snd_soc_device *socdev = rtd->socdev;
549 struct snd_soc_codec *codec = socdev->codec;
550 struct wm8971_priv *wm8971 = codec->private_data;
551 u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3;
552 u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0;
553 int coeff = get_coeff(wm8971->sysclk, params_rate(params));
554
555 /* bit size */
556 switch (params_format(params)) {
557 case SNDRV_PCM_FORMAT_S16_LE:
558 break;
559 case SNDRV_PCM_FORMAT_S20_3LE:
560 iface |= 0x0004;
561 break;
562 case SNDRV_PCM_FORMAT_S24_LE:
563 iface |= 0x0008;
564 break;
565 case SNDRV_PCM_FORMAT_S32_LE:
566 iface |= 0x000c;
567 break;
568 }
569
570 /* set iface & srate */
571 wm8971_write(codec, WM8971_IFACE, iface);
572 if (coeff >= 0)
573 wm8971_write(codec, WM8971_SRATE, srate |
574 (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
575
576 return 0;
577}
578
579static int wm8971_mute(struct snd_soc_dai *dai, int mute)
580{
581 struct snd_soc_codec *codec = dai->codec;
582 u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7;
583
584 if (mute)
585 wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8);
586 else
587 wm8971_write(codec, WM8971_ADCDAC, mute_reg);
588 return 0;
589}
590
591static int wm8971_set_bias_level(struct snd_soc_codec *codec,
592 enum snd_soc_bias_level level)
593{
594 u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
595
596 switch (level) {
597 case SND_SOC_BIAS_ON:
598 /* set vmid to 50k and unmute dac */
599 wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
600 break;
601 case SND_SOC_BIAS_PREPARE:
602 break;
603 case SND_SOC_BIAS_STANDBY:
604 /* mute dac and set vmid to 500k, enable VREF */
605 wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
606 break;
607 case SND_SOC_BIAS_OFF:
608 wm8971_write(codec, WM8971_PWR1, 0x0001);
609 break;
610 }
611 codec->bias_level = level;
612 return 0;
613}
614
615#define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
616 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
617 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
618
619#define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
620 SNDRV_PCM_FMTBIT_S24_LE)
621
622struct snd_soc_dai wm8971_dai = {
623 .name = "WM8971",
624 .playback = {
625 .stream_name = "Playback",
626 .channels_min = 1,
627 .channels_max = 2,
628 .rates = WM8971_RATES,
629 .formats = WM8971_FORMATS,},
630 .capture = {
631 .stream_name = "Capture",
632 .channels_min = 1,
633 .channels_max = 2,
634 .rates = WM8971_RATES,
635 .formats = WM8971_FORMATS,},
636 .ops = {
637 .hw_params = wm8971_pcm_hw_params,
638 },
639 .dai_ops = {
640 .digital_mute = wm8971_mute,
641 .set_fmt = wm8971_set_dai_fmt,
642 .set_sysclk = wm8971_set_dai_sysclk,
643 },
644};
645EXPORT_SYMBOL_GPL(wm8971_dai);
646
647static void wm8971_work(struct work_struct *work)
648{
649 struct snd_soc_codec *codec =
650 container_of(work, struct snd_soc_codec, delayed_work.work);
651 wm8971_set_bias_level(codec, codec->bias_level);
652}
653
654static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
655{
656 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
657 struct snd_soc_codec *codec = socdev->codec;
658
659 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
660 return 0;
661}
662
663static int wm8971_resume(struct platform_device *pdev)
664{
665 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
666 struct snd_soc_codec *codec = socdev->codec;
667 int i;
668 u8 data[2];
669 u16 *cache = codec->reg_cache;
670 u16 reg;
671
672 /* Sync reg_cache with the hardware */
673 for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) {
674 if (i + 1 == WM8971_RESET)
675 continue;
676 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
677 data[1] = cache[i] & 0x00ff;
678 codec->hw_write(codec->control_data, data, 2);
679 }
680
681 wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
682
683 /* charge wm8971 caps */
684 if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
685 reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
686 wm8971_write(codec, WM8971_PWR1, reg | 0x01c0);
687 codec->bias_level = SND_SOC_BIAS_ON;
688 queue_delayed_work(wm8971_workq, &codec->delayed_work,
689 msecs_to_jiffies(1000));
690 }
691
692 return 0;
693}
694
695static int wm8971_init(struct snd_soc_device *socdev)
696{
697 struct snd_soc_codec *codec = socdev->codec;
698 int reg, ret = 0;
699
700 codec->name = "WM8971";
701 codec->owner = THIS_MODULE;
702 codec->read = wm8971_read_reg_cache;
703 codec->write = wm8971_write;
704 codec->set_bias_level = wm8971_set_bias_level;
705 codec->dai = &wm8971_dai;
706 codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
707 codec->num_dai = 1;
708 codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL);
709
710 if (codec->reg_cache == NULL)
711 return -ENOMEM;
712
713 wm8971_reset(codec);
714
715 /* register pcms */
716 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
717 if (ret < 0) {
718 printk(KERN_ERR "wm8971: failed to create pcms\n");
719 goto pcm_err;
720 }
721
722 /* charge output caps - set vmid to 5k for quick power up */
723 reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
724 wm8971_write(codec, WM8971_PWR1, reg | 0x01c0);
725 codec->bias_level = SND_SOC_BIAS_STANDBY;
726 queue_delayed_work(wm8971_workq, &codec->delayed_work,
727 msecs_to_jiffies(1000));
728
729 /* set the update bits */
730 reg = wm8971_read_reg_cache(codec, WM8971_LDAC);
731 wm8971_write(codec, WM8971_LDAC, reg | 0x0100);
732 reg = wm8971_read_reg_cache(codec, WM8971_RDAC);
733 wm8971_write(codec, WM8971_RDAC, reg | 0x0100);
734
735 reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V);
736 wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100);
737 reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V);
738 wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100);
739
740 reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V);
741 wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100);
742 reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V);
743 wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100);
744
745 reg = wm8971_read_reg_cache(codec, WM8971_LINVOL);
746 wm8971_write(codec, WM8971_LINVOL, reg | 0x0100);
747 reg = wm8971_read_reg_cache(codec, WM8971_RINVOL);
748 wm8971_write(codec, WM8971_RINVOL, reg | 0x0100);
749
750 wm8971_add_controls(codec);
751 wm8971_add_widgets(codec);
752 ret = snd_soc_register_card(socdev);
753 if (ret < 0) {
754 printk(KERN_ERR "wm8971: failed to register card\n");
755 goto card_err;
756 }
757 return ret;
758
759card_err:
760 snd_soc_free_pcms(socdev);
761 snd_soc_dapm_free(socdev);
762pcm_err:
763 kfree(codec->reg_cache);
764 return ret;
765}
766
767/* If the i2c layer weren't so broken, we could pass this kind of data
768 around */
769static struct snd_soc_device *wm8971_socdev;
770
771#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
772
773static int wm8971_i2c_probe(struct i2c_client *i2c,
774 const struct i2c_device_id *id)
775{
776 struct snd_soc_device *socdev = wm8971_socdev;
777 struct snd_soc_codec *codec = socdev->codec;
778 int ret;
779
780 i2c_set_clientdata(i2c, codec);
781
782 codec->control_data = i2c;
783
784 ret = wm8971_init(socdev);
785 if (ret < 0)
786 pr_err("failed to initialise WM8971\n");
787
788 return ret;
789}
790
791static int wm8971_i2c_remove(struct i2c_client *client)
792{
793 struct snd_soc_codec *codec = i2c_get_clientdata(client);
794 kfree(codec->reg_cache);
795 return 0;
796}
797
798static const struct i2c_device_id wm8971_i2c_id[] = {
799 { "wm8971", 0 },
800 { }
801};
802MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
803
804static struct i2c_driver wm8971_i2c_driver = {
805 .driver = {
806 .name = "WM8971 I2C Codec",
807 .owner = THIS_MODULE,
808 },
809 .probe = wm8971_i2c_probe,
810 .remove = wm8971_i2c_remove,
811 .id_table = wm8971_i2c_id,
812};
813
814static int wm8971_add_i2c_device(struct platform_device *pdev,
815 const struct wm8971_setup_data *setup)
816{
817 struct i2c_board_info info;
818 struct i2c_adapter *adapter;
819 struct i2c_client *client;
820 int ret;
821
822 ret = i2c_add_driver(&wm8971_i2c_driver);
823 if (ret != 0) {
824 dev_err(&pdev->dev, "can't add i2c driver\n");
825 return ret;
826 }
827
828 memset(&info, 0, sizeof(struct i2c_board_info));
829 info.addr = setup->i2c_address;
830 strlcpy(info.type, "wm8971", I2C_NAME_SIZE);
831
832 adapter = i2c_get_adapter(setup->i2c_bus);
833 if (!adapter) {
834 dev_err(&pdev->dev, "can't get i2c adapter %d\n",
835 setup->i2c_bus);
836 goto err_driver;
837 }
838
839 client = i2c_new_device(adapter, &info);
840 i2c_put_adapter(adapter);
841 if (!client) {
842 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
843 (unsigned int)info.addr);
844 goto err_driver;
845 }
846
847 return 0;
848
849err_driver:
850 i2c_del_driver(&wm8971_i2c_driver);
851 return -ENODEV;
852}
853
854#endif
855
856static int wm8971_probe(struct platform_device *pdev)
857{
858 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
859 struct wm8971_setup_data *setup;
860 struct snd_soc_codec *codec;
861 struct wm8971_priv *wm8971;
862 int ret = 0;
863
864 pr_info("WM8971 Audio Codec %s", WM8971_VERSION);
865
866 setup = socdev->codec_data;
867 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
868 if (codec == NULL)
869 return -ENOMEM;
870
871 wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
872 if (wm8971 == NULL) {
873 kfree(codec);
874 return -ENOMEM;
875 }
876
877 codec->private_data = wm8971;
878 socdev->codec = codec;
879 mutex_init(&codec->mutex);
880 INIT_LIST_HEAD(&codec->dapm_widgets);
881 INIT_LIST_HEAD(&codec->dapm_paths);
882 wm8971_socdev = socdev;
883
884 INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
885 wm8971_workq = create_workqueue("wm8971");
886 if (wm8971_workq == NULL) {
887 kfree(codec->private_data);
888 kfree(codec);
889 return -ENOMEM;
890 }
891
892#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
893 if (setup->i2c_address) {
894 codec->hw_write = (hw_write_t)i2c_master_send;
895 ret = wm8971_add_i2c_device(pdev, setup);
896 }
897#endif
898 /* Add other interfaces here */
899
900 if (ret != 0) {
901 destroy_workqueue(wm8971_workq);
902 kfree(codec->private_data);
903 kfree(codec);
904 }
905
906 return ret;
907}
908
909/* power down chip */
910static int wm8971_remove(struct platform_device *pdev)
911{
912 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
913 struct snd_soc_codec *codec = socdev->codec;
914
915 if (codec->control_data)
916 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
917 if (wm8971_workq)
918 destroy_workqueue(wm8971_workq);
919 snd_soc_free_pcms(socdev);
920 snd_soc_dapm_free(socdev);
921#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
922 i2c_unregister_device(codec->control_data);
923 i2c_del_driver(&wm8971_i2c_driver);
924#endif
925 kfree(codec->private_data);
926 kfree(codec);
927
928 return 0;
929}
930
931struct snd_soc_codec_device soc_codec_dev_wm8971 = {
932 .probe = wm8971_probe,
933 .remove = wm8971_remove,
934 .suspend = wm8971_suspend,
935 .resume = wm8971_resume,
936};
937
938EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
939
940MODULE_DESCRIPTION("ASoC WM8971 driver");
941MODULE_AUTHOR("Lab126");
942MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h
new file mode 100644
index 000000000000..ef4f08f9f344
--- /dev/null
+++ b/sound/soc/codecs/wm8971.h
@@ -0,0 +1,64 @@
1/*
2 * wm8971.h -- audio driver for WM8971
3 *
4 * Copyright 2005 Lab126, Inc.
5 *
6 * Author: Kenneth Kiraly <kiraly@lab126.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 _WM8971_H
16#define _WM8971_H
17
18#define WM8971_LINVOL 0x00
19#define WM8971_RINVOL 0x01
20#define WM8971_LOUT1V 0x02
21#define WM8971_ROUT1V 0x03
22#define WM8971_ADCDAC 0x05
23#define WM8971_IFACE 0x07
24#define WM8971_SRATE 0x08
25#define WM8971_LDAC 0x0a
26#define WM8971_RDAC 0x0b
27#define WM8971_BASS 0x0c
28#define WM8971_TREBLE 0x0d
29#define WM8971_RESET 0x0f
30#define WM8971_ALC1 0x11
31#define WM8971_ALC2 0x12
32#define WM8971_ALC3 0x13
33#define WM8971_NGATE 0x14
34#define WM8971_LADC 0x15
35#define WM8971_RADC 0x16
36#define WM8971_ADCTL1 0x17
37#define WM8971_ADCTL2 0x18
38#define WM8971_PWR1 0x19
39#define WM8971_PWR2 0x1a
40#define WM8971_ADCTL3 0x1b
41#define WM8971_ADCIN 0x1f
42#define WM8971_LADCIN 0x20
43#define WM8971_RADCIN 0x21
44#define WM8971_LOUTM1 0x22
45#define WM8971_LOUTM2 0x23
46#define WM8971_ROUTM1 0x24
47#define WM8971_ROUTM2 0x25
48#define WM8971_MOUTM1 0x26
49#define WM8971_MOUTM2 0x27
50#define WM8971_LOUT2V 0x28
51#define WM8971_ROUT2V 0x29
52#define WM8971_MOUTV 0x2A
53
54#define WM8971_SYSCLK 0
55
56struct wm8971_setup_data {
57 int i2c_bus;
58 unsigned short i2c_address;
59};
60
61extern struct snd_soc_dai wm8971_dai;
62extern struct snd_soc_codec_device soc_codec_dev_wm8971;
63
64#endif