[PATCH 20/20] ASoC: mediatek: mt8196: Unwind register clock and cache restore failures
From: Pengpeng Hou <hidden>
Date: 2026-08-28 11:34:44
Also in:
linux-mediatek, linux-sound, lkml
Subsystem:
sound, sound - soc layer / dynamic audio power management (asoc), the rest · Maintainers:
Jaroslav Kysela, Takashi Iwai, Liam Girdwood, Mark Brown, Linus Torvalds
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 <redacted>
---
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