Skip to content

Commit 1a38336

Browse files
committed
ASoC: wm8994: Improve sequencing of AIF channel enables
This ensures a clean startup of the channels, without this change some use cases could result in issues in a small proportion of cases. Signed-off-by: Mark Brown <[email protected]> Cc: [email protected]
1 parent cdf27f3 commit 1a38336

File tree

1 file changed

+222
-54
lines changed

1 file changed

+222
-54
lines changed

sound/soc/codecs/wm8994.c

Lines changed: 222 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,61 +1000,170 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
10001000
}
10011001
}
10021002

1003-
static int late_enable_ev(struct snd_soc_dapm_widget *w,
1004-
struct snd_kcontrol *kcontrol, int event)
1003+
static int aif1clk_ev(struct snd_soc_dapm_widget *w,
1004+
struct snd_kcontrol *kcontrol, int event)
10051005
{
10061006
struct snd_soc_codec *codec = w->codec;
1007-
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1007+
struct wm8994 *control = codec->control_data;
1008+
int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
1009+
int dac;
1010+
int adc;
1011+
int val;
1012+
1013+
switch (control->type) {
1014+
case WM8994:
1015+
case WM8958:
1016+
mask |= WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA;
1017+
break;
1018+
default:
1019+
break;
1020+
}
10081021

10091022
switch (event) {
10101023
case SND_SOC_DAPM_PRE_PMU:
1011-
if (wm8994->aif1clk_enable) {
1012-
snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
1013-
WM8994_AIF1CLK_ENA_MASK,
1014-
WM8994_AIF1CLK_ENA);
1015-
wm8994->aif1clk_enable = 0;
1016-
}
1017-
if (wm8994->aif2clk_enable) {
1018-
snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
1019-
WM8994_AIF2CLK_ENA_MASK,
1020-
WM8994_AIF2CLK_ENA);
1021-
wm8994->aif2clk_enable = 0;
1022-
}
1024+
val = snd_soc_read(codec, WM8994_AIF1_CONTROL_1);
1025+
if ((val & WM8994_AIF1ADCL_SRC) &&
1026+
(val & WM8994_AIF1ADCR_SRC))
1027+
adc = WM8994_AIF1ADC1R_ENA | WM8994_AIF1ADC2R_ENA;
1028+
else if (!(val & WM8994_AIF1ADCL_SRC) &&
1029+
!(val & WM8994_AIF1ADCR_SRC))
1030+
adc = WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC2L_ENA;
1031+
else
1032+
adc = WM8994_AIF1ADC1R_ENA | WM8994_AIF1ADC2R_ENA |
1033+
WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC2L_ENA;
1034+
1035+
val = snd_soc_read(codec, WM8994_AIF1_CONTROL_2);
1036+
if ((val & WM8994_AIF1DACL_SRC) &&
1037+
(val & WM8994_AIF1DACR_SRC))
1038+
dac = WM8994_AIF1DAC1R_ENA | WM8994_AIF1DAC2R_ENA;
1039+
else if (!(val & WM8994_AIF1DACL_SRC) &&
1040+
!(val & WM8994_AIF1DACR_SRC))
1041+
dac = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC2L_ENA;
1042+
else
1043+
dac = WM8994_AIF1DAC1R_ENA | WM8994_AIF1DAC2R_ENA |
1044+
WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC2L_ENA;
1045+
1046+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
1047+
mask, adc);
1048+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
1049+
mask, dac);
1050+
snd_soc_update_bits(codec, WM8994_CLOCKING_1,
1051+
WM8994_AIF1DSPCLK_ENA |
1052+
WM8994_SYSDSPCLK_ENA,
1053+
WM8994_AIF1DSPCLK_ENA |
1054+
WM8994_SYSDSPCLK_ENA);
1055+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4, mask,
1056+
WM8994_AIF1ADC1R_ENA |
1057+
WM8994_AIF1ADC1L_ENA |
1058+
WM8994_AIF1ADC2R_ENA |
1059+
WM8994_AIF1ADC2L_ENA);
1060+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, mask,
1061+
WM8994_AIF1DAC1R_ENA |
1062+
WM8994_AIF1DAC1L_ENA |
1063+
WM8994_AIF1DAC2R_ENA |
1064+
WM8994_AIF1DAC2L_ENA);
10231065
break;
1024-
}
10251066

1026-
/* We may also have postponed startup of DSP, handle that. */
1027-
wm8958_aif_ev(w, kcontrol, event);
1067+
case SND_SOC_DAPM_PRE_PMD:
1068+
case SND_SOC_DAPM_POST_PMD:
1069+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
1070+
mask, 0);
1071+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
1072+
mask, 0);
1073+
1074+
val = snd_soc_read(codec, WM8994_CLOCKING_1);
1075+
if (val & WM8994_AIF2DSPCLK_ENA)
1076+
val = WM8994_SYSDSPCLK_ENA;
1077+
else
1078+
val = 0;
1079+
snd_soc_update_bits(codec, WM8994_CLOCKING_1,
1080+
WM8994_SYSDSPCLK_ENA |
1081+
WM8994_AIF1DSPCLK_ENA, val);
1082+
break;
1083+
}
10281084

10291085
return 0;
10301086
}
10311087

1032-
static int late_disable_ev(struct snd_soc_dapm_widget *w,
1033-
struct snd_kcontrol *kcontrol, int event)
1088+
static int aif2clk_ev(struct snd_soc_dapm_widget *w,
1089+
struct snd_kcontrol *kcontrol, int event)
10341090
{
10351091
struct snd_soc_codec *codec = w->codec;
1036-
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1092+
int dac;
1093+
int adc;
1094+
int val;
10371095

10381096
switch (event) {
1097+
case SND_SOC_DAPM_PRE_PMU:
1098+
val = snd_soc_read(codec, WM8994_AIF2_CONTROL_1);
1099+
if ((val & WM8994_AIF2ADCL_SRC) &&
1100+
(val & WM8994_AIF2ADCR_SRC))
1101+
adc = WM8994_AIF2ADCR_ENA;
1102+
else if (!(val & WM8994_AIF2ADCL_SRC) &&
1103+
!(val & WM8994_AIF2ADCR_SRC))
1104+
adc = WM8994_AIF2ADCL_ENA;
1105+
else
1106+
adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA;
1107+
1108+
1109+
val = snd_soc_read(codec, WM8994_AIF2_CONTROL_2);
1110+
if ((val & WM8994_AIF2DACL_SRC) &&
1111+
(val & WM8994_AIF2DACR_SRC))
1112+
dac = WM8994_AIF2DACR_ENA;
1113+
else if (!(val & WM8994_AIF2DACL_SRC) &&
1114+
!(val & WM8994_AIF2DACR_SRC))
1115+
dac = WM8994_AIF2DACL_ENA;
1116+
else
1117+
dac = WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA;
1118+
1119+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
1120+
WM8994_AIF2ADCL_ENA |
1121+
WM8994_AIF2ADCR_ENA, adc);
1122+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
1123+
WM8994_AIF2DACL_ENA |
1124+
WM8994_AIF2DACR_ENA, dac);
1125+
snd_soc_update_bits(codec, WM8994_CLOCKING_1,
1126+
WM8994_AIF2DSPCLK_ENA |
1127+
WM8994_SYSDSPCLK_ENA,
1128+
WM8994_AIF2DSPCLK_ENA |
1129+
WM8994_SYSDSPCLK_ENA);
1130+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
1131+
WM8994_AIF2ADCL_ENA |
1132+
WM8994_AIF2ADCR_ENA,
1133+
WM8994_AIF2ADCL_ENA |
1134+
WM8994_AIF2ADCR_ENA);
1135+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
1136+
WM8994_AIF2DACL_ENA |
1137+
WM8994_AIF2DACR_ENA,
1138+
WM8994_AIF2DACL_ENA |
1139+
WM8994_AIF2DACR_ENA);
1140+
break;
1141+
1142+
case SND_SOC_DAPM_PRE_PMD:
10391143
case SND_SOC_DAPM_POST_PMD:
1040-
if (wm8994->aif1clk_disable) {
1041-
snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
1042-
WM8994_AIF1CLK_ENA_MASK, 0);
1043-
wm8994->aif1clk_disable = 0;
1044-
}
1045-
if (wm8994->aif2clk_disable) {
1046-
snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
1047-
WM8994_AIF2CLK_ENA_MASK, 0);
1048-
wm8994->aif2clk_disable = 0;
1049-
}
1144+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
1145+
WM8994_AIF2DACL_ENA |
1146+
WM8994_AIF2DACR_ENA, 0);
1147+
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
1148+
WM8994_AIF2ADCL_ENA |
1149+
WM8994_AIF2ADCR_ENA, 0);
1150+
1151+
val = snd_soc_read(codec, WM8994_CLOCKING_1);
1152+
if (val & WM8994_AIF1DSPCLK_ENA)
1153+
val = WM8994_SYSDSPCLK_ENA;
1154+
else
1155+
val = 0;
1156+
snd_soc_update_bits(codec, WM8994_CLOCKING_1,
1157+
WM8994_SYSDSPCLK_ENA |
1158+
WM8994_AIF2DSPCLK_ENA, val);
10501159
break;
10511160
}
10521161

10531162
return 0;
10541163
}
10551164

1056-
static int aif1clk_ev(struct snd_soc_dapm_widget *w,
1057-
struct snd_kcontrol *kcontrol, int event)
1165+
static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
1166+
struct snd_kcontrol *kcontrol, int event)
10581167
{
10591168
struct snd_soc_codec *codec = w->codec;
10601169
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1071,8 +1180,8 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
10711180
return 0;
10721181
}
10731182

1074-
static int aif2clk_ev(struct snd_soc_dapm_widget *w,
1075-
struct snd_kcontrol *kcontrol, int event)
1183+
static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
1184+
struct snd_kcontrol *kcontrol, int event)
10761185
{
10771186
struct snd_soc_codec *codec = w->codec;
10781187
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1089,6 +1198,63 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
10891198
return 0;
10901199
}
10911200

1201+
static int late_enable_ev(struct snd_soc_dapm_widget *w,
1202+
struct snd_kcontrol *kcontrol, int event)
1203+
{
1204+
struct snd_soc_codec *codec = w->codec;
1205+
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1206+
1207+
switch (event) {
1208+
case SND_SOC_DAPM_PRE_PMU:
1209+
if (wm8994->aif1clk_enable) {
1210+
aif1clk_ev(w, kcontrol, event);
1211+
snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
1212+
WM8994_AIF1CLK_ENA_MASK,
1213+
WM8994_AIF1CLK_ENA);
1214+
wm8994->aif1clk_enable = 0;
1215+
}
1216+
if (wm8994->aif2clk_enable) {
1217+
aif2clk_ev(w, kcontrol, event);
1218+
snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
1219+
WM8994_AIF2CLK_ENA_MASK,
1220+
WM8994_AIF2CLK_ENA);
1221+
wm8994->aif2clk_enable = 0;
1222+
}
1223+
break;
1224+
}
1225+
1226+
/* We may also have postponed startup of DSP, handle that. */
1227+
wm8958_aif_ev(w, kcontrol, event);
1228+
1229+
return 0;
1230+
}
1231+
1232+
static int late_disable_ev(struct snd_soc_dapm_widget *w,
1233+
struct snd_kcontrol *kcontrol, int event)
1234+
{
1235+
struct snd_soc_codec *codec = w->codec;
1236+
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1237+
1238+
switch (event) {
1239+
case SND_SOC_DAPM_POST_PMD:
1240+
if (wm8994->aif1clk_disable) {
1241+
snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
1242+
WM8994_AIF1CLK_ENA_MASK, 0);
1243+
aif1clk_ev(w, kcontrol, event);
1244+
wm8994->aif1clk_disable = 0;
1245+
}
1246+
if (wm8994->aif2clk_disable) {
1247+
snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
1248+
WM8994_AIF2CLK_ENA_MASK, 0);
1249+
aif2clk_ev(w, kcontrol, event);
1250+
wm8994->aif2clk_disable = 0;
1251+
}
1252+
break;
1253+
}
1254+
1255+
return 0;
1256+
}
1257+
10921258
static int adc_mux_ev(struct snd_soc_dapm_widget *w,
10931259
struct snd_kcontrol *kcontrol, int event)
10941260
{
@@ -1385,9 +1551,9 @@ static const struct snd_kcontrol_new aif2dacr_src_mux =
13851551
SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);
13861552

13871553
static const struct snd_soc_dapm_widget wm8994_lateclk_revd_widgets[] = {
1388-
SND_SOC_DAPM_SUPPLY("AIF1CLK", SND_SOC_NOPM, 0, 0, aif1clk_ev,
1554+
SND_SOC_DAPM_SUPPLY("AIF1CLK", SND_SOC_NOPM, 0, 0, aif1clk_late_ev,
13891555
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1390-
SND_SOC_DAPM_SUPPLY("AIF2CLK", SND_SOC_NOPM, 0, 0, aif2clk_ev,
1556+
SND_SOC_DAPM_SUPPLY("AIF2CLK", SND_SOC_NOPM, 0, 0, aif2clk_late_ev,
13911557
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
13921558

13931559
SND_SOC_DAPM_PGA_E("Late DAC1L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
@@ -1416,8 +1582,10 @@ SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
14161582
};
14171583

14181584
static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
1419-
SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
1420-
SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0),
1585+
SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, aif1clk_ev,
1586+
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
1587+
SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, aif2clk_ev,
1588+
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
14211589
SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
14221590
SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
14231591
left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
@@ -1470,30 +1638,30 @@ SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event,
14701638
SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
14711639
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
14721640

1473-
SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8994_CLOCKING_1, 3, 0, NULL, 0),
1474-
SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8994_CLOCKING_1, 2, 0, NULL, 0),
1475-
SND_SOC_DAPM_SUPPLY("DSPINTCLK", WM8994_CLOCKING_1, 1, 0, NULL, 0),
1641+
SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0),
1642+
SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0),
1643+
SND_SOC_DAPM_SUPPLY("DSPINTCLK", SND_SOC_NOPM, 1, 0, NULL, 0),
14761644

14771645
SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", NULL,
1478-
0, WM8994_POWER_MANAGEMENT_4, 9, 0),
1646+
0, SND_SOC_NOPM, 9, 0),
14791647
SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", NULL,
1480-
0, WM8994_POWER_MANAGEMENT_4, 8, 0),
1648+
0, SND_SOC_NOPM, 8, 0),
14811649
SND_SOC_DAPM_AIF_IN_E("AIF1DAC1L", NULL, 0,
1482-
WM8994_POWER_MANAGEMENT_5, 9, 0, wm8958_aif_ev,
1650+
SND_SOC_NOPM, 9, 0, wm8958_aif_ev,
14831651
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
14841652
SND_SOC_DAPM_AIF_IN_E("AIF1DAC1R", NULL, 0,
1485-
WM8994_POWER_MANAGEMENT_5, 8, 0, wm8958_aif_ev,
1653+
SND_SOC_NOPM, 8, 0, wm8958_aif_ev,
14861654
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
14871655

14881656
SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", NULL,
1489-
0, WM8994_POWER_MANAGEMENT_4, 11, 0),
1657+
0, SND_SOC_NOPM, 11, 0),
14901658
SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", NULL,
1491-
0, WM8994_POWER_MANAGEMENT_4, 10, 0),
1659+
0, SND_SOC_NOPM, 10, 0),
14921660
SND_SOC_DAPM_AIF_IN_E("AIF1DAC2L", NULL, 0,
1493-
WM8994_POWER_MANAGEMENT_5, 11, 0, wm8958_aif_ev,
1661+
SND_SOC_NOPM, 11, 0, wm8958_aif_ev,
14941662
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
14951663
SND_SOC_DAPM_AIF_IN_E("AIF1DAC2R", NULL, 0,
1496-
WM8994_POWER_MANAGEMENT_5, 10, 0, wm8958_aif_ev,
1664+
SND_SOC_NOPM, 10, 0, wm8958_aif_ev,
14971665
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
14981666

14991667
SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
@@ -1520,14 +1688,14 @@ SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
15201688
dac1r_mix, ARRAY_SIZE(dac1r_mix)),
15211689

15221690
SND_SOC_DAPM_AIF_OUT("AIF2ADCL", NULL, 0,
1523-
WM8994_POWER_MANAGEMENT_4, 13, 0),
1691+
SND_SOC_NOPM, 13, 0),
15241692
SND_SOC_DAPM_AIF_OUT("AIF2ADCR", NULL, 0,
1525-
WM8994_POWER_MANAGEMENT_4, 12, 0),
1693+
SND_SOC_NOPM, 12, 0),
15261694
SND_SOC_DAPM_AIF_IN_E("AIF2DACL", NULL, 0,
1527-
WM8994_POWER_MANAGEMENT_5, 13, 0, wm8958_aif_ev,
1695+
SND_SOC_NOPM, 13, 0, wm8958_aif_ev,
15281696
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
15291697
SND_SOC_DAPM_AIF_IN_E("AIF2DACR", NULL, 0,
1530-
WM8994_POWER_MANAGEMENT_5, 12, 0, wm8958_aif_ev,
1698+
SND_SOC_NOPM, 12, 0, wm8958_aif_ev,
15311699
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
15321700

15331701
SND_SOC_DAPM_AIF_IN("AIF1DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),

0 commit comments

Comments
 (0)