MLK-21484-3: ASoC: fsl_sai: ensure clk is unprepared before reparent
authorViorel Suman <viorel.suman@nxp.com>
Thu, 18 Apr 2019 12:28:04 +0000 (15:28 +0300)
committerViorel Suman <viorel.suman@nxp.com>
Mon, 22 Apr 2019 06:47:00 +0000 (09:47 +0300)
On recent kernels clks which are marked with CLK_SET_RATE_GATE are
"protected" against further changes at clk_prepare time, including clk
reparent. Wrap clk set_parent and set_rate operations with
disable_unprepare and prepare_enable.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
sound/soc/fsl/fsl_sai.c

index febc612..1b6a5b9 100644 (file)
@@ -242,6 +242,7 @@ static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id,
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
        struct clk *p = sai->mclk_clk[clk_id], *pll = 0, *npll = 0;
        u64 ratio = freq;
+       bool reparent = false;
        int ret;
 
        while (p && sai->pll8k_clk && sai->pll11k_clk) {
@@ -255,28 +256,31 @@ static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id,
                p = pp;
        }
 
-       if (pll) {
-               npll = (do_div(ratio, 8000) ? sai->pll11k_clk : sai->pll8k_clk);
-               if (!clk_is_match(pll, npll)) {
-                       if (sai->mclk_streams == 0) {
-                               ret = clk_set_parent(p, npll);
-                               if (ret < 0)
-                                       dev_warn(dai->dev,
-                                               "failed to set parent %s: %d\n",
-                                               __clk_get_name(npll), ret);
-                       } else {
-                               dev_err(dai->dev,
-                                       "PLL %s is in use by a running stream.\n",
-                                       __clk_get_name(pll));
-                               return -EINVAL;
-                       }
+       npll = (do_div(ratio, 8000) ? sai->pll11k_clk : sai->pll8k_clk);
+       if (pll && !clk_is_match(pll, npll)) {
+               if (sai->mclk_streams != 0) {
+                       dev_err(dai->dev,
+                               "PLL %s is in use by a running stream.\n",
+                               __clk_get_name(pll));
+                       return -EINVAL;
                }
+               reparent = true;
+       }
+
+       clk_disable_unprepare(sai->mclk_clk[clk_id]);
+       if (reparent) {
+               ret = clk_set_parent(p, npll);
+               if (ret < 0)
+                       dev_warn(dai->dev, "failed to set parent %s: %d\n",
+                                __clk_get_name(npll), ret);
        }
 
        ret = clk_set_rate(sai->mclk_clk[clk_id], freq);
        if (ret < 0)
-               dev_err(dai->dev, "failed to set clock rate (%u): %d\n",
-                               freq, ret);
+               dev_warn(dai->dev, "failed to set clock rate (%u): %d\n", freq,
+                        ret);
+       clk_prepare_enable(sai->mclk_clk[clk_id]);
+
        return ret;
 }