From: Kuninori Morimoto <[email protected]>

[ Upstream commit 06e8f5c842f2dbb232897ba967ea7b422745c271 ]

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 <[email protected]>
Signed-off-by: Kuninori Morimoto <[email protected]>
Tested-by: Leon Kong <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Mark Brown <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
---
 sound/soc/sh/rcar/adg.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index e821ccc70f478..141d9a030c59a 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -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;
@@ -113,9 +114,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 */
        };
@@ -301,7 +302,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];
        }
 
@@ -368,10 +369,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);
-- 
2.20.1



Reply via email to