aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c289
-rw-r--r--sound/soc/codecs/wm8994.c305
-rw-r--r--sound/soc/codecs/wm8994.h71
4 files changed, 364 insertions, 303 deletions
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 379bc55f0723..49121ad0e172 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -69,7 +69,7 @@ snd-soc-wm8988-objs := wm8988.o
69snd-soc-wm8990-objs := wm8990.o 69snd-soc-wm8990-objs := wm8990.o
70snd-soc-wm8991-objs := wm8991.o 70snd-soc-wm8991-objs := wm8991.o
71snd-soc-wm8993-objs := wm8993.o 71snd-soc-wm8993-objs := wm8993.o
72snd-soc-wm8994-objs := wm8994.o wm8994-tables.o 72snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o
73snd-soc-wm8995-objs := wm8995.o 73snd-soc-wm8995-objs := wm8995.o
74snd-soc-wm9081-objs := wm9081.o 74snd-soc-wm9081-objs := wm9081.o
75snd-soc-wm9705-objs := wm9705.o 75snd-soc-wm9705-objs := wm9705.o
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
new file mode 100644
index 000000000000..4b4c93c20331
--- /dev/null
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -0,0 +1,289 @@
1/*
2 * wm8958-dsp2.c -- WM8958 DSP2 support
3 *
4 * Copyright 2011 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/init.h>
16#include <linux/delay.h>
17#include <linux/pm.h>
18#include <linux/i2c.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <sound/soc.h>
22#include <sound/initval.h>
23#include <sound/tlv.h>
24#include <trace/events/asoc.h>
25
26#include <linux/mfd/wm8994/core.h>
27#include <linux/mfd/wm8994/registers.h>
28#include <linux/mfd/wm8994/pdata.h>
29#include <linux/mfd/wm8994/gpio.h>
30
31#include "wm8994.h"
32
33static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start)
34{
35 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
36 struct wm8994_pdata *pdata = wm8994->pdata;
37 int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
38 int ena, reg, aif, i;
39
40 switch (mbc) {
41 case 0:
42 pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
43 aif = 0;
44 break;
45 case 1:
46 pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
47 aif = 0;
48 break;
49 case 2:
50 pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
51 aif = 1;
52 break;
53 default:
54 BUG();
55 return;
56 }
57
58 /* We can only enable the MBC if the AIF is enabled and we
59 * want it to be enabled. */
60 ena = pwr_reg && wm8994->mbc_ena[mbc];
61
62 reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
63
64 dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n",
65 mbc, start, pwr_reg, reg);
66
67 if (start && ena) {
68 /* If the DSP is already running then noop */
69 if (reg & WM8958_DSP2_ENA)
70 return;
71
72 /* Switch the clock over to the appropriate AIF */
73 snd_soc_update_bits(codec, WM8994_CLOCKING_1,
74 WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
75 aif << WM8958_DSP2CLK_SRC_SHIFT |
76 WM8958_DSP2CLK_ENA);
77
78 snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
79 WM8958_DSP2_ENA, WM8958_DSP2_ENA);
80
81 /* If we've got user supplied MBC settings use them */
82 if (pdata && pdata->num_mbc_cfgs) {
83 struct wm8958_mbc_cfg *cfg
84 = &pdata->mbc_cfgs[wm8994->mbc_cfg];
85
86 for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
87 snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
88 cfg->coeff_regs[i]);
89
90 for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
91 snd_soc_write(codec,
92 i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
93 cfg->cutoff_regs[i]);
94 }
95
96 /* Run the DSP */
97 snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
98 WM8958_DSP2_RUNR);
99
100 /* And we're off! */
101 snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
102 WM8958_MBC_ENA | WM8958_MBC_SEL_MASK,
103 mbc << WM8958_MBC_SEL_SHIFT |
104 WM8958_MBC_ENA);
105 } else {
106 /* If the DSP is already stopped then noop */
107 if (!(reg & WM8958_DSP2_ENA))
108 return;
109
110 snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
111 WM8958_MBC_ENA, 0);
112 snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
113 WM8958_DSP2_ENA, 0);
114 snd_soc_update_bits(codec, WM8994_CLOCKING_1,
115 WM8958_DSP2CLK_ENA, 0);
116 }
117}
118
119int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
120 struct snd_kcontrol *kcontrol, int event)
121{
122 struct snd_soc_codec *codec = w->codec;
123 int mbc;
124
125 switch (w->shift) {
126 case 13:
127 case 12:
128 mbc = 2;
129 break;
130 case 11:
131 case 10:
132 mbc = 1;
133 break;
134 case 9:
135 case 8:
136 mbc = 0;
137 break;
138 default:
139 BUG();
140 return -EINVAL;
141 }
142
143 switch (event) {
144 case SND_SOC_DAPM_POST_PMU:
145 wm8958_mbc_apply(codec, mbc, 1);
146 break;
147 case SND_SOC_DAPM_POST_PMD:
148 wm8958_mbc_apply(codec, mbc, 0);
149 break;
150 }
151
152 return 0;
153}
154
155static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
156 struct snd_ctl_elem_value *ucontrol)
157{
158 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
159 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
160 struct wm8994_pdata *pdata = wm8994->pdata;
161 int value = ucontrol->value.integer.value[0];
162 int reg;
163
164 /* Don't allow on the fly reconfiguration */
165 reg = snd_soc_read(codec, WM8994_CLOCKING_1);
166 if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
167 return -EBUSY;
168
169 if (value >= pdata->num_mbc_cfgs)
170 return -EINVAL;
171
172 wm8994->mbc_cfg = value;
173
174 return 0;
175}
176
177static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
178 struct snd_ctl_elem_value *ucontrol)
179{
180 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
181 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
182
183 ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
184
185 return 0;
186}
187
188static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
189 struct snd_ctl_elem_info *uinfo)
190{
191 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
192 uinfo->count = 1;
193 uinfo->value.integer.min = 0;
194 uinfo->value.integer.max = 1;
195 return 0;
196}
197
198static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
199 struct snd_ctl_elem_value *ucontrol)
200{
201 int mbc = kcontrol->private_value;
202 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
203 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
204
205 ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
206
207 return 0;
208}
209
210static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
211 struct snd_ctl_elem_value *ucontrol)
212{
213 int mbc = kcontrol->private_value;
214 int i;
215 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
216 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
217
218 if (ucontrol->value.integer.value[0] > 1)
219 return -EINVAL;
220
221 for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
222 if (mbc != i && wm8994->mbc_ena[i]) {
223 dev_dbg(codec->dev, "MBC %d active already\n", mbc);
224 return -EBUSY;
225 }
226 }
227
228 wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
229
230 wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]);
231
232 return 0;
233}
234
235#define WM8958_MBC_SWITCH(xname, xval) {\
236 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
237 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
238 .info = wm8958_mbc_info, \
239 .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
240 .private_value = xval }
241
242static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
243WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
244WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
245WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
246};
247
248void wm8958_dsp2_init(struct snd_soc_codec *codec)
249{
250 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
251 struct wm8994_pdata *pdata = wm8994->pdata;
252 int ret, i;
253
254 snd_soc_add_controls(codec, wm8958_mbc_snd_controls,
255 ARRAY_SIZE(wm8958_mbc_snd_controls));
256
257 if (!pdata)
258 return;
259
260 if (pdata->num_mbc_cfgs) {
261 struct snd_kcontrol_new control[] = {
262 SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
263 wm8958_get_mbc_enum, wm8958_put_mbc_enum),
264 };
265
266 /* We need an array of texts for the enum API */
267 wm8994->mbc_texts = kmalloc(sizeof(char *)
268 * pdata->num_mbc_cfgs, GFP_KERNEL);
269 if (!wm8994->mbc_texts) {
270 dev_err(wm8994->codec->dev,
271 "Failed to allocate %d MBC config texts\n",
272 pdata->num_mbc_cfgs);
273 return;
274 }
275
276 for (i = 0; i < pdata->num_mbc_cfgs; i++)
277 wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
278
279 wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
280 wm8994->mbc_enum.texts = wm8994->mbc_texts;
281
282 ret = snd_soc_add_controls(wm8994->codec, control, 1);
283 if (ret != 0)
284 dev_err(wm8994->codec->dev,
285 "Failed to add MBC mode controls: %d\n", ret);
286 }
287
288
289}
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
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 999b8851226b..93a6cf1e1308 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -11,6 +11,8 @@
11 11
12#include <sound/soc.h> 12#include <sound/soc.h>
13 13
14#include "wm_hubs.h"
15
14/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ 16/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
15#define WM8994_SYSCLK_MCLK1 1 17#define WM8994_SYSCLK_MCLK1 1
16#define WM8994_SYSCLK_MCLK2 2 18#define WM8994_SYSCLK_MCLK2 2
@@ -45,4 +47,73 @@ struct wm8994_access_mask {
45extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE]; 47extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
46extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE]; 48extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
47 49
50int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
51 struct snd_kcontrol *kcontrol, int event);
52
53void wm8958_dsp2_init(struct snd_soc_codec *codec);
54
55struct wm8994_micdet {
56 struct snd_soc_jack *jack;
57 int det;
58 int shrt;
59};
60
61/* codec private data */
62struct wm8994_fll_config {
63 int src;
64 int in;
65 int out;
66};
67
68#define WM8994_NUM_DRC 3
69#define WM8994_NUM_EQ 3
70
71struct wm8994_priv {
72 struct wm_hubs_data hubs;
73 enum snd_soc_control_type control_type;
74 void *control_data;
75 struct snd_soc_codec *codec;
76 int sysclk[2];
77 int sysclk_rate[2];
78 int mclk[2];
79 int aifclk[2];
80 struct wm8994_fll_config fll[2], fll_suspend[2];
81
82 int dac_rates[2];
83 int lrclk_shared[2];
84
85 int mbc_ena[3];
86
87 /* Platform dependant DRC configuration */
88 const char **drc_texts;
89 int drc_cfg[WM8994_NUM_DRC];
90 struct soc_enum drc_enum;
91
92 /* Platform dependant ReTune mobile configuration */
93 int num_retune_mobile_texts;
94 const char **retune_mobile_texts;
95 int retune_mobile_cfg[WM8994_NUM_EQ];
96 struct soc_enum retune_mobile_enum;
97
98 /* Platform dependant MBC configuration */
99 int mbc_cfg;
100 const char **mbc_texts;
101 struct soc_enum mbc_enum;
102
103 struct wm8994_micdet micdet[2];
104
105 wm8958_micdet_cb jack_cb;
106 void *jack_cb_data;
107 int micdet_irq;
108
109 int revision;
110 struct wm8994_pdata *pdata;
111
112 unsigned int aif1clk_enable:1;
113 unsigned int aif2clk_enable:1;
114
115 unsigned int aif1clk_disable:1;
116 unsigned int aif2clk_disable:1;
117};
118
48#endif 119#endif