Hi Geert Thank you for reporting > ------------[ cut here ]------------ > clk_multiplier already disabled (snip) > ------------[ cut here ]------------ > clk_multiplier already unprepared (snip) > Unfortunately I cannot reproduce it at will. > The above is from today's renesas-devel release, but my logs indicate > it happens every few months since at least v6.1. > So far I have seen it on all Salvator-X(S) variants, but not on any other > SoCs or boards. Hmm... I'm not sure why, but according to the log, it seems it calls clk_disable_unprepare() without calling clk_prepare_enable(). I think "clk_multiplier" means "cs2000" on Salvator-X(S). Basically, I don't think it can be happen. But current rsnd driver doesn't check return value of clk_prepare_enable(). So if cs2000 failed clk_enable() for some reasons, indeed clk_disable_unprepare() might be called without enabled (It is another issue, though...) I'm not tesed, but can this patch improve situation ? If above assumption was correct, the clk WARNING issue itself can be solved, but sound driver itself will fail to probe... ------------------ From: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> Date: Tue, 17 Dec 2024 11:30:46 +0900 Subject: [PATCH] ASoC: rsnd: check rsnd_adg_clk_enable() return value rsnd_adg_clk_enable() might be failed for some reasons. In such case, we will get WARNING from clk.c when suspend was used that it try to disable clk without enabled. Check rsnd_adg_clk_enable() return value. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> --- sound/soc/renesas/rcar/adg.c | 30 ++++++++++++++++++++++++------ sound/soc/renesas/rcar/core.c | 4 +--- sound/soc/renesas/rcar/rsnd.h | 2 +- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/sound/soc/renesas/rcar/adg.c b/sound/soc/renesas/rcar/adg.c index 0f190abf00e75..723dcc88af306 100644 --- a/sound/soc/renesas/rcar/adg.c +++ b/sound/soc/renesas/rcar/adg.c @@ -374,12 +374,12 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) return 0; } -void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) +int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; - int i; + int ret = 0, i; if (enable) { rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr); @@ -389,18 +389,33 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) for_each_rsnd_clkin(clk, adg, i) { if (enable) { - clk_prepare_enable(clk); + ret = clk_prepare_enable(clk); /* * We shouldn't use clk_get_rate() under * atomic context. Let's keep it when * rsnd_adg_clk_enable() was called */ - adg->clkin_rate[i] = clk_get_rate(clk); + if (ret < 0) + break; + else + adg->clkin_rate[i] = clk_get_rate(clk); } else { - clk_disable_unprepare(clk); + if (adg->clkin_rate[i]) + clk_disable_unprepare(clk); + + adg->clkin_rate[i] = 0; } } + + /* + * rsnd_adg_clk_enable() might return error (_disable() will not). + * We need to rollback in such case + */ + if (ret < 0) + rsnd_adg_clk_disable(priv); + + return ret; } static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv, @@ -753,7 +768,10 @@ int rsnd_adg_probe(struct rsnd_priv *priv) if (ret) return ret; - rsnd_adg_clk_enable(priv); + ret = rsnd_adg_clk_enable(priv); + if (ret) + return ret; + rsnd_adg_clk_dbg_info(priv, NULL); return 0; diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c index e2234928c9e88..d3709fd0409e4 100644 --- a/sound/soc/renesas/rcar/core.c +++ b/sound/soc/renesas/rcar/core.c @@ -2086,9 +2086,7 @@ static int __maybe_unused rsnd_resume(struct device *dev) { struct rsnd_priv *priv = dev_get_drvdata(dev); - rsnd_adg_clk_enable(priv); - - return 0; + return rsnd_adg_clk_enable(priv); } static const struct dev_pm_ops rsnd_pm_ops = { diff --git a/sound/soc/renesas/rcar/rsnd.h b/sound/soc/renesas/rcar/rsnd.h index 3c164d8e3b16b..a5f54b65313c4 100644 --- a/sound/soc/renesas/rcar/rsnd.h +++ b/sound/soc/renesas/rcar/rsnd.h @@ -608,7 +608,7 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, struct rsnd_dai_stream *io); #define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) #define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) -void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable); +int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable); void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m); /* -- 2.43.0 Thank you for your help !! Best regards --- Kuninori Morimoto