2019-08-19 19:26:41

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 00/21] ASoC: sun4i-i2s: Number of fixes and TDM Support

From: Maxime Ripard <[email protected]>

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
--
git-series 0.9.1


2019-08-19 19:26:53

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 02/21] ASoC: sun4i-i2s: Switch to devm for PCM register

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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);
--
git-series 0.9.1

2019-08-19 19:27:06

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 14/21] ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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,
--
git-series 0.9.1

2019-08-19 19:27:09

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 03/21] ASoC: sun4i-i2s: Replace call to params_channels by local variable

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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,
--
git-series 0.9.1

2019-08-19 19:27:17

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 06/21] ASoC: sun4i-i2s: Rework MCLK divider calculation

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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;
--
git-series 0.9.1

2019-08-19 19:27:42

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 11/21] ASoC: sun4i-i2s: Use the actual format width instead of an hardcoded one

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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;
}
--
git-series 0.9.1

2019-08-19 19:28:17

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 17/21] ASoC: sun4i-i2s: Remove duplicated quirks structure

From: Maxime Ripard <[email protected]>

The A83t and H3 have the same quirks, so it doesn't make sense to duplicate
the quirks structure.

Signed-off-by: Maxime Ripard <[email protected]>
---
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",
--
git-series 0.9.1

2019-08-19 19:28:17

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 15/21] ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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,
--
git-series 0.9.1

2019-08-19 19:28:27

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 20/21] ASoC: sun4i-i2s: Add support for TDM slots

From: Maxime Ripard <[email protected]>

The i2s controller supports TDM, for up to 8 slots. Let's support the TDM
API.

Signed-off-by: Maxime Ripard <[email protected]>
---
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,
};

--
git-series 0.9.1

2019-08-19 19:28:29

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 12/21] ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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;
}

--
git-series 0.9.1

2019-08-19 19:28:34

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 21/21] ASoC: sun4i-i2s: Add support for DSP formats

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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),
--
git-series 0.9.1

2019-08-19 19:28:37

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 19/21] ASoC: sun4i-i2s: Support more channels

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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,
},
--
git-series 0.9.1

2019-08-19 19:28:50

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 18/21] ASoC: sun4i-i2s: Pass the channels number as an argument

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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,
--
git-series 0.9.1

2019-08-19 19:28:57

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 04/21] ASoC: sun4i-i2s: Move the channel configuration to a callback

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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)
--
git-series 0.9.1

2019-08-19 19:29:08

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 16/21] ASoC: sun4i-i2s: Fix the LRCK period on A83t

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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),
--
git-series 0.9.1

2019-08-19 19:29:16

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 13/21] ASoC: sun4i-i2s: Fix the LRCK polarity

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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;
--
git-series 0.9.1

2019-08-19 19:29:31

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 10/21] ASoC: sun4i-i2s: RX and TX counter registers are swapped

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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)
--
git-series 0.9.1

2019-08-19 19:29:34

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 08/21] ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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,
--
git-series 0.9.1

2019-08-19 19:29:43

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 09/21] ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs

From: Maxime Ripard <[email protected]>

From: Marcus Cooper <[email protected]>

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 <[email protected]>
[Maxime: Fix the commit log, use a field in the quirk structure]
Signed-off-by: Maxime Ripard <[email protected]>
---
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 = &dividers[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 = &dividers[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,
--
git-series 0.9.1

2019-08-19 19:29:55

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 05/21] ASoC: sun4i-i2s: Move the format configuration to a callback

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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;
}

--
git-series 0.9.1

2019-08-19 19:30:44

by Maxime Ripard

[permalink] [raw]
Subject: [PATCH 07/21] ASoC: sun4i-i2s: Don't use the oversample to calculate BCLK

From: Maxime Ripard <[email protected]>

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 <[email protected]>
---
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;
--
git-series 0.9.1

2019-08-20 05:48:00

by Sergey Suloev

[permalink] [raw]
Subject: Re: [PATCH 20/21] ASoC: sun4i-i2s: Add support for TDM slots

Hi, Maxime,

On 8/19/19 10:25 PM, Maxime Ripard wrote:
> From: Maxime Ripard <[email protected]>
>
> The i2s controller supports TDM, for up to 8 slots. Let's support the TDM
> API.
>
> Signed-off-by: Maxime Ripard <[email protected]>
> ---
> 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,
> };
>


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


2019-08-20 17:41:28

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 11/21] ASoC: sun4i-i2s: Use the actual format width instead of an hardcoded one

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)));


Attachments:
(No filename) (1.04 kB)
signature.asc (499.00 B)
Download all attachments

2019-08-20 17:42:12

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/43b07f8cd8e0e280c64ce61d57c307678c923e9b.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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,
--
2.20.1

2019-08-20 17:42:23

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Don't use the oversample to calculate BCLK" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/c3595e3a9788c2ef2dcc30aa3c8c4953bb5cc249.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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;
--
2.20.1

2019-08-20 17:42:32

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Replace call to params_channels by local variable" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/c0faaac69ad40248f24eed3c3b2fa1ccc4a85b70.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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,
--
2.20.1

2019-08-20 17:42:38

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Move the format configuration to a callback" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/dc818644c3e40734e7a97247c994b1fca1c3c047.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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;
}

--
2.20.1

2019-08-20 17:42:40

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Move the channel configuration to a callback" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/6414463de69584e8227fa495b13aa5f4798e1f0e.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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)
--
2.20.1

2019-08-20 17:42:57

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/0b6665be216b3bd0e7bc43724818f05f3f8ee881.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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,
--
2.20.1

2019-08-20 17:43:01

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: RX and TX counter registers are swapped" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/8b26477560ad5fd8f69e037b167c5e61de5c26a3.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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)
--
2.20.1

2019-08-20 17:43:19

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs" to the asoc tree

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 <[email protected]>
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 <[email protected]>

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 <[email protected]>
[Maxime: Fix the commit log, use a field in the quirk structure]
Signed-off-by: Maxime Ripard <[email protected]>
Link: https://lore.kernel.org/r/0e5b4abf06cd3202354315201c6af44caeb20236.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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 = &dividers[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 = &dividers[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,
--
2.20.1

2019-08-20 17:43:39

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Fix the LRCK polarity" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/e03fb6b2a916223070b9f18405b0ef117a452ff4.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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;
--
2.20.1

2019-08-20 17:44:22

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Pass the channels number as an argument" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/48887cf7abfaab6597db233b24d7a088a913e48a.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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,
--
2.20.1

2019-08-20 17:44:36

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Switch to devm for PCM register" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/606d271187091e858e8c15e20555af0b79798fe1.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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);
--
2.20.1

2019-08-20 17:44:41

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Rework MCLK divider calculation" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/dcc5deb2eb650758d268bddd20f60ba58856d024.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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;
--
2.20.1

2019-08-20 17:44:43

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/9cbdde80a299288878e58225df4d7884e0301348.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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;
}

--
2.20.1

2019-08-20 17:45:06

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Fix the LRCK period on A83t" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/6a0ee0bc1375bcb53840d3fb2d2f3d9732b8e57e.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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),
--
2.20.1

2019-08-20 17:45:06

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Remove duplicated quirks structure" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/5ade5de27d23918c5ef30387c23aead951d5ad64.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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",
--
2.20.1

2019-08-20 17:45:16

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/d93f0943cc39d880750daf459a0eeab34c63518e.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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,
--
2.20.1

2019-08-20 17:45:22

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Support more channels" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/27d9de5cd56f3a544851b8cd8af08bf836d19637.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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,
},
--
2.20.1

2019-08-21 12:07:19

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 20/21] ASoC: sun4i-i2s: Add support for TDM slots

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 <[email protected]>
> >
> > The i2s controller supports TDM, for up to 8 slots. Let's support the TDM
> > API.
> >
> > Signed-off-by: Maxime Ripard <[email protected]>
> > ---
> > 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,
> > };
>
> 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


Attachments:
(No filename) (5.16 kB)
signature.asc (235.00 B)
Download all attachments

2019-08-21 12:10:03

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 20/21] ASoC: sun4i-i2s: Add support for TDM slots

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.


Attachments:
(No filename) (997.00 B)
signature.asc (499.00 B)
Download all attachments

2019-08-21 15:09:14

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-i2s: Add support for TDM slots" to the asoc tree

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 <[email protected]>
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 <[email protected]>
Link: https://lore.kernel.org/r/26392af30b3e7b31ee48d5b867d45be8675db046.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <[email protected]>
---
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,
};

--
2.20.1

2019-08-21 15:09:14

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 21/21] ASoC: sun4i-i2s: Add support for DSP formats

On Mon, Aug 19, 2019 at 09:25:28PM +0200, Maxime Ripard wrote:
> From: Maxime Ripard <[email protected]>
>
> 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.


Attachments:
(No filename) (282.00 B)
signature.asc (499.00 B)
Download all attachments

2019-08-23 11:07:19

by Sergey Suloev

[permalink] [raw]
Subject: Re: [PATCH 20/21] ASoC: sun4i-i2s: Add support for TDM slots

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 <[email protected]>
>>>
>>> The i2s controller supports TDM, for up to 8 slots. Let's support the TDM
>>> API.
>>>
>>> Signed-off-by: Maxime Ripard <[email protected]>
>>> ---
>>> 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,
>>> };
>> 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

2019-08-27 08:21:50

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH 00/21] ASoC: sun4i-i2s: Number of fixes and TDM Support

Hi everyone,

On Tue, Aug 20, 2019 at 3:25 AM Maxime Ripard <[email protected]> wrote:
>
> From: Maxime Ripard <[email protected]>
>
> 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

2019-08-27 09:26:59

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: Applied "ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs" to the asoc tree

Hi,

On Wed, Aug 21, 2019 at 1:41 AM Mark Brown <[email protected]> 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 <[email protected]>
> 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 <[email protected]>

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 <[email protected]>
> [Maxime: Fix the commit log, use a field in the quirk structure]
> Signed-off-by: Maxime Ripard <[email protected]>
> Link: https://lore.kernel.org/r/0e5b4abf06cd3202354315201c6af44caeb20236.1566242458.git-series.maxime.ripard@bootlin.com
> Signed-off-by: Mark Brown <[email protected]>

2019-08-27 09:38:01

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 00/21] ASoC: sun4i-i2s: Number of fixes and TDM Support

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 <[email protected]> wrote:
> >
> > From: Maxime Ripard <[email protected]>
> >
> > 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


Attachments:
(No filename) (2.88 kB)
signature.asc (235.00 B)
Download all attachments

2019-08-27 10:49:09

by Mark Brown

[permalink] [raw]
Subject: Re: Applied "ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs" to the asoc tree

On Tue, Aug 27, 2019 at 05:25:21PM +0800, Chen-Yu Tsai wrote:

> > From: Marcus Cooper <[email protected]>

> 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.


Attachments:
(No filename) (828.00 B)
signature.asc (499.00 B)
Download all attachments