Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: tas2770: Fix handling of mute/unmute

Because the PWR_CTRL field is modeled as the power state of the DAC
widget, and at the same time it is used to implement mute/unmute, we
need some additional book-keeping to have the right end result no matter
the sequence of calls. Without this fix, one can mute an ongoing stream
by toggling a speaker pin control.

Fixes: 1a476abc723e ("tas2770: add tas2770 smart PA kernel driver")
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Link: https://lore.kernel.org/r/20220808141246.5749-5-povik+lin@cutebit.org
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Martin Povišer and committed by
Mark Brown
1e5907bc 482c23fb

+32 -27
+30 -27
sound/soc/codecs/tas2770.c
··· 46 46 usleep_range(1000, 2000); 47 47 } 48 48 49 + static int tas2770_update_pwr_ctrl(struct tas2770_priv *tas2770) 50 + { 51 + struct snd_soc_component *component = tas2770->component; 52 + unsigned int val; 53 + int ret; 54 + 55 + if (tas2770->dac_powered) 56 + val = tas2770->unmuted ? 57 + TAS2770_PWR_CTRL_ACTIVE : TAS2770_PWR_CTRL_MUTE; 58 + else 59 + val = TAS2770_PWR_CTRL_SHUTDOWN; 60 + 61 + ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, 62 + TAS2770_PWR_CTRL_MASK, val); 63 + if (ret < 0) 64 + return ret; 65 + 66 + return 0; 67 + } 68 + 49 69 #ifdef CONFIG_PM 50 70 static int tas2770_codec_suspend(struct snd_soc_component *component) 51 71 { ··· 102 82 gpiod_set_value_cansleep(tas2770->sdz_gpio, 1); 103 83 usleep_range(1000, 2000); 104 84 } else { 105 - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, 106 - TAS2770_PWR_CTRL_MASK, 107 - TAS2770_PWR_CTRL_ACTIVE); 85 + ret = tas2770_update_pwr_ctrl(tas2770); 108 86 if (ret < 0) 109 87 return ret; 110 88 } ··· 138 120 139 121 switch (event) { 140 122 case SND_SOC_DAPM_POST_PMU: 141 - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, 142 - TAS2770_PWR_CTRL_MASK, 143 - TAS2770_PWR_CTRL_MUTE); 123 + tas2770->dac_powered = 1; 124 + ret = tas2770_update_pwr_ctrl(tas2770); 144 125 break; 145 126 case SND_SOC_DAPM_PRE_PMD: 146 - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, 147 - TAS2770_PWR_CTRL_MASK, 148 - TAS2770_PWR_CTRL_SHUTDOWN); 127 + tas2770->dac_powered = 0; 128 + ret = tas2770_update_pwr_ctrl(tas2770); 149 129 break; 150 130 default: 151 131 dev_err(tas2770->dev, "Not supported evevt\n"); 152 132 return -EINVAL; 153 133 } 154 134 155 - if (ret < 0) 156 - return ret; 157 - 158 - return 0; 135 + return ret; 159 136 } 160 137 161 138 static const struct snd_kcontrol_new isense_switch = ··· 184 171 static int tas2770_mute(struct snd_soc_dai *dai, int mute, int direction) 185 172 { 186 173 struct snd_soc_component *component = dai->component; 187 - int ret; 174 + struct tas2770_priv *tas2770 = 175 + snd_soc_component_get_drvdata(component); 188 176 189 - if (mute) 190 - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, 191 - TAS2770_PWR_CTRL_MASK, 192 - TAS2770_PWR_CTRL_MUTE); 193 - else 194 - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, 195 - TAS2770_PWR_CTRL_MASK, 196 - TAS2770_PWR_CTRL_ACTIVE); 197 - 198 - if (ret < 0) 199 - return ret; 200 - 201 - return 0; 177 + tas2770->unmuted = !mute; 178 + return tas2770_update_pwr_ctrl(tas2770); 202 179 } 203 180 204 181 static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)
+2
sound/soc/codecs/tas2770.h
··· 138 138 struct device *dev; 139 139 int v_sense_slot; 140 140 int i_sense_slot; 141 + bool dac_powered; 142 + bool unmuted; 141 143 }; 142 144 143 145 #endif /* __TAS2770__ */