diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2011-06-27 11:04:01 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-06-28 12:11:20 -0400 |
commit | cc52688a08880021d31a109f36ee4a78c10ba214 (patch) | |
tree | edfb2c23204a895c55aa53b3515850b8d686ffff /sound/soc/codecs/adav80x.c | |
parent | 766705eef5d0faa9fc1e6a0cac95fc433bf5de70 (diff) |
ASoC: Add ADAV80x codec driver
This patch adds support for the Analog Devices ADAV801 and ADAV803 audio codec.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/adav80x.c')
-rw-r--r-- | sound/soc/codecs/adav80x.c | 951 |
1 files changed, 951 insertions, 0 deletions
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c new file mode 100644 index 000000000000..e30fba62392d --- /dev/null +++ b/sound/soc/codecs/adav80x.c | |||
@@ -0,0 +1,951 @@ | |||
1 | /* | ||
2 | * ADAV80X Audio Codec driver supporting ADAV801, ADAV803 | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * Author: Yi Li <yi.li@analog.com> | ||
6 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include <sound/tlv.h> | ||
21 | #include <sound/soc.h> | ||
22 | |||
23 | #include "adav80x.h" | ||
24 | |||
25 | #define ADAV80X_PLAYBACK_CTRL 0x04 | ||
26 | #define ADAV80X_AUX_IN_CTRL 0x05 | ||
27 | #define ADAV80X_REC_CTRL 0x06 | ||
28 | #define ADAV80X_AUX_OUT_CTRL 0x07 | ||
29 | #define ADAV80X_DPATH_CTRL1 0x62 | ||
30 | #define ADAV80X_DPATH_CTRL2 0x63 | ||
31 | #define ADAV80X_DAC_CTRL1 0x64 | ||
32 | #define ADAV80X_DAC_CTRL2 0x65 | ||
33 | #define ADAV80X_DAC_CTRL3 0x66 | ||
34 | #define ADAV80X_DAC_L_VOL 0x68 | ||
35 | #define ADAV80X_DAC_R_VOL 0x69 | ||
36 | #define ADAV80X_PGA_L_VOL 0x6c | ||
37 | #define ADAV80X_PGA_R_VOL 0x6d | ||
38 | #define ADAV80X_ADC_CTRL1 0x6e | ||
39 | #define ADAV80X_ADC_CTRL2 0x6f | ||
40 | #define ADAV80X_ADC_L_VOL 0x70 | ||
41 | #define ADAV80X_ADC_R_VOL 0x71 | ||
42 | #define ADAV80X_PLL_CTRL1 0x74 | ||
43 | #define ADAV80X_PLL_CTRL2 0x75 | ||
44 | #define ADAV80X_ICLK_CTRL1 0x76 | ||
45 | #define ADAV80X_ICLK_CTRL2 0x77 | ||
46 | #define ADAV80X_PLL_CLK_SRC 0x78 | ||
47 | #define ADAV80X_PLL_OUTE 0x7a | ||
48 | |||
49 | #define ADAV80X_PLL_CLK_SRC_PLL_XIN(pll) 0x00 | ||
50 | #define ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll) (0x40 << (pll)) | ||
51 | #define ADAV80X_PLL_CLK_SRC_PLL_MASK(pll) (0x40 << (pll)) | ||
52 | |||
53 | #define ADAV80X_ICLK_CTRL1_DAC_SRC(src) ((src) << 5) | ||
54 | #define ADAV80X_ICLK_CTRL1_ADC_SRC(src) ((src) << 2) | ||
55 | #define ADAV80X_ICLK_CTRL1_ICLK2_SRC(src) (src) | ||
56 | #define ADAV80X_ICLK_CTRL2_ICLK1_SRC(src) ((src) << 3) | ||
57 | |||
58 | #define ADAV80X_PLL_CTRL1_PLLDIV 0x10 | ||
59 | #define ADAV80X_PLL_CTRL1_PLLPD(pll) (0x04 << (pll)) | ||
60 | #define ADAV80X_PLL_CTRL1_XTLPD 0x02 | ||
61 | |||
62 | #define ADAV80X_PLL_CTRL2_FIELD(pll, x) ((x) << ((pll) * 4)) | ||
63 | |||
64 | #define ADAV80X_PLL_CTRL2_FS_48(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x00) | ||
65 | #define ADAV80X_PLL_CTRL2_FS_32(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x08) | ||
66 | #define ADAV80X_PLL_CTRL2_FS_44(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0c) | ||
67 | |||
68 | #define ADAV80X_PLL_CTRL2_SEL(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x02) | ||
69 | #define ADAV80X_PLL_CTRL2_DOUB(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x01) | ||
70 | #define ADAV80X_PLL_CTRL2_PLL_MASK(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0f) | ||
71 | |||
72 | #define ADAV80X_ADC_CTRL1_MODULATOR_MASK 0x80 | ||
73 | #define ADAV80X_ADC_CTRL1_MODULATOR_128FS 0x00 | ||
74 | #define ADAV80X_ADC_CTRL1_MODULATOR_64FS 0x80 | ||
75 | |||
76 | #define ADAV80X_DAC_CTRL1_PD 0x80 | ||
77 | |||
78 | #define ADAV80X_DAC_CTRL2_DIV1 0x00 | ||
79 | #define ADAV80X_DAC_CTRL2_DIV1_5 0x10 | ||
80 | #define ADAV80X_DAC_CTRL2_DIV2 0x20 | ||
81 | #define ADAV80X_DAC_CTRL2_DIV3 0x30 | ||
82 | #define ADAV80X_DAC_CTRL2_DIV_MASK 0x30 | ||
83 | |||
84 | #define ADAV80X_DAC_CTRL2_INTERPOL_256FS 0x00 | ||
85 | #define ADAV80X_DAC_CTRL2_INTERPOL_128FS 0x40 | ||
86 | #define ADAV80X_DAC_CTRL2_INTERPOL_64FS 0x80 | ||
87 | #define ADAV80X_DAC_CTRL2_INTERPOL_MASK 0xc0 | ||
88 | |||
89 | #define ADAV80X_DAC_CTRL2_DEEMPH_NONE 0x00 | ||
90 | #define ADAV80X_DAC_CTRL2_DEEMPH_44 0x01 | ||
91 | #define ADAV80X_DAC_CTRL2_DEEMPH_32 0x02 | ||
92 | #define ADAV80X_DAC_CTRL2_DEEMPH_48 0x03 | ||
93 | #define ADAV80X_DAC_CTRL2_DEEMPH_MASK 0x01 | ||
94 | |||
95 | #define ADAV80X_CAPTURE_MODE_MASTER 0x20 | ||
96 | #define ADAV80X_CAPTURE_WORD_LEN24 0x00 | ||
97 | #define ADAV80X_CAPTURE_WORD_LEN20 0x04 | ||
98 | #define ADAV80X_CAPTRUE_WORD_LEN18 0x08 | ||
99 | #define ADAV80X_CAPTURE_WORD_LEN16 0x0c | ||
100 | #define ADAV80X_CAPTURE_WORD_LEN_MASK 0x0c | ||
101 | |||
102 | #define ADAV80X_CAPTURE_MODE_LEFT_J 0x00 | ||
103 | #define ADAV80X_CAPTURE_MODE_I2S 0x01 | ||
104 | #define ADAV80X_CAPTURE_MODE_RIGHT_J 0x03 | ||
105 | #define ADAV80X_CAPTURE_MODE_MASK 0x03 | ||
106 | |||
107 | #define ADAV80X_PLAYBACK_MODE_MASTER 0x10 | ||
108 | #define ADAV80X_PLAYBACK_MODE_LEFT_J 0x00 | ||
109 | #define ADAV80X_PLAYBACK_MODE_I2S 0x01 | ||
110 | #define ADAV80X_PLAYBACK_MODE_RIGHT_J_24 0x04 | ||
111 | #define ADAV80X_PLAYBACK_MODE_RIGHT_J_20 0x05 | ||
112 | #define ADAV80X_PLAYBACK_MODE_RIGHT_J_18 0x06 | ||
113 | #define ADAV80X_PLAYBACK_MODE_RIGHT_J_16 0x07 | ||
114 | #define ADAV80X_PLAYBACK_MODE_MASK 0x07 | ||
115 | |||
116 | #define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) | ||
117 | |||
118 | static u8 adav80x_default_regs[] = { | ||
119 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00, | ||
120 | 0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
121 | 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37, | ||
122 | 0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b, | ||
123 | 0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00, | ||
124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, | ||
126 | 0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee, | ||
127 | 0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f, | ||
128 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, | ||
129 | 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, | ||
130 | }; | ||
131 | |||
132 | struct adav80x { | ||
133 | enum snd_soc_control_type control_type; | ||
134 | |||
135 | enum adav80x_clk_src clk_src; | ||
136 | unsigned int sysclk; | ||
137 | enum adav80x_pll_src pll_src; | ||
138 | |||
139 | unsigned int dai_fmt[2]; | ||
140 | unsigned int rate; | ||
141 | bool deemph; | ||
142 | bool sysclk_pd[3]; | ||
143 | }; | ||
144 | |||
145 | static const char *adav80x_mux_text[] = { | ||
146 | "ADC", | ||
147 | "Playback", | ||
148 | "Aux Playback", | ||
149 | }; | ||
150 | |||
151 | static const unsigned int adav80x_mux_values[] = { | ||
152 | 0, 2, 3, | ||
153 | }; | ||
154 | |||
155 | #define ADAV80X_MUX_ENUM_DECL(name, reg, shift) \ | ||
156 | SOC_VALUE_ENUM_DOUBLE_DECL(name, reg, shift, 7, \ | ||
157 | ARRAY_SIZE(adav80x_mux_text), adav80x_mux_text, \ | ||
158 | adav80x_mux_values) | ||
159 | |||
160 | static ADAV80X_MUX_ENUM_DECL(adav80x_aux_capture_enum, ADAV80X_DPATH_CTRL1, 0); | ||
161 | static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3); | ||
162 | static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3); | ||
163 | |||
164 | static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl = | ||
165 | SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum); | ||
166 | static const struct snd_kcontrol_new adav80x_capture_mux_ctrl = | ||
167 | SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum); | ||
168 | static const struct snd_kcontrol_new adav80x_dac_mux_ctrl = | ||
169 | SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum); | ||
170 | |||
171 | #define ADAV80X_MUX(name, ctrl) \ | ||
172 | SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) | ||
173 | |||
174 | static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { | ||
175 | SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1), | ||
176 | SND_SOC_DAPM_ADC("ADC", NULL, ADAV80X_ADC_CTRL1, 5, 1), | ||
177 | |||
178 | SND_SOC_DAPM_PGA("Right PGA", ADAV80X_ADC_CTRL1, 0, 1, NULL, 0), | ||
179 | SND_SOC_DAPM_PGA("Left PGA", ADAV80X_ADC_CTRL1, 1, 1, NULL, 0), | ||
180 | |||
181 | SND_SOC_DAPM_AIF_OUT("AIFOUT", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), | ||
182 | SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), | ||
183 | |||
184 | SND_SOC_DAPM_AIF_OUT("AIFAUXOUT", "Aux Capture", 0, SND_SOC_NOPM, 0, 0), | ||
185 | SND_SOC_DAPM_AIF_IN("AIFAUXIN", "Aux Playback", 0, SND_SOC_NOPM, 0, 0), | ||
186 | |||
187 | ADAV80X_MUX("Aux Capture Select", &adav80x_aux_capture_mux_ctrl), | ||
188 | ADAV80X_MUX("Capture Select", &adav80x_capture_mux_ctrl), | ||
189 | ADAV80X_MUX("DAC Select", &adav80x_dac_mux_ctrl), | ||
190 | |||
191 | SND_SOC_DAPM_INPUT("VINR"), | ||
192 | SND_SOC_DAPM_INPUT("VINL"), | ||
193 | SND_SOC_DAPM_OUTPUT("VOUTR"), | ||
194 | SND_SOC_DAPM_OUTPUT("VOUTL"), | ||
195 | |||
196 | SND_SOC_DAPM_SUPPLY("SYSCLK", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
197 | SND_SOC_DAPM_SUPPLY("PLL1", ADAV80X_PLL_CTRL1, 2, 1, NULL, 0), | ||
198 | SND_SOC_DAPM_SUPPLY("PLL2", ADAV80X_PLL_CTRL1, 3, 1, NULL, 0), | ||
199 | SND_SOC_DAPM_SUPPLY("OSC", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0), | ||
200 | }; | ||
201 | |||
202 | static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, | ||
203 | struct snd_soc_dapm_widget *sink) | ||
204 | { | ||
205 | struct snd_soc_codec *codec = source->codec; | ||
206 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
207 | const char *clk; | ||
208 | |||
209 | switch (adav80x->clk_src) { | ||
210 | case ADAV80X_CLK_PLL1: | ||
211 | clk = "PLL1"; | ||
212 | break; | ||
213 | case ADAV80X_CLK_PLL2: | ||
214 | clk = "PLL2"; | ||
215 | break; | ||
216 | case ADAV80X_CLK_XTAL: | ||
217 | clk = "OSC"; | ||
218 | break; | ||
219 | default: | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | return strcmp(source->name, clk) == 0; | ||
224 | } | ||
225 | |||
226 | static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, | ||
227 | struct snd_soc_dapm_widget *sink) | ||
228 | { | ||
229 | struct snd_soc_codec *codec = source->codec; | ||
230 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
231 | |||
232 | return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; | ||
233 | } | ||
234 | |||
235 | |||
236 | static const struct snd_soc_dapm_route adav80x_dapm_routes[] = { | ||
237 | { "DAC Select", "ADC", "ADC" }, | ||
238 | { "DAC Select", "Playback", "AIFIN" }, | ||
239 | { "DAC Select", "Aux Playback", "AIFAUXIN" }, | ||
240 | { "DAC", NULL, "DAC Select" }, | ||
241 | |||
242 | { "Capture Select", "ADC", "ADC" }, | ||
243 | { "Capture Select", "Playback", "AIFIN" }, | ||
244 | { "Capture Select", "Aux Playback", "AIFAUXIN" }, | ||
245 | { "AIFOUT", NULL, "Capture Select" }, | ||
246 | |||
247 | { "Aux Capture Select", "ADC", "ADC" }, | ||
248 | { "Aux Capture Select", "Playback", "AIFIN" }, | ||
249 | { "Aux Capture Select", "Aux Playback", "AIFAUXIN" }, | ||
250 | { "AIFAUXOUT", NULL, "Aux Capture Select" }, | ||
251 | |||
252 | { "VOUTR", NULL, "DAC" }, | ||
253 | { "VOUTL", NULL, "DAC" }, | ||
254 | |||
255 | { "Left PGA", NULL, "VINL" }, | ||
256 | { "Right PGA", NULL, "VINR" }, | ||
257 | { "ADC", NULL, "Left PGA" }, | ||
258 | { "ADC", NULL, "Right PGA" }, | ||
259 | |||
260 | { "SYSCLK", NULL, "PLL1", adav80x_dapm_sysclk_check }, | ||
261 | { "SYSCLK", NULL, "PLL2", adav80x_dapm_sysclk_check }, | ||
262 | { "SYSCLK", NULL, "OSC", adav80x_dapm_sysclk_check }, | ||
263 | { "PLL1", NULL, "OSC", adav80x_dapm_pll_check }, | ||
264 | { "PLL2", NULL, "OSC", adav80x_dapm_pll_check }, | ||
265 | |||
266 | { "ADC", NULL, "SYSCLK" }, | ||
267 | { "DAC", NULL, "SYSCLK" }, | ||
268 | { "AIFOUT", NULL, "SYSCLK" }, | ||
269 | { "AIFAUXOUT", NULL, "SYSCLK" }, | ||
270 | { "AIFIN", NULL, "SYSCLK" }, | ||
271 | { "AIFAUXIN", NULL, "SYSCLK" }, | ||
272 | }; | ||
273 | |||
274 | static int adav80x_set_deemph(struct snd_soc_codec *codec) | ||
275 | { | ||
276 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
277 | unsigned int val; | ||
278 | |||
279 | if (adav80x->deemph) { | ||
280 | switch (adav80x->rate) { | ||
281 | case 32000: | ||
282 | val = ADAV80X_DAC_CTRL2_DEEMPH_32; | ||
283 | break; | ||
284 | case 44100: | ||
285 | val = ADAV80X_DAC_CTRL2_DEEMPH_44; | ||
286 | break; | ||
287 | case 48000: | ||
288 | case 64000: | ||
289 | case 88200: | ||
290 | case 96000: | ||
291 | val = ADAV80X_DAC_CTRL2_DEEMPH_48; | ||
292 | break; | ||
293 | default: | ||
294 | val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; | ||
295 | break; | ||
296 | } | ||
297 | } else { | ||
298 | val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; | ||
299 | } | ||
300 | |||
301 | return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, | ||
302 | ADAV80X_DAC_CTRL2_DEEMPH_MASK, val); | ||
303 | } | ||
304 | |||
305 | static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, | ||
306 | struct snd_ctl_elem_value *ucontrol) | ||
307 | { | ||
308 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
309 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
310 | unsigned int deemph = ucontrol->value.enumerated.item[0]; | ||
311 | |||
312 | if (deemph > 1) | ||
313 | return -EINVAL; | ||
314 | |||
315 | adav80x->deemph = deemph; | ||
316 | |||
317 | return adav80x_set_deemph(codec); | ||
318 | } | ||
319 | |||
320 | static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, | ||
321 | struct snd_ctl_elem_value *ucontrol) | ||
322 | { | ||
323 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
324 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
325 | |||
326 | ucontrol->value.enumerated.item[0] = adav80x->deemph; | ||
327 | return 0; | ||
328 | }; | ||
329 | |||
330 | static const DECLARE_TLV_DB_SCALE(adav80x_inpga_tlv, 0, 50, 0); | ||
331 | static const DECLARE_TLV_DB_MINMAX(adav80x_digital_tlv, -9563, 0); | ||
332 | |||
333 | static const struct snd_kcontrol_new adav80x_controls[] = { | ||
334 | SOC_DOUBLE_R_TLV("Master Playback Volume", ADAV80X_DAC_L_VOL, | ||
335 | ADAV80X_DAC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), | ||
336 | SOC_DOUBLE_R_TLV("Master Capture Volume", ADAV80X_ADC_L_VOL, | ||
337 | ADAV80X_ADC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), | ||
338 | |||
339 | SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAV80X_PGA_L_VOL, | ||
340 | ADAV80X_PGA_R_VOL, 0, 0x30, 0, adav80x_inpga_tlv), | ||
341 | |||
342 | SOC_DOUBLE("Master Playback Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 0), | ||
343 | SOC_DOUBLE("Master Capture Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1), | ||
344 | |||
345 | SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0), | ||
346 | |||
347 | SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0, | ||
348 | adav80x_get_deemph, adav80x_put_deemph), | ||
349 | }; | ||
350 | |||
351 | static unsigned int adav80x_port_ctrl_regs[2][2] = { | ||
352 | { ADAV80X_REC_CTRL, ADAV80X_PLAYBACK_CTRL, }, | ||
353 | { ADAV80X_AUX_OUT_CTRL, ADAV80X_AUX_IN_CTRL }, | ||
354 | }; | ||
355 | |||
356 | static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
357 | { | ||
358 | struct snd_soc_codec *codec = dai->codec; | ||
359 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
360 | unsigned int capture = 0x00; | ||
361 | unsigned int playback = 0x00; | ||
362 | |||
363 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
364 | case SND_SOC_DAIFMT_CBM_CFM: | ||
365 | capture |= ADAV80X_CAPTURE_MODE_MASTER; | ||
366 | playback |= ADAV80X_PLAYBACK_MODE_MASTER; | ||
367 | case SND_SOC_DAIFMT_CBS_CFS: | ||
368 | break; | ||
369 | default: | ||
370 | return -EINVAL; | ||
371 | } | ||
372 | |||
373 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
374 | case SND_SOC_DAIFMT_I2S: | ||
375 | capture |= ADAV80X_CAPTURE_MODE_I2S; | ||
376 | playback |= ADAV80X_PLAYBACK_MODE_I2S; | ||
377 | break; | ||
378 | case SND_SOC_DAIFMT_LEFT_J: | ||
379 | capture |= ADAV80X_CAPTURE_MODE_LEFT_J; | ||
380 | playback |= ADAV80X_PLAYBACK_MODE_LEFT_J; | ||
381 | break; | ||
382 | case SND_SOC_DAIFMT_RIGHT_J: | ||
383 | capture |= ADAV80X_CAPTURE_MODE_RIGHT_J; | ||
384 | playback |= ADAV80X_PLAYBACK_MODE_RIGHT_J_24; | ||
385 | break; | ||
386 | default: | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | |||
390 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
391 | case SND_SOC_DAIFMT_NB_NF: | ||
392 | break; | ||
393 | default: | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], | ||
398 | ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER, | ||
399 | capture); | ||
400 | snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback); | ||
401 | |||
402 | adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int adav80x_set_adc_clock(struct snd_soc_codec *codec, | ||
408 | unsigned int sample_rate) | ||
409 | { | ||
410 | unsigned int val; | ||
411 | |||
412 | if (sample_rate <= 48000) | ||
413 | val = ADAV80X_ADC_CTRL1_MODULATOR_128FS; | ||
414 | else | ||
415 | val = ADAV80X_ADC_CTRL1_MODULATOR_64FS; | ||
416 | |||
417 | snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1, | ||
418 | ADAV80X_ADC_CTRL1_MODULATOR_MASK, val); | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int adav80x_set_dac_clock(struct snd_soc_codec *codec, | ||
424 | unsigned int sample_rate) | ||
425 | { | ||
426 | unsigned int val; | ||
427 | |||
428 | if (sample_rate <= 48000) | ||
429 | val = ADAV80X_DAC_CTRL2_DIV1 | ADAV80X_DAC_CTRL2_INTERPOL_256FS; | ||
430 | else | ||
431 | val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS; | ||
432 | |||
433 | snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, | ||
434 | ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK, | ||
435 | val); | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, | ||
441 | struct snd_soc_dai *dai, snd_pcm_format_t format) | ||
442 | { | ||
443 | unsigned int val; | ||
444 | |||
445 | switch (format) { | ||
446 | case SNDRV_PCM_FORMAT_S16_LE: | ||
447 | val = ADAV80X_CAPTURE_WORD_LEN16; | ||
448 | break; | ||
449 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
450 | val = ADAV80X_CAPTRUE_WORD_LEN18; | ||
451 | break; | ||
452 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
453 | val = ADAV80X_CAPTURE_WORD_LEN20; | ||
454 | break; | ||
455 | case SNDRV_PCM_FORMAT_S24_LE: | ||
456 | val = ADAV80X_CAPTURE_WORD_LEN24; | ||
457 | break; | ||
458 | default: | ||
459 | break; | ||
460 | } | ||
461 | |||
462 | snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], | ||
463 | ADAV80X_CAPTURE_WORD_LEN_MASK, val); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec, | ||
469 | struct snd_soc_dai *dai, snd_pcm_format_t format) | ||
470 | { | ||
471 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
472 | unsigned int val; | ||
473 | |||
474 | if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J) | ||
475 | return 0; | ||
476 | |||
477 | switch (format) { | ||
478 | case SNDRV_PCM_FORMAT_S16_LE: | ||
479 | val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16; | ||
480 | break; | ||
481 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
482 | val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18; | ||
483 | break; | ||
484 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
485 | val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20; | ||
486 | break; | ||
487 | case SNDRV_PCM_FORMAT_S24_LE: | ||
488 | val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24; | ||
489 | break; | ||
490 | default: | ||
491 | break; | ||
492 | } | ||
493 | |||
494 | snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1], | ||
495 | ADAV80X_PLAYBACK_MODE_MASK, val); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int adav80x_hw_params(struct snd_pcm_substream *substream, | ||
501 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
502 | { | ||
503 | struct snd_soc_codec *codec = dai->codec; | ||
504 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
505 | unsigned int rate = params_rate(params); | ||
506 | |||
507 | if (rate * 256 != adav80x->sysclk) | ||
508 | return -EINVAL; | ||
509 | |||
510 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
511 | adav80x_set_playback_pcm_format(codec, dai, | ||
512 | params_format(params)); | ||
513 | adav80x_set_dac_clock(codec, rate); | ||
514 | } else { | ||
515 | adav80x_set_capture_pcm_format(codec, dai, | ||
516 | params_format(params)); | ||
517 | adav80x_set_adc_clock(codec, rate); | ||
518 | } | ||
519 | adav80x->rate = rate; | ||
520 | adav80x_set_deemph(codec); | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int adav80x_set_sysclk(struct snd_soc_codec *codec, | ||
526 | int clk_id, unsigned int freq, int dir) | ||
527 | { | ||
528 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
529 | |||
530 | if (dir == SND_SOC_CLOCK_IN) { | ||
531 | switch (clk_id) { | ||
532 | case ADAV80X_CLK_XIN: | ||
533 | case ADAV80X_CLK_XTAL: | ||
534 | case ADAV80X_CLK_MCLKI: | ||
535 | case ADAV80X_CLK_PLL1: | ||
536 | case ADAV80X_CLK_PLL2: | ||
537 | break; | ||
538 | default: | ||
539 | return -EINVAL; | ||
540 | } | ||
541 | |||
542 | adav80x->sysclk = freq; | ||
543 | |||
544 | if (adav80x->clk_src != clk_id) { | ||
545 | unsigned int iclk_ctrl1, iclk_ctrl2; | ||
546 | |||
547 | adav80x->clk_src = clk_id; | ||
548 | if (clk_id == ADAV80X_CLK_XTAL) | ||
549 | clk_id = ADAV80X_CLK_XIN; | ||
550 | |||
551 | iclk_ctrl1 = ADAV80X_ICLK_CTRL1_DAC_SRC(clk_id) | | ||
552 | ADAV80X_ICLK_CTRL1_ADC_SRC(clk_id) | | ||
553 | ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id); | ||
554 | iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id); | ||
555 | |||
556 | snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1); | ||
557 | snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2); | ||
558 | |||
559 | snd_soc_dapm_sync(&codec->dapm); | ||
560 | } | ||
561 | } else { | ||
562 | unsigned int mask; | ||
563 | |||
564 | switch (clk_id) { | ||
565 | case ADAV80X_CLK_SYSCLK1: | ||
566 | case ADAV80X_CLK_SYSCLK2: | ||
567 | case ADAV80X_CLK_SYSCLK3: | ||
568 | break; | ||
569 | default: | ||
570 | return -EINVAL; | ||
571 | } | ||
572 | |||
573 | clk_id -= ADAV80X_CLK_SYSCLK1; | ||
574 | mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id); | ||
575 | |||
576 | if (freq == 0) { | ||
577 | snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask); | ||
578 | adav80x->sysclk_pd[clk_id] = true; | ||
579 | } else { | ||
580 | snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0); | ||
581 | adav80x->sysclk_pd[clk_id] = false; | ||
582 | } | ||
583 | |||
584 | if (adav80x->sysclk_pd[0]) | ||
585 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); | ||
586 | else | ||
587 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | ||
588 | |||
589 | if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) | ||
590 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL2"); | ||
591 | else | ||
592 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); | ||
593 | |||
594 | snd_soc_dapm_sync(&codec->dapm); | ||
595 | } | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, | ||
601 | int source, unsigned int freq_in, unsigned int freq_out) | ||
602 | { | ||
603 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
604 | unsigned int pll_ctrl1 = 0; | ||
605 | unsigned int pll_ctrl2 = 0; | ||
606 | unsigned int pll_src; | ||
607 | |||
608 | switch (source) { | ||
609 | case ADAV80X_PLL_SRC_XTAL: | ||
610 | case ADAV80X_PLL_SRC_XIN: | ||
611 | case ADAV80X_PLL_SRC_MCLKI: | ||
612 | break; | ||
613 | default: | ||
614 | return -EINVAL; | ||
615 | } | ||
616 | |||
617 | if (!freq_out) | ||
618 | return 0; | ||
619 | |||
620 | switch (freq_in) { | ||
621 | case 27000000: | ||
622 | break; | ||
623 | case 54000000: | ||
624 | if (source == ADAV80X_PLL_SRC_XIN) { | ||
625 | pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV; | ||
626 | break; | ||
627 | } | ||
628 | default: | ||
629 | return -EINVAL; | ||
630 | } | ||
631 | |||
632 | if (freq_out > 12288000) { | ||
633 | pll_ctrl2 |= ADAV80X_PLL_CTRL2_DOUB(pll_id); | ||
634 | freq_out /= 2; | ||
635 | } | ||
636 | |||
637 | /* freq_out = sample_rate * 256 */ | ||
638 | switch (freq_out) { | ||
639 | case 8192000: | ||
640 | pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_32(pll_id); | ||
641 | break; | ||
642 | case 11289600: | ||
643 | pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_44(pll_id); | ||
644 | break; | ||
645 | case 12288000: | ||
646 | pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_48(pll_id); | ||
647 | break; | ||
648 | default: | ||
649 | return -EINVAL; | ||
650 | } | ||
651 | |||
652 | snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV, | ||
653 | pll_ctrl1); | ||
654 | snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2, | ||
655 | ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2); | ||
656 | |||
657 | if (source != adav80x->pll_src) { | ||
658 | if (source == ADAV80X_PLL_SRC_MCLKI) | ||
659 | pll_src = ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll_id); | ||
660 | else | ||
661 | pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id); | ||
662 | |||
663 | snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC, | ||
664 | ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src); | ||
665 | |||
666 | adav80x->pll_src = source; | ||
667 | |||
668 | snd_soc_dapm_sync(&codec->dapm); | ||
669 | } | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | static int adav80x_set_bias_level(struct snd_soc_codec *codec, | ||
675 | enum snd_soc_bias_level level) | ||
676 | { | ||
677 | unsigned int mask = ADAV80X_DAC_CTRL1_PD; | ||
678 | |||
679 | switch (level) { | ||
680 | case SND_SOC_BIAS_ON: | ||
681 | break; | ||
682 | case SND_SOC_BIAS_PREPARE: | ||
683 | break; | ||
684 | case SND_SOC_BIAS_STANDBY: | ||
685 | snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00); | ||
686 | break; | ||
687 | case SND_SOC_BIAS_OFF: | ||
688 | snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask); | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | codec->dapm.bias_level = level; | ||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | /* Enforce the same sample rate on all audio interfaces */ | ||
697 | static int adav80x_dai_startup(struct snd_pcm_substream *substream, | ||
698 | struct snd_soc_dai *dai) | ||
699 | { | ||
700 | struct snd_soc_codec *codec = dai->codec; | ||
701 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
702 | |||
703 | if (!codec->active || !adav80x->rate) | ||
704 | return 0; | ||
705 | |||
706 | return snd_pcm_hw_constraint_minmax(substream->runtime, | ||
707 | SNDRV_PCM_HW_PARAM_RATE, adav80x->rate, adav80x->rate); | ||
708 | } | ||
709 | |||
710 | static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, | ||
711 | struct snd_soc_dai *dai) | ||
712 | { | ||
713 | struct snd_soc_codec *codec = dai->codec; | ||
714 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
715 | |||
716 | if (!codec->active) | ||
717 | adav80x->rate = 0; | ||
718 | } | ||
719 | |||
720 | static const struct snd_soc_dai_ops adav80x_dai_ops = { | ||
721 | .set_fmt = adav80x_set_dai_fmt, | ||
722 | .hw_params = adav80x_hw_params, | ||
723 | .startup = adav80x_dai_startup, | ||
724 | .shutdown = adav80x_dai_shutdown, | ||
725 | }; | ||
726 | |||
727 | #define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
728 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | \ | ||
729 | SNDRV_PCM_RATE_96000) | ||
730 | |||
731 | #define ADAV80X_CAPTURE_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | ||
732 | |||
733 | #define ADAV80X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ | ||
734 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
735 | |||
736 | static struct snd_soc_dai_driver adav80x_dais[] = { | ||
737 | { | ||
738 | .name = "adav80x-hifi", | ||
739 | .id = 0, | ||
740 | .playback = { | ||
741 | .stream_name = "HiFi Playback", | ||
742 | .channels_min = 2, | ||
743 | .channels_max = 2, | ||
744 | .rates = ADAV80X_PLAYBACK_RATES, | ||
745 | .formats = ADAV80X_FORMATS, | ||
746 | }, | ||
747 | .capture = { | ||
748 | .stream_name = "HiFi Capture", | ||
749 | .channels_min = 2, | ||
750 | .channels_max = 2, | ||
751 | .rates = ADAV80X_CAPTURE_RATES, | ||
752 | .formats = ADAV80X_FORMATS, | ||
753 | }, | ||
754 | .ops = &adav80x_dai_ops, | ||
755 | }, | ||
756 | { | ||
757 | .name = "adav80x-aux", | ||
758 | .id = 1, | ||
759 | .playback = { | ||
760 | .stream_name = "Aux Playback", | ||
761 | .channels_min = 2, | ||
762 | .channels_max = 2, | ||
763 | .rates = ADAV80X_PLAYBACK_RATES, | ||
764 | .formats = ADAV80X_FORMATS, | ||
765 | }, | ||
766 | .capture = { | ||
767 | .stream_name = "Aux Capture", | ||
768 | .channels_min = 2, | ||
769 | .channels_max = 2, | ||
770 | .rates = ADAV80X_CAPTURE_RATES, | ||
771 | .formats = ADAV80X_FORMATS, | ||
772 | }, | ||
773 | .ops = &adav80x_dai_ops, | ||
774 | }, | ||
775 | }; | ||
776 | |||
777 | static int adav80x_probe(struct snd_soc_codec *codec) | ||
778 | { | ||
779 | int ret; | ||
780 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
781 | |||
782 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type); | ||
783 | if (ret) { | ||
784 | dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); | ||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | /* Force PLLs on for SYSCLK output */ | ||
789 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | ||
790 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); | ||
791 | |||
792 | /* Power down S/PDIF receiver, since it is currently not supported */ | ||
793 | snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20); | ||
794 | /* Disable DAC zero flag */ | ||
795 | snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6); | ||
796 | |||
797 | return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
798 | } | ||
799 | |||
800 | static int adav80x_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
801 | { | ||
802 | return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
803 | } | ||
804 | |||
805 | static int adav80x_resume(struct snd_soc_codec *codec) | ||
806 | { | ||
807 | adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
808 | codec->cache_sync = 1; | ||
809 | snd_soc_cache_sync(codec); | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int adav80x_remove(struct snd_soc_codec *codec) | ||
815 | { | ||
816 | return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
817 | } | ||
818 | |||
819 | static struct snd_soc_codec_driver adav80x_codec_driver = { | ||
820 | .probe = adav80x_probe, | ||
821 | .remove = adav80x_remove, | ||
822 | .suspend = adav80x_suspend, | ||
823 | .resume = adav80x_resume, | ||
824 | .set_bias_level = adav80x_set_bias_level, | ||
825 | |||
826 | .set_pll = adav80x_set_pll, | ||
827 | .set_sysclk = adav80x_set_sysclk, | ||
828 | |||
829 | .reg_word_size = sizeof(u8), | ||
830 | .reg_cache_size = ARRAY_SIZE(adav80x_default_regs), | ||
831 | .reg_cache_default = adav80x_default_regs, | ||
832 | |||
833 | .controls = adav80x_controls, | ||
834 | .num_controls = ARRAY_SIZE(adav80x_controls), | ||
835 | .dapm_widgets = adav80x_dapm_widgets, | ||
836 | .num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets), | ||
837 | .dapm_routes = adav80x_dapm_routes, | ||
838 | .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), | ||
839 | }; | ||
840 | |||
841 | static int __devinit adav80x_bus_probe(struct device *dev, | ||
842 | enum snd_soc_control_type control_type) | ||
843 | { | ||
844 | struct adav80x *adav80x; | ||
845 | int ret; | ||
846 | |||
847 | adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); | ||
848 | if (!adav80x) | ||
849 | return -ENOMEM; | ||
850 | |||
851 | dev_set_drvdata(dev, adav80x); | ||
852 | adav80x->control_type = control_type; | ||
853 | |||
854 | ret = snd_soc_register_codec(dev, &adav80x_codec_driver, | ||
855 | adav80x_dais, ARRAY_SIZE(adav80x_dais)); | ||
856 | if (ret) | ||
857 | kfree(adav80x); | ||
858 | |||
859 | return ret; | ||
860 | } | ||
861 | |||
862 | static int __devexit adav80x_bus_remove(struct device *dev) | ||
863 | { | ||
864 | snd_soc_unregister_codec(dev); | ||
865 | kfree(dev_get_drvdata(dev)); | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | #if defined(CONFIG_SPI_MASTER) | ||
870 | static int __devinit adav80x_spi_probe(struct spi_device *spi) | ||
871 | { | ||
872 | return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); | ||
873 | } | ||
874 | |||
875 | static int __devexit adav80x_spi_remove(struct spi_device *spi) | ||
876 | { | ||
877 | return adav80x_bus_remove(&spi->dev); | ||
878 | } | ||
879 | |||
880 | static struct spi_driver adav80x_spi_driver = { | ||
881 | .driver = { | ||
882 | .name = "adav801", | ||
883 | .owner = THIS_MODULE, | ||
884 | }, | ||
885 | .probe = adav80x_spi_probe, | ||
886 | .remove = __devexit_p(adav80x_spi_remove), | ||
887 | }; | ||
888 | #endif | ||
889 | |||
890 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
891 | static const struct i2c_device_id adav80x_id[] = { | ||
892 | { "adav803", 0 }, | ||
893 | { } | ||
894 | }; | ||
895 | MODULE_DEVICE_TABLE(i2c, adav80x_id); | ||
896 | |||
897 | static int __devinit adav80x_i2c_probe(struct i2c_client *client, | ||
898 | const struct i2c_device_id *id) | ||
899 | { | ||
900 | return adav80x_bus_probe(&client->dev, SND_SOC_I2C); | ||
901 | } | ||
902 | |||
903 | static int __devexit adav80x_i2c_remove(struct i2c_client *client) | ||
904 | { | ||
905 | return adav80x_bus_remove(&client->dev); | ||
906 | } | ||
907 | |||
908 | static struct i2c_driver adav80x_i2c_driver = { | ||
909 | .driver = { | ||
910 | .name = "adav803", | ||
911 | .owner = THIS_MODULE, | ||
912 | }, | ||
913 | .probe = adav80x_i2c_probe, | ||
914 | .remove = __devexit_p(adav80x_i2c_remove), | ||
915 | .id_table = adav80x_id, | ||
916 | }; | ||
917 | #endif | ||
918 | |||
919 | static int __init adav80x_init(void) | ||
920 | { | ||
921 | int ret = 0; | ||
922 | |||
923 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
924 | ret = i2c_add_driver(&adav80x_i2c_driver); | ||
925 | if (ret) | ||
926 | return ret; | ||
927 | #endif | ||
928 | |||
929 | #if defined(CONFIG_SPI_MASTER) | ||
930 | ret = spi_register_driver(&adav80x_spi_driver); | ||
931 | #endif | ||
932 | |||
933 | return ret; | ||
934 | } | ||
935 | module_init(adav80x_init); | ||
936 | |||
937 | static void __exit adav80x_exit(void) | ||
938 | { | ||
939 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
940 | i2c_del_driver(&adav80x_i2c_driver); | ||
941 | #endif | ||
942 | #if defined(CONFIG_SPI_MASTER) | ||
943 | spi_unregister_driver(&adav80x_spi_driver); | ||
944 | #endif | ||
945 | } | ||
946 | module_exit(adav80x_exit); | ||
947 | |||
948 | MODULE_DESCRIPTION("ASoC ADAV80x driver"); | ||
949 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
950 | MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); | ||
951 | MODULE_LICENSE("GPL"); | ||