On Thu 20 Feb 2020 at 21:57, Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx> wrote: > The AIU audio controller on the Meson8 and Meson8b SoC families is > compatible with the one found in the later GXBB family. Add compatible > strings for these two older SoC families so the driver can be loaded for > them. > > Instead of using the I2S divider from the AIU_CLK_CTRL_MORE register we > need to use the I2S divider from the AIU_CLK_CTRL register. This older > register is less flexible because it only supports four divider settings > (1, 2, 4, 8) compared to the AIU_CLK_CTRL_MORE register (which supports > dividers in the range 0..64). > > Signed-off-by: Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx> Reviewed-by: Jerome Brunet <jbrunet@xxxxxxxxxxxx> > --- > sound/soc/meson/Kconfig | 2 +- > sound/soc/meson/aiu-encoder-i2s.c | 92 +++++++++++++++++++++++-------- > sound/soc/meson/aiu.c | 9 +++ > sound/soc/meson/aiu.h | 1 + > 4 files changed, 81 insertions(+), 23 deletions(-) > > diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig > index 897a706dcda0..d27e9180b453 100644 > --- a/sound/soc/meson/Kconfig > +++ b/sound/soc/meson/Kconfig > @@ -10,7 +10,7 @@ config SND_MESON_AIU > imply SND_SOC_HDMI_CODEC if DRM_MESON_DW_HDMI > help > Select Y or M to add support for the Audio output subsystem found > - in the Amlogic GX SoC family > + in the Amlogic Meson8, Meson8b and GX SoC families > > config SND_MESON_AXG_FIFO > tristate > diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c > index 4900e38e7e49..cc73b5d5c2b7 100644 > --- a/sound/soc/meson/aiu-encoder-i2s.c > +++ b/sound/soc/meson/aiu-encoder-i2s.c > @@ -111,34 +111,40 @@ static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component, > return 0; > } > > -static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, > - struct snd_pcm_hw_params *params) > +static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component, > + struct snd_pcm_hw_params *params, > + unsigned int bs) > { > - struct aiu *aiu = snd_soc_component_get_drvdata(component); > - unsigned int srate = params_rate(params); > - unsigned int fs, bs; > - > - /* Get the oversampling factor */ > - fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate); > + switch (bs) { > + case 1: > + case 2: > + case 4: > + case 8: > + /* These are the only valid legacy dividers */ > + break; I wonder how it will work with the 8ch mode and 16bits but we can deal with this later on. > > - if (fs % 64) > + default: > + dev_err(component->dev, "Unsupported i2s divider: %u\n", bs); > return -EINVAL; > + }; > > - /* Send data MSB first */ > - snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG, > - AIU_I2S_DAC_CFG_MSB_FIRST, > - AIU_I2S_DAC_CFG_MSB_FIRST); > + snd_soc_component_update_bits(component, AIU_CLK_CTRL, > + AIU_CLK_CTRL_I2S_DIV, > + FIELD_PREP(AIU_CLK_CTRL_I2S_DIV, > + __ffs(bs))); > > - /* Set bclk to lrlck ratio */ > - snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL, > - AIU_CODEC_DAC_LRCLK_CTRL_DIV, > - FIELD_PREP(AIU_CODEC_DAC_LRCLK_CTRL_DIV, > - 64 - 1)); > + snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE, > + AIU_CLK_CTRL_MORE_I2S_DIV, > + FIELD_PREP(AIU_CLK_CTRL_MORE_I2S_DIV, > + 0)); > > - /* Use CLK_MORE for mclk to bclk divider */ > - snd_soc_component_update_bits(component, AIU_CLK_CTRL, > - AIU_CLK_CTRL_I2S_DIV, 0); > + return 0; > +} > > +static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, > + struct snd_pcm_hw_params *params, > + unsigned int bs) > +{ > /* > * NOTE: this HW is odd. > * In most configuration, the i2s divider is 'mclk / blck'. > @@ -146,7 +152,6 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, > * increased by 50% to get the correct output rate. > * No idea why ! > */ > - bs = fs / 64; > if (params_width(params) == 16 && params_channels(params) == 8) { > if (bs % 2) { > dev_err(component->dev, > @@ -156,11 +161,54 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, > bs += bs / 2; > } > > + /* Use CLK_MORE for mclk to bclk divider */ > + snd_soc_component_update_bits(component, AIU_CLK_CTRL, > + AIU_CLK_CTRL_I2S_DIV, > + FIELD_PREP(AIU_CLK_CTRL_I2S_DIV, 0)); > + > snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE, > AIU_CLK_CTRL_MORE_I2S_DIV, > FIELD_PREP(AIU_CLK_CTRL_MORE_I2S_DIV, > bs - 1)); > > + return 0; > +} > + > +static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, > + struct snd_pcm_hw_params *params) > +{ > + struct aiu *aiu = snd_soc_component_get_drvdata(component); > + unsigned int srate = params_rate(params); > + unsigned int fs, bs; > + int ret; > + > + /* Get the oversampling factor */ > + fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate); > + > + if (fs % 64) > + return -EINVAL; > + > + /* Send data MSB first */ > + snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG, > + AIU_I2S_DAC_CFG_MSB_FIRST, > + AIU_I2S_DAC_CFG_MSB_FIRST); > + > + /* Set bclk to lrlck ratio */ > + snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL, > + AIU_CODEC_DAC_LRCLK_CTRL_DIV, > + FIELD_PREP(AIU_CODEC_DAC_LRCLK_CTRL_DIV, > + 64 - 1)); > + > + bs = fs / 64; > + > + if (aiu->platform->has_clk_ctrl_more_i2s_div) > + ret = aiu_encoder_i2s_set_more_div(component, params, bs); > + else > + ret = aiu_encoder_i2s_set_legacy_div(component, params, bs); > + > + if (ret) > + return ret; > + > /* Make sure amclk is used for HDMI i2s as well */ > snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE, > AIU_CLK_CTRL_MORE_HDMI_AMCLK, > diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c > index 38209312a8c3..dc35ca79021c 100644 > --- a/sound/soc/meson/aiu.c > +++ b/sound/soc/meson/aiu.c > @@ -351,15 +351,24 @@ static int aiu_remove(struct platform_device *pdev) > > static const struct aiu_platform_data aiu_gxbb_pdata = { > .has_acodec = false, > + .has_clk_ctrl_more_i2s_div = true, > }; > > static const struct aiu_platform_data aiu_gxl_pdata = { > .has_acodec = true, > + .has_clk_ctrl_more_i2s_div = true, > +}; > + > +static const struct aiu_platform_data aiu_meson8_pdata = { > + .has_acodec = false, > + .has_clk_ctrl_more_i2s_div = false, > }; > > static const struct of_device_id aiu_of_match[] = { > { .compatible = "amlogic,aiu-gxbb", .data = &aiu_gxbb_pdata }, > { .compatible = "amlogic,aiu-gxl", .data = &aiu_gxl_pdata }, > + { .compatible = "amlogic,aiu-meson8", .data = &aiu_meson8_pdata }, > + { .compatible = "amlogic,aiu-meson8b", .data = &aiu_meson8_pdata }, > {} > }; > MODULE_DEVICE_TABLE(of, aiu_of_match); > diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h > index ab003638d5e5..87aa19ac4af3 100644 > --- a/sound/soc/meson/aiu.h > +++ b/sound/soc/meson/aiu.h > @@ -29,6 +29,7 @@ struct aiu_interface { > > struct aiu_platform_data { > bool has_acodec; > + bool has_clk_ctrl_more_i2s_div; > }; > > struct aiu {