diff options
Diffstat (limited to 'sound/soc/codecs/cs4271.c')
-rw-r--r-- | sound/soc/codecs/cs4271.c | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c new file mode 100644 index 000000000000..083aab96ca80 --- /dev/null +++ b/sound/soc/codecs/cs4271.c | |||
@@ -0,0 +1,667 @@ | |||
1 | /* | ||
2 | * CS4271 ASoC codec driver | ||
3 | * | ||
4 | * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version 2 | ||
9 | * of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * This driver support CS4271 codec being master or slave, working | ||
17 | * in control port mode, connected either via SPI or I2C. | ||
18 | * The data format accepted is I2S or left-justified. | ||
19 | * DAPM support not implemented. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/tlv.h> | ||
28 | #include <linux/gpio.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/spi/spi.h> | ||
31 | #include <sound/cs4271.h> | ||
32 | |||
33 | #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
34 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
35 | SNDRV_PCM_FMTBIT_S32_LE) | ||
36 | #define CS4271_PCM_RATES SNDRV_PCM_RATE_8000_192000 | ||
37 | |||
38 | /* | ||
39 | * CS4271 registers | ||
40 | * High byte represents SPI chip address (0x10) + write command (0) | ||
41 | * Low byte - codec register address | ||
42 | */ | ||
43 | #define CS4271_MODE1 0x2001 /* Mode Control 1 */ | ||
44 | #define CS4271_DACCTL 0x2002 /* DAC Control */ | ||
45 | #define CS4271_DACVOL 0x2003 /* DAC Volume & Mixing Control */ | ||
46 | #define CS4271_VOLA 0x2004 /* DAC Channel A Volume Control */ | ||
47 | #define CS4271_VOLB 0x2005 /* DAC Channel B Volume Control */ | ||
48 | #define CS4271_ADCCTL 0x2006 /* ADC Control */ | ||
49 | #define CS4271_MODE2 0x2007 /* Mode Control 2 */ | ||
50 | #define CS4271_CHIPID 0x2008 /* Chip ID */ | ||
51 | |||
52 | #define CS4271_FIRSTREG CS4271_MODE1 | ||
53 | #define CS4271_LASTREG CS4271_MODE2 | ||
54 | #define CS4271_NR_REGS ((CS4271_LASTREG & 0xFF) + 1) | ||
55 | |||
56 | /* Bit masks for the CS4271 registers */ | ||
57 | #define CS4271_MODE1_MODE_MASK 0xC0 | ||
58 | #define CS4271_MODE1_MODE_1X 0x00 | ||
59 | #define CS4271_MODE1_MODE_2X 0x80 | ||
60 | #define CS4271_MODE1_MODE_4X 0xC0 | ||
61 | |||
62 | #define CS4271_MODE1_DIV_MASK 0x30 | ||
63 | #define CS4271_MODE1_DIV_1 0x00 | ||
64 | #define CS4271_MODE1_DIV_15 0x10 | ||
65 | #define CS4271_MODE1_DIV_2 0x20 | ||
66 | #define CS4271_MODE1_DIV_3 0x30 | ||
67 | |||
68 | #define CS4271_MODE1_MASTER 0x08 | ||
69 | |||
70 | #define CS4271_MODE1_DAC_DIF_MASK 0x07 | ||
71 | #define CS4271_MODE1_DAC_DIF_LJ 0x00 | ||
72 | #define CS4271_MODE1_DAC_DIF_I2S 0x01 | ||
73 | #define CS4271_MODE1_DAC_DIF_RJ16 0x02 | ||
74 | #define CS4271_MODE1_DAC_DIF_RJ24 0x03 | ||
75 | #define CS4271_MODE1_DAC_DIF_RJ20 0x04 | ||
76 | #define CS4271_MODE1_DAC_DIF_RJ18 0x05 | ||
77 | |||
78 | #define CS4271_DACCTL_AMUTE 0x80 | ||
79 | #define CS4271_DACCTL_IF_SLOW 0x40 | ||
80 | |||
81 | #define CS4271_DACCTL_DEM_MASK 0x30 | ||
82 | #define CS4271_DACCTL_DEM_DIS 0x00 | ||
83 | #define CS4271_DACCTL_DEM_441 0x10 | ||
84 | #define CS4271_DACCTL_DEM_48 0x20 | ||
85 | #define CS4271_DACCTL_DEM_32 0x30 | ||
86 | |||
87 | #define CS4271_DACCTL_SVRU 0x08 | ||
88 | #define CS4271_DACCTL_SRD 0x04 | ||
89 | #define CS4271_DACCTL_INVA 0x02 | ||
90 | #define CS4271_DACCTL_INVB 0x01 | ||
91 | |||
92 | #define CS4271_DACVOL_BEQUA 0x40 | ||
93 | #define CS4271_DACVOL_SOFT 0x20 | ||
94 | #define CS4271_DACVOL_ZEROC 0x10 | ||
95 | |||
96 | #define CS4271_DACVOL_ATAPI_MASK 0x0F | ||
97 | #define CS4271_DACVOL_ATAPI_M_M 0x00 | ||
98 | #define CS4271_DACVOL_ATAPI_M_BR 0x01 | ||
99 | #define CS4271_DACVOL_ATAPI_M_BL 0x02 | ||
100 | #define CS4271_DACVOL_ATAPI_M_BLR2 0x03 | ||
101 | #define CS4271_DACVOL_ATAPI_AR_M 0x04 | ||
102 | #define CS4271_DACVOL_ATAPI_AR_BR 0x05 | ||
103 | #define CS4271_DACVOL_ATAPI_AR_BL 0x06 | ||
104 | #define CS4271_DACVOL_ATAPI_AR_BLR2 0x07 | ||
105 | #define CS4271_DACVOL_ATAPI_AL_M 0x08 | ||
106 | #define CS4271_DACVOL_ATAPI_AL_BR 0x09 | ||
107 | #define CS4271_DACVOL_ATAPI_AL_BL 0x0A | ||
108 | #define CS4271_DACVOL_ATAPI_AL_BLR2 0x0B | ||
109 | #define CS4271_DACVOL_ATAPI_ALR2_M 0x0C | ||
110 | #define CS4271_DACVOL_ATAPI_ALR2_BR 0x0D | ||
111 | #define CS4271_DACVOL_ATAPI_ALR2_BL 0x0E | ||
112 | #define CS4271_DACVOL_ATAPI_ALR2_BLR2 0x0F | ||
113 | |||
114 | #define CS4271_VOLA_MUTE 0x80 | ||
115 | #define CS4271_VOLA_VOL_MASK 0x7F | ||
116 | #define CS4271_VOLB_MUTE 0x80 | ||
117 | #define CS4271_VOLB_VOL_MASK 0x7F | ||
118 | |||
119 | #define CS4271_ADCCTL_DITHER16 0x20 | ||
120 | |||
121 | #define CS4271_ADCCTL_ADC_DIF_MASK 0x10 | ||
122 | #define CS4271_ADCCTL_ADC_DIF_LJ 0x00 | ||
123 | #define CS4271_ADCCTL_ADC_DIF_I2S 0x10 | ||
124 | |||
125 | #define CS4271_ADCCTL_MUTEA 0x08 | ||
126 | #define CS4271_ADCCTL_MUTEB 0x04 | ||
127 | #define CS4271_ADCCTL_HPFDA 0x02 | ||
128 | #define CS4271_ADCCTL_HPFDB 0x01 | ||
129 | |||
130 | #define CS4271_MODE2_LOOP 0x10 | ||
131 | #define CS4271_MODE2_MUTECAEQUB 0x08 | ||
132 | #define CS4271_MODE2_FREEZE 0x04 | ||
133 | #define CS4271_MODE2_CPEN 0x02 | ||
134 | #define CS4271_MODE2_PDN 0x01 | ||
135 | |||
136 | #define CS4271_CHIPID_PART_MASK 0xF0 | ||
137 | #define CS4271_CHIPID_REV_MASK 0x0F | ||
138 | |||
139 | /* | ||
140 | * Default CS4271 power-up configuration | ||
141 | * Array contains non-existing in hw register at address 0 | ||
142 | * Array do not include Chip ID, as codec driver does not use | ||
143 | * registers read operations at all | ||
144 | */ | ||
145 | static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = { | ||
146 | 0, | ||
147 | 0, | ||
148 | CS4271_DACCTL_AMUTE, | ||
149 | CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, | ||
150 | 0, | ||
151 | 0, | ||
152 | 0, | ||
153 | 0, | ||
154 | }; | ||
155 | |||
156 | struct cs4271_private { | ||
157 | /* SND_SOC_I2C or SND_SOC_SPI */ | ||
158 | enum snd_soc_control_type bus_type; | ||
159 | void *control_data; | ||
160 | unsigned int mclk; | ||
161 | bool master; | ||
162 | bool deemph; | ||
163 | /* Current sample rate for de-emphasis control */ | ||
164 | int rate; | ||
165 | /* GPIO driving Reset pin, if any */ | ||
166 | int gpio_nreset; | ||
167 | /* GPIO that disable serial bus, if any */ | ||
168 | int gpio_disable; | ||
169 | }; | ||
170 | |||
171 | /* | ||
172 | * @freq is the desired MCLK rate | ||
173 | * MCLK rate should (c) be the sample rate, multiplied by one of the | ||
174 | * ratios listed in cs4271_mclk_fs_ratios table | ||
175 | */ | ||
176 | static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
177 | int clk_id, unsigned int freq, int dir) | ||
178 | { | ||
179 | struct snd_soc_codec *codec = codec_dai->codec; | ||
180 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
181 | |||
182 | cs4271->mclk = freq; | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
187 | unsigned int format) | ||
188 | { | ||
189 | struct snd_soc_codec *codec = codec_dai->codec; | ||
190 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
191 | unsigned int val = 0; | ||
192 | int ret; | ||
193 | |||
194 | switch (format & SND_SOC_DAIFMT_MASTER_MASK) { | ||
195 | case SND_SOC_DAIFMT_CBS_CFS: | ||
196 | cs4271->master = 0; | ||
197 | break; | ||
198 | case SND_SOC_DAIFMT_CBM_CFM: | ||
199 | cs4271->master = 1; | ||
200 | val |= CS4271_MODE1_MASTER; | ||
201 | break; | ||
202 | default: | ||
203 | dev_err(codec->dev, "Invalid DAI format\n"); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
208 | case SND_SOC_DAIFMT_LEFT_J: | ||
209 | val |= CS4271_MODE1_DAC_DIF_LJ; | ||
210 | ret = snd_soc_update_bits(codec, CS4271_ADCCTL, | ||
211 | CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ); | ||
212 | if (ret < 0) | ||
213 | return ret; | ||
214 | break; | ||
215 | case SND_SOC_DAIFMT_I2S: | ||
216 | val |= CS4271_MODE1_DAC_DIF_I2S; | ||
217 | ret = snd_soc_update_bits(codec, CS4271_ADCCTL, | ||
218 | CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S); | ||
219 | if (ret < 0) | ||
220 | return ret; | ||
221 | break; | ||
222 | default: | ||
223 | dev_err(codec->dev, "Invalid DAI format\n"); | ||
224 | return -EINVAL; | ||
225 | } | ||
226 | |||
227 | ret = snd_soc_update_bits(codec, CS4271_MODE1, | ||
228 | CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val); | ||
229 | if (ret < 0) | ||
230 | return ret; | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int cs4271_deemph[] = {0, 44100, 48000, 32000}; | ||
235 | |||
236 | static int cs4271_set_deemph(struct snd_soc_codec *codec) | ||
237 | { | ||
238 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
239 | int i, ret; | ||
240 | int val = CS4271_DACCTL_DEM_DIS; | ||
241 | |||
242 | if (cs4271->deemph) { | ||
243 | /* Find closest de-emphasis freq */ | ||
244 | val = 1; | ||
245 | for (i = 2; i < ARRAY_SIZE(cs4271_deemph); i++) | ||
246 | if (abs(cs4271_deemph[i] - cs4271->rate) < | ||
247 | abs(cs4271_deemph[val] - cs4271->rate)) | ||
248 | val = i; | ||
249 | val <<= 4; | ||
250 | } | ||
251 | |||
252 | ret = snd_soc_update_bits(codec, CS4271_DACCTL, | ||
253 | CS4271_DACCTL_DEM_MASK, val); | ||
254 | if (ret < 0) | ||
255 | return ret; | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int cs4271_get_deemph(struct snd_kcontrol *kcontrol, | ||
260 | struct snd_ctl_elem_value *ucontrol) | ||
261 | { | ||
262 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
263 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
264 | |||
265 | ucontrol->value.enumerated.item[0] = cs4271->deemph; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int cs4271_put_deemph(struct snd_kcontrol *kcontrol, | ||
270 | struct snd_ctl_elem_value *ucontrol) | ||
271 | { | ||
272 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
273 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
274 | |||
275 | cs4271->deemph = ucontrol->value.enumerated.item[0]; | ||
276 | return cs4271_set_deemph(codec); | ||
277 | } | ||
278 | |||
279 | struct cs4271_clk_cfg { | ||
280 | bool master; /* codec mode */ | ||
281 | u8 speed_mode; /* codec speed mode: 1x, 2x, 4x */ | ||
282 | unsigned short ratio; /* MCLK / sample rate */ | ||
283 | u8 ratio_mask; /* ratio bit mask for Master mode */ | ||
284 | }; | ||
285 | |||
286 | static struct cs4271_clk_cfg cs4271_clk_tab[] = { | ||
287 | {1, CS4271_MODE1_MODE_1X, 256, CS4271_MODE1_DIV_1}, | ||
288 | {1, CS4271_MODE1_MODE_1X, 384, CS4271_MODE1_DIV_15}, | ||
289 | {1, CS4271_MODE1_MODE_1X, 512, CS4271_MODE1_DIV_2}, | ||
290 | {1, CS4271_MODE1_MODE_1X, 768, CS4271_MODE1_DIV_3}, | ||
291 | {1, CS4271_MODE1_MODE_2X, 128, CS4271_MODE1_DIV_1}, | ||
292 | {1, CS4271_MODE1_MODE_2X, 192, CS4271_MODE1_DIV_15}, | ||
293 | {1, CS4271_MODE1_MODE_2X, 256, CS4271_MODE1_DIV_2}, | ||
294 | {1, CS4271_MODE1_MODE_2X, 384, CS4271_MODE1_DIV_3}, | ||
295 | {1, CS4271_MODE1_MODE_4X, 64, CS4271_MODE1_DIV_1}, | ||
296 | {1, CS4271_MODE1_MODE_4X, 96, CS4271_MODE1_DIV_15}, | ||
297 | {1, CS4271_MODE1_MODE_4X, 128, CS4271_MODE1_DIV_2}, | ||
298 | {1, CS4271_MODE1_MODE_4X, 192, CS4271_MODE1_DIV_3}, | ||
299 | {0, CS4271_MODE1_MODE_1X, 256, CS4271_MODE1_DIV_1}, | ||
300 | {0, CS4271_MODE1_MODE_1X, 384, CS4271_MODE1_DIV_1}, | ||
301 | {0, CS4271_MODE1_MODE_1X, 512, CS4271_MODE1_DIV_1}, | ||
302 | {0, CS4271_MODE1_MODE_1X, 768, CS4271_MODE1_DIV_2}, | ||
303 | {0, CS4271_MODE1_MODE_1X, 1024, CS4271_MODE1_DIV_2}, | ||
304 | {0, CS4271_MODE1_MODE_2X, 128, CS4271_MODE1_DIV_1}, | ||
305 | {0, CS4271_MODE1_MODE_2X, 192, CS4271_MODE1_DIV_1}, | ||
306 | {0, CS4271_MODE1_MODE_2X, 256, CS4271_MODE1_DIV_1}, | ||
307 | {0, CS4271_MODE1_MODE_2X, 384, CS4271_MODE1_DIV_2}, | ||
308 | {0, CS4271_MODE1_MODE_2X, 512, CS4271_MODE1_DIV_2}, | ||
309 | {0, CS4271_MODE1_MODE_4X, 64, CS4271_MODE1_DIV_1}, | ||
310 | {0, CS4271_MODE1_MODE_4X, 96, CS4271_MODE1_DIV_1}, | ||
311 | {0, CS4271_MODE1_MODE_4X, 128, CS4271_MODE1_DIV_1}, | ||
312 | {0, CS4271_MODE1_MODE_4X, 192, CS4271_MODE1_DIV_2}, | ||
313 | {0, CS4271_MODE1_MODE_4X, 256, CS4271_MODE1_DIV_2}, | ||
314 | }; | ||
315 | |||
316 | #define CS4171_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab) | ||
317 | |||
318 | static int cs4271_hw_params(struct snd_pcm_substream *substream, | ||
319 | struct snd_pcm_hw_params *params, | ||
320 | struct snd_soc_dai *dai) | ||
321 | { | ||
322 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
323 | struct snd_soc_codec *codec = rtd->codec; | ||
324 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
325 | int i, ret; | ||
326 | unsigned int ratio, val; | ||
327 | |||
328 | cs4271->rate = params_rate(params); | ||
329 | |||
330 | /* Configure DAC */ | ||
331 | if (cs4271->rate < 50000) | ||
332 | val = CS4271_MODE1_MODE_1X; | ||
333 | else if (cs4271->rate < 100000) | ||
334 | val = CS4271_MODE1_MODE_2X; | ||
335 | else | ||
336 | val = CS4271_MODE1_MODE_4X; | ||
337 | |||
338 | ratio = cs4271->mclk / cs4271->rate; | ||
339 | for (i = 0; i < CS4171_NR_RATIOS; i++) | ||
340 | if ((cs4271_clk_tab[i].master == cs4271->master) && | ||
341 | (cs4271_clk_tab[i].speed_mode == val) && | ||
342 | (cs4271_clk_tab[i].ratio == ratio)) | ||
343 | break; | ||
344 | |||
345 | if (i == CS4171_NR_RATIOS) { | ||
346 | dev_err(codec->dev, "Invalid sample rate\n"); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | |||
350 | val |= cs4271_clk_tab[i].ratio_mask; | ||
351 | |||
352 | ret = snd_soc_update_bits(codec, CS4271_MODE1, | ||
353 | CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val); | ||
354 | if (ret < 0) | ||
355 | return ret; | ||
356 | |||
357 | return cs4271_set_deemph(codec); | ||
358 | } | ||
359 | |||
360 | static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute) | ||
361 | { | ||
362 | struct snd_soc_codec *codec = dai->codec; | ||
363 | int ret; | ||
364 | int val_a = 0; | ||
365 | int val_b = 0; | ||
366 | |||
367 | if (mute) { | ||
368 | val_a = CS4271_VOLA_MUTE; | ||
369 | val_b = CS4271_VOLB_MUTE; | ||
370 | } | ||
371 | |||
372 | ret = snd_soc_update_bits(codec, CS4271_VOLA, CS4271_VOLA_MUTE, val_a); | ||
373 | if (ret < 0) | ||
374 | return ret; | ||
375 | ret = snd_soc_update_bits(codec, CS4271_VOLB, CS4271_VOLB_MUTE, val_b); | ||
376 | if (ret < 0) | ||
377 | return ret; | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /* CS4271 controls */ | ||
383 | static DECLARE_TLV_DB_SCALE(cs4271_dac_tlv, -12700, 100, 0); | ||
384 | |||
385 | static const struct snd_kcontrol_new cs4271_snd_controls[] = { | ||
386 | SOC_DOUBLE_R_TLV("Master Playback Volume", CS4271_VOLA, CS4271_VOLB, | ||
387 | 0, 0x7F, 1, cs4271_dac_tlv), | ||
388 | SOC_SINGLE("Digital Loopback Switch", CS4271_MODE2, 4, 1, 0), | ||
389 | SOC_SINGLE("Soft Ramp Switch", CS4271_DACVOL, 5, 1, 0), | ||
390 | SOC_SINGLE("Zero Cross Switch", CS4271_DACVOL, 4, 1, 0), | ||
391 | SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0, | ||
392 | cs4271_get_deemph, cs4271_put_deemph), | ||
393 | SOC_SINGLE("Auto-Mute Switch", CS4271_DACCTL, 7, 1, 0), | ||
394 | SOC_SINGLE("Slow Roll Off Filter Switch", CS4271_DACCTL, 6, 1, 0), | ||
395 | SOC_SINGLE("Soft Volume Ramp-Up Switch", CS4271_DACCTL, 3, 1, 0), | ||
396 | SOC_SINGLE("Soft Ramp-Down Switch", CS4271_DACCTL, 2, 1, 0), | ||
397 | SOC_SINGLE("Left Channel Inversion Switch", CS4271_DACCTL, 1, 1, 0), | ||
398 | SOC_SINGLE("Right Channel Inversion Switch", CS4271_DACCTL, 0, 1, 0), | ||
399 | SOC_DOUBLE("Master Capture Switch", CS4271_ADCCTL, 3, 2, 1, 1), | ||
400 | SOC_SINGLE("Dither 16-Bit Data Switch", CS4271_ADCCTL, 5, 1, 0), | ||
401 | SOC_DOUBLE("High Pass Filter Switch", CS4271_ADCCTL, 1, 0, 1, 1), | ||
402 | SOC_DOUBLE_R("Master Playback Switch", CS4271_VOLA, CS4271_VOLB, | ||
403 | 7, 1, 1), | ||
404 | }; | ||
405 | |||
406 | static struct snd_soc_dai_ops cs4271_dai_ops = { | ||
407 | .hw_params = cs4271_hw_params, | ||
408 | .set_sysclk = cs4271_set_dai_sysclk, | ||
409 | .set_fmt = cs4271_set_dai_fmt, | ||
410 | .digital_mute = cs4271_digital_mute, | ||
411 | }; | ||
412 | |||
413 | static struct snd_soc_dai_driver cs4271_dai = { | ||
414 | .name = "cs4271-hifi", | ||
415 | .playback = { | ||
416 | .stream_name = "Playback", | ||
417 | .channels_min = 2, | ||
418 | .channels_max = 2, | ||
419 | .rates = CS4271_PCM_RATES, | ||
420 | .formats = CS4271_PCM_FORMATS, | ||
421 | }, | ||
422 | .capture = { | ||
423 | .stream_name = "Capture", | ||
424 | .channels_min = 2, | ||
425 | .channels_max = 2, | ||
426 | .rates = CS4271_PCM_RATES, | ||
427 | .formats = CS4271_PCM_FORMATS, | ||
428 | }, | ||
429 | .ops = &cs4271_dai_ops, | ||
430 | .symmetric_rates = 1, | ||
431 | }; | ||
432 | |||
433 | #ifdef CONFIG_PM | ||
434 | static int cs4271_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg) | ||
435 | { | ||
436 | int ret; | ||
437 | /* Set power-down bit */ | ||
438 | ret = snd_soc_update_bits(codec, CS4271_MODE2, 0, CS4271_MODE2_PDN); | ||
439 | if (ret < 0) | ||
440 | return ret; | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int cs4271_soc_resume(struct snd_soc_codec *codec) | ||
445 | { | ||
446 | int ret; | ||
447 | /* Restore codec state */ | ||
448 | ret = snd_soc_cache_sync(codec); | ||
449 | if (ret < 0) | ||
450 | return ret; | ||
451 | /* then disable the power-down bit */ | ||
452 | ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0); | ||
453 | if (ret < 0) | ||
454 | return ret; | ||
455 | return 0; | ||
456 | } | ||
457 | #else | ||
458 | #define cs4271_soc_suspend NULL | ||
459 | #define cs4271_soc_resume NULL | ||
460 | #endif /* CONFIG_PM */ | ||
461 | |||
462 | static int cs4271_probe(struct snd_soc_codec *codec) | ||
463 | { | ||
464 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
465 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; | ||
466 | int ret; | ||
467 | int gpio_nreset = -EINVAL; | ||
468 | |||
469 | codec->control_data = cs4271->control_data; | ||
470 | |||
471 | if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset)) | ||
472 | gpio_nreset = cs4271plat->gpio_nreset; | ||
473 | |||
474 | if (gpio_nreset >= 0) | ||
475 | if (gpio_request(gpio_nreset, "CS4271 Reset")) | ||
476 | gpio_nreset = -EINVAL; | ||
477 | if (gpio_nreset >= 0) { | ||
478 | /* Reset codec */ | ||
479 | gpio_direction_output(gpio_nreset, 0); | ||
480 | udelay(1); | ||
481 | gpio_set_value(gpio_nreset, 1); | ||
482 | /* Give the codec time to wake up */ | ||
483 | udelay(1); | ||
484 | } | ||
485 | |||
486 | cs4271->gpio_nreset = gpio_nreset; | ||
487 | |||
488 | /* | ||
489 | * In case of I2C, chip address specified in board data. | ||
490 | * So cache IO operations use 8 bit codec register address. | ||
491 | * In case of SPI, chip address and register address | ||
492 | * passed together as 16 bit value. | ||
493 | * Anyway, register address is masked with 0xFF inside | ||
494 | * soc-cache code. | ||
495 | */ | ||
496 | if (cs4271->bus_type == SND_SOC_SPI) | ||
497 | ret = snd_soc_codec_set_cache_io(codec, 16, 8, | ||
498 | cs4271->bus_type); | ||
499 | else | ||
500 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, | ||
501 | cs4271->bus_type); | ||
502 | if (ret) { | ||
503 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | ret = snd_soc_update_bits(codec, CS4271_MODE2, 0, | ||
508 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN); | ||
509 | if (ret < 0) | ||
510 | return ret; | ||
511 | ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0); | ||
512 | if (ret < 0) | ||
513 | return ret; | ||
514 | /* Power-up sequence requires 85 uS */ | ||
515 | udelay(85); | ||
516 | |||
517 | return snd_soc_add_controls(codec, cs4271_snd_controls, | ||
518 | ARRAY_SIZE(cs4271_snd_controls)); | ||
519 | } | ||
520 | |||
521 | static int cs4271_remove(struct snd_soc_codec *codec) | ||
522 | { | ||
523 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
524 | int gpio_nreset; | ||
525 | |||
526 | gpio_nreset = cs4271->gpio_nreset; | ||
527 | |||
528 | if (gpio_is_valid(gpio_nreset)) { | ||
529 | /* Set codec to the reset state */ | ||
530 | gpio_set_value(gpio_nreset, 0); | ||
531 | gpio_free(gpio_nreset); | ||
532 | } | ||
533 | |||
534 | return 0; | ||
535 | }; | ||
536 | |||
537 | static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { | ||
538 | .probe = cs4271_probe, | ||
539 | .remove = cs4271_remove, | ||
540 | .suspend = cs4271_soc_suspend, | ||
541 | .resume = cs4271_soc_resume, | ||
542 | .reg_cache_default = cs4271_dflt_reg, | ||
543 | .reg_cache_size = ARRAY_SIZE(cs4271_dflt_reg), | ||
544 | .reg_word_size = sizeof(cs4271_dflt_reg[0]), | ||
545 | .compress_type = SND_SOC_FLAT_COMPRESSION, | ||
546 | }; | ||
547 | |||
548 | #if defined(CONFIG_SPI_MASTER) | ||
549 | static int __devinit cs4271_spi_probe(struct spi_device *spi) | ||
550 | { | ||
551 | struct cs4271_private *cs4271; | ||
552 | |||
553 | cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL); | ||
554 | if (!cs4271) | ||
555 | return -ENOMEM; | ||
556 | |||
557 | spi_set_drvdata(spi, cs4271); | ||
558 | cs4271->control_data = spi; | ||
559 | cs4271->bus_type = SND_SOC_SPI; | ||
560 | |||
561 | return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271, | ||
562 | &cs4271_dai, 1); | ||
563 | } | ||
564 | |||
565 | static int __devexit cs4271_spi_remove(struct spi_device *spi) | ||
566 | { | ||
567 | snd_soc_unregister_codec(&spi->dev); | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static struct spi_driver cs4271_spi_driver = { | ||
572 | .driver = { | ||
573 | .name = "cs4271", | ||
574 | .owner = THIS_MODULE, | ||
575 | }, | ||
576 | .probe = cs4271_spi_probe, | ||
577 | .remove = __devexit_p(cs4271_spi_remove), | ||
578 | }; | ||
579 | #endif /* defined(CONFIG_SPI_MASTER) */ | ||
580 | |||
581 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
582 | static const struct i2c_device_id cs4271_i2c_id[] = { | ||
583 | {"cs4271", 0}, | ||
584 | {} | ||
585 | }; | ||
586 | MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); | ||
587 | |||
588 | static int __devinit cs4271_i2c_probe(struct i2c_client *client, | ||
589 | const struct i2c_device_id *id) | ||
590 | { | ||
591 | struct cs4271_private *cs4271; | ||
592 | |||
593 | cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL); | ||
594 | if (!cs4271) | ||
595 | return -ENOMEM; | ||
596 | |||
597 | i2c_set_clientdata(client, cs4271); | ||
598 | cs4271->control_data = client; | ||
599 | cs4271->bus_type = SND_SOC_I2C; | ||
600 | |||
601 | return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271, | ||
602 | &cs4271_dai, 1); | ||
603 | } | ||
604 | |||
605 | static int __devexit cs4271_i2c_remove(struct i2c_client *client) | ||
606 | { | ||
607 | snd_soc_unregister_codec(&client->dev); | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | static struct i2c_driver cs4271_i2c_driver = { | ||
612 | .driver = { | ||
613 | .name = "cs4271", | ||
614 | .owner = THIS_MODULE, | ||
615 | }, | ||
616 | .id_table = cs4271_i2c_id, | ||
617 | .probe = cs4271_i2c_probe, | ||
618 | .remove = __devexit_p(cs4271_i2c_remove), | ||
619 | }; | ||
620 | #endif /* defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) */ | ||
621 | |||
622 | /* | ||
623 | * We only register our serial bus driver here without | ||
624 | * assignment to particular chip. So if any of the below | ||
625 | * fails, there is some problem with I2C or SPI subsystem. | ||
626 | * In most cases this module will be compiled with support | ||
627 | * of only one serial bus. | ||
628 | */ | ||
629 | static int __init cs4271_modinit(void) | ||
630 | { | ||
631 | int ret; | ||
632 | |||
633 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
634 | ret = i2c_add_driver(&cs4271_i2c_driver); | ||
635 | if (ret) { | ||
636 | pr_err("Failed to register CS4271 I2C driver: %d\n", ret); | ||
637 | return ret; | ||
638 | } | ||
639 | #endif | ||
640 | |||
641 | #if defined(CONFIG_SPI_MASTER) | ||
642 | ret = spi_register_driver(&cs4271_spi_driver); | ||
643 | if (ret) { | ||
644 | pr_err("Failed to register CS4271 SPI driver: %d\n", ret); | ||
645 | return ret; | ||
646 | } | ||
647 | #endif | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | module_init(cs4271_modinit); | ||
652 | |||
653 | static void __exit cs4271_modexit(void) | ||
654 | { | ||
655 | #if defined(CONFIG_SPI_MASTER) | ||
656 | spi_unregister_driver(&cs4271_spi_driver); | ||
657 | #endif | ||
658 | |||
659 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
660 | i2c_del_driver(&cs4271_i2c_driver); | ||
661 | #endif | ||
662 | } | ||
663 | module_exit(cs4271_modexit); | ||
664 | |||
665 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | ||
666 | MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver"); | ||
667 | MODULE_LICENSE("GPL"); | ||