aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2019-08-05 23:45:38 -0400
committerMark Brown <broonie@kernel.org>2019-08-07 09:17:47 -0400
commit06e8f5c842f2dbb232897ba967ea7b422745c271 (patch)
tree212e88aa7cab3d6ce770563c0a8876fbed777e0a
parent7c0767643f3b6b0dd2cda923ae37a18590d431cf (diff)
ASoC: rsnd: don't call clk_get_rate() under atomic context
ADG is using clk_get_rate() under atomic context, thus, we might have scheduling issue. To avoid this issue, we need to get/keep clk rate under non atomic context. We need to handle ADG as special device at Renesas Sound driver. From SW point of view, we want to impletent it as rsnd_mod_ops :: prepare, but it makes code just complicate. To avoid complicated code/patch, this patch adds new clk_rate[] array, and keep clk IN rate when rsnd_adg_clk_enable() was called. Reported-by: Leon Kong <Leon.KONG@cn.bosch.com> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Tested-by: Leon Kong <Leon.KONG@cn.bosch.com> Link: https://lore.kernel.org/r/87v9vb0xkp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/sh/rcar/adg.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index fce4e050a9b7..b9aacf3d3b29 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -30,6 +30,7 @@ struct rsnd_adg {
30 struct clk *clkout[CLKOUTMAX]; 30 struct clk *clkout[CLKOUTMAX];
31 struct clk_onecell_data onecell; 31 struct clk_onecell_data onecell;
32 struct rsnd_mod mod; 32 struct rsnd_mod mod;
33 int clk_rate[CLKMAX];
33 u32 flags; 34 u32 flags;
34 u32 ckr; 35 u32 ckr;
35 u32 rbga; 36 u32 rbga;
@@ -114,9 +115,9 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
114 unsigned int val, en; 115 unsigned int val, en;
115 unsigned int min, diff; 116 unsigned int min, diff;
116 unsigned int sel_rate[] = { 117 unsigned int sel_rate[] = {
117 clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */ 118 adg->clk_rate[CLKA], /* 0000: CLKA */
118 clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */ 119 adg->clk_rate[CLKB], /* 0001: CLKB */
119 clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */ 120 adg->clk_rate[CLKC], /* 0010: CLKC */
120 adg->rbga_rate_for_441khz, /* 0011: RBGA */ 121 adg->rbga_rate_for_441khz, /* 0011: RBGA */
121 adg->rbgb_rate_for_48khz, /* 0100: RBGB */ 122 adg->rbgb_rate_for_48khz, /* 0100: RBGB */
122 }; 123 };
@@ -302,7 +303,7 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
302 * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. 303 * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
303 */ 304 */
304 for_each_rsnd_clk(clk, adg, i) { 305 for_each_rsnd_clk(clk, adg, i) {
305 if (rate == clk_get_rate(clk)) 306 if (rate == adg->clk_rate[i])
306 return sel_table[i]; 307 return sel_table[i];
307 } 308 }
308 309
@@ -369,10 +370,18 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
369 370
370 for_each_rsnd_clk(clk, adg, i) { 371 for_each_rsnd_clk(clk, adg, i) {
371 ret = 0; 372 ret = 0;
372 if (enable) 373 if (enable) {
373 ret = clk_prepare_enable(clk); 374 ret = clk_prepare_enable(clk);
374 else 375
376 /*
377 * We shouldn't use clk_get_rate() under
378 * atomic context. Let's keep it when
379 * rsnd_adg_clk_enable() was called
380 */
381 adg->clk_rate[i] = clk_get_rate(adg->clk[i]);
382 } else {
375 clk_disable_unprepare(clk); 383 clk_disable_unprepare(clk);
384 }
376 385
377 if (ret < 0) 386 if (ret < 0)
378 dev_warn(dev, "can't use clk %d\n", i); 387 dev_warn(dev, "can't use clk %d\n", i);