[alsa-devel] [PATCH 00/21] ASoC: sun4i-i2s: Number of fixes and TDM Support
From: Maxime Ripard maxime.ripard@bootlin.com
Hi,
This series aims at fixing a number of issues in the current i2s driver, mostly related to the i2s master support and the A83t support. It also uses that occasion to cleanup a few things and simplify the driver. Finally, it builds on those fixes and cleanups to introduce TDM and DSP formats support.
Let me know what you think, Maxime
Marcus Cooper (1): ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
Maxime Ripard (20): ASoC: sun4i-i2s: Register regmap and PCM before our component ASoC: sun4i-i2s: Switch to devm for PCM register ASoC: sun4i-i2s: Replace call to params_channels by local variable ASoC: sun4i-i2s: Move the channel configuration to a callback ASoC: sun4i-i2s: Move the format configuration to a callback ASoC: sun4i-i2s: Rework MCLK divider calculation ASoC: sun4i-i2s: Don't use the oversample to calculate BCLK ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs ASoC: sun4i-i2s: RX and TX counter registers are swapped ASoC: sun4i-i2s: Use the actual format width instead of an hardcoded one ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs ASoC: sun4i-i2s: Fix the LRCK polarity ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t ASoC: sun4i-i2s: Fix the LRCK period on A83t ASoC: sun4i-i2s: Remove duplicated quirks structure ASoC: sun4i-i2s: Pass the channels number as an argument ASoC: sun4i-i2s: Support more channels ASoC: sun4i-i2s: Add support for TDM slots ASoC: sun4i-i2s: Add support for DSP formats
sound/soc/sunxi/sun4i-i2s.c | 660 ++++++++++++++++++++----------------- 1 file changed, 372 insertions(+), 288 deletions(-)
base-commit: d45331b00ddb179e291766617259261c112db872
From: Maxime Ripard maxime.ripard@bootlin.com
So far the regmap and the dmaengine PCM are registered after our component has been, which means that our driver isn't properly initialised by then.
Let's fix that.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 7fa5c61169db..85c3b2c8cd77 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1148,11 +1148,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_pm_disable; }
- ret = devm_snd_soc_register_component(&pdev->dev, - &sun4i_i2s_component, - &sun4i_i2s_dai, 1); + ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); if (ret) { - dev_err(&pdev->dev, "Could not register DAI\n"); + dev_err(&pdev->dev, "Could not initialise regmap fields\n"); goto err_suspend; }
@@ -1162,9 +1160,11 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_suspend; }
- ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); + ret = devm_snd_soc_register_component(&pdev->dev, + &sun4i_i2s_component, + &sun4i_i2s_dai, 1); if (ret) { - dev_err(&pdev->dev, "Could not initialise regmap fields\n"); + dev_err(&pdev->dev, "Could not register DAI\n"); goto err_suspend; }
The patch
ASoC: sun4i-i2s: Register regmap and PCM before our component
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.3
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From bf283a05c09b58db83afbb1a8a3c6a684c56c1bb Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:08 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Register regmap and PCM before our component
So far the regmap and the dmaengine PCM are registered after our component has been, which means that our driver isn't properly initialised by then.
Let's fix that.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/67e303f37f141ef73ce9ed47d7f831b63c694424.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 7fa5c61169db..85c3b2c8cd77 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1148,11 +1148,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_pm_disable; }
- ret = devm_snd_soc_register_component(&pdev->dev, - &sun4i_i2s_component, - &sun4i_i2s_dai, 1); + ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); if (ret) { - dev_err(&pdev->dev, "Could not register DAI\n"); + dev_err(&pdev->dev, "Could not initialise regmap fields\n"); goto err_suspend; }
@@ -1162,9 +1160,11 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_suspend; }
- ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); + ret = devm_snd_soc_register_component(&pdev->dev, + &sun4i_i2s_component, + &sun4i_i2s_dai, 1); if (ret) { - dev_err(&pdev->dev, "Could not initialise regmap fields\n"); + dev_err(&pdev->dev, "Could not register DAI\n"); goto err_suspend; }
From: Maxime Ripard maxime.ripard@bootlin.com
Since the introduction of the driver, a new managed helper for the dmaengine PCM registration has been created. Let's use it to simplify a bit our probe and remove functions.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 85c3b2c8cd77..1ed7670eae9c 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1154,7 +1154,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_suspend; }
- ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { dev_err(&pdev->dev, "Could not register PCM\n"); goto err_suspend; @@ -1185,8 +1185,6 @@ static int sun4i_i2s_remove(struct platform_device *pdev) { struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);
- snd_dmaengine_pcm_unregister(&pdev->dev); - pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) sun4i_i2s_runtime_suspend(&pdev->dev);
The patch
ASoC: sun4i-i2s: Switch to devm for PCM register
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From a49d24e7d8d4fd4edf59e6373983e0bf4a2cca15 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:09 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Switch to devm for PCM register
Since the introduction of the driver, a new managed helper for the dmaengine PCM registration has been created. Let's use it to simplify a bit our probe and remove functions.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/606d271187091e858e8c15e20555af0b79798fe1.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index d97d694c48df..70608fa30bf2 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1154,7 +1154,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_suspend; }
- ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { dev_err(&pdev->dev, "Could not register PCM\n"); goto err_suspend; @@ -1183,8 +1183,6 @@ static int sun4i_i2s_remove(struct platform_device *pdev) { struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);
- snd_dmaengine_pcm_unregister(&pdev->dev); - pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) sun4i_i2s_runtime_suspend(&pdev->dev);
From: Maxime Ripard maxime.ripard@bootlin.com
The sun4i_i2s_hw_params already has a variable holding the value returned by params_channels, so let's just use that variable instead of calling params_channels multiple times.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 1ed7670eae9c..ac84c29224eb 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -411,10 +411,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
/* Configure the channels */ regmap_field_write(i2s->field_txchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); - + SUN4I_I2S_CHAN_SEL(channels)); regmap_field_write(i2s->field_rxchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); + SUN4I_I2S_CHAN_SEL(channels));
if (i2s->variant->has_chsel_tx_chen) regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
The patch
ASoC: sun4i-i2s: Replace call to params_channels by local variable
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From c7dd0828c088a71f30de8d249f63b2fa9f0d322d Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:10 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Replace call to params_channels by local variable
The sun4i_i2s_hw_params already has a variable holding the value returned by params_channels, so let's just use that variable instead of calling params_channels multiple times.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/c0faaac69ad40248f24eed3c3b2fa1ccc4a85b70.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index d879db581073..77b7b81daf74 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -412,10 +412,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
/* Configure the channels */ regmap_field_write(i2s->field_txchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); - + SUN4I_I2S_CHAN_SEL(channels)); regmap_field_write(i2s->field_rxchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); + SUN4I_I2S_CHAN_SEL(channels));
if (i2s->variant->has_chsel_tx_chen) regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
From: Maxime Ripard maxime.ripard@bootlin.com
The two main generations of our I2S controller require a slightly different channel configuration, mostly because of a quite different register layout and some additional registers being needed on the newer generation.
This used to be controlled through a bunch of booleans, however this proved to be quite impractical, especially since a bunch of SoCs forgot to set those parameters and therefore were broken from that point of view.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 156 ++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 87 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index ac84c29224eb..657041606c2f 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -80,6 +80,7 @@ #define SUN4I_I2S_TX_CNT_REG 0x2c
#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 +#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0) #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
#define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 @@ -122,8 +123,6 @@ struct sun4i_i2s; * @has_reset: SoC needs reset deasserted. * @has_slave_select_bit: SoC has a bit to enable slave mode. * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. - * @has_chcfg: tx and rx slot number need to be set. - * @has_chsel_tx_chen: SoC requires that the tx channels are enabled. * @has_chsel_offset: SoC uses offset for selecting dai operational mode. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. @@ -135,17 +134,11 @@ struct sun4i_i2s; * @field_fmt_bclk: regmap field to set clk polarity. * @field_fmt_lrclk: regmap field to set frame polarity. * @field_fmt_mode: regmap field to set the operational mode. - * @field_txchanmap: location of the tx channel mapping register. - * @field_rxchanmap: location of the rx channel mapping register. - * @field_txchansel: location of the tx channel select bit fields. - * @field_rxchansel: location of the rx channel select bit fields. */ struct sun4i_i2s_quirks { bool has_reset; bool has_slave_select_bit; bool has_fmt_set_lrck_period; - bool has_chcfg; - bool has_chsel_tx_chen; bool has_chsel_offset; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; @@ -159,13 +152,11 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk; struct reg_field field_fmt_mode; - struct reg_field field_txchanmap; - struct reg_field field_rxchanmap; - struct reg_field field_txchansel; - struct reg_field field_rxchansel;
s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); + int (*set_chan_cfg)(const struct sun4i_i2s *, + const struct snd_pcm_hw_params *); };
struct sun4i_i2s { @@ -186,10 +177,6 @@ struct sun4i_i2s { struct regmap_field *field_fmt_bclk; struct regmap_field *field_fmt_lrclk; struct regmap_field *field_fmt_mode; - struct regmap_field *field_txchanmap; - struct regmap_field *field_rxchanmap; - struct regmap_field *field_txchansel; - struct regmap_field *field_rxchansel;
const struct sun4i_i2s_quirks *variant; }; @@ -381,44 +368,77 @@ static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width) return (width - 8) / 4 + 1; }
-static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + const struct snd_pcm_hw_params *params) { - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - int sr, wss, channels; - u32 width; + unsigned int channels = params_channels(params);
- channels = params_channels(params); - if (channels != 2) { - dev_err(dai->dev, "Unsupported number of channels: %d\n", - channels); + if (channels != 2) return -EINVAL; - }
- if (i2s->variant->has_chcfg) { - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); - } + /* Map the channels for playback and capture */ + regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); + regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); + + /* Configure the channels */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + + return 0; +} + +static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + const struct snd_pcm_hw_params *params) +{ + unsigned int channels = params_channels(params); + + if (channels != 2) + return -EINVAL;
/* Map the channels for playback and capture */ - regmap_field_write(i2s->field_txchanmap, 0x76543210); - regmap_field_write(i2s->field_rxchanmap, 0x00003210); + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); + regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
/* Configure the channels */ - regmap_field_write(i2s->field_txchansel, + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); - regmap_field_write(i2s->field_rxchansel, + + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels));
- if (i2s->variant->has_chsel_tx_chen) - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_EN_MASK, - SUN8I_I2S_TX_CHAN_EN(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); + + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_EN_MASK, + SUN8I_I2S_TX_CHAN_EN(channels)); + + return 0; +} + +static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + int ret, sr, wss; + u32 width; + + ret = i2s->variant->set_chan_cfg(i2s, params); + if (ret < 0) { + dev_err(dai->dev, "Invalid channel configuration\n"); + return ret; + }
switch (params_physical_width(params)) { case 16: @@ -916,12 +936,9 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, };
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { @@ -935,12 +952,9 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, };
static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { @@ -954,12 +968,9 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun8i_i2s_set_chan_cfg, };
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { @@ -969,8 +980,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .mclk_offset = 1, .bclk_offset = 2, .has_fmt_set_lrck_period = true, - .has_chcfg = true, - .has_chsel_tx_chen = true, .has_chsel_offset = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), @@ -978,12 +987,9 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5), - .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun8i_i2s_set_chan_cfg, };
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { @@ -997,12 +1003,9 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, };
static int sun4i_i2s_init_regmap_fields(struct device *dev, @@ -1044,28 +1047,7 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_mode)) return PTR_ERR(i2s->field_fmt_mode);
- i2s->field_txchanmap = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_txchanmap); - if (IS_ERR(i2s->field_txchanmap)) - return PTR_ERR(i2s->field_txchanmap); - - i2s->field_rxchanmap = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_rxchanmap); - if (IS_ERR(i2s->field_rxchanmap)) - return PTR_ERR(i2s->field_rxchanmap); - - i2s->field_txchansel = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_txchansel); - if (IS_ERR(i2s->field_txchansel)) - return PTR_ERR(i2s->field_txchansel); - - i2s->field_rxchansel = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_rxchansel); - return PTR_ERR_OR_ZERO(i2s->field_rxchansel); + return 0; }
static int sun4i_i2s_probe(struct platform_device *pdev)
The patch
ASoC: sun4i-i2s: Move the channel configuration to a callback
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From d70be625f25af7a2bc91b7d17d205f6071f08f2f Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:11 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Move the channel configuration to a callback
The two main generations of our I2S controller require a slightly different channel configuration, mostly because of a quite different register layout and some additional registers being needed on the newer generation.
This used to be controlled through a bunch of booleans, however this proved to be quite impractical, especially since a bunch of SoCs forgot to set those parameters and therefore were broken from that point of view.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/6414463de69584e8227fa495b13aa5f4798e1f0e.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 156 ++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 87 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 2c909c6cafa9..42e45c9a947a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -80,6 +80,7 @@ #define SUN4I_I2S_TX_CNT_REG 0x2c
#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 +#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0) #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
#define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 @@ -122,8 +123,6 @@ struct sun4i_i2s; * @has_reset: SoC needs reset deasserted. * @has_slave_select_bit: SoC has a bit to enable slave mode. * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. - * @has_chcfg: tx and rx slot number need to be set. - * @has_chsel_tx_chen: SoC requires that the tx channels are enabled. * @has_chsel_offset: SoC uses offset for selecting dai operational mode. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. @@ -135,17 +134,11 @@ struct sun4i_i2s; * @field_fmt_bclk: regmap field to set clk polarity. * @field_fmt_lrclk: regmap field to set frame polarity. * @field_fmt_mode: regmap field to set the operational mode. - * @field_txchanmap: location of the tx channel mapping register. - * @field_rxchanmap: location of the rx channel mapping register. - * @field_txchansel: location of the tx channel select bit fields. - * @field_rxchansel: location of the rx channel select bit fields. */ struct sun4i_i2s_quirks { bool has_reset; bool has_slave_select_bit; bool has_fmt_set_lrck_period; - bool has_chcfg; - bool has_chsel_tx_chen; bool has_chsel_offset; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; @@ -159,13 +152,11 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk; struct reg_field field_fmt_mode; - struct reg_field field_txchanmap; - struct reg_field field_rxchanmap; - struct reg_field field_txchansel; - struct reg_field field_rxchansel;
s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); + int (*set_chan_cfg)(const struct sun4i_i2s *, + const struct snd_pcm_hw_params *); };
struct sun4i_i2s { @@ -186,10 +177,6 @@ struct sun4i_i2s { struct regmap_field *field_fmt_bclk; struct regmap_field *field_fmt_lrclk; struct regmap_field *field_fmt_mode; - struct regmap_field *field_txchanmap; - struct regmap_field *field_rxchanmap; - struct regmap_field *field_txchansel; - struct regmap_field *field_rxchansel;
const struct sun4i_i2s_quirks *variant; }; @@ -380,44 +367,77 @@ static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width) return (width - 8) / 4 + 1; }
-static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + const struct snd_pcm_hw_params *params) { - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - int sr, wss, channels; - u32 width; + unsigned int channels = params_channels(params);
- channels = params_channels(params); - if (channels != 2) { - dev_err(dai->dev, "Unsupported number of channels: %d\n", - channels); + if (channels != 2) return -EINVAL; - }
- if (i2s->variant->has_chcfg) { - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); - } + /* Map the channels for playback and capture */ + regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); + regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); + + /* Configure the channels */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + + return 0; +} + +static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + const struct snd_pcm_hw_params *params) +{ + unsigned int channels = params_channels(params); + + if (channels != 2) + return -EINVAL;
/* Map the channels for playback and capture */ - regmap_field_write(i2s->field_txchanmap, 0x76543210); - regmap_field_write(i2s->field_rxchanmap, 0x00003210); + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); + regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
/* Configure the channels */ - regmap_field_write(i2s->field_txchansel, + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); - regmap_field_write(i2s->field_rxchansel, + + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels));
- if (i2s->variant->has_chsel_tx_chen) - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_EN_MASK, - SUN8I_I2S_TX_CHAN_EN(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); + + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_EN_MASK, + SUN8I_I2S_TX_CHAN_EN(channels)); + + return 0; +} + +static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + int ret, sr, wss; + u32 width; + + ret = i2s->variant->set_chan_cfg(i2s, params); + if (ret < 0) { + dev_err(dai->dev, "Invalid channel configuration\n"); + return ret; + }
switch (params_physical_width(params)) { case 16: @@ -915,12 +935,9 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, };
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { @@ -934,12 +951,9 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, };
static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { @@ -953,12 +967,9 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun8i_i2s_set_chan_cfg, };
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { @@ -968,8 +979,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .mclk_offset = 1, .bclk_offset = 2, .has_fmt_set_lrck_period = true, - .has_chcfg = true, - .has_chsel_tx_chen = true, .has_chsel_offset = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), @@ -977,12 +986,9 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5), - .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun8i_i2s_set_chan_cfg, };
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { @@ -996,12 +1002,9 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, };
static int sun4i_i2s_init_regmap_fields(struct device *dev, @@ -1043,28 +1046,7 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_mode)) return PTR_ERR(i2s->field_fmt_mode);
- i2s->field_txchanmap = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_txchanmap); - if (IS_ERR(i2s->field_txchanmap)) - return PTR_ERR(i2s->field_txchanmap); - - i2s->field_rxchanmap = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_rxchanmap); - if (IS_ERR(i2s->field_rxchanmap)) - return PTR_ERR(i2s->field_rxchanmap); - - i2s->field_txchansel = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_txchansel); - if (IS_ERR(i2s->field_txchansel)) - return PTR_ERR(i2s->field_txchansel); - - i2s->field_rxchansel = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_rxchansel); - return PTR_ERR_OR_ZERO(i2s->field_rxchansel); + return 0; }
static int sun4i_i2s_probe(struct platform_device *pdev)
From: Maxime Ripard maxime.ripard@bootlin.com
The two main generations of our I2S controller require a slightly different format configuration, mostly because of a quite different register layout and some additional registers being needed on the newer generation.
This used to be controlled through a bunch of booleans, however this proved to be quite impractical, especially since a bunch of SoCs forgot to set those parameters and therefore were broken from that point of view.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 199 +++++++++++++++++++------------------ 1 file changed, 106 insertions(+), 93 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 657041606c2f..fbbedb660cc6 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -93,6 +93,11 @@ #define SUN8I_I2S_CTRL_BCLK_OUT BIT(18) #define SUN8I_I2S_CTRL_LRCK_OUT BIT(17)
+#define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4) +#define SUN8I_I2S_CTRL_MODE_RIGHT (2 << 4) +#define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) +#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) + #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
@@ -121,9 +126,7 @@ struct sun4i_i2s; * struct sun4i_i2s_quirks - Differences between SoC variants. * * @has_reset: SoC needs reset deasserted. - * @has_slave_select_bit: SoC has a bit to enable slave mode. * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. - * @has_chsel_offset: SoC uses offset for selecting dai operational mode. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. * @mclk_offset: Value by which mclkdiv needs to be adjusted. @@ -133,13 +136,10 @@ struct sun4i_i2s; * @field_fmt_sr: regmap field to set sample resolution. * @field_fmt_bclk: regmap field to set clk polarity. * @field_fmt_lrclk: regmap field to set frame polarity. - * @field_fmt_mode: regmap field to set the operational mode. */ struct sun4i_i2s_quirks { bool has_reset; - bool has_slave_select_bit; bool has_fmt_set_lrck_period; - bool has_chsel_offset; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; unsigned int mclk_offset; @@ -151,12 +151,12 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_sr; struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk; - struct reg_field field_fmt_mode;
s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); int (*set_chan_cfg)(const struct sun4i_i2s *, const struct snd_pcm_hw_params *); + int (*set_fmt)(const struct sun4i_i2s *, unsigned int); };
struct sun4i_i2s { @@ -176,7 +176,6 @@ struct sun4i_i2s { struct regmap_field *field_fmt_sr; struct regmap_field *field_fmt_bclk; struct regmap_field *field_fmt_lrclk; - struct regmap_field *field_fmt_mode;
const struct sun4i_i2s_quirks *variant; }; @@ -466,52 +465,117 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, params_width(params)); }
-static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) { - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); u32 val; - u32 offset = 0; - u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; - u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
/* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: val = SUN4I_I2S_FMT0_FMT_I2S; - offset = 1; break; + case SND_SOC_DAIFMT_LEFT_J: val = SUN4I_I2S_FMT0_FMT_LEFT_J; break; + case SND_SOC_DAIFMT_RIGHT_J: val = SUN4I_I2S_FMT0_FMT_RIGHT_J; break; + default: - dev_err(dai->dev, "Unsupported format: %d\n", - fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; }
- if (i2s->variant->has_chsel_offset) { - /* - * offset being set indicates that we're connected to an i2s - * device, however offset is only used on the sun8i block and - * i2s shares the same setting with the LJ format. Increment - * val so that the bit to value to write is correct. - */ - if (offset > 0) - val++; - /* blck offset determines whether i2s or LJ */ - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); - - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN4I_I2S_FMT0_FMT_MASK, val); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN4I_I2S_CTRL_MODE_MASTER; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = SUN4I_I2S_CTRL_MODE_SLAVE; + break; + + default: + return -EINVAL; } + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_MODE_MASK, val); + return 0; +}
- regmap_field_write(i2s->field_fmt_mode, val); +static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) +{ + u32 mode, val; + u8 offset; + + /* DAI Mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 1; + break; + + case SND_SOC_DAIFMT_LEFT_J: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 0; + break; + + case SND_SOC_DAIFMT_RIGHT_J: + mode = SUN8I_I2S_CTRL_MODE_RIGHT; + offset = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_MODE_MASK, mode); + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, + val); + + return 0; +} + +static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; + u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; + int ret;
/* DAI clock polarity */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -539,50 +603,10 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) regmap_field_write(i2s->field_fmt_bclk, bclk_polarity); regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
- if (i2s->variant->has_slave_select_bit) { - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* BCLK and LRCLK master */ - val = SUN4I_I2S_CTRL_MODE_MASTER; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* BCLK and LRCLK slave */ - val = SUN4I_I2S_CTRL_MODE_SLAVE; - break; - default: - dev_err(dai->dev, "Unsupported slave setting: %d\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - } - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_MODE_MASK, - val); - } else { - /* - * The newer i2s block does not have a slave select bit, - * instead the clk pins are configured as inputs. - */ - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* BCLK and LRCLK master */ - val = SUN8I_I2S_CTRL_BCLK_OUT | - SUN8I_I2S_CTRL_LRCK_OUT; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* BCLK and LRCLK slave */ - val = 0; - break; - default: - dev_err(dai->dev, "Unsupported slave setting: %d\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - } - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN8I_I2S_CTRL_BCLK_OUT | - SUN8I_I2S_CTRL_LRCK_OUT, - val); + ret = i2s->variant->set_fmt(i2s, fmt); + if (ret) { + dev_err(dai->dev, "Unsupported format configuration\n"); + return ret; }
/* Set significant bits in our FIFOs */ @@ -934,11 +958,10 @@ 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), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, };
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { @@ -950,11 +973,10 @@ 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), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, };
static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { @@ -966,11 +988,10 @@ 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), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, .set_chan_cfg = sun8i_i2s_set_chan_cfg, + .set_fmt = sun8i_i2s_set_soc_fmt, };
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { @@ -980,32 +1001,30 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .mclk_offset = 1, .bclk_offset = 2, .has_fmt_set_lrck_period = true, - .has_chsel_offset = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .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), - .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, .set_chan_cfg = sun8i_i2s_set_chan_cfg, + .set_fmt = sun8i_i2s_set_soc_fmt, };
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .has_slave_select_bit = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, };
static int sun4i_i2s_init_regmap_fields(struct device *dev, @@ -1041,12 +1060,6 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_lrclk)) return PTR_ERR(i2s->field_fmt_lrclk);
- i2s->field_fmt_mode = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_mode); - if (IS_ERR(i2s->field_fmt_mode)) - return PTR_ERR(i2s->field_fmt_mode); - return 0; }
The patch
ASoC: sun4i-i2s: Move the format configuration to a callback
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 71137bcd0a9a778f9407a3bee46c62fcccee4f83 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:12 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Move the format configuration to a callback
The two main generations of our I2S controller require a slightly different format configuration, mostly because of a quite different register layout and some additional registers being needed on the newer generation.
This used to be controlled through a bunch of booleans, however this proved to be quite impractical, especially since a bunch of SoCs forgot to set those parameters and therefore were broken from that point of view.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/dc818644c3e40734e7a97247c994b1fca1c3c047.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 199 +++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 93 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 42e45c9a947a..93ea627e2f1f 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -93,6 +93,11 @@ #define SUN8I_I2S_CTRL_BCLK_OUT BIT(18) #define SUN8I_I2S_CTRL_LRCK_OUT BIT(17)
+#define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4) +#define SUN8I_I2S_CTRL_MODE_RIGHT (2 << 4) +#define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) +#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) + #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
@@ -121,9 +126,7 @@ struct sun4i_i2s; * struct sun4i_i2s_quirks - Differences between SoC variants. * * @has_reset: SoC needs reset deasserted. - * @has_slave_select_bit: SoC has a bit to enable slave mode. * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. - * @has_chsel_offset: SoC uses offset for selecting dai operational mode. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. * @mclk_offset: Value by which mclkdiv needs to be adjusted. @@ -133,13 +136,10 @@ struct sun4i_i2s; * @field_fmt_sr: regmap field to set sample resolution. * @field_fmt_bclk: regmap field to set clk polarity. * @field_fmt_lrclk: regmap field to set frame polarity. - * @field_fmt_mode: regmap field to set the operational mode. */ struct sun4i_i2s_quirks { bool has_reset; - bool has_slave_select_bit; bool has_fmt_set_lrck_period; - bool has_chsel_offset; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; unsigned int mclk_offset; @@ -151,12 +151,12 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_sr; struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk; - struct reg_field field_fmt_mode;
s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); int (*set_chan_cfg)(const struct sun4i_i2s *, const struct snd_pcm_hw_params *); + int (*set_fmt)(const struct sun4i_i2s *, unsigned int); };
struct sun4i_i2s { @@ -176,7 +176,6 @@ struct sun4i_i2s { struct regmap_field *field_fmt_sr; struct regmap_field *field_fmt_bclk; struct regmap_field *field_fmt_lrclk; - struct regmap_field *field_fmt_mode;
const struct sun4i_i2s_quirks *variant; }; @@ -465,52 +464,117 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, params_width(params)); }
-static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) { - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); u32 val; - u32 offset = 0; - u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; - u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
/* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: val = SUN4I_I2S_FMT0_FMT_I2S; - offset = 1; break; + case SND_SOC_DAIFMT_LEFT_J: val = SUN4I_I2S_FMT0_FMT_LEFT_J; break; + case SND_SOC_DAIFMT_RIGHT_J: val = SUN4I_I2S_FMT0_FMT_RIGHT_J; break; + default: - dev_err(dai->dev, "Unsupported format: %d\n", - fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; }
- if (i2s->variant->has_chsel_offset) { - /* - * offset being set indicates that we're connected to an i2s - * device, however offset is only used on the sun8i block and - * i2s shares the same setting with the LJ format. Increment - * val so that the bit to value to write is correct. - */ - if (offset > 0) - val++; - /* blck offset determines whether i2s or LJ */ - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); - - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN4I_I2S_FMT0_FMT_MASK, val); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN4I_I2S_CTRL_MODE_MASTER; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = SUN4I_I2S_CTRL_MODE_SLAVE; + break; + + default: + return -EINVAL; } + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_MODE_MASK, val); + return 0; +}
- regmap_field_write(i2s->field_fmt_mode, val); +static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) +{ + u32 mode, val; + u8 offset; + + /* DAI Mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 1; + break; + + case SND_SOC_DAIFMT_LEFT_J: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 0; + break; + + case SND_SOC_DAIFMT_RIGHT_J: + mode = SUN8I_I2S_CTRL_MODE_RIGHT; + offset = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_MODE_MASK, mode); + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, + val); + + return 0; +} + +static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; + u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; + int ret;
/* DAI clock polarity */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -538,50 +602,10 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) regmap_field_write(i2s->field_fmt_bclk, bclk_polarity); regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
- if (i2s->variant->has_slave_select_bit) { - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* BCLK and LRCLK master */ - val = SUN4I_I2S_CTRL_MODE_MASTER; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* BCLK and LRCLK slave */ - val = SUN4I_I2S_CTRL_MODE_SLAVE; - break; - default: - dev_err(dai->dev, "Unsupported slave setting: %d\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - } - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_MODE_MASK, - val); - } else { - /* - * The newer i2s block does not have a slave select bit, - * instead the clk pins are configured as inputs. - */ - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* BCLK and LRCLK master */ - val = SUN8I_I2S_CTRL_BCLK_OUT | - SUN8I_I2S_CTRL_LRCK_OUT; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* BCLK and LRCLK slave */ - val = 0; - break; - default: - dev_err(dai->dev, "Unsupported slave setting: %d\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - } - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN8I_I2S_CTRL_BCLK_OUT | - SUN8I_I2S_CTRL_LRCK_OUT, - val); + ret = i2s->variant->set_fmt(i2s, fmt); + if (ret) { + dev_err(dai->dev, "Unsupported format configuration\n"); + return ret; }
/* Set significant bits in our FIFOs */ @@ -933,11 +957,10 @@ 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), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, };
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { @@ -949,11 +972,10 @@ 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), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, };
static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { @@ -965,11 +987,10 @@ 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), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, .set_chan_cfg = sun8i_i2s_set_chan_cfg, + .set_fmt = sun8i_i2s_set_soc_fmt, };
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { @@ -979,32 +1000,30 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .mclk_offset = 1, .bclk_offset = 2, .has_fmt_set_lrck_period = true, - .has_chsel_offset = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .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), - .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, .set_chan_cfg = sun8i_i2s_set_chan_cfg, + .set_fmt = sun8i_i2s_set_soc_fmt, };
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .has_slave_select_bit = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, };
static int sun4i_i2s_init_regmap_fields(struct device *dev, @@ -1040,12 +1059,6 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_lrclk)) return PTR_ERR(i2s->field_fmt_lrclk);
- i2s->field_fmt_mode = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_mode); - if (IS_ERR(i2s->field_fmt_mode)) - return PTR_ERR(i2s->field_fmt_mode); - return 0; }
From: Maxime Ripard maxime.ripard@bootlin.com
The MCLK divider calculation is currently computing the ideal divider using the oversample rate, the sample rate and the parent rate.
However, since we have access to the frequency is supposed to be running at already, and as it turns out we're using it to compute the oversample rate, we can just use the ratio between the parent rate and the MCLK rate to simplify a bit the formula.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index fbbedb660cc6..3d7f4a97e0ba 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -225,11 +225,10 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, }
static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, - unsigned int oversample_rate, - unsigned int module_rate, - unsigned int sampling_rate) + unsigned long parent_rate, + unsigned long mclk_rate) { - int div = module_rate / sampling_rate / oversample_rate; + int div = parent_rate / mclk_rate; int i;
for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { @@ -308,8 +307,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; }
- mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, - clk_rate, rate); + mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq); if (mclk_div < 0) { dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div); return -EINVAL;
The patch
ASoC: sun4i-i2s: Rework MCLK divider calculation
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 8bcf62b73e5421df94deca95d7d7c152997fe5b4 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:13 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Rework MCLK divider calculation
The MCLK divider calculation is currently computing the ideal divider using the oversample rate, the sample rate and the parent rate.
However, since we have access to the frequency is supposed to be running at already, and as it turns out we're using it to compute the oversample rate, we can just use the ratio between the parent rate and the MCLK rate to simplify a bit the formula.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/dcc5deb2eb650758d268bddd20f60ba58856d024.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 77b7b81daf74..0a5fb9d4b289 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -240,11 +240,10 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, }
static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, - unsigned int oversample_rate, - unsigned int module_rate, - unsigned int sampling_rate) + unsigned long parent_rate, + unsigned long mclk_rate) { - int div = module_rate / sampling_rate / oversample_rate; + int div = parent_rate / mclk_rate; int i;
for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { @@ -323,8 +322,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; }
- mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, - clk_rate, rate); + mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq); if (mclk_div < 0) { dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div); return -EINVAL;
From: Maxime Ripard maxime.ripard@bootlin.com
The BCLK divider should be calculated using the parameters that actually make the BCLK rate: the number of channels, the sampling rate and the sample width.
We've been using the oversample_rate previously because in the former SoCs, the BCLK's parent is MCLK, which in turn is being used to generate the oversample rate, so we end up with something like this:
oversample = mclk_rate / sampling_rate bclk_div = oversample / word_size / channels
So, bclk_div = mclk_rate / sampling_rate / word_size / channels.
And this is actually better, since the oversampling ratio only plays a role because the MCLK is its parent, not because of what BCLK is supposed to be.
Furthermore, that assumption of MCLK being the parent has been broken on newer SoCs, so let's use the proper formula, and have the parent rate as an argument.
Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3") Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Fixes: 66ecce332538 ("ASoC: sun4i-i2s: Add compatibility with A64 codec I2S") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 3d7f4a97e0ba..ee8ee3eb2087 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -208,10 +208,11 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { };
static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, - unsigned int oversample_rate, + unsigned long parent_rate, + unsigned int sampling_rate, unsigned int word_size) { - int div = oversample_rate / word_size / 2; + int div = parent_rate / sampling_rate / word_size / 2; int i;
for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { @@ -300,8 +301,8 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; }
- bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, - word_size); + bclk_div = sun4i_i2s_get_bclk_div(i2s, i2s->mclk_freq, + rate, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL;
The patch
ASoC: sun4i-i2s: Don't use the oversample to calculate BCLK
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 7df8f9a20196072162d9dc8fe99943f2d35f23d5 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:14 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Don't use the oversample to calculate BCLK
The BCLK divider should be calculated using the parameters that actually make the BCLK rate: the number of channels, the sampling rate and the sample width.
We've been using the oversample_rate previously because in the former SoCs, the BCLK's parent is MCLK, which in turn is being used to generate the oversample rate, so we end up with something like this:
oversample = mclk_rate / sampling_rate bclk_div = oversample / word_size / channels
So, bclk_div = mclk_rate / sampling_rate / word_size / channels.
And this is actually better, since the oversampling ratio only plays a role because the MCLK is its parent, not because of what BCLK is supposed to be.
Furthermore, that assumption of MCLK being the parent has been broken on newer SoCs, so let's use the proper formula, and have the parent rate as an argument.
Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3") Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Fixes: 66ecce332538 ("ASoC: sun4i-i2s: Add compatibility with A64 codec I2S") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/c3595e3a9788c2ef2dcc30aa3c8c4953bb5cc249.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 70608fa30bf2..d879db581073 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -222,10 +222,11 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { };
static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, - unsigned int oversample_rate, + unsigned long parent_rate, + unsigned int sampling_rate, unsigned int word_size) { - int div = oversample_rate / word_size / 2; + int div = parent_rate / sampling_rate / word_size / 2; int i;
for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { @@ -315,8 +316,8 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; }
- bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, - word_size); + bclk_div = sun4i_i2s_get_bclk_div(i2s, i2s->mclk_freq, + rate, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL;
From: Maxime Ripard maxime.ripard@bootlin.com
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 --- sound/soc/sunxi/sun4i-i2s.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index ee8ee3eb2087..51be395102b2 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -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,
The patch
ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From fb19739d7f688142b61d0fca476188c4fd9e937a Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:15 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs
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.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 93ea627e2f1f..acfcdb26086a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -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,
From: Maxime Ripard maxime.ripard@bootlin.com
From: Marcus Cooper codekipper@gmail.com
The clock division dividers have changed between the older (A10/A31) and newer (H3, A64, etc) SoCs.
While this was addressed through an offset on some SoCs, it was missing some dividers as well, so the support wasn't perfect. Let's introduce a pointer in the quirk structure for the divider calculation functions to use so we can have the proper range now.
Signed-off-by: Marcus Cooper codekipper@gmail.com [Maxime: Fix the commit log, use a field in the quirk structure] Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 63 +++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 14 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 51be395102b2..8d49ee7d2a95 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -129,8 +129,6 @@ struct sun4i_i2s; * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. - * @mclk_offset: Value by which mclkdiv needs to be adjusted. - * @bclk_offset: Value by which bclkdiv needs to be adjusted. * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. @@ -142,8 +140,6 @@ struct sun4i_i2s_quirks { bool has_fmt_set_lrck_period; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; - unsigned int mclk_offset; - unsigned int bclk_offset;
/* Register fields for i2s */ struct reg_field field_clkdiv_mclk_en; @@ -152,6 +148,11 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk;
+ const struct sun4i_i2s_clk_div *bclk_dividers; + unsigned int num_bclk_dividers; + const struct sun4i_i2s_clk_div *mclk_dividers; + unsigned int num_mclk_dividers; + 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); @@ -208,6 +209,24 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { /* TODO - extend divide ratio supported by newer SoCs */ };
+static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = { + { .div = 1, .val = 1 }, + { .div = 2, .val = 2 }, + { .div = 4, .val = 3 }, + { .div = 6, .val = 4 }, + { .div = 8, .val = 5 }, + { .div = 12, .val = 6 }, + { .div = 16, .val = 7 }, + { .div = 24, .val = 8 }, + { .div = 32, .val = 9 }, + { .div = 48, .val = 10 }, + { .div = 64, .val = 11 }, + { .div = 96, .val = 12 }, + { .div = 128, .val = 13 }, + { .div = 176, .val = 14 }, + { .div = 192, .val = 15 }, +}; + static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) { return i2s->mclk_freq; @@ -223,11 +242,12 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, unsigned int sampling_rate, unsigned int word_size) { + const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; int div = parent_rate / sampling_rate / word_size / 2; int i;
- for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { - const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i]; + for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { + const struct sun4i_i2s_clk_div *bdiv = ÷rs[i];
if (bdiv->div == div) return bdiv->val; @@ -240,11 +260,12 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, unsigned long parent_rate, unsigned long mclk_rate) { + const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers; int div = parent_rate / mclk_rate; int i;
- for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { - const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i]; + for (i = 0; i < i2s->variant->num_mclk_dividers; i++) { + const struct sun4i_i2s_clk_div *mdiv = ÷rs[i];
if (mdiv->div == div) return mdiv->val; @@ -326,10 +347,6 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; }
- /* Adjust the clock division values if needed */ - bclk_div += i2s->variant->bclk_offset; - mclk_div += i2s->variant->mclk_offset; - regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | SUN4I_I2S_CLK_DIV_MCLK(mclk_div)); @@ -969,6 +986,10 @@ 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), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, @@ -985,6 +1006,10 @@ 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), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, @@ -1001,6 +1026,10 @@ 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), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, @@ -1012,14 +1041,16 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, - .mclk_offset = 1, - .bclk_offset = 2, .has_fmt_set_lrck_period = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .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), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, @@ -1036,6 +1067,10 @@ 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), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss,
The patch
ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From c1d3a921d72bd21f266ca28c15213fbe78160a4b Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:16 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
From: Marcus Cooper codekipper@gmail.com
The clock division dividers have changed between the older (A10/A31) and newer (H3, A64, etc) SoCs.
While this was addressed through an offset on some SoCs, it was missing some dividers as well, so the support wasn't perfect. Let's introduce a pointer in the quirk structure for the divider calculation functions to use so we can have the proper range now.
Signed-off-by: Marcus Cooper codekipper@gmail.com [Maxime: Fix the commit log, use a field in the quirk structure] Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/0e5b4abf06cd3202354315201c6af44caeb20236.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 63 ++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 14 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index acfcdb26086a..0a7f1d0f7371 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -129,8 +129,6 @@ struct sun4i_i2s; * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. - * @mclk_offset: Value by which mclkdiv needs to be adjusted. - * @bclk_offset: Value by which bclkdiv needs to be adjusted. * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. @@ -142,8 +140,6 @@ struct sun4i_i2s_quirks { bool has_fmt_set_lrck_period; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; - unsigned int mclk_offset; - unsigned int bclk_offset;
/* Register fields for i2s */ struct reg_field field_clkdiv_mclk_en; @@ -152,6 +148,11 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk;
+ const struct sun4i_i2s_clk_div *bclk_dividers; + unsigned int num_bclk_dividers; + const struct sun4i_i2s_clk_div *mclk_dividers; + unsigned int num_mclk_dividers; + 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); @@ -208,6 +209,24 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { /* TODO - extend divide ratio supported by newer SoCs */ };
+static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = { + { .div = 1, .val = 1 }, + { .div = 2, .val = 2 }, + { .div = 4, .val = 3 }, + { .div = 6, .val = 4 }, + { .div = 8, .val = 5 }, + { .div = 12, .val = 6 }, + { .div = 16, .val = 7 }, + { .div = 24, .val = 8 }, + { .div = 32, .val = 9 }, + { .div = 48, .val = 10 }, + { .div = 64, .val = 11 }, + { .div = 96, .val = 12 }, + { .div = 128, .val = 13 }, + { .div = 176, .val = 14 }, + { .div = 192, .val = 15 }, +}; + static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) { return i2s->mclk_freq; @@ -223,11 +242,12 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, unsigned int sampling_rate, unsigned int word_size) { + const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; int div = parent_rate / sampling_rate / word_size / 2; int i;
- for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { - const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i]; + for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { + const struct sun4i_i2s_clk_div *bdiv = ÷rs[i];
if (bdiv->div == div) return bdiv->val; @@ -240,11 +260,12 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, unsigned long parent_rate, unsigned long mclk_rate) { + const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers; int div = parent_rate / mclk_rate; int i;
- for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { - const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i]; + for (i = 0; i < i2s->variant->num_mclk_dividers; i++) { + const struct sun4i_i2s_clk_div *mdiv = ÷rs[i];
if (mdiv->div == div) return mdiv->val; @@ -326,10 +347,6 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; }
- /* Adjust the clock division values if needed */ - bclk_div += i2s->variant->bclk_offset; - mclk_div += i2s->variant->mclk_offset; - regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | SUN4I_I2S_CLK_DIV_MCLK(mclk_div)); @@ -969,6 +986,10 @@ 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), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, @@ -985,6 +1006,10 @@ 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), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, @@ -1001,6 +1026,10 @@ 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), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, @@ -1012,14 +1041,16 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, - .mclk_offset = 1, - .bclk_offset = 2, .has_fmt_set_lrck_period = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .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), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, @@ -1036,6 +1067,10 @@ 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), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss,
Hi,
On Wed, Aug 21, 2019 at 1:41 AM Mark Brown broonie@kernel.org wrote:
The patch
ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From c1d3a921d72bd21f266ca28c15213fbe78160a4b Mon Sep 17 00:00:00 2001 From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:16 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
From: Marcus Cooper codekipper@gmail.com
The authorship of this patch looks to be wrong. Maybe it's a tooling issue. I imagine it might have happened if Maxime created the patches using `git format-patch` with his @bootlin.com address, then sent them with his @kernel.org address, and `git send-email` swapped out the "From:" header and prepended it to the body.
Either way the "From:" line looks odd in the commit log.
ChenYu
The clock division dividers have changed between the older (A10/A31) and newer (H3, A64, etc) SoCs.
While this was addressed through an offset on some SoCs, it was missing some dividers as well, so the support wasn't perfect. Let's introduce a pointer in the quirk structure for the divider calculation functions to use so we can have the proper range now.
Signed-off-by: Marcus Cooper codekipper@gmail.com [Maxime: Fix the commit log, use a field in the quirk structure] Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/0e5b4abf06cd3202354315201c6af44caeb20236.156624245... Signed-off-by: Mark Brown broonie@kernel.org
On Tue, Aug 27, 2019 at 05:25:21PM +0800, Chen-Yu Tsai wrote:
From: Marcus Cooper codekipper@gmail.com
The authorship of this patch looks to be wrong. Maybe it's a tooling issue. I imagine it might have happened if Maxime created the patches using `git format-patch` with his @bootlin.com address, then sent them with his @kernel.org address, and `git send-email` swapped out the "From:" header and prepended it to the body.
No idea. In any case it's kind of hard to fix at this point since there's a merge in the way. This is why I like using branches for things but Linus doesn't :/
Either way the "From:" line looks odd in the commit log.
This is what git format-patch does when sending stuff via e-mail if the author is different from the sender, it uses that to override things.
From: Maxime Ripard maxime.ripard@bootlin.com
The RX and TX counters registers offset have been swapped, fix that.
Fixes: fa7c0d13cb26 ("ASoC: sunxi: Add Allwinner A10 Digital Audio driver") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 8d49ee7d2a95..08fc04ad3585 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -76,8 +76,8 @@ #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0)
-#define SUN4I_I2S_RX_CNT_REG 0x28 -#define SUN4I_I2S_TX_CNT_REG 0x2c +#define SUN4I_I2S_TX_CNT_REG 0x28 +#define SUN4I_I2S_RX_CNT_REG 0x2c
#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 #define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0)
The patch
ASoC: sun4i-i2s: RX and TX counter registers are swapped
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From cf2c0e1ce9544df42170fb921f12da82dc0cc8d6 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:17 +0200 Subject: [PATCH] ASoC: sun4i-i2s: RX and TX counter registers are swapped
The RX and TX counters registers offset have been swapped, fix that.
Fixes: fa7c0d13cb26 ("ASoC: sunxi: Add Allwinner A10 Digital Audio driver") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/8b26477560ad5fd8f69e037b167c5e61de5c26a3.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 0a7f1d0f7371..53c95e5289f5 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -76,8 +76,8 @@ #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0)
-#define SUN4I_I2S_RX_CNT_REG 0x28 -#define SUN4I_I2S_TX_CNT_REG 0x2c +#define SUN4I_I2S_TX_CNT_REG 0x28 +#define SUN4I_I2S_RX_CNT_REG 0x2c
#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 #define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0)
From: Maxime Ripard maxime.ripard@bootlin.com
The LRCK period field in the FMT0 register holds the number of LRCK period for one channel in I2S mode.
This has been hardcoded to 32, while it really should be the physical width of the format, which creates an improper clock when using a 16bit format, with the i2s controller as LRCK master.
Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 08fc04ad3585..2996beb4f092 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -357,7 +357,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, if (i2s->variant->has_fmt_set_lrck_period) regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, - SUN8I_I2S_FMT0_LRCK_PERIOD(32)); + SUN8I_I2S_FMT0_LRCK_PERIOD(params_physical_width(params)));
return 0; }
On Mon, Aug 19, 2019 at 09:25:18PM +0200, Maxime Ripard wrote:
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
SUN8I_I2S_FMT0_LRCK_PERIOD(32));
SUN8I_I2S_FMT0_LRCK_PERIOD(params_physical_width(params)));
This doesn't build for me:
In file included from sound/soc/sunxi/sun4i-i2s.c:16: sound/soc/sunxi/sun4i-i2s.c: In function ‘sun4i_i2s_set_clk_rate’: sound/soc/sunxi/sun4i-i2s.c:360:57: error: ‘params’ undeclared (first use in this function); did you mean ‘parameq’? SUN8I_I2S_FMT0_LRCK_PERIOD(params_physical_width(params))); ^~~~~~ ./include/linux/regmap.h:75:42: note: in definition of macro ‘regmap_update_bits’ regmap_update_bits_base(map, reg, mask, val, NULL, false, false) ^~~ sound/soc/sunxi/sun4i-i2s.c:360:8: note: in expansion of macro ‘SUN8I_I2S_FMT0_LRCK_PERIOD’ SUN8I_I2S_FMT0_LRCK_PERIOD(params_physical_width(params)));
From: Maxime Ripard maxime.ripard@bootlin.com
The LRCK and BCLK polarity offsets on newer SoCs has been changed, yet the driver didn't take it into account for all of them.
This was taken into account for the H3, but not the A83t. This was handled using a reg_field for the H3.
However, the value in that field will not be the same, so reg_field is not adapted in that case. Let's change for proper calls with the regular values.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 118 ++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 58 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 2996beb4f092..e614c2d52af5 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -46,8 +46,6 @@ #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) -#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1) -#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
#define SUN4I_I2S_FMT1_REG 0x08 #define SUN4I_I2S_FIFO_TX_REG 0x0c @@ -98,8 +96,14 @@ #define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) #define SUN8I_I2S_CTRL_MODE_PCM (0 << 4)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19) #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
#define SUN8I_I2S_INT_STA_REG 0x0c #define SUN8I_I2S_FIFO_TX_REG 0x20 @@ -132,8 +136,6 @@ struct sun4i_i2s; * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. - * @field_fmt_bclk: regmap field to set clk polarity. - * @field_fmt_lrclk: regmap field to set frame polarity. */ struct sun4i_i2s_quirks { bool has_reset; @@ -145,8 +147,6 @@ struct sun4i_i2s_quirks { struct reg_field field_clkdiv_mclk_en; struct reg_field field_fmt_wss; struct reg_field field_fmt_sr; - struct reg_field field_fmt_bclk; - struct reg_field field_fmt_lrclk;
const struct sun4i_i2s_clk_div *bclk_dividers; unsigned int num_bclk_dividers; @@ -176,8 +176,6 @@ struct sun4i_i2s { struct regmap_field *field_clkdiv_mclk_en; struct regmap_field *field_fmt_wss; struct regmap_field *field_fmt_sr; - struct regmap_field *field_fmt_bclk; - struct regmap_field *field_fmt_lrclk;
const struct sun4i_i2s_quirks *variant; }; @@ -498,6 +496,33 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, { u32 val;
+ /* DAI clock polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_NF: + val = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN4I_I2S_FMT0_BCLK_POLARITY_MASK, + val); + /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -545,6 +570,33 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, u32 mode, val; u8 offset;
+ /* DAI clock polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_NF: + val = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, + val); + /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -601,36 +653,8 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; - u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; int ret;
- /* DAI clock polarity */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_IF: - /* Invert both clocks */ - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_IB_NF: - /* Invert bit clock */ - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_NB_IF: - /* Invert frame clock */ - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_NB_NF: - break; - default: - dev_err(dai->dev, "Unsupported clock polarity: %d\n", - fmt & SND_SOC_DAIFMT_INV_MASK); - return -EINVAL; - } - - regmap_field_write(i2s->field_fmt_bclk, bclk_polarity); - regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity); - ret = i2s->variant->set_fmt(i2s, fmt); if (ret) { dev_err(dai->dev, "Unsupported format configuration\n"); @@ -984,8 +1008,6 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1004,8 +1026,6 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1024,8 +1044,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div, @@ -1045,8 +1063,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .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), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div, @@ -1065,8 +1081,6 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1099,18 +1113,6 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_sr)) return PTR_ERR(i2s->field_fmt_sr);
- i2s->field_fmt_bclk = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_bclk); - if (IS_ERR(i2s->field_fmt_bclk)) - return PTR_ERR(i2s->field_fmt_bclk); - - i2s->field_fmt_lrclk = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_lrclk); - if (IS_ERR(i2s->field_fmt_lrclk)) - return PTR_ERR(i2s->field_fmt_lrclk); - return 0; }
The patch
ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 515fcfbc773632e160f4b94e8df8d278a8d704f7 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:19 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs
The LRCK and BCLK polarity offsets on newer SoCs has been changed, yet the driver didn't take it into account for all of them.
This was taken into account for the H3, but not the A83t. This was handled using a reg_field for the H3.
However, the value in that field will not be the same, so reg_field is not adapted in that case. Let's change for proper calls with the regular values.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/9cbdde80a299288878e58225df4d7884e0301348.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 118 ++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 58 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 53c95e5289f5..e3eadfe38aaf 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -46,8 +46,6 @@ #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) -#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1) -#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
#define SUN4I_I2S_FMT1_REG 0x08 #define SUN4I_I2S_FIFO_TX_REG 0x0c @@ -98,8 +96,14 @@ #define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) #define SUN8I_I2S_CTRL_MODE_PCM (0 << 4)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19) #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
#define SUN8I_I2S_INT_STA_REG 0x0c #define SUN8I_I2S_FIFO_TX_REG 0x20 @@ -132,8 +136,6 @@ struct sun4i_i2s; * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. - * @field_fmt_bclk: regmap field to set clk polarity. - * @field_fmt_lrclk: regmap field to set frame polarity. */ struct sun4i_i2s_quirks { bool has_reset; @@ -145,8 +147,6 @@ struct sun4i_i2s_quirks { struct reg_field field_clkdiv_mclk_en; struct reg_field field_fmt_wss; struct reg_field field_fmt_sr; - struct reg_field field_fmt_bclk; - struct reg_field field_fmt_lrclk;
const struct sun4i_i2s_clk_div *bclk_dividers; unsigned int num_bclk_dividers; @@ -176,8 +176,6 @@ struct sun4i_i2s { struct regmap_field *field_clkdiv_mclk_en; struct regmap_field *field_fmt_wss; struct regmap_field *field_fmt_sr; - struct regmap_field *field_fmt_bclk; - struct regmap_field *field_fmt_lrclk;
const struct sun4i_i2s_quirks *variant; }; @@ -498,6 +496,33 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, { u32 val;
+ /* DAI clock polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_NF: + val = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN4I_I2S_FMT0_BCLK_POLARITY_MASK, + val); + /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -545,6 +570,33 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, u32 mode, val; u8 offset;
+ /* DAI clock polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_NF: + val = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, + val); + /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -601,36 +653,8 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; - u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; int ret;
- /* DAI clock polarity */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_IF: - /* Invert both clocks */ - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_IB_NF: - /* Invert bit clock */ - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_NB_IF: - /* Invert frame clock */ - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_NB_NF: - break; - default: - dev_err(dai->dev, "Unsupported clock polarity: %d\n", - fmt & SND_SOC_DAIFMT_INV_MASK); - return -EINVAL; - } - - regmap_field_write(i2s->field_fmt_bclk, bclk_polarity); - regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity); - ret = i2s->variant->set_fmt(i2s, fmt); if (ret) { dev_err(dai->dev, "Unsupported format configuration\n"); @@ -984,8 +1008,6 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1004,8 +1026,6 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1024,8 +1044,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div, @@ -1045,8 +1063,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .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), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div, @@ -1065,8 +1081,6 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .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), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1099,18 +1113,6 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_sr)) return PTR_ERR(i2s->field_fmt_sr);
- i2s->field_fmt_bclk = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_bclk); - if (IS_ERR(i2s->field_fmt_bclk)) - return PTR_ERR(i2s->field_fmt_bclk); - - i2s->field_fmt_lrclk = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_lrclk); - if (IS_ERR(i2s->field_fmt_lrclk)) - return PTR_ERR(i2s->field_fmt_lrclk); - return 0; }
From: Maxime Ripard maxime.ripard@bootlin.com
The LRCK polarity "normal" polarity in the I2S/TDM specs and in the Allwinner datasheet are not the same. In the case where the i2s controller is being used as the LRCK master, it's pretty clear when looked at under a scope.
Let's fix this, and add a comment to clear up as much the confusion as possible.
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 --- sound/soc/sunxi/sun4i-i2s.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index e614c2d52af5..9c9061621b15 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -570,23 +570,29 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, u32 mode, val; u8 offset;
- /* DAI clock polarity */ + /* + * DAI clock polarity + * + * The setup for LRCK contradicts the datasheet, but under a + * scope it's clear that the LRCK polarity is reversed + * compared to the expected polarity on the bus. + */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_IF: /* Invert both clocks */ - val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | - SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; break; case SND_SOC_DAIFMT_IB_NF: /* Invert bit clock */ - val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; break; case SND_SOC_DAIFMT_NB_IF: /* Invert frame clock */ - val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + val = 0; break; case SND_SOC_DAIFMT_NB_NF: - val = 0; + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; break; default: return -EINVAL;
The patch
ASoC: sun4i-i2s: Fix the LRCK polarity
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From dd657eae8164f7e4bafe8b875031a7c6c50646a9 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:20 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Fix the LRCK polarity
The LRCK polarity "normal" polarity in the I2S/TDM specs and in the Allwinner datasheet are not the same. In the case where the i2s controller is being used as the LRCK master, it's pretty clear when looked at under a scope.
Let's fix this, and add a comment to clear up as much the confusion as possible.
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/e03fb6b2a916223070b9f18405b0ef117a452ff4.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index e3eadfe38aaf..29b5eacd3abe 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -570,23 +570,29 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, u32 mode, val; u8 offset;
- /* DAI clock polarity */ + /* + * DAI clock polarity + * + * The setup for LRCK contradicts the datasheet, but under a + * scope it's clear that the LRCK polarity is reversed + * compared to the expected polarity on the bus. + */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_IF: /* Invert both clocks */ - val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | - SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; break; case SND_SOC_DAIFMT_IB_NF: /* Invert bit clock */ - val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; break; case SND_SOC_DAIFMT_NB_IF: /* Invert frame clock */ - val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + val = 0; break; case SND_SOC_DAIFMT_NB_NF: - val = 0; + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; break; default: return -EINVAL;
From: Maxime Ripard maxime.ripard@bootlin.com
The A83t has the same bit fields offsets than the A10 and A31, while this was the first device with the new layout, fix that.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 9c9061621b15..b5c9774e2f60 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1048,8 +1048,8 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), - .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), - .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div,
The patch
ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 2e04fc4dbf50195262aa5a2ae6d35baa5b598cae Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:21 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t
The A83t has the same bit fields offsets than the A10 and A31, while this was the first device with the new layout, fix that.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/d93f0943cc39d880750daf459a0eeab34c63518e.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 29b5eacd3abe..59d809df8d2a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1048,8 +1048,8 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), - .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), - .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div,
From: Maxime Ripard maxime.ripard@bootlin.com
The A83t, unlike previous SoCs, has the MCLK enable bit at the 8th bit of the CLK_DIV register, unlike what is declared in the driver.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index b5c9774e2f60..5dd742f24a7e 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1047,7 +1047,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .bclk_dividers = sun8i_i2s_clk_div,
The patch
ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From bf943d527987c38f6fb11f9515e0cf2839286eb8 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:22 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t
The A83t, unlike previous SoCs, has the MCLK enable bit at the 8th bit of the CLK_DIV register, unlike what is declared in the driver.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/43b07f8cd8e0e280c64ce61d57c307678c923e9b.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 59d809df8d2a..0fce3c476772 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1047,7 +1047,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .bclk_dividers = sun8i_i2s_clk_div,
From: Maxime Ripard maxime.ripard@bootlin.com
Unlike the previous SoCs, the A83t, like the newer ones, need the LRCK bitfield to be set. Let's add it.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 5dd742f24a7e..65bc296abb37 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1047,6 +1047,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, + .has_fmt_set_lrck_period = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
The patch
ASoC: sun4i-i2s: Fix the LRCK period on A83t
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 69e450e50ca6dde566f3ac3f2c329fb0492441ef Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:23 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Fix the LRCK period on A83t
Unlike the previous SoCs, the A83t, like the newer ones, need the LRCK bitfield to be set. Let's add it.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/6a0ee0bc1375bcb53840d3fb2d2f3d9732b8e57e.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 0fce3c476772..9468584f4eb0 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1047,6 +1047,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, + .has_fmt_set_lrck_period = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
From: Maxime Ripard maxime.ripard@bootlin.com
The A83t and H3 have the same quirks, so it doesn't make sense to duplicate the quirks structure.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 65bc296abb37..5dcbab0b4bcb 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1062,25 +1062,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .set_fmt = sun8i_i2s_set_soc_fmt, };
-static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { - .has_reset = true, - .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, - .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, - .has_fmt_set_lrck_period = true, - .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), - .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), - .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), - .bclk_dividers = sun8i_i2s_clk_div, - .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), - .mclk_dividers = sun8i_i2s_clk_div, - .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), - .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, - .set_fmt = sun8i_i2s_set_soc_fmt, -}; - static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, @@ -1264,7 +1245,7 @@ static const struct of_device_id sun4i_i2s_match[] = { }, { .compatible = "allwinner,sun8i-h3-i2s", - .data = &sun8i_h3_i2s_quirks, + .data = &sun8i_a83t_i2s_quirks, }, { .compatible = "allwinner,sun50i-a64-codec-i2s",
The patch
ASoC: sun4i-i2s: Remove duplicated quirks structure
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 3e9acd7ac6933cdc20c441bbf9a38ed9e42e1490 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:24 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Remove duplicated quirks structure
The A83t and H3 have the same quirks, so it doesn't make sense to duplicate the quirks structure.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/5ade5de27d23918c5ef30387c23aead951d5ad64.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 9468584f4eb0..4c636f1cf7dc 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1062,25 +1062,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .set_fmt = sun8i_i2s_set_soc_fmt, };
-static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { - .has_reset = true, - .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, - .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, - .has_fmt_set_lrck_period = true, - .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), - .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), - .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), - .bclk_dividers = sun8i_i2s_clk_div, - .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), - .mclk_dividers = sun8i_i2s_clk_div, - .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), - .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, - .set_fmt = sun8i_i2s_set_soc_fmt, -}; - static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, @@ -1262,7 +1243,7 @@ static const struct of_device_id sun4i_i2s_match[] = { }, { .compatible = "allwinner,sun8i-h3-i2s", - .data = &sun8i_h3_i2s_quirks, + .data = &sun8i_a83t_i2s_quirks, }, { .compatible = "allwinner,sun50i-a64-codec-i2s",
From: Maxime Ripard maxime.ripard@bootlin.com
The channels number have been hardcoded to 2 so far, while the controller supports more than that.
Remove the instance where it has been hardcoded to compute the BCLK divider, and pass it through as an argument to ease further support of more channels.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 5dcbab0b4bcb..905e9bd16024 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -238,10 +238,11 @@ static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, unsigned long parent_rate, unsigned int sampling_rate, + unsigned int channels, unsigned int word_size) { const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; - int div = parent_rate / sampling_rate / word_size / 2; + int div = parent_rate / sampling_rate / word_size / channels; int i;
for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { @@ -286,6 +287,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, + unsigned int channels, unsigned int word_size) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -333,7 +335,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, - rate, word_size); + rate, channels, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; @@ -488,7 +490,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, regmap_field_write(i2s->field_fmt_sr, sr);
return sun4i_i2s_set_clk_rate(dai, params_rate(params), - params_width(params)); + 2, params_width(params)); }
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
The patch
ASoC: sun4i-i2s: Pass the channels number as an argument
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 0083a507a78fdfa868acc0709408b59e72488a61 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:25 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Pass the channels number as an argument
The channels number have been hardcoded to 2 so far, while the controller supports more than that.
Remove the instance where it has been hardcoded to compute the BCLK divider, and pass it through as an argument to ease further support of more channels.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/48887cf7abfaab6597db233b24d7a088a913e48a.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 4c636f1cf7dc..6b172dfbc25d 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -238,10 +238,11 @@ static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, unsigned long parent_rate, unsigned int sampling_rate, + unsigned int channels, unsigned int word_size) { const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; - int div = parent_rate / sampling_rate / word_size / 2; + int div = parent_rate / sampling_rate / word_size / channels; int i;
for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { @@ -286,6 +287,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, + unsigned int channels, unsigned int word_size) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -333,7 +335,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, - rate, word_size); + rate, channels, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; @@ -488,7 +490,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, regmap_field_write(i2s->field_fmt_sr, sr);
return sun4i_i2s_set_clk_rate(dai, params_rate(params), - params_width(params)); + 2, params_width(params)); }
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
From: Maxime Ripard maxime.ripard@bootlin.com
We've been limited to 2 channels in the driver while the controller supports from 1 to 8 channels, in both capture and playback. let's remove the hardcoded checks and numbers, and extend the range of channel numbers we can use.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 905e9bd16024..0dac09814b65 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -400,9 +400,6 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, { unsigned int channels = params_channels(params);
- if (channels != 2) - return -EINVAL; - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); @@ -423,9 +420,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, { unsigned int channels = params_channels(params);
- if (channels != 2) - return -EINVAL; - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210); @@ -458,6 +452,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int channels = params_channels(params); int ret, sr, wss; u32 width;
@@ -490,7 +485,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, regmap_field_write(i2s->field_fmt_sr, sr);
return sun4i_i2s_set_clk_rate(dai, params_rate(params), - 2, params_width(params)); + channels, params_width(params)); }
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, @@ -814,15 +809,15 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = { .probe = sun4i_i2s_dai_probe, .capture = { .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .playback = { .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, },
The patch
ASoC: sun4i-i2s: Support more channels
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From bbf9a127abca4aac5cc75f882bc7efcc398e86ae Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:26 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Support more channels
We've been limited to 2 channels in the driver while the controller supports from 1 to 8 channels, in both capture and playback. let's remove the hardcoded checks and numbers, and extend the range of channel numbers we can use.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/27d9de5cd56f3a544851b8cd8af08bf836d19637.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 6b172dfbc25d..9e691baee1e8 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -400,9 +400,6 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, { unsigned int channels = params_channels(params);
- if (channels != 2) - return -EINVAL; - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); @@ -423,9 +420,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, { unsigned int channels = params_channels(params);
- if (channels != 2) - return -EINVAL; - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210); @@ -458,6 +452,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int channels = params_channels(params); int ret, sr, wss; u32 width;
@@ -490,7 +485,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, regmap_field_write(i2s->field_fmt_sr, sr);
return sun4i_i2s_set_clk_rate(dai, params_rate(params), - 2, params_width(params)); + channels, params_width(params)); }
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, @@ -814,15 +809,15 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = { .probe = sun4i_i2s_dai_probe, .capture = { .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .playback = { .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, },
From: Maxime Ripard maxime.ripard@bootlin.com
The i2s controller supports TDM, for up to 8 slots. Let's support the TDM API.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 40 ++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 0dac09814b65..4f76daeaaed7 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -168,6 +168,8 @@ struct sun4i_i2s { struct reset_control *rst;
unsigned int mclk_freq; + unsigned int slots; + unsigned int slot_width;
struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; @@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, - unsigned int channels, + unsigned int slots, unsigned int word_size) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, - rate, channels, word_size); + rate, slots, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; @@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, const struct snd_pcm_hw_params *params) { unsigned int channels = params_channels(params); + unsigned int slots = channels; + + if (i2s->slots) + slots = i2s->slots;
/* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); @@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); @@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int word_size = params_width(params); unsigned int channels = params_channels(params); + unsigned int slots = channels; int ret, sr, wss; u32 width;
+ if (i2s->slots) + slots = i2s->slots; + + if (i2s->slot_width) + word_size = i2s->slot_width; + ret = i2s->variant->set_chan_cfg(i2s, params); if (ret < 0) { dev_err(dai->dev, "Invalid channel configuration\n"); @@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (sr < 0) return -EINVAL;
- wss = i2s->variant->get_wss(i2s, params_width(params)); + wss = i2s->variant->get_wss(i2s, word_size); if (wss < 0) return -EINVAL;
regmap_field_write(i2s->field_fmt_wss, wss); regmap_field_write(i2s->field_fmt_sr, sr);
- return sun4i_i2s_set_clk_rate(dai, params_rate(params), - channels, params_width(params)); + return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size); }
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, @@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; }
+static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + if (slots > 8) + return -EINVAL; + + i2s->slots = slots; + i2s->slot_width = slot_width; + + return 0; +} + static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk, + .set_tdm_slot = sun4i_i2s_set_tdm_slot, .trigger = sun4i_i2s_trigger, };
Hi, Maxime,
On 8/19/19 10:25 PM, Maxime Ripard wrote:
From: Maxime Ripard maxime.ripard@bootlin.com
The i2s controller supports TDM, for up to 8 slots. Let's support the TDM API.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com
sound/soc/sunxi/sun4i-i2s.c | 40 ++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 0dac09814b65..4f76daeaaed7 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -168,6 +168,8 @@ struct sun4i_i2s { struct reset_control *rst;
unsigned int mclk_freq;
unsigned int slots;
unsigned int slot_width;
struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data;
@@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate,
unsigned int channels,
{ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);unsigned int slots, unsigned int word_size)
@@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
rate, channels, word_size);
if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL;rate, slots, word_size);
@@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, const struct snd_pcm_hw_params *params) { unsigned int channels = params_channels(params);
unsigned int slots = channels;
if (i2s->slots)
slots = i2s->slots;
/* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
@@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels));
@@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int word_size = params_width(params); unsigned int channels = params_channels(params);
unsigned int slots = channels; int ret, sr, wss; u32 width;
if (i2s->slots)
slots = i2s->slots;
if (i2s->slot_width)
word_size = i2s->slot_width;
ret = i2s->variant->set_chan_cfg(i2s, params); if (ret < 0) { dev_err(dai->dev, "Invalid channel configuration\n");
@@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (sr < 0) return -EINVAL;
- wss = i2s->variant->get_wss(i2s, params_width(params));
wss = i2s->variant->get_wss(i2s, word_size); if (wss < 0) return -EINVAL;
regmap_field_write(i2s->field_fmt_wss, wss); regmap_field_write(i2s->field_fmt_sr, sr);
- return sun4i_i2s_set_clk_rate(dai, params_rate(params),
channels, params_width(params));
return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size); }
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
@@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; }
+static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width)
+{
- struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- if (slots > 8)
return -EINVAL;
- i2s->slots = slots;
- i2s->slot_width = slot_width;
- return 0;
+}
- static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk,
- .set_tdm_slot = sun4i_i2s_set_tdm_slot, .trigger = sun4i_i2s_trigger, };
it seems like you forgot to implement sun4i_i2s_dai_ops.set_bclk_ratio because, as I far as I understand, it should alter tdm slots functionality indirectly.
Thank you, SS
Hi,
On Tue, Aug 20, 2019 at 08:46:30AM +0300, Sergey Suloev wrote:
Hi, Maxime,
On 8/19/19 10:25 PM, Maxime Ripard wrote:
From: Maxime Ripard maxime.ripard@bootlin.com
The i2s controller supports TDM, for up to 8 slots. Let's support the TDM API.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com
sound/soc/sunxi/sun4i-i2s.c | 40 ++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 0dac09814b65..4f76daeaaed7 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -168,6 +168,8 @@ struct sun4i_i2s { struct reset_control *rst; unsigned int mclk_freq;
- unsigned int slots;
- unsigned int slot_width; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data;
@@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate,
unsigned int channels,
{ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);unsigned int slots, unsigned int word_size)
@@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
rate, channels, word_size);
if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL;rate, slots, word_size);
@@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, const struct snd_pcm_hw_params *params) { unsigned int channels = params_channels(params);
- unsigned int slots = channels;
- if (i2s->slots)
/* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);slots = i2s->slots;
@@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels));
@@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- unsigned int word_size = params_width(params); unsigned int channels = params_channels(params);
- unsigned int slots = channels; int ret, sr, wss; u32 width;
- if (i2s->slots)
slots = i2s->slots;
- if (i2s->slot_width)
word_size = i2s->slot_width;
- ret = i2s->variant->set_chan_cfg(i2s, params); if (ret < 0) { dev_err(dai->dev, "Invalid channel configuration\n");
@@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (sr < 0) return -EINVAL;
- wss = i2s->variant->get_wss(i2s, params_width(params));
- wss = i2s->variant->get_wss(i2s, word_size); if (wss < 0) return -EINVAL; regmap_field_write(i2s->field_fmt_wss, wss); regmap_field_write(i2s->field_fmt_sr, sr);
- return sun4i_i2s_set_clk_rate(dai, params_rate(params),
channels, params_width(params));
- return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size); } static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
@@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } +static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width)
+{
- struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- if (slots > 8)
return -EINVAL;
- i2s->slots = slots;
- i2s->slot_width = slot_width;
- return 0;
+}
- static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk,
- .set_tdm_slot = sun4i_i2s_set_tdm_slot, .trigger = sun4i_i2s_trigger, };
it seems like you forgot to implement sun4i_i2s_dai_ops.set_bclk_ratio because, as I far as I understand, it should alter tdm slots functionality indirectly.
As far as I can see, while this indeed changes a few things on the TDM setup, it's optional, orthogonal and it has a single user in the tree (some intel platform card).
So I'd say that if someone ever needs it, we can have it, but it's not a blocker.
Maxime
-- Maxime Ripard, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
On Wed, Aug 21, 2019 at 02:05:51PM +0200, Maxime Ripard wrote:
On Tue, Aug 20, 2019 at 08:46:30AM +0300, Sergey Suloev wrote:
Please delete unneeded context from mails when replying. Doing this makes it much easier to find your reply in the message, helping ensure it won't be missed by people scrolling through the irrelevant quoted material.
.set_sysclk = sun4i_i2s_set_sysclk,
- .set_tdm_slot = sun4i_i2s_set_tdm_slot, .trigger = sun4i_i2s_trigger, };
it seems like you forgot to implement sun4i_i2s_dai_ops.set_bclk_ratio because, as I far as I understand, it should alter tdm slots functionality indirectly.
As far as I can see, while this indeed changes a few things on the TDM setup, it's optional, orthogonal and it has a single user in the tree (some intel platform card).
So I'd say that if someone ever needs it, we can have it, but it's not a blocker.
Yes, that's a compltely orthogonal callback.
Hi, Maxime,
On 8/21/19 3:05 PM, Maxime Ripard wrote:
Hi,
On Tue, Aug 20, 2019 at 08:46:30AM +0300, Sergey Suloev wrote:
Hi, Maxime,
On 8/19/19 10:25 PM, Maxime Ripard wrote:
From: Maxime Ripard maxime.ripard@bootlin.com
The i2s controller supports TDM, for up to 8 slots. Let's support the TDM API.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com
sound/soc/sunxi/sun4i-i2s.c | 40 ++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 0dac09814b65..4f76daeaaed7 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -168,6 +168,8 @@ struct sun4i_i2s { struct reset_control *rst; unsigned int mclk_freq;
- unsigned int slots;
- unsigned int slot_width; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data;
@@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate,
unsigned int channels,
{ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);unsigned int slots, unsigned int word_size)
@@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
rate, channels, word_size);
if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL;rate, slots, word_size);
@@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, const struct snd_pcm_hw_params *params) { unsigned int channels = params_channels(params);
- unsigned int slots = channels;
- if (i2s->slots)
/* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);slots = i2s->slots;
@@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels));
@@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- unsigned int word_size = params_width(params); unsigned int channels = params_channels(params);
- unsigned int slots = channels; int ret, sr, wss; u32 width;
- if (i2s->slots)
slots = i2s->slots;
- if (i2s->slot_width)
word_size = i2s->slot_width;
- ret = i2s->variant->set_chan_cfg(i2s, params); if (ret < 0) { dev_err(dai->dev, "Invalid channel configuration\n");
@@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (sr < 0) return -EINVAL;
- wss = i2s->variant->get_wss(i2s, params_width(params));
- wss = i2s->variant->get_wss(i2s, word_size); if (wss < 0) return -EINVAL; regmap_field_write(i2s->field_fmt_wss, wss); regmap_field_write(i2s->field_fmt_sr, sr);
- return sun4i_i2s_set_clk_rate(dai, params_rate(params),
channels, params_width(params));
- return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size); } static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
@@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } +static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width)
+{
- struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- if (slots > 8)
return -EINVAL;
- i2s->slots = slots;
- i2s->slot_width = slot_width;
- return 0;
+}
- static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk,
- .set_tdm_slot = sun4i_i2s_set_tdm_slot, .trigger = sun4i_i2s_trigger, };
it seems like you forgot to implement sun4i_i2s_dai_ops.set_bclk_ratio because, as I far as I understand, it should alter tdm slots functionality indirectly.
As far as I can see, while this indeed changes a few things on the TDM setup, it's optional, orthogonal and it has a single user in the tree (some intel platform card).
So I'd say that if someone ever needs it, we can have it, but it's not a blocker.
"orthogonal" meaning that one can achieve the same effect with using "sun4i_i2s_set_tdm_slot" instead of "set_bclk_ratio" ?
For example, for WM8731 codec in "non-USB" master mode should generate BCLK = 64 * FS, and I had to implement "set_bclk_ratio" in order to setup it. Note, that this is 100% mandatory condition for the code to operate in this mode.
Did you mean that now the correct way would be using "sun4i_i2s_set_tdm_slot" instead ?
Thank you
Maxime
-- Maxime Ripard, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
The patch
ASoC: sun4i-i2s: Add support for TDM slots
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 137befe19f310400a8b20fd8a4ce8c4141aafde0 Mon Sep 17 00:00:00 2001
From: Maxime Ripard maxime.ripard@bootlin.com Date: Mon, 19 Aug 2019 21:25:27 +0200 Subject: [PATCH] ASoC: sun4i-i2s: Add support for TDM slots
The i2s controller supports TDM, for up to 8 slots. Let's support the TDM API.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com Link: https://lore.kernel.org/r/26392af30b3e7b31ee48d5b867d45be8675db046.156624245... Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 40 +++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 9e691baee1e8..8326b8cfa569 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -168,6 +168,8 @@ struct sun4i_i2s { struct reset_control *rst;
unsigned int mclk_freq; + unsigned int slots; + unsigned int slot_width;
struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; @@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, - unsigned int channels, + unsigned int slots, unsigned int word_size) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, - rate, channels, word_size); + rate, slots, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; @@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, const struct snd_pcm_hw_params *params) { unsigned int channels = params_channels(params); + unsigned int slots = channels; + + if (i2s->slots) + slots = i2s->slots;
/* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); @@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); @@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int word_size = params_width(params); unsigned int channels = params_channels(params); + unsigned int slots = channels; int ret, sr, wss; u32 width;
+ if (i2s->slots) + slots = i2s->slots; + + if (i2s->slot_width) + word_size = i2s->slot_width; + ret = i2s->variant->set_chan_cfg(i2s, params); if (ret < 0) { dev_err(dai->dev, "Invalid channel configuration\n"); @@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (sr < 0) return -EINVAL;
- wss = i2s->variant->get_wss(i2s, params_width(params)); + wss = i2s->variant->get_wss(i2s, word_size); if (wss < 0) return -EINVAL;
regmap_field_write(i2s->field_fmt_wss, wss); regmap_field_write(i2s->field_fmt_sr, sr);
- return sun4i_i2s_set_clk_rate(dai, params_rate(params), - channels, params_width(params)); + return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size); }
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, @@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; }
+static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + if (slots > 8) + return -EINVAL; + + i2s->slots = slots; + i2s->slot_width = slot_width; + + return 0; +} + static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk, + .set_tdm_slot = sun4i_i2s_set_tdm_slot, .trigger = sun4i_i2s_trigger, };
From: Maxime Ripard maxime.ripard@bootlin.com
In addition to the I2S format, the controller also supports the DSP_* formats.
This requires some extra care on the LRCK period calculation, since the controller, with the PCM formats, require that the value set is no longer the periods of LRCK for a single channel, but for all of them.
Let's add the code to deal with this, and support the DSP_A and DSP_B formats.
Signed-off-by: Maxime Ripard maxime.ripard@bootlin.com --- sound/soc/sunxi/sun4i-i2s.c | 44 ++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 4f76daeaaed7..198e3c580297 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -130,7 +130,6 @@ struct sun4i_i2s; * struct sun4i_i2s_quirks - Differences between SoC variants. * * @has_reset: SoC needs reset deasserted. - * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. * @field_clkdiv_mclk_en: regmap field to enable mclk output. @@ -139,7 +138,6 @@ struct sun4i_i2s; */ struct sun4i_i2s_quirks { bool has_reset; - bool has_fmt_set_lrck_period; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap;
@@ -167,6 +165,7 @@ struct sun4i_i2s { struct regmap *regmap; struct reset_control *rst;
+ unsigned int format; unsigned int mclk_freq; unsigned int slots; unsigned int slot_width; @@ -355,12 +354,6 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
- /* Set sync period */ - if (i2s->variant->has_fmt_set_lrck_period) - regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, - SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, - SUN8I_I2S_FMT0_LRCK_PERIOD(params_physical_width(params))); - return 0; }
@@ -422,6 +415,7 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, { unsigned int channels = params_channels(params); unsigned int slots = channels; + unsigned int lrck_period;
if (i2s->slots) slots = i2s->slots; @@ -445,6 +439,26 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
+ switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + lrck_period = params_physical_width(params) * slots; + break; + + case SND_SOC_DAIFMT_I2S: + lrck_period = params_physical_width(params); + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, + SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN8I_I2S_TX_CHAN_EN_MASK, SUN8I_I2S_TX_CHAN_EN(channels)); @@ -614,6 +628,16 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
/* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + mode = SUN8I_I2S_CTRL_MODE_PCM; + offset = 1; + break; + + case SND_SOC_DAIFMT_DSP_B: + mode = SUN8I_I2S_CTRL_MODE_PCM; + offset = 0; + break; + case SND_SOC_DAIFMT_I2S: mode = SUN8I_I2S_CTRL_MODE_LEFT; offset = 1; @@ -682,6 +706,9 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); + + i2s->format = fmt; + return 0; }
@@ -1072,7 +1099,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .has_fmt_set_lrck_period = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
On Mon, Aug 19, 2019 at 09:25:28PM +0200, Maxime Ripard wrote:
From: Maxime Ripard maxime.ripard@bootlin.com
In addition to the I2S format, the controller also supports the DSP_* formats.
This doesn't seem to apply against current code, please check and resend.
Hi everyone,
On Tue, Aug 20, 2019 at 3:25 AM Maxime Ripard mripard@kernel.org wrote:
From: Maxime Ripard maxime.ripard@bootlin.com
Hi,
This series aims at fixing a number of issues in the current i2s driver, mostly related to the i2s master support and the A83t support. It also uses that occasion to cleanup a few things and simplify the driver. Finally, it builds on those fixes and cleanups to introduce TDM and DSP formats support.
Let me know what you think, Maxime
Marcus Cooper (1): ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
Maxime Ripard (20): ASoC: sun4i-i2s: Register regmap and PCM before our component ASoC: sun4i-i2s: Switch to devm for PCM register ASoC: sun4i-i2s: Replace call to params_channels by local variable ASoC: sun4i-i2s: Move the channel configuration to a callback ASoC: sun4i-i2s: Move the format configuration to a callback ASoC: sun4i-i2s: Rework MCLK divider calculation ASoC: sun4i-i2s: Don't use the oversample to calculate BCLK ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs ASoC: sun4i-i2s: RX and TX counter registers are swapped ASoC: sun4i-i2s: Use the actual format width instead of an hardcoded one ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs ASoC: sun4i-i2s: Fix the LRCK polarity ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t ASoC: sun4i-i2s: Fix the LRCK period on A83t ASoC: sun4i-i2s: Remove duplicated quirks structure
Unfortunately the patches that "fix" support on the A83T actually break it. The confusion stems from the user manual not actually documenting the I2S controller. Instead it documents the TDM controller, which is very similar or the same as the I2S controller in the H3. The I2S controller that we actually support in this driver is not the TDM controller, but three other I2S controllers that are only mentioned in the memory map. Support for this was done by referencing the BSP kernel, which has separate driver instances for each controller instance, both I2S and TDM.
Now to remedy this I could send reverts for all the "A83t" patches, and fixes for all the others that affect the A83t quirks. However the fixes tags existing in the tree would be wrong and confusing. That might be a pain for the stable kernel maintainers.
Any suggestions on how to proceed?
Regards ChenYu
ASoC: sun4i-i2s: Pass the channels number as an argument ASoC: sun4i-i2s: Support more channels ASoC: sun4i-i2s: Add support for TDM slots ASoC: sun4i-i2s: Add support for DSP formats
sound/soc/sunxi/sun4i-i2s.c | 660 ++++++++++++++++++++----------------- 1 file changed, 372 insertions(+), 288 deletions(-)
base-commit: d45331b00ddb179e291766617259261c112db872
git-series 0.9.1
Hi,
On Tue, Aug 27, 2019 at 04:20:24PM +0800, Chen-Yu Tsai wrote:
Hi everyone,
On Tue, Aug 20, 2019 at 3:25 AM Maxime Ripard mripard@kernel.org wrote:
From: Maxime Ripard maxime.ripard@bootlin.com
Hi,
This series aims at fixing a number of issues in the current i2s driver, mostly related to the i2s master support and the A83t support. It also uses that occasion to cleanup a few things and simplify the driver. Finally, it builds on those fixes and cleanups to introduce TDM and DSP formats support.
Let me know what you think, Maxime
Marcus Cooper (1): ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
Maxime Ripard (20): ASoC: sun4i-i2s: Register regmap and PCM before our component ASoC: sun4i-i2s: Switch to devm for PCM register ASoC: sun4i-i2s: Replace call to params_channels by local variable ASoC: sun4i-i2s: Move the channel configuration to a callback ASoC: sun4i-i2s: Move the format configuration to a callback ASoC: sun4i-i2s: Rework MCLK divider calculation ASoC: sun4i-i2s: Don't use the oversample to calculate BCLK ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs ASoC: sun4i-i2s: RX and TX counter registers are swapped ASoC: sun4i-i2s: Use the actual format width instead of an hardcoded one ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs ASoC: sun4i-i2s: Fix the LRCK polarity ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t ASoC: sun4i-i2s: Fix the LRCK period on A83t ASoC: sun4i-i2s: Remove duplicated quirks structure
Unfortunately the patches that "fix" support on the A83T actually break it. The confusion stems from the user manual not actually documenting the I2S controller. Instead it documents the TDM controller, which is very similar or the same as the I2S controller in the H3. The I2S controller that we actually support in this driver is not the TDM controller, but three other I2S controllers that are only mentioned in the memory map. Support for this was done by referencing the BSP kernel, which has separate driver instances for each controller instance, both I2S and TDM.
Now to remedy this I could send reverts for all the "A83t" patches, and fixes for all the others that affect the A83t quirks. However the fixes tags existing in the tree would be wrong and confusing. That might be a pain for the stable kernel maintainers.
Any suggestions on how to proceed?
I've just sent two patches to address that (adding a comment in the process so that hopefully it doesn't happen again).
Let me know if it works, and sorry for the mess :/ Maxime
-- Maxime Ripard, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
participants (4)
-
Chen-Yu Tsai
-
Mark Brown
-
Maxime Ripard
-
Sergey Suloev