0293763debe5811160fb3b7cc23284a91df2a94a
[linux-3.10.git] / sound / soc / codecs / wm8958-dsp2.c
1 /*
2  * wm8958-dsp2.c  --  WM8958 DSP2 support
3  *
4  * Copyright 2011 Wolfson Microelectronics plc
5  *
6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/init.h>
16 #include <linux/delay.h>
17 #include <linux/pm.h>
18 #include <linux/i2c.h>
19 #include <linux/platform_device.h>
20 #include <linux/slab.h>
21 #include <sound/soc.h>
22 #include <sound/initval.h>
23 #include <sound/tlv.h>
24 #include <trace/events/asoc.h>
25
26 #include <linux/mfd/wm8994/core.h>
27 #include <linux/mfd/wm8994/registers.h>
28 #include <linux/mfd/wm8994/pdata.h>
29 #include <linux/mfd/wm8994/gpio.h>
30
31 #include "wm8994.h"
32
33 #define WM_FW_BLOCK_INFO 0xff
34 #define WM_FW_BLOCK_PM   0x00
35 #define WM_FW_BLOCK_X    0x01
36 #define WM_FW_BLOCK_Y    0x02
37 #define WM_FW_BLOCK_Z    0x03
38 #define WM_FW_BLOCK_I    0x06
39 #define WM_FW_BLOCK_A    0x08
40 #define WM_FW_BLOCK_C    0x0c
41
42 static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
43                           const struct firmware *fw, bool check)
44 {
45         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
46         u64 data64;
47         u32 data32;
48         const u8 *data;
49         char *str;
50         size_t block_len, len;
51         int ret = 0;
52
53         /* Suppress unneeded downloads */
54         if (wm8994->cur_fw == fw)
55                 return 0;
56
57         if (fw->size < 32) {
58                 dev_err(codec->dev, "%s: firmware too short\n", name);
59                 goto err;
60         }
61
62         if (memcmp(fw->data, "WMFW", 4) != 0) {
63                 dev_err(codec->dev, "%s: firmware has bad file magic %08x\n",
64                         name, data32);
65                 goto err;
66         }
67
68         memcpy(&data32, fw->data + 4, sizeof(data32));
69         len = be32_to_cpu(data32);
70
71         memcpy(&data32, fw->data + 8, sizeof(data32));
72         data32 = be32_to_cpu(data32);
73         if ((data32 >> 24) & 0xff) {
74                 dev_err(codec->dev, "%s: unsupported firmware version %d\n",
75                         name, (data32 >> 24) & 0xff);
76                 goto err;
77         }
78         if ((data32 & 0xffff) != 8958) {
79                 dev_err(codec->dev, "%s: unsupported target device %d\n",
80                         name, data32 & 0xffff);
81                 goto err;
82         }
83         if (((data32 >> 16) & 0xff) != 0xc) {
84                 dev_err(codec->dev, "%s: unsupported target core %d\n",
85                         name, (data32 >> 16) & 0xff);
86                 goto err;
87         }
88
89         if (check) {
90                 memcpy(&data64, fw->data + 24, sizeof(u64));
91                 dev_info(codec->dev, "%s timestamp %llx\n",
92                          name, be64_to_cpu(data64));
93         } else {
94                 snd_soc_write(codec, 0x102, 0x2);
95                 snd_soc_write(codec, 0x900, 0x2);
96         }
97
98         data = fw->data + len;
99         len = fw->size - len;
100         while (len) {
101                 if (len < 12) {
102                         dev_err(codec->dev, "%s short data block of %zd\n",
103                                 name, len);
104                         goto err;
105                 }
106
107                 memcpy(&data32, data + 4, sizeof(data32));
108                 block_len = be32_to_cpu(data32);
109                 if (block_len + 8 > len) {
110                         dev_err(codec->dev, "%zd byte block longer than file\n",
111                                 block_len);
112                         goto err;
113                 }
114                 if (block_len == 0) {
115                         dev_err(codec->dev, "Zero length block\n");
116                         goto err;
117                 }
118
119                 memcpy(&data32, data, sizeof(data32));
120                 data32 = be32_to_cpu(data32);
121
122                 switch ((data32 >> 24) & 0xff) {
123                 case WM_FW_BLOCK_INFO:
124                         /* Informational text */
125                         if (!check)
126                                 break;
127
128                         str = kzalloc(block_len + 1, GFP_KERNEL);
129                         if (str) {
130                                 memcpy(str, data + 8, block_len);
131                                 dev_info(codec->dev, "%s: %s\n", name, str);
132                                 kfree(str);
133                         } else {
134                                 dev_err(codec->dev, "Out of memory\n");
135                         }
136                         break;
137                 case WM_FW_BLOCK_PM:
138                 case WM_FW_BLOCK_X:
139                 case WM_FW_BLOCK_Y:
140                 case WM_FW_BLOCK_Z:
141                 case WM_FW_BLOCK_I:
142                 case WM_FW_BLOCK_A:
143                 case WM_FW_BLOCK_C:
144                         dev_dbg(codec->dev, "%s: %zd bytes of %x@%x\n", name,
145                                 block_len, (data32 >> 24) & 0xff,
146                                 data32 & 0xffffff);
147
148                         if (check)
149                                 break;
150
151                         data32 &= 0xffffff;
152
153                         wm8994_bulk_write(codec->control_data,
154                                           data32 & 0xffffff,
155                                           block_len / 2,
156                                           (void *)(data + 8));
157
158                         break;
159                 default:
160                         dev_warn(codec->dev, "%s: unknown block type %d\n",
161                                  name, (data32 >> 24) & 0xff);
162                         break;
163                 }
164
165                 /* Round up to the next 32 bit word */
166                 block_len += block_len % 4;
167
168                 data += block_len + 8;
169                 len -= block_len + 8;
170         }
171
172         if (!check) {
173                 dev_dbg(codec->dev, "%s: download done\n", name);
174                 wm8994->cur_fw = fw;
175         } else {
176                 dev_info(codec->dev, "%s: got firmware\n", name);
177         }
178
179         goto ok;
180
181 err:
182         ret = -EINVAL;
183 ok:
184         if (!check) {
185                 snd_soc_write(codec, 0x900, 0x0);
186                 snd_soc_write(codec, 0x102, 0x0);
187         }
188
189         return ret;
190 }
191
192 static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
193 {
194         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
195         struct wm8994_pdata *pdata = wm8994->pdata;
196         int i;
197
198         /* If the DSP is already running then noop */
199         if (snd_soc_read(codec, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
200                 return;
201
202         /* If we have MBC firmware download it */
203         if (wm8994->mbc)
204                 wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false);
205
206         snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
207                             WM8958_DSP2_ENA, WM8958_DSP2_ENA);
208
209         /* If we've got user supplied MBC settings use them */
210         if (pdata && pdata->num_mbc_cfgs) {
211                 struct wm8958_mbc_cfg *cfg
212                         = &pdata->mbc_cfgs[wm8994->mbc_cfg];
213
214                 for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
215                         snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
216                                       cfg->coeff_regs[i]);
217
218                 for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
219                         snd_soc_write(codec,
220                                       i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
221                                       cfg->cutoff_regs[i]);
222         }
223
224         /* Run the DSP */
225         snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
226                       WM8958_DSP2_RUNR);
227
228         /* And we're off! */
229         snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
230                             WM8958_MBC_ENA |
231                             WM8958_MBC_SEL_MASK,
232                             path << WM8958_MBC_SEL_SHIFT |
233                             WM8958_MBC_ENA);
234 }
235
236 static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
237 {
238         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
239         struct wm8994_pdata *pdata = wm8994->pdata;
240         int i, ena;
241
242         if (wm8994->mbc_vss)
243                 wm8958_dsp2_fw(codec, "MBC+VSS", wm8994->mbc_vss, false);
244
245         snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
246                             WM8958_DSP2_ENA, WM8958_DSP2_ENA);
247
248         /* If we've got user supplied settings use them */
249         if (pdata && pdata->num_mbc_cfgs) {
250                 struct wm8958_mbc_cfg *cfg
251                         = &pdata->mbc_cfgs[wm8994->mbc_cfg];
252
253                 for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
254                         snd_soc_write(codec, i + 0x2800,
255                                       cfg->combined_regs[i]);
256         }
257
258         if (pdata && pdata->num_vss_cfgs) {
259                 struct wm8958_vss_cfg *cfg
260                         = &pdata->vss_cfgs[wm8994->vss_cfg];
261
262                 for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
263                         snd_soc_write(codec, i + 0x2600, cfg->regs[i]);
264         }
265
266         if (pdata && pdata->num_vss_hpf_cfgs) {
267                 struct wm8958_vss_hpf_cfg *cfg
268                         = &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg];
269
270                 for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
271                         snd_soc_write(codec, i + 0x2400, cfg->regs[i]);
272         }
273
274         /* Run the DSP */
275         snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
276                       WM8958_DSP2_RUNR);
277
278         /* Enable the algorithms we've selected */
279         ena = 0;
280         if (wm8994->mbc_ena[path])
281                 ena |= 0x8;
282         if (wm8994->hpf2_ena[path])
283                 ena |= 0x4;
284         if (wm8994->hpf1_ena[path])
285                 ena |= 0x2;
286         if (wm8994->vss_ena[path])
287                 ena |= 0x1;
288
289         snd_soc_write(codec, 0x2201, ena);
290
291         /* Switch the DSP into the data path */
292         snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
293                             WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
294                             path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
295 }
296
297 static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
298 {
299         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
300         struct wm8994_pdata *pdata = wm8994->pdata;
301         int i;
302
303         wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false);
304
305         snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
306                             WM8958_DSP2_ENA, WM8958_DSP2_ENA);
307
308         /* If we've got user supplied settings use them */
309         if (pdata && pdata->num_enh_eq_cfgs) {
310                 struct wm8958_enh_eq_cfg *cfg
311                         = &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg];
312
313                 for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
314                         snd_soc_write(codec, i + 0x2200,
315                                       cfg->regs[i]);
316         }
317
318         /* Run the DSP */
319         snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
320                       WM8958_DSP2_RUNR);
321
322         /* Switch the DSP into the data path */
323         snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
324                             WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
325                             path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
326 }
327
328 static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
329 {
330         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
331         int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
332         int ena, reg, aif;
333
334         switch (path) {
335         case 0:
336                 pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
337                 aif = 0;
338                 break;
339         case 1:
340                 pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
341                 aif = 0;
342                 break;
343         case 2:
344                 pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
345                 aif = 1;
346                 break;
347         default:
348                 BUG();
349                 return;
350         }
351
352         /* Do we have both an active AIF and an active algorithm? */
353         ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] ||
354                 wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] ||
355                 wm8994->enh_eq_ena[path];
356         if (!pwr_reg)
357                 ena = 0;
358
359         reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
360
361         dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
362                 path, wm8994->dsp_active, start, pwr_reg, reg);
363
364         if (start && ena) {
365                 /* If the DSP is already running then noop */
366                 if (reg & WM8958_DSP2_ENA)
367                         return;
368
369                 /* If either AIFnCLK is not yet enabled postpone */
370                 if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
371                       & WM8994_AIF1CLK_ENA_MASK) &&
372                     !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
373                       & WM8994_AIF2CLK_ENA_MASK))
374                         return;
375
376                 /* Switch the clock over to the appropriate AIF */
377                 snd_soc_update_bits(codec, WM8994_CLOCKING_1,
378                                     WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
379                                     aif << WM8958_DSP2CLK_SRC_SHIFT |
380                                     WM8958_DSP2CLK_ENA);
381
382                 if (wm8994->enh_eq_ena[path])
383                         wm8958_dsp_start_enh_eq(codec, path);
384                 else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
385                     wm8994->hpf2_ena[path])
386                         wm8958_dsp_start_vss(codec, path);
387                 else if (wm8994->mbc_ena[path])
388                         wm8958_dsp_start_mbc(codec, path);
389
390                 wm8994->dsp_active = path;
391
392                 dev_dbg(codec->dev, "DSP running in path %d\n", path);
393         }
394
395         if (!start && wm8994->dsp_active == path) {
396                 /* If the DSP is already stopped then noop */
397                 if (!(reg & WM8958_DSP2_ENA))
398                         return;
399
400                 snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
401                                     WM8958_MBC_ENA, 0); 
402                 snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
403                               WM8958_DSP2_STOP);
404                 snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
405                                     WM8958_DSP2_ENA, 0);
406                 snd_soc_update_bits(codec, WM8994_CLOCKING_1,
407                                     WM8958_DSP2CLK_ENA, 0);
408
409                 wm8994->dsp_active = -1;
410
411                 dev_dbg(codec->dev, "DSP stopped\n");
412         }
413 }
414
415 int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
416                   struct snd_kcontrol *kcontrol, int event)
417 {
418         struct snd_soc_codec *codec = w->codec;
419         int i;
420
421         switch (event) {
422         case SND_SOC_DAPM_POST_PMU:
423         case SND_SOC_DAPM_PRE_PMU:
424                 for (i = 0; i < 3; i++)
425                         wm8958_dsp_apply(codec, i, 1);
426                 break;
427         case SND_SOC_DAPM_POST_PMD:
428         case SND_SOC_DAPM_PRE_PMD:
429                 for (i = 0; i < 3; i++)
430                         wm8958_dsp_apply(codec, i, 0);
431                 break;
432         }
433
434         return 0;
435 }
436
437 /* Check if DSP2 is in use on another AIF */
438 static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
439 {
440         int i;
441
442         for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
443                 if (i == aif)
444                         continue;
445                 if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] ||
446                     wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i])
447                         return 1;
448         }
449
450         return 0;
451 }
452
453 static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
454                                struct snd_ctl_elem_value *ucontrol)
455 {
456         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
457         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
458         struct wm8994_pdata *pdata = wm8994->pdata;
459         int value = ucontrol->value.integer.value[0];
460         int reg;
461
462         /* Don't allow on the fly reconfiguration */
463         reg = snd_soc_read(codec, WM8994_CLOCKING_1);
464         if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
465                 return -EBUSY;
466
467         if (value >= pdata->num_mbc_cfgs)
468                 return -EINVAL;
469
470         wm8994->mbc_cfg = value;
471
472         return 0;
473 }
474
475 static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
476                                struct snd_ctl_elem_value *ucontrol)
477 {
478         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
479         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
480
481         ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
482
483         return 0;
484 }
485
486 static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
487                            struct snd_ctl_elem_info *uinfo)
488 {
489         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
490         uinfo->count = 1;
491         uinfo->value.integer.min = 0;
492         uinfo->value.integer.max = 1;
493         return 0;
494 }
495
496 static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
497                           struct snd_ctl_elem_value *ucontrol)
498 {
499         int mbc = kcontrol->private_value;
500         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
501         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
502
503         ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
504
505         return 0;
506 }
507
508 static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
509                           struct snd_ctl_elem_value *ucontrol)
510 {
511         int mbc = kcontrol->private_value;
512         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
513         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
514
515         if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
516                 return 0;
517
518         if (ucontrol->value.integer.value[0] > 1)
519                 return -EINVAL;
520
521         if (wm8958_dsp2_busy(wm8994, mbc)) {
522                 dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc);
523                 return -EBUSY;
524         }
525
526         if (wm8994->enh_eq_ena[mbc])
527                 return -EBUSY;
528
529         wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
530
531         wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]);
532
533         return 0;
534 }
535
536 #define WM8958_MBC_SWITCH(xname, xval) {\
537         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
538         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
539         .info = wm8958_mbc_info, \
540         .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
541         .private_value = xval }
542
543 static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
544                                struct snd_ctl_elem_value *ucontrol)
545 {
546         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
547         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
548         struct wm8994_pdata *pdata = wm8994->pdata;
549         int value = ucontrol->value.integer.value[0];
550         int reg;
551
552         /* Don't allow on the fly reconfiguration */
553         reg = snd_soc_read(codec, WM8994_CLOCKING_1);
554         if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
555                 return -EBUSY;
556
557         if (value >= pdata->num_vss_cfgs)
558                 return -EINVAL;
559
560         wm8994->vss_cfg = value;
561
562         return 0;
563 }
564
565 static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
566                                struct snd_ctl_elem_value *ucontrol)
567 {
568         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
569         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
570
571         ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
572
573         return 0;
574 }
575
576 static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
577                                    struct snd_ctl_elem_value *ucontrol)
578 {
579         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
580         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
581         struct wm8994_pdata *pdata = wm8994->pdata;
582         int value = ucontrol->value.integer.value[0];
583         int reg;
584
585         /* Don't allow on the fly reconfiguration */
586         reg = snd_soc_read(codec, WM8994_CLOCKING_1);
587         if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
588                 return -EBUSY;
589
590         if (value >= pdata->num_vss_hpf_cfgs)
591                 return -EINVAL;
592
593         wm8994->vss_hpf_cfg = value;
594
595         return 0;
596 }
597
598 static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
599                                    struct snd_ctl_elem_value *ucontrol)
600 {
601         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
602         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
603
604         ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
605
606         return 0;
607 }
608
609 static int wm8958_vss_info(struct snd_kcontrol *kcontrol,
610                            struct snd_ctl_elem_info *uinfo)
611 {
612         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
613         uinfo->count = 1;
614         uinfo->value.integer.min = 0;
615         uinfo->value.integer.max = 1;
616         return 0;
617 }
618
619 static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
620                           struct snd_ctl_elem_value *ucontrol)
621 {
622         int vss = kcontrol->private_value;
623         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
624         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
625
626         ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
627
628         return 0;
629 }
630
631 static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
632                           struct snd_ctl_elem_value *ucontrol)
633 {
634         int vss = kcontrol->private_value;
635         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
636         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
637
638         if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
639                 return 0;
640
641         if (ucontrol->value.integer.value[0] > 1)
642                 return -EINVAL;
643
644         if (!wm8994->mbc_vss)
645                 return -ENODEV;
646
647         if (wm8958_dsp2_busy(wm8994, vss)) {
648                 dev_dbg(codec->dev, "DSP2 active on %d already\n", vss);
649                 return -EBUSY;
650         }
651
652         if (wm8994->enh_eq_ena[vss])
653                 return -EBUSY;
654
655         wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
656
657         wm8958_dsp_apply(codec, vss, wm8994->vss_ena[vss]);
658
659         return 0;
660 }
661
662
663 #define WM8958_VSS_SWITCH(xname, xval) {\
664         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
665         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
666         .info = wm8958_vss_info, \
667         .get = wm8958_vss_get, .put = wm8958_vss_put, \
668         .private_value = xval }
669
670 static int wm8958_hpf_info(struct snd_kcontrol *kcontrol,
671                            struct snd_ctl_elem_info *uinfo)
672 {
673         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
674         uinfo->count = 1;
675         uinfo->value.integer.min = 0;
676         uinfo->value.integer.max = 1;
677         return 0;
678 }
679
680 static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
681                           struct snd_ctl_elem_value *ucontrol)
682 {
683         int hpf = kcontrol->private_value;
684         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
685         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
686
687         if (hpf < 3)
688                 ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
689         else
690                 ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3];
691
692         return 0;
693 }
694
695 static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
696                           struct snd_ctl_elem_value *ucontrol)
697 {
698         int hpf = kcontrol->private_value;
699         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
700         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
701
702         if (hpf < 3) {
703                 if (wm8994->hpf1_ena[hpf % 3] ==
704                     ucontrol->value.integer.value[0])
705                         return 0;
706         } else {
707                 if (wm8994->hpf2_ena[hpf % 3] ==
708                     ucontrol->value.integer.value[0])
709                         return 0;
710         }
711
712         if (ucontrol->value.integer.value[0] > 1)
713                 return -EINVAL;
714
715         if (!wm8994->mbc_vss)
716                 return -ENODEV;
717
718         if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
719                 dev_dbg(codec->dev, "DSP2 active on %d already\n", hpf);
720                 return -EBUSY;
721         }
722
723         if (wm8994->enh_eq_ena[hpf % 3])
724                 return -EBUSY;
725
726         if (hpf < 3)
727                 wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0];
728         else
729                 wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
730
731         wm8958_dsp_apply(codec, hpf % 3, ucontrol->value.integer.value[0]);
732
733         return 0;
734 }
735
736 #define WM8958_HPF_SWITCH(xname, xval) {\
737         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
738         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
739         .info = wm8958_hpf_info, \
740         .get = wm8958_hpf_get, .put = wm8958_hpf_put, \
741         .private_value = xval }
742
743 static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
744                                   struct snd_ctl_elem_value *ucontrol)
745 {
746         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
747         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
748         struct wm8994_pdata *pdata = wm8994->pdata;
749         int value = ucontrol->value.integer.value[0];
750         int reg;
751
752         /* Don't allow on the fly reconfiguration */
753         reg = snd_soc_read(codec, WM8994_CLOCKING_1);
754         if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
755                 return -EBUSY;
756
757         if (value >= pdata->num_enh_eq_cfgs)
758                 return -EINVAL;
759
760         wm8994->enh_eq_cfg = value;
761
762         return 0;
763 }
764
765 static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
766                                   struct snd_ctl_elem_value *ucontrol)
767 {
768         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
769         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
770
771         ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
772
773         return 0;
774 }
775
776 static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol,
777                            struct snd_ctl_elem_info *uinfo)
778 {
779         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
780         uinfo->count = 1;
781         uinfo->value.integer.min = 0;
782         uinfo->value.integer.max = 1;
783         return 0;
784 }
785
786 static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
787                           struct snd_ctl_elem_value *ucontrol)
788 {
789         int eq = kcontrol->private_value;
790         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
791         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
792
793         ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
794
795         return 0;
796 }
797
798 static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
799                           struct snd_ctl_elem_value *ucontrol)
800 {
801         int eq = kcontrol->private_value;
802         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
803         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
804
805         if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
806                 return 0;
807
808         if (ucontrol->value.integer.value[0] > 1)
809                 return -EINVAL;
810
811         if (!wm8994->enh_eq)
812                 return -ENODEV;
813
814         if (wm8958_dsp2_busy(wm8994, eq)) {
815                 dev_dbg(codec->dev, "DSP2 active on %d already\n", eq);
816                 return -EBUSY;
817         }
818
819         if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] ||
820             wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq])
821                 return -EBUSY;
822
823         wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
824
825         wm8958_dsp_apply(codec, eq, ucontrol->value.integer.value[0]);
826
827         return 0;
828 }
829
830 #define WM8958_ENH_EQ_SWITCH(xname, xval) {\
831         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
832         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
833         .info = wm8958_enh_eq_info, \
834         .get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
835         .private_value = xval }
836
837 static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
838 WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
839 WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
840 WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
841 };
842
843 static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = {
844 WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
845 WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
846 WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
847 WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
848 WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
849 WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
850 WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
851 WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
852 WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
853 };
854
855 static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = {
856 WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
857 WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
858 WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
859 };
860
861 static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
862 {
863         struct snd_soc_codec *codec = context;
864         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
865
866         if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) {
867                 mutex_lock(&codec->mutex);
868                 wm8994->enh_eq = fw;
869                 mutex_unlock(&codec->mutex);
870         }
871 }
872
873 static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
874 {
875         struct snd_soc_codec *codec = context;
876         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
877
878         if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) {
879                 mutex_lock(&codec->mutex);
880                 wm8994->mbc_vss = fw;
881                 mutex_unlock(&codec->mutex);
882         }
883
884         /* We can't have more than one request outstanding at once so
885          * we daisy chain.
886          */
887         request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
888                                 "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
889                                 codec, wm8958_enh_eq_loaded);
890 }
891
892 static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
893 {
894         struct snd_soc_codec *codec = context;
895         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
896
897         if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0)
898                 return;
899
900         mutex_lock(&codec->mutex);
901         wm8994->mbc = fw;
902         mutex_unlock(&codec->mutex);
903
904         /* We can't have more than one request outstanding at once so
905          * we daisy chain.
906          */
907         request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
908                                 "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
909                                 codec, wm8958_mbc_vss_loaded);
910 }
911
912 void wm8958_dsp2_init(struct snd_soc_codec *codec)
913 {
914         struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
915         struct wm8994_pdata *pdata = wm8994->pdata;
916         int ret, i;
917
918         wm8994->dsp_active = -1;
919
920         snd_soc_add_controls(codec, wm8958_mbc_snd_controls,
921                              ARRAY_SIZE(wm8958_mbc_snd_controls));
922         snd_soc_add_controls(codec, wm8958_vss_snd_controls,
923                              ARRAY_SIZE(wm8958_vss_snd_controls));
924         snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls,
925                              ARRAY_SIZE(wm8958_enh_eq_snd_controls));
926
927
928         /* We don't *require* firmware and don't want to delay boot */
929         request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
930                                 "wm8958_mbc.wfw", codec->dev, GFP_KERNEL,
931                                 codec, wm8958_mbc_loaded);
932
933         if (!pdata)
934                 return;
935
936         if (pdata->num_mbc_cfgs) {
937                 struct snd_kcontrol_new control[] = {
938                         SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
939                                      wm8958_get_mbc_enum, wm8958_put_mbc_enum),
940                 };
941
942                 /* We need an array of texts for the enum API */
943                 wm8994->mbc_texts = kmalloc(sizeof(char *)
944                                             * pdata->num_mbc_cfgs, GFP_KERNEL);
945                 if (!wm8994->mbc_texts) {
946                         dev_err(wm8994->codec->dev,
947                                 "Failed to allocate %d MBC config texts\n",
948                                 pdata->num_mbc_cfgs);
949                         return;
950                 }
951
952                 for (i = 0; i < pdata->num_mbc_cfgs; i++)
953                         wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
954
955                 wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
956                 wm8994->mbc_enum.texts = wm8994->mbc_texts;
957
958                 ret = snd_soc_add_controls(wm8994->codec, control, 1);
959                 if (ret != 0)
960                         dev_err(wm8994->codec->dev,
961                                 "Failed to add MBC mode controls: %d\n", ret);
962         }
963
964         if (pdata->num_vss_cfgs) {
965                 struct snd_kcontrol_new control[] = {
966                         SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
967                                      wm8958_get_vss_enum, wm8958_put_vss_enum),
968                 };
969
970                 /* We need an array of texts for the enum API */
971                 wm8994->vss_texts = kmalloc(sizeof(char *)
972                                             * pdata->num_vss_cfgs, GFP_KERNEL);
973                 if (!wm8994->vss_texts) {
974                         dev_err(wm8994->codec->dev,
975                                 "Failed to allocate %d VSS config texts\n",
976                                 pdata->num_vss_cfgs);
977                         return;
978                 }
979
980                 for (i = 0; i < pdata->num_vss_cfgs; i++)
981                         wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
982
983                 wm8994->vss_enum.max = pdata->num_vss_cfgs;
984                 wm8994->vss_enum.texts = wm8994->vss_texts;
985
986                 ret = snd_soc_add_controls(wm8994->codec, control, 1);
987                 if (ret != 0)
988                         dev_err(wm8994->codec->dev,
989                                 "Failed to add VSS mode controls: %d\n", ret);
990         }
991
992         if (pdata->num_vss_hpf_cfgs) {
993                 struct snd_kcontrol_new control[] = {
994                         SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
995                                      wm8958_get_vss_hpf_enum,
996                                      wm8958_put_vss_hpf_enum),
997                 };
998
999                 /* We need an array of texts for the enum API */
1000                 wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
1001                                                 * pdata->num_vss_hpf_cfgs, GFP_KERNEL);
1002                 if (!wm8994->vss_hpf_texts) {
1003                         dev_err(wm8994->codec->dev,
1004                                 "Failed to allocate %d VSS HPF config texts\n",
1005                                 pdata->num_vss_hpf_cfgs);
1006                         return;
1007                 }
1008
1009                 for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
1010                         wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
1011
1012                 wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
1013                 wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
1014
1015                 ret = snd_soc_add_controls(wm8994->codec, control, 1);
1016                 if (ret != 0)
1017                         dev_err(wm8994->codec->dev,
1018                                 "Failed to add VSS HPFmode controls: %d\n",
1019                                 ret);
1020         }
1021
1022         if (pdata->num_enh_eq_cfgs) {
1023                 struct snd_kcontrol_new control[] = {
1024                         SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
1025                                      wm8958_get_enh_eq_enum,
1026                                      wm8958_put_enh_eq_enum),
1027                 };
1028
1029                 /* We need an array of texts for the enum API */
1030                 wm8994->enh_eq_texts = kmalloc(sizeof(char *)
1031                                                 * pdata->num_enh_eq_cfgs, GFP_KERNEL);
1032                 if (!wm8994->enh_eq_texts) {
1033                         dev_err(wm8994->codec->dev,
1034                                 "Failed to allocate %d enhanced EQ config texts\n",
1035                                 pdata->num_enh_eq_cfgs);
1036                         return;
1037                 }
1038
1039                 for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
1040                         wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
1041
1042                 wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
1043                 wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
1044
1045                 ret = snd_soc_add_controls(wm8994->codec, control, 1);
1046                 if (ret != 0)
1047                         dev_err(wm8994->codec->dev,
1048                                 "Failed to add enhanced EQ controls: %d\n",
1049                                 ret);
1050         }
1051 }