diff options
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r-- | sound/soc/codecs/wm8994.c | 395 |
1 files changed, 81 insertions, 314 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 84e1bd1d2822..970a95c5360b 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -38,12 +38,6 @@ | |||
38 | #include "wm8994.h" | 38 | #include "wm8994.h" |
39 | #include "wm_hubs.h" | 39 | #include "wm_hubs.h" |
40 | 40 | ||
41 | struct fll_config { | ||
42 | int src; | ||
43 | int in; | ||
44 | int out; | ||
45 | }; | ||
46 | |||
47 | #define WM8994_NUM_DRC 3 | 41 | #define WM8994_NUM_DRC 3 |
48 | #define WM8994_NUM_EQ 3 | 42 | #define WM8994_NUM_EQ 3 |
49 | 43 | ||
@@ -59,63 +53,11 @@ static int wm8994_retune_mobile_base[] = { | |||
59 | WM8994_AIF2_EQ_GAINS_1, | 53 | WM8994_AIF2_EQ_GAINS_1, |
60 | }; | 54 | }; |
61 | 55 | ||
62 | struct wm8994_micdet { | ||
63 | struct snd_soc_jack *jack; | ||
64 | int det; | ||
65 | int shrt; | ||
66 | }; | ||
67 | |||
68 | /* codec private data */ | ||
69 | struct wm8994_priv { | ||
70 | struct wm_hubs_data hubs; | ||
71 | enum snd_soc_control_type control_type; | ||
72 | void *control_data; | ||
73 | struct snd_soc_codec *codec; | ||
74 | int sysclk[2]; | ||
75 | int sysclk_rate[2]; | ||
76 | int mclk[2]; | ||
77 | int aifclk[2]; | ||
78 | struct fll_config fll[2], fll_suspend[2]; | ||
79 | |||
80 | int dac_rates[2]; | ||
81 | int lrclk_shared[2]; | ||
82 | |||
83 | int mbc_ena[3]; | ||
84 | |||
85 | /* Platform dependent DRC configuration */ | ||
86 | const char **drc_texts; | ||
87 | int drc_cfg[WM8994_NUM_DRC]; | ||
88 | struct soc_enum drc_enum; | ||
89 | |||
90 | /* Platform dependent ReTune mobile configuration */ | ||
91 | int num_retune_mobile_texts; | ||
92 | const char **retune_mobile_texts; | ||
93 | int retune_mobile_cfg[WM8994_NUM_EQ]; | ||
94 | struct soc_enum retune_mobile_enum; | ||
95 | |||
96 | /* Platform dependent MBC configuration */ | ||
97 | int mbc_cfg; | ||
98 | const char **mbc_texts; | ||
99 | struct soc_enum mbc_enum; | ||
100 | |||
101 | struct wm8994_micdet micdet[2]; | ||
102 | |||
103 | wm8958_micdet_cb jack_cb; | ||
104 | void *jack_cb_data; | ||
105 | int micdet_irq; | ||
106 | |||
107 | int revision; | ||
108 | struct wm8994_pdata *pdata; | ||
109 | |||
110 | unsigned int aif1clk_enable:1; | ||
111 | unsigned int aif2clk_enable:1; | ||
112 | |||
113 | unsigned int aif1clk_disable:1; | ||
114 | unsigned int aif2clk_disable:1; | ||
115 | }; | ||
116 | |||
117 | static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) | 56 | static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) |
118 | { | 57 | { |
58 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
59 | struct wm8994 *control = wm8994->control_data; | ||
60 | |||
119 | switch (reg) { | 61 | switch (reg) { |
120 | case WM8994_GPIO_1: | 62 | case WM8994_GPIO_1: |
121 | case WM8994_GPIO_2: | 63 | case WM8994_GPIO_2: |
@@ -132,6 +74,15 @@ static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) | |||
132 | case WM8994_INTERRUPT_STATUS_2: | 74 | case WM8994_INTERRUPT_STATUS_2: |
133 | case WM8994_INTERRUPT_RAW_STATUS_2: | 75 | case WM8994_INTERRUPT_RAW_STATUS_2: |
134 | return 1; | 76 | return 1; |
77 | |||
78 | case WM8958_DSP2_PROGRAM: | ||
79 | case WM8958_DSP2_CONFIG: | ||
80 | case WM8958_DSP2_EXECCONTROL: | ||
81 | if (control->type == WM8958) | ||
82 | return 1; | ||
83 | else | ||
84 | return 0; | ||
85 | |||
135 | default: | 86 | default: |
136 | break; | 87 | break; |
137 | } | 88 | } |
@@ -574,215 +525,6 @@ static const struct soc_enum dac_osr = | |||
574 | static const struct soc_enum adc_osr = | 525 | static const struct soc_enum adc_osr = |
575 | SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text); | 526 | SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text); |
576 | 527 | ||
577 | static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start) | ||
578 | { | ||
579 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
580 | struct wm8994_pdata *pdata = wm8994->pdata; | ||
581 | int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5); | ||
582 | int ena, reg, aif, i; | ||
583 | |||
584 | switch (mbc) { | ||
585 | case 0: | ||
586 | pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA); | ||
587 | aif = 0; | ||
588 | break; | ||
589 | case 1: | ||
590 | pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA); | ||
591 | aif = 0; | ||
592 | break; | ||
593 | case 2: | ||
594 | pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA); | ||
595 | aif = 1; | ||
596 | break; | ||
597 | default: | ||
598 | BUG(); | ||
599 | return; | ||
600 | } | ||
601 | |||
602 | /* We can only enable the MBC if the AIF is enabled and we | ||
603 | * want it to be enabled. */ | ||
604 | ena = pwr_reg && wm8994->mbc_ena[mbc]; | ||
605 | |||
606 | reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM); | ||
607 | |||
608 | dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n", | ||
609 | mbc, start, pwr_reg, reg); | ||
610 | |||
611 | if (start && ena) { | ||
612 | /* If the DSP is already running then noop */ | ||
613 | if (reg & WM8958_DSP2_ENA) | ||
614 | return; | ||
615 | |||
616 | /* Switch the clock over to the appropriate AIF */ | ||
617 | snd_soc_update_bits(codec, WM8994_CLOCKING_1, | ||
618 | WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA, | ||
619 | aif << WM8958_DSP2CLK_SRC_SHIFT | | ||
620 | WM8958_DSP2CLK_ENA); | ||
621 | |||
622 | snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, | ||
623 | WM8958_DSP2_ENA, WM8958_DSP2_ENA); | ||
624 | |||
625 | /* If we've got user supplied MBC settings use them */ | ||
626 | if (pdata && pdata->num_mbc_cfgs) { | ||
627 | struct wm8958_mbc_cfg *cfg | ||
628 | = &pdata->mbc_cfgs[wm8994->mbc_cfg]; | ||
629 | |||
630 | for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++) | ||
631 | snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1, | ||
632 | cfg->coeff_regs[i]); | ||
633 | |||
634 | for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++) | ||
635 | snd_soc_write(codec, | ||
636 | i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1, | ||
637 | cfg->cutoff_regs[i]); | ||
638 | } | ||
639 | |||
640 | /* Run the DSP */ | ||
641 | snd_soc_write(codec, WM8958_DSP2_EXECCONTROL, | ||
642 | WM8958_DSP2_RUNR); | ||
643 | |||
644 | /* And we're off! */ | ||
645 | snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, | ||
646 | WM8958_MBC_ENA | WM8958_MBC_SEL_MASK, | ||
647 | mbc << WM8958_MBC_SEL_SHIFT | | ||
648 | WM8958_MBC_ENA); | ||
649 | } else { | ||
650 | /* If the DSP is already stopped then noop */ | ||
651 | if (!(reg & WM8958_DSP2_ENA)) | ||
652 | return; | ||
653 | |||
654 | snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, | ||
655 | WM8958_MBC_ENA, 0); | ||
656 | snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, | ||
657 | WM8958_DSP2_ENA, 0); | ||
658 | snd_soc_update_bits(codec, WM8994_CLOCKING_1, | ||
659 | WM8958_DSP2CLK_ENA, 0); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | static int wm8958_aif_ev(struct snd_soc_dapm_widget *w, | ||
664 | struct snd_kcontrol *kcontrol, int event) | ||
665 | { | ||
666 | struct snd_soc_codec *codec = w->codec; | ||
667 | int mbc; | ||
668 | |||
669 | switch (w->shift) { | ||
670 | case 13: | ||
671 | case 12: | ||
672 | mbc = 2; | ||
673 | break; | ||
674 | case 11: | ||
675 | case 10: | ||
676 | mbc = 1; | ||
677 | break; | ||
678 | case 9: | ||
679 | case 8: | ||
680 | mbc = 0; | ||
681 | break; | ||
682 | default: | ||
683 | BUG(); | ||
684 | return -EINVAL; | ||
685 | } | ||
686 | |||
687 | switch (event) { | ||
688 | case SND_SOC_DAPM_POST_PMU: | ||
689 | wm8958_mbc_apply(codec, mbc, 1); | ||
690 | break; | ||
691 | case SND_SOC_DAPM_POST_PMD: | ||
692 | wm8958_mbc_apply(codec, mbc, 0); | ||
693 | break; | ||
694 | } | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, | ||
700 | struct snd_ctl_elem_value *ucontrol) | ||
701 | { | ||
702 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
703 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
704 | struct wm8994_pdata *pdata = wm8994->pdata; | ||
705 | int value = ucontrol->value.integer.value[0]; | ||
706 | int reg; | ||
707 | |||
708 | /* Don't allow on the fly reconfiguration */ | ||
709 | reg = snd_soc_read(codec, WM8994_CLOCKING_1); | ||
710 | if (reg < 0 || reg & WM8958_DSP2CLK_ENA) | ||
711 | return -EBUSY; | ||
712 | |||
713 | if (value >= pdata->num_mbc_cfgs) | ||
714 | return -EINVAL; | ||
715 | |||
716 | wm8994->mbc_cfg = value; | ||
717 | |||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol, | ||
722 | struct snd_ctl_elem_value *ucontrol) | ||
723 | { | ||
724 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
725 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
726 | |||
727 | ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg; | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int wm8958_mbc_info(struct snd_kcontrol *kcontrol, | ||
733 | struct snd_ctl_elem_info *uinfo) | ||
734 | { | ||
735 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
736 | uinfo->count = 1; | ||
737 | uinfo->value.integer.min = 0; | ||
738 | uinfo->value.integer.max = 1; | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static int wm8958_mbc_get(struct snd_kcontrol *kcontrol, | ||
743 | struct snd_ctl_elem_value *ucontrol) | ||
744 | { | ||
745 | int mbc = kcontrol->private_value; | ||
746 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
747 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
748 | |||
749 | ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc]; | ||
750 | |||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, | ||
755 | struct snd_ctl_elem_value *ucontrol) | ||
756 | { | ||
757 | int mbc = kcontrol->private_value; | ||
758 | int i; | ||
759 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
760 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
761 | |||
762 | if (ucontrol->value.integer.value[0] > 1) | ||
763 | return -EINVAL; | ||
764 | |||
765 | for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) { | ||
766 | if (mbc != i && wm8994->mbc_ena[i]) { | ||
767 | dev_dbg(codec->dev, "MBC %d active already\n", mbc); | ||
768 | return -EBUSY; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0]; | ||
773 | |||
774 | wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]); | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | #define WM8958_MBC_SWITCH(xname, xval) {\ | ||
780 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
781 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
782 | .info = wm8958_mbc_info, \ | ||
783 | .get = wm8958_mbc_get, .put = wm8958_mbc_put, \ | ||
784 | .private_value = xval } | ||
785 | |||
786 | static const struct snd_kcontrol_new wm8994_snd_controls[] = { | 528 | static const struct snd_kcontrol_new wm8994_snd_controls[] = { |
787 | SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, | 529 | SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, |
788 | WM8994_AIF1_ADC1_RIGHT_VOLUME, | 530 | WM8994_AIF1_ADC1_RIGHT_VOLUME, |
@@ -924,9 +666,6 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0, | |||
924 | 666 | ||
925 | static const struct snd_kcontrol_new wm8958_snd_controls[] = { | 667 | static const struct snd_kcontrol_new wm8958_snd_controls[] = { |
926 | SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), | 668 | SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), |
927 | WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0), | ||
928 | WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1), | ||
929 | WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2), | ||
930 | }; | 669 | }; |
931 | 670 | ||
932 | static int clk_sys_event(struct snd_soc_dapm_widget *w, | 671 | static int clk_sys_event(struct snd_soc_dapm_widget *w, |
@@ -1032,6 +771,9 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w, | |||
1032 | break; | 771 | break; |
1033 | } | 772 | } |
1034 | 773 | ||
774 | /* We may also have postponed startup of DSP, handle that. */ | ||
775 | wm8958_aif_ev(w, kcontrol, event); | ||
776 | |||
1035 | return 0; | 777 | return 0; |
1036 | } | 778 | } |
1037 | 779 | ||
@@ -1135,7 +877,8 @@ static const char *hp_mux_text[] = { | |||
1135 | static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol, | 877 | static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol, |
1136 | struct snd_ctl_elem_value *ucontrol) | 878 | struct snd_ctl_elem_value *ucontrol) |
1137 | { | 879 | { |
1138 | struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); | 880 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
881 | struct snd_soc_dapm_widget *w = wlist->widgets[0]; | ||
1139 | struct snd_soc_codec *codec = w->codec; | 882 | struct snd_soc_codec *codec = w->codec; |
1140 | int ret; | 883 | int ret; |
1141 | 884 | ||
@@ -1262,7 +1005,8 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | |||
1262 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, | 1005 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, |
1263 | struct snd_ctl_elem_value *ucontrol) | 1006 | struct snd_ctl_elem_value *ucontrol) |
1264 | { | 1007 | { |
1265 | struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); | 1008 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
1009 | struct snd_soc_dapm_widget *w = wlist->widgets[0]; | ||
1266 | struct snd_soc_codec *codec = w->codec; | 1010 | struct snd_soc_codec *codec = w->codec; |
1267 | int ret; | 1011 | int ret; |
1268 | 1012 | ||
@@ -2180,6 +1924,8 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2180 | WM8994_VMID_BUF_ENA | | 1924 | WM8994_VMID_BUF_ENA | |
2181 | WM8994_VMID_RAMP_MASK, 0); | 1925 | WM8994_VMID_RAMP_MASK, 0); |
2182 | 1926 | ||
1927 | wm8994->cur_fw = NULL; | ||
1928 | |||
2183 | pm_runtime_put(codec->dev); | 1929 | pm_runtime_put(codec->dev); |
2184 | } | 1930 | } |
2185 | break; | 1931 | break; |
@@ -2672,11 +2418,22 @@ static struct snd_soc_dai_driver wm8994_dai[] = { | |||
2672 | static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state) | 2418 | static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state) |
2673 | { | 2419 | { |
2674 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 2420 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
2421 | struct wm8994 *control = codec->control_data; | ||
2675 | int i, ret; | 2422 | int i, ret; |
2676 | 2423 | ||
2424 | switch (control->type) { | ||
2425 | case WM8994: | ||
2426 | snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0); | ||
2427 | break; | ||
2428 | case WM8958: | ||
2429 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | ||
2430 | WM8958_MICD_ENA, 0); | ||
2431 | break; | ||
2432 | } | ||
2433 | |||
2677 | for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { | 2434 | for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { |
2678 | memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], | 2435 | memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], |
2679 | sizeof(struct fll_config)); | 2436 | sizeof(struct wm8994_fll_config)); |
2680 | ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0); | 2437 | ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0); |
2681 | if (ret < 0) | 2438 | if (ret < 0) |
2682 | dev_warn(codec->dev, "Failed to stop FLL%d: %d\n", | 2439 | dev_warn(codec->dev, "Failed to stop FLL%d: %d\n", |
@@ -2691,6 +2448,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state) | |||
2691 | static int wm8994_resume(struct snd_soc_codec *codec) | 2448 | static int wm8994_resume(struct snd_soc_codec *codec) |
2692 | { | 2449 | { |
2693 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 2450 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
2451 | struct wm8994 *control = codec->control_data; | ||
2694 | int i, ret; | 2452 | int i, ret; |
2695 | unsigned int val, mask; | 2453 | unsigned int val, mask; |
2696 | 2454 | ||
@@ -2729,6 +2487,19 @@ static int wm8994_resume(struct snd_soc_codec *codec) | |||
2729 | i + 1, ret); | 2487 | i + 1, ret); |
2730 | } | 2488 | } |
2731 | 2489 | ||
2490 | switch (control->type) { | ||
2491 | case WM8994: | ||
2492 | if (wm8994->micdet[0].jack || wm8994->micdet[1].jack) | ||
2493 | snd_soc_update_bits(codec, WM8994_MICBIAS, | ||
2494 | WM8994_MICD_ENA, WM8994_MICD_ENA); | ||
2495 | break; | ||
2496 | case WM8958: | ||
2497 | if (wm8994->jack_cb) | ||
2498 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | ||
2499 | WM8958_MICD_ENA, WM8958_MICD_ENA); | ||
2500 | break; | ||
2501 | } | ||
2502 | |||
2732 | return 0; | 2503 | return 0; |
2733 | } | 2504 | } |
2734 | #else | 2505 | #else |
@@ -2862,34 +2633,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) | |||
2862 | dev_dbg(codec->dev, "%d ReTune Mobile configurations\n", | 2633 | dev_dbg(codec->dev, "%d ReTune Mobile configurations\n", |
2863 | pdata->num_retune_mobile_cfgs); | 2634 | pdata->num_retune_mobile_cfgs); |
2864 | 2635 | ||
2865 | if (pdata->num_mbc_cfgs) { | ||
2866 | struct snd_kcontrol_new control[] = { | ||
2867 | SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum, | ||
2868 | wm8958_get_mbc_enum, wm8958_put_mbc_enum), | ||
2869 | }; | ||
2870 | |||
2871 | /* We need an array of texts for the enum API */ | ||
2872 | wm8994->mbc_texts = kmalloc(sizeof(char *) | ||
2873 | * pdata->num_mbc_cfgs, GFP_KERNEL); | ||
2874 | if (!wm8994->mbc_texts) { | ||
2875 | dev_err(wm8994->codec->dev, | ||
2876 | "Failed to allocate %d MBC config texts\n", | ||
2877 | pdata->num_mbc_cfgs); | ||
2878 | return; | ||
2879 | } | ||
2880 | |||
2881 | for (i = 0; i < pdata->num_mbc_cfgs; i++) | ||
2882 | wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; | ||
2883 | |||
2884 | wm8994->mbc_enum.max = pdata->num_mbc_cfgs; | ||
2885 | wm8994->mbc_enum.texts = wm8994->mbc_texts; | ||
2886 | |||
2887 | ret = snd_soc_add_controls(wm8994->codec, control, 1); | ||
2888 | if (ret != 0) | ||
2889 | dev_err(wm8994->codec->dev, | ||
2890 | "Failed to add MBC mode controls: %d\n", ret); | ||
2891 | } | ||
2892 | |||
2893 | if (pdata->num_retune_mobile_cfgs) | 2636 | if (pdata->num_retune_mobile_cfgs) |
2894 | wm8994_handle_retune_mobile_pdata(wm8994); | 2637 | wm8994_handle_retune_mobile_pdata(wm8994); |
2895 | else | 2638 | else |
@@ -3343,14 +3086,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3343 | case WM8958: | 3086 | case WM8958: |
3344 | snd_soc_add_controls(codec, wm8958_snd_controls, | 3087 | snd_soc_add_controls(codec, wm8958_snd_controls, |
3345 | ARRAY_SIZE(wm8958_snd_controls)); | 3088 | ARRAY_SIZE(wm8958_snd_controls)); |
3346 | snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets, | ||
3347 | ARRAY_SIZE(wm8994_lateclk_widgets)); | ||
3348 | snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets, | ||
3349 | ARRAY_SIZE(wm8994_adc_widgets)); | ||
3350 | snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets, | ||
3351 | ARRAY_SIZE(wm8994_dac_widgets)); | ||
3352 | snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets, | 3089 | snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets, |
3353 | ARRAY_SIZE(wm8958_dapm_widgets)); | 3090 | ARRAY_SIZE(wm8958_dapm_widgets)); |
3091 | if (wm8994->revision < 1) { | ||
3092 | snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, | ||
3093 | ARRAY_SIZE(wm8994_lateclk_revd_widgets)); | ||
3094 | snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets, | ||
3095 | ARRAY_SIZE(wm8994_adc_revd_widgets)); | ||
3096 | snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets, | ||
3097 | ARRAY_SIZE(wm8994_dac_revd_widgets)); | ||
3098 | } else { | ||
3099 | snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets, | ||
3100 | ARRAY_SIZE(wm8994_lateclk_widgets)); | ||
3101 | snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets, | ||
3102 | ARRAY_SIZE(wm8994_adc_widgets)); | ||
3103 | snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets, | ||
3104 | ARRAY_SIZE(wm8994_dac_widgets)); | ||
3105 | } | ||
3354 | break; | 3106 | break; |
3355 | } | 3107 | } |
3356 | 3108 | ||
@@ -3374,10 +3126,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3374 | } | 3126 | } |
3375 | break; | 3127 | break; |
3376 | case WM8958: | 3128 | case WM8958: |
3377 | snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon, | 3129 | if (wm8994->revision < 1) { |
3378 | ARRAY_SIZE(wm8994_lateclk_intercon)); | 3130 | snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon, |
3379 | snd_soc_dapm_add_routes(dapm, wm8958_intercon, | 3131 | ARRAY_SIZE(wm8994_revd_intercon)); |
3380 | ARRAY_SIZE(wm8958_intercon)); | 3132 | snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon, |
3133 | ARRAY_SIZE(wm8994_lateclk_revd_intercon)); | ||
3134 | } else { | ||
3135 | snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon, | ||
3136 | ARRAY_SIZE(wm8994_lateclk_intercon)); | ||
3137 | snd_soc_dapm_add_routes(dapm, wm8958_intercon, | ||
3138 | ARRAY_SIZE(wm8958_intercon)); | ||
3139 | } | ||
3140 | |||
3141 | wm8958_dsp2_init(codec); | ||
3381 | break; | 3142 | break; |
3382 | } | 3143 | } |
3383 | 3144 | ||
@@ -3420,6 +3181,12 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
3420 | free_irq(wm8994->micdet_irq, wm8994); | 3181 | free_irq(wm8994->micdet_irq, wm8994); |
3421 | break; | 3182 | break; |
3422 | } | 3183 | } |
3184 | if (wm8994->mbc) | ||
3185 | release_firmware(wm8994->mbc); | ||
3186 | if (wm8994->mbc_vss) | ||
3187 | release_firmware(wm8994->mbc_vss); | ||
3188 | if (wm8994->enh_eq) | ||
3189 | release_firmware(wm8994->enh_eq); | ||
3423 | kfree(wm8994->retune_mobile_texts); | 3190 | kfree(wm8994->retune_mobile_texts); |
3424 | kfree(wm8994->drc_texts); | 3191 | kfree(wm8994->drc_texts); |
3425 | kfree(wm8994); | 3192 | kfree(wm8994); |