2 * wm8958-dsp2.c -- WM8958 DSP2 support
4 * Copyright 2011 Wolfson Microelectronics plc
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
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.
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/init.h>
16 #include <linux/delay.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>
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>
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
42 static int wm8958_dsp2_fw(struct snd_soc_codec
*codec
, const char *name
,
43 const struct firmware
*fw
, bool check
)
45 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
50 size_t block_len
, len
;
53 /* Suppress unneeded downloads */
54 if (wm8994
->cur_fw
== fw
)
58 dev_err(codec
->dev
, "%s: firmware too short (%zd bytes)\n",
63 if (memcmp(fw
->data
, "WMFW", 4) != 0) {
64 memcpy(&data32
, fw
->data
, sizeof(data32
));
65 data32
= be32_to_cpu(data32
);
66 dev_err(codec
->dev
, "%s: firmware has bad file magic %08x\n",
71 memcpy(&data32
, fw
->data
+ 4, sizeof(data32
));
72 len
= be32_to_cpu(data32
);
74 memcpy(&data32
, fw
->data
+ 8, sizeof(data32
));
75 data32
= be32_to_cpu(data32
);
76 if ((data32
>> 24) & 0xff) {
77 dev_err(codec
->dev
, "%s: unsupported firmware version %d\n",
78 name
, (data32
>> 24) & 0xff);
81 if ((data32
& 0xffff) != 8958) {
82 dev_err(codec
->dev
, "%s: unsupported target device %d\n",
83 name
, data32
& 0xffff);
86 if (((data32
>> 16) & 0xff) != 0xc) {
87 dev_err(codec
->dev
, "%s: unsupported target core %d\n",
88 name
, (data32
>> 16) & 0xff);
93 memcpy(&data64
, fw
->data
+ 24, sizeof(u64
));
94 dev_info(codec
->dev
, "%s timestamp %llx\n",
95 name
, be64_to_cpu(data64
));
97 snd_soc_write(codec
, 0x102, 0x2);
98 snd_soc_write(codec
, 0x900, 0x2);
101 data
= fw
->data
+ len
;
102 len
= fw
->size
- len
;
105 dev_err(codec
->dev
, "%s short data block of %zd\n",
110 memcpy(&data32
, data
+ 4, sizeof(data32
));
111 block_len
= be32_to_cpu(data32
);
112 if (block_len
+ 8 > len
) {
113 dev_err(codec
->dev
, "%zd byte block longer than file\n",
117 if (block_len
== 0) {
118 dev_err(codec
->dev
, "Zero length block\n");
122 memcpy(&data32
, data
, sizeof(data32
));
123 data32
= be32_to_cpu(data32
);
125 switch ((data32
>> 24) & 0xff) {
126 case WM_FW_BLOCK_INFO
:
127 /* Informational text */
131 str
= kzalloc(block_len
+ 1, GFP_KERNEL
);
133 memcpy(str
, data
+ 8, block_len
);
134 dev_info(codec
->dev
, "%s: %s\n", name
, str
);
137 dev_err(codec
->dev
, "Out of memory\n");
147 dev_dbg(codec
->dev
, "%s: %zd bytes of %x@%x\n", name
,
148 block_len
, (data32
>> 24) & 0xff,
156 wm8994_bulk_write(wm8994
->wm8994
,
163 dev_warn(codec
->dev
, "%s: unknown block type %d\n",
164 name
, (data32
>> 24) & 0xff);
168 /* Round up to the next 32 bit word */
169 block_len
+= block_len
% 4;
171 data
+= block_len
+ 8;
172 len
-= block_len
+ 8;
176 dev_dbg(codec
->dev
, "%s: download done\n", name
);
179 dev_info(codec
->dev
, "%s: got firmware\n", name
);
188 snd_soc_write(codec
, 0x900, 0x0);
189 snd_soc_write(codec
, 0x102, 0x0);
195 static void wm8958_dsp_start_mbc(struct snd_soc_codec
*codec
, int path
)
197 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
198 struct wm8994
*control
= wm8994
->wm8994
;
201 /* If the DSP is already running then noop */
202 if (snd_soc_read(codec
, WM8958_DSP2_PROGRAM
) & WM8958_DSP2_ENA
)
205 /* If we have MBC firmware download it */
207 wm8958_dsp2_fw(codec
, "MBC", wm8994
->mbc
, false);
209 snd_soc_update_bits(codec
, WM8958_DSP2_PROGRAM
,
210 WM8958_DSP2_ENA
, WM8958_DSP2_ENA
);
212 /* If we've got user supplied MBC settings use them */
213 if (control
->pdata
.num_mbc_cfgs
) {
214 struct wm8958_mbc_cfg
*cfg
215 = &control
->pdata
.mbc_cfgs
[wm8994
->mbc_cfg
];
217 for (i
= 0; i
< ARRAY_SIZE(cfg
->coeff_regs
); i
++)
218 snd_soc_write(codec
, i
+ WM8958_MBC_BAND_1_K_1
,
221 for (i
= 0; i
< ARRAY_SIZE(cfg
->cutoff_regs
); i
++)
223 i
+ WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1
,
224 cfg
->cutoff_regs
[i
]);
228 snd_soc_write(codec
, WM8958_DSP2_EXECCONTROL
,
232 snd_soc_update_bits(codec
, WM8958_DSP2_CONFIG
,
235 path
<< WM8958_MBC_SEL_SHIFT
|
239 static void wm8958_dsp_start_vss(struct snd_soc_codec
*codec
, int path
)
241 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
242 struct wm8994
*control
= wm8994
->wm8994
;
246 wm8958_dsp2_fw(codec
, "MBC+VSS", wm8994
->mbc_vss
, false);
248 snd_soc_update_bits(codec
, WM8958_DSP2_PROGRAM
,
249 WM8958_DSP2_ENA
, WM8958_DSP2_ENA
);
251 /* If we've got user supplied settings use them */
252 if (control
->pdata
.num_mbc_cfgs
) {
253 struct wm8958_mbc_cfg
*cfg
254 = &control
->pdata
.mbc_cfgs
[wm8994
->mbc_cfg
];
256 for (i
= 0; i
< ARRAY_SIZE(cfg
->combined_regs
); i
++)
257 snd_soc_write(codec
, i
+ 0x2800,
258 cfg
->combined_regs
[i
]);
261 if (control
->pdata
.num_vss_cfgs
) {
262 struct wm8958_vss_cfg
*cfg
263 = &control
->pdata
.vss_cfgs
[wm8994
->vss_cfg
];
265 for (i
= 0; i
< ARRAY_SIZE(cfg
->regs
); i
++)
266 snd_soc_write(codec
, i
+ 0x2600, cfg
->regs
[i
]);
269 if (control
->pdata
.num_vss_hpf_cfgs
) {
270 struct wm8958_vss_hpf_cfg
*cfg
271 = &control
->pdata
.vss_hpf_cfgs
[wm8994
->vss_hpf_cfg
];
273 for (i
= 0; i
< ARRAY_SIZE(cfg
->regs
); i
++)
274 snd_soc_write(codec
, i
+ 0x2400, cfg
->regs
[i
]);
278 snd_soc_write(codec
, WM8958_DSP2_EXECCONTROL
,
281 /* Enable the algorithms we've selected */
283 if (wm8994
->mbc_ena
[path
])
285 if (wm8994
->hpf2_ena
[path
])
287 if (wm8994
->hpf1_ena
[path
])
289 if (wm8994
->vss_ena
[path
])
292 snd_soc_write(codec
, 0x2201, ena
);
294 /* Switch the DSP into the data path */
295 snd_soc_update_bits(codec
, WM8958_DSP2_CONFIG
,
296 WM8958_MBC_SEL_MASK
| WM8958_MBC_ENA
,
297 path
<< WM8958_MBC_SEL_SHIFT
| WM8958_MBC_ENA
);
300 static void wm8958_dsp_start_enh_eq(struct snd_soc_codec
*codec
, int path
)
302 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
303 struct wm8994
*control
= wm8994
->wm8994
;
306 wm8958_dsp2_fw(codec
, "ENH_EQ", wm8994
->enh_eq
, false);
308 snd_soc_update_bits(codec
, WM8958_DSP2_PROGRAM
,
309 WM8958_DSP2_ENA
, WM8958_DSP2_ENA
);
311 /* If we've got user supplied settings use them */
312 if (control
->pdata
.num_enh_eq_cfgs
) {
313 struct wm8958_enh_eq_cfg
*cfg
314 = &control
->pdata
.enh_eq_cfgs
[wm8994
->enh_eq_cfg
];
316 for (i
= 0; i
< ARRAY_SIZE(cfg
->regs
); i
++)
317 snd_soc_write(codec
, i
+ 0x2200,
322 snd_soc_write(codec
, WM8958_DSP2_EXECCONTROL
,
325 /* Switch the DSP into the data path */
326 snd_soc_update_bits(codec
, WM8958_DSP2_CONFIG
,
327 WM8958_MBC_SEL_MASK
| WM8958_MBC_ENA
,
328 path
<< WM8958_MBC_SEL_SHIFT
| WM8958_MBC_ENA
);
331 static void wm8958_dsp_apply(struct snd_soc_codec
*codec
, int path
, int start
)
333 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
334 int pwr_reg
= snd_soc_read(codec
, WM8994_POWER_MANAGEMENT_5
);
339 pwr_reg
&= (WM8994_AIF1DAC1L_ENA
| WM8994_AIF1DAC1R_ENA
);
343 pwr_reg
&= (WM8994_AIF1DAC2L_ENA
| WM8994_AIF1DAC2R_ENA
);
347 pwr_reg
&= (WM8994_AIF2DACL_ENA
| WM8994_AIF2DACR_ENA
);
355 /* Do we have both an active AIF and an active algorithm? */
356 ena
= wm8994
->mbc_ena
[path
] || wm8994
->vss_ena
[path
] ||
357 wm8994
->hpf1_ena
[path
] || wm8994
->hpf2_ena
[path
] ||
358 wm8994
->enh_eq_ena
[path
];
362 reg
= snd_soc_read(codec
, WM8958_DSP2_PROGRAM
);
364 dev_dbg(codec
->dev
, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
365 path
, wm8994
->dsp_active
, start
, pwr_reg
, reg
);
368 /* If the DSP is already running then noop */
369 if (reg
& WM8958_DSP2_ENA
)
372 /* If either AIFnCLK is not yet enabled postpone */
373 if (!(snd_soc_read(codec
, WM8994_AIF1_CLOCKING_1
)
374 & WM8994_AIF1CLK_ENA_MASK
) &&
375 !(snd_soc_read(codec
, WM8994_AIF2_CLOCKING_1
)
376 & WM8994_AIF2CLK_ENA_MASK
))
379 /* Switch the clock over to the appropriate AIF */
380 snd_soc_update_bits(codec
, WM8994_CLOCKING_1
,
381 WM8958_DSP2CLK_SRC
| WM8958_DSP2CLK_ENA
,
382 aif
<< WM8958_DSP2CLK_SRC_SHIFT
|
385 if (wm8994
->enh_eq_ena
[path
])
386 wm8958_dsp_start_enh_eq(codec
, path
);
387 else if (wm8994
->vss_ena
[path
] || wm8994
->hpf1_ena
[path
] ||
388 wm8994
->hpf2_ena
[path
])
389 wm8958_dsp_start_vss(codec
, path
);
390 else if (wm8994
->mbc_ena
[path
])
391 wm8958_dsp_start_mbc(codec
, path
);
393 wm8994
->dsp_active
= path
;
395 dev_dbg(codec
->dev
, "DSP running in path %d\n", path
);
398 if (!start
&& wm8994
->dsp_active
== path
) {
399 /* If the DSP is already stopped then noop */
400 if (!(reg
& WM8958_DSP2_ENA
))
403 snd_soc_update_bits(codec
, WM8958_DSP2_CONFIG
,
405 snd_soc_write(codec
, WM8958_DSP2_EXECCONTROL
,
407 snd_soc_update_bits(codec
, WM8958_DSP2_PROGRAM
,
409 snd_soc_update_bits(codec
, WM8994_CLOCKING_1
,
410 WM8958_DSP2CLK_ENA
, 0);
412 wm8994
->dsp_active
= -1;
414 dev_dbg(codec
->dev
, "DSP stopped\n");
418 int wm8958_aif_ev(struct snd_soc_dapm_widget
*w
,
419 struct snd_kcontrol
*kcontrol
, int event
)
421 struct snd_soc_codec
*codec
= w
->codec
;
425 case SND_SOC_DAPM_POST_PMU
:
426 case SND_SOC_DAPM_PRE_PMU
:
427 for (i
= 0; i
< 3; i
++)
428 wm8958_dsp_apply(codec
, i
, 1);
430 case SND_SOC_DAPM_POST_PMD
:
431 case SND_SOC_DAPM_PRE_PMD
:
432 for (i
= 0; i
< 3; i
++)
433 wm8958_dsp_apply(codec
, i
, 0);
440 /* Check if DSP2 is in use on another AIF */
441 static int wm8958_dsp2_busy(struct wm8994_priv
*wm8994
, int aif
)
445 for (i
= 0; i
< ARRAY_SIZE(wm8994
->mbc_ena
); i
++) {
448 if (wm8994
->mbc_ena
[i
] || wm8994
->vss_ena
[i
] ||
449 wm8994
->hpf1_ena
[i
] || wm8994
->hpf2_ena
[i
])
456 static int wm8958_put_mbc_enum(struct snd_kcontrol
*kcontrol
,
457 struct snd_ctl_elem_value
*ucontrol
)
459 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
460 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
461 struct wm8994
*control
= wm8994
->wm8994
;
462 int value
= ucontrol
->value
.integer
.value
[0];
465 /* Don't allow on the fly reconfiguration */
466 reg
= snd_soc_read(codec
, WM8994_CLOCKING_1
);
467 if (reg
< 0 || reg
& WM8958_DSP2CLK_ENA
)
470 if (value
>= control
->pdata
.num_mbc_cfgs
)
473 wm8994
->mbc_cfg
= value
;
478 static int wm8958_get_mbc_enum(struct snd_kcontrol
*kcontrol
,
479 struct snd_ctl_elem_value
*ucontrol
)
481 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
482 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
484 ucontrol
->value
.enumerated
.item
[0] = wm8994
->mbc_cfg
;
489 static int wm8958_mbc_info(struct snd_kcontrol
*kcontrol
,
490 struct snd_ctl_elem_info
*uinfo
)
492 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
494 uinfo
->value
.integer
.min
= 0;
495 uinfo
->value
.integer
.max
= 1;
499 static int wm8958_mbc_get(struct snd_kcontrol
*kcontrol
,
500 struct snd_ctl_elem_value
*ucontrol
)
502 int mbc
= kcontrol
->private_value
;
503 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
504 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
506 ucontrol
->value
.integer
.value
[0] = wm8994
->mbc_ena
[mbc
];
511 static int wm8958_mbc_put(struct snd_kcontrol
*kcontrol
,
512 struct snd_ctl_elem_value
*ucontrol
)
514 int mbc
= kcontrol
->private_value
;
515 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
516 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
518 if (wm8994
->mbc_ena
[mbc
] == ucontrol
->value
.integer
.value
[0])
521 if (ucontrol
->value
.integer
.value
[0] > 1)
524 if (wm8958_dsp2_busy(wm8994
, mbc
)) {
525 dev_dbg(codec
->dev
, "DSP2 active on %d already\n", mbc
);
529 if (wm8994
->enh_eq_ena
[mbc
])
532 wm8994
->mbc_ena
[mbc
] = ucontrol
->value
.integer
.value
[0];
534 wm8958_dsp_apply(codec
, mbc
, wm8994
->mbc_ena
[mbc
]);
539 #define WM8958_MBC_SWITCH(xname, xval) {\
540 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
541 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
542 .info = wm8958_mbc_info, \
543 .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
544 .private_value = xval }
546 static int wm8958_put_vss_enum(struct snd_kcontrol
*kcontrol
,
547 struct snd_ctl_elem_value
*ucontrol
)
549 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
550 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
551 struct wm8994
*control
= wm8994
->wm8994
;
552 int value
= ucontrol
->value
.integer
.value
[0];
555 /* Don't allow on the fly reconfiguration */
556 reg
= snd_soc_read(codec
, WM8994_CLOCKING_1
);
557 if (reg
< 0 || reg
& WM8958_DSP2CLK_ENA
)
560 if (value
>= control
->pdata
.num_vss_cfgs
)
563 wm8994
->vss_cfg
= value
;
568 static int wm8958_get_vss_enum(struct snd_kcontrol
*kcontrol
,
569 struct snd_ctl_elem_value
*ucontrol
)
571 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
572 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
574 ucontrol
->value
.enumerated
.item
[0] = wm8994
->vss_cfg
;
579 static int wm8958_put_vss_hpf_enum(struct snd_kcontrol
*kcontrol
,
580 struct snd_ctl_elem_value
*ucontrol
)
582 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
583 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
584 struct wm8994
*control
= wm8994
->wm8994
;
585 int value
= ucontrol
->value
.integer
.value
[0];
588 /* Don't allow on the fly reconfiguration */
589 reg
= snd_soc_read(codec
, WM8994_CLOCKING_1
);
590 if (reg
< 0 || reg
& WM8958_DSP2CLK_ENA
)
593 if (value
>= control
->pdata
.num_vss_hpf_cfgs
)
596 wm8994
->vss_hpf_cfg
= value
;
601 static int wm8958_get_vss_hpf_enum(struct snd_kcontrol
*kcontrol
,
602 struct snd_ctl_elem_value
*ucontrol
)
604 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
605 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
607 ucontrol
->value
.enumerated
.item
[0] = wm8994
->vss_hpf_cfg
;
612 static int wm8958_vss_info(struct snd_kcontrol
*kcontrol
,
613 struct snd_ctl_elem_info
*uinfo
)
615 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
617 uinfo
->value
.integer
.min
= 0;
618 uinfo
->value
.integer
.max
= 1;
622 static int wm8958_vss_get(struct snd_kcontrol
*kcontrol
,
623 struct snd_ctl_elem_value
*ucontrol
)
625 int vss
= kcontrol
->private_value
;
626 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
627 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
629 ucontrol
->value
.integer
.value
[0] = wm8994
->vss_ena
[vss
];
634 static int wm8958_vss_put(struct snd_kcontrol
*kcontrol
,
635 struct snd_ctl_elem_value
*ucontrol
)
637 int vss
= kcontrol
->private_value
;
638 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
639 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
641 if (wm8994
->vss_ena
[vss
] == ucontrol
->value
.integer
.value
[0])
644 if (ucontrol
->value
.integer
.value
[0] > 1)
647 if (!wm8994
->mbc_vss
)
650 if (wm8958_dsp2_busy(wm8994
, vss
)) {
651 dev_dbg(codec
->dev
, "DSP2 active on %d already\n", vss
);
655 if (wm8994
->enh_eq_ena
[vss
])
658 wm8994
->vss_ena
[vss
] = ucontrol
->value
.integer
.value
[0];
660 wm8958_dsp_apply(codec
, vss
, wm8994
->vss_ena
[vss
]);
666 #define WM8958_VSS_SWITCH(xname, xval) {\
667 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
668 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
669 .info = wm8958_vss_info, \
670 .get = wm8958_vss_get, .put = wm8958_vss_put, \
671 .private_value = xval }
673 static int wm8958_hpf_info(struct snd_kcontrol
*kcontrol
,
674 struct snd_ctl_elem_info
*uinfo
)
676 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
678 uinfo
->value
.integer
.min
= 0;
679 uinfo
->value
.integer
.max
= 1;
683 static int wm8958_hpf_get(struct snd_kcontrol
*kcontrol
,
684 struct snd_ctl_elem_value
*ucontrol
)
686 int hpf
= kcontrol
->private_value
;
687 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
688 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
691 ucontrol
->value
.integer
.value
[0] = wm8994
->hpf1_ena
[hpf
% 3];
693 ucontrol
->value
.integer
.value
[0] = wm8994
->hpf2_ena
[hpf
% 3];
698 static int wm8958_hpf_put(struct snd_kcontrol
*kcontrol
,
699 struct snd_ctl_elem_value
*ucontrol
)
701 int hpf
= kcontrol
->private_value
;
702 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
703 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
706 if (wm8994
->hpf1_ena
[hpf
% 3] ==
707 ucontrol
->value
.integer
.value
[0])
710 if (wm8994
->hpf2_ena
[hpf
% 3] ==
711 ucontrol
->value
.integer
.value
[0])
715 if (ucontrol
->value
.integer
.value
[0] > 1)
718 if (!wm8994
->mbc_vss
)
721 if (wm8958_dsp2_busy(wm8994
, hpf
% 3)) {
722 dev_dbg(codec
->dev
, "DSP2 active on %d already\n", hpf
);
726 if (wm8994
->enh_eq_ena
[hpf
% 3])
730 wm8994
->hpf1_ena
[hpf
% 3] = ucontrol
->value
.integer
.value
[0];
732 wm8994
->hpf2_ena
[hpf
% 3] = ucontrol
->value
.integer
.value
[0];
734 wm8958_dsp_apply(codec
, hpf
% 3, ucontrol
->value
.integer
.value
[0]);
739 #define WM8958_HPF_SWITCH(xname, xval) {\
740 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
741 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
742 .info = wm8958_hpf_info, \
743 .get = wm8958_hpf_get, .put = wm8958_hpf_put, \
744 .private_value = xval }
746 static int wm8958_put_enh_eq_enum(struct snd_kcontrol
*kcontrol
,
747 struct snd_ctl_elem_value
*ucontrol
)
749 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
750 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
751 struct wm8994
*control
= wm8994
->wm8994
;
752 int value
= ucontrol
->value
.integer
.value
[0];
755 /* Don't allow on the fly reconfiguration */
756 reg
= snd_soc_read(codec
, WM8994_CLOCKING_1
);
757 if (reg
< 0 || reg
& WM8958_DSP2CLK_ENA
)
760 if (value
>= control
->pdata
.num_enh_eq_cfgs
)
763 wm8994
->enh_eq_cfg
= value
;
768 static int wm8958_get_enh_eq_enum(struct snd_kcontrol
*kcontrol
,
769 struct snd_ctl_elem_value
*ucontrol
)
771 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
772 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
774 ucontrol
->value
.enumerated
.item
[0] = wm8994
->enh_eq_cfg
;
779 static int wm8958_enh_eq_info(struct snd_kcontrol
*kcontrol
,
780 struct snd_ctl_elem_info
*uinfo
)
782 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
784 uinfo
->value
.integer
.min
= 0;
785 uinfo
->value
.integer
.max
= 1;
789 static int wm8958_enh_eq_get(struct snd_kcontrol
*kcontrol
,
790 struct snd_ctl_elem_value
*ucontrol
)
792 int eq
= kcontrol
->private_value
;
793 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
794 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
796 ucontrol
->value
.integer
.value
[0] = wm8994
->enh_eq_ena
[eq
];
801 static int wm8958_enh_eq_put(struct snd_kcontrol
*kcontrol
,
802 struct snd_ctl_elem_value
*ucontrol
)
804 int eq
= kcontrol
->private_value
;
805 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
806 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
808 if (wm8994
->enh_eq_ena
[eq
] == ucontrol
->value
.integer
.value
[0])
811 if (ucontrol
->value
.integer
.value
[0] > 1)
817 if (wm8958_dsp2_busy(wm8994
, eq
)) {
818 dev_dbg(codec
->dev
, "DSP2 active on %d already\n", eq
);
822 if (wm8994
->mbc_ena
[eq
] || wm8994
->vss_ena
[eq
] ||
823 wm8994
->hpf1_ena
[eq
] || wm8994
->hpf2_ena
[eq
])
826 wm8994
->enh_eq_ena
[eq
] = ucontrol
->value
.integer
.value
[0];
828 wm8958_dsp_apply(codec
, eq
, ucontrol
->value
.integer
.value
[0]);
833 #define WM8958_ENH_EQ_SWITCH(xname, xval) {\
834 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
835 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
836 .info = wm8958_enh_eq_info, \
837 .get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
838 .private_value = xval }
840 static const struct snd_kcontrol_new wm8958_mbc_snd_controls
[] = {
841 WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
842 WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
843 WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
846 static const struct snd_kcontrol_new wm8958_vss_snd_controls
[] = {
847 WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
848 WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
849 WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
850 WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
851 WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
852 WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
853 WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
854 WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
855 WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
858 static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls
[] = {
859 WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
860 WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
861 WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
864 static void wm8958_enh_eq_loaded(const struct firmware
*fw
, void *context
)
866 struct snd_soc_codec
*codec
= context
;
867 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
869 if (fw
&& (wm8958_dsp2_fw(codec
, "ENH_EQ", fw
, true) == 0)) {
870 mutex_lock(&codec
->mutex
);
872 mutex_unlock(&codec
->mutex
);
876 static void wm8958_mbc_vss_loaded(const struct firmware
*fw
, void *context
)
878 struct snd_soc_codec
*codec
= context
;
879 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
881 if (fw
&& (wm8958_dsp2_fw(codec
, "MBC+VSS", fw
, true) == 0)) {
882 mutex_lock(&codec
->mutex
);
883 wm8994
->mbc_vss
= fw
;
884 mutex_unlock(&codec
->mutex
);
888 static void wm8958_mbc_loaded(const struct firmware
*fw
, void *context
)
890 struct snd_soc_codec
*codec
= context
;
891 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
893 if (fw
&& (wm8958_dsp2_fw(codec
, "MBC", fw
, true) == 0)) {
894 mutex_lock(&codec
->mutex
);
896 mutex_unlock(&codec
->mutex
);
900 void wm8958_dsp2_init(struct snd_soc_codec
*codec
)
902 struct wm8994_priv
*wm8994
= snd_soc_codec_get_drvdata(codec
);
903 struct wm8994
*control
= wm8994
->wm8994
;
904 struct wm8994_pdata
*pdata
= &control
->pdata
;
907 wm8994
->dsp_active
= -1;
909 snd_soc_add_codec_controls(codec
, wm8958_mbc_snd_controls
,
910 ARRAY_SIZE(wm8958_mbc_snd_controls
));
911 snd_soc_add_codec_controls(codec
, wm8958_vss_snd_controls
,
912 ARRAY_SIZE(wm8958_vss_snd_controls
));
913 snd_soc_add_codec_controls(codec
, wm8958_enh_eq_snd_controls
,
914 ARRAY_SIZE(wm8958_enh_eq_snd_controls
));
917 /* We don't *require* firmware and don't want to delay boot */
918 request_firmware_nowait(THIS_MODULE
, FW_ACTION_HOTPLUG
,
919 "wm8958_mbc.wfw", codec
->dev
, GFP_KERNEL
,
920 codec
, wm8958_mbc_loaded
);
921 request_firmware_nowait(THIS_MODULE
, FW_ACTION_HOTPLUG
,
922 "wm8958_mbc_vss.wfw", codec
->dev
, GFP_KERNEL
,
923 codec
, wm8958_mbc_vss_loaded
);
924 request_firmware_nowait(THIS_MODULE
, FW_ACTION_HOTPLUG
,
925 "wm8958_enh_eq.wfw", codec
->dev
, GFP_KERNEL
,
926 codec
, wm8958_enh_eq_loaded
);
928 if (pdata
->num_mbc_cfgs
) {
929 struct snd_kcontrol_new control
[] = {
930 SOC_ENUM_EXT("MBC Mode", wm8994
->mbc_enum
,
931 wm8958_get_mbc_enum
, wm8958_put_mbc_enum
),
934 /* We need an array of texts for the enum API */
935 wm8994
->mbc_texts
= kmalloc(sizeof(char *)
936 * pdata
->num_mbc_cfgs
, GFP_KERNEL
);
937 if (!wm8994
->mbc_texts
) {
938 dev_err(wm8994
->hubs
.codec
->dev
,
939 "Failed to allocate %d MBC config texts\n",
940 pdata
->num_mbc_cfgs
);
944 for (i
= 0; i
< pdata
->num_mbc_cfgs
; i
++)
945 wm8994
->mbc_texts
[i
] = pdata
->mbc_cfgs
[i
].name
;
947 wm8994
->mbc_enum
.max
= pdata
->num_mbc_cfgs
;
948 wm8994
->mbc_enum
.texts
= wm8994
->mbc_texts
;
950 ret
= snd_soc_add_codec_controls(wm8994
->hubs
.codec
,
953 dev_err(wm8994
->hubs
.codec
->dev
,
954 "Failed to add MBC mode controls: %d\n", ret
);
957 if (pdata
->num_vss_cfgs
) {
958 struct snd_kcontrol_new control
[] = {
959 SOC_ENUM_EXT("VSS Mode", wm8994
->vss_enum
,
960 wm8958_get_vss_enum
, wm8958_put_vss_enum
),
963 /* We need an array of texts for the enum API */
964 wm8994
->vss_texts
= kmalloc(sizeof(char *)
965 * pdata
->num_vss_cfgs
, GFP_KERNEL
);
966 if (!wm8994
->vss_texts
) {
967 dev_err(wm8994
->hubs
.codec
->dev
,
968 "Failed to allocate %d VSS config texts\n",
969 pdata
->num_vss_cfgs
);
973 for (i
= 0; i
< pdata
->num_vss_cfgs
; i
++)
974 wm8994
->vss_texts
[i
] = pdata
->vss_cfgs
[i
].name
;
976 wm8994
->vss_enum
.max
= pdata
->num_vss_cfgs
;
977 wm8994
->vss_enum
.texts
= wm8994
->vss_texts
;
979 ret
= snd_soc_add_codec_controls(wm8994
->hubs
.codec
,
982 dev_err(wm8994
->hubs
.codec
->dev
,
983 "Failed to add VSS mode controls: %d\n", ret
);
986 if (pdata
->num_vss_hpf_cfgs
) {
987 struct snd_kcontrol_new control
[] = {
988 SOC_ENUM_EXT("VSS HPF Mode", wm8994
->vss_hpf_enum
,
989 wm8958_get_vss_hpf_enum
,
990 wm8958_put_vss_hpf_enum
),
993 /* We need an array of texts for the enum API */
994 wm8994
->vss_hpf_texts
= kmalloc(sizeof(char *)
995 * pdata
->num_vss_hpf_cfgs
, GFP_KERNEL
);
996 if (!wm8994
->vss_hpf_texts
) {
997 dev_err(wm8994
->hubs
.codec
->dev
,
998 "Failed to allocate %d VSS HPF config texts\n",
999 pdata
->num_vss_hpf_cfgs
);
1003 for (i
= 0; i
< pdata
->num_vss_hpf_cfgs
; i
++)
1004 wm8994
->vss_hpf_texts
[i
] = pdata
->vss_hpf_cfgs
[i
].name
;
1006 wm8994
->vss_hpf_enum
.max
= pdata
->num_vss_hpf_cfgs
;
1007 wm8994
->vss_hpf_enum
.texts
= wm8994
->vss_hpf_texts
;
1009 ret
= snd_soc_add_codec_controls(wm8994
->hubs
.codec
,
1012 dev_err(wm8994
->hubs
.codec
->dev
,
1013 "Failed to add VSS HPFmode controls: %d\n",
1017 if (pdata
->num_enh_eq_cfgs
) {
1018 struct snd_kcontrol_new control
[] = {
1019 SOC_ENUM_EXT("Enhanced EQ Mode", wm8994
->enh_eq_enum
,
1020 wm8958_get_enh_eq_enum
,
1021 wm8958_put_enh_eq_enum
),
1024 /* We need an array of texts for the enum API */
1025 wm8994
->enh_eq_texts
= kmalloc(sizeof(char *)
1026 * pdata
->num_enh_eq_cfgs
, GFP_KERNEL
);
1027 if (!wm8994
->enh_eq_texts
) {
1028 dev_err(wm8994
->hubs
.codec
->dev
,
1029 "Failed to allocate %d enhanced EQ config texts\n",
1030 pdata
->num_enh_eq_cfgs
);
1034 for (i
= 0; i
< pdata
->num_enh_eq_cfgs
; i
++)
1035 wm8994
->enh_eq_texts
[i
] = pdata
->enh_eq_cfgs
[i
].name
;
1037 wm8994
->enh_eq_enum
.max
= pdata
->num_enh_eq_cfgs
;
1038 wm8994
->enh_eq_enum
.texts
= wm8994
->enh_eq_texts
;
1040 ret
= snd_soc_add_codec_controls(wm8994
->hubs
.codec
,
1043 dev_err(wm8994
->hubs
.codec
->dev
,
1044 "Failed to add enhanced EQ controls: %d\n",