From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current rsnd driver enables ADG clock when .probe timing, but it breaks sound after Suspend/Resume. These should be setups every suspend/resume timing too. This patch is tested on R-Car Gen3 Salvator-X board
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Tested-by: Gaku Inami gaku.inami.xw@bp.renesas.com --- sound/soc/sh/rcar/adg.c | 38 ++++++++++++++++++++++++-------------- sound/soc/sh/rcar/core.c | 24 ++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 3 +++ 3 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index f1068170..85a33ac 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -380,6 +380,25 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) return 0; }
+void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct clk *clk; + int i, ret; + + for_each_rsnd_clk(clk, adg, i) { + ret = 0; + if (enable) + ret = clk_prepare_enable(clk); + else + clk_disable_unprepare(clk); + + if (ret < 0) + dev_warn(dev, "can't use clk %d\n", i); + } +} + static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) { @@ -391,20 +410,15 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, [CLKC] = "clk_c", [CLKI] = "clk_i", }; - int i, ret; + int i;
for (i = 0; i < CLKMAX; i++) { clk = devm_clk_get(dev, clk_name[i]); adg->clk[i] = IS_ERR(clk) ? NULL : clk; }
- for_each_rsnd_clk(clk, adg, i) { - ret = clk_prepare_enable(clk); - if (ret < 0) - dev_warn(dev, "can't use clk %d\n", i); - + for_each_rsnd_clk(clk, adg, i) dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); - } }
static void rsnd_adg_get_clkout(struct rsnd_priv *priv, @@ -568,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
priv->adg = adg;
+ rsnd_adg_clk_enable(priv); + return 0; }
void rsnd_adg_remove(struct rsnd_priv *priv) { - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct clk *clk; - int i; - - for_each_rsnd_clk(clk, adg, i) { - clk_disable_unprepare(clk); - } + rsnd_adg_clk_disable(priv); } diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index a328bfe..b8de983 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1358,9 +1358,33 @@ static int rsnd_remove(struct platform_device *pdev) return ret; }
+static int rsnd_suspend(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_disable(priv); + + return 0; +} + +static int rsnd_resume(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_enable(priv); + + return 0; +} + +static struct dev_pm_ops rsnd_pm_ops = { + .suspend = rsnd_suspend, + .resume = rsnd_resume, +}; + static struct platform_driver rsnd_driver = { .driver = { .name = "rcar_sound", + .pm = &rsnd_pm_ops, .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index dc05152..f301130 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -501,6 +501,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, unsigned int out_rate); int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) +#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
/* * R-Car sound priv