Re: [PATCH 17/22] ASoC: rsnd: Add system suspend/resume support
From: Kuninori Morimoto
Date: Sun Mar 22 2026 - 21:57:52 EST
Hi John
> 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>
> ---
If my memory was correct, besically, all mods (SSI, SCU, etc) will be
called with SNDRV_PCM_TRIGGER_SUSPEND/RESUME when suspend/resume.
So they are basically automatically stopped when suspend,
and automatically started when resume. see rsnd_soc_dai_trigger()
We need to care about ADG when suspend/resume because it is always ON
device. At least on R-Car.
If you need special handling for RZ, you need to care whether it is
R-Car or RZ, etc.
> 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
>