Merge branch 'asoc-5.4' into asoc-next
[linux-2.6-microblaze.git] / sound / soc / atmel / mchp-i2s-mcc.c
index ab7d5f9..befc2a3 100644 (file)
@@ -392,11 +392,11 @@ static int mchp_i2s_mcc_clk_get_rate_diff(struct clk *clk,
 }
 
 static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
-                                   unsigned int bclk, unsigned int *mra)
+                                   unsigned int bclk, unsigned int *mra,
+                                   unsigned long *best_rate)
 {
        unsigned long clk_rate;
        unsigned long lcm_rate;
-       unsigned long best_rate = 0;
        unsigned long best_diff_rate = ~0;
        unsigned int sysclk;
        struct clk *best_clk = NULL;
@@ -423,7 +423,7 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
             (clk_rate == bclk || clk_rate / (bclk * 2) <= GENMASK(5, 0));
             clk_rate += lcm_rate) {
                ret = mchp_i2s_mcc_clk_get_rate_diff(dev->gclk, clk_rate,
-                                                    &best_clk, &best_rate,
+                                                    &best_clk, best_rate,
                                                     &best_diff_rate);
                if (ret) {
                        dev_err(dev->dev, "gclk error for rate %lu: %d",
@@ -437,7 +437,7 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
                }
 
                ret = mchp_i2s_mcc_clk_get_rate_diff(dev->pclk, clk_rate,
-                                                    &best_clk, &best_rate,
+                                                    &best_clk, best_rate,
                                                     &best_diff_rate);
                if (ret) {
                        dev_err(dev->dev, "pclk error for rate %lu: %d",
@@ -459,33 +459,17 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
 
        dev_dbg(dev->dev, "source CLK is %s with rate %lu, diff %lu\n",
                best_clk == dev->pclk ? "pclk" : "gclk",
-               best_rate, best_diff_rate);
-
-       /* set the rate */
-       ret = clk_set_rate(best_clk, best_rate);
-       if (ret) {
-               dev_err(dev->dev, "unable to set rate %lu to %s: %d\n",
-                       best_rate, best_clk == dev->pclk ? "PCLK" : "GCLK",
-                       ret);
-               return ret;
-       }
+               *best_rate, best_diff_rate);
 
        /* Configure divisors */
        if (dev->sysclk)
-               *mra |= MCHP_I2SMCC_MRA_IMCKDIV(best_rate / (2 * sysclk));
-       *mra |= MCHP_I2SMCC_MRA_ISCKDIV(best_rate / (2 * bclk));
+               *mra |= MCHP_I2SMCC_MRA_IMCKDIV(*best_rate / (2 * sysclk));
+       *mra |= MCHP_I2SMCC_MRA_ISCKDIV(*best_rate / (2 * bclk));
 
-       if (best_clk == dev->gclk) {
+       if (best_clk == dev->gclk)
                *mra |= MCHP_I2SMCC_MRA_SRCCLK_GCLK;
-               ret = clk_prepare(dev->gclk);
-               if (ret < 0)
-                       dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret);
-               else
-                       dev->gclk_use = 1;
-       } else {
+       else
                *mra |= MCHP_I2SMCC_MRA_SRCCLK_PCLK;
-               dev->gclk_use = 0;
-       }
 
        return 0;
 }
@@ -502,6 +486,7 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
                                  struct snd_soc_dai *dai)
 {
+       unsigned long rate = 0;
        struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
        u32 mra = 0;
        u32 mrb = 0;
@@ -640,6 +625,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       if (set_divs) {
+               bclk_rate = frame_length * params_rate(params);
+               ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra,
+                                              &rate);
+               if (ret) {
+                       dev_err(dev->dev,
+                               "unable to configure the divisors: %d\n", ret);
+                       return ret;
+               }
+       }
+
        /*
         * If we are already running, the wanted setup must be
         * the same with the one that's currently ongoing
@@ -656,19 +652,27 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
                return 0;
        }
 
-       /* Save the number of channels to know what interrupts to enable */
-       dev->channels = channels;
-
-       if (set_divs) {
-               bclk_rate = frame_length * params_rate(params);
-               ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra);
+       if (mra & MCHP_I2SMCC_MRA_SRCCLK_GCLK && !dev->gclk_use) {
+               /* set the rate */
+               ret = clk_set_rate(dev->gclk, rate);
                if (ret) {
-                       dev_err(dev->dev, "unable to configure the divisors: %d\n",
-                               ret);
+                       dev_err(dev->dev,
+                               "unable to set rate %lu to GCLK: %d\n",
+                               rate, ret);
+                       return ret;
+               }
+
+               ret = clk_prepare(dev->gclk);
+               if (ret < 0) {
+                       dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret);
                        return ret;
                }
+               dev->gclk_use = 1;
        }
 
+       /* Save the number of channels to know what interrupts to enable */
+       dev->channels = channels;
+
        ret = regmap_write(dev->regmap, MCHP_I2SMCC_MRA, mra);
        if (ret < 0) {
                if (dev->gclk_use) {