mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
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:
parent
ec1b5ebf6d
commit
ef19ecf042
|
|
@ -953,3 +953,29 @@ void rsnd_adg_remove(struct rsnd_priv *priv)
|
|||
/* It should be called after rsnd_adg_clk_disable() */
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -2159,11 +2160,35 @@ static void rsnd_remove(struct platform_device *pdev)
|
|||
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)
|
||||
{
|
||||
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_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;
|
||||
}
|
||||
|
|
@ -2172,7 +2197,21 @@ static int rsnd_resume(struct device *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 = {
|
||||
|
|
|
|||
|
|
@ -378,3 +378,23 @@ void rsnd_ctu_remove(struct rsnd_priv *priv)
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1035,3 +1035,25 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
|
|||
/* dummy mem mod for debug */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -381,3 +381,23 @@ void rsnd_dvc_remove(struct rsnd_priv *priv)
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -345,3 +345,23 @@ void rsnd_mix_remove(struct rsnd_priv *priv)
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
|
||||
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 rsnd_mod *mod, char *x);
|
||||
|
||||
|
|
@ -429,6 +431,8 @@ int rsnd_mod_init(struct rsnd_priv *priv,
|
|||
enum rsnd_mod_type type,
|
||||
int id);
|
||||
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 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_probe(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,
|
||||
struct rsnd_dai_stream *io,
|
||||
unsigned int in_rate,
|
||||
|
|
@ -822,6 +828,8 @@ extern const char * const volume_ramp_rate[];
|
|||
*/
|
||||
int rsnd_ssi_probe(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);
|
||||
int rsnd_ssi_use_busif(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);
|
||||
int rsnd_ssiu_probe(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,
|
||||
struct device_node *playback,
|
||||
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);
|
||||
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);
|
||||
|
||||
#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);
|
||||
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);
|
||||
#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
|
||||
#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);
|
||||
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);
|
||||
#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
|
||||
#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);
|
||||
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);
|
||||
#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
|
||||
#define rsnd_parse_connect_dvc(rdai, playback, capture) \
|
||||
|
|
|
|||
|
|
@ -834,3 +834,37 @@ void rsnd_src_remove(struct rsnd_priv *priv)
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1257,3 +1257,23 @@ void rsnd_ssi_remove(struct rsnd_priv *priv)
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -629,3 +629,23 @@ void rsnd_ssiu_remove(struct rsnd_priv *priv)
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user