Skip to content

Commit

Permalink
ASoC: rsnd: don't call clk_get_rate() under atomic context
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
morimoto authored and broonie committed Aug 7, 2019
1 parent 7c07676 commit 06e8f5c
Showing 1 changed file with 15 additions and 6 deletions.
21 changes: 15 additions & 6 deletions sound/soc/sh/rcar/adg.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct rsnd_adg {
struct clk *clkout[CLKOUTMAX];
struct clk_onecell_data onecell;
struct rsnd_mod mod;
int clk_rate[CLKMAX];
u32 flags;
u32 ckr;
u32 rbga;
Expand Down Expand Up @@ -114,9 +115,9 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
unsigned int val, en;
unsigned int min, diff;
unsigned int sel_rate[] = {
clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */
clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */
clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */
adg->clk_rate[CLKA], /* 0000: CLKA */
adg->clk_rate[CLKB], /* 0001: CLKB */
adg->clk_rate[CLKC], /* 0010: CLKC */
adg->rbga_rate_for_441khz, /* 0011: RBGA */
adg->rbgb_rate_for_48khz, /* 0100: RBGB */
};
Expand Down Expand Up @@ -302,7 +303,7 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
* AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
*/
for_each_rsnd_clk(clk, adg, i) {
if (rate == clk_get_rate(clk))
if (rate == adg->clk_rate[i])
return sel_table[i];
}

Expand Down Expand Up @@ -369,10 +370,18 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)

for_each_rsnd_clk(clk, adg, i) {
ret = 0;
if (enable)
if (enable) {
ret = clk_prepare_enable(clk);
else

/*
* We shouldn't use clk_get_rate() under
* atomic context. Let's keep it when
* rsnd_adg_clk_enable() was called
*/
adg->clk_rate[i] = clk_get_rate(adg->clk[i]);
} else {
clk_disable_unprepare(clk);
}

if (ret < 0)
dev_warn(dev, "can't use clk %d\n", i);
Expand Down

0 comments on commit 06e8f5c

Please sign in to comment.