]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/soc/codecs/cs42l51.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[karo-tx-linux.git] / sound / soc / codecs / cs42l51.c
1 /*
2  * cs42l51.c
3  *
4  * ASoC Driver for Cirrus Logic CS42L51 codecs
5  *
6  * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
7  *
8  * Based on cs4270.c - Copyright (c) Freescale Semiconductor
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * For now:
20  *  - Only I2C is support. Not SPI
21  *  - master mode *NOT* supported
22  */
23
24 #include <linux/module.h>
25 #include <linux/platform_device.h>
26 #include <linux/slab.h>
27 #include <sound/core.h>
28 #include <sound/soc.h>
29 #include <sound/soc-dapm.h>
30 #include <sound/tlv.h>
31 #include <sound/initval.h>
32 #include <sound/pcm_params.h>
33 #include <sound/pcm.h>
34 #include <linux/i2c.h>
35
36 #include "cs42l51.h"
37
38 enum master_slave_mode {
39         MODE_SLAVE,
40         MODE_SLAVE_AUTO,
41         MODE_MASTER,
42 };
43
44 struct cs42l51_private {
45         unsigned int mclk;
46         unsigned int audio_mode;        /* The mode (I2S or left-justified) */
47         enum master_slave_mode func;
48         struct snd_soc_codec codec;
49         u8 reg_cache[CS42L51_NUMREGS];
50 };
51
52 static struct snd_soc_codec *cs42l51_codec;
53
54 #define CS42L51_FORMATS ( \
55                 SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
56                 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
57                 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
58                 SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
59
60 static int cs42l51_fill_cache(struct snd_soc_codec *codec)
61 {
62         u8 *cache = codec->reg_cache + 1;
63         struct i2c_client *i2c_client = codec->control_data;
64         s32 length;
65
66         length = i2c_smbus_read_i2c_block_data(i2c_client,
67                         CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
68         if (length != CS42L51_NUMREGS) {
69                 dev_err(&i2c_client->dev,
70                                 "I2C read failure, addr=0x%x (ret=%d vs %d)\n",
71                                 i2c_client->addr, length, CS42L51_NUMREGS);
72                 return -EIO;
73         }
74
75         return 0;
76 }
77
78 static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
79         const struct i2c_device_id *id)
80 {
81         struct snd_soc_codec *codec;
82         struct cs42l51_private *cs42l51;
83         int ret = 0;
84         int reg;
85
86         if (cs42l51_codec)
87                 return -EBUSY;
88
89         /* Verify that we have a CS42L51 */
90         ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
91         if (ret < 0) {
92                 dev_err(&i2c_client->dev, "failed to read I2C\n");
93                 goto error;
94         }
95
96         if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
97             (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
98                 dev_err(&i2c_client->dev, "Invalid chip id\n");
99                 ret = -ENODEV;
100                 goto error;
101         }
102
103         dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
104                                 ret & 7);
105
106         cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
107         if (!cs42l51) {
108                 dev_err(&i2c_client->dev, "could not allocate codec\n");
109                 return -ENOMEM;
110         }
111         codec = &cs42l51->codec;
112
113         mutex_init(&codec->mutex);
114         INIT_LIST_HEAD(&codec->dapm_widgets);
115         INIT_LIST_HEAD(&codec->dapm_paths);
116
117         codec->dev = &i2c_client->dev;
118         codec->name = "CS42L51";
119         codec->owner = THIS_MODULE;
120         codec->dai = &cs42l51_dai;
121         codec->num_dai = 1;
122         snd_soc_codec_set_drvdata(codec, cs42l51);
123
124         codec->control_data = i2c_client;
125         codec->reg_cache = cs42l51->reg_cache;
126         codec->reg_cache_size = CS42L51_NUMREGS;
127         i2c_set_clientdata(i2c_client, codec);
128
129         ret = cs42l51_fill_cache(codec);
130         if (ret < 0) {
131                 dev_err(&i2c_client->dev, "failed to fill register cache\n");
132                 goto error_alloc;
133         }
134
135         ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
136         if (ret < 0) {
137                 dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
138                 goto error_alloc;
139         }
140
141         /*
142          * DAC configuration
143          * - Use signal processor
144          * - auto mute
145          * - vol changes immediate
146          * - no de-emphasize
147          */
148         reg = CS42L51_DAC_CTL_DATA_SEL(1)
149                 | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
150         ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
151         if (ret < 0)
152                 goto error_alloc;
153
154         cs42l51_dai.dev = codec->dev;
155         cs42l51_codec = codec;
156
157         ret = snd_soc_register_codec(codec);
158         if (ret != 0) {
159                 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
160                 goto error_alloc;
161         }
162
163         ret = snd_soc_register_dai(&cs42l51_dai);
164         if (ret < 0) {
165                 dev_err(&i2c_client->dev, "failed to register DAIe\n");
166                 goto error_reg;
167         }
168
169         return 0;
170
171 error_reg:
172         snd_soc_unregister_codec(codec);
173 error_alloc:
174         kfree(cs42l51);
175 error:
176         return ret;
177 }
178
179 static int cs42l51_i2c_remove(struct i2c_client *client)
180 {
181         struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
182         snd_soc_unregister_dai(&cs42l51_dai);
183         snd_soc_unregister_codec(cs42l51_codec);
184         cs42l51_codec = NULL;
185         kfree(cs42l51);
186         return 0;
187 }
188
189
190 static const struct i2c_device_id cs42l51_id[] = {
191         {"cs42l51", 0},
192         {}
193 };
194 MODULE_DEVICE_TABLE(i2c, cs42l51_id);
195
196 static struct i2c_driver cs42l51_i2c_driver = {
197         .driver = {
198                 .name = "CS42L51 I2C",
199                 .owner = THIS_MODULE,
200         },
201         .id_table = cs42l51_id,
202         .probe = cs42l51_i2c_probe,
203         .remove = cs42l51_i2c_remove,
204 };
205
206 static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
207                         struct snd_ctl_elem_value *ucontrol)
208 {
209         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
210         unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
211
212         switch (value) {
213         default:
214         case 0:
215                 ucontrol->value.integer.value[0] = 0;
216                 break;
217         /* same value : (L+R)/2 and (R+L)/2 */
218         case 1:
219         case 2:
220                 ucontrol->value.integer.value[0] = 1;
221                 break;
222         case 3:
223                 ucontrol->value.integer.value[0] = 2;
224                 break;
225         }
226
227         return 0;
228 }
229
230 #define CHAN_MIX_NORMAL 0x00
231 #define CHAN_MIX_BOTH   0x55
232 #define CHAN_MIX_SWAP   0xFF
233
234 static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
235                         struct snd_ctl_elem_value *ucontrol)
236 {
237         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
238         unsigned char val;
239
240         switch (ucontrol->value.integer.value[0]) {
241         default:
242         case 0:
243                 val = CHAN_MIX_NORMAL;
244                 break;
245         case 1:
246                 val = CHAN_MIX_BOTH;
247                 break;
248         case 2:
249                 val = CHAN_MIX_SWAP;
250                 break;
251         }
252
253         snd_soc_write(codec, CS42L51_PCM_MIXER, val);
254
255         return 1;
256 }
257
258 static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
259 static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
260 /* This is a lie. after -102 db, it stays at -102 */
261 /* maybe a range would be better */
262 static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
263
264 static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
265 static const char *chan_mix[] = {
266         "L R",
267         "L+R",
268         "R L",
269 };
270
271 static const struct soc_enum cs42l51_chan_mix =
272         SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
273
274 static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
275         SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
276                         CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
277                         7, 0xffffff99, 0x18, adc_pcm_tlv),
278         SOC_DOUBLE_R("PCM Playback Switch",
279                         CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
280         SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
281                         CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
282                         8, 0xffffff19, 0x18, aout_tlv),
283         SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
284                         CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
285                         7, 0xffffff99, 0x18, adc_pcm_tlv),
286         SOC_DOUBLE_R("ADC Mixer Switch",
287                         CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
288         SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
289         SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
290         SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
291         SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
292         SOC_DOUBLE_TLV("Mic Boost Volume",
293                         CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
294         SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
295         SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
296         SOC_ENUM_EXT("PCM channel mixer",
297                         cs42l51_chan_mix,
298                         cs42l51_get_chan_mix, cs42l51_set_chan_mix),
299 };
300
301 /*
302  * to power down, one must:
303  * 1.) Enable the PDN bit
304  * 2.) enable power-down for the select channels
305  * 3.) disable the PDN bit.
306  */
307 static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
308                 struct snd_kcontrol *kcontrol, int event)
309 {
310         unsigned long value;
311
312         value = snd_soc_read(w->codec, CS42L51_POWER_CTL1);
313         value &= ~CS42L51_POWER_CTL1_PDN;
314
315         switch (event) {
316         case SND_SOC_DAPM_PRE_PMD:
317                 value |= CS42L51_POWER_CTL1_PDN;
318                 break;
319         default:
320         case SND_SOC_DAPM_POST_PMD:
321                 break;
322         }
323         snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
324                 CS42L51_POWER_CTL1_PDN, value);
325
326         return 0;
327 }
328
329 static const char *cs42l51_dac_names[] = {"Direct PCM",
330         "DSP PCM", "ADC"};
331 static const struct soc_enum cs42l51_dac_mux_enum =
332         SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
333 static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
334         SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
335
336 static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
337         "MIC Left", "MIC+preamp Left"};
338 static const struct soc_enum cs42l51_adcl_mux_enum =
339         SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
340 static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
341         SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
342
343 static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
344         "MIC Right", "MIC+preamp Right"};
345 static const struct soc_enum cs42l51_adcr_mux_enum =
346         SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
347 static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
348         SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
349
350 static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
351         SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
352         SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
353                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
354         SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
355                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
356         SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
357                 CS42L51_POWER_CTL1, 1, 1,
358                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
359         SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
360                 CS42L51_POWER_CTL1, 2, 1,
361                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
362         SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
363                 CS42L51_POWER_CTL1, 5, 1,
364                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
365         SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
366                 CS42L51_POWER_CTL1, 6, 1,
367                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
368
369         /* analog/mic */
370         SND_SOC_DAPM_INPUT("AIN1L"),
371         SND_SOC_DAPM_INPUT("AIN1R"),
372         SND_SOC_DAPM_INPUT("AIN2L"),
373         SND_SOC_DAPM_INPUT("AIN2R"),
374         SND_SOC_DAPM_INPUT("MICL"),
375         SND_SOC_DAPM_INPUT("MICR"),
376
377         SND_SOC_DAPM_MIXER("Mic Preamp Left",
378                 CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
379         SND_SOC_DAPM_MIXER("Mic Preamp Right",
380                 CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
381
382         /* HP */
383         SND_SOC_DAPM_OUTPUT("HPL"),
384         SND_SOC_DAPM_OUTPUT("HPR"),
385
386         /* mux */
387         SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
388                 &cs42l51_dac_mux_controls),
389         SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
390                 &cs42l51_adcl_mux_controls),
391         SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
392                 &cs42l51_adcr_mux_controls),
393 };
394
395 static const struct snd_soc_dapm_route cs42l51_routes[] = {
396         {"HPL", NULL, "Left DAC"},
397         {"HPR", NULL, "Right DAC"},
398
399         {"Left ADC", NULL, "Left PGA"},
400         {"Right ADC", NULL, "Right PGA"},
401
402         {"Mic Preamp Left",  NULL,  "MICL"},
403         {"Mic Preamp Right", NULL,  "MICR"},
404
405         {"PGA-ADC Mux Left",  "AIN1 Left",        "AIN1L" },
406         {"PGA-ADC Mux Left",  "AIN2 Left",        "AIN2L" },
407         {"PGA-ADC Mux Left",  "MIC Left",         "MICL"  },
408         {"PGA-ADC Mux Left",  "MIC+preamp Left",  "Mic Preamp Left" },
409         {"PGA-ADC Mux Right", "AIN1 Right",       "AIN1R" },
410         {"PGA-ADC Mux Right", "AIN2 Right",       "AIN2R" },
411         {"PGA-ADC Mux Right", "MIC Right",        "MICR" },
412         {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
413
414         {"Left PGA", NULL, "PGA-ADC Mux Left"},
415         {"Right PGA", NULL, "PGA-ADC Mux Right"},
416 };
417
418 static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
419                 unsigned int format)
420 {
421         struct snd_soc_codec *codec = codec_dai->codec;
422         struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
423         int ret = 0;
424
425         switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
426         case SND_SOC_DAIFMT_I2S:
427         case SND_SOC_DAIFMT_LEFT_J:
428         case SND_SOC_DAIFMT_RIGHT_J:
429                 cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
430                 break;
431         default:
432                 dev_err(codec->dev, "invalid DAI format\n");
433                 ret = -EINVAL;
434         }
435
436         switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
437         case SND_SOC_DAIFMT_CBM_CFM:
438                 cs42l51->func = MODE_MASTER;
439                 break;
440         case SND_SOC_DAIFMT_CBS_CFS:
441                 cs42l51->func = MODE_SLAVE_AUTO;
442                 break;
443         default:
444                 ret = -EINVAL;
445                 break;
446         }
447
448         return ret;
449 }
450
451 struct cs42l51_ratios {
452         unsigned int ratio;
453         unsigned char speed_mode;
454         unsigned char mclk;
455 };
456
457 static struct cs42l51_ratios slave_ratios[] = {
458         {  512, CS42L51_QSM_MODE, 0 }, {  768, CS42L51_QSM_MODE, 0 },
459         { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
460         { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
461         {  256, CS42L51_HSM_MODE, 0 }, {  384, CS42L51_HSM_MODE, 0 },
462         {  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
463         { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
464         {  128, CS42L51_SSM_MODE, 0 }, {  192, CS42L51_SSM_MODE, 0 },
465         {  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
466         {  512, CS42L51_SSM_MODE, 0 }, {  768, CS42L51_SSM_MODE, 0 },
467         {  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
468         {  256, CS42L51_DSM_MODE, 0 }, {  384, CS42L51_DSM_MODE, 0 },
469 };
470
471 static struct cs42l51_ratios slave_auto_ratios[] = {
472         { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
473         { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
474         {  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
475         { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
476         {  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
477         {  512, CS42L51_SSM_MODE, 1 }, {  768, CS42L51_SSM_MODE, 1 },
478         {  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
479         {  256, CS42L51_DSM_MODE, 1 }, {  384, CS42L51_DSM_MODE, 1 },
480 };
481
482 static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
483                 int clk_id, unsigned int freq, int dir)
484 {
485         struct snd_soc_codec *codec = codec_dai->codec;
486         struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
487         struct cs42l51_ratios *ratios = NULL;
488         int nr_ratios = 0;
489         unsigned int rates = 0;
490         unsigned int rate_min = -1;
491         unsigned int rate_max = 0;
492         int i;
493
494         cs42l51->mclk = freq;
495
496         switch (cs42l51->func) {
497         case MODE_MASTER:
498                 return -EINVAL;
499         case MODE_SLAVE:
500                 ratios = slave_ratios;
501                 nr_ratios = ARRAY_SIZE(slave_ratios);
502                 break;
503         case MODE_SLAVE_AUTO:
504                 ratios = slave_auto_ratios;
505                 nr_ratios = ARRAY_SIZE(slave_auto_ratios);
506                 break;
507         }
508
509         for (i = 0; i < nr_ratios; i++) {
510                 unsigned int rate = freq / ratios[i].ratio;
511                 rates |= snd_pcm_rate_to_rate_bit(rate);
512                 if (rate < rate_min)
513                         rate_min = rate;
514                 if (rate > rate_max)
515                         rate_max = rate;
516         }
517         rates &= ~SNDRV_PCM_RATE_KNOT;
518
519         if (!rates) {
520                 dev_err(codec->dev, "could not find a valid sample rate\n");
521                 return -EINVAL;
522         }
523
524         codec_dai->playback.rates = rates;
525         codec_dai->playback.rate_min = rate_min;
526         codec_dai->playback.rate_max = rate_max;
527
528         codec_dai->capture.rates = rates;
529         codec_dai->capture.rate_min = rate_min;
530         codec_dai->capture.rate_max = rate_max;
531
532         return 0;
533 }
534
535 static int cs42l51_hw_params(struct snd_pcm_substream *substream,
536                 struct snd_pcm_hw_params *params,
537                 struct snd_soc_dai *dai)
538 {
539         struct snd_soc_pcm_runtime *rtd = substream->private_data;
540         struct snd_soc_device *socdev = rtd->socdev;
541         struct snd_soc_codec *codec = socdev->card->codec;
542         struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
543         int ret;
544         unsigned int i;
545         unsigned int rate;
546         unsigned int ratio;
547         struct cs42l51_ratios *ratios = NULL;
548         int nr_ratios = 0;
549         int intf_ctl, power_ctl, fmt;
550
551         switch (cs42l51->func) {
552         case MODE_MASTER:
553                 return -EINVAL;
554         case MODE_SLAVE:
555                 ratios = slave_ratios;
556                 nr_ratios = ARRAY_SIZE(slave_ratios);
557                 break;
558         case MODE_SLAVE_AUTO:
559                 ratios = slave_auto_ratios;
560                 nr_ratios = ARRAY_SIZE(slave_auto_ratios);
561                 break;
562         }
563
564         /* Figure out which MCLK/LRCK ratio to use */
565         rate = params_rate(params);     /* Sampling rate, in Hz */
566         ratio = cs42l51->mclk / rate;    /* MCLK/LRCK ratio */
567         for (i = 0; i < nr_ratios; i++) {
568                 if (ratios[i].ratio == ratio)
569                         break;
570         }
571
572         if (i == nr_ratios) {
573                 /* We did not find a matching ratio */
574                 dev_err(codec->dev, "could not find matching ratio\n");
575                 return -EINVAL;
576         }
577
578         intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
579         power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
580
581         intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
582                         | CS42L51_INTF_CTL_DAC_FORMAT(7));
583         power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
584                         | CS42L51_MIC_POWER_CTL_MCLK_DIV2);
585
586         switch (cs42l51->func) {
587         case MODE_MASTER:
588                 intf_ctl |= CS42L51_INTF_CTL_MASTER;
589                 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
590                 break;
591         case MODE_SLAVE:
592                 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
593                 break;
594         case MODE_SLAVE_AUTO:
595                 power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
596                 break;
597         }
598
599         switch (cs42l51->audio_mode) {
600         case SND_SOC_DAIFMT_I2S:
601                 intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
602                 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
603                 break;
604         case SND_SOC_DAIFMT_LEFT_J:
605                 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
606                 break;
607         case SND_SOC_DAIFMT_RIGHT_J:
608                 switch (params_format(params)) {
609                 case SNDRV_PCM_FORMAT_S16_LE:
610                 case SNDRV_PCM_FORMAT_S16_BE:
611                         fmt = CS42L51_DAC_DIF_RJ16;
612                         break;
613                 case SNDRV_PCM_FORMAT_S18_3LE:
614                 case SNDRV_PCM_FORMAT_S18_3BE:
615                         fmt = CS42L51_DAC_DIF_RJ18;
616                         break;
617                 case SNDRV_PCM_FORMAT_S20_3LE:
618                 case SNDRV_PCM_FORMAT_S20_3BE:
619                         fmt = CS42L51_DAC_DIF_RJ20;
620                         break;
621                 case SNDRV_PCM_FORMAT_S24_LE:
622                 case SNDRV_PCM_FORMAT_S24_BE:
623                         fmt = CS42L51_DAC_DIF_RJ24;
624                         break;
625                 default:
626                         dev_err(codec->dev, "unknown format\n");
627                         return -EINVAL;
628                 }
629                 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
630                 break;
631         default:
632                 dev_err(codec->dev, "unknown format\n");
633                 return -EINVAL;
634         }
635
636         if (ratios[i].mclk)
637                 power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
638
639         ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
640         if (ret < 0)
641                 return ret;
642
643         ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
644         if (ret < 0)
645                 return ret;
646
647         return 0;
648 }
649
650 static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
651 {
652         struct snd_soc_codec *codec = dai->codec;
653         int reg;
654         int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
655
656         reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
657
658         if (mute)
659                 reg |= mask;
660         else
661                 reg &= ~mask;
662
663         return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
664 }
665
666 static struct snd_soc_dai_ops cs42l51_dai_ops = {
667         .hw_params      = cs42l51_hw_params,
668         .set_sysclk     = cs42l51_set_dai_sysclk,
669         .set_fmt        = cs42l51_set_dai_fmt,
670         .digital_mute   = cs42l51_dai_mute,
671 };
672
673 struct snd_soc_dai cs42l51_dai = {
674         .name = "CS42L51 HiFi",
675         .playback = {
676                 .stream_name = "Playback",
677                 .channels_min = 1,
678                 .channels_max = 2,
679                 .rates = SNDRV_PCM_RATE_8000_96000,
680                 .formats = CS42L51_FORMATS,
681         },
682         .capture = {
683                 .stream_name = "Capture",
684                 .channels_min = 1,
685                 .channels_max = 2,
686                 .rates = SNDRV_PCM_RATE_8000_96000,
687                 .formats = CS42L51_FORMATS,
688         },
689         .ops = &cs42l51_dai_ops,
690 };
691 EXPORT_SYMBOL_GPL(cs42l51_dai);
692
693
694 static int cs42l51_probe(struct platform_device *pdev)
695 {
696         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
697         struct snd_soc_codec *codec;
698         int ret = 0;
699
700         if (!cs42l51_codec) {
701                 dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
702                 return -EINVAL;
703         }
704
705         socdev->card->codec = cs42l51_codec;
706         codec = socdev->card->codec;
707
708         /* Register PCMs */
709         ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
710         if (ret < 0) {
711                 dev_err(&pdev->dev, "failed to create PCMs\n");
712                 return ret;
713         }
714
715         snd_soc_add_controls(codec, cs42l51_snd_controls,
716                 ARRAY_SIZE(cs42l51_snd_controls));
717         snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
718                 ARRAY_SIZE(cs42l51_dapm_widgets));
719         snd_soc_dapm_add_routes(codec, cs42l51_routes,
720                 ARRAY_SIZE(cs42l51_routes));
721
722         return 0;
723 }
724
725
726 static int cs42l51_remove(struct platform_device *pdev)
727 {
728         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
729
730         snd_soc_free_pcms(socdev);
731         snd_soc_dapm_free(socdev);
732
733         return 0;
734 }
735
736 struct snd_soc_codec_device soc_codec_device_cs42l51 = {
737         .probe =        cs42l51_probe,
738         .remove =       cs42l51_remove
739 };
740 EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
741
742 static int __init cs42l51_init(void)
743 {
744         int ret;
745
746         ret = i2c_add_driver(&cs42l51_i2c_driver);
747         if (ret != 0) {
748                 printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
749                 return ret;
750         }
751         return 0;
752 }
753 module_init(cs42l51_init);
754
755 static void __exit cs42l51_exit(void)
756 {
757         i2c_del_driver(&cs42l51_i2c_driver);
758 }
759 module_exit(cs42l51_exit);
760
761 MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
762 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
763 MODULE_LICENSE("GPL");