[PATCH 20/20] ASoC: mediatek: mt8196: Unwind register clock and cache restore failures
From: Pengpeng Hou
Date: Fri Aug 28 2026 - 07:39:59 EST
mt8196_afe_runtime_resume() first acquires three register-access clocks
and then replays the register cache. mt8196_afe_enable_reg_rw_clk()
ignores each clock-enable result and leaks already enabled clocks when a
later rate change fails. Runtime resume also ignores regcache_sync()
and proceeds with 26 MHz requests and main-clock enable.
Make the register-clock helper acquire transactionally and unwind the
successful prefix on every failure. Return cache replay errors after
restoring cache-only and dirty state and disabling the three
register-access clocks.
The issue was identified via static analysis and manually reviewed.
Fixes: 7384ecab34eb ("ASoC: mediatek: mt8196: support audio clock control")
Fixes: 57513aabfe5b ("ASoC: mediatek: mt8196: add platform driver")
Assisted-by: LLM
Signed-off-by: Pengpeng Hou <pengpeng@xxxxxxxxxxx>
---
sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 27 ++++++++++++++++++----
sound/soc/mediatek/mt8196/mt8196-afe-pcm.c | 8 ++++++-
2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
index 286e39f53ae0..ea0835e73510 100644
--- a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
@@ -511,26 +511,43 @@ int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
int ret;
/* bus clock for AFE external access, like DRAM */
- mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
+ if (ret)
+ return ret;
/* bus clock for AFE internal access, like AFE SRAM */
- mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
+ ret = mt8196_afe_enable_clk(afe,
+ afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
+ if (ret)
+ goto disable_adsp;
+
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
MT8196_AFE_26M);
if (ret)
- return ret;
+ goto disable_intbus;
/* enable audio h clock */
- mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ if (ret)
+ goto disable_intbus;
+
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
MT8196_AFE_26M);
if (ret)
- return ret;
+ goto disable_audio_h;
/* AFE hw clock */
/* IPM2.0: USE HOPPING & 26M */
/* set in the regmap_register_patch */
return 0;
+
+disable_audio_h:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+disable_intbus:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
+disable_adsp:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
+ return ret;
}
int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
index a1ae8322d8b6..49283f242c00 100644
--- a/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
@@ -2222,7 +2222,13 @@ static int mt8196_afe_runtime_resume(struct device *dev)
goto skip_regmap;
}
regcache_cache_only(afe->regmap, false);
- regcache_sync(afe->regmap);
+ ret = regcache_sync(afe->regmap);
+ if (ret) {
+ regcache_cache_only(afe->regmap, true);
+ regcache_mark_dirty(afe->regmap);
+ mt8196_afe_disable_reg_rw_clk(afe);
+ return ret;
+ }
/* set audio 26M request */
regmap_update_bits(afe->regmap, AFE_SPM_CONTROL_REQ, 0x1, 0x1);
--
2.43.0