powerpc/tm: Fix restoring FP/VMX facility incorrectly on interrupts
[sfrench/cifs-2.6.git] / sound / soc / codecs / cs42xx8.c
1 /*
2  * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
3  *
4  * Copyright (C) 2014 Freescale Semiconductor, Inc.
5  *
6  * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
7  *
8  * This file is licensed under the terms of the GNU General Public License
9  * version 2. This program is licensed "as is" without any warranty of any
10  * kind, whether express or implied.
11  */
12
13 #include <linux/clk.h>
14 #include <linux/delay.h>
15 #include <linux/module.h>
16 #include <linux/of_device.h>
17 #include <linux/gpio/consumer.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/regulator/consumer.h>
20 #include <sound/pcm_params.h>
21 #include <sound/soc.h>
22 #include <sound/tlv.h>
23
24 #include "cs42xx8.h"
25
26 #define CS42XX8_NUM_SUPPLIES 4
27 static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
28         "VA",
29         "VD",
30         "VLS",
31         "VLC",
32 };
33
34 #define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
35                          SNDRV_PCM_FMTBIT_S20_3LE | \
36                          SNDRV_PCM_FMTBIT_S24_LE | \
37                          SNDRV_PCM_FMTBIT_S32_LE)
38
39 /* codec private data */
40 struct cs42xx8_priv {
41         struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
42         const struct cs42xx8_driver_data *drvdata;
43         struct regmap *regmap;
44         struct clk *clk;
45
46         bool slave_mode;
47         unsigned long sysclk;
48         u32 tx_channels;
49         struct gpio_desc *gpiod_reset;
50 };
51
52 /* -127.5dB to 0dB with step of 0.5dB */
53 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
54 /* -64dB to 24dB with step of 0.5dB */
55 static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
56
57 static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
58 static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
59                                         "Soft Ramp", "Soft Ramp on Zero Cross" };
60
61 static const struct soc_enum adc1_single_enum =
62         SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
63 static const struct soc_enum adc2_single_enum =
64         SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
65 static const struct soc_enum adc3_single_enum =
66         SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
67 static const struct soc_enum dac_szc_enum =
68         SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
69 static const struct soc_enum adc_szc_enum =
70         SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
71
72 static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
73         SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
74                          CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
75         SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
76                          CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
77         SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
78                          CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
79         SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
80                          CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
81         SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
82                            CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
83         SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
84                            CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
85         SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
86         SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
87         SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
88         SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
89         SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
90         SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
91         SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
92         SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
93         SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
94         SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
95         SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
96         SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
97         SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
98         SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
99         SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
100         SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
101 };
102
103 static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
104         SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
105                            CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
106         SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
107         SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
108 };
109
110 static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
111         SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
112         SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
113         SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
114         SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
115
116         SND_SOC_DAPM_OUTPUT("AOUT1L"),
117         SND_SOC_DAPM_OUTPUT("AOUT1R"),
118         SND_SOC_DAPM_OUTPUT("AOUT2L"),
119         SND_SOC_DAPM_OUTPUT("AOUT2R"),
120         SND_SOC_DAPM_OUTPUT("AOUT3L"),
121         SND_SOC_DAPM_OUTPUT("AOUT3R"),
122         SND_SOC_DAPM_OUTPUT("AOUT4L"),
123         SND_SOC_DAPM_OUTPUT("AOUT4R"),
124
125         SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
126         SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
127
128         SND_SOC_DAPM_INPUT("AIN1L"),
129         SND_SOC_DAPM_INPUT("AIN1R"),
130         SND_SOC_DAPM_INPUT("AIN2L"),
131         SND_SOC_DAPM_INPUT("AIN2R"),
132
133         SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
134 };
135
136 static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
137         SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
138
139         SND_SOC_DAPM_INPUT("AIN3L"),
140         SND_SOC_DAPM_INPUT("AIN3R"),
141 };
142
143 static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
144         /* Playback */
145         { "AOUT1L", NULL, "DAC1" },
146         { "AOUT1R", NULL, "DAC1" },
147         { "DAC1", NULL, "PWR" },
148
149         { "AOUT2L", NULL, "DAC2" },
150         { "AOUT2R", NULL, "DAC2" },
151         { "DAC2", NULL, "PWR" },
152
153         { "AOUT3L", NULL, "DAC3" },
154         { "AOUT3R", NULL, "DAC3" },
155         { "DAC3", NULL, "PWR" },
156
157         { "AOUT4L", NULL, "DAC4" },
158         { "AOUT4R", NULL, "DAC4" },
159         { "DAC4", NULL, "PWR" },
160
161         /* Capture */
162         { "ADC1", NULL, "AIN1L" },
163         { "ADC1", NULL, "AIN1R" },
164         { "ADC1", NULL, "PWR" },
165
166         { "ADC2", NULL, "AIN2L" },
167         { "ADC2", NULL, "AIN2R" },
168         { "ADC2", NULL, "PWR" },
169 };
170
171 static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
172         /* Capture */
173         { "ADC3", NULL, "AIN3L" },
174         { "ADC3", NULL, "AIN3R" },
175         { "ADC3", NULL, "PWR" },
176 };
177
178 struct cs42xx8_ratios {
179         unsigned int ratio;
180         unsigned char speed;
181         unsigned char mclk;
182 };
183
184 static const struct cs42xx8_ratios cs42xx8_ratios[] = {
185         { 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
186         { 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
187         { 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
188         { 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
189         { 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
190         { 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
191         { 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
192         { 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
193         { 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
194 };
195
196 static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
197                                   int clk_id, unsigned int freq, int dir)
198 {
199         struct snd_soc_component *component = codec_dai->component;
200         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
201
202         cs42xx8->sysclk = freq;
203
204         return 0;
205 }
206
207 static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
208                                unsigned int format)
209 {
210         struct snd_soc_component *component = codec_dai->component;
211         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
212         u32 val;
213
214         /* Set DAI format */
215         switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
216         case SND_SOC_DAIFMT_LEFT_J:
217                 val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
218                 break;
219         case SND_SOC_DAIFMT_I2S:
220                 val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
221                 break;
222         case SND_SOC_DAIFMT_RIGHT_J:
223                 val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
224                 break;
225         case SND_SOC_DAIFMT_DSP_A:
226                 val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
227                 break;
228         default:
229                 dev_err(component->dev, "unsupported dai format\n");
230                 return -EINVAL;
231         }
232
233         regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
234                            CS42XX8_INTF_DAC_DIF_MASK |
235                            CS42XX8_INTF_ADC_DIF_MASK, val);
236
237         /* Set master/slave audio interface */
238         switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
239         case SND_SOC_DAIFMT_CBS_CFS:
240                 cs42xx8->slave_mode = true;
241                 break;
242         case SND_SOC_DAIFMT_CBM_CFM:
243                 cs42xx8->slave_mode = false;
244                 break;
245         default:
246                 dev_err(component->dev, "unsupported master/slave mode\n");
247                 return -EINVAL;
248         }
249
250         return 0;
251 }
252
253 static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
254                              struct snd_pcm_hw_params *params,
255                              struct snd_soc_dai *dai)
256 {
257         struct snd_soc_component *component = dai->component;
258         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
259         bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
260         u32 ratio = cs42xx8->sysclk / params_rate(params);
261         u32 i, fm, val, mask;
262
263         if (tx)
264                 cs42xx8->tx_channels = params_channels(params);
265
266         for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
267                 if (cs42xx8_ratios[i].ratio == ratio)
268                         break;
269         }
270
271         if (i == ARRAY_SIZE(cs42xx8_ratios)) {
272                 dev_err(component->dev, "unsupported sysclk ratio\n");
273                 return -EINVAL;
274         }
275
276         mask = CS42XX8_FUNCMOD_MFREQ_MASK;
277         val = cs42xx8_ratios[i].mclk;
278
279         fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
280
281         regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
282                            CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
283                            CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
284
285         return 0;
286 }
287
288 static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
289 {
290         struct snd_soc_component *component = dai->component;
291         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
292         u8 dac_unmute = cs42xx8->tx_channels ?
293                         ~((0x1 << cs42xx8->tx_channels) - 1) : 0;
294
295         regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,
296                      mute ? CS42XX8_DACMUTE_ALL : dac_unmute);
297
298         return 0;
299 }
300
301 static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
302         .set_fmt        = cs42xx8_set_dai_fmt,
303         .set_sysclk     = cs42xx8_set_dai_sysclk,
304         .hw_params      = cs42xx8_hw_params,
305         .digital_mute   = cs42xx8_digital_mute,
306 };
307
308 static struct snd_soc_dai_driver cs42xx8_dai = {
309         .playback = {
310                 .stream_name = "Playback",
311                 .channels_min = 1,
312                 .channels_max = 8,
313                 .rates = SNDRV_PCM_RATE_8000_192000,
314                 .formats = CS42XX8_FORMATS,
315         },
316         .capture = {
317                 .stream_name = "Capture",
318                 .channels_min = 1,
319                 .rates = SNDRV_PCM_RATE_8000_192000,
320                 .formats = CS42XX8_FORMATS,
321         },
322         .ops = &cs42xx8_dai_ops,
323 };
324
325 static const struct reg_default cs42xx8_reg[] = {
326         { 0x02, 0x00 },   /* Power Control */
327         { 0x03, 0xF0 },   /* Functional Mode */
328         { 0x04, 0x46 },   /* Interface Formats */
329         { 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */
330         { 0x06, 0x10 },   /* Transition Control */
331         { 0x07, 0x00 },   /* DAC Channel Mute */
332         { 0x08, 0x00 },   /* Volume Control AOUT1 */
333         { 0x09, 0x00 },   /* Volume Control AOUT2 */
334         { 0x0a, 0x00 },   /* Volume Control AOUT3 */
335         { 0x0b, 0x00 },   /* Volume Control AOUT4 */
336         { 0x0c, 0x00 },   /* Volume Control AOUT5 */
337         { 0x0d, 0x00 },   /* Volume Control AOUT6 */
338         { 0x0e, 0x00 },   /* Volume Control AOUT7 */
339         { 0x0f, 0x00 },   /* Volume Control AOUT8 */
340         { 0x10, 0x00 },   /* DAC Channel Invert */
341         { 0x11, 0x00 },   /* Volume Control AIN1 */
342         { 0x12, 0x00 },   /* Volume Control AIN2 */
343         { 0x13, 0x00 },   /* Volume Control AIN3 */
344         { 0x14, 0x00 },   /* Volume Control AIN4 */
345         { 0x15, 0x00 },   /* Volume Control AIN5 */
346         { 0x16, 0x00 },   /* Volume Control AIN6 */
347         { 0x17, 0x00 },   /* ADC Channel Invert */
348         { 0x18, 0x00 },   /* Status Control */
349         { 0x1a, 0x00 },   /* Status Mask */
350         { 0x1b, 0x00 },   /* MUTEC Pin Control */
351 };
352
353 static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
354 {
355         switch (reg) {
356         case CS42XX8_STATUS:
357                 return true;
358         default:
359                 return false;
360         }
361 }
362
363 static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
364 {
365         switch (reg) {
366         case CS42XX8_CHIPID:
367         case CS42XX8_STATUS:
368                 return false;
369         default:
370                 return true;
371         }
372 }
373
374 const struct regmap_config cs42xx8_regmap_config = {
375         .reg_bits = 8,
376         .val_bits = 8,
377
378         .max_register = CS42XX8_LASTREG,
379         .reg_defaults = cs42xx8_reg,
380         .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
381         .volatile_reg = cs42xx8_volatile_register,
382         .writeable_reg = cs42xx8_writeable_register,
383         .cache_type = REGCACHE_RBTREE,
384 };
385 EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
386
387 static int cs42xx8_component_probe(struct snd_soc_component *component)
388 {
389         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
390         struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
391
392         switch (cs42xx8->drvdata->num_adcs) {
393         case 3:
394                 snd_soc_add_component_controls(component, cs42xx8_adc3_snd_controls,
395                                         ARRAY_SIZE(cs42xx8_adc3_snd_controls));
396                 snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
397                                         ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
398                 snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
399                                         ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
400                 break;
401         default:
402                 break;
403         }
404
405         /* Mute all DAC channels */
406         regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
407
408         return 0;
409 }
410
411 static const struct snd_soc_component_driver cs42xx8_driver = {
412         .probe                  = cs42xx8_component_probe,
413         .controls               = cs42xx8_snd_controls,
414         .num_controls           = ARRAY_SIZE(cs42xx8_snd_controls),
415         .dapm_widgets           = cs42xx8_dapm_widgets,
416         .num_dapm_widgets       = ARRAY_SIZE(cs42xx8_dapm_widgets),
417         .dapm_routes            = cs42xx8_dapm_routes,
418         .num_dapm_routes        = ARRAY_SIZE(cs42xx8_dapm_routes),
419         .use_pmdown_time        = 1,
420         .endianness             = 1,
421         .non_legacy_dai_naming  = 1,
422 };
423
424 const struct cs42xx8_driver_data cs42448_data = {
425         .name = "cs42448",
426         .num_adcs = 3,
427 };
428 EXPORT_SYMBOL_GPL(cs42448_data);
429
430 const struct cs42xx8_driver_data cs42888_data = {
431         .name = "cs42888",
432         .num_adcs = 2,
433 };
434 EXPORT_SYMBOL_GPL(cs42888_data);
435
436 const struct of_device_id cs42xx8_of_match[] = {
437         { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
438         { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
439         { /* sentinel */ }
440 };
441 MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
442 EXPORT_SYMBOL_GPL(cs42xx8_of_match);
443
444 int cs42xx8_probe(struct device *dev, struct regmap *regmap)
445 {
446         const struct of_device_id *of_id;
447         struct cs42xx8_priv *cs42xx8;
448         int ret, val, i;
449
450         if (IS_ERR(regmap)) {
451                 ret = PTR_ERR(regmap);
452                 dev_err(dev, "failed to allocate regmap: %d\n", ret);
453                 return ret;
454         }
455
456         cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
457         if (cs42xx8 == NULL)
458                 return -ENOMEM;
459
460         cs42xx8->regmap = regmap;
461         dev_set_drvdata(dev, cs42xx8);
462
463         of_id = of_match_device(cs42xx8_of_match, dev);
464         if (of_id)
465                 cs42xx8->drvdata = of_id->data;
466
467         if (!cs42xx8->drvdata) {
468                 dev_err(dev, "failed to find driver data\n");
469                 return -EINVAL;
470         }
471
472         cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
473                                                         GPIOD_OUT_HIGH);
474         if (IS_ERR(cs42xx8->gpiod_reset))
475                 return PTR_ERR(cs42xx8->gpiod_reset);
476
477         gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
478
479         cs42xx8->clk = devm_clk_get(dev, "mclk");
480         if (IS_ERR(cs42xx8->clk)) {
481                 dev_err(dev, "failed to get the clock: %ld\n",
482                                 PTR_ERR(cs42xx8->clk));
483                 return -EINVAL;
484         }
485
486         cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
487
488         for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
489                 cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
490
491         ret = devm_regulator_bulk_get(dev,
492                         ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
493         if (ret) {
494                 dev_err(dev, "failed to request supplies: %d\n", ret);
495                 return ret;
496         }
497
498         ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
499                                     cs42xx8->supplies);
500         if (ret) {
501                 dev_err(dev, "failed to enable supplies: %d\n", ret);
502                 return ret;
503         }
504
505         /* Make sure hardware reset done */
506         msleep(5);
507
508         /* Validate the chip ID */
509         ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
510         if (ret < 0) {
511                 dev_err(dev, "failed to get device ID, ret = %d", ret);
512                 goto err_enable;
513         }
514
515         /* The top four bits of the chip ID should be 0000 */
516         if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {
517                 dev_err(dev, "unmatched chip ID: %d\n",
518                         (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);
519                 ret = -EINVAL;
520                 goto err_enable;
521         }
522
523         dev_info(dev, "found device, revision %X\n",
524                         val & CS42XX8_CHIPID_REV_ID_MASK);
525
526         cs42xx8_dai.name = cs42xx8->drvdata->name;
527
528         /* Each adc supports stereo input */
529         cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
530
531         ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
532         if (ret) {
533                 dev_err(dev, "failed to register component:%d\n", ret);
534                 goto err_enable;
535         }
536
537         regcache_cache_only(cs42xx8->regmap, true);
538
539 err_enable:
540         regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
541                                cs42xx8->supplies);
542
543         return ret;
544 }
545 EXPORT_SYMBOL_GPL(cs42xx8_probe);
546
547 #ifdef CONFIG_PM
548 static int cs42xx8_runtime_resume(struct device *dev)
549 {
550         struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
551         int ret;
552
553         ret = clk_prepare_enable(cs42xx8->clk);
554         if (ret) {
555                 dev_err(dev, "failed to enable mclk: %d\n", ret);
556                 return ret;
557         }
558
559         gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
560
561         ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
562                                     cs42xx8->supplies);
563         if (ret) {
564                 dev_err(dev, "failed to enable supplies: %d\n", ret);
565                 goto err_clk;
566         }
567
568         /* Make sure hardware reset done */
569         msleep(5);
570
571         regcache_cache_only(cs42xx8->regmap, false);
572         regcache_mark_dirty(cs42xx8->regmap);
573
574         ret = regcache_sync(cs42xx8->regmap);
575         if (ret) {
576                 dev_err(dev, "failed to sync regmap: %d\n", ret);
577                 goto err_bulk;
578         }
579
580         return 0;
581
582 err_bulk:
583         regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
584                                cs42xx8->supplies);
585 err_clk:
586         clk_disable_unprepare(cs42xx8->clk);
587
588         return ret;
589 }
590
591 static int cs42xx8_runtime_suspend(struct device *dev)
592 {
593         struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
594
595         regcache_cache_only(cs42xx8->regmap, true);
596
597         regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
598                                cs42xx8->supplies);
599
600         gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1);
601
602         clk_disable_unprepare(cs42xx8->clk);
603
604         return 0;
605 }
606 #endif
607
608 const struct dev_pm_ops cs42xx8_pm = {
609         SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
610 };
611 EXPORT_SYMBOL_GPL(cs42xx8_pm);
612
613 MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
614 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
615 MODULE_LICENSE("GPL");