aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorDimitris Papastamos <dp@opensource.wolfsonmicro.com>2011-02-11 11:32:11 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-02-13 14:44:54 -0500
commit173efa09e4c807a2a764509ddd593ad13a44d1df (patch)
tree112a5b62f90b587daa2f389ab07e05b913a5aff6 /sound
parent3088e3b4963d26d6f6f54987f595b974ed6d48d8 (diff)
ASoC: WM8994: Improve robustness in some use cases
Ensure that on disabling certain registers such as AIF1DAC1L, AIF1DAC1R etc. the AIF1CLK and AIF2CLK remain enabled. Similarly when enabling those registers, AIF1CLK and AIF2CLK will remain disabled. 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
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm8994.c142
1 files changed, 133 insertions, 9 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 37b8aa8a680f..bd0cfdd1386f 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -107,6 +107,9 @@ struct wm8994_priv {
107 107
108 int revision; 108 int revision;
109 struct wm8994_pdata *pdata; 109 struct wm8994_pdata *pdata;
110
111 unsigned int aif1clk_enable:1;
112 unsigned int aif2clk_enable:1;
110}; 113};
111 114
112static int wm8994_readable(unsigned int reg) 115static int wm8994_readable(unsigned int reg)
@@ -1004,6 +1007,82 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
1004 } 1007 }
1005} 1008}
1006 1009
1010static int late_enable_ev(struct snd_soc_dapm_widget *w,
1011 struct snd_kcontrol *kcontrol, int event)
1012{
1013 struct snd_soc_codec *codec = w->codec;
1014 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1015
1016 switch (event) {
1017 case SND_SOC_DAPM_PRE_PMU:
1018 if (wm8994->aif1clk_enable)
1019 snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
1020 WM8994_AIF1CLK_ENA_MASK,
1021 WM8994_AIF1CLK_ENA);
1022 if (wm8994->aif2clk_enable)
1023 snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
1024 WM8994_AIF2CLK_ENA_MASK,
1025 WM8994_AIF2CLK_ENA);
1026 break;
1027 }
1028
1029 return 0;
1030}
1031
1032static int late_disable_ev(struct snd_soc_dapm_widget *w,
1033 struct snd_kcontrol *kcontrol, int event)
1034{
1035 struct snd_soc_codec *codec = w->codec;
1036 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1037
1038 switch (event) {
1039 case SND_SOC_DAPM_POST_PMD:
1040 if (wm8994->aif1clk_enable) {
1041 snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
1042 WM8994_AIF1CLK_ENA_MASK, 0);
1043 wm8994->aif1clk_enable = 0;
1044 }
1045 if (wm8994->aif2clk_enable) {
1046 snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
1047 WM8994_AIF2CLK_ENA_MASK, 0);
1048 wm8994->aif2clk_enable = 0;
1049 }
1050 break;
1051 }
1052
1053 return 0;
1054}
1055
1056static int aif1clk_ev(struct snd_soc_dapm_widget *w,
1057 struct snd_kcontrol *kcontrol, int event)
1058{
1059 struct snd_soc_codec *codec = w->codec;
1060 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1061
1062 switch (event) {
1063 case SND_SOC_DAPM_PRE_PMU:
1064 wm8994->aif1clk_enable = 1;
1065 break;
1066 }
1067
1068 return 0;
1069}
1070
1071static int aif2clk_ev(struct snd_soc_dapm_widget *w,
1072 struct snd_kcontrol *kcontrol, int event)
1073{
1074 struct snd_soc_codec *codec = w->codec;
1075 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1076
1077 switch (event) {
1078 case SND_SOC_DAPM_PRE_PMU:
1079 wm8994->aif2clk_enable = 1;
1080 break;
1081 }
1082
1083 return 0;
1084}
1085
1007static const char *hp_mux_text[] = { 1086static const char *hp_mux_text[] = {
1008 "Mixer", 1087 "Mixer",
1009 "DAC", 1088 "DAC",
@@ -1272,6 +1351,29 @@ static const struct soc_enum aif2dacr_src_enum =
1272static const struct snd_kcontrol_new aif2dacr_src_mux = 1351static const struct snd_kcontrol_new aif2dacr_src_mux =
1273 SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum); 1352 SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);
1274 1353
1354static const struct snd_soc_dapm_widget wm8994_lateclk_revd_widgets[] = {
1355SND_SOC_DAPM_SUPPLY("AIF1CLK", SND_SOC_NOPM, 0, 0, aif1clk_ev,
1356 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1357SND_SOC_DAPM_SUPPLY("AIF2CLK", SND_SOC_NOPM, 0, 0, aif2clk_ev,
1358 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1359
1360SND_SOC_DAPM_PGA_E("Late DAC1L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
1361 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1362SND_SOC_DAPM_PGA_E("Late DAC1R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
1363 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1364SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
1365 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1366SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
1367 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1368
1369SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
1370};
1371
1372static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
1373SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
1374SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0)
1375};
1376
1275static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { 1377static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
1276SND_SOC_DAPM_INPUT("DMIC1DAT"), 1378SND_SOC_DAPM_INPUT("DMIC1DAT"),
1277SND_SOC_DAPM_INPUT("DMIC2DAT"), 1379SND_SOC_DAPM_INPUT("DMIC2DAT"),
@@ -1284,9 +1386,6 @@ SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8994_CLOCKING_1, 3, 0, NULL, 0),
1284SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8994_CLOCKING_1, 2, 0, NULL, 0), 1386SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8994_CLOCKING_1, 2, 0, NULL, 0),
1285SND_SOC_DAPM_SUPPLY("DSPINTCLK", WM8994_CLOCKING_1, 1, 0, NULL, 0), 1387SND_SOC_DAPM_SUPPLY("DSPINTCLK", WM8994_CLOCKING_1, 1, 0, NULL, 0),
1286 1388
1287SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
1288SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0),
1289
1290SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", NULL, 1389SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", NULL,
1291 0, WM8994_POWER_MANAGEMENT_4, 9, 0), 1390 0, WM8994_POWER_MANAGEMENT_4, 9, 0),
1292SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", NULL, 1391SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", NULL,
@@ -1516,14 +1615,12 @@ static const struct snd_soc_dapm_route intercon[] = {
1516 { "AIF2ADC Mux", "AIF3DACDAT", "AIF3ADCDAT" }, 1615 { "AIF2ADC Mux", "AIF3DACDAT", "AIF3ADCDAT" },
1517 1616
1518 /* DAC1 inputs */ 1617 /* DAC1 inputs */
1519 { "DAC1L", NULL, "DAC1L Mixer" },
1520 { "DAC1L Mixer", "AIF2 Switch", "AIF2DACL" }, 1618 { "DAC1L Mixer", "AIF2 Switch", "AIF2DACL" },
1521 { "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, 1619 { "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
1522 { "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, 1620 { "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
1523 { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" }, 1621 { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
1524 { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" }, 1622 { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
1525 1623
1526 { "DAC1R", NULL, "DAC1R Mixer" },
1527 { "DAC1R Mixer", "AIF2 Switch", "AIF2DACR" }, 1624 { "DAC1R Mixer", "AIF2 Switch", "AIF2DACR" },
1528 { "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, 1625 { "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
1529 { "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, 1626 { "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
@@ -1532,7 +1629,6 @@ static const struct snd_soc_dapm_route intercon[] = {
1532 1629
1533 /* DAC2/AIF2 outputs */ 1630 /* DAC2/AIF2 outputs */
1534 { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" }, 1631 { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" },
1535 { "DAC2L", NULL, "AIF2DAC2L Mixer" },
1536 { "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" }, 1632 { "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" },
1537 { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, 1633 { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
1538 { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, 1634 { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
@@ -1540,7 +1636,6 @@ static const struct snd_soc_dapm_route intercon[] = {
1540 { "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" }, 1636 { "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
1541 1637
1542 { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" }, 1638 { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" },
1543 { "DAC2R", NULL, "AIF2DAC2R Mixer" },
1544 { "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" }, 1639 { "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" },
1545 { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, 1640 { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
1546 { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, 1641 { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
@@ -1584,6 +1679,24 @@ static const struct snd_soc_dapm_route intercon[] = {
1584 { "Right Headphone Mux", "DAC", "DAC1R" }, 1679 { "Right Headphone Mux", "DAC", "DAC1R" },
1585}; 1680};
1586 1681
1682static const struct snd_soc_dapm_route wm8994_lateclk_revd_intercon[] = {
1683 { "DAC1L", NULL, "Late DAC1L Enable PGA" },
1684 { "Late DAC1L Enable PGA", NULL, "DAC1L Mixer" },
1685 { "DAC1R", NULL, "Late DAC1R Enable PGA" },
1686 { "Late DAC1R Enable PGA", NULL, "DAC1R Mixer" },
1687 { "DAC2L", NULL, "Late DAC2L Enable PGA" },
1688 { "Late DAC2L Enable PGA", NULL, "AIF2DAC2L Mixer" },
1689 { "DAC2R", NULL, "Late DAC2R Enable PGA" },
1690 { "Late DAC2R Enable PGA", NULL, "AIF2DAC2R Mixer" }
1691};
1692
1693static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = {
1694 { "DAC1L", NULL, "DAC1L Mixer" },
1695 { "DAC1R", NULL, "DAC1R Mixer" },
1696 { "DAC2L", NULL, "AIF2DAC2L Mixer" },
1697 { "DAC2R", NULL, "AIF2DAC2R Mixer" },
1698};
1699
1587static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { 1700static const struct snd_soc_dapm_route wm8994_revd_intercon[] = {
1588 { "AIF1DACDAT", NULL, "AIF2DACDAT" }, 1701 { "AIF1DACDAT", NULL, "AIF2DACDAT" },
1589 { "AIF2DACDAT", NULL, "AIF1DACDAT" }, 1702 { "AIF2DACDAT", NULL, "AIF1DACDAT" },
@@ -3125,6 +3238,12 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
3125 case WM8994: 3238 case WM8994:
3126 snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, 3239 snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
3127 ARRAY_SIZE(wm8994_specific_dapm_widgets)); 3240 ARRAY_SIZE(wm8994_specific_dapm_widgets));
3241 if (wm8994->revision < 4)
3242 snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
3243 ARRAY_SIZE(wm8994_lateclk_revd_widgets));
3244 else
3245 snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
3246 ARRAY_SIZE(wm8994_lateclk_widgets));
3128 break; 3247 break;
3129 case WM8958: 3248 case WM8958:
3130 snd_soc_add_controls(codec, wm8958_snd_controls, 3249 snd_soc_add_controls(codec, wm8958_snd_controls,
@@ -3143,10 +3262,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
3143 snd_soc_dapm_add_routes(dapm, wm8994_intercon, 3262 snd_soc_dapm_add_routes(dapm, wm8994_intercon,
3144 ARRAY_SIZE(wm8994_intercon)); 3263 ARRAY_SIZE(wm8994_intercon));
3145 3264
3146 if (wm8994->revision < 4) 3265 if (wm8994->revision < 4) {
3147 snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon, 3266 snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
3148 ARRAY_SIZE(wm8994_revd_intercon)); 3267 ARRAY_SIZE(wm8994_revd_intercon));
3149 3268 snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
3269 ARRAY_SIZE(wm8994_lateclk_revd_intercon));
3270 } else {
3271 snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
3272 ARRAY_SIZE(wm8994_lateclk_intercon));
3273 }
3150 break; 3274 break;
3151 case WM8958: 3275 case WM8958:
3152 snd_soc_dapm_add_routes(dapm, wm8958_intercon, 3276 snd_soc_dapm_add_routes(dapm, wm8958_intercon,