]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ASoC: tas2770: Power cycle amp on ISENSE/VSENSE change
authorHector Martin <marcan@marcan.st>
Sat, 5 Apr 2025 23:15:05 +0000 (09:15 +1000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Jun 2025 10:04:15 +0000 (11:04 +0100)
[ Upstream commit f529c91be8a34ac12e7599bf87c65b6f4a2c9f5c ]

The ISENSE/VSENSE blocks are only powered up when the amplifier
transitions from shutdown to active. This means that if those controls
are flipped on while the amplifier is already playing back audio, they
will have no effect.

Fix this by forcing a power cycle around transitions in those controls.

Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Link: https://patch.msgid.link/20250406-apple-codec-changes-v5-1-50a00ec850a3@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
sound/soc/codecs/tas2770.c

index 1928c1616a52dc26f1fb6cb3c9a68b215e00fc99..629cc24d51c3d8908fcdead4bbdc940858531130 100644 (file)
@@ -158,11 +158,37 @@ static const struct snd_kcontrol_new isense_switch =
 static const struct snd_kcontrol_new vsense_switch =
        SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1);
 
+static int sense_event(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);
+
+       /*
+        * Powering up ISENSE/VSENSE requires a trip through the shutdown state.
+        * Do that here to ensure that our changes are applied properly, otherwise
+        * we might end up with non-functional IVSENSE if playback started earlier,
+        * which would break software speaker protection.
+        */
+       switch (event) {
+       case SND_SOC_DAPM_PRE_REG:
+               return snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
+                                                   TAS2770_PWR_CTRL_MASK,
+                                                   TAS2770_PWR_CTRL_SHUTDOWN);
+       case SND_SOC_DAPM_POST_REG:
+               return tas2770_update_pwr_ctrl(tas2770);
+       default:
+               return 0;
+       }
+}
+
 static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
        SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2770_asi1_mux),
-       SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch),
-       SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch),
+       SND_SOC_DAPM_SWITCH_E("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch,
+               sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG),
+       SND_SOC_DAPM_SWITCH_E("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch,
+               sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG),
        SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event,
                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
        SND_SOC_DAPM_OUTPUT("OUT"),