aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-04-26 15:06:56 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-04-27 13:42:10 -0400
commitaf31a227e1abee06ccd88c2c52f4fb36b786cebe (patch)
tree1d828dbc011d4c8871f851ba4dcf6a3fe45995c7 /sound
parentf57b8488bc39f7674cbadf4e2db05a7db8ffa660 (diff)
ASoC: wm_hubs: Special case headphones for digital paths in more use cases
The optimisations which we can do with caching the headphone DCS result in wm_hubs have only been enabled in cases where class W is enabled. However, there are more use cases which can benefit from the cache, especially with WM8994 series devices with their more advanced digital routing. Rather than keying off the class W information from the CODECs have a check in wm_hubs for a suitable path and use that to determine if we can deploy our headphone optimisations. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm8993.c2
-rw-r--r--sound/soc/codecs/wm8994.c4
-rw-r--r--sound/soc/codecs/wm_hubs.c48
-rw-r--r--sound/soc/codecs/wm_hubs.h5
4 files changed, 45 insertions, 14 deletions
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index d256a9340644..8bb005926aa0 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -852,7 +852,6 @@ static int class_w_put(struct snd_kcontrol *kcontrol,
852 0); 852 0);
853 } 853 }
854 wm8993->class_w_users++; 854 wm8993->class_w_users++;
855 wm8993->hubs_data.class_w = true;
856 } 855 }
857 856
858 /* Implement the change */ 857 /* Implement the change */
@@ -869,7 +868,6 @@ static int class_w_put(struct snd_kcontrol *kcontrol,
869 WM8993_CP_DYN_V); 868 WM8993_CP_DYN_V);
870 } 869 }
871 wm8993->class_w_users--; 870 wm8993->class_w_users--;
872 wm8993->hubs_data.class_w = false;
873 } 871 }
874 872
875 dev_dbg(codec->dev, "Indirect DAC use count now %d\n", 873 dev_dbg(codec->dev, "Indirect DAC use count now %d\n",
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index a22c29386243..2475e1c10334 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -998,13 +998,11 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
998 WM8994_CP_DYN_PWR | 998 WM8994_CP_DYN_PWR |
999 WM8994_CP_DYN_SRC_SEL_MASK, 999 WM8994_CP_DYN_SRC_SEL_MASK,
1000 source | WM8994_CP_DYN_PWR); 1000 source | WM8994_CP_DYN_PWR);
1001 wm8994->hubs.class_w = true;
1002 1001
1003 } else { 1002 } else {
1004 dev_dbg(codec->dev, "Class W disabled\n"); 1003 dev_dbg(codec->dev, "Class W disabled\n");
1005 snd_soc_update_bits(codec, WM8994_CLASS_W_1, 1004 snd_soc_update_bits(codec, WM8994_CLASS_W_1,
1006 WM8994_CP_DYN_PWR, 0); 1005 WM8994_CP_DYN_PWR, 0);
1007 wm8994->hubs.class_w = false;
1008 } 1006 }
1009} 1007}
1010 1008
@@ -3609,7 +3607,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
3609 wm8994->hubs.dcs_readback_mode = 2; 3607 wm8994->hubs.dcs_readback_mode = 2;
3610 wm8994->hubs.no_series_update = 1; 3608 wm8994->hubs.no_series_update = 1;
3611 wm8994->hubs.hp_startup_mode = 1; 3609 wm8994->hubs.hp_startup_mode = 1;
3612 wm8994->hubs.no_cache_class_w = true; 3610 wm8994->hubs.no_cache_dac_hp_direct = true;
3613 wm8994->fll_byp = true; 3611 wm8994->fll_byp = true;
3614 3612
3615 switch (wm8994->revision) { 3613 switch (wm8994->revision) {
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index f13f2886339c..15aed8b7d981 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -109,6 +109,42 @@ irqreturn_t wm_hubs_dcs_done(int irq, void *data)
109} 109}
110EXPORT_SYMBOL_GPL(wm_hubs_dcs_done); 110EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
111 111
112static bool wm_hubs_dac_hp_direct(struct snd_soc_codec *codec)
113{
114 int reg;
115
116 /* If we're going via the mixer we'll need to do additional checks */
117 reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER1);
118 if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
119 if (reg & ~WM8993_DACL_TO_MIXOUTL) {
120 dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
121 reg & ~WM8993_DACL_TO_HPOUT1L);
122 return false;
123 } else {
124 dev_vdbg(codec->dev, "HPL connected to mixer\n");
125 return false;
126 }
127 } else {
128 dev_vdbg(codec->dev, "HPL connected to DAC\n");
129 }
130
131 reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER2);
132 if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
133 if (reg & ~WM8993_DACR_TO_MIXOUTR) {
134 dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
135 reg & ~WM8993_DACR_TO_HPOUT1R);
136 return false;
137 } else {
138 dev_vdbg(codec->dev, "HPR connected to mixer\n");
139 return false;
140 }
141 } else {
142 dev_vdbg(codec->dev, "HPR connected to DAC\n");
143 }
144
145 return true;
146}
147
112/* 148/*
113 * Startup calibration of the DC servo 149 * Startup calibration of the DC servo
114 */ 150 */
@@ -129,10 +165,10 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
129 165
130 /* If we're using a digital only path and have a previously 166 /* If we're using a digital only path and have a previously
131 * callibrated DC servo offset stored then use that. */ 167 * callibrated DC servo offset stored then use that. */
132 if (hubs->class_w && hubs->class_w_dcs) { 168 if (wm_hubs_dac_hp_direct(codec) && hubs->dac_hp_direct_dcs) {
133 dev_dbg(codec->dev, "Using cached DC servo offset %x\n", 169 dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
134 hubs->class_w_dcs); 170 hubs->dac_hp_direct_dcs);
135 snd_soc_write(codec, dcs_reg, hubs->class_w_dcs); 171 snd_soc_write(codec, dcs_reg, hubs->dac_hp_direct_dcs);
136 wait_for_dc_servo(codec, 172 wait_for_dc_servo(codec,
137 WM8993_DCS_TRIG_DAC_WR_0 | 173 WM8993_DCS_TRIG_DAC_WR_0 |
138 WM8993_DCS_TRIG_DAC_WR_1); 174 WM8993_DCS_TRIG_DAC_WR_1);
@@ -207,8 +243,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
207 243
208 /* Save the callibrated offset if we're in class W mode and 244 /* Save the callibrated offset if we're in class W mode and
209 * therefore don't have any analogue signal mixed in. */ 245 * therefore don't have any analogue signal mixed in. */
210 if (hubs->class_w && !hubs->no_cache_class_w) 246 if (wm_hubs_dac_hp_direct(codec) && !hubs->no_cache_dac_hp_direct)
211 hubs->class_w_dcs = dcs_cfg; 247 hubs->dac_hp_direct_dcs = dcs_cfg;
212} 248}
213 249
214/* 250/*
@@ -224,7 +260,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
224 ret = snd_soc_put_volsw(kcontrol, ucontrol); 260 ret = snd_soc_put_volsw(kcontrol, ucontrol);
225 261
226 /* Updating the analogue gains invalidates the DC servo cache */ 262 /* Updating the analogue gains invalidates the DC servo cache */
227 hubs->class_w_dcs = 0; 263 hubs->dac_hp_direct_dcs = 0;
228 264
229 /* If we're applying an offset correction then updating the 265 /* If we're applying an offset correction then updating the
230 * callibration would be likely to introduce further offsets. */ 266 * callibration would be likely to introduce further offsets. */
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index 5705276f4943..8bb9f1b51bf3 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -30,9 +30,8 @@ struct wm_hubs_data {
30 int series_startup; 30 int series_startup;
31 int no_series_update; 31 int no_series_update;
32 32
33 bool no_cache_class_w; 33 bool no_cache_dac_hp_direct;
34 bool class_w; 34 u16 dac_hp_direct_dcs;
35 u16 class_w_dcs;
36 35
37 bool lineout1_se; 36 bool lineout1_se;
38 bool lineout1n_ena; 37 bool lineout1n_ena;