ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs
authorMaxime Ripard <maxime.ripard@bootlin.com>
Mon, 19 Aug 2019 19:25:15 +0000 (21:25 +0200)
committerMark Brown <broonie@kernel.org>
Tue, 20 Aug 2019 17:31:24 +0000 (18:31 +0100)
On the first generation of Allwinner SoCs (A10-A31), the i2s controller was
using the MCLK as BCLK parent. However, this changed since the introduction
of the A83t and BCLK now uses the module clock as its parent.

Let's introduce a hook to get the parent rate and use that in our divider
calculations.

Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3")
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://lore.kernel.org/r/0b6665be216b3bd0e7bc43724818f05f3f8ee881.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sunxi/sun4i-i2s.c

index 93ea627e2f1fb55bd41926ef713a8c315eb43c2c..acfcdb26086a87d16abf3dcf88fb3da84331db9d 100644 (file)
@@ -152,6 +152,7 @@ struct sun4i_i2s_quirks {
        struct reg_field                field_fmt_bclk;
        struct reg_field                field_fmt_lrclk;
 
+       unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
        s8      (*get_sr)(const struct sun4i_i2s *, int);
        s8      (*get_wss)(const struct sun4i_i2s *, int);
        int     (*set_chan_cfg)(const struct sun4i_i2s *,
@@ -207,6 +208,16 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
        /* TODO - extend divide ratio supported by newer SoCs */
 };
 
+static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
+{
+       return i2s->mclk_freq;
+}
+
+static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
+{
+       return clk_get_rate(i2s->mod_clk);
+}
+
 static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
                                  unsigned long parent_rate,
                                  unsigned int sampling_rate,
@@ -259,7 +270,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
                                  unsigned int word_size)
 {
        struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       unsigned int oversample_rate, clk_rate;
+       unsigned int oversample_rate, clk_rate, bclk_parent_rate;
        int bclk_div, mclk_div;
        int ret;
 
@@ -301,7 +312,8 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       bclk_div = sun4i_i2s_get_bclk_div(i2s, i2s->mclk_freq,
+       bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
+       bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
                                          rate, word_size);
        if (bclk_div < 0) {
                dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
@@ -957,6 +969,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
        .field_fmt_sr           = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
        .field_fmt_bclk         = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
        .field_fmt_lrclk        = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+       .get_bclk_parent_rate   = sun4i_i2s_get_bclk_parent_rate,
        .get_sr                 = sun4i_i2s_get_sr,
        .get_wss                = sun4i_i2s_get_wss,
        .set_chan_cfg           = sun4i_i2s_set_chan_cfg,
@@ -972,6 +985,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
        .field_fmt_sr           = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
        .field_fmt_bclk         = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
        .field_fmt_lrclk        = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+       .get_bclk_parent_rate   = sun4i_i2s_get_bclk_parent_rate,
        .get_sr                 = sun4i_i2s_get_sr,
        .get_wss                = sun4i_i2s_get_wss,
        .set_chan_cfg           = sun4i_i2s_set_chan_cfg,
@@ -987,6 +1001,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
        .field_fmt_sr           = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
        .field_fmt_bclk         = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
        .field_fmt_lrclk        = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+       .get_bclk_parent_rate   = sun8i_i2s_get_bclk_parent_rate,
        .get_sr                 = sun8i_i2s_get_sr_wss,
        .get_wss                = sun8i_i2s_get_sr_wss,
        .set_chan_cfg           = sun8i_i2s_set_chan_cfg,
@@ -1005,6 +1020,7 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
        .field_fmt_sr           = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
        .field_fmt_bclk         = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
        .field_fmt_lrclk        = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
+       .get_bclk_parent_rate   = sun8i_i2s_get_bclk_parent_rate,
        .get_sr                 = sun8i_i2s_get_sr_wss,
        .get_wss                = sun8i_i2s_get_sr_wss,
        .set_chan_cfg           = sun8i_i2s_set_chan_cfg,
@@ -1020,6 +1036,7 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
        .field_fmt_sr           = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
        .field_fmt_bclk         = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
        .field_fmt_lrclk        = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+       .get_bclk_parent_rate   = sun4i_i2s_get_bclk_parent_rate,
        .get_sr                 = sun4i_i2s_get_sr,
        .get_wss                = sun4i_i2s_get_wss,
        .set_chan_cfg           = sun4i_i2s_set_chan_cfg,