diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-04-26 15:06:56 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-04-27 13:42:10 -0400 |
commit | af31a227e1abee06ccd88c2c52f4fb36b786cebe (patch) | |
tree | 1d828dbc011d4c8871f851ba4dcf6a3fe45995c7 /sound | |
parent | f57b8488bc39f7674cbadf4e2db05a7db8ffa660 (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.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm_hubs.c | 48 | ||||
-rw-r--r-- | sound/soc/codecs/wm_hubs.h | 5 |
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 | } |
110 | EXPORT_SYMBOL_GPL(wm_hubs_dcs_done); | 110 | EXPORT_SYMBOL_GPL(wm_hubs_dcs_done); |
111 | 111 | ||
112 | static 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; |