}
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;
(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",
}
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",
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;
}
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;
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
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)
return ret;