[PATCH 17/22] ASoC: rsnd: Add system suspend/resume support
From: John Madieu
Date: Thu Mar 19 2026 - 12:06:47 EST
On RZ/G3E and similar SoCs, the audio subsystem loses its state during
deep sleep, due to lacking of proper clock and reset management in the
PM path.
Implement suspend/resume callbacks that save and restore the hardware
state by managing clocks and reset controls in the correct order:
- Suspend follows reverse probe order
- Resume follows probe order
Note that module clocks (mod->clk) are left in "prepared but disabled"
state after rsnd_mod_init(), so suspend only needs to unprepare them
and resume only needs to prepare them.
Signed-off-by: John Madieu <john.madieu.xa@xxxxxxxxxxxxxx>
---
sound/soc/renesas/rcar/core.c | 108 +++++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 2 deletions(-)
diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c
index 6a25580b9c6a..eb504551e410 100644
--- a/sound/soc/renesas/rcar/core.c
+++ b/sound/soc/renesas/rcar/core.c
@@ -962,7 +962,8 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
static const struct snd_pcm_hardware rsnd_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID,
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_RESUME,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8192,
@@ -2059,11 +2060,70 @@ static void rsnd_remove(struct platform_device *pdev)
remove_func[i](priv);
}
+static void rsnd_suspend_mod(struct rsnd_mod *mod)
+{
+ if (!mod)
+ return;
+
+ clk_unprepare(mod->clk);
+ reset_control_assert(mod->rstc);
+}
+
+static void rsnd_resume_mod(struct rsnd_mod *mod)
+{
+ if (!mod)
+ return;
+
+ reset_control_deassert(mod->rstc);
+ clk_prepare(mod->clk);
+}
+
static int rsnd_suspend(struct device *dev)
{
struct rsnd_priv *priv = dev_get_drvdata(dev);
+ int i;
+
+ /*
+ * Reverse order of probe:
+ * ADG -> DVC -> MIX -> CTU -> SRC -> SSIU -> SSI -> DMA
+ */
+ /* ADG */
+ /* ADG clock disabled via rsnd_adg_clk_disable() -> adg->adg */
rsnd_adg_clk_disable(priv);
+ rsnd_suspend_mod(rsnd_adg_mod_get(priv));
+
+ /* DVC */
+ for (i = priv->dvc_nr - 1; i >= 0; i--)
+ rsnd_suspend_mod(rsnd_dvc_mod_get(priv, i));
+
+ /* MIX */
+ for (i = priv->mix_nr - 1; i >= 0; i--)
+ rsnd_suspend_mod(rsnd_mix_mod_get(priv, i));
+
+ /* CTU */
+ for (i = priv->ctu_nr - 1; i >= 0; i--)
+ rsnd_suspend_mod(rsnd_ctu_mod_get(priv, i));
+
+ /* SRC */
+ for (i = priv->src_nr - 1; i >= 0; i--)
+ rsnd_suspend_mod(rsnd_src_mod_get(priv, i));
+
+ clk_disable_unprepare(priv->clk_scu_x2);
+ clk_disable_unprepare(priv->clk_scu);
+
+ /* SSIU */
+ for (i = priv->ssiu_nr - 1; i >= 0; i--)
+ rsnd_suspend_mod(rsnd_ssiu_mod_get(priv, i));
+
+ /* SSI */
+ for (i = priv->ssi_nr - 1; i >= 0; i--)
+ rsnd_suspend_mod(rsnd_ssi_mod_get(priv, i));
+
+ /* DMA */
+ clk_disable_unprepare(priv->clk_audmac_pp);
+ if (priv->rstc_audmac_pp)
+ reset_control_assert(priv->rstc_audmac_pp);
return 0;
}
@@ -2071,8 +2131,52 @@ static int rsnd_suspend(struct device *dev)
static int rsnd_resume(struct device *dev)
{
struct rsnd_priv *priv = dev_get_drvdata(dev);
+ int i;
+
+ /*
+ * Same order as probe:
+ * DMA -> SSI -> SSIU -> SRC -> CTU -> MIX -> DVC -> ADG
+ */
+
+ /* DMA */
+ if (priv->rstc_audmac_pp)
+ reset_control_deassert(priv->rstc_audmac_pp);
- return rsnd_adg_clk_enable(priv);
+ clk_prepare_enable(priv->clk_audmac_pp);
+
+ /* SSI */
+ for (i = 0; i < priv->ssi_nr; i++)
+ rsnd_resume_mod(rsnd_ssi_mod_get(priv, i));
+
+ /* SSIU */
+ for (i = 0; i < priv->ssiu_nr; i++)
+ rsnd_resume_mod(rsnd_ssiu_mod_get(priv, i));
+
+ /* SRC */
+ clk_prepare_enable(priv->clk_scu);
+ clk_prepare_enable(priv->clk_scu_x2);
+
+ for (i = 0; i < priv->src_nr; i++)
+ rsnd_resume_mod(rsnd_src_mod_get(priv, i));
+
+ /* CTU */
+ for (i = 0; i < priv->ctu_nr; i++)
+ rsnd_resume_mod(rsnd_ctu_mod_get(priv, i));
+
+ /* MIX */
+ for (i = 0; i < priv->mix_nr; i++)
+ rsnd_resume_mod(rsnd_mix_mod_get(priv, i));
+
+ /* DVC */
+ for (i = 0; i < priv->dvc_nr; i++)
+ rsnd_resume_mod(rsnd_dvc_mod_get(priv, i));
+
+ /* ADG */
+ rsnd_resume_mod(rsnd_adg_mod_get(priv));
+ /* ADG clock enabled via rsnd_adg_clk_enable() -> adg->adg */
+ rsnd_adg_clk_enable(priv);
+
+ return 0;
}
static const struct dev_pm_ops rsnd_pm_ops = {
--
2.25.1