[PATCH 2/3] ASoC: sun8i-codec: Set the BCLK divider

Chen-Yu Tsai wens at csie.org
Wed Nov 8 08:22:23 PST 2017


On Wed, Nov 8, 2017 at 11:47 PM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> While the current code was reporting to be able to work in master mode, it
> failed to do so because the BCLK divider wasn't programmed, meaning that
> the BCLK would run at the PLL's frequency no matter the sample rate.
>
> It was obviously a bit too fast.
>
> Add support to retrieve the divider to use, and set it. Since our PLL is
> not always able to generate a perfect multiple of the sample rate, we'll
> have to choose the closest divider that matches our setup.
>
> Fixes: 36c684936fae ("ASoC: Add sun8i digital audio codec")
> Cc: <stable at vger.kernel.org>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 53 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 53 insertions(+)
>
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 038107baf414..522546e6b153 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -73,6 +73,7 @@
>  #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK         GENMASK(11, 8)
>  #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK  GENMASK(5, 4)
>  #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK  GENMASK(8, 6)
> +#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK  GENMASK(12, 9)
>
>  struct sun8i_codec {
>         struct device   *dev;
> @@ -226,12 +227,57 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>         return 0;
>  }
>
> +struct sun8i_codec_clk_div {
> +       u8      div;
> +       u8      val;
> +};
> +
> +static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
> +       { .div = 1,     .val = 0 },
> +       { .div = 2,     .val = 1 },
> +       { .div = 4,     .val = 2 },
> +       { .div = 6,     .val = 3 },
> +       { .div = 8,     .val = 4 },
> +       { .div = 12,    .val = 5 },
> +       { .div = 16,    .val = 6 },
> +       { .div = 24,    .val = 7 },
> +       { .div = 32,    .val = 8 },
> +       { .div = 48,    .val = 9 },
> +       { .div = 64,    .val = 10 },
> +       { .div = 96,    .val = 11 },
> +       { .div = 128,   .val = 12 },
> +       { .div = 192,   .val = 13 },
> +};
> +
> +static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
> +                                  unsigned int rate,
> +                                  unsigned int word_size)
> +{
> +       unsigned long clk_rate = clk_get_rate(scodec->clk_module);
> +       unsigned int div = clk_rate / rate / word_size / 2;
> +       unsigned int best_val = 0, best_diff = ~0;
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
> +               const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
> +               unsigned int diff = abs(bdiv->div - div);
> +
> +               if (diff < best_diff) {
> +                       best_diff = diff;
> +                       best_val = bdiv->val;
> +               }
> +       }
> +
> +       return best_val;
> +}
> +
>  static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>                                  struct snd_pcm_hw_params *params,
>                                  struct snd_soc_dai *dai)
>  {
>         struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
>         int sample_rate;
> +       u8 bclk_div;
>
>         /*
>          * The CPU DAI handles only a sample of 16 bits. Configure the
> @@ -241,6 +287,13 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>                            SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
>                            SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);

This looks like it's using 16 bit words regardless of the settings in params.

>
> +       bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params),
> +                                           params_width(params));

But here you pass params_width(params). Seems a bit error prone.

Otherwise,

Reviewed-by: Chen-Yu Tsai <wens at csie.org>

> +
> +       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> +                          SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
> +                          bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
> +
>         regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>                            SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
>                            SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
> --
> 2.14.3
>



More information about the linux-arm-kernel mailing list