aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,