lkml.org 
[lkml]   [2019]   [May]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.0 62/95] ASoC: stm32: sai: fix master clock management
    Date
    [ Upstream commit e37c2deafe7058cf7989c4c47bbf1140cc867d89 ]

    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 <olivier.moysan@st.com>
    Signed-off-by: Mark Brown <broonie@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    sound/soc/stm/stm32_sai_sub.c | 64 +++++++++++++++++++++++++----------
    1 file changed, 47 insertions(+), 17 deletions(-)

    diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
    index bc69e68191ad1..1cf9df4b6f11c 100644
    --- a/sound/soc/stm/stm32_sai_sub.c
    +++ b/sound/soc/stm/stm32_sai_sub.c
    @@ -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)
    @@ -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)
    {
    @@ -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;
    @@ -916,11 +940,13 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
    int cr1, mask, div = 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)) {
    @@ -1075,9 +1101,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;
    --
    2.20.1


    \
     
     \ /
      Last update: 2019-05-09 21:00    [W:4.185 / U:0.084 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site