aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8994.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-03-09 14:31:01 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-03-18 06:52:40 -0400
commitf701a2e594e62b35d895ad5ec1db8d2d0714c158 (patch)
tree1f3b5c23a3258cdd56bd3db65618ccaa8b7479b1 /sound/soc/codecs/wm8994.c
parent780e2806986f9cc980808687da95160c65baa78a (diff)
ASoC: Factor WM8958 DSP2 handling into separate file
DSP2 on the WM8958 has a default ROM which provides a multi-band compressor for enhanced performance on mobile devices but can also support runtime download of alternative firmware. In preparation for more exploiting this functionality refactor the code to split the handling of DSP2 into a separate file. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r--sound/soc/codecs/wm8994.c305
1 files changed, 3 insertions, 302 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 9458289bb563..96e1379f4fad 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
41struct 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,61 +53,6 @@ static int wm8994_retune_mobile_base[] = {
59 WM8994_AIF2_EQ_GAINS_1, 53 WM8994_AIF2_EQ_GAINS_1,
60}; 54};
61 55
62struct wm8994_micdet {
63 struct snd_soc_jack *jack;
64 int det;
65 int shrt;
66};
67
68/* codec private data */
69struct 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 dependant DRC configuration */
86 const char **drc_texts;
87 int drc_cfg[WM8994_NUM_DRC];
88 struct soc_enum drc_enum;
89
90 /* Platform dependant 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 dependant 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
117static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) 56static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
118{ 57{
119 switch (reg) { 58 switch (reg) {
@@ -574,215 +513,6 @@ static const struct soc_enum dac_osr =
574static const struct soc_enum adc_osr = 513static const struct soc_enum adc_osr =
575 SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text); 514 SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
576 515
577static 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
663static 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
699static 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
721static 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
732static 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
742static 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
754static 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
786static const struct snd_kcontrol_new wm8994_snd_controls[] = { 516static const struct snd_kcontrol_new wm8994_snd_controls[] = {
787SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, 517SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
788 WM8994_AIF1_ADC1_RIGHT_VOLUME, 518 WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -924,9 +654,6 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
924 654
925static const struct snd_kcontrol_new wm8958_snd_controls[] = { 655static const struct snd_kcontrol_new wm8958_snd_controls[] = {
926SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), 656SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
927WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
928WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
929WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
930}; 657};
931 658
932static int clk_sys_event(struct snd_soc_dapm_widget *w, 659static int clk_sys_event(struct snd_soc_dapm_widget *w,
@@ -2676,7 +2403,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
2676 2403
2677 for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { 2404 for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
2678 memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], 2405 memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
2679 sizeof(struct fll_config)); 2406 sizeof(struct wm8994_fll_config));
2680 ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0); 2407 ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
2681 if (ret < 0) 2408 if (ret < 0)
2682 dev_warn(codec->dev, "Failed to stop FLL%d: %d\n", 2409 dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
@@ -2862,34 +2589,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
2862 dev_dbg(codec->dev, "%d ReTune Mobile configurations\n", 2589 dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
2863 pdata->num_retune_mobile_cfgs); 2590 pdata->num_retune_mobile_cfgs);
2864 2591
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) 2592 if (pdata->num_retune_mobile_cfgs)
2894 wm8994_handle_retune_mobile_pdata(wm8994); 2593 wm8994_handle_retune_mobile_pdata(wm8994);
2895 else 2594 else
@@ -3378,6 +3077,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
3378 snd_soc_dapm_add_routes(dapm, wm8958_intercon, 3077 snd_soc_dapm_add_routes(dapm, wm8958_intercon,
3379 ARRAY_SIZE(wm8958_intercon)); 3078 ARRAY_SIZE(wm8958_intercon));
3380 } 3079 }
3080
3081 wm8958_dsp2_init(codec);
3381 break; 3082 break;
3382 } 3083 }
3383 3084