Skip to content

Commit ed0abc8

Browse files
John Madieubroonie
authored andcommitted
ASoC: rsnd: adg: make rsnd_adg_clk_control() idempotent
rsnd_adg_clk_control() is asymmetric on the disable path: the clkin clocks are guarded by clkin_rate[], but the "adg" clock is disabled unconditionally. If an enable attempt fails (for example a clkin failing to turn on during resume), the error path correctly rolls everything back, but rsnd_resume() ignores the return value, so the following system suspend calls rsnd_adg_clk_disable() again and underflows the "adg" clock enable count: adg_0_clks1 already disabled WARNING: drivers/clk/clk.c:1188 clk_core_disable+0xa4/0xac Call trace: clk_core_disable+0xa4/0xac (P) clk_disable+0x30/0x4c rsnd_adg_clk_control+0x9c/0x2cc rsnd_suspend+0x20/0x74 device_suspend+0x140/0x3ec dpm_suspend+0x168/0x270 Track the enable state explicitly and bail out of redundant enable/disable calls, mirroring what is already done for the per-SSI clock prepare state. A failed enable leaves the state as disabled, so the next suspend becomes a no-op and the next resume retries cleanly. Fixes: 47899d5 ("ASoC: rsnd: adg: Add per-SSI ADG and SSIF supply clock management") Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com> Acked-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Link: https://patch.msgid.link/20260610164704.2211321-1-john.madieu.xa@bp.renesas.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 95edf2d commit ed0abc8

1 file changed

Lines changed: 28 additions & 1 deletion

File tree

  • sound/soc/renesas/rcar

sound/soc/renesas/rcar/adg.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct rsnd_adg {
4545
struct rsnd_mod mod;
4646
int clkin_rate[CLKINMAX];
4747
bool ssi_clk_prepared;
48+
bool clk_enabled;
4849
int clkin_size;
4950
int clkout_size;
5051
u32 ckr;
@@ -463,6 +464,22 @@ int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
463464
struct clk *clk;
464465
int ret = 0, i;
465466

467+
/*
468+
* rsnd_adg_clk_enable() and rsnd_adg_clk_disable() can be called
469+
* redundantly, for example when system suspend follows a resume
470+
* whose enable failed. Make this function idempotent so that the
471+
* "adg" clock, which has no clkin_rate[] style guard, is never
472+
* disabled twice.
473+
*/
474+
if (enable) {
475+
if (adg->clk_enabled)
476+
return 0;
477+
} else {
478+
if (!adg->clk_enabled)
479+
return 0;
480+
adg->clk_enabled = false;
481+
}
482+
466483
if (enable) {
467484
ret = clk_prepare_enable(adg->adg);
468485
if (ret < 0)
@@ -520,12 +537,22 @@ int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
520537
* rsnd_adg_clk_enable() might return error (_disable() will not).
521538
* We need to rollback in such case
522539
*/
523-
if (ret < 0)
540+
if (ret < 0) {
541+
/*
542+
* Mark as enabled so that the rollback below is not
543+
* short-circuited by the idempotency guard. It clears
544+
* the flag again on its way through.
545+
*/
546+
adg->clk_enabled = true;
524547
rsnd_adg_clk_disable(priv);
548+
return ret;
549+
}
525550

526551
/* disable adg */
527552
if (!enable)
528553
clk_disable_unprepare(adg->adg);
554+
else
555+
adg->clk_enabled = true;
529556

530557
return ret;
531558
}

0 commit comments

Comments
 (0)