2 * sound/soc/sprd/dai/vbc/r1p0/vbc-codec.c
4 * SPRD SoC VBC Codec -- SpreadTrum SOC VBC Codec function.
6 * Copyright (C) 2013 SpreadTrum Ltd.
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 #include <linux/module.h>
18 #include <linux/moduleparam.h>
19 #include <linux/init.h>
20 #include <linux/kernel.h>
21 #include <linux/string.h>
22 #include <linux/sysfs.h>
23 #include <linux/stat.h>
24 #include <linux/device.h>
25 #include <linux/platform_device.h>
26 #include <linux/slab.h>
27 #include <linux/firmware.h>
28 #include <linux/workqueue.h>
30 #include <sound/core.h>
31 #include <sound/soc.h>
32 #include <sound/soc-dapm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/tlv.h>
36 #include "sprd-asoc-common.h"
37 #include "vbc-codec.h"
39 #define FUN_REG(f) ((unsigned short)(-((f) + 1)))
40 #define SOC_REG(r) ((unsigned short)(r))
42 struct vbc_fw_header {
43 char magic[VBC_EQ_FIRMWARE_MAGIC_LEN];
48 struct vbc_eq_profile {
49 char magic[VBC_EQ_FIRMWARE_MAGIC_LEN];
50 char name[VBC_EQ_PROFILE_NAME_MAX];
52 u32 effect_paras[VBC_EFFECT_PARAS_LEN];
55 static const u32 vbc_eq_profile_default[VBC_EFFECT_PARAS_LEN] = {
56 /* TODO the default register value */
57 0x00000000, /* DAPATCHCTL */
58 0x00001818, /* DADGCTL */
59 0x0000007F, /* DAHPCTL */
60 0x00000000, /* DAALCCTL0 */
61 0x00000000, /* DAALCCTL1 */
62 0x00000000, /* DAALCCTL2 */
63 0x00000000, /* DAALCCTL3 */
64 0x00000000, /* DAALCCTL4 */
65 0x00000000, /* DAALCCTL5 */
66 0x00000000, /* DAALCCTL6 */
67 0x00000000, /* DAALCCTL7 */
68 0x00000000, /* DAALCCTL8 */
69 0x00000000, /* DAALCCTL9 */
70 0x00000000, /* DAALCCTL10 */
71 0x00000183, /* STCTL0 */
72 0x00000183, /* STCTL1 */
73 0x00000000, /* ADPATCHCTL */
74 0x00001818, /* ADDGCTL */
75 0x00000000, /* HPCOEF0 */
80 struct snd_soc_codec *codec;
85 struct vbc_fw_header hdr;
86 struct vbc_eq_profile *data;
87 void (*vbc_eq_apply) (struct snd_soc_codec * codec, void *data,
91 static void vbc_eq_try_apply(struct snd_soc_codec *codec, int vbc_idx);
93 #define VBC_DG_VAL_MAX (0x7F)
95 typedef int (*vbc_dg_set) (int enable, int dg);
110 SPRD_VBC_MUX_START = 0,
117 #define IS_SPRD_VBC_MUX_RANG(reg) ((reg) >= SPRD_VBC_MUX_START && (reg) < (SPRD_VBC_MUX_MAX))
118 #define SPRD_VBC_MUX_IDX(reg) (reg - SPRD_VBC_MUX_START)
120 static const char *vbc_mux_debug_str[SPRD_VBC_MUX_MAX] = {
126 typedef int (*sprd_vbc_mux_set) (int sel);
127 struct sprd_vbc_mux_op {
129 sprd_vbc_mux_set set;
133 VBC_LOOP_SWITCH_START = SPRD_VBC_MUX_MAX,
134 VBC_AD_LOOP_SWITCH = VBC_LOOP_SWITCH_START,
138 #define IS_SPRD_VBC_SWITCH_RANG(reg) ((reg) >= VBC_LOOP_SWITCH_START && (reg) < (VBC_LOOP_SWITCH_MAX))
139 #define SPRD_VBC_SWITCH_IDX(reg) (reg - VBC_LOOP_SWITCH_START)
141 struct vbc_codec_priv {
142 struct snd_soc_codec *codec;
143 struct vbc_equ vbc_eq_setting;
144 struct mutex load_mutex;
146 int vbc_loop_switch[SPRD_VBC_SWITCH_IDX(VBC_LOOP_SWITCH_MAX)];
147 struct vbc_dg dg[VBC_IDX_MAX];
149 int adc_dgmux_val[ADC_DGMUX_MAX];
150 struct st_hpf_dg st_dg;
151 struct sprd_vbc_mux_op sprd_vbc_mux[SPRD_VBC_MUX_MAX];
154 static int vbc_ad0_inmux_set(int val)
156 vbc_reg_update(ADPATCHCTL, val << VBADPATH_AD0_INMUX_SHIFT,
157 VBADPATH_AD0_INMUX_MASK);
161 static int vbc_ad1_inmux_set(int val)
163 vbc_reg_update(ADPATCHCTL, val << VBADPATH_AD1_INMUX_SHIFT,
164 VBADPATH_AD1_INMUX_MASK);
168 static int vbc_ad0_dgmux_set(int val)
170 vbc_reg_update(ADPATCHCTL, val << VBADPATH_AD0_DGMUX_SHIFT,
171 VBADPATH_AD0_DGMUX_MASK);
175 static int vbc_ad1_dgmux_set(int val)
177 vbc_reg_update(ADPATCHCTL, val << VBADPATH_AD1_DGMUX_SHIFT,
178 VBADPATH_AD1_DGMUX_MASK);
182 static int vbc_ad_iismux_set(int port)
184 vbc_reg_update(VBIISSEL, port << VBIISSEL_AD_PORT_SHIFT,
185 VBIISSEL_AD_PORT_MASK);
189 static int vbc_da_iismux_set(int port)
191 vbc_reg_update(VBIISSEL, port << VBIISSEL_DA_PORT_SHIFT,
192 VBIISSEL_DA_PORT_MASK);
196 static int vbc_try_ad_iismux_set(int port);
198 static sprd_vbc_mux_set vbc_mux_cfg[SPRD_VBC_MUX_MAX] = {
201 vbc_try_ad_iismux_set,
204 static inline int vbc_da0_dg_set(int enable, int dg)
207 vbc_reg_update(DADGCTL, 0x80 | (0xFF & dg), 0xFF);
209 vbc_reg_update(DADGCTL, 0, 0x80);
214 static inline int vbc_da1_dg_set(int enable, int dg)
217 vbc_reg_update(DADGCTL, (0x80 | (0xFF & dg)) << 8, 0xFF00);
219 vbc_reg_update(DADGCTL, 0, 0x8000);
224 static inline int vbc_ad0_dg_set(int enable, int dg)
227 vbc_reg_update(ADDGCTL, 0x80 | (0xFF & dg), 0xFF);
229 vbc_reg_update(ADDGCTL, 0, 0x80);
234 static inline int vbc_ad1_dg_set(int enable, int dg)
237 vbc_reg_update(ADDGCTL, (0x80 | (0xFF & dg)) << 8, 0xFF00);
239 vbc_reg_update(ADDGCTL, 0, 0x8000);
244 static inline int vbc_st0_dg_set(int dg)
246 vbc_reg_update(STCTL0, (0x7F & dg) << 4, 0x7F0);
250 static inline int vbc_st1_dg_set(int dg)
252 vbc_reg_update(STCTL1, (0x7F & dg) << 4, 0x7F0);
256 static inline int vbc_st0_hpf_set(int enable, int hpf_val)
259 vbc_reg_update(STCTL0, BIT(VBST_HPF_0), BIT(VBST_HPF_0));
260 vbc_reg_update(STCTL0, 0xF & hpf_val, 0xF);
262 vbc_reg_update(STCTL0, 0, BIT(VBST_HPF_0));
263 vbc_reg_update(STCTL0, 3, 0xF);
268 static inline int vbc_st1_hpf_set(int enable, int hpf_val)
271 vbc_reg_update(STCTL1, BIT(VBST_HPF_1), BIT(VBST_HPF_1));
272 vbc_reg_update(STCTL1, 0xF & hpf_val, 0xF);
274 vbc_reg_update(STCTL1, 0, BIT(VBST_HPF_1));
275 vbc_reg_update(STCTL1, 3, 0xF);
280 static int vbc_try_dg_set(struct vbc_codec_priv *vbc_codec, int vbc_idx, int id)
282 struct vbc_dg *p_dg = &vbc_codec->dg[vbc_idx];
283 int dg = p_dg->dg_val[id];
284 if (p_dg->dg_switch[id]) {
285 p_dg->dg_set[id] (1, dg);
287 p_dg->dg_set[id] (0, dg);
292 static int vbc_try_st_dg_set(struct vbc_codec_priv *vbc_codec, int id)
294 struct st_hpf_dg *p_st_dg = &vbc_codec->st_dg;
295 if (id == VBC_LEFT) {
296 vbc_st0_dg_set(p_st_dg->dg_val[id]);
298 vbc_st1_dg_set(p_st_dg->dg_val[id]);
303 static int vbc_try_st_hpf_set(struct vbc_codec_priv *vbc_codec, int id)
305 struct st_hpf_dg *p_st_dg = &vbc_codec->st_dg;
306 if (id == VBC_LEFT) {
307 vbc_st0_hpf_set(p_st_dg->hpf_switch[id], p_st_dg->hpf_val[id]);
309 vbc_st1_hpf_set(p_st_dg->hpf_switch[id], p_st_dg->hpf_val[id]);
314 static int vbc_try_da_iismux_set(int port)
316 return vbc_da_iismux_set(port ? (port + 1) : 0);
319 static int vbc_try_ad_iismux_set(int port)
321 return vbc_ad_iismux_set(port);
324 static int vbc_try_ad_dgmux_set(struct vbc_codec_priv *vbc_codec, int id)
328 vbc_ad0_dgmux_set(vbc_codec->adc_dgmux_val[ADC0_DGMUX]);
331 vbc_ad1_dgmux_set(vbc_codec->adc_dgmux_val[ADC1_DGMUX]);
339 #ifdef CONFIG_SND_SOC_SPRD_AUDIO_DEBUG
340 static const char *get_event_name(int event)
344 case SND_SOC_DAPM_PRE_PMU:
347 case SND_SOC_DAPM_POST_PMU:
348 ev_name = "POST_PMU";
350 case SND_SOC_DAPM_PRE_PMD:
353 case SND_SOC_DAPM_POST_PMD:
354 ev_name = "POST_PMD";
364 static const char *ad0_inmux_txt[] = {
365 "IIS0AD0", "IIS1AD0", "NOINPUT",
368 static const char *ad1_inmux_txt[] = {
369 "IIS1AD1", "IIS0AD1", "NOINPUT",
372 static const char *ad_iis_txt[] = {
376 #define SPRD_VBC_ENUM(xreg, xmax, xtexts)\
377 SOC_ENUM_SINGLE(FUN_REG(xreg), 0, xmax, xtexts)
379 static const struct soc_enum vbc_mux_sel_enum[SPRD_VBC_MUX_MAX] = {
381 SPRD_VBC_ENUM(SPRD_VBC_AD0_INMUX, 4, ad0_inmux_txt),
382 SPRD_VBC_ENUM(SPRD_VBC_AD1_INMUX, 4, ad1_inmux_txt),
384 SPRD_VBC_ENUM(SPRD_VBC_AD_IISMUX, 4, ad_iis_txt),
387 static int vbc_chan_event(struct snd_soc_dapm_widget *w,
388 struct snd_kcontrol *kcontrol, int event)
390 int vbc_idx = FUN_REG(w->reg);
394 sp_asoc_pr_dbg("%s(%s%d) Event is %s\n", __func__,
395 vbc_get_name(vbc_idx), chan, get_event_name(event));
398 case SND_SOC_DAPM_PRE_PMU:
399 vbc_chan_enable(1, vbc_idx, chan);
401 case SND_SOC_DAPM_POST_PMD:
402 vbc_chan_enable(0, vbc_idx, chan);
413 static int vbc_power_event(struct snd_soc_dapm_widget *w,
414 struct snd_kcontrol *kcontrol, int event)
418 sp_asoc_pr_dbg("%s Event is %s\n", __func__, get_event_name(event));
421 case SND_SOC_DAPM_PRE_PMU:
424 case SND_SOC_DAPM_POST_PMD:
436 static int dfm_event(struct snd_soc_dapm_widget *w,
437 struct snd_kcontrol *kcontrol, int event)
439 struct snd_soc_codec *codec = w->codec;
440 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
441 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
444 sp_asoc_pr_dbg("%s Event is %s\n", __func__, get_event_name(event));
446 case SND_SOC_DAPM_POST_PMU:
447 fm_set_vbc_buffer_size(); /*No use in FM function, just for debug VBC */
448 vbc_try_st_dg_set(vbc_codec, VBC_LEFT);
449 vbc_try_st_dg_set(vbc_codec, VBC_RIGHT);
450 if (!p_eq_setting->codec)
451 p_eq_setting->codec = codec;
453 if (p_eq_setting->is_active && p_eq_setting->data)
454 vbc_eq_try_apply(codec, VBC_PLAYBACK);
457 case SND_SOC_DAPM_PRE_PMD:
468 static int aud_event(struct snd_soc_dapm_widget *w,
469 struct snd_kcontrol *kcontrol, int event)
471 struct snd_soc_codec *codec = w->codec;
472 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
473 unsigned int vbc_idx = FUN_REG(w->reg);
474 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
477 sp_asoc_pr_dbg("%s Event is %s\n Chan is %s", __func__,
478 get_event_name(event), vbc_get_name(vbc_idx));
481 case SND_SOC_DAPM_PRE_PMU:
483 if (!p_eq_setting->codec)
484 p_eq_setting->codec = codec;
485 if (p_eq_setting->is_active && p_eq_setting->data)
486 vbc_eq_try_apply(codec, vbc_idx);
488 case SND_SOC_DAPM_PRE_PMD:
498 static int mux_event(struct snd_soc_dapm_widget *w,
499 struct snd_kcontrol *kcontrol, int event)
501 struct snd_soc_codec *codec = w->codec;
502 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
503 unsigned int id = SPRD_VBC_MUX_IDX(FUN_REG(w->reg));
504 struct sprd_vbc_mux_op *mux = &(vbc_codec->sprd_vbc_mux[id]);
507 sp_asoc_pr_dbg("%s Set %s(%d) Event is %s\n", __func__,
508 vbc_mux_debug_str[id], mux->val, get_event_name(event));
511 case SND_SOC_DAPM_PRE_PMU:
512 mux->set = vbc_mux_cfg[id];
513 ret = mux->set(mux->val);
515 case SND_SOC_DAPM_PRE_PMD:
517 ret = vbc_mux_cfg[id] (0);
527 static int sprd_vbc_mux_get(struct snd_kcontrol *kcontrol,
528 struct snd_ctl_elem_value *ucontrol)
530 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
531 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
532 struct snd_soc_codec *codec = widget->codec;
533 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
534 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
535 unsigned int reg = SPRD_VBC_MUX_IDX(FUN_REG(e->reg));
536 struct sprd_vbc_mux_op *mux = &(vbc_codec->sprd_vbc_mux[reg]);
538 ucontrol->value.enumerated.item[0] = mux->val;
543 static int sprd_vbc_mux_put(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
546 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
547 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
548 struct snd_soc_codec *codec = widget->codec;
549 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
550 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
551 unsigned int reg = SPRD_VBC_MUX_IDX(FUN_REG(e->reg));
552 unsigned int max = e->max;
553 unsigned int mask = (1 << fls(max)) - 1;
554 struct sprd_vbc_mux_op *mux = &(vbc_codec->sprd_vbc_mux[reg]);
557 if (mux->val == ucontrol->value.enumerated.item[0])
560 sp_asoc_pr_info("Set MUX[%s] to %d\n", vbc_mux_debug_str[reg],
561 ucontrol->value.enumerated.item[0]);
563 if (ucontrol->value.enumerated.item[0] > e->max - 1)
566 /*notice the sequence */
567 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
569 /*update reg: must be set after snd_soc_dapm_put_enum_double->change = snd_soc_test_bits(widget->codec, e->reg, mask, val); */
570 mux->val = (ucontrol->value.enumerated.item[0] & mask);
572 ret = mux->set(mux->val);
578 #define SPRD_VBC_MUX(xname, xenum) \
579 SOC_DAPM_ENUM_EXT(xname, xenum, sprd_vbc_mux_get, sprd_vbc_mux_put)
581 static const struct snd_kcontrol_new vbc_mux[SPRD_VBC_MUX_MAX] = {
582 SPRD_VBC_MUX("AD0 INMUX", vbc_mux_sel_enum[SPRD_VBC_AD0_INMUX]),
583 SPRD_VBC_MUX("AD1 INMUX", vbc_mux_sel_enum[SPRD_VBC_AD1_INMUX]),
584 SPRD_VBC_MUX("AD IISMUX", vbc_mux_sel_enum[SPRD_VBC_AD_IISMUX]),
587 #define VBC_DAPM_MUX_E(wname, wreg) \
588 SND_SOC_DAPM_MUX_E(wname, FUN_REG(wreg), 0, 0, &vbc_mux[wreg], mux_event, \
589 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)
591 static int vbc_loop_switch_get(struct snd_kcontrol *kcontrol,
592 struct snd_ctl_elem_value *ucontrol)
594 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
595 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
596 struct snd_soc_codec *codec = widget->codec;
597 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
598 struct soc_mixer_control *mc =
599 (struct soc_mixer_control *)kcontrol->private_value;
600 int id = SPRD_VBC_SWITCH_IDX(FUN_REG(mc->reg));
601 ucontrol->value.integer.value[0] = vbc_codec->vbc_loop_switch[id];
605 static int vbc_loop_switch_put(struct snd_kcontrol *kcontrol,
606 struct snd_ctl_elem_value *ucontrol)
609 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
610 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
611 struct snd_soc_codec *codec = widget->codec;
612 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
613 struct soc_mixer_control *mc =
614 (struct soc_mixer_control *)kcontrol->private_value;
615 int id = SPRD_VBC_SWITCH_IDX(FUN_REG(mc->reg));
617 ret = ucontrol->value.integer.value[0];
618 if (ret == vbc_codec->vbc_loop_switch[id]) {
622 sp_asoc_pr_info("VBC AD LOOP Switch Set %x\n",
623 (int)ucontrol->value.integer.value[0]);
625 snd_soc_dapm_put_volsw(kcontrol, ucontrol);
627 vbc_codec->vbc_loop_switch[id] = ret;
632 static const struct snd_kcontrol_new vbc_loop_control[] = {
633 SOC_SINGLE_EXT("Switch",
634 FUN_REG(VBC_AD_LOOP_SWITCH),
637 vbc_loop_switch_put),
640 static const struct snd_soc_dapm_widget vbc_codec_dapm_widgets[] = {
642 SND_SOC_DAPM_SUPPLY("VBC Power", SND_SOC_NOPM, 0, 0,
644 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
647 VBC_DAPM_MUX_E("AD0 INMUX", SPRD_VBC_AD0_INMUX),
648 VBC_DAPM_MUX_E("AD1 INMUX", SPRD_VBC_AD1_INMUX),
651 VBC_DAPM_MUX_E("AD IISMUX", SPRD_VBC_AD_IISMUX),
654 SND_SOC_DAPM_PGA_S("ST0 Switch", 4, SOC_REG(STCTL0), VBST_EN_0, 0, NULL,
656 SND_SOC_DAPM_PGA_S("ST1 Switch", 4, SOC_REG(STCTL1), VBST_EN_1, 0, NULL,
660 SND_SOC_DAPM_PGA_S("DA0 FM Mixer", 4, SOC_REG(DAPATCHCTL),
661 VBDAPATH_DA0_ADDFM_SHIFT, 0, NULL, 0),
662 SND_SOC_DAPM_PGA_S("DA1 FM Mixer", 4, SOC_REG(DAPATCHCTL),
663 VBDAPATH_DA1_ADDFM_SHIFT, 0, NULL, 0),
665 SND_SOC_DAPM_LINE("DFM", dfm_event),
668 SND_SOC_DAPM_PGA_S("DA0 Switch", 5, FUN_REG(VBC_PLAYBACK), VBC_LEFT, 0,
670 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
672 SND_SOC_DAPM_PGA_S("DA1 Switch", 5, FUN_REG(VBC_PLAYBACK), VBC_RIGHT, 0,
674 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
676 SND_SOC_DAPM_PGA_S("AD0 Switch", 5, FUN_REG(VBC_CAPTRUE), VBC_LEFT, 0,
678 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
680 SND_SOC_DAPM_PGA_S("AD1 Switch", 5, FUN_REG(VBC_CAPTRUE), VBC_RIGHT, 0,
682 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
684 /*AUD loop var vbc switch */
685 SND_SOC_DAPM_PGA_S("Aud input", 4, FUN_REG(VBC_CAPTRUE), 0, 0,
687 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
688 SND_SOC_DAPM_SWITCH("Aud Loop in VBC", SND_SOC_NOPM, 0, 0,
689 &vbc_loop_control[SPRD_VBC_SWITCH_IDX
690 (VBC_AD_LOOP_SWITCH)]),
693 /* sprd_vbc supported interconnection*/
694 static const struct snd_soc_dapm_route vbc_codec_intercon[] = {
695 /************************power********************************/
696 /* digital fm playback need to open DA Clk and DA power */
697 {"DFM", NULL, "VBC Power"},
699 /********************** capture in path in vbc ********************/
701 {"Aud Loop in VBC", "Switch", "Aud input"},
704 {"AD IISMUX", "DIGFM", "Dig FM Jack"},
705 {"AD IISMUX", "AUDIIS0", "Aud Loop in VBC"},
707 {"AD0 INMUX", "IIS0AD0", "AD IISMUX"},
708 {"AD0 INMUX", "IIS1AD0", "AD IISMUX"},
709 {"AD1 INMUX", "IIS1AD1", "AD IISMUX"},
710 {"AD1 INMUX", "IIS0AD1", "AD IISMUX"},
712 {"AD0 Switch", NULL, "AD0 INMUX"},
713 {"AD1 Switch", NULL, "AD1 INMUX"},
715 /********************** fm playback route ********************/
717 {"ST0 INMUX", NULL, "AD0 Switch"},
718 {"ST1 INMUX", NULL, "AD1 Switch"},
720 {"ST0 Switch", NULL, "ST0 INMUX"},
721 {"ST1 Switch", NULL, "ST1 INMUX"},
722 {"DA0 Switch", NULL, "ST0 Switch"},
723 {"DA1 Switch", NULL, "ST1 Switch"},
724 {"DA0 FM Mixer", NULL, "DA0 Switch"},
725 {"DA1 FM Mixer", NULL, "DA1 Switch"},
726 {"DFM", NULL, "DA0 FM Mixer"},
727 {"DFM", NULL, "DA1 FM Mixer"},
730 int vbc_codec_startup(int vbc_idx, struct snd_soc_dai *dai)
732 struct vbc_codec_priv *vbc_codec = dev_get_drvdata(dai->dev);
733 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
734 sp_asoc_pr_dbg("%s %s\n", __func__, vbc_get_name(vbc_idx));
738 vbc_try_da_iismux_set(vbc_codec->vbc_da_iis_port);
741 vbc_try_ad_iismux_set(vbc_codec->sprd_vbc_mux
742 [SPRD_VBC_AD_IISMUX].val);
743 vbc_try_ad_dgmux_set(vbc_codec, 0);
744 vbc_try_ad_dgmux_set(vbc_codec, 1);
748 if (p_eq_setting->is_active && p_eq_setting->data)
749 vbc_eq_try_apply(vbc_codec->codec, vbc_idx);
751 vbc_try_dg_set(vbc_codec, vbc_idx, VBC_LEFT);
752 vbc_try_dg_set(vbc_codec, vbc_idx, VBC_RIGHT);
761 #ifdef CONFIG_PROC_FS
762 static void vbc_proc_read(struct snd_info_entry *entry,
763 struct snd_info_buffer *buffer)
767 snd_iprintf(buffer, "vbc register dump\n");
768 for (reg = ARM_VB_BASE + 0x10; reg < ARM_VB_END; reg += 0x10) {
769 snd_iprintf(buffer, "0x%04x | 0x%04x 0x%04x 0x%04x 0x%04x\n",
771 , vbc_reg_read(reg + 0x00)
772 , vbc_reg_read(reg + 0x04)
773 , vbc_reg_read(reg + 0x08)
774 , vbc_reg_read(reg + 0x0C)
779 static void vbc_proc_init(struct snd_soc_codec *codec)
781 struct snd_info_entry *entry;
783 if (!snd_card_proc_new(codec->card->snd_card, "vbc", &entry))
784 snd_info_set_text_ops(entry, NULL, vbc_proc_read);
786 #else /* !CONFIG_PROC_FS */
787 static inline void vbc_proc_init(struct snd_soc_codec *codec)
792 static int vbc_eq_reg_offset(u32 reg)
795 if ((reg >= DAPATCHCTL) && (reg <= ADDGCTL)) {
796 i = (reg - DAPATCHCTL) >> 2;
797 } else if ((reg >= HPCOEF0) && (reg <= HPCOEF42)) {
798 i = ((reg - HPCOEF0) >> 2) + ((ADDGCTL - DAPATCHCTL) >> 2) + 1;
800 BUG_ON(i >= VBC_EFFECT_PARAS_LEN);
804 static inline void vbc_eq_reg_set(u32 reg, void *data)
806 u32 *effect_paras = (u32 *) data;
807 vbc_reg_write(reg, effect_paras[vbc_eq_reg_offset(reg)]);
810 static inline void vbc_eq_reg_set_range(u32 reg_start, u32 reg_end, void *data)
813 for (reg_addr = reg_start; reg_addr <= reg_end; reg_addr += 4) {
814 vbc_eq_reg_set(reg_addr, data);
818 static void vbc_eq_reg_apply(struct snd_soc_codec *codec, void *data,
821 if (vbc_idx == VBC_PLAYBACK) {
822 vbc_eq_reg_set_range(DAALCCTL0, DAALCCTL10, data);
823 vbc_eq_reg_set_range(HPCOEF0, HPCOEF42, data);
825 vbc_eq_reg_set(DAHPCTL, data);
826 /*FM function maybe use this regs,and EQ setting don't use them */
827 /*vbc_da_eq_reg_set(DAPATCHCTL, data); */
829 /*vbc_da_eq_reg_set(STCTL0, data); */
830 /*vbc_da_eq_reg_set(STCTL1, data); */
833 vbc_eq_reg_set(ADPATCHCTL, data);
837 static void vbc_eq_profile_apply(struct snd_soc_codec *codec, void *data,
841 vbc_eq_reg_apply(codec, data, vbc_idx);
845 static void vbc_eq_profile_close(struct snd_soc_codec *codec, int vbc_idx)
847 vbc_eq_profile_apply(codec, &vbc_eq_profile_default, vbc_idx);
850 static void vbc_eq_try_apply(struct snd_soc_codec *codec, int vbc_idx)
852 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
853 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
856 sp_asoc_pr_dbg("%s 0x%x\n", __func__, (int)p_eq_setting->vbc_eq_apply);
857 if (p_eq_setting->vbc_eq_apply) {
858 struct vbc_eq_profile *now;
859 mutex_lock(&vbc_codec->load_mutex);
860 now = &p_eq_setting->data[p_eq_setting->now_profile];
861 data = now->effect_paras;
862 sp_asoc_pr_info("VBC %s EQ Apply '%s'\n",
863 vbc_get_name(vbc_idx), now->name);
864 p_eq_setting->vbc_eq_apply(codec, data, vbc_idx);
865 mutex_unlock(&vbc_codec->load_mutex);
869 static int vbc_eq_profile_get(struct snd_kcontrol *kcontrol,
870 struct snd_ctl_elem_value *ucontrol)
872 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
873 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
874 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
875 ucontrol->value.integer.value[0] = p_eq_setting->now_profile;
879 static int vbc_eq_profile_put(struct snd_kcontrol *kcontrol,
880 struct snd_ctl_elem_value *ucontrol)
883 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
884 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
885 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
886 struct soc_mixer_control *mc =
887 (struct soc_mixer_control *)kcontrol->private_value;
888 int vbc_idx = FUN_REG(mc->reg);
891 profile_max = p_eq_setting->hdr.num_profile;
893 ret = ucontrol->value.integer.value[0];
894 if (ret == p_eq_setting->now_profile) {
898 sp_asoc_pr_info("VBC %s EQ Select %ld max %d\n",
899 vbc_get_name(vbc_idx),
900 ucontrol->value.integer.value[0], profile_max);
902 if (ret < profile_max) {
903 p_eq_setting->now_profile = ret;
906 if (p_eq_setting->is_active && p_eq_setting->data)
907 vbc_eq_try_apply(codec, vbc_idx);
912 static int vbc_eq_loading(struct snd_soc_codec *codec)
916 const struct firmware *fw;
921 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
922 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
924 sp_asoc_pr_dbg("%s\n", __func__);
925 mutex_lock(&vbc_codec->load_mutex);
926 p_eq_setting->is_loading = 1;
928 /* request firmware for VBC EQ */
929 ret = request_firmware(&fw, "vbc_eq", p_eq_setting->dev);
931 pr_err("ERR:Failed to load firmware: %d\n", ret);
935 old_num_profile = p_eq_setting->hdr.num_profile;
937 memcpy(&p_eq_setting->hdr, fw_data, sizeof(p_eq_setting->hdr));
940 (p_eq_setting->hdr.magic, VBC_EQ_FIRMWARE_MAGIC_ID,
941 VBC_EQ_FIRMWARE_MAGIC_LEN)) {
942 pr_err("ERR:Firmware magic error!\n");
947 if (p_eq_setting->hdr.profile_version != VBC_EQ_PROFILE_VERSION) {
948 pr_err("ERR:Firmware support version is 0x%x!\n",
949 VBC_EQ_PROFILE_VERSION);
954 if (p_eq_setting->hdr.num_profile > VBC_EQ_PROFILE_CNT_MAX) {
956 ("ERR:Firmware profile to large at %d, max count is %d!\n",
957 p_eq_setting->hdr.num_profile, VBC_EQ_PROFILE_CNT_MAX);
962 if (old_num_profile != p_eq_setting->hdr.num_profile) {
963 vbc_safe_kfree(&p_eq_setting->data);
966 len = p_eq_setting->hdr.num_profile * sizeof(struct vbc_eq_profile);
967 if (p_eq_setting->data == NULL) {
968 p_eq_setting->data = kzalloc(len, GFP_KERNEL);
969 if (p_eq_setting->data == NULL) {
974 offset = sizeof(struct vbc_fw_header);
975 memcpy(p_eq_setting->data, fw_data + offset, len);
977 for (i = 0; i < p_eq_setting->hdr.num_profile; i++) {
978 const char *magic = (char *)p_eq_setting->data[i].magic;
980 (magic, VBC_EQ_FIRMWARE_MAGIC_ID,
981 VBC_EQ_FIRMWARE_MAGIC_LEN)) {
983 ("ERR:Firmware profile[%d] magic error!magic: %s \n",
994 release_firmware(fw);
996 p_eq_setting->is_loading = 0;
997 mutex_unlock(&vbc_codec->load_mutex);
999 if (p_eq_setting->is_active && p_eq_setting->data)
1000 vbc_eq_try_apply(codec, 0);
1002 sp_asoc_pr_dbg("return %i\n", ret);
1006 static int vbc_switch_get(struct snd_kcontrol *kcontrol,
1007 struct snd_ctl_elem_value *ucontrol)
1010 ret = arch_audio_vbc_switch(AUDIO_NO_CHANGE);
1012 ucontrol->value.integer.value[0] =
1013 (ret == AUDIO_TO_DSP_CTRL ? 0 : 1);
1017 static int vbc_switch_reg_val[];
1018 static int vbc_switch_put(struct snd_kcontrol *kcontrol,
1019 struct snd_ctl_elem_value *ucontrol)
1022 struct soc_enum *texts = (struct soc_enum *)kcontrol->private_value;
1024 sp_asoc_pr_info("VBC Switch to %s\n",
1025 texts->texts[ucontrol->value.integer.value[0]]);
1027 ret = ucontrol->value.integer.value[0];
1028 ret = arch_audio_vbc_switch(ret == 0 ?
1029 AUDIO_TO_DSP_CTRL : AUDIO_TO_ARM_CTRL);
1034 static int vbc_eq_switch_get(struct snd_kcontrol *kcontrol,
1035 struct snd_ctl_elem_value *ucontrol)
1037 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1038 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1039 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
1040 ucontrol->value.integer.value[0] = p_eq_setting->is_active;
1044 static int vbc_eq_switch_put(struct snd_kcontrol *kcontrol,
1045 struct snd_ctl_elem_value *ucontrol)
1047 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1048 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1049 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
1050 struct soc_mixer_control *mc =
1051 (struct soc_mixer_control *)kcontrol->private_value;
1052 int id = FUN_REG(mc->reg);
1055 ret = ucontrol->value.integer.value[0];
1056 if (ret == p_eq_setting->is_active) {
1060 sp_asoc_pr_info("VBC EQ Switch %s\n",
1061 STR_ON_OFF(ucontrol->value.integer.value[0]));
1063 if ((ret == 0) || (ret == 1)) {
1064 p_eq_setting->is_active = ret;
1065 if (p_eq_setting->is_active && p_eq_setting->data) {
1066 p_eq_setting->vbc_eq_apply = vbc_eq_profile_apply;
1067 vbc_eq_try_apply(codec, id);
1069 p_eq_setting->vbc_eq_apply = 0;
1070 vbc_eq_profile_close(codec, id);
1077 static int vbc_eq_load_get(struct snd_kcontrol *kcontrol,
1078 struct snd_ctl_elem_value *ucontrol)
1080 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1081 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1082 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
1083 ucontrol->value.integer.value[0] = p_eq_setting->is_loading;
1087 static int vbc_eq_load_put(struct snd_kcontrol *kcontrol,
1088 struct snd_ctl_elem_value *ucontrol)
1090 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1092 struct soc_enum *texts = (struct soc_enum *)kcontrol->private_value;
1094 sp_asoc_pr_info("VBC EQ %s\n",
1095 texts->texts[ucontrol->value.integer.value[0]]);
1097 ret = ucontrol->value.integer.value[0];
1099 ret = vbc_eq_loading(codec);
1105 static int vbc_dg_get(struct snd_kcontrol *kcontrol,
1106 struct snd_ctl_elem_value *ucontrol)
1108 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1109 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1110 struct soc_mixer_control *mc =
1111 (struct soc_mixer_control *)kcontrol->private_value;
1112 int id = FUN_REG(mc->reg);
1113 int vbc_idx = mc->shift;
1115 ucontrol->value.integer.value[0] = vbc_codec->dg[vbc_idx].dg_val[id];
1119 static int vbc_dg_put(struct snd_kcontrol *kcontrol,
1120 struct snd_ctl_elem_value *ucontrol)
1123 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1124 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1125 struct soc_mixer_control *mc =
1126 (struct soc_mixer_control *)kcontrol->private_value;
1127 int id = FUN_REG(mc->reg);
1128 int vbc_idx = mc->shift;
1130 ret = ucontrol->value.integer.value[0];
1131 if (ret == vbc_codec->dg[vbc_idx].dg_val[id]) {
1135 sp_asoc_pr_info("VBC %s%d DG set 0x%02x\n",
1136 vbc_get_name(vbc_idx), id,
1137 (int)ucontrol->value.integer.value[0]);
1139 if (ret <= VBC_DG_VAL_MAX) {
1140 vbc_codec->dg[vbc_idx].dg_val[id] = ret;
1143 vbc_try_dg_set(vbc_codec, vbc_idx, id);
1148 static int vbc_st_dg_get(struct snd_kcontrol *kcontrol,
1149 struct snd_ctl_elem_value *ucontrol)
1151 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1152 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1153 struct soc_mixer_control *mc =
1154 (struct soc_mixer_control *)kcontrol->private_value;
1155 int id = FUN_REG(mc->reg);
1157 ucontrol->value.integer.value[0] = vbc_codec->st_dg.dg_val[id];
1161 static int vbc_st_dg_put(struct snd_kcontrol *kcontrol,
1162 struct snd_ctl_elem_value *ucontrol)
1165 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1166 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1167 struct soc_mixer_control *mc =
1168 (struct soc_mixer_control *)kcontrol->private_value;
1169 int id = FUN_REG(mc->reg);
1171 ret = ucontrol->value.integer.value[0];
1172 if (ret == vbc_codec->st_dg.dg_val[id]) {
1176 sp_asoc_pr_info("VBC ST%d DG set 0x%02x\n", id,
1177 (int)ucontrol->value.integer.value[0]);
1179 if (ret <= VBC_DG_VAL_MAX) {
1180 vbc_codec->st_dg.dg_val[id] = ret;
1183 vbc_try_st_dg_set(vbc_codec, id);
1188 static int vbc_dg_switch_get(struct snd_kcontrol *kcontrol,
1189 struct snd_ctl_elem_value *ucontrol)
1191 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1192 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1193 struct soc_mixer_control *mc =
1194 (struct soc_mixer_control *)kcontrol->private_value;
1195 int id = FUN_REG(mc->reg);
1196 int vbc_idx = mc->shift;
1198 ucontrol->value.integer.value[0] = vbc_codec->dg[vbc_idx].dg_switch[id];
1202 static int vbc_dg_switch_put(struct snd_kcontrol *kcontrol,
1203 struct snd_ctl_elem_value *ucontrol)
1206 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1207 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1208 struct soc_mixer_control *mc =
1209 (struct soc_mixer_control *)kcontrol->private_value;
1210 int id = FUN_REG(mc->reg);
1211 int vbc_idx = mc->shift;
1213 ret = ucontrol->value.integer.value[0];
1214 if (ret == vbc_codec->dg[vbc_idx].dg_switch[id]) {
1218 sp_asoc_pr_info("VBC %s%d DG Switch %s\n",
1219 vbc_get_name(vbc_idx), id,
1220 STR_ON_OFF(ucontrol->value.integer.value[0]));
1222 vbc_codec->dg[vbc_idx].dg_switch[id] = ret;
1224 vbc_try_dg_set(vbc_codec, vbc_idx, id);
1229 static int vbc_st_hpf_switch_get(struct snd_kcontrol *kcontrol,
1230 struct snd_ctl_elem_value *ucontrol)
1232 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1233 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1234 struct soc_mixer_control *mc =
1235 (struct soc_mixer_control *)kcontrol->private_value;
1236 int id = FUN_REG(mc->reg);
1238 ucontrol->value.integer.value[0] = vbc_codec->st_dg.hpf_switch[id];
1242 static int vbc_st_hpf_switch_put(struct snd_kcontrol *kcontrol,
1243 struct snd_ctl_elem_value *ucontrol)
1246 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1247 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1248 struct soc_mixer_control *mc =
1249 (struct soc_mixer_control *)kcontrol->private_value;
1250 int id = FUN_REG(mc->reg);
1252 ret = ucontrol->value.integer.value[0];
1253 if (ret == vbc_codec->st_dg.hpf_switch[id]) {
1257 sp_asoc_pr_info("VBC ST%d HPF Switch %s\n", id,
1258 STR_ON_OFF(ucontrol->value.integer.value[0]));
1260 vbc_codec->st_dg.hpf_switch[id] = ret;
1262 vbc_try_st_hpf_set(vbc_codec, id);
1267 static int vbc_st_hpf_get(struct snd_kcontrol *kcontrol,
1268 struct snd_ctl_elem_value *ucontrol)
1270 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1271 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1272 struct soc_mixer_control *mc =
1273 (struct soc_mixer_control *)kcontrol->private_value;
1274 int id = FUN_REG(mc->reg);
1276 ucontrol->value.integer.value[0] = vbc_codec->st_dg.hpf_val[id];
1280 static int vbc_st_hpf_put(struct snd_kcontrol *kcontrol,
1281 struct snd_ctl_elem_value *ucontrol)
1284 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1285 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1286 struct soc_mixer_control *mc =
1287 (struct soc_mixer_control *)kcontrol->private_value;
1288 int id = FUN_REG(mc->reg);
1290 ret = ucontrol->value.integer.value[0];
1291 if (ret == vbc_codec->st_dg.hpf_val[id]) {
1295 sp_asoc_pr_info("VBC ST%d HPF set 0x%02x\n", id,
1296 (int)ucontrol->value.integer.value[0]);
1298 if (ret <= VBC_DG_VAL_MAX) {
1299 vbc_codec->st_dg.hpf_val[id] = ret;
1302 vbc_try_st_hpf_set(vbc_codec, id);
1307 static int adc_dgmux_get(struct snd_kcontrol *kcontrol,
1308 struct snd_ctl_elem_value *ucontrol)
1310 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1311 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1312 struct soc_mixer_control *mc =
1313 (struct soc_mixer_control *)kcontrol->private_value;
1314 int id = FUN_REG(mc->reg);
1316 ucontrol->value.integer.value[0] = vbc_codec->adc_dgmux_val[id];
1320 static int adc_dgmux_put(struct snd_kcontrol *kcontrol,
1321 struct snd_ctl_elem_value *ucontrol)
1324 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1325 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1326 struct soc_mixer_control *mc =
1327 (struct soc_mixer_control *)kcontrol->private_value;
1328 int id = FUN_REG(mc->reg);
1330 ret = ucontrol->value.integer.value[0];
1331 if (ret == vbc_codec->adc_dgmux_val[id]) {
1335 sp_asoc_pr_info("VBC AD%d DG mux : %ld\n", id,
1336 ucontrol->value.integer.value[0]);
1338 vbc_codec->adc_dgmux_val[id] = ret;
1339 vbc_try_ad_dgmux_set(vbc_codec, id);
1344 static int dac_iismux_get(struct snd_kcontrol *kcontrol,
1345 struct snd_ctl_elem_value *ucontrol)
1347 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1348 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1349 ucontrol->value.integer.value[0] = vbc_codec->vbc_da_iis_port;
1353 static int dac_iismux_put(struct snd_kcontrol *kcontrol,
1354 struct snd_ctl_elem_value *ucontrol)
1356 struct soc_enum *texts = (struct soc_enum *)kcontrol->private_value;
1357 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1358 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1360 if (vbc_codec->vbc_da_iis_port == ucontrol->value.integer.value[0])
1363 sp_asoc_pr_info("VBC DA output to %s\n",
1364 texts->texts[ucontrol->value.integer.value[0]]);
1366 vbc_codec->vbc_da_iis_port = ucontrol->value.integer.value[0];
1368 vbc_try_da_iismux_set(vbc_codec->vbc_da_iis_port);
1373 static const char *switch_function[] = { "dsp", "arm" };
1374 static const char *eq_load_function[] = { "idle", "loading" };
1375 static const char *da_iis_mux_function[] =
1376 { "sprd-codec", "ext-codec-4", "ext-codec-6" };
1377 static const char *fm_sample_rate_function[] = { "32000", "48000" };
1379 static const struct soc_enum vbc_enum[] = {
1380 SOC_ENUM_SINGLE_EXT(2, switch_function),
1381 SOC_ENUM_SINGLE_EXT(2, eq_load_function),
1382 SOC_ENUM_SINGLE_EXT(3, da_iis_mux_function),
1383 SOC_ENUM_SINGLE_EXT(2, fm_sample_rate_function),
1386 static const struct snd_kcontrol_new vbc_codec_snd_controls[] = {
1387 SOC_ENUM_EXT("VBC Switch", vbc_enum[0], vbc_switch_get,
1389 SOC_SINGLE_EXT("VBC EQ Switch", FUN_REG(VBC_PLAYBACK), 0, 1, 0,
1392 SOC_ENUM_EXT("VBC EQ Update", vbc_enum[1], vbc_eq_load_get,
1395 SOC_SINGLE_EXT("VBC DACL DG Set", FUN_REG(VBC_LEFT),
1396 VBC_PLAYBACK, VBC_DG_VAL_MAX, 0, vbc_dg_get,
1398 SOC_SINGLE_EXT("VBC DACR DG Set", FUN_REG(VBC_RIGHT),
1399 VBC_PLAYBACK, VBC_DG_VAL_MAX, 0, vbc_dg_get,
1401 SOC_SINGLE_EXT("VBC ADCL DG Set", FUN_REG(VBC_LEFT),
1402 VBC_CAPTRUE, VBC_DG_VAL_MAX, 0, vbc_dg_get,
1404 SOC_SINGLE_EXT("VBC ADCR DG Set", FUN_REG(VBC_RIGHT),
1405 VBC_CAPTRUE, VBC_DG_VAL_MAX, 0, vbc_dg_get,
1407 SOC_SINGLE_EXT("VBC STL DG Set", FUN_REG(VBC_LEFT),
1408 0, VBC_DG_VAL_MAX, 0, vbc_st_dg_get, vbc_st_dg_put),
1409 SOC_SINGLE_EXT("VBC STR DG Set", FUN_REG(VBC_RIGHT),
1410 0, VBC_DG_VAL_MAX, 0, vbc_st_dg_get, vbc_st_dg_put),
1412 SOC_SINGLE_EXT("VBC DACL DG Switch", FUN_REG(VBC_LEFT),
1413 VBC_PLAYBACK, 1, 0, vbc_dg_switch_get,
1415 SOC_SINGLE_EXT("VBC DACR DG Switch", FUN_REG(VBC_RIGHT),
1416 VBC_PLAYBACK, 1, 0, vbc_dg_switch_get,
1418 SOC_SINGLE_EXT("VBC ADCL DG Switch", FUN_REG(VBC_LEFT),
1419 VBC_CAPTRUE, 1, 0, vbc_dg_switch_get,
1421 SOC_SINGLE_EXT("VBC ADCR DG Switch", FUN_REG(VBC_RIGHT),
1422 VBC_CAPTRUE, 1, 0, vbc_dg_switch_get,
1424 SOC_SINGLE_EXT("VBC STL HPF Switch", FUN_REG(VBC_LEFT),
1425 0, 1, 0, vbc_st_hpf_switch_get, vbc_st_hpf_switch_put),
1426 SOC_SINGLE_EXT("VBC STR HPF Switch", FUN_REG(VBC_RIGHT),
1427 0, 1, 0, vbc_st_hpf_switch_get, vbc_st_hpf_switch_put),
1428 SOC_SINGLE_EXT("VBC STL HPF Set", FUN_REG(VBC_LEFT),
1429 0, VBC_DG_VAL_MAX, 0, vbc_st_hpf_get, vbc_st_hpf_put),
1430 SOC_SINGLE_EXT("VBC STR HPF Set", FUN_REG(VBC_RIGHT),
1431 0, VBC_DG_VAL_MAX, 0, vbc_st_hpf_get, vbc_st_hpf_put),
1433 SOC_SINGLE_EXT("VBC AD0 DG Mux", FUN_REG(ADC0_DGMUX), 0, 1, 0,
1434 adc_dgmux_get, adc_dgmux_put),
1435 SOC_SINGLE_EXT("VBC AD1 DG Mux", FUN_REG(ADC1_DGMUX), 0, 1, 0,
1436 adc_dgmux_get, adc_dgmux_put),
1437 SOC_ENUM_EXT("VBC DA IIS Mux", vbc_enum[2], dac_iismux_get,
1439 SOC_SINGLE_EXT("VBC DA EQ Profile Select", FUN_REG(VBC_PLAYBACK), 0,
1440 VBC_EQ_PROFILE_CNT_MAX, 0,
1441 vbc_eq_profile_get, vbc_eq_profile_put),
1445 static unsigned int vbc_codec_read(struct snd_soc_codec *codec,
1448 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1449 /* Because snd_soc_update_bits reg is 16 bits short type,
1450 so muse do following convert
1452 if (IS_SPRD_VBC_RANG(reg | SPRD_VBC_BASE_HI)) {
1453 reg |= SPRD_VBC_BASE_HI;
1454 return vbc_reg_read(reg);
1455 } else if (IS_SPRD_VBC_MUX_RANG(FUN_REG(reg))) {
1456 int id = SPRD_VBC_MUX_IDX(FUN_REG(reg));
1457 struct sprd_vbc_mux_op *mux = &(vbc_codec->sprd_vbc_mux[id]);
1459 } else if (IS_SPRD_VBC_SWITCH_RANG(FUN_REG(reg))) {
1460 int id = SPRD_VBC_SWITCH_IDX(FUN_REG(reg));
1461 return vbc_codec->vbc_loop_switch[id];
1464 sp_asoc_pr_dbg("The Register is NOT VBC Codec's reg = 0x%x\n", reg);
1468 static int vbc_codec_write(struct snd_soc_codec *codec, unsigned int reg,
1471 if (IS_SPRD_VBC_RANG(reg | SPRD_VBC_BASE_HI)) {
1472 reg |= SPRD_VBC_BASE_HI;
1473 return vbc_reg_write(reg, val);
1475 sp_asoc_pr_dbg("The Register is NOT VBC Codec's reg = 0x%x\n", reg);
1479 static int vbc_codec_soc_probe(struct snd_soc_codec *codec)
1481 struct vbc_codec_priv *vbc_codec = snd_soc_codec_get_drvdata(codec);
1482 struct vbc_equ *p_eq_setting = &vbc_codec->vbc_eq_setting;
1485 sp_asoc_pr_dbg("%s\n", __func__);
1487 codec->dapm.idle_bias_off = 1;
1489 vbc_codec->codec = codec;
1490 p_eq_setting->codec = codec;
1492 vbc_proc_init(codec);
1497 /* power down chip */
1498 static int vbc_codec_soc_remove(struct snd_soc_codec *codec)
1503 static struct snd_soc_codec_driver soc_codec_dev_vbc_codec = {
1504 .probe = vbc_codec_soc_probe,
1505 .remove = vbc_codec_soc_remove,
1506 .read = vbc_codec_read,
1507 .write = vbc_codec_write,
1508 .reg_word_size = sizeof(u16),
1509 .reg_cache_step = 2,
1510 .dapm_widgets = vbc_codec_dapm_widgets,
1511 .num_dapm_widgets = ARRAY_SIZE(vbc_codec_dapm_widgets),
1512 .dapm_routes = vbc_codec_intercon,
1513 .num_dapm_routes = ARRAY_SIZE(vbc_codec_intercon),
1514 .controls = vbc_codec_snd_controls,
1515 .num_controls = ARRAY_SIZE(vbc_codec_snd_controls),
1518 static int sprd_vbc_codec_probe(struct platform_device *pdev)
1520 struct vbc_codec_priv *vbc_codec;
1523 sp_asoc_pr_dbg("%s\n", __func__);
1525 vbc_codec = devm_kzalloc(&pdev->dev, sizeof(struct vbc_codec_priv),
1527 if (vbc_codec == NULL)
1530 platform_set_drvdata(pdev, vbc_codec);
1532 ret = snd_soc_register_codec(&pdev->dev,
1533 &soc_codec_dev_vbc_codec, NULL, 0);
1535 pr_err("ERR:Failed to register VBC-CODEC: %d\n", ret);
1538 /* AP refer to array vbc_switch_reg_val */
1539 vbc_codec->vbc_control = 2;
1540 vbc_codec->vbc_eq_setting.dev = &pdev->dev;
1541 vbc_codec->st_dg.dg_val[0] = 0x18;
1542 vbc_codec->st_dg.dg_val[1] = 0x18;
1543 vbc_codec->st_dg.hpf_val[0] = 0x3;
1544 vbc_codec->st_dg.hpf_val[1] = 0x3;
1545 vbc_codec->dg[0].dg_val[0] = 0x18;
1546 vbc_codec->dg[0].dg_val[1] = 0x18;
1547 vbc_codec->dg[1].dg_val[0] = 0x18;
1548 vbc_codec->dg[1].dg_val[1] = 0x18;
1549 vbc_codec->dg[0].dg_set[0] = vbc_da0_dg_set;
1550 vbc_codec->dg[0].dg_set[1] = vbc_da1_dg_set;
1551 vbc_codec->dg[1].dg_set[0] = vbc_ad0_dg_set;
1552 vbc_codec->dg[1].dg_set[1] = vbc_ad1_dg_set;
1553 mutex_init(&vbc_codec->load_mutex);
1558 static int sprd_vbc_codec_remove(struct platform_device *pdev)
1560 struct vbc_codec_priv *vbc_codec = platform_get_drvdata(pdev);
1561 vbc_codec->vbc_eq_setting.dev = 0;
1563 snd_soc_unregister_codec(&pdev->dev);
1567 MODULE_DESCRIPTION("SPRD ASoC VBC Codec Driver");
1568 MODULE_AUTHOR("Zhenfang Wang <zhenfang.wang@spreadtrum.com>");
1569 MODULE_AUTHOR("Ken.Kuang <ken.kuang@spreadtrum.com>");
1570 MODULE_LICENSE("GPL");
1571 MODULE_ALIAS("codec:VBC Codec");