diff options
| author | Dimitris Papastamos <dp@opensource.wolfsonmicro.com> | 2011-02-11 11:32:12 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-02-13 14:45:01 -0500 |
| commit | c52fd021bc027a90a10782c0dcf667ac0135e478 (patch) | |
| tree | f01f88c04ee4aacfd898aea8b0e09bd66e67c45b | |
| parent | 173efa09e4c807a2a764509ddd593ad13a44d1df (diff) | |
ASoC: WM8994: Improve playback robustness
On WM8994 revision D and earlier ensure proper playback robustness
as some rare use cases can trigger issues.
Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: stable@kernel.org
| -rw-r--r-- | sound/soc/codecs/wm8994.c | 59 |
1 files changed, 52 insertions, 7 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index bd0cfdd1386..a60b5dbf015 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
| @@ -1083,6 +1083,17 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, | |||
| 1083 | return 0; | 1083 | return 0; |
| 1084 | } | 1084 | } |
| 1085 | 1085 | ||
| 1086 | static int dac_ev(struct snd_soc_dapm_widget *w, | ||
| 1087 | struct snd_kcontrol *kcontrol, int event) | ||
| 1088 | { | ||
| 1089 | struct snd_soc_codec *codec = w->codec; | ||
| 1090 | unsigned int mask = 1 << w->shift; | ||
| 1091 | |||
| 1092 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, | ||
| 1093 | mask, mask); | ||
| 1094 | return 0; | ||
| 1095 | } | ||
| 1096 | |||
| 1086 | static const char *hp_mux_text[] = { | 1097 | static const char *hp_mux_text[] = { |
| 1087 | "Mixer", | 1098 | "Mixer", |
| 1088 | "DAC", | 1099 | "DAC", |
| @@ -1374,6 +1385,24 @@ SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), | |||
| 1374 | SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0) | 1385 | SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0) |
| 1375 | }; | 1386 | }; |
| 1376 | 1387 | ||
| 1388 | static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { | ||
| 1389 | SND_SOC_DAPM_DAC_E("DAC2L", NULL, SND_SOC_NOPM, 3, 0, | ||
| 1390 | dac_ev, SND_SOC_DAPM_PRE_PMU), | ||
| 1391 | SND_SOC_DAPM_DAC_E("DAC2R", NULL, SND_SOC_NOPM, 2, 0, | ||
| 1392 | dac_ev, SND_SOC_DAPM_PRE_PMU), | ||
| 1393 | SND_SOC_DAPM_DAC_E("DAC1L", NULL, SND_SOC_NOPM, 1, 0, | ||
| 1394 | dac_ev, SND_SOC_DAPM_PRE_PMU), | ||
| 1395 | SND_SOC_DAPM_DAC_E("DAC1R", NULL, SND_SOC_NOPM, 0, 0, | ||
| 1396 | dac_ev, SND_SOC_DAPM_PRE_PMU), | ||
| 1397 | }; | ||
| 1398 | |||
| 1399 | static const struct snd_soc_dapm_widget wm8994_dac_widgets[] = { | ||
| 1400 | SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0), | ||
| 1401 | SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0), | ||
| 1402 | SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0), | ||
| 1403 | SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0), | ||
| 1404 | }; | ||
| 1405 | |||
| 1377 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { | 1406 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { |
| 1378 | SND_SOC_DAPM_INPUT("DMIC1DAT"), | 1407 | SND_SOC_DAPM_INPUT("DMIC1DAT"), |
| 1379 | SND_SOC_DAPM_INPUT("DMIC2DAT"), | 1408 | SND_SOC_DAPM_INPUT("DMIC2DAT"), |
| @@ -1471,11 +1500,6 @@ SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), | |||
| 1471 | SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), | 1500 | SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), |
| 1472 | SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), | 1501 | SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), |
| 1473 | 1502 | ||
| 1474 | SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0), | ||
| 1475 | SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0), | ||
| 1476 | SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0), | ||
| 1477 | SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0), | ||
| 1478 | |||
| 1479 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), | 1503 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), |
| 1480 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), | 1504 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), |
| 1481 | 1505 | ||
| @@ -2627,6 +2651,22 @@ static int wm8994_resume(struct snd_soc_codec *codec) | |||
| 2627 | { | 2651 | { |
| 2628 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 2652 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
| 2629 | int i, ret; | 2653 | int i, ret; |
| 2654 | unsigned int val, mask; | ||
| 2655 | |||
| 2656 | if (wm8994->revision < 4) { | ||
| 2657 | /* force a HW read */ | ||
| 2658 | val = wm8994_reg_read(codec->control_data, | ||
| 2659 | WM8994_POWER_MANAGEMENT_5); | ||
| 2660 | |||
| 2661 | /* modify the cache only */ | ||
| 2662 | codec->cache_only = 1; | ||
| 2663 | mask = WM8994_DAC1R_ENA | WM8994_DAC1L_ENA | | ||
| 2664 | WM8994_DAC2R_ENA | WM8994_DAC2L_ENA; | ||
| 2665 | val &= mask; | ||
| 2666 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, | ||
| 2667 | mask, val); | ||
| 2668 | codec->cache_only = 0; | ||
| 2669 | } | ||
| 2630 | 2670 | ||
| 2631 | /* Restore the registers */ | 2671 | /* Restore the registers */ |
| 2632 | ret = snd_soc_cache_sync(codec); | 2672 | ret = snd_soc_cache_sync(codec); |
| @@ -3238,12 +3278,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
| 3238 | case WM8994: | 3278 | case WM8994: |
| 3239 | snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, | 3279 | snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, |
| 3240 | ARRAY_SIZE(wm8994_specific_dapm_widgets)); | 3280 | ARRAY_SIZE(wm8994_specific_dapm_widgets)); |
| 3241 | if (wm8994->revision < 4) | 3281 | if (wm8994->revision < 4) { |
| 3242 | snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, | 3282 | snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, |
| 3243 | ARRAY_SIZE(wm8994_lateclk_revd_widgets)); | 3283 | ARRAY_SIZE(wm8994_lateclk_revd_widgets)); |
| 3244 | else | 3284 | snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets, |
| 3285 | ARRAY_SIZE(wm8994_dac_revd_widgets)); | ||
| 3286 | } else { | ||
| 3245 | snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets, | 3287 | snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets, |
| 3246 | ARRAY_SIZE(wm8994_lateclk_widgets)); | 3288 | ARRAY_SIZE(wm8994_lateclk_widgets)); |
| 3289 | snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets, | ||
| 3290 | ARRAY_SIZE(wm8994_dac_widgets)); | ||
| 3291 | } | ||
| 3247 | break; | 3292 | break; |
| 3248 | case WM8958: | 3293 | case WM8958: |
| 3249 | snd_soc_add_controls(codec, wm8958_snd_controls, | 3294 | snd_soc_add_controls(codec, wm8958_snd_controls, |
