ASoC: rsnd: Add system suspend/resume support

Add system suspend/resume support for the ASoC rsnd driver, required
for RZ/G3E platforms. Distribute the per-module suspend/resume work
across the relevant files (adg.c, ssi.c, ssiu.c, src.c, ctu.c, mix.c,
dvc.c, dma.c) rather than centralising it in core.c.

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/20260525110230.4014435-19-john.madieu.xa@bp.renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
John Madieu 2026-05-25 11:02:30 +00:00 committed by Mark Brown
parent ec1b5ebf6d
commit ef19ecf042
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
10 changed files with 241 additions and 2 deletions

View File

@ -953,3 +953,29 @@ void rsnd_adg_remove(struct rsnd_priv *priv)
/* It should be called after rsnd_adg_clk_disable() */ /* It should be called after rsnd_adg_clk_disable() */
rsnd_adg_null_clk_clean(priv); rsnd_adg_null_clk_clean(priv);
} }
static struct rsnd_mod *rsnd_adg_mod_get(struct rsnd_priv *priv)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
if (!adg)
return NULL;
return rsnd_mod_get(adg);
}
void rsnd_adg_suspend(struct rsnd_priv *priv)
{
struct rsnd_mod *mod = rsnd_adg_mod_get(priv);
if (mod)
rsnd_suspend_clk_reset(mod->clk, mod->rstc);
}
void rsnd_adg_resume(struct rsnd_priv *priv)
{
struct rsnd_mod *mod = rsnd_adg_mod_get(priv);
if (mod)
rsnd_resume_clk_reset(mod->clk, mod->rstc);
}

View File

@ -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 = { static const struct snd_pcm_hardware rsnd_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED | .info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID, SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME,
.buffer_bytes_max = 64 * 1024, .buffer_bytes_max = 64 * 1024,
.period_bytes_min = 32, .period_bytes_min = 32,
.period_bytes_max = 8192, .period_bytes_max = 8192,
@ -2159,11 +2160,35 @@ static void rsnd_remove(struct platform_device *pdev)
remove_func[i](priv); remove_func[i](priv);
} }
void rsnd_suspend_clk_reset(struct clk *clk, struct reset_control *rstc)
{
clk_unprepare(clk);
reset_control_assert(rstc);
}
void rsnd_resume_clk_reset(struct clk *clk, struct reset_control *rstc)
{
reset_control_deassert(rstc);
clk_prepare(clk);
}
static int rsnd_suspend(struct device *dev) static int rsnd_suspend(struct device *dev)
{ {
struct rsnd_priv *priv = dev_get_drvdata(dev); struct rsnd_priv *priv = dev_get_drvdata(dev);
/*
* Reverse order of probe:
* ADG -> DVC -> MIX -> CTU -> SRC -> SSIU -> SSI -> DMA
*/
rsnd_adg_clk_disable(priv); rsnd_adg_clk_disable(priv);
rsnd_adg_suspend(priv);
rsnd_dvc_suspend(priv);
rsnd_mix_suspend(priv);
rsnd_ctu_suspend(priv);
rsnd_src_suspend(priv);
rsnd_ssiu_suspend(priv);
rsnd_ssi_suspend(priv);
rsnd_dma_suspend(priv);
return 0; return 0;
} }
@ -2172,7 +2197,21 @@ static int rsnd_resume(struct device *dev)
{ {
struct rsnd_priv *priv = dev_get_drvdata(dev); struct rsnd_priv *priv = dev_get_drvdata(dev);
return rsnd_adg_clk_enable(priv); /*
* Same order as probe:
* DMA -> SSI -> SSIU -> SRC -> CTU -> MIX -> DVC -> ADG
*/
rsnd_dma_resume(priv);
rsnd_ssi_resume(priv);
rsnd_ssiu_resume(priv);
rsnd_src_resume(priv);
rsnd_ctu_resume(priv);
rsnd_mix_resume(priv);
rsnd_dvc_resume(priv);
rsnd_adg_resume(priv);
rsnd_adg_clk_enable(priv);
return 0;
} }
static const struct dev_pm_ops rsnd_pm_ops = { static const struct dev_pm_ops rsnd_pm_ops = {

View File

@ -378,3 +378,23 @@ void rsnd_ctu_remove(struct rsnd_priv *priv)
rsnd_mod_quit(rsnd_mod_get(ctu)); rsnd_mod_quit(rsnd_mod_get(ctu));
} }
} }
void rsnd_ctu_suspend(struct rsnd_priv *priv)
{
struct rsnd_ctu *ctu;
int i;
for_each_rsnd_ctu(ctu, priv, i)
rsnd_suspend_clk_reset(rsnd_mod_get(ctu)->clk,
rsnd_mod_get(ctu)->rstc);
}
void rsnd_ctu_resume(struct rsnd_priv *priv)
{
struct rsnd_ctu *ctu;
int i;
for_each_rsnd_ctu(ctu, priv, i)
rsnd_resume_clk_reset(rsnd_mod_get(ctu)->clk,
rsnd_mod_get(ctu)->rstc);
}

View File

@ -1035,3 +1035,25 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
/* dummy mem mod for debug */ /* dummy mem mod for debug */
return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0); return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0);
} }
void rsnd_dma_suspend(struct rsnd_priv *priv)
{
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
if (dmac) {
/* Mirror probe (which enables clk before deasserting reset) */
rsnd_suspend_clk_reset(NULL, dmac->audmapp_rstc);
clk_disable_unprepare(dmac->audmapp_clk);
}
}
void rsnd_dma_resume(struct rsnd_priv *priv)
{
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
if (dmac) {
/* Clock must be stable before reset is deasserted */
clk_prepare_enable(dmac->audmapp_clk);
rsnd_resume_clk_reset(NULL, dmac->audmapp_rstc);
}
}

View File

@ -381,3 +381,23 @@ void rsnd_dvc_remove(struct rsnd_priv *priv)
rsnd_mod_quit(rsnd_mod_get(dvc)); rsnd_mod_quit(rsnd_mod_get(dvc));
} }
} }
void rsnd_dvc_suspend(struct rsnd_priv *priv)
{
struct rsnd_dvc *dvc;
int i;
for_each_rsnd_dvc(dvc, priv, i)
rsnd_suspend_clk_reset(rsnd_mod_get(dvc)->clk,
rsnd_mod_get(dvc)->rstc);
}
void rsnd_dvc_resume(struct rsnd_priv *priv)
{
struct rsnd_dvc *dvc;
int i;
for_each_rsnd_dvc(dvc, priv, i)
rsnd_resume_clk_reset(rsnd_mod_get(dvc)->clk,
rsnd_mod_get(dvc)->rstc);
}

View File

@ -345,3 +345,23 @@ void rsnd_mix_remove(struct rsnd_priv *priv)
rsnd_mod_quit(rsnd_mod_get(mix)); rsnd_mod_quit(rsnd_mod_get(mix));
} }
} }
void rsnd_mix_suspend(struct rsnd_priv *priv)
{
struct rsnd_mix *mix;
int i;
for_each_rsnd_mix(mix, priv, i)
rsnd_suspend_clk_reset(rsnd_mod_get(mix)->clk,
rsnd_mod_get(mix)->rstc);
}
void rsnd_mix_resume(struct rsnd_priv *priv)
{
struct rsnd_mix *mix;
int i;
for_each_rsnd_mix(mix, priv, i)
rsnd_resume_clk_reset(rsnd_mod_get(mix)->clk,
rsnd_mod_get(mix)->rstc);
}

View File

@ -267,6 +267,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
int rsnd_dma_attach(struct rsnd_dai_stream *io, int rsnd_dma_attach(struct rsnd_dai_stream *io,
struct rsnd_mod *mod, struct rsnd_mod **dma_mod); struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
int rsnd_dma_probe(struct rsnd_priv *priv); int rsnd_dma_probe(struct rsnd_priv *priv);
void rsnd_dma_suspend(struct rsnd_priv *priv);
void rsnd_dma_resume(struct rsnd_priv *priv);
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
struct rsnd_mod *mod, char *x); struct rsnd_mod *mod, char *x);
@ -429,6 +431,8 @@ int rsnd_mod_init(struct rsnd_priv *priv,
enum rsnd_mod_type type, enum rsnd_mod_type type,
int id); int id);
void rsnd_mod_quit(struct rsnd_mod *mod); void rsnd_mod_quit(struct rsnd_mod *mod);
void rsnd_suspend_clk_reset(struct clk *clk, struct reset_control *rstc);
void rsnd_resume_clk_reset(struct clk *clk, struct reset_control *rstc);
struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
struct rsnd_mod *mod); struct rsnd_mod *mod);
void rsnd_mod_interrupt(struct rsnd_mod *mod, void rsnd_mod_interrupt(struct rsnd_mod *mod,
@ -625,6 +629,8 @@ int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod);
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate); int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate);
int rsnd_adg_probe(struct rsnd_priv *priv); int rsnd_adg_probe(struct rsnd_priv *priv);
void rsnd_adg_remove(struct rsnd_priv *priv); void rsnd_adg_remove(struct rsnd_priv *priv);
void rsnd_adg_suspend(struct rsnd_priv *priv);
void rsnd_adg_resume(struct rsnd_priv *priv);
int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
unsigned int in_rate, unsigned int in_rate,
@ -822,6 +828,8 @@ extern const char * const volume_ramp_rate[];
*/ */
int rsnd_ssi_probe(struct rsnd_priv *priv); int rsnd_ssi_probe(struct rsnd_priv *priv);
void rsnd_ssi_remove(struct rsnd_priv *priv); void rsnd_ssi_remove(struct rsnd_priv *priv);
void rsnd_ssi_suspend(struct rsnd_priv *priv);
void rsnd_ssi_resume(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io); u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io);
@ -845,6 +853,8 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
struct rsnd_mod *mod); struct rsnd_mod *mod);
int rsnd_ssiu_probe(struct rsnd_priv *priv); int rsnd_ssiu_probe(struct rsnd_priv *priv);
void rsnd_ssiu_remove(struct rsnd_priv *priv); void rsnd_ssiu_remove(struct rsnd_priv *priv);
void rsnd_ssiu_suspend(struct rsnd_priv *priv);
void rsnd_ssiu_resume(struct rsnd_priv *priv);
void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
struct device_node *playback, struct device_node *playback,
struct device_node *capture); struct device_node *capture);
@ -856,6 +866,8 @@ bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod);
*/ */
int rsnd_src_probe(struct rsnd_priv *priv); int rsnd_src_probe(struct rsnd_priv *priv);
void rsnd_src_remove(struct rsnd_priv *priv); void rsnd_src_remove(struct rsnd_priv *priv);
void rsnd_src_suspend(struct rsnd_priv *priv);
void rsnd_src_resume(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1) #define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1)
@ -875,6 +887,8 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
*/ */
int rsnd_ctu_probe(struct rsnd_priv *priv); int rsnd_ctu_probe(struct rsnd_priv *priv);
void rsnd_ctu_remove(struct rsnd_priv *priv); void rsnd_ctu_remove(struct rsnd_priv *priv);
void rsnd_ctu_suspend(struct rsnd_priv *priv);
void rsnd_ctu_resume(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) #define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
#define rsnd_parse_connect_ctu(rdai, playback, capture) \ #define rsnd_parse_connect_ctu(rdai, playback, capture) \
@ -887,6 +901,8 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
*/ */
int rsnd_mix_probe(struct rsnd_priv *priv); int rsnd_mix_probe(struct rsnd_priv *priv);
void rsnd_mix_remove(struct rsnd_priv *priv); void rsnd_mix_remove(struct rsnd_priv *priv);
void rsnd_mix_suspend(struct rsnd_priv *priv);
void rsnd_mix_resume(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX) #define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
#define rsnd_parse_connect_mix(rdai, playback, capture) \ #define rsnd_parse_connect_mix(rdai, playback, capture) \
@ -899,6 +915,8 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
*/ */
int rsnd_dvc_probe(struct rsnd_priv *priv); int rsnd_dvc_probe(struct rsnd_priv *priv);
void rsnd_dvc_remove(struct rsnd_priv *priv); void rsnd_dvc_remove(struct rsnd_priv *priv);
void rsnd_dvc_suspend(struct rsnd_priv *priv);
void rsnd_dvc_resume(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC) #define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
#define rsnd_parse_connect_dvc(rdai, playback, capture) \ #define rsnd_parse_connect_dvc(rdai, playback, capture) \

View File

@ -834,3 +834,37 @@ void rsnd_src_remove(struct rsnd_priv *priv)
rsnd_mod_quit(rsnd_mod_get(src)); rsnd_mod_quit(rsnd_mod_get(src));
} }
} }
void rsnd_src_suspend(struct rsnd_priv *priv)
{
struct rsnd_src_ctrl *src_ctrl = rsnd_priv_to_src_ctrl(priv);
struct rsnd_src *src;
int i;
if (!src_ctrl)
return;
for_each_rsnd_src(src, priv, i)
rsnd_suspend_clk_reset(rsnd_mod_get(src)->clk,
rsnd_mod_get(src)->rstc);
clk_disable_unprepare(src_ctrl->scu_x2);
clk_disable_unprepare(src_ctrl->scu);
}
void rsnd_src_resume(struct rsnd_priv *priv)
{
struct rsnd_src_ctrl *src_ctrl = rsnd_priv_to_src_ctrl(priv);
struct rsnd_src *src;
int i;
if (!src_ctrl)
return;
clk_prepare_enable(src_ctrl->scu);
clk_prepare_enable(src_ctrl->scu_x2);
for_each_rsnd_src(src, priv, i)
rsnd_resume_clk_reset(rsnd_mod_get(src)->clk,
rsnd_mod_get(src)->rstc);
}

View File

@ -1257,3 +1257,23 @@ void rsnd_ssi_remove(struct rsnd_priv *priv)
rsnd_mod_quit(rsnd_mod_get(ssi)); rsnd_mod_quit(rsnd_mod_get(ssi));
} }
} }
void rsnd_ssi_suspend(struct rsnd_priv *priv)
{
struct rsnd_ssi *ssi;
int i;
for_each_rsnd_ssi(ssi, priv, i)
rsnd_suspend_clk_reset(rsnd_mod_get(ssi)->clk,
rsnd_mod_get(ssi)->rstc);
}
void rsnd_ssi_resume(struct rsnd_priv *priv)
{
struct rsnd_ssi *ssi;
int i;
for_each_rsnd_ssi(ssi, priv, i)
rsnd_resume_clk_reset(rsnd_mod_get(ssi)->clk,
rsnd_mod_get(ssi)->rstc);
}

View File

@ -629,3 +629,23 @@ void rsnd_ssiu_remove(struct rsnd_priv *priv)
rsnd_mod_quit(rsnd_mod_get(ssiu)); rsnd_mod_quit(rsnd_mod_get(ssiu));
} }
} }
void rsnd_ssiu_suspend(struct rsnd_priv *priv)
{
struct rsnd_ssiu *ssiu;
int i;
for_each_rsnd_ssiu(ssiu, priv, i)
rsnd_suspend_clk_reset(rsnd_mod_get(ssiu)->clk,
rsnd_mod_get(ssiu)->rstc);
}
void rsnd_ssiu_resume(struct rsnd_priv *priv)
{
struct rsnd_ssiu *ssiu;
int i;
for_each_rsnd_ssiu(ssiu, priv, i)
rsnd_resume_clk_reset(rsnd_mod_get(ssiu)->clk,
rsnd_mod_get(ssiu)->rstc);
}