[PATCH] ASoC: sunxi: sun50i-dmic: resume device for control access

Jiale Yao yaojiale02 at 163.com
Tue Oct 27 22:06:26 PDT 2026


The capture volume controls use regmap directly while runtime PM may
have suspended the DMIC and disabled its clocks. Since the regmap has no
cache, reading or writing a control while suspended accesses unpowered
hardware.

Use control callbacks which resume the device around the regmap access
and release the runtime PM reference afterwards.

Fixes: 9a8cadddd930 ("ASoC: sunxi: DMIC: Add controls for adjusting the mic gains")
Cc: stable at vger.kernel.org
Signed-off-by: Jiale Yao <yaojiale02 at 163.com>
---
 sound/soc/sunxi/sun50i-dmic.c | 59 +++++++++++++++++++++++++++--------
 1 file changed, 46 insertions(+), 13 deletions(-)

diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c
index 5c784b1f6846..a5f70db856b9 100644
--- a/sound/soc/sunxi/sun50i-dmic.c
+++ b/sound/soc/sunxi/sun50i-dmic.c
@@ -286,22 +286,55 @@ MODULE_DEVICE_TABLE(of, sun50i_dmic_of_match);
 
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(sun50i_dmic_vol_scale, -12000, 75, 1);
 
-static const struct snd_kcontrol_new sun50i_dmic_controls[] = {
+static int sun50i_dmic_get_volsw(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	int ret;
 
-        SOC_DOUBLE_TLV("DMIC Channel 0 Capture Volume", SUN50I_DMIC_D0D1_VOL_CTR,
-                       SUN50I_DMIC_D0D1_VOL_CTR_0L, SUN50I_DMIC_D0D1_VOL_CTR_0R,
-                       0xFF, 0, sun50i_dmic_vol_scale),
-        SOC_DOUBLE_TLV("DMIC Channel 1 Capture Volume", SUN50I_DMIC_D0D1_VOL_CTR,
-                       SUN50I_DMIC_D0D1_VOL_CTR_1L, SUN50I_DMIC_D0D1_VOL_CTR_1R,
-                       0xFF, 0, sun50i_dmic_vol_scale),
-        SOC_DOUBLE_TLV("DMIC Channel 2 Capture Volume", SUN50I_DMIC_D2D3_VOL_CTR,
-                       SUN50I_DMIC_D2D3_VOL_CTR_2L, SUN50I_DMIC_D2D3_VOL_CTR_2R,
-                       0xFF, 0, sun50i_dmic_vol_scale),
-        SOC_DOUBLE_TLV("DMIC Channel 3 Capture Volume", SUN50I_DMIC_D2D3_VOL_CTR,
-                       SUN50I_DMIC_D2D3_VOL_CTR_3L, SUN50I_DMIC_D2D3_VOL_CTR_3R,
-                       0xFF, 0, sun50i_dmic_vol_scale),
+	ret = pm_runtime_resume_and_get(component->dev);
+	if (ret < 0)
+		return ret;
 
+	ret = snd_soc_get_volsw(kcontrol, ucontrol);
+	pm_runtime_put(component->dev);
 
+	return ret;
+}
+
+static int sun50i_dmic_put_volsw(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	int ret;
+
+	ret = pm_runtime_resume_and_get(component->dev);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	pm_runtime_put(component->dev);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new sun50i_dmic_controls[] = {
+	SOC_DOUBLE_EXT_TLV("DMIC Channel 0 Capture Volume", SUN50I_DMIC_D0D1_VOL_CTR,
+			   SUN50I_DMIC_D0D1_VOL_CTR_0L, SUN50I_DMIC_D0D1_VOL_CTR_0R,
+			   0xFF, 0, sun50i_dmic_get_volsw, sun50i_dmic_put_volsw,
+			   sun50i_dmic_vol_scale),
+	SOC_DOUBLE_EXT_TLV("DMIC Channel 1 Capture Volume", SUN50I_DMIC_D0D1_VOL_CTR,
+			   SUN50I_DMIC_D0D1_VOL_CTR_1L, SUN50I_DMIC_D0D1_VOL_CTR_1R,
+			   0xFF, 0, sun50i_dmic_get_volsw, sun50i_dmic_put_volsw,
+			   sun50i_dmic_vol_scale),
+	SOC_DOUBLE_EXT_TLV("DMIC Channel 2 Capture Volume", SUN50I_DMIC_D2D3_VOL_CTR,
+			   SUN50I_DMIC_D2D3_VOL_CTR_2L, SUN50I_DMIC_D2D3_VOL_CTR_2R,
+			   0xFF, 0, sun50i_dmic_get_volsw, sun50i_dmic_put_volsw,
+			   sun50i_dmic_vol_scale),
+	SOC_DOUBLE_EXT_TLV("DMIC Channel 3 Capture Volume", SUN50I_DMIC_D2D3_VOL_CTR,
+			   SUN50I_DMIC_D2D3_VOL_CTR_3L, SUN50I_DMIC_D2D3_VOL_CTR_3R,
+			   0xFF, 0, sun50i_dmic_get_volsw, sun50i_dmic_put_volsw,
+			   sun50i_dmic_vol_scale),
 };
 
 static const struct snd_soc_component_driver sun50i_dmic_component = {
-- 
2.34.1




More information about the linux-arm-kernel mailing list