aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2010-01-27 12:56:23 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-01-27 15:55:35 -0500
commit0d34e91596ef537c2893a031f0483014bb82adf3 (patch)
tree140e86285b303ee43359b0545994534bcea2ce66 /sound/soc
parent583b2be626b047eeb4f9a26721e38fe4992b2d02 (diff)
ASoC: add a WM8978 codec driver
The WM8978 codec from Wolfson Microelectronics is very similar to wm8974, but is stereo and also has some differences in pin configuration and internal signal routing. This driver is based on wm8974 and takes the differences into account. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/wm8978.c1124
-rw-r--r--sound/soc/codecs/wm8978.h89
4 files changed, 1219 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 62ff26a08a2f..0aad72fc1961 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -57,6 +57,7 @@ config SND_SOC_ALL_CODECS
57 select SND_SOC_WM8961 if I2C 57 select SND_SOC_WM8961 if I2C
58 select SND_SOC_WM8971 if I2C 58 select SND_SOC_WM8971 if I2C
59 select SND_SOC_WM8974 if I2C 59 select SND_SOC_WM8974 if I2C
60 select SND_SOC_WM8978 if I2C
60 select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI 61 select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
61 select SND_SOC_WM8990 if I2C 62 select SND_SOC_WM8990 if I2C
62 select SND_SOC_WM8993 if I2C 63 select SND_SOC_WM8993 if I2C
@@ -230,6 +231,9 @@ config SND_SOC_WM8971
230config SND_SOC_WM8974 231config SND_SOC_WM8974
231 tristate 232 tristate
232 233
234config SND_SOC_WM8978
235 tristate
236
233config SND_SOC_WM8988 237config SND_SOC_WM8988
234 tristate 238 tristate
235 239
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index ea9835412e6a..fbd290e41e9e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -44,6 +44,7 @@ snd-soc-wm8960-objs := wm8960.o
44snd-soc-wm8961-objs := wm8961.o 44snd-soc-wm8961-objs := wm8961.o
45snd-soc-wm8971-objs := wm8971.o 45snd-soc-wm8971-objs := wm8971.o
46snd-soc-wm8974-objs := wm8974.o 46snd-soc-wm8974-objs := wm8974.o
47snd-soc-wm8978-objs := wm8978.o
47snd-soc-wm8988-objs := wm8988.o 48snd-soc-wm8988-objs := wm8988.o
48snd-soc-wm8990-objs := wm8990.o 49snd-soc-wm8990-objs := wm8990.o
49snd-soc-wm8993-objs := wm8993.o 50snd-soc-wm8993-objs := wm8993.o
@@ -103,6 +104,7 @@ obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
103obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o 104obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
104obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o 105obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
105obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o 106obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
107obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o
106obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o 108obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
107obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o 109obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
108obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o 110obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
new file mode 100644
index 000000000000..d9d4e9dd1adb
--- /dev/null
+++ b/sound/soc/codecs/wm8978.c
@@ -0,0 +1,1124 @@
1/*
2 * wm8978.c -- WM8978 ALSA SoC Audio Codec driver
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 * Copyright (C) 2007 Carlos Munoz <carlos@kenati.com>
6 * Copyright 2006-2009 Wolfson Microelectronics PLC.
7 * Based on wm8974 and wm8990 by Liam Girdwood <lrg@slimlogic.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/delay.h>
19#include <linux/pm.h>
20#include <linux/i2c.h>
21#include <linux/platform_device.h>
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
26#include <sound/soc-dapm.h>
27#include <sound/initval.h>
28#include <sound/tlv.h>
29#include <asm/div64.h>
30
31#include "wm8978.h"
32
33static struct snd_soc_codec *wm8978_codec;
34
35/* wm8978 register cache. Note that register 0 is not included in the cache. */
36static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
37 0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */
38 0x0050, 0x0000, 0x0140, 0x0000, /* 0x04...0x07 */
39 0x0000, 0x0000, 0x0000, 0x00ff, /* 0x08...0x0b */
40 0x00ff, 0x0000, 0x0100, 0x00ff, /* 0x0c...0x0f */
41 0x00ff, 0x0000, 0x012c, 0x002c, /* 0x10...0x13 */
42 0x002c, 0x002c, 0x002c, 0x0000, /* 0x14...0x17 */
43 0x0032, 0x0000, 0x0000, 0x0000, /* 0x18...0x1b */
44 0x0000, 0x0000, 0x0000, 0x0000, /* 0x1c...0x1f */
45 0x0038, 0x000b, 0x0032, 0x0000, /* 0x20...0x23 */
46 0x0008, 0x000c, 0x0093, 0x00e9, /* 0x24...0x27 */
47 0x0000, 0x0000, 0x0000, 0x0000, /* 0x28...0x2b */
48 0x0033, 0x0010, 0x0010, 0x0100, /* 0x2c...0x2f */
49 0x0100, 0x0002, 0x0001, 0x0001, /* 0x30...0x33 */
50 0x0039, 0x0039, 0x0039, 0x0039, /* 0x34...0x37 */
51 0x0001, 0x0001, /* 0x38...0x3b */
52};
53
54/* codec private data */
55struct wm8978_priv {
56 struct snd_soc_codec codec;
57 unsigned int f_pllout;
58 unsigned int f_mclk;
59 unsigned int f_256fs;
60 unsigned int f_opclk;
61 enum wm8978_sysclk_src sysclk;
62 u16 reg_cache[WM8978_CACHEREGNUM];
63};
64
65static const char *wm8978_companding[] = {"Off", "NC", "u-law", "A-law"};
66static const char *wm8978_eqmode[] = {"Capture", "Playback"};
67static const char *wm8978_bw[] = {"Narrow", "Wide"};
68static const char *wm8978_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz"};
69static const char *wm8978_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz"};
70static const char *wm8978_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz"};
71static const char *wm8978_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"};
72static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"};
73static const char *wm8978_alc3[] = {"ALC", "Limiter"};
74static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"};
75
76static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1,
77 wm8978_companding);
78static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3,
79 wm8978_companding);
80static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode);
81static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1);
82static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw);
83static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2);
84static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw);
85static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3);
86static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw);
87static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4);
88static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5);
89static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3);
90static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1);
91
92static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
93static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
94static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
95static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
96static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1);
97
98static const struct snd_kcontrol_new wm8978_snd_controls[] = {
99
100 SOC_SINGLE("Digital Loopback Switch",
101 WM8978_COMPANDING_CONTROL, 0, 1, 0),
102
103 SOC_ENUM("ADC Companding", adc_compand),
104 SOC_ENUM("DAC Companding", dac_compand),
105
106 SOC_DOUBLE("DAC Inversion Switch", WM8978_DAC_CONTROL, 0, 1, 1, 0),
107
108 SOC_DOUBLE_R_TLV("PCM Volume",
109 WM8978_LEFT_DAC_DIGITAL_VOLUME, WM8978_RIGHT_DAC_DIGITAL_VOLUME,
110 0, 255, 0, digital_tlv),
111
112 SOC_SINGLE("High Pass Filter Switch", WM8978_ADC_CONTROL, 8, 1, 0),
113 SOC_SINGLE("High Pass Cut Off", WM8978_ADC_CONTROL, 4, 7, 0),
114 SOC_DOUBLE("ADC Inversion Switch", WM8978_ADC_CONTROL, 0, 1, 1, 0),
115
116 SOC_DOUBLE_R_TLV("ADC Volume",
117 WM8978_LEFT_ADC_DIGITAL_VOLUME, WM8978_RIGHT_ADC_DIGITAL_VOLUME,
118 0, 255, 0, digital_tlv),
119
120 SOC_ENUM("Equaliser Function", eqmode),
121 SOC_ENUM("EQ1 Cut Off", eq1),
122 SOC_SINGLE_TLV("EQ1 Volume", WM8978_EQ1, 0, 24, 1, eq_tlv),
123
124 SOC_ENUM("Equaliser EQ2 Bandwith", eq2bw),
125 SOC_ENUM("EQ2 Cut Off", eq2),
126 SOC_SINGLE_TLV("EQ2 Volume", WM8978_EQ2, 0, 24, 1, eq_tlv),
127
128 SOC_ENUM("Equaliser EQ3 Bandwith", eq3bw),
129 SOC_ENUM("EQ3 Cut Off", eq3),
130 SOC_SINGLE_TLV("EQ3 Volume", WM8978_EQ3, 0, 24, 1, eq_tlv),
131
132 SOC_ENUM("Equaliser EQ4 Bandwith", eq4bw),
133 SOC_ENUM("EQ4 Cut Off", eq4),
134 SOC_SINGLE_TLV("EQ4 Volume", WM8978_EQ4, 0, 24, 1, eq_tlv),
135
136 SOC_ENUM("EQ5 Cut Off", eq5),
137 SOC_SINGLE_TLV("EQ5 Volume", WM8978_EQ5, 0, 24, 1, eq_tlv),
138
139 SOC_SINGLE("DAC Playback Limiter Switch",
140 WM8978_DAC_LIMITER_1, 8, 1, 0),
141 SOC_SINGLE("DAC Playback Limiter Decay",
142 WM8978_DAC_LIMITER_1, 4, 15, 0),
143 SOC_SINGLE("DAC Playback Limiter Attack",
144 WM8978_DAC_LIMITER_1, 0, 15, 0),
145
146 SOC_SINGLE("DAC Playback Limiter Threshold",
147 WM8978_DAC_LIMITER_2, 4, 7, 0),
148 SOC_SINGLE("DAC Playback Limiter Boost",
149 WM8978_DAC_LIMITER_2, 0, 15, 0),
150
151 SOC_ENUM("ALC Enable Switch", alc1),
152 SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0),
153 SOC_SINGLE("ALC Capture Max Gain", WM8978_ALC_CONTROL_1, 3, 7, 0),
154
155 SOC_SINGLE("ALC Capture Hold", WM8978_ALC_CONTROL_2, 4, 7, 0),
156 SOC_SINGLE("ALC Capture Target", WM8978_ALC_CONTROL_2, 0, 15, 0),
157
158 SOC_ENUM("ALC Capture Mode", alc3),
159 SOC_SINGLE("ALC Capture Decay", WM8978_ALC_CONTROL_3, 4, 15, 0),
160 SOC_SINGLE("ALC Capture Attack", WM8978_ALC_CONTROL_3, 0, 15, 0),
161
162 SOC_SINGLE("ALC Capture Noise Gate Switch", WM8978_NOISE_GATE, 3, 1, 0),
163 SOC_SINGLE("ALC Capture Noise Gate Threshold",
164 WM8978_NOISE_GATE, 0, 7, 0),
165
166 SOC_DOUBLE_R("Capture PGA ZC Switch",
167 WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL,
168 7, 1, 0),
169
170 /* OUT1 - Headphones */
171 SOC_DOUBLE_R("Headphone Playback ZC Switch",
172 WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 7, 1, 0),
173
174 SOC_DOUBLE_R_TLV("Headphone Playback Volume",
175 WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL,
176 0, 63, 0, spk_tlv),
177
178 /* OUT2 - Speakers */
179 SOC_DOUBLE_R("Speaker Playback ZC Switch",
180 WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 7, 1, 0),
181
182 SOC_DOUBLE_R_TLV("Speaker Playback Volume",
183 WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL,
184 0, 63, 0, spk_tlv),
185
186 /* OUT3/4 - Line Output */
187 SOC_DOUBLE_R("Line Playback Switch",
188 WM8978_OUT3_MIXER_CONTROL, WM8978_OUT4_MIXER_CONTROL, 6, 1, 1),
189
190 /* Mixer #3: Boost (Input) mixer */
191 SOC_DOUBLE_R("PGA Boost (+20dB)",
192 WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
193 8, 1, 0),
194 SOC_DOUBLE_R_TLV("L2/R2 Boost Volume",
195 WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
196 4, 7, 0, boost_tlv),
197 SOC_DOUBLE_R_TLV("Aux Boost Volume",
198 WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
199 0, 7, 0, boost_tlv),
200
201 /* Input PGA volume */
202 SOC_DOUBLE_R_TLV("Input PGA Volume",
203 WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL,
204 0, 63, 0, inpga_tlv),
205
206 /* Headphone */
207 SOC_DOUBLE_R("Headphone Switch",
208 WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 6, 1, 1),
209
210 /* Speaker */
211 SOC_DOUBLE_R("Speaker Switch",
212 WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 6, 1, 1),
213};
214
215/* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */
216static const struct snd_kcontrol_new wm8978_left_out_mixer[] = {
217 SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_LEFT_MIXER_CONTROL, 1, 1, 0),
218 SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_LEFT_MIXER_CONTROL, 5, 1, 0),
219 SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_LEFT_MIXER_CONTROL, 0, 1, 0),
220};
221
222static const struct snd_kcontrol_new wm8978_right_out_mixer[] = {
223 SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_RIGHT_MIXER_CONTROL, 1, 1, 0),
224 SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 5, 1, 0),
225 SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 0, 1, 0),
226};
227
228/* OUT3/OUT4 Mixer not implemented */
229
230/* Mixer #2: Input PGA Mute */
231static const struct snd_kcontrol_new wm8978_left_input_mixer[] = {
232 SOC_DAPM_SINGLE("L2 Switch", WM8978_INPUT_CONTROL, 2, 1, 0),
233 SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 1, 1, 0),
234 SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 0, 1, 0),
235};
236static const struct snd_kcontrol_new wm8978_right_input_mixer[] = {
237 SOC_DAPM_SINGLE("R2 Switch", WM8978_INPUT_CONTROL, 6, 1, 0),
238 SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 5, 1, 0),
239 SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 4, 1, 0),
240};
241
242static const struct snd_soc_dapm_widget wm8978_dapm_widgets[] = {
243 SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",
244 WM8978_POWER_MANAGEMENT_3, 0, 0),
245 SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",
246 WM8978_POWER_MANAGEMENT_3, 1, 0),
247 SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture",
248 WM8978_POWER_MANAGEMENT_2, 0, 0),
249 SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture",
250 WM8978_POWER_MANAGEMENT_2, 1, 0),
251
252 /* Mixer #1: OUT1,2 */
253 SOC_MIXER_ARRAY("Left Output Mixer", WM8978_POWER_MANAGEMENT_3,
254 2, 0, wm8978_left_out_mixer),
255 SOC_MIXER_ARRAY("Right Output Mixer", WM8978_POWER_MANAGEMENT_3,
256 3, 0, wm8978_right_out_mixer),
257
258 SOC_MIXER_ARRAY("Left Input Mixer", WM8978_POWER_MANAGEMENT_2,
259 2, 0, wm8978_left_input_mixer),
260 SOC_MIXER_ARRAY("Right Input Mixer", WM8978_POWER_MANAGEMENT_2,
261 3, 0, wm8978_right_input_mixer),
262
263 SND_SOC_DAPM_PGA("Left Boost Mixer", WM8978_POWER_MANAGEMENT_2,
264 4, 0, NULL, 0),
265 SND_SOC_DAPM_PGA("Right Boost Mixer", WM8978_POWER_MANAGEMENT_2,
266 5, 0, NULL, 0),
267
268 SND_SOC_DAPM_PGA("Left Capture PGA", WM8978_LEFT_INP_PGA_CONTROL,
269 6, 1, NULL, 0),
270 SND_SOC_DAPM_PGA("Right Capture PGA", WM8978_RIGHT_INP_PGA_CONTROL,
271 6, 1, NULL, 0),
272
273 SND_SOC_DAPM_PGA("Left Headphone Out", WM8978_POWER_MANAGEMENT_2,
274 7, 0, NULL, 0),
275 SND_SOC_DAPM_PGA("Right Headphone Out", WM8978_POWER_MANAGEMENT_2,
276 8, 0, NULL, 0),
277
278 SND_SOC_DAPM_PGA("Left Speaker Out", WM8978_POWER_MANAGEMENT_3,
279 6, 0, NULL, 0),
280 SND_SOC_DAPM_PGA("Right Speaker Out", WM8978_POWER_MANAGEMENT_3,
281 5, 0, NULL, 0),
282
283 SND_SOC_DAPM_MIXER("OUT4 VMID", WM8978_POWER_MANAGEMENT_3,
284 8, 0, NULL, 0),
285
286 SND_SOC_DAPM_MICBIAS("Mic Bias", WM8978_POWER_MANAGEMENT_1, 4, 0),
287
288 SND_SOC_DAPM_INPUT("LMICN"),
289 SND_SOC_DAPM_INPUT("LMICP"),
290 SND_SOC_DAPM_INPUT("RMICN"),
291 SND_SOC_DAPM_INPUT("RMICP"),
292 SND_SOC_DAPM_INPUT("LAUX"),
293 SND_SOC_DAPM_INPUT("RAUX"),
294 SND_SOC_DAPM_INPUT("L2"),
295 SND_SOC_DAPM_INPUT("R2"),
296 SND_SOC_DAPM_OUTPUT("LHP"),
297 SND_SOC_DAPM_OUTPUT("RHP"),
298 SND_SOC_DAPM_OUTPUT("LSPK"),
299 SND_SOC_DAPM_OUTPUT("RSPK"),
300};
301
302static const struct snd_soc_dapm_route audio_map[] = {
303 /* Output mixer */
304 {"Right Output Mixer", "PCM Playback Switch", "Right DAC"},
305 {"Right Output Mixer", "Aux Playback Switch", "RAUX"},
306 {"Right Output Mixer", "Line Bypass Switch", "Right Boost Mixer"},
307
308 {"Left Output Mixer", "PCM Playback Switch", "Left DAC"},
309 {"Left Output Mixer", "Aux Playback Switch", "LAUX"},
310 {"Left Output Mixer", "Line Bypass Switch", "Left Boost Mixer"},
311
312 /* Outputs */
313 {"Right Headphone Out", NULL, "Right Output Mixer"},
314 {"RHP", NULL, "Right Headphone Out"},
315
316 {"Left Headphone Out", NULL, "Left Output Mixer"},
317 {"LHP", NULL, "Left Headphone Out"},
318
319 {"Right Speaker Out", NULL, "Right Output Mixer"},
320 {"RSPK", NULL, "Right Speaker Out"},
321
322 {"Left Speaker Out", NULL, "Left Output Mixer"},
323 {"LSPK", NULL, "Left Speaker Out"},
324
325 /* Boost Mixer */
326 {"Right ADC", NULL, "Right Boost Mixer"},
327
328 {"Right Boost Mixer", NULL, "RAUX"},
329 {"Right Boost Mixer", NULL, "Right Capture PGA"},
330 {"Right Boost Mixer", NULL, "R2"},
331
332 {"Left ADC", NULL, "Left Boost Mixer"},
333
334 {"Left Boost Mixer", NULL, "LAUX"},
335 {"Left Boost Mixer", NULL, "Left Capture PGA"},
336 {"Left Boost Mixer", NULL, "L2"},
337
338 /* Input PGA */
339 {"Right Capture PGA", NULL, "Right Input Mixer"},
340 {"Left Capture PGA", NULL, "Left Input Mixer"},
341
342 {"Right Input Mixer", "R2 Switch", "R2"},
343 {"Right Input Mixer", "MicN Switch", "RMICN"},
344 {"Right Input Mixer", "MicP Switch", "RMICP"},
345
346 {"Left Input Mixer", "L2 Switch", "L2"},
347 {"Left Input Mixer", "MicN Switch", "LMICN"},
348 {"Left Input Mixer", "MicP Switch", "LMICP"},
349};
350
351static int wm8978_add_widgets(struct snd_soc_codec *codec)
352{
353 snd_soc_dapm_new_controls(codec, wm8978_dapm_widgets,
354 ARRAY_SIZE(wm8978_dapm_widgets));
355
356 /* set up the WM8978 audio map */
357 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
358
359 return 0;
360}
361
362/* PLL divisors */
363struct wm8978_pll_div {
364 u32 k;
365 u8 n;
366 u8 div2;
367};
368
369#define FIXED_PLL_SIZE (1 << 24)
370
371static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
372 unsigned int source)
373{
374 u64 k_part;
375 unsigned int k, n_div, n_mod;
376
377 n_div = target / source;
378 if (n_div < 6) {
379 source >>= 1;
380 pll_div->div2 = 1;
381 n_div = target / source;
382 } else {
383 pll_div->div2 = 0;
384 }
385
386 if (n_div < 6 || n_div > 12)
387 dev_warn(wm8978_codec->dev,
388 "WM8978 N value exceeds recommended range! N = %u\n",
389 n_div);
390
391 pll_div->n = n_div;
392 n_mod = target - source * n_div;
393 k_part = FIXED_PLL_SIZE * (long long)n_mod + source / 2;
394
395 do_div(k_part, source);
396
397 k = k_part & 0xFFFFFFFF;
398
399 pll_div->k = k;
400}
401/*
402 * Calculate internal frequencies and dividers, according to Figure 40
403 * "PLL and Clock Select Circuit" in WM8978 datasheet Rev. 2.6
404 */
405static int wm8978_configure_pll(struct snd_soc_codec *codec)
406{
407 struct wm8978_priv *wm8978 = codec->private_data;
408 struct wm8978_pll_div pll_div;
409 unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk,
410 f_256fs = wm8978->f_256fs;
411 unsigned int f2, opclk_div;
412
413 if (!f_mclk)
414 return -EINVAL;
415
416 if (f_opclk) {
417 /*
418 * The user needs OPCLK. Choose OPCLKDIV to put
419 * 6 <= R = f2 / f1 < 13, 1 <= OPCLKDIV <= 4.
420 * f_opclk = f_mclk * prescale * R / 4 / OPCLKDIV, where
421 * prescale = 1, or prescale = 2. Prescale is calculated inside
422 * pll_factors(). We have to select f_PLLOUT, such that
423 * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be
424 * f_mclk * 3 / 16 <= f_opclk < f_mclk * 13 / 4.
425 */
426 if (16 * f_opclk < 3 * f_mclk || 4 * f_opclk >= 13 * f_mclk)
427 return -EINVAL;
428
429 if (4 * f_opclk < 3 * f_mclk)
430 /* Have to use OPCLKDIV */
431 opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk;
432 else
433 opclk_div = 1;
434
435 dev_dbg(codec->dev, "%s: OPCLKDIV=%d\n", __func__, opclk_div);
436
437 snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 0x30,
438 (opclk_div - 1) << 4);
439
440 wm8978->f_pllout = f_opclk * opclk_div;
441 } else if (f_256fs) {
442 /*
443 * Not using OPCLK, choose R:
444 * 6 <= R = f2 / f1 < 13, to put 1 <= MCLKDIV <= 12.
445 * f_256fs = f_mclk * prescale * R / 4 / MCLKDIV, where
446 * prescale = 1, or prescale = 2. Prescale is calculated inside
447 * pll_factors(). We have to select f_PLLOUT, such that
448 * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be
449 * f_mclk * 3 / 48 <= f_256fs < f_mclk * 13 / 4. This means MCLK
450 * must be 3.781MHz <= f_MCLK <= 32.768MHz
451 */
452 if (48 * f_256fs < 3 * f_mclk || 4 * f_256fs >= 13 * f_mclk)
453 return -EINVAL;
454
455 /*
456 * MCLKDIV will be selected in .hw_params(), just choose a
457 * suitable f_PLLOUT
458 */
459 if (4 * f_256fs < 3 * f_mclk)
460 /* Will have to use MCLKDIV */
461 wm8978->f_pllout = wm8978->f_mclk * 3 / 4;
462 else
463 wm8978->f_pllout = f_256fs;
464
465 /* GPIO1 into default mode as input - before configuring PLL */
466 snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0);
467 } else {
468 return -EINVAL;
469 }
470
471 f2 = wm8978->f_pllout * 4;
472
473 dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__,
474 wm8978->f_mclk, wm8978->f_pllout);
475
476 pll_factors(&pll_div, f2, wm8978->f_mclk);
477
478 dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n",
479 __func__, pll_div.n, pll_div.k, pll_div.div2);
480
481 /* Turn PLL off for configuration... */
482 snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
483
484 snd_soc_write(codec, WM8978_PLL_N, (pll_div.div2 << 4) | pll_div.n);
485 snd_soc_write(codec, WM8978_PLL_K1, pll_div.k >> 18);
486 snd_soc_write(codec, WM8978_PLL_K2, (pll_div.k >> 9) & 0x1ff);
487 snd_soc_write(codec, WM8978_PLL_K3, pll_div.k & 0x1ff);
488
489 /* ...and on again */
490 snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
491
492 if (f_opclk)
493 /* Output PLL (OPCLK) to GPIO1 */
494 snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 4);
495
496 return 0;
497}
498
499/*
500 * Configure WM8978 clock dividers.
501 */
502static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
503 int div_id, int div)
504{
505 struct snd_soc_codec *codec = codec_dai->codec;
506 struct wm8978_priv *wm8978 = codec->private_data;
507 int ret = 0;
508
509 switch (div_id) {
510 case WM8978_OPCLKRATE:
511 wm8978->f_opclk = div;
512
513 if (wm8978->f_mclk)
514 ret = wm8978_configure_pll(codec);
515 break;
516 case WM8978_MCLKDIV:
517 if (div & ~0xe0)
518 return -EINVAL;
519 snd_soc_update_bits(codec, WM8978_CLOCKING, 0xe0, div);
520 break;
521 case WM8978_ADCCLK:
522 if (div & ~8)
523 return -EINVAL;
524 snd_soc_update_bits(codec, WM8978_ADC_CONTROL, 8, div);
525 break;
526 case WM8978_DACCLK:
527 if (div & ~8)
528 return -EINVAL;
529 snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 8, div);
530 break;
531 case WM8978_BCLKDIV:
532 if (div & ~0x1c)
533 return -EINVAL;
534 snd_soc_update_bits(codec, WM8978_CLOCKING, 0x1c, div);
535 break;
536 default:
537 return -EINVAL;
538 }
539
540 dev_dbg(codec->dev, "%s: ID %d, value %u\n", __func__, div_id, div);
541
542 return ret;
543}
544
545/*
546 * @freq: when .set_pll() us not used, freq is codec MCLK input frequency
547 */
548static int wm8978_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
549 unsigned int freq, int dir)
550{
551 struct snd_soc_codec *codec = codec_dai->codec;
552 struct wm8978_priv *wm8978 = codec->private_data;
553 int ret = 0;
554
555 dev_dbg(codec->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq);
556
557 if (freq) {
558 wm8978->f_mclk = freq;
559
560 /* Even if MCLK is used for system clock, might have to drive OPCLK */
561 if (wm8978->f_opclk)
562 ret = wm8978_configure_pll(codec);
563
564 /* Our sysclk is fixed to 256 * fs, will configure in .hw_params() */
565
566 if (!ret)
567 wm8978->sysclk = clk_id;
568 }
569
570 if (wm8978->sysclk == WM8978_PLL && (!freq || clk_id == WM8978_MCLK)) {
571 /* Clock CODEC directly from MCLK */
572 snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0);
573
574 /* GPIO1 into default mode as input - before configuring PLL */
575 snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0);
576
577 /* Turn off PLL */
578 snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
579 wm8978->sysclk = WM8978_MCLK;
580 wm8978->f_pllout = 0;
581 wm8978->f_opclk = 0;
582 }
583
584 return ret;
585}
586
587/*
588 * Set ADC and Voice DAC format.
589 */
590static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
591{
592 struct snd_soc_codec *codec = codec_dai->codec;
593 /*
594 * BCLK polarity mask = 0x100, LRC clock polarity mask = 0x80,
595 * Data Format mask = 0x18: all will be calculated anew
596 */
597 u16 iface = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x198;
598 u16 clk = snd_soc_read(codec, WM8978_CLOCKING);
599
600 dev_dbg(codec->dev, "%s\n", __func__);
601
602 /* set master/slave audio interface */
603 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
604 case SND_SOC_DAIFMT_CBM_CFM:
605 clk |= 1;
606 break;
607 case SND_SOC_DAIFMT_CBS_CFS:
608 clk &= ~1;
609 break;
610 default:
611 return -EINVAL;
612 }
613
614 /* interface format */
615 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
616 case SND_SOC_DAIFMT_I2S:
617 iface |= 0x10;
618 break;
619 case SND_SOC_DAIFMT_RIGHT_J:
620 break;
621 case SND_SOC_DAIFMT_LEFT_J:
622 iface |= 0x8;
623 break;
624 case SND_SOC_DAIFMT_DSP_A:
625 iface |= 0x18;
626 break;
627 default:
628 return -EINVAL;
629 }
630
631 /* clock inversion */
632 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
633 case SND_SOC_DAIFMT_NB_NF:
634 break;
635 case SND_SOC_DAIFMT_IB_IF:
636 iface |= 0x180;
637 break;
638 case SND_SOC_DAIFMT_IB_NF:
639 iface |= 0x100;
640 break;
641 case SND_SOC_DAIFMT_NB_IF:
642 iface |= 0x80;
643 break;
644 default:
645 return -EINVAL;
646 }
647
648 snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface);
649 snd_soc_write(codec, WM8978_CLOCKING, clk);
650
651 return 0;
652}
653
654/* MCLK dividers */
655static const int mclk_numerator[] = {1, 3, 2, 3, 4, 6, 8, 12};
656static const int mclk_denominator[] = {1, 2, 1, 1, 1, 1, 1, 1};
657
658/*
659 * Set PCM DAI bit size and sample rate.
660 */
661static int wm8978_hw_params(struct snd_pcm_substream *substream,
662 struct snd_pcm_hw_params *params,
663 struct snd_soc_dai *dai)
664{
665 struct snd_soc_pcm_runtime *rtd = substream->private_data;
666 struct snd_soc_device *socdev = rtd->socdev;
667 struct snd_soc_codec *codec = socdev->card->codec;
668 struct wm8978_priv *wm8978 = codec->private_data;
669 /* Word length mask = 0x60 */
670 u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
671 /* Sampling rate mask = 0xe (for filters) */
672 u16 add_ctl = snd_soc_read(codec, WM8978_ADDITIONAL_CONTROL) & ~0xe;
673 u16 clking = snd_soc_read(codec, WM8978_CLOCKING);
674 enum wm8978_sysclk_src current_clk_id = clking & 0x100 ?
675 WM8978_PLL : WM8978_MCLK;
676 unsigned int f_sel, diff, diff_best = INT_MAX;
677 int i, best = 0;
678
679 if (!wm8978->f_mclk)
680 return -EINVAL;
681
682 /* bit size */
683 switch (params_format(params)) {
684 case SNDRV_PCM_FORMAT_S16_LE:
685 break;
686 case SNDRV_PCM_FORMAT_S20_3LE:
687 iface_ctl |= 0x20;
688 break;
689 case SNDRV_PCM_FORMAT_S24_LE:
690 iface_ctl |= 0x40;
691 break;
692 case SNDRV_PCM_FORMAT_S32_LE:
693 iface_ctl |= 0x60;
694 break;
695 }
696
697 /* filter coefficient */
698 switch (params_rate(params)) {
699 case 8000:
700 add_ctl |= 0x5 << 1;
701 break;
702 case 11025:
703 add_ctl |= 0x4 << 1;
704 break;
705 case 16000:
706 add_ctl |= 0x3 << 1;
707 break;
708 case 22050:
709 add_ctl |= 0x2 << 1;
710 break;
711 case 32000:
712 add_ctl |= 0x1 << 1;
713 break;
714 case 44100:
715 case 48000:
716 break;
717 }
718
719 /* Sampling rate is known now, can configure the MCLK divider */
720 wm8978->f_256fs = params_rate(params) * 256;
721
722 if (wm8978->sysclk == WM8978_MCLK) {
723 f_sel = wm8978->f_mclk;
724 } else {
725 if (!wm8978->f_pllout) {
726 int ret = wm8978_configure_pll(codec);
727 if (ret < 0)
728 return ret;
729 }
730 f_sel = wm8978->f_pllout;
731 }
732
733 /*
734 * In some cases it is possible to reconfigure PLL to a higher frequency
735 * by raising OPCLKDIV, but normally OPCLK is configured to 256 * fs or
736 * 512 * fs, so, we should be fine.
737 */
738 if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs)
739 return -EINVAL;
740
741 for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) {
742 diff = abs(wm8978->f_256fs * 3 -
743 f_sel * 3 * mclk_denominator[i] / mclk_numerator[i]);
744
745 if (diff < diff_best) {
746 diff_best = diff;
747 best = i;
748 }
749
750 if (!diff)
751 break;
752 }
753
754 if (diff)
755 dev_warn(codec->dev, "Imprecise clock: %u%s\n",
756 f_sel * mclk_denominator[best] / mclk_numerator[best],
757 wm8978->sysclk == WM8978_MCLK ?
758 ", consider using PLL" : "");
759
760 dev_dbg(codec->dev, "%s: fmt %d, rate %u, MCLK divisor #%d\n", __func__,
761 params_format(params), params_rate(params), best);
762
763 /* MCLK divisor mask = 0xe0 */
764 snd_soc_update_bits(codec, WM8978_CLOCKING, 0xe0, best << 5);
765
766 snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface_ctl);
767 snd_soc_write(codec, WM8978_ADDITIONAL_CONTROL, add_ctl);
768
769 if (wm8978->sysclk != current_clk_id) {
770 if (wm8978->sysclk == WM8978_PLL)
771 /* Run CODEC from PLL instead of MCLK */
772 snd_soc_update_bits(codec, WM8978_CLOCKING,
773 0x100, 0x100);
774 else
775 /* Clock CODEC directly from MCLK */
776 snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0);
777 }
778
779 return 0;
780}
781
782static int wm8978_mute(struct snd_soc_dai *dai, int mute)
783{
784 struct snd_soc_codec *codec = dai->codec;
785
786 dev_dbg(codec->dev, "%s: %d\n", __func__, mute);
787
788 if (mute)
789 snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0x40);
790 else
791 snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0);
792
793 return 0;
794}
795
796static int wm8978_set_bias_level(struct snd_soc_codec *codec,
797 enum snd_soc_bias_level level)
798{
799 u16 power1 = snd_soc_read(codec, WM8978_POWER_MANAGEMENT_1) & ~3;
800
801 switch (level) {
802 case SND_SOC_BIAS_ON:
803 case SND_SOC_BIAS_PREPARE:
804 power1 |= 1; /* VMID 75k */
805 snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1);
806 break;
807 case SND_SOC_BIAS_STANDBY:
808 /* bit 3: enable bias, bit 2: enable I/O tie off buffer */
809 power1 |= 0xc;
810
811 if (codec->bias_level == SND_SOC_BIAS_OFF) {
812 /* Initial cap charge at VMID 5k */
813 snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1,
814 power1 | 0x3);
815 mdelay(100);
816 }
817
818 power1 |= 0x2; /* VMID 500k */
819 snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1);
820 break;
821 case SND_SOC_BIAS_OFF:
822 /* Preserve PLL - OPCLK may be used by someone */
823 snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, ~0x20, 0);
824 snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0);
825 snd_soc_write(codec, WM8978_POWER_MANAGEMENT_3, 0);
826 break;
827 }
828
829 dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1);
830
831 codec->bias_level = level;
832 return 0;
833}
834
835#define WM8978_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
836 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
837
838static struct snd_soc_dai_ops wm8978_dai_ops = {
839 .hw_params = wm8978_hw_params,
840 .digital_mute = wm8978_mute,
841 .set_fmt = wm8978_set_dai_fmt,
842 .set_clkdiv = wm8978_set_dai_clkdiv,
843 .set_sysclk = wm8978_set_dai_sysclk,
844};
845
846/* Also supports 12kHz */
847struct snd_soc_dai wm8978_dai = {
848 .name = "WM8978 HiFi",
849 .id = 1,
850 .playback = {
851 .stream_name = "Playback",
852 .channels_min = 1,
853 .channels_max = 2,
854 .rates = SNDRV_PCM_RATE_8000_48000,
855 .formats = WM8978_FORMATS,
856 },
857 .capture = {
858 .stream_name = "Capture",
859 .channels_min = 1,
860 .channels_max = 2,
861 .rates = SNDRV_PCM_RATE_8000_48000,
862 .formats = WM8978_FORMATS,
863 },
864 .ops = &wm8978_dai_ops,
865};
866EXPORT_SYMBOL_GPL(wm8978_dai);
867
868static int wm8978_suspend(struct platform_device *pdev, pm_message_t state)
869{
870 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
871 struct snd_soc_codec *codec = socdev->card->codec;
872
873 wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
874 /* Also switch PLL off */
875 snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
876 /* Put to sleep */
877 snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0x40);
878
879 return 0;
880}
881
882static int wm8978_resume(struct platform_device *pdev)
883{
884 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
885 struct snd_soc_codec *codec = socdev->card->codec;
886 struct wm8978_priv *wm8978 = codec->private_data;
887 int i;
888 u16 *cache = codec->reg_cache;
889
890 /* Wake up the codec */
891 snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0);
892
893 /* Sync reg_cache with the hardware */
894 for (i = 0; i < ARRAY_SIZE(wm8978_reg); i++) {
895 if (i == WM8978_RESET)
896 continue;
897 if (cache[i] != wm8978_reg[i])
898 snd_soc_write(codec, i, cache[i]);
899 }
900
901 wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
902
903 if (wm8978->f_pllout)
904 /* Switch PLL on */
905 snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
906
907 return 0;
908}
909
910static int wm8978_probe(struct platform_device *pdev)
911{
912 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
913 struct snd_soc_codec *codec;
914 int ret = 0;
915
916 if (wm8978_codec == NULL) {
917 dev_err(&pdev->dev, "Codec device not registered\n");
918 return -ENODEV;
919 }
920
921 socdev->card->codec = wm8978_codec;
922 codec = wm8978_codec;
923
924 /* register pcms */
925 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
926 if (ret < 0) {
927 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
928 goto pcm_err;
929 }
930
931 snd_soc_add_controls(codec, wm8978_snd_controls,
932 ARRAY_SIZE(wm8978_snd_controls));
933 wm8978_add_widgets(codec);
934
935pcm_err:
936 return ret;
937}
938
939/* power down chip */
940static int wm8978_remove(struct platform_device *pdev)
941{
942 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
943
944 snd_soc_free_pcms(socdev);
945 snd_soc_dapm_free(socdev);
946
947 return 0;
948}
949
950struct snd_soc_codec_device soc_codec_dev_wm8978 = {
951 .probe = wm8978_probe,
952 .remove = wm8978_remove,
953 .suspend = wm8978_suspend,
954 .resume = wm8978_resume,
955};
956EXPORT_SYMBOL_GPL(soc_codec_dev_wm8978);
957
958/*
959 * These registers contain an "update" bit - bit 8. This means, for example,
960 * that one can write new DAC digital volume for both channels, but only when
961 * the update bit is set, will also the volume be updated - simultaneously for
962 * both channels.
963 */
964static const int update_reg[] = {
965 WM8978_LEFT_DAC_DIGITAL_VOLUME,
966 WM8978_RIGHT_DAC_DIGITAL_VOLUME,
967 WM8978_LEFT_ADC_DIGITAL_VOLUME,
968 WM8978_RIGHT_ADC_DIGITAL_VOLUME,
969 WM8978_LEFT_INP_PGA_CONTROL,
970 WM8978_RIGHT_INP_PGA_CONTROL,
971 WM8978_LOUT1_HP_CONTROL,
972 WM8978_ROUT1_HP_CONTROL,
973 WM8978_LOUT2_SPK_CONTROL,
974 WM8978_ROUT2_SPK_CONTROL,
975};
976
977static __devinit int wm8978_register(struct wm8978_priv *wm8978)
978{
979 int ret, i;
980 struct snd_soc_codec *codec = &wm8978->codec;
981
982 if (wm8978_codec) {
983 dev_err(codec->dev, "Another WM8978 is registered\n");
984 return -EINVAL;
985 }
986
987 /*
988 * Set default system clock to PLL, it is more precise, this is also the
989 * default hardware setting
990 */
991 wm8978->sysclk = WM8978_PLL;
992
993 mutex_init(&codec->mutex);
994 INIT_LIST_HEAD(&codec->dapm_widgets);
995 INIT_LIST_HEAD(&codec->dapm_paths);
996
997 codec->private_data = wm8978;
998 codec->name = "WM8978";
999 codec->owner = THIS_MODULE;
1000 codec->bias_level = SND_SOC_BIAS_OFF;
1001 codec->set_bias_level = wm8978_set_bias_level;
1002 codec->dai = &wm8978_dai;
1003 codec->num_dai = 1;
1004 codec->reg_cache_size = WM8978_CACHEREGNUM;
1005 codec->reg_cache = &wm8978->reg_cache;
1006
1007 ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
1008 if (ret < 0) {
1009 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
1010 goto err;
1011 }
1012
1013 memcpy(codec->reg_cache, wm8978_reg, sizeof(wm8978_reg));
1014
1015 /*
1016 * Set the update bit in all registers, that have one. This way all
1017 * writes to those registers will also cause the update bit to be
1018 * written.
1019 */
1020 for (i = 0; i < ARRAY_SIZE(update_reg); i++)
1021 ((u16 *)codec->reg_cache)[update_reg[i]] |= 0x100;
1022
1023 /* Reset the codec */
1024 ret = snd_soc_write(codec, WM8978_RESET, 0);
1025 if (ret < 0) {
1026 dev_err(codec->dev, "Failed to issue reset\n");
1027 goto err;
1028 }
1029
1030 wm8978_dai.dev = codec->dev;
1031
1032 wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1033
1034 wm8978_codec = codec;
1035
1036 ret = snd_soc_register_codec(codec);
1037 if (ret != 0) {
1038 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
1039 goto err;
1040 }
1041
1042 ret = snd_soc_register_dai(&wm8978_dai);
1043 if (ret != 0) {
1044 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
1045 goto err_codec;
1046 }
1047
1048 return 0;
1049
1050err_codec:
1051 snd_soc_unregister_codec(codec);
1052err:
1053 kfree(wm8978);
1054 return ret;
1055}
1056
1057static __devexit void wm8978_unregister(struct wm8978_priv *wm8978)
1058{
1059 wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF);
1060 snd_soc_unregister_dai(&wm8978_dai);
1061 snd_soc_unregister_codec(&wm8978->codec);
1062 kfree(wm8978);
1063 wm8978_codec = NULL;
1064}
1065
1066static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
1067 const struct i2c_device_id *id)
1068{
1069 struct wm8978_priv *wm8978;
1070 struct snd_soc_codec *codec;
1071
1072 wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL);
1073 if (wm8978 == NULL)
1074 return -ENOMEM;
1075
1076 codec = &wm8978->codec;
1077 codec->hw_write = (hw_write_t)i2c_master_send;
1078
1079 i2c_set_clientdata(i2c, wm8978);
1080 codec->control_data = i2c;
1081
1082 codec->dev = &i2c->dev;
1083
1084 return wm8978_register(wm8978);
1085}
1086
1087static __devexit int wm8978_i2c_remove(struct i2c_client *client)
1088{
1089 struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
1090 wm8978_unregister(wm8978);
1091 return 0;
1092}
1093
1094static const struct i2c_device_id wm8978_i2c_id[] = {
1095 { "wm8978", 0 },
1096 { }
1097};
1098MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);
1099
1100static struct i2c_driver wm8978_i2c_driver = {
1101 .driver = {
1102 .name = "WM8978",
1103 .owner = THIS_MODULE,
1104 },
1105 .probe = wm8978_i2c_probe,
1106 .remove = __devexit_p(wm8978_i2c_remove),
1107 .id_table = wm8978_i2c_id,
1108};
1109
1110static int __init wm8978_modinit(void)
1111{
1112 return i2c_add_driver(&wm8978_i2c_driver);
1113}
1114module_init(wm8978_modinit);
1115
1116static void __exit wm8978_exit(void)
1117{
1118 i2c_del_driver(&wm8978_i2c_driver);
1119}
1120module_exit(wm8978_exit);
1121
1122MODULE_DESCRIPTION("ASoC WM8978 codec driver");
1123MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
1124MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h
new file mode 100644
index 000000000000..b58f0bf947e7
--- /dev/null
+++ b/sound/soc/codecs/wm8978.h
@@ -0,0 +1,89 @@
1/*
2 * wm8978.h -- codec driver for WM8978
3 *
4 * Copyright 2009 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef __WM8978_H__
12#define __WM8978_H__
13
14/*
15 * Register values.
16 */
17#define WM8978_RESET 0x00
18#define WM8978_POWER_MANAGEMENT_1 0x01
19#define WM8978_POWER_MANAGEMENT_2 0x02
20#define WM8978_POWER_MANAGEMENT_3 0x03
21#define WM8978_AUDIO_INTERFACE 0x04
22#define WM8978_COMPANDING_CONTROL 0x05
23#define WM8978_CLOCKING 0x06
24#define WM8978_ADDITIONAL_CONTROL 0x07
25#define WM8978_GPIO_CONTROL 0x08
26#define WM8978_JACK_DETECT_CONTROL_1 0x09
27#define WM8978_DAC_CONTROL 0x0A
28#define WM8978_LEFT_DAC_DIGITAL_VOLUME 0x0B
29#define WM8978_RIGHT_DAC_DIGITAL_VOLUME 0x0C
30#define WM8978_JACK_DETECT_CONTROL_2 0x0D
31#define WM8978_ADC_CONTROL 0x0E
32#define WM8978_LEFT_ADC_DIGITAL_VOLUME 0x0F
33#define WM8978_RIGHT_ADC_DIGITAL_VOLUME 0x10
34#define WM8978_EQ1 0x12
35#define WM8978_EQ2 0x13
36#define WM8978_EQ3 0x14
37#define WM8978_EQ4 0x15
38#define WM8978_EQ5 0x16
39#define WM8978_DAC_LIMITER_1 0x18
40#define WM8978_DAC_LIMITER_2 0x19
41#define WM8978_NOTCH_FILTER_1 0x1b
42#define WM8978_NOTCH_FILTER_2 0x1c
43#define WM8978_NOTCH_FILTER_3 0x1d
44#define WM8978_NOTCH_FILTER_4 0x1e
45#define WM8978_ALC_CONTROL_1 0x20
46#define WM8978_ALC_CONTROL_2 0x21
47#define WM8978_ALC_CONTROL_3 0x22
48#define WM8978_NOISE_GATE 0x23
49#define WM8978_PLL_N 0x24
50#define WM8978_PLL_K1 0x25
51#define WM8978_PLL_K2 0x26
52#define WM8978_PLL_K3 0x27
53#define WM8978_3D_CONTROL 0x29
54#define WM8978_BEEP_CONTROL 0x2b
55#define WM8978_INPUT_CONTROL 0x2c
56#define WM8978_LEFT_INP_PGA_CONTROL 0x2d
57#define WM8978_RIGHT_INP_PGA_CONTROL 0x2e
58#define WM8978_LEFT_ADC_BOOST_CONTROL 0x2f
59#define WM8978_RIGHT_ADC_BOOST_CONTROL 0x30
60#define WM8978_OUTPUT_CONTROL 0x31
61#define WM8978_LEFT_MIXER_CONTROL 0x32
62#define WM8978_RIGHT_MIXER_CONTROL 0x33
63#define WM8978_LOUT1_HP_CONTROL 0x34
64#define WM8978_ROUT1_HP_CONTROL 0x35
65#define WM8978_LOUT2_SPK_CONTROL 0x36
66#define WM8978_ROUT2_SPK_CONTROL 0x37
67#define WM8978_OUT3_MIXER_CONTROL 0x38
68#define WM8978_OUT4_MIXER_CONTROL 0x39
69
70#define WM8978_CACHEREGNUM 58
71
72/* Clock divider Id's */
73enum wm8978_clk_id {
74 WM8978_OPCLKRATE,
75 WM8978_MCLKDIV,
76 WM8978_ADCCLK,
77 WM8978_DACCLK,
78 WM8978_BCLKDIV,
79};
80
81enum wm8978_sysclk_src {
82 WM8978_PLL,
83 WM8978_MCLK
84};
85
86extern struct snd_soc_dai wm8978_dai;
87extern struct snd_soc_codec_device soc_codec_dev_wm8978;
88
89#endif /* __WM8978_H__ */