diff options
author | Timur Tabi <timur@freescale.com> | 2007-07-31 12:18:44 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2007-10-16 09:58:19 -0400 |
commit | b0c813ceee8963790bebe73956574336604ae574 (patch) | |
tree | 6873d84bcedb3454ddf1da1aa0821b4e84b32c27 /sound | |
parent | 8259980ebcecd8096a04cc43c1c1d72e1c0ed165 (diff) |
[ALSA] ASoC CS4270 codec device driver
This patch adds ALSA SoC support for the Cirrus Logic CS4270 codec. The
following features are suppored:
1) Stand-alone and software mode
2) Software mode via I2C only
3) Master mode, not Slave
4) No power management
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/Kconfig | 20 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/cs4270.c | 808 | ||||
-rw-r--r-- | sound/soc/codecs/cs4270.h | 28 |
4 files changed, 858 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e5fb437b86e8..78248808a9d8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -17,3 +17,23 @@ config SND_SOC_WM8753 | |||
17 | config SND_SOC_WM9712 | 17 | config SND_SOC_WM9712 |
18 | tristate | 18 | tristate |
19 | depends on SND_SOC | 19 | depends on SND_SOC |
20 | |||
21 | # Cirrus Logic CS4270 Codec | ||
22 | config SND_SOC_CS4270 | ||
23 | tristate | ||
24 | depends on SND_SOC | ||
25 | |||
26 | # Cirrus Logic CS4270 Codec Hardware Mute Support | ||
27 | # Select if you have external muting circuitry attached to your CS4270. | ||
28 | config SND_SOC_CS4270_HWMUTE | ||
29 | bool | ||
30 | depends on SND_SOC_CS4270 | ||
31 | |||
32 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | ||
33 | # Select if you are affected by the errata where the part will not function | ||
34 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | ||
35 | # not select any sample rates that require MCLK to be divided by 1.5. | ||
36 | config SND_SOC_CS4270_VD33_ERRATA | ||
37 | bool | ||
38 | depends on SND_SOC_CS4270 | ||
39 | |||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index e39a747a17cf..7ad78e36d506 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -3,9 +3,11 @@ snd-soc-wm8731-objs := wm8731.o | |||
3 | snd-soc-wm8750-objs := wm8750.o | 3 | snd-soc-wm8750-objs := wm8750.o |
4 | snd-soc-wm8753-objs := wm8753.o | 4 | snd-soc-wm8753-objs := wm8753.o |
5 | snd-soc-wm9712-objs := wm9712.o | 5 | snd-soc-wm9712-objs := wm9712.o |
6 | snd-soc-cs4270-objs := cs4270.o | ||
6 | 7 | ||
7 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 8 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
8 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 9 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
9 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 10 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
10 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 11 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
11 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 12 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
13 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | ||
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c new file mode 100644 index 000000000000..b659a5dfd776 --- /dev/null +++ b/sound/soc/codecs/cs4270.c | |||
@@ -0,0 +1,808 @@ | |||
1 | /* | ||
2 | * CS4270 ALSA SoC (ASoC) codec driver | ||
3 | * | ||
4 | * Author: Timur Tabi <timur@freescale.com> | ||
5 | * | ||
6 | * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under | ||
7 | * the terms of the GNU General Public License version 2. This program | ||
8 | * is licensed "as is" without any warranty of any kind, whether express | ||
9 | * or implied. | ||
10 | * | ||
11 | * This is an ASoC device driver for the Cirrus Logic CS4270 codec. | ||
12 | * | ||
13 | * Current features/limitations: | ||
14 | * | ||
15 | * 1) Stand-alone and software mode is supported. Stand-alone is | ||
16 | * automatically selected if I2C is disabled or if a CS4270 is not found | ||
17 | * on the I2C bus. | ||
18 | * 2) Only I2C is supported, not SPI | ||
19 | * 3) Only Master mode is supported, not Slave. | ||
20 | * 4) The machine driver's 'startup' function must call | ||
21 | * cs4270_set_dai_sysclk() with the value of MCLK. | ||
22 | * 5) Only I2S and left-justified modes are supported | ||
23 | * 6) Power management is not supported | ||
24 | * 7) The only supported control is volume and hardware mute (if enabled) | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <sound/driver.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/initval.h> | ||
33 | #include <linux/i2c.h> | ||
34 | |||
35 | #include "cs4270.h" | ||
36 | |||
37 | /* Private data for the CS4270 */ | ||
38 | struct cs4270_private { | ||
39 | unsigned int mclk; /* Input frequency of the MCLK pin */ | ||
40 | unsigned int mode; /* The mode (I2S or left-justified) */ | ||
41 | }; | ||
42 | |||
43 | /* | ||
44 | * The codec isn't really big-endian or little-endian, since the I2S | ||
45 | * interface requires data to be sent serially with the MSbit first. | ||
46 | * However, to support BE and LE I2S devices, we specify both here. That | ||
47 | * way, ALSA will always match the bit patterns. | ||
48 | */ | ||
49 | #define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ | ||
50 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
51 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ | ||
52 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
53 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ | ||
54 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | ||
55 | |||
56 | #ifdef CONFIG_I2C | ||
57 | |||
58 | /* CS4270 registers addresses */ | ||
59 | #define CS4270_CHIPID 0x01 /* Chip ID */ | ||
60 | #define CS4270_PWRCTL 0x02 /* Power Control */ | ||
61 | #define CS4270_MODE 0x03 /* Mode Control */ | ||
62 | #define CS4270_FORMAT 0x04 /* Serial Format, ADC/DAC Control */ | ||
63 | #define CS4270_TRANS 0x05 /* Transition Control */ | ||
64 | #define CS4270_MUTE 0x06 /* Mute Control */ | ||
65 | #define CS4270_VOLA 0x07 /* DAC Channel A Volume Control */ | ||
66 | #define CS4270_VOLB 0x08 /* DAC Channel B Volume Control */ | ||
67 | |||
68 | #define CS4270_FIRSTREG 0x01 | ||
69 | #define CS4270_LASTREG 0x08 | ||
70 | #define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) | ||
71 | |||
72 | /* Bit masks for the CS4270 registers */ | ||
73 | #define CS4270_CHIPID_ID 0xF0 | ||
74 | #define CS4270_CHIPID_REV 0x0F | ||
75 | #define CS4270_PWRCTL_FREEZE 0x80 | ||
76 | #define CS4270_PWRCTL_PDN_ADC 0x20 | ||
77 | #define CS4270_PWRCTL_PDN_DAC 0x02 | ||
78 | #define CS4270_PWRCTL_PDN 0x01 | ||
79 | #define CS4270_MODE_SPEED_MASK 0x30 | ||
80 | #define CS4270_MODE_1X 0x00 | ||
81 | #define CS4270_MODE_2X 0x10 | ||
82 | #define CS4270_MODE_4X 0x20 | ||
83 | #define CS4270_MODE_SLAVE 0x30 | ||
84 | #define CS4270_MODE_DIV_MASK 0x0E | ||
85 | #define CS4270_MODE_DIV1 0x00 | ||
86 | #define CS4270_MODE_DIV15 0x02 | ||
87 | #define CS4270_MODE_DIV2 0x04 | ||
88 | #define CS4270_MODE_DIV3 0x06 | ||
89 | #define CS4270_MODE_DIV4 0x08 | ||
90 | #define CS4270_MODE_POPGUARD 0x01 | ||
91 | #define CS4270_FORMAT_FREEZE_A 0x80 | ||
92 | #define CS4270_FORMAT_FREEZE_B 0x40 | ||
93 | #define CS4270_FORMAT_LOOPBACK 0x20 | ||
94 | #define CS4270_FORMAT_DAC_MASK 0x18 | ||
95 | #define CS4270_FORMAT_DAC_LJ 0x00 | ||
96 | #define CS4270_FORMAT_DAC_I2S 0x08 | ||
97 | #define CS4270_FORMAT_DAC_RJ16 0x18 | ||
98 | #define CS4270_FORMAT_DAC_RJ24 0x10 | ||
99 | #define CS4270_FORMAT_ADC_MASK 0x01 | ||
100 | #define CS4270_FORMAT_ADC_LJ 0x00 | ||
101 | #define CS4270_FORMAT_ADC_I2S 0x01 | ||
102 | #define CS4270_TRANS_ONE_VOL 0x80 | ||
103 | #define CS4270_TRANS_SOFT 0x40 | ||
104 | #define CS4270_TRANS_ZERO 0x20 | ||
105 | #define CS4270_TRANS_INV_ADC_A 0x08 | ||
106 | #define CS4270_TRANS_INV_ADC_B 0x10 | ||
107 | #define CS4270_TRANS_INV_DAC_A 0x02 | ||
108 | #define CS4270_TRANS_INV_DAC_B 0x04 | ||
109 | #define CS4270_TRANS_DEEMPH 0x01 | ||
110 | #define CS4270_MUTE_AUTO 0x20 | ||
111 | #define CS4270_MUTE_ADC_A 0x08 | ||
112 | #define CS4270_MUTE_ADC_B 0x10 | ||
113 | #define CS4270_MUTE_POLARITY 0x04 | ||
114 | #define CS4270_MUTE_DAC_A 0x01 | ||
115 | #define CS4270_MUTE_DAC_B 0x02 | ||
116 | |||
117 | /* | ||
118 | * A list of addresses on which this CS4270 could use. I2C addresses are | ||
119 | * 7 bits. For the CS4270, the upper four bits are always 1001, and the | ||
120 | * lower three bits are determined via the AD2, AD1, and AD0 pins | ||
121 | * (respectively). | ||
122 | */ | ||
123 | static unsigned short normal_i2c[] = { | ||
124 | 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, I2C_CLIENT_END | ||
125 | }; | ||
126 | I2C_CLIENT_INSMOD; | ||
127 | |||
128 | /* | ||
129 | * Pre-fill the CS4270 register cache. | ||
130 | * | ||
131 | * We use the auto-increment feature of the CS4270 to read all registers in | ||
132 | * one shot. | ||
133 | */ | ||
134 | static int cs4270_fill_cache(struct snd_soc_codec *codec) | ||
135 | { | ||
136 | u8 *cache = codec->reg_cache; | ||
137 | struct i2c_client *i2c_client = codec->control_data; | ||
138 | s32 length; | ||
139 | |||
140 | length = i2c_smbus_read_i2c_block_data(i2c_client, | ||
141 | CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache); | ||
142 | |||
143 | if (length != CS4270_NUMREGS) { | ||
144 | printk(KERN_ERR "cs4270: I2C read failure, addr=%u\n", | ||
145 | i2c_client->addr); | ||
146 | return -EIO; | ||
147 | } | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Read from the CS4270 register cache. | ||
154 | * | ||
155 | * This CS4270 registers are cached to avoid excessive I2C I/O operations. | ||
156 | * After the initial read to pre-fill the cache, the CS4270 never updates | ||
157 | * the register values, so we won't have a cache coherncy problem. | ||
158 | */ | ||
159 | static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec, | ||
160 | unsigned int reg) | ||
161 | { | ||
162 | u8 *cache = codec->reg_cache; | ||
163 | |||
164 | if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) | ||
165 | return -EIO; | ||
166 | |||
167 | return cache[reg - CS4270_FIRSTREG]; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Write to a CS4270 register via the I2C bus. | ||
172 | * | ||
173 | * This function writes the given value to the given CS4270 register, and | ||
174 | * also updates the register cache. | ||
175 | * | ||
176 | * Note that we don't use the hw_write function pointer of snd_soc_codec. | ||
177 | * That's because it's too clunky: the hw_write_t prototype does not match | ||
178 | * i2c_smbus_write_byte_data(), and it's just another layer of overhead. | ||
179 | */ | ||
180 | static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, | ||
181 | unsigned int value) | ||
182 | { | ||
183 | if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) | ||
184 | return -EIO; | ||
185 | |||
186 | if (i2c_smbus_write_byte_data(codec->control_data, reg, value) == 0) { | ||
187 | /* We've written to the hardware, so update the cache */ | ||
188 | u8 *cache = codec->reg_cache; | ||
189 | cache[reg - CS4270_FIRSTREG] = value; | ||
190 | return 0; | ||
191 | } else { | ||
192 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
193 | return -EIO; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Clock Ratio Selection for Master Mode. | ||
199 | * | ||
200 | * The data for this chart is taken from Table 5 of the CS4270 reference | ||
201 | * manual. | ||
202 | * | ||
203 | * This table is used to determine how to program the Mode Control register. | ||
204 | * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling | ||
205 | * rates the CS4270 currently supports. | ||
206 | * | ||
207 | * 'ratio' is the MCLK/LRCK ratio. MCLK is usually a fixed input frequency, | ||
208 | * and LRCK is equal to the sampling rate. The CS4270 only supports sampling | ||
209 | * rates where this ratio is one of: 64, 96, 128, 192, 256, 384, 512, 768 or | ||
210 | * 1024. | ||
211 | * | ||
212 | * 'speed_mode' is the corresponding bit pattern to be written to the | ||
213 | * MODE bits of the Mode Control Register | ||
214 | * | ||
215 | * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of | ||
216 | * the Mode Control Register. | ||
217 | * | ||
218 | * In situations where a single ratio is represented by multiple speed | ||
219 | * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick | ||
220 | * double-speed instead of quad-speed. However, the CS4270 errata states | ||
221 | * that Divide-By-1.5 can cause failures, so we avoid that mode where | ||
222 | * possible. | ||
223 | * | ||
224 | * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not | ||
225 | * work if VD = 3.3V. If this effects you, select the | ||
226 | * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will | ||
227 | * never select any sample rates that require divide-by-1.5. | ||
228 | */ | ||
229 | static struct { | ||
230 | unsigned int ratio; | ||
231 | u8 speed_mode; | ||
232 | u8 mclk; | ||
233 | } cs4270_mode_ratios[] = { | ||
234 | {64, CS4270_MODE_4X, CS4270_MODE_DIV1}, | ||
235 | #ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA | ||
236 | {96, CS4270_MODE_4X, CS4270_MODE_DIV15}, | ||
237 | #endif | ||
238 | {128, CS4270_MODE_2X, CS4270_MODE_DIV1}, | ||
239 | {192, CS4270_MODE_4X, CS4270_MODE_DIV3}, | ||
240 | {256, CS4270_MODE_1X, CS4270_MODE_DIV1}, | ||
241 | {384, CS4270_MODE_2X, CS4270_MODE_DIV3}, | ||
242 | {512, CS4270_MODE_1X, CS4270_MODE_DIV2}, | ||
243 | {768, CS4270_MODE_1X, CS4270_MODE_DIV3}, | ||
244 | {1024, CS4270_MODE_1X, CS4270_MODE_DIV4} | ||
245 | }; | ||
246 | |||
247 | /* | ||
248 | * Program the CS4270 with the given hardware parameters. | ||
249 | * | ||
250 | * The .dai_ops functions are used to provide board-specific data, like | ||
251 | * input frequencies, to this driver. This function takes that information, | ||
252 | * combines it with the hardware parameters provided, and programs the | ||
253 | * hardware accordingly. | ||
254 | */ | ||
255 | static int cs4270_hw_params(struct snd_pcm_substream *substream, | ||
256 | struct snd_pcm_hw_params *params) | ||
257 | { | ||
258 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
259 | struct snd_soc_device *socdev = rtd->socdev; | ||
260 | struct snd_soc_codec *codec = socdev->codec; | ||
261 | struct cs4270_private *cs4270 = codec->private_data; | ||
262 | unsigned int ret = 0; | ||
263 | unsigned int i; | ||
264 | unsigned int rate; | ||
265 | unsigned int ratio; | ||
266 | int reg; | ||
267 | |||
268 | /* Figure out which MCLK/LRCK ratio to use */ | ||
269 | |||
270 | rate = params_rate(params); /* Sampling rate, in Hz */ | ||
271 | ratio = cs4270->mclk / rate; /* MCLK/LRCK ratio */ | ||
272 | |||
273 | for (i = 0; i < ARRAY_SIZE(cs4270_mode_ratios); i++) { | ||
274 | if (cs4270_mode_ratios[i].ratio == ratio) | ||
275 | break; | ||
276 | } | ||
277 | |||
278 | if (i == ARRAY_SIZE(cs4270_mode_ratios)) { | ||
279 | /* We did not find a matching ratio */ | ||
280 | printk(KERN_ERR "cs4270: could not find matching ratio\n"); | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | |||
284 | /* Freeze and power-down the codec */ | ||
285 | |||
286 | ret = snd_soc_write(codec, CS4270_PWRCTL, CS4270_PWRCTL_FREEZE | | ||
287 | CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | | ||
288 | CS4270_PWRCTL_PDN); | ||
289 | if (ret < 0) { | ||
290 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | /* Program the mode control register */ | ||
295 | |||
296 | reg = snd_soc_read(codec, CS4270_MODE); | ||
297 | reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK); | ||
298 | reg |= cs4270_mode_ratios[i].speed_mode | cs4270_mode_ratios[i].mclk; | ||
299 | |||
300 | ret = snd_soc_write(codec, CS4270_MODE, reg); | ||
301 | if (ret < 0) { | ||
302 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | /* Program the format register */ | ||
307 | |||
308 | reg = snd_soc_read(codec, CS4270_FORMAT); | ||
309 | reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK); | ||
310 | |||
311 | switch (cs4270->mode) { | ||
312 | case SND_SOC_DAIFMT_I2S: | ||
313 | reg |= CS4270_FORMAT_DAC_I2S | CS4270_FORMAT_ADC_I2S; | ||
314 | break; | ||
315 | case SND_SOC_DAIFMT_LEFT_J: | ||
316 | reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ; | ||
317 | break; | ||
318 | default: | ||
319 | printk(KERN_ERR "cs4270: unknown format\n"); | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | ret = snd_soc_write(codec, CS4270_FORMAT, reg); | ||
324 | if (ret < 0) { | ||
325 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
326 | return ret; | ||
327 | } | ||
328 | |||
329 | /* Disable auto-mute. This feature appears to be buggy, because in | ||
330 | some situations, auto-mute will not deactivate when it should. */ | ||
331 | |||
332 | reg = snd_soc_read(codec, CS4270_MUTE); | ||
333 | reg &= ~CS4270_MUTE_AUTO; | ||
334 | ret = snd_soc_write(codec, CS4270_MUTE, reg); | ||
335 | if (ret < 0) { | ||
336 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | /* Thaw and power-up the codec */ | ||
341 | |||
342 | ret = snd_soc_write(codec, CS4270_PWRCTL, 0); | ||
343 | if (ret < 0) { | ||
344 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | #ifdef CONFIG_SND_SOC_CS4270_HWMUTE | ||
352 | |||
353 | /* | ||
354 | * Set the CS4270 external mute | ||
355 | * | ||
356 | * This function toggles the mute bits in the MUTE register. The CS4270's | ||
357 | * mute capability is intended for external muting circuitry, so if the | ||
358 | * board does not have the MUTEA or MUTEB pins connected to such circuitry, | ||
359 | * then this function will do nothing. | ||
360 | */ | ||
361 | static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute) | ||
362 | { | ||
363 | struct snd_soc_codec *codec = dai->codec; | ||
364 | int reg6; | ||
365 | |||
366 | reg6 = snd_soc_read(codec, CS4270_MUTE); | ||
367 | |||
368 | if (mute) | ||
369 | reg6 |= CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | | ||
370 | CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; | ||
371 | else | ||
372 | reg6 &= ~(CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | | ||
373 | CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); | ||
374 | |||
375 | return snd_soc_write(codec, CS4270_MUTE, reg6); | ||
376 | } | ||
377 | |||
378 | #endif | ||
379 | |||
380 | /* | ||
381 | * Sampling rate <-> bit patter mapping | ||
382 | * | ||
383 | * This array maps sampling rates to their SNDRV_PCM_RATE_x equivalent. | ||
384 | * | ||
385 | * This is really something that ALSA should provide. | ||
386 | * | ||
387 | * This table is used by cs4270_set_dai_sysclk() to tell ALSA which sampling | ||
388 | * rates the CS4270 currently supports. | ||
389 | */ | ||
390 | static struct { | ||
391 | unsigned int rate; | ||
392 | unsigned int bit; | ||
393 | } rate_map[] = { | ||
394 | {5512, SNDRV_PCM_RATE_5512}, | ||
395 | {8000, SNDRV_PCM_RATE_8000}, | ||
396 | {11025, SNDRV_PCM_RATE_11025}, | ||
397 | {16000, SNDRV_PCM_RATE_16000}, | ||
398 | {22050, SNDRV_PCM_RATE_22050}, | ||
399 | {32000, SNDRV_PCM_RATE_32000}, | ||
400 | {44100, SNDRV_PCM_RATE_44100}, | ||
401 | {48000, SNDRV_PCM_RATE_48000}, | ||
402 | {64000, SNDRV_PCM_RATE_64000}, | ||
403 | {88200, SNDRV_PCM_RATE_88200}, | ||
404 | {96000, SNDRV_PCM_RATE_96000}, | ||
405 | {176400, SNDRV_PCM_RATE_176400}, | ||
406 | {192000, SNDRV_PCM_RATE_192000} | ||
407 | }; | ||
408 | |||
409 | /* | ||
410 | * Determine the CS4270 samples rates. | ||
411 | * | ||
412 | * 'freq' is the input frequency to MCLK. The other parameters are ignored. | ||
413 | * | ||
414 | * The value of MCLK is used to determine which sample rates are supported | ||
415 | * by the CS4270. The ratio of MCLK / Fs must be equal to one of nine | ||
416 | * support values: 64, 96, 128, 192, 256, 384, 512, 768, and 1024. | ||
417 | * | ||
418 | * This function calculates the nine ratios and determines which ones match | ||
419 | * a standard sample rate. If there's a match, then it is added to the list | ||
420 | * of support sample rates. | ||
421 | * | ||
422 | * This function must be called by the machine driver's 'startup' function, | ||
423 | * otherwise the list of supported sample rates will not be available in | ||
424 | * time for ALSA. | ||
425 | */ | ||
426 | static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | ||
427 | int clk_id, unsigned int freq, int dir) | ||
428 | { | ||
429 | struct snd_soc_codec *codec = codec_dai->codec; | ||
430 | struct cs4270_private *cs4270 = codec->private_data; | ||
431 | unsigned int rates = 0; | ||
432 | unsigned int rate_min = -1; | ||
433 | unsigned int rate_max = 0; | ||
434 | unsigned int i; | ||
435 | |||
436 | cs4270->mclk = freq; | ||
437 | |||
438 | for (i = 0; i < ARRAY_SIZE(cs4270_mode_ratios); i++) { | ||
439 | unsigned int rate; | ||
440 | unsigned int j; | ||
441 | rate = freq / cs4270_mode_ratios[i].ratio; | ||
442 | for (j = 0; j < ARRAY_SIZE(rate_map); j++) { | ||
443 | if (rate == rate_map[j].rate) { | ||
444 | rates |= rate_map[j].bit; | ||
445 | if (rate < rate_min) | ||
446 | rate_min = rate; | ||
447 | if (rate > rate_max) | ||
448 | rate_max = rate; | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | |||
453 | if (!rate_max) { | ||
454 | printk(KERN_ERR "cs4270: could not find a valid rate\n"); | ||
455 | return -EINVAL; | ||
456 | } | ||
457 | |||
458 | codec_dai->playback.rates = rates; | ||
459 | codec_dai->playback.rate_min = rate_min; | ||
460 | codec_dai->playback.rate_max = rate_max; | ||
461 | |||
462 | codec_dai->capture.rates = rates; | ||
463 | codec_dai->capture.rate_min = rate_min; | ||
464 | codec_dai->capture.rate_max = rate_max; | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | /* | ||
470 | * Configure the codec for the selected audio format | ||
471 | * | ||
472 | * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the | ||
473 | * codec accordingly. | ||
474 | * | ||
475 | * Currently, this function only supports SND_SOC_DAIFMT_I2S and | ||
476 | * SND_SOC_DAIFMT_LEFT_J. The CS4270 codec also supports right-justified | ||
477 | * data for playback only, but ASoC currently does not support different | ||
478 | * formats for playback vs. record. | ||
479 | */ | ||
480 | static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | ||
481 | unsigned int format) | ||
482 | { | ||
483 | struct snd_soc_codec *codec = codec_dai->codec; | ||
484 | struct cs4270_private *cs4270 = codec->private_data; | ||
485 | int ret = 0; | ||
486 | |||
487 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
488 | case SND_SOC_DAIFMT_I2S: | ||
489 | case SND_SOC_DAIFMT_LEFT_J: | ||
490 | cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK; | ||
491 | break; | ||
492 | default: | ||
493 | printk(KERN_ERR "cs4270: invalid DAI format\n"); | ||
494 | ret = -EINVAL; | ||
495 | } | ||
496 | |||
497 | return ret; | ||
498 | } | ||
499 | |||
500 | static int cs4270_i2c_probe(struct i2c_adapter *adap, int addr, int kind); | ||
501 | |||
502 | /* | ||
503 | * Notify the driver that a new I2C bus has been found. | ||
504 | * | ||
505 | * This function is called for each I2C bus in the system. The function | ||
506 | * then asks the I2C subsystem to probe that bus at the addresses on which | ||
507 | * our device (the CS4270) could exist. If a device is found at one of | ||
508 | * those addresses, then our probe function (cs4270_i2c_probe) is called. | ||
509 | */ | ||
510 | static int cs4270_i2c_attach(struct i2c_adapter *adapter) | ||
511 | { | ||
512 | return i2c_probe(adapter, &addr_data, cs4270_i2c_probe); | ||
513 | } | ||
514 | |||
515 | static int cs4270_i2c_detach(struct i2c_client *client) | ||
516 | { | ||
517 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
518 | |||
519 | i2c_detach_client(client); | ||
520 | codec->control_data = NULL; | ||
521 | |||
522 | kfree(codec->reg_cache); | ||
523 | codec->reg_cache = NULL; | ||
524 | |||
525 | kfree(client); | ||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | /* A list of non-DAPM controls that the CS4270 supports */ | ||
530 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { | ||
531 | SOC_DOUBLE_R("Master Playback Volume", | ||
532 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 0) | ||
533 | }; | ||
534 | |||
535 | static struct i2c_driver cs4270_i2c_driver = { | ||
536 | .driver = { | ||
537 | .name = "CS4270 I2C", | ||
538 | .owner = THIS_MODULE, | ||
539 | }, | ||
540 | .id = I2C_DRIVERID_CS4270, | ||
541 | .attach_adapter = cs4270_i2c_attach, | ||
542 | .detach_client = cs4270_i2c_detach, | ||
543 | }; | ||
544 | |||
545 | /* | ||
546 | * Global variable to store socdev for i2c probe function. | ||
547 | * | ||
548 | * If struct i2c_driver had a private_data field, we wouldn't need to use | ||
549 | * cs4270_socdec. This is the only way to pass the socdev structure to | ||
550 | * cs4270_i2c_probe(). | ||
551 | * | ||
552 | * The real solution to cs4270_socdev is to create a mechanism | ||
553 | * that maps I2C addresses to snd_soc_device structures. Perhaps the | ||
554 | * creation of the snd_soc_device object should be moved out of | ||
555 | * cs4270_probe() and into cs4270_i2c_probe(), but that would make this | ||
556 | * driver dependent on I2C. The CS4270 supports "stand-alone" mode, whereby | ||
557 | * the chip is *not* connected to the I2C bus, but is instead configured via | ||
558 | * input pins. | ||
559 | */ | ||
560 | static struct snd_soc_device *cs4270_socdev; | ||
561 | |||
562 | /* | ||
563 | * Initialize the I2C interface of the CS4270 | ||
564 | * | ||
565 | * This function is called for whenever the I2C subsystem finds a device | ||
566 | * at a particular address. | ||
567 | * | ||
568 | * Note: snd_soc_new_pcms() must be called before this function can be called, | ||
569 | * because of snd_ctl_add(). | ||
570 | */ | ||
571 | static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | ||
572 | { | ||
573 | struct snd_soc_device *socdev = cs4270_socdev; | ||
574 | struct snd_soc_codec *codec = socdev->codec; | ||
575 | struct i2c_client *i2c_client = NULL; | ||
576 | int i; | ||
577 | int ret = 0; | ||
578 | |||
579 | /* Probing all possible addresses has one drawback: if there are | ||
580 | multiple CS4270s on the bus, then you cannot specify which | ||
581 | socdev is matched with which CS4270. For now, we just reject | ||
582 | this I2C device if the socdev already has one attached. */ | ||
583 | if (codec->control_data) | ||
584 | return -ENODEV; | ||
585 | |||
586 | /* Note: codec_dai->codec is NULL here */ | ||
587 | |||
588 | i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
589 | if (!i2c_client) { | ||
590 | printk(KERN_ERR "cs4270: could not allocate I2C client\n"); | ||
591 | return -ENOMEM; | ||
592 | } | ||
593 | |||
594 | codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); | ||
595 | if (!codec->reg_cache) { | ||
596 | printk(KERN_ERR "cs4270: could not allocate register cache\n"); | ||
597 | ret = -ENOMEM; | ||
598 | goto error; | ||
599 | } | ||
600 | |||
601 | i2c_set_clientdata(i2c_client, codec); | ||
602 | strcpy(i2c_client->name, "CS4270"); | ||
603 | |||
604 | i2c_client->driver = &cs4270_i2c_driver; | ||
605 | i2c_client->adapter = adapter; | ||
606 | i2c_client->addr = addr; | ||
607 | |||
608 | /* Verify that we have a CS4270 */ | ||
609 | |||
610 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); | ||
611 | if (ret < 0) { | ||
612 | printk(KERN_ERR "cs4270: failed to read I2C\n"); | ||
613 | goto error; | ||
614 | } | ||
615 | /* The top four bits of the chip ID should be 1100. */ | ||
616 | if ((ret & 0xF0) != 0xC0) { | ||
617 | /* The device at this address is not a CS4270 codec */ | ||
618 | ret = -ENODEV; | ||
619 | goto error; | ||
620 | } | ||
621 | |||
622 | printk(KERN_INFO "cs4270: found device at I2C address %X\n", addr); | ||
623 | printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); | ||
624 | |||
625 | /* Tell the I2C layer a new client has arrived */ | ||
626 | |||
627 | ret = i2c_attach_client(i2c_client); | ||
628 | if (ret) { | ||
629 | printk(KERN_ERR "cs4270: could not attach codec, " | ||
630 | "I2C address %x, error code %i\n", addr, ret); | ||
631 | goto error; | ||
632 | } | ||
633 | |||
634 | codec->control_data = i2c_client; | ||
635 | codec->read = cs4270_read_reg_cache; | ||
636 | codec->write = cs4270_i2c_write; | ||
637 | codec->reg_cache_size = CS4270_NUMREGS; | ||
638 | |||
639 | /* The I2C interface is set up, so pre-fill our register cache */ | ||
640 | |||
641 | ret = cs4270_fill_cache(codec); | ||
642 | if (ret < 0) { | ||
643 | printk(KERN_ERR "cs4270: failed to fill register cache\n"); | ||
644 | goto error; | ||
645 | } | ||
646 | |||
647 | /* Add the non-DAPM controls */ | ||
648 | |||
649 | for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) { | ||
650 | struct snd_kcontrol *kctrl = | ||
651 | snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL); | ||
652 | |||
653 | ret = snd_ctl_add(codec->card, kctrl); | ||
654 | if (ret < 0) | ||
655 | goto error; | ||
656 | } | ||
657 | |||
658 | return 0; | ||
659 | |||
660 | error: | ||
661 | if (codec->control_data) { | ||
662 | i2c_detach_client(i2c_client); | ||
663 | codec->control_data = NULL; | ||
664 | } | ||
665 | |||
666 | kfree(codec->reg_cache); | ||
667 | codec->reg_cache = NULL; | ||
668 | codec->reg_cache_size = 0; | ||
669 | |||
670 | kfree(i2c_client); | ||
671 | |||
672 | return ret; | ||
673 | } | ||
674 | |||
675 | #endif | ||
676 | |||
677 | struct snd_soc_codec_dai cs4270_dai = { | ||
678 | .name = "CS4270", | ||
679 | .playback = { | ||
680 | .stream_name = "Playback", | ||
681 | .channels_min = 1, | ||
682 | .channels_max = 2, | ||
683 | .rates = 0, | ||
684 | .formats = CS4270_FORMATS, | ||
685 | }, | ||
686 | .capture = { | ||
687 | .stream_name = "Capture", | ||
688 | .channels_min = 1, | ||
689 | .channels_max = 2, | ||
690 | .rates = 0, | ||
691 | .formats = CS4270_FORMATS, | ||
692 | }, | ||
693 | .dai_ops = { | ||
694 | .set_sysclk = cs4270_set_dai_sysclk, | ||
695 | .set_fmt = cs4270_set_dai_fmt, | ||
696 | } | ||
697 | }; | ||
698 | EXPORT_SYMBOL_GPL(cs4270_dai); | ||
699 | |||
700 | /* | ||
701 | * ASoC probe function | ||
702 | * | ||
703 | * This function is called when the machine driver calls | ||
704 | * platform_device_add(). | ||
705 | */ | ||
706 | static int cs4270_probe(struct platform_device *pdev) | ||
707 | { | ||
708 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
709 | struct snd_soc_codec *codec; | ||
710 | int ret = 0; | ||
711 | |||
712 | printk(KERN_INFO "CS4270 ALSA SoC Codec\n"); | ||
713 | |||
714 | /* Allocate enough space for the snd_soc_codec structure | ||
715 | and our private data together. */ | ||
716 | codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) + | ||
717 | sizeof(struct cs4270_private), GFP_KERNEL); | ||
718 | if (!codec) { | ||
719 | printk(KERN_ERR "cs4270: Could not allocate codec structure\n"); | ||
720 | return -ENOMEM; | ||
721 | } | ||
722 | |||
723 | mutex_init(&codec->mutex); | ||
724 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
725 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
726 | |||
727 | codec->name = "CS4270"; | ||
728 | codec->owner = THIS_MODULE; | ||
729 | codec->dai = &cs4270_dai; | ||
730 | codec->num_dai = 1; | ||
731 | codec->private_data = codec + ALIGN(sizeof(struct snd_soc_codec), 4); | ||
732 | |||
733 | socdev->codec = codec; | ||
734 | |||
735 | /* Register PCMs */ | ||
736 | |||
737 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
738 | if (ret < 0) { | ||
739 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); | ||
740 | return ret; | ||
741 | } | ||
742 | |||
743 | #ifdef CONFIG_I2C | ||
744 | cs4270_socdev = socdev; | ||
745 | |||
746 | ret = i2c_add_driver(&cs4270_i2c_driver); | ||
747 | if (ret) { | ||
748 | printk(KERN_ERR "cs4270: failed to attach driver"); | ||
749 | snd_soc_free_pcms(socdev); | ||
750 | return ret; | ||
751 | } | ||
752 | |||
753 | /* Did we find a CS4270 on the I2C bus? */ | ||
754 | if (codec->control_data) { | ||
755 | /* Initialize codec ops */ | ||
756 | cs4270_dai.ops.hw_params = cs4270_hw_params; | ||
757 | #ifdef CONFIG_SND_SOC_CS4270_HWMUTE | ||
758 | cs4270_dai.dai_ops.digital_mute = cs4270_mute; | ||
759 | #endif | ||
760 | } else | ||
761 | printk(KERN_INFO "cs4270: no I2C device found, " | ||
762 | "using stand-alone mode\n"); | ||
763 | #else | ||
764 | printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n"); | ||
765 | #endif | ||
766 | |||
767 | ret = snd_soc_register_card(socdev); | ||
768 | if (ret < 0) { | ||
769 | printk(KERN_ERR "cs4270: failed to register card\n"); | ||
770 | snd_soc_free_pcms(socdev); | ||
771 | return ret; | ||
772 | } | ||
773 | |||
774 | return ret; | ||
775 | } | ||
776 | |||
777 | static int cs4270_remove(struct platform_device *pdev) | ||
778 | { | ||
779 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
780 | |||
781 | snd_soc_free_pcms(socdev); | ||
782 | |||
783 | #ifdef CONFIG_I2C | ||
784 | if (socdev->codec->control_data) | ||
785 | i2c_del_driver(&cs4270_i2c_driver); | ||
786 | #endif | ||
787 | |||
788 | kfree(socdev->codec); | ||
789 | socdev->codec = NULL; | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | /* | ||
795 | * ASoC codec device structure | ||
796 | * | ||
797 | * Assign this variable to the codec_dev field of the machine driver's | ||
798 | * snd_soc_device structure. | ||
799 | */ | ||
800 | struct snd_soc_codec_device soc_codec_device_cs4270 = { | ||
801 | .probe = cs4270_probe, | ||
802 | .remove = cs4270_remove | ||
803 | }; | ||
804 | EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); | ||
805 | |||
806 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | ||
807 | MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); | ||
808 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h new file mode 100644 index 000000000000..0ced49b7804d --- /dev/null +++ b/sound/soc/codecs/cs4270.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Cirrus Logic CS4270 ALSA SoC Codec Driver | ||
3 | * | ||
4 | * Author: Timur Tabi <timur@freescale.com> | ||
5 | * | ||
6 | * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under | ||
7 | * the terms of the GNU General Public License version 2. This program | ||
8 | * is licensed "as is" without any warranty of any kind, whether express | ||
9 | * or implied. | ||
10 | */ | ||
11 | |||
12 | #ifndef _CS4270_H | ||
13 | #define _CS4270_H | ||
14 | |||
15 | /* | ||
16 | * The ASoC codec DAI structure for the CS4270. Assign this structure to | ||
17 | * the .codec_dai field of your machine driver's snd_soc_dai_link structure. | ||
18 | */ | ||
19 | extern struct snd_soc_codec_dai cs4270_dai; | ||
20 | |||
21 | /* | ||
22 | * The ASoC codec device structure for the CS4270. Assign this structure | ||
23 | * to the .codec_dev field of your machine driver's snd_soc_device | ||
24 | * structure. | ||
25 | */ | ||
26 | extern struct snd_soc_codec_device soc_codec_device_cs4270; | ||
27 | |||
28 | #endif | ||