Merge tag 'tty-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[linux-2.6-microblaze.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/clk.h>
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <sound/core.h>
28 #include <sound/soc.h>
29 #include <sound/tlv.h>
30 #include <sound/initval.h>
31 #include <sound/pcm_params.h>
32 #include <sound/pcm.h>
33 #include <linux/regmap.h>
34
35 #include "cs42l51.h"
36
37 enum master_slave_mode {
38         MODE_SLAVE,
39         MODE_SLAVE_AUTO,
40         MODE_MASTER,
41 };
42
43 struct cs42l51_private {
44         unsigned int mclk;
45         struct clk *mclk_handle;
46         unsigned int audio_mode;        /* The mode (I2S or left-justified) */
47         enum master_slave_mode func;
48 };
49
50 #define CS42L51_FORMATS ( \
51                 SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
52                 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
53                 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
54                 SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
55
56 static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
57                         struct snd_ctl_elem_value *ucontrol)
58 {
59         struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
60         unsigned long value = snd_soc_component_read32(component, CS42L51_PCM_MIXER)&3;
61
62         switch (value) {
63         default:
64         case 0:
65                 ucontrol->value.enumerated.item[0] = 0;
66                 break;
67         /* same value : (L+R)/2 and (R+L)/2 */
68         case 1:
69         case 2:
70                 ucontrol->value.enumerated.item[0] = 1;
71                 break;
72         case 3:
73                 ucontrol->value.enumerated.item[0] = 2;
74                 break;
75         }
76
77         return 0;
78 }
79
80 #define CHAN_MIX_NORMAL 0x00
81 #define CHAN_MIX_BOTH   0x55
82 #define CHAN_MIX_SWAP   0xFF
83
84 static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
85                         struct snd_ctl_elem_value *ucontrol)
86 {
87         struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
88         unsigned char val;
89
90         switch (ucontrol->value.enumerated.item[0]) {
91         default:
92         case 0:
93                 val = CHAN_MIX_NORMAL;
94                 break;
95         case 1:
96                 val = CHAN_MIX_BOTH;
97                 break;
98         case 2:
99                 val = CHAN_MIX_SWAP;
100                 break;
101         }
102
103         snd_soc_component_write(component, CS42L51_PCM_MIXER, val);
104
105         return 1;
106 }
107
108 static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
109 static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
110
111 static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
112
113 static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
114 static const char *chan_mix[] = {
115         "L R",
116         "L+R",
117         "R L",
118 };
119
120 static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix);
121
122 static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
123         SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
124                         CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
125                         0, 0x19, 0x7F, adc_pcm_tlv),
126         SOC_DOUBLE_R("PCM Playback Switch",
127                         CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
128         SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
129                         CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
130                         0, 0x34, 0xE4, aout_tlv),
131         SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
132                         CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
133                         0, 0x19, 0x7F, adc_pcm_tlv),
134         SOC_DOUBLE_R("ADC Mixer Switch",
135                         CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
136         SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
137         SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
138         SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
139         SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
140         SOC_DOUBLE_TLV("Mic Boost Volume",
141                         CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
142         SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
143         SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
144         SOC_ENUM_EXT("PCM channel mixer",
145                         cs42l51_chan_mix,
146                         cs42l51_get_chan_mix, cs42l51_set_chan_mix),
147 };
148
149 /*
150  * to power down, one must:
151  * 1.) Enable the PDN bit
152  * 2.) enable power-down for the select channels
153  * 3.) disable the PDN bit.
154  */
155 static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
156                 struct snd_kcontrol *kcontrol, int event)
157 {
158         struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
159
160         switch (event) {
161         case SND_SOC_DAPM_PRE_PMD:
162                 snd_soc_component_update_bits(component, CS42L51_POWER_CTL1,
163                                     CS42L51_POWER_CTL1_PDN,
164                                     CS42L51_POWER_CTL1_PDN);
165                 break;
166         default:
167         case SND_SOC_DAPM_POST_PMD:
168                 snd_soc_component_update_bits(component, CS42L51_POWER_CTL1,
169                                     CS42L51_POWER_CTL1_PDN, 0);
170                 break;
171         }
172
173         return 0;
174 }
175
176 static const char *cs42l51_dac_names[] = {"Direct PCM",
177         "DSP PCM", "ADC"};
178 static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum,
179                             CS42L51_DAC_CTL, 6, cs42l51_dac_names);
180 static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
181         SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
182
183 static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
184         "MIC Left", "MIC+preamp Left"};
185 static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum,
186                             CS42L51_ADC_INPUT, 4, cs42l51_adcl_names);
187 static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
188         SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
189
190 static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
191         "MIC Right", "MIC+preamp Right"};
192 static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum,
193                             CS42L51_ADC_INPUT, 6, cs42l51_adcr_names);
194 static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
195         SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
196
197 static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
198         SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
199         SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
200                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
201         SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
202                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
203         SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
204                 CS42L51_POWER_CTL1, 1, 1,
205                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
206         SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
207                 CS42L51_POWER_CTL1, 2, 1,
208                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
209         SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
210                 CS42L51_POWER_CTL1, 5, 1,
211                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
212         SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
213                 CS42L51_POWER_CTL1, 6, 1,
214                 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
215
216         /* analog/mic */
217         SND_SOC_DAPM_INPUT("AIN1L"),
218         SND_SOC_DAPM_INPUT("AIN1R"),
219         SND_SOC_DAPM_INPUT("AIN2L"),
220         SND_SOC_DAPM_INPUT("AIN2R"),
221         SND_SOC_DAPM_INPUT("MICL"),
222         SND_SOC_DAPM_INPUT("MICR"),
223
224         SND_SOC_DAPM_MIXER("Mic Preamp Left",
225                 CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
226         SND_SOC_DAPM_MIXER("Mic Preamp Right",
227                 CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
228
229         /* HP */
230         SND_SOC_DAPM_OUTPUT("HPL"),
231         SND_SOC_DAPM_OUTPUT("HPR"),
232
233         /* mux */
234         SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
235                 &cs42l51_dac_mux_controls),
236         SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
237                 &cs42l51_adcl_mux_controls),
238         SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
239                 &cs42l51_adcr_mux_controls),
240 };
241
242 static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = {
243         SND_SOC_DAPM_CLOCK_SUPPLY("MCLK")
244 };
245
246 static const struct snd_soc_dapm_route cs42l51_routes[] = {
247         {"HPL", NULL, "Left DAC"},
248         {"HPR", NULL, "Right DAC"},
249
250         {"Left ADC", NULL, "Left PGA"},
251         {"Right ADC", NULL, "Right PGA"},
252
253         {"Mic Preamp Left",  NULL,  "MICL"},
254         {"Mic Preamp Right", NULL,  "MICR"},
255
256         {"PGA-ADC Mux Left",  "AIN1 Left",        "AIN1L" },
257         {"PGA-ADC Mux Left",  "AIN2 Left",        "AIN2L" },
258         {"PGA-ADC Mux Left",  "MIC Left",         "MICL"  },
259         {"PGA-ADC Mux Left",  "MIC+preamp Left",  "Mic Preamp Left" },
260         {"PGA-ADC Mux Right", "AIN1 Right",       "AIN1R" },
261         {"PGA-ADC Mux Right", "AIN2 Right",       "AIN2R" },
262         {"PGA-ADC Mux Right", "MIC Right",        "MICR" },
263         {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
264
265         {"Left PGA", NULL, "PGA-ADC Mux Left"},
266         {"Right PGA", NULL, "PGA-ADC Mux Right"},
267 };
268
269 static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
270                 unsigned int format)
271 {
272         struct snd_soc_component *component = codec_dai->component;
273         struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
274
275         switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
276         case SND_SOC_DAIFMT_I2S:
277         case SND_SOC_DAIFMT_LEFT_J:
278         case SND_SOC_DAIFMT_RIGHT_J:
279                 cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
280                 break;
281         default:
282                 dev_err(component->dev, "invalid DAI format\n");
283                 return -EINVAL;
284         }
285
286         switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
287         case SND_SOC_DAIFMT_CBM_CFM:
288                 cs42l51->func = MODE_MASTER;
289                 break;
290         case SND_SOC_DAIFMT_CBS_CFS:
291                 cs42l51->func = MODE_SLAVE_AUTO;
292                 break;
293         default:
294                 dev_err(component->dev, "Unknown master/slave configuration\n");
295                 return -EINVAL;
296         }
297
298         return 0;
299 }
300
301 struct cs42l51_ratios {
302         unsigned int ratio;
303         unsigned char speed_mode;
304         unsigned char mclk;
305 };
306
307 static struct cs42l51_ratios slave_ratios[] = {
308         {  512, CS42L51_QSM_MODE, 0 }, {  768, CS42L51_QSM_MODE, 0 },
309         { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
310         { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
311         {  256, CS42L51_HSM_MODE, 0 }, {  384, CS42L51_HSM_MODE, 0 },
312         {  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
313         { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
314         {  128, CS42L51_SSM_MODE, 0 }, {  192, CS42L51_SSM_MODE, 0 },
315         {  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
316         {  512, CS42L51_SSM_MODE, 0 }, {  768, CS42L51_SSM_MODE, 0 },
317         {  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
318         {  256, CS42L51_DSM_MODE, 0 }, {  384, CS42L51_DSM_MODE, 0 },
319 };
320
321 static struct cs42l51_ratios slave_auto_ratios[] = {
322         { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
323         { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
324         {  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
325         { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
326         {  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
327         {  512, CS42L51_SSM_MODE, 1 }, {  768, CS42L51_SSM_MODE, 1 },
328         {  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
329         {  256, CS42L51_DSM_MODE, 1 }, {  384, CS42L51_DSM_MODE, 1 },
330 };
331
332 static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
333                 int clk_id, unsigned int freq, int dir)
334 {
335         struct snd_soc_component *component = codec_dai->component;
336         struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
337
338         cs42l51->mclk = freq;
339         return 0;
340 }
341
342 static int cs42l51_hw_params(struct snd_pcm_substream *substream,
343                 struct snd_pcm_hw_params *params,
344                 struct snd_soc_dai *dai)
345 {
346         struct snd_soc_component *component = dai->component;
347         struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
348         int ret;
349         unsigned int i;
350         unsigned int rate;
351         unsigned int ratio;
352         struct cs42l51_ratios *ratios = NULL;
353         int nr_ratios = 0;
354         int intf_ctl, power_ctl, fmt;
355
356         switch (cs42l51->func) {
357         case MODE_MASTER:
358                 return -EINVAL;
359         case MODE_SLAVE:
360                 ratios = slave_ratios;
361                 nr_ratios = ARRAY_SIZE(slave_ratios);
362                 break;
363         case MODE_SLAVE_AUTO:
364                 ratios = slave_auto_ratios;
365                 nr_ratios = ARRAY_SIZE(slave_auto_ratios);
366                 break;
367         }
368
369         /* Figure out which MCLK/LRCK ratio to use */
370         rate = params_rate(params);     /* Sampling rate, in Hz */
371         ratio = cs42l51->mclk / rate;    /* MCLK/LRCK ratio */
372         for (i = 0; i < nr_ratios; i++) {
373                 if (ratios[i].ratio == ratio)
374                         break;
375         }
376
377         if (i == nr_ratios) {
378                 /* We did not find a matching ratio */
379                 dev_err(component->dev, "could not find matching ratio\n");
380                 return -EINVAL;
381         }
382
383         intf_ctl = snd_soc_component_read32(component, CS42L51_INTF_CTL);
384         power_ctl = snd_soc_component_read32(component, CS42L51_MIC_POWER_CTL);
385
386         intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
387                         | CS42L51_INTF_CTL_DAC_FORMAT(7));
388         power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
389                         | CS42L51_MIC_POWER_CTL_MCLK_DIV2);
390
391         switch (cs42l51->func) {
392         case MODE_MASTER:
393                 intf_ctl |= CS42L51_INTF_CTL_MASTER;
394                 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
395                 break;
396         case MODE_SLAVE:
397                 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
398                 break;
399         case MODE_SLAVE_AUTO:
400                 power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
401                 break;
402         }
403
404         switch (cs42l51->audio_mode) {
405         case SND_SOC_DAIFMT_I2S:
406                 intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
407                 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
408                 break;
409         case SND_SOC_DAIFMT_LEFT_J:
410                 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
411                 break;
412         case SND_SOC_DAIFMT_RIGHT_J:
413                 switch (params_width(params)) {
414                 case 16:
415                         fmt = CS42L51_DAC_DIF_RJ16;
416                         break;
417                 case 18:
418                         fmt = CS42L51_DAC_DIF_RJ18;
419                         break;
420                 case 20:
421                         fmt = CS42L51_DAC_DIF_RJ20;
422                         break;
423                 case 24:
424                         fmt = CS42L51_DAC_DIF_RJ24;
425                         break;
426                 default:
427                         dev_err(component->dev, "unknown format\n");
428                         return -EINVAL;
429                 }
430                 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
431                 break;
432         default:
433                 dev_err(component->dev, "unknown format\n");
434                 return -EINVAL;
435         }
436
437         if (ratios[i].mclk)
438                 power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
439
440         ret = snd_soc_component_write(component, CS42L51_INTF_CTL, intf_ctl);
441         if (ret < 0)
442                 return ret;
443
444         ret = snd_soc_component_write(component, CS42L51_MIC_POWER_CTL, power_ctl);
445         if (ret < 0)
446                 return ret;
447
448         return 0;
449 }
450
451 static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
452 {
453         struct snd_soc_component *component = dai->component;
454         int reg;
455         int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
456
457         reg = snd_soc_component_read32(component, CS42L51_DAC_OUT_CTL);
458
459         if (mute)
460                 reg |= mask;
461         else
462                 reg &= ~mask;
463
464         return snd_soc_component_write(component, CS42L51_DAC_OUT_CTL, reg);
465 }
466
467 static const struct snd_soc_dai_ops cs42l51_dai_ops = {
468         .hw_params      = cs42l51_hw_params,
469         .set_sysclk     = cs42l51_set_dai_sysclk,
470         .set_fmt        = cs42l51_set_dai_fmt,
471         .digital_mute   = cs42l51_dai_mute,
472 };
473
474 static struct snd_soc_dai_driver cs42l51_dai = {
475         .name = "cs42l51-hifi",
476         .playback = {
477                 .stream_name = "Playback",
478                 .channels_min = 1,
479                 .channels_max = 2,
480                 .rates = SNDRV_PCM_RATE_8000_96000,
481                 .formats = CS42L51_FORMATS,
482         },
483         .capture = {
484                 .stream_name = "Capture",
485                 .channels_min = 1,
486                 .channels_max = 2,
487                 .rates = SNDRV_PCM_RATE_8000_96000,
488                 .formats = CS42L51_FORMATS,
489         },
490         .ops = &cs42l51_dai_ops,
491 };
492
493 static int cs42l51_component_probe(struct snd_soc_component *component)
494 {
495         int ret, reg;
496         struct snd_soc_dapm_context *dapm;
497         struct cs42l51_private *cs42l51;
498
499         cs42l51 = snd_soc_component_get_drvdata(component);
500         dapm = snd_soc_component_get_dapm(component);
501
502         if (cs42l51->mclk_handle)
503                 snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1);
504
505         /*
506          * DAC configuration
507          * - Use signal processor
508          * - auto mute
509          * - vol changes immediate
510          * - no de-emphasize
511          */
512         reg = CS42L51_DAC_CTL_DATA_SEL(1)
513                 | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
514         ret = snd_soc_component_write(component, CS42L51_DAC_CTL, reg);
515         if (ret < 0)
516                 return ret;
517
518         return 0;
519 }
520
521 static const struct snd_soc_component_driver soc_component_device_cs42l51 = {
522         .probe                  = cs42l51_component_probe,
523         .controls               = cs42l51_snd_controls,
524         .num_controls           = ARRAY_SIZE(cs42l51_snd_controls),
525         .dapm_widgets           = cs42l51_dapm_widgets,
526         .num_dapm_widgets       = ARRAY_SIZE(cs42l51_dapm_widgets),
527         .dapm_routes            = cs42l51_routes,
528         .num_dapm_routes        = ARRAY_SIZE(cs42l51_routes),
529         .idle_bias_on           = 1,
530         .use_pmdown_time        = 1,
531         .endianness             = 1,
532         .non_legacy_dai_naming  = 1,
533 };
534
535 const struct regmap_config cs42l51_regmap = {
536         .max_register = CS42L51_CHARGE_FREQ,
537         .cache_type = REGCACHE_RBTREE,
538 };
539 EXPORT_SYMBOL_GPL(cs42l51_regmap);
540
541 int cs42l51_probe(struct device *dev, struct regmap *regmap)
542 {
543         struct cs42l51_private *cs42l51;
544         unsigned int val;
545         int ret;
546
547         if (IS_ERR(regmap))
548                 return PTR_ERR(regmap);
549
550         cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private),
551                                GFP_KERNEL);
552         if (!cs42l51)
553                 return -ENOMEM;
554
555         dev_set_drvdata(dev, cs42l51);
556
557         cs42l51->mclk_handle = devm_clk_get(dev, "MCLK");
558         if (IS_ERR(cs42l51->mclk_handle)) {
559                 if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT)
560                         return PTR_ERR(cs42l51->mclk_handle);
561                 cs42l51->mclk_handle = NULL;
562         }
563
564         /* Verify that we have a CS42L51 */
565         ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
566         if (ret < 0) {
567                 dev_err(dev, "failed to read I2C\n");
568                 goto error;
569         }
570
571         if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
572             (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
573                 dev_err(dev, "Invalid chip id: %x\n", val);
574                 ret = -ENODEV;
575                 goto error;
576         }
577         dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n",
578                  val & CS42L51_CHIP_REV_MASK);
579
580         ret = devm_snd_soc_register_component(dev,
581                         &soc_component_device_cs42l51, &cs42l51_dai, 1);
582 error:
583         return ret;
584 }
585 EXPORT_SYMBOL_GPL(cs42l51_probe);
586
587 const struct of_device_id cs42l51_of_match[] = {
588         { .compatible = "cirrus,cs42l51", },
589         { }
590 };
591 MODULE_DEVICE_TABLE(of, cs42l51_of_match);
592 EXPORT_SYMBOL_GPL(cs42l51_of_match);
593
594 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
595 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
596 MODULE_LICENSE("GPL");