Skip to content

Commit

Permalink
ASoC: stm32: sai: fix master clock management
Browse files Browse the repository at this point in the history
When master clock is used, master clock rate is set exclusively.
Parent clocks of master clock cannot be changed after a call to
clk_set_rate_exclusive(). So the parent clock of SAI kernel clock
must be set before.
Ensure also that exclusive rate operations are balanced
in STM32 SAI driver.

Signed-off-by: Olivier Moysan <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
  • Loading branch information
Olivier Moysan authored and broonie committed Apr 10, 2019
1 parent d6ba3f8 commit e37c2de
Showing 1 changed file with 47 additions and 17 deletions.
64 changes: 47 additions & 17 deletions sound/soc/stm/stm32_sai_sub.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
#define SAI_IEC60958_STATUS_BYTES 24

#define SAI_MCLK_NAME_LEN 32
#define SAI_RATE_11K 11025

/**
* struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
Expand Down Expand Up @@ -309,6 +310,25 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai,
return ret;
}

static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai,
unsigned int rate)
{
struct platform_device *pdev = sai->pdev;
struct clk *parent_clk = sai->pdata->clk_x8k;
int ret;

if (!(rate % SAI_RATE_11K))
parent_clk = sai->pdata->clk_x11k;

ret = clk_set_parent(sai->sai_ck, parent_clk);
if (ret)
dev_err(&pdev->dev, " Error %d setting sai_ck parent clock. %s",
ret, ret == -EBUSY ?
"Active stream rates conflict\n" : "\n");

return ret;
}

static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
Expand Down Expand Up @@ -490,25 +510,29 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;

if (dir == SND_SOC_CLOCK_OUT) {
if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) {
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
SAI_XCR1_NODIV,
(unsigned int)~SAI_XCR1_NODIV);
if (ret < 0)
return ret;

dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
sai->mclk_rate = freq;
/* If master clock is used, set parent clock now */
ret = stm32_sai_set_parent_clock(sai, freq);
if (ret)
return ret;

if (sai->sai_mclk) {
ret = clk_set_rate_exclusive(sai->sai_mclk,
sai->mclk_rate);
if (ret) {
dev_err(cpu_dai->dev,
"Could not set mclk rate\n");
return ret;
}
ret = clk_set_rate_exclusive(sai->sai_mclk, freq);
if (ret) {
dev_err(cpu_dai->dev,
ret == -EBUSY ?
"Active streams have incompatible rates" :
"Could not set mclk rate\n");
return ret;
}

dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
sai->mclk_rate = freq;
}

return 0;
Expand Down Expand Up @@ -916,11 +940,13 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
int div = 0, cr1 = 0;
int sai_clk_rate, mclk_ratio, den;
unsigned int rate = params_rate(params);
int ret;

if (!(rate % 11025))
clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k);
else
clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k);
if (!sai->sai_mclk) {
ret = stm32_sai_set_parent_clock(sai, rate);
if (ret)
return ret;
}
sai_clk_rate = clk_get_rate(sai->sai_ck);

if (STM_SAI_IS_F4(sai->pdata)) {
Expand Down Expand Up @@ -1079,9 +1105,13 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV,
SAI_XCR1_NODIV);

clk_disable_unprepare(sai->sai_ck);
/* Release mclk rate only if rate was actually set */
if (sai->mclk_rate) {
clk_rate_exclusive_put(sai->sai_mclk);
sai->mclk_rate = 0;
}

clk_rate_exclusive_put(sai->sai_mclk);
clk_disable_unprepare(sai->sai_ck);

spin_lock_irqsave(&sai->irq_lock, flags);
sai->substream = NULL;
Expand Down

0 comments on commit e37c2de

Please sign in to comment.