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