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>
This commit is contained in:
parent
7c0767643f
commit
06e8f5c842
@ -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;
|
||||
@ -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 */
|
||||
};
|
||||
@ -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];
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user