[PATCH v4 0/9]ASoC: sun4i-i2s: Updates to the driver

113 views
Skip to first unread message

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:39 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

Hi All,

here is a patch series to add some improvements to the sun4i-i2s driver
found whilst getting slave clocking and hdmi audio working on the newer
SoCs. As the LibreELEC project is progressing extremely well then there
has been some activity getting surround sound working and this is included.

The functionality included with the new patch set has been extended to
cover more sample resolutions, multi-lane data output for HDMI audio
and some bug fixes that have been discovered along the way.

I can see more usage of the tdm property since I last attempted to push
these patches and the examples currently in mainline sort of the opposite
to what I'm trying to achieve. When we first started looking at the i2s
driver, the codecs that we were using allowed for the frame width to be
determined based on the sampling resolution but in most use cases it
seems that a fixed width is required(my highest priority should be to get
HDMI audio support in). We're using the tdm property to override the old
way to calculate the frame width. What I've seen in what has already been
mainlined is that the i2s driver has a frame width that is fixed to 32
bits and this can be overridden using the tdm property.

I still need to investigate the FIFO syncing issues which i've not had a
chance to change or address the concerns that broonie and wens brought up.
This change has been moved to the top of the patch stack.

BR,
CK

---
v4 changes compared to v3 are:
- Moved patches around so that the more controversial of patches are
at the top of the stack.
- Added more details to commit messages.
- Fixed 20bit audio PCM format to use 4 bytes.
- Reduced number of flags used to indicate a new SoC.

v3 changes compared to v2 are:
- added back slave mode changes
- added back the use of tdm properties
- changes to regmap and caching
- removed loopback functionality
- fixes to the channel offset mask

v2 changes compared to v1 are:
- removed slave mode changes which didn't set mclk and bclk div.
- removed use of tdm and now use a dedicated property.
- fix commit message to better explain reason for sign extending
- add divider calculations for newer SoCs.
- add support for multi-lane i2s data output.
- add support for 20, 24 and 32 bit samples.
- add loopback property so blocks can be tested without a codec.


Marcus Cooper (9):
ASoC: sun4i-i2s: Fix sun8i tx channel offset mask
ASoC: sun4i-i2s: Add offset to RX channel select
ASoC: sun4i-i2s: Add regmap field to sign extend sample
ASoC: sun4i-i2s: Reduce quirks for sun8i-h3
ASoC: sun4i-i2s: Add set_tdm_slot functionality
ASoC: sun4i-i2s: Add multi-lane functionality
ASoC: sun4i-i2s: Add multichannel functionality
ASoc: sun4i-i2s: Add 20, 24 and 32 bit support
ASoC: sun4i-i2s: Adjust regmap settings

sound/soc/sunxi/sun4i-i2s.c | 242 ++++++++++++++++++++++++------------
1 file changed, 164 insertions(+), 78 deletions(-)

--
2.21.0

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:40 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

Although not causing any noticeable issues, the mask for the
channel offset is covering too many bits.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index c53bfed8d4c2..90bd3963d8ae 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -106,7 +106,7 @@

#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
-#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 11)
+#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12)
#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12)
#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
--
2.21.0

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:41 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

Whilst testing the capture functionality of the i2s on the newer
SoCs it was noticed that the recording was somewhat distorted.
This was due to the offset not being set correctly on the receiver
side.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 90bd3963d8ae..fd7c37596f21 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -456,6 +456,10 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
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_field_write(i2s->field_fmt_mode, val);
--
2.21.0

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:42 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

On the newer SoCs this is set by default to transfer a 0 after
each sample in each slot. However the platform that this driver
was developed on had the default setting where it padded the
audio gain with zeros. This isn't a problem whilst we have only
support for 16bit audio but with larger sample resolution rates
in the pipeline then it should be fixed to also pad. Without this
the audio gets distorted.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index fd7c37596f21..e2961d8f6e8c 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -134,6 +134,7 @@
* @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_fmt_sext: regmap field to set the sign extension.
* @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.
@@ -159,6 +160,7 @@ 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_fmt_sext;
struct reg_field field_txchanmap;
struct reg_field field_rxchanmap;
struct reg_field field_txchansel;
@@ -183,6 +185,7 @@ 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_fmt_sext;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -342,6 +345,9 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
SUN8I_I2S_FMT0_LRCK_PERIOD(32));

+ /* Set sign extension to pad out LSB with 0 */
+ regmap_field_write(i2s->field_fmt_sext, 0);
+
return 0;
}

@@ -887,6 +893,7 @@ 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_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 8, 8),
.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),
@@ -904,6 +911,7 @@ 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_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 8, 8),
.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),
@@ -944,6 +952,7 @@ 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_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_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),
@@ -1006,6 +1015,12 @@ 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_fmt_sext =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_fmt_sext);
+ if (IS_ERR(i2s->field_fmt_sext))
+ return PTR_ERR(i2s->field_fmt_sext);
+
i2s->field_txchanmap =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_txchanmap);
--
2.21.0

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:42 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

We have a number of flags used to identify the functionality
of the IP block found on the sun8i-h3 and later devices. As it
is only neccessary to identify this new block then replace
these flags with just one.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 23 +++++++----------------
1 file changed, 7 insertions(+), 16 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index e2961d8f6e8c..329883750d6f 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -119,10 +119,7 @@
*
* @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.
+ * @is_h3_i2s_based: This block is similiar to what is found on the h3.
* @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.
@@ -143,10 +140,7 @@
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;
+ bool is_h3_i2s_based;
unsigned int reg_offset_txdata; /* TX FIFO */
const struct regmap_config *sun4i_i2s_regmap;
unsigned int mclk_offset;
@@ -340,7 +334,7 @@ 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)
+ if (i2s->variant->is_h3_i2s_based)
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
SUN8I_I2S_FMT0_LRCK_PERIOD(32));
@@ -366,7 +360,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}

- if (i2s->variant->has_chcfg) {
+ if (i2s->variant->is_h3_i2s_based) {
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));
@@ -386,7 +380,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
regmap_field_write(i2s->field_rxchansel,
SUN4I_I2S_CHAN_SEL(params_channels(params)));

- if (i2s->variant->has_chsel_tx_chen)
+ if (i2s->variant->is_h3_i2s_based)
regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
SUN8I_I2S_TX_CHAN_EN_MASK,
SUN8I_I2S_TX_CHAN_EN(channels));
@@ -449,7 +443,7 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}

- if (i2s->variant->has_chsel_offset) {
+ if (i2s->variant->is_h3_i2s_based) {
/*
* offset being set indicates that we're connected to an i2s
* device, however offset is only used on the sun8i block and
@@ -942,10 +936,7 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.mclk_offset = 1,
.bclk_offset = 2,
.fmt_offset = 3,
- .has_fmt_set_lrck_period = true,
- .has_chcfg = true,
- .has_chsel_tx_chen = true,
- .has_chsel_offset = true,
+ .is_h3_i2s_based = 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.21.0

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:43 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

Some codecs require a different amount of a bit clocks per frame than
what is calculated by the sample width. Use the tdm slot bindings to
provide this mechanism.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 329883750d6f..bca73b3c0d74 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -186,6 +186,9 @@ struct sun4i_i2s {
struct regmap_field *field_rxchansel;

const struct sun4i_i2s_quirks *variant;
+
+ unsigned int tdm_slots;
+ unsigned int slot_width;
};

struct sun4i_i2s_clk_div {
@@ -337,7 +340,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
if (i2s->variant->is_h3_i2s_based)
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(word_size));

/* Set sign extension to pad out LSB with 0 */
regmap_field_write(i2s->field_fmt_sext, 0);
@@ -414,7 +417,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
sr + i2s->variant->fmt_offset);

return sun4i_i2s_set_clk_rate(dai, params_rate(params),
- params_width(params));
+ i2s->tdm_slots ?
+ i2s->slot_width : params_width(params));
}

static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -657,11 +661,25 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
return 0;
}

+static int sun4i_i2s_set_dai_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int width)
+{
+ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ i2s->tdm_slots = slots;
+
+ i2s->slot_width = 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,
.trigger = sun4i_i2s_trigger,
+ .set_tdm_slot = sun4i_i2s_set_dai_tdm_slot,
};

static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
--
2.21.0

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:45 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

The i2s block supports multi-lane i2s output however this functionality
is only possible in earlier SoCs where the pins are exposed and for
the i2s block used for HDMI audio on the later SoCs.

To enable this functionality, an optional property has been added to
the bindings.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 44 ++++++++++++++++++++++++++++++++-----
1 file changed, 39 insertions(+), 5 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index bca73b3c0d74..75217fb52bfa 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -23,7 +23,7 @@

#define SUN4I_I2S_CTRL_REG 0x00
#define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
-#define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
+#define SUN4I_I2S_CTRL_SDO_EN(lines) (((1 << lines) - 1) << 8)
#define SUN4I_I2S_CTRL_MODE_MASK BIT(5)
#define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5)
#define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
@@ -355,14 +355,23 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
int sr, wss, channels;
u32 width;
+ int lines;

channels = params_channels(params);
- if (channels != 2) {
+ if ((channels > dai->driver->playback.channels_max) ||
+ (channels < dai->driver->playback.channels_min)) {
dev_err(dai->dev, "Unsupported number of channels: %d\n",
channels);
return -EINVAL;
}

+ lines = (channels + 1) / 2;
+
+ /* Enable the required output lines */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN4I_I2S_CTRL_SDO_EN_MASK,
+ SUN4I_I2S_CTRL_SDO_EN(lines));
+
if (i2s->variant->is_h3_i2s_based) {
regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
@@ -373,8 +382,19 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
}

/* Map the channels for playback and capture */
- regmap_field_write(i2s->field_txchanmap, 0x76543210);
regmap_field_write(i2s->field_rxchanmap, 0x00003210);
+ regmap_field_write(i2s->field_txchanmap, 0x10);
+ if (i2s->variant->is_h3_i2s_based) {
+ if (channels > 2)
+ regmap_write(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_MAP_REG+4, 0x32);
+ if (channels > 4)
+ regmap_write(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_MAP_REG+8, 0x54);
+ if (channels > 6)
+ regmap_write(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_MAP_REG+12, 0x76);
+ }

/* Configure the channels */
regmap_field_write(i2s->field_txchansel,
@@ -1057,9 +1077,10 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev,
static int sun4i_i2s_probe(struct platform_device *pdev)
{
struct sun4i_i2s *i2s;
+ struct snd_soc_dai_driver *soc_dai;
struct resource *res;
void __iomem *regs;
- int irq, ret;
+ int irq, ret, val;

i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
@@ -1126,6 +1147,19 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
i2s->capture_dma_data.maxburst = 8;

+ soc_dai = devm_kmemdup(&pdev->dev, &sun4i_i2s_dai,
+ sizeof(*soc_dai), GFP_KERNEL);
+ if (!soc_dai) {
+ ret = -ENOMEM;
+ goto err_pm_disable;
+ }
+
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "allwinner,playback-channels", &val)) {
+ if (val >= 2 && val <= 8)
+ soc_dai->playback.channels_max = val;
+ }
+
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
ret = sun4i_i2s_runtime_resume(&pdev->dev);
@@ -1135,7 +1169,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)

ret = devm_snd_soc_register_component(&pdev->dev,
&sun4i_i2s_component,
- &sun4i_i2s_dai, 1);
+ soc_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Could not register DAI\n");
goto err_suspend;
--
2.21.0

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:46 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

The i2s block can be used to pass PCM data over multiple channels
and is sometimes used for the audio side of an HDMI connection.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 121 +++++++++++++++++++-----------------
1 file changed, 64 insertions(+), 57 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 75217fb52bfa..3549a87ed9e9 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -189,6 +189,7 @@ struct sun4i_i2s {

unsigned int tdm_slots;
unsigned int slot_width;
+ unsigned int offset;
};

struct sun4i_i2s_clk_div {
@@ -358,56 +359,71 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
int lines;

channels = params_channels(params);
- if ((channels > dai->driver->playback.channels_max) ||
- (channels < dai->driver->playback.channels_min)) {
- dev_err(dai->dev, "Unsupported number of channels: %d\n",
- channels);
- return -EINVAL;
- }
-
- lines = (channels + 1) / 2;
-
- /* Enable the required output lines */
- regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
- SUN4I_I2S_CTRL_SDO_EN_MASK,
- SUN4I_I2S_CTRL_SDO_EN(lines));
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if ((channels > dai->driver->playback.channels_max) ||
+ (channels < dai->driver->playback.channels_min)) {
+ dev_err(dai->dev, "Unsupported number of channels: %d\n",
+ channels);
+ return -EINVAL;
+ }

- if (i2s->variant->is_h3_i2s_based) {
- 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));
- }
+ lines = (channels + 1) / 2;

- /* Map the channels for playback and capture */
- regmap_field_write(i2s->field_rxchanmap, 0x00003210);
- regmap_field_write(i2s->field_txchanmap, 0x10);
- if (i2s->variant->is_h3_i2s_based) {
- if (channels > 2)
- regmap_write(i2s->regmap,
- SUN8I_I2S_TX_CHAN_MAP_REG+4, 0x32);
- if (channels > 4)
- regmap_write(i2s->regmap,
- SUN8I_I2S_TX_CHAN_MAP_REG+8, 0x54);
- if (channels > 6)
- regmap_write(i2s->regmap,
- SUN8I_I2S_TX_CHAN_MAP_REG+12, 0x76);
+ /* Enable the required output lines */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN4I_I2S_CTRL_SDO_EN_MASK,
+ SUN4I_I2S_CTRL_SDO_EN(lines));
+
+ if (i2s->variant->is_h3_i2s_based)
+ 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_field_write(i2s->field_txchanmap, 0x10);
+ /* Configure the channels */
+ regmap_field_write(i2s->field_txchansel, SUN4I_I2S_CHAN_SEL(2));
+
+ if (i2s->variant->is_h3_i2s_based) {
+ u32 chan_sel = SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset) | 0x1;
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+ chan_sel | 0x30);
+
+ if (channels > 2) {
+ regmap_write(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_MAP_REG+4, 0x32);
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG+4,
+ chan_sel | 0x30);
+ }
+ if (channels > 4) {
+ regmap_write(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_MAP_REG+8, 0x54);
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG+8,
+ chan_sel | 0x30);
+ }
+ if (channels > 6) {
+ regmap_write(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_MAP_REG+12, 0x76);
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG+12,
+ chan_sel | 0x30);
+ }
+ }
+ } else {
+ /* Map the channels for capture */
+ regmap_field_write(i2s->field_rxchanmap, 0x00003210);
+ regmap_field_write(i2s->field_rxchansel,
+ SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
+ if (i2s->variant->is_h3_i2s_based) {
+ 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_RX_CHAN_SEL_REG,
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
+ SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset));
+ }
}

- /* Configure the channels */
- regmap_field_write(i2s->field_txchansel,
- SUN4I_I2S_CHAN_SEL(params_channels(params)));
-
- regmap_field_write(i2s->field_rxchansel,
- SUN4I_I2S_CHAN_SEL(params_channels(params)));
-
- if (i2s->variant->is_h3_i2s_based)
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN8I_I2S_TX_CHAN_EN_MASK,
- SUN8I_I2S_TX_CHAN_EN(channels));
-
switch (params_physical_width(params)) {
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -445,7 +461,6 @@ 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 val;
- u32 offset = 0;
u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;

@@ -453,7 +468,7 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
val = SUN4I_I2S_FMT0_FMT_I2S;
- offset = 1;
+ i2s->offset = 1;
break;
case SND_SOC_DAIFMT_LEFT_J:
val = SUN4I_I2S_FMT0_FMT_LEFT_J;
@@ -474,16 +489,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
* i2s shares the same setting with the LJ format. Increment
* val so that the bit to value to write is correct.
*/
- if (offset > 0)
+ if (i2s->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));

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:47 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

Bypass the regmap cache when flushing the i2s FIFOs and modify the tables
to reflect this.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 29 +++++++++--------------------
1 file changed, 9 insertions(+), 20 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 351b8021173b..92828a84902d 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -595,9 +595,11 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
{
/* Flush RX FIFO */
+ regcache_cache_bypass(i2s->regmap, true);
regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
+ regcache_cache_bypass(i2s->regmap, false);

/* Clear RX counter */
regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);
@@ -616,9 +618,11 @@ static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
{
/* Flush TX FIFO */
+ regcache_cache_bypass(i2s->regmap, true);
regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
SUN4I_I2S_FIFO_CTRL_FLUSH_TX,
SUN4I_I2S_FIFO_CTRL_FLUSH_TX);
+ regcache_cache_bypass(i2s->regmap, false);

/* Clear TX counter */
regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0);
@@ -771,13 +775,7 @@ static const struct snd_soc_component_driver sun4i_i2s_component = {

static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg)
{
- switch (reg) {
- case SUN4I_I2S_FIFO_TX_REG:
- return false;
-
- default:
- return true;
- }
+ return true;
}

static bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg)
@@ -796,6 +794,8 @@ static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case SUN4I_I2S_FIFO_RX_REG:
+ case SUN4I_I2S_FIFO_TX_REG:
+ case SUN4I_I2S_FIFO_STA_REG:
case SUN4I_I2S_INT_STA_REG:
case SUN4I_I2S_RX_CNT_REG:
case SUN4I_I2S_TX_CNT_REG:
@@ -806,23 +806,12 @@ static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)
}
}

-static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case SUN8I_I2S_FIFO_TX_REG:
- return false;
-
- default:
- return true;
- }
-}
-
static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
if (reg == SUN8I_I2S_INT_STA_REG)
return true;
if (reg == SUN8I_I2S_FIFO_TX_REG)
- return false;
+ return true;

return sun4i_i2s_volatile_reg(dev, reg);
}
@@ -877,7 +866,7 @@ static const struct regmap_config sun8i_i2s_regmap_config = {
.reg_defaults = sun8i_i2s_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(sun8i_i2s_reg_defaults),
.writeable_reg = sun4i_i2s_wr_reg,
- .readable_reg = sun8i_i2s_rd_reg,
+ .readable_reg = sun4i_i2s_rd_reg,
.volatile_reg = sun8i_i2s_volatile_reg,
};

--
2.21.0

codek...@gmail.com

unread,
Jun 3, 2019, 1:47:47 PM6/3/19
to maxime...@free-electrons.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Marcus Cooper
From: Marcus Cooper <codek...@gmail.com>

Extend the functionality of the driver to include support of 20 and
24 bits per sample for the earlier SoCs.

Newer SoCs can also handle 32bit samples.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
---
sound/soc/sunxi/sun4i-i2s.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 3549a87ed9e9..351b8021173b 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -428,6 +428,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
+ case 20:
+ case 24:
+ case 32:
+ width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
default:
dev_err(dai->dev, "Unsupported physical sample width: %d\n",
params_physical_width(params));
@@ -440,7 +445,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
sr = 0;
wss = 0;
break;
-
+ case 20:
+ sr = 1;
+ wss = 1;
+ break;
+ case 24:
+ sr = 2;
+ wss = 2;
+ break;
+ case 32:
+ sr = 4;
+ wss = 4;
+ break;
default:
dev_err(dai->dev, "Unsupported sample width: %d\n",
params_width(params));
@@ -722,6 +738,13 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}

+#define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+#define SUN8I_FORMATS (SUN4I_FORMATS | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
static struct snd_soc_dai_driver sun4i_i2s_dai = {
.probe = sun4i_i2s_dai_probe,
.capture = {
@@ -729,14 +752,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SUN4I_FORMATS,
},
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SUN4I_FORMATS,
},
.ops = &sun4i_i2s_dai_ops,
.symmetric_rates = 1,
@@ -1161,6 +1184,11 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
goto err_pm_disable;
}

+ if (i2s->variant->is_h3_i2s_based) {
+ soc_dai->playback.formats = SUN8I_FORMATS;
+ soc_dai->capture.formats = SUN8I_FORMATS;
+ }
+
if (!of_property_read_u32(pdev->dev.of_node,
"allwinner,playback-channels", &val)) {
if (val >= 2 && val <= 8)
--
2.21.0

Maxime Ripard

unread,
Jun 4, 2019, 3:34:50 AM6/4/19
to codek...@gmail.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it
On Mon, Jun 03, 2019 at 07:47:27PM +0200, codek...@gmail.com wrote:
> From: Marcus Cooper <codek...@gmail.com>
>
> Although not causing any noticeable issues, the mask for the
> channel offset is covering too many bits.
>
> Signed-off-by: Marcus Cooper <codek...@gmail.com>

Acked-by: Maxime Ripard <maxime...@bootlin.com>

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
signature.asc

Maxime Ripard

unread,
Jun 4, 2019, 3:37:03 AM6/4/19
to codek...@gmail.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it
On Mon, Jun 03, 2019 at 07:47:28PM +0200, codek...@gmail.com wrote:
> From: Marcus Cooper <codek...@gmail.com>
>
> Whilst testing the capture functionality of the i2s on the newer
> SoCs it was noticed that the recording was somewhat distorted.
> This was due to the offset not being set correctly on the receiver
> side.
>
> Signed-off-by: Marcus Cooper <codek...@gmail.com>

signature.asc

Chen-Yu Tsai

unread,
Jun 4, 2019, 3:39:08 AM6/4/19
to Maxime Ripard, Code Kipper, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
On Tue, Jun 4, 2019 at 3:34 PM Maxime Ripard <maxime...@bootlin.com> wrote:
>
> On Mon, Jun 03, 2019 at 07:47:27PM +0200, codek...@gmail.com wrote:
> > From: Marcus Cooper <codek...@gmail.com>
> >
> > Although not causing any noticeable issues, the mask for the
> > channel offset is covering too many bits.
> >
> > Signed-off-by: Marcus Cooper <codek...@gmail.com>
>
> Acked-by: Maxime Ripard <maxime...@bootlin.com>

Would be nice to have

Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3")

But otherwise,

Acked-by: Chen-Yu Tsai <we...@csie.org>

Chen-Yu Tsai

unread,
Jun 4, 2019, 3:39:59 AM6/4/19
to Maxime Ripard, Code Kipper, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
On Tue, Jun 4, 2019 at 3:37 PM Maxime Ripard <maxime...@bootlin.com> wrote:
>
> On Mon, Jun 03, 2019 at 07:47:28PM +0200, codek...@gmail.com wrote:
> > From: Marcus Cooper <codek...@gmail.com>
> >
> > Whilst testing the capture functionality of the i2s on the newer
> > SoCs it was noticed that the recording was somewhat distorted.
> > This was due to the offset not being set correctly on the receiver
> > side.
> >
> > Signed-off-by: Marcus Cooper <codek...@gmail.com>
>
> Acked-by: Maxime Ripard <maxime...@bootlin.com>

Maxime Ripard

unread,
Jun 4, 2019, 3:43:05 AM6/4/19
to codek...@gmail.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it
On Mon, Jun 03, 2019 at 07:47:29PM +0200, codek...@gmail.com wrote:
> From: Marcus Cooper <codek...@gmail.com>
>
> On the newer SoCs this is set by default to transfer a 0 after

Which SoCs?

> each sample in each slot. However the platform that this driver

Which platform?

> was developed on had the default setting where it padded the audio
> gain with zeros. This isn't a problem whilst we have only support
> for 16bit audio but with larger sample resolution rates in the
> pipeline then it should be fixed to also pad. Without this the audio
> gets distorted.
>
> Signed-off-by: Marcus Cooper <codek...@gmail.com>

Once the commit log fixed,
signature.asc

Maxime Ripard

unread,
Jun 4, 2019, 3:46:36 AM6/4/19
to codek...@gmail.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it
On Mon, Jun 03, 2019 at 07:47:30PM +0200, codek...@gmail.com wrote:
> From: Marcus Cooper <codek...@gmail.com>
>
> We have a number of flags used to identify the functionality
> of the IP block found on the sun8i-h3 and later devices. As it
> is only neccessary to identify this new block then replace
> these flags with just one.
>
> Signed-off-by: Marcus Cooper <codek...@gmail.com>

This carries exactly the same meaning than the compatible, so this is
entirely redundant.

The more I think of it, the more I fell like we should have function
pointers instead, and have hooks to deal with these kind of things.

I've been working a lot on that driver recently, and there's some many
parameters and regmap_fields that it becomes pretty hard to work on.
signature.asc

Maxime Ripard

unread,
Jun 4, 2019, 3:49:47 AM6/4/19
to codek...@gmail.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it
On Mon, Jun 03, 2019 at 07:47:31PM +0200, codek...@gmail.com wrote:
> From: Marcus Cooper <codek...@gmail.com>
>
> Some codecs require a different amount of a bit clocks per frame than

Which codec? And what are the actual requirements?

> what is calculated by the sample width. Use the tdm slot bindings to
> provide this mechanism.
>
> Signed-off-by: Marcus Cooper <codek...@gmail.com>
> ---
> sound/soc/sunxi/sun4i-i2s.c | 22 ++++++++++++++++++++--
> 1 file changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
> index 329883750d6f..bca73b3c0d74 100644
> --- a/sound/soc/sunxi/sun4i-i2s.c
> +++ b/sound/soc/sunxi/sun4i-i2s.c
> @@ -186,6 +186,9 @@ struct sun4i_i2s {
> struct regmap_field *field_rxchansel;
>
> const struct sun4i_i2s_quirks *variant;
> +
> + unsigned int tdm_slots;
> + unsigned int slot_width;
> };
>
> struct sun4i_i2s_clk_div {
> @@ -337,7 +340,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
> if (i2s->variant->is_h3_i2s_based)
> 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(word_size));

This is an unrelated change, it should be in a separate patch.

>
> /* Set sign extension to pad out LSB with 0 */
> regmap_field_write(i2s->field_fmt_sext, 0);
> @@ -414,7 +417,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
> sr + i2s->variant->fmt_offset);
>
> return sun4i_i2s_set_clk_rate(dai, params_rate(params),
> - params_width(params));
> + i2s->tdm_slots ?
> + i2s->slot_width : params_width(params));
> }
>
> static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> @@ -657,11 +661,25 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
> return 0;
> }
>
> +static int sun4i_i2s_set_dai_tdm_slot(struct snd_soc_dai *dai,
> + unsigned int tx_mask, unsigned int rx_mask,
> + int slots, int width)

The alignment after the wraping should be at the opening parenthesis.

> +{
> + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
> +
> + i2s->tdm_slots = slots;
> +
> + i2s->slot_width = 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,
> .trigger = sun4i_i2s_trigger,
> + .set_tdm_slot = sun4i_i2s_set_dai_tdm_slot,

Please sort them by alphabetical order.

Thanks!
signature.asc

Chen-Yu Tsai

unread,
Jun 4, 2019, 3:54:00 AM6/4/19
to Code Kipper, Maxime Ripard, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
On Tue, Jun 4, 2019 at 1:47 AM <codek...@gmail.com> wrote:
>
> From: Marcus Cooper <codek...@gmail.com>
>
> On the newer SoCs this is set by default to transfer a 0 after
> each sample in each slot. However the platform that this driver
> was developed on had the default setting where it padded the
> audio gain with zeros. This isn't a problem whilst we have only
> support for 16bit audio but with larger sample resolution rates
> in the pipeline then it should be fixed to also pad. Without this
> the audio gets distorted.

Curious, both the A10 and A20 manuals say the default value for this
field is 0, which means 0 padding.

sun4i_i2s_reg_defaults[] also has that field set to 0.

You're saying you are seeing the field set to 1?

ChenYu
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi...@googlegroups.com.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20190603174735.21002-4-codekipper%40gmail.com.
> For more options, visit https://groups.google.com/d/optout.

Maxime Ripard

unread,
Jun 4, 2019, 3:58:44 AM6/4/19
to codek...@gmail.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it
On Mon, Jun 03, 2019 at 07:47:32PM +0200, codek...@gmail.com wrote:
> From: Marcus Cooper <codek...@gmail.com>
>
> The i2s block supports multi-lane i2s output however this functionality
> is only possible in earlier SoCs where the pins are exposed and for
> the i2s block used for HDMI audio on the later SoCs.
>
> To enable this functionality, an optional property has been added to
> the bindings.
>
> Signed-off-by: Marcus Cooper <codek...@gmail.com>

I'd like to have Mark's input on this, but I'm really worried about
the interaction with the proper TDM support.

Our fundamental issue is that the controller can have up to 8
channels, but either on 4 lines (instead of 1), or 8 channels on 1
(like proper TDM) (or any combination between the two, but that should
be pretty rare).

You're trying to do the first one, and I'm trying to do the second one.

There's a number of assumptions later on that will break the TDM case,
see below for examples
This has the assumption that each line will have 2 channels, which is wrong.

> if (i2s->variant->is_h3_i2s_based) {
> regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
> SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
> @@ -373,8 +382,19 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
> }
>
> /* Map the channels for playback and capture */
> - regmap_field_write(i2s->field_txchanmap, 0x76543210);
> regmap_field_write(i2s->field_rxchanmap, 0x00003210);
> + regmap_field_write(i2s->field_txchanmap, 0x10);
> + if (i2s->variant->is_h3_i2s_based) {
> + if (channels > 2)
> + regmap_write(i2s->regmap,
> + SUN8I_I2S_TX_CHAN_MAP_REG+4, 0x32);
> + if (channels > 4)
> + regmap_write(i2s->regmap,
> + SUN8I_I2S_TX_CHAN_MAP_REG+8, 0x54);
> + if (channels > 6)
> + regmap_write(i2s->regmap,
> + SUN8I_I2S_TX_CHAN_MAP_REG+12, 0x76);
> + }

And this creates a mapping matching that.
I'm not quite sure how this works.

of_property_read_u32 will return 0, so you will enter in the
condition. But what happens if the property is missing?
signature.asc

Code Kipper

unread,
Jun 4, 2019, 4:15:35 AM6/4/19
to Chen-Yu Tsai, Maxime Ripard, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
On Tue, 4 Jun 2019 at 09:39, Chen-Yu Tsai <we...@csie.org> wrote:
>
> On Tue, Jun 4, 2019 at 3:34 PM Maxime Ripard <maxime...@bootlin.com> wrote:
> >
> > On Mon, Jun 03, 2019 at 07:47:27PM +0200, codek...@gmail.com wrote:
> > > From: Marcus Cooper <codek...@gmail.com>
> > >
> > > Although not causing any noticeable issues, the mask for the
> > > channel offset is covering too many bits.
> > >
> > > Signed-off-by: Marcus Cooper <codek...@gmail.com>
> >
> > Acked-by: Maxime Ripard <maxime...@bootlin.com>
>
> Would be nice to have
>
> Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3")
Thanks....I'll keep this in mind for future reference as jernej also
mention this to me.
BR,
CK

Maxime Ripard

unread,
Jun 4, 2019, 4:19:44 AM6/4/19
to codek...@gmail.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it
On Mon, Jun 03, 2019 at 07:47:34PM +0200, codek...@gmail.com wrote:
> From: Marcus Cooper <codek...@gmail.com>
>
> Extend the functionality of the driver to include support of 20 and
> 24 bits per sample for the earlier SoCs.
>
> Newer SoCs can also handle 32bit samples.
>
> Signed-off-by: Marcus Cooper <codek...@gmail.com>
> ---
> sound/soc/sunxi/sun4i-i2s.c | 34 +++++++++++++++++++++++++++++++---
> 1 file changed, 31 insertions(+), 3 deletions(-)
>
> diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
> index 3549a87ed9e9..351b8021173b 100644
> --- a/sound/soc/sunxi/sun4i-i2s.c
> +++ b/sound/soc/sunxi/sun4i-i2s.c
> @@ -428,6 +428,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
> case 16:
> width = DMA_SLAVE_BUSWIDTH_2_BYTES;
> break;
> + case 20:
> + case 24:
> + case 32:
> + width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> + break;

Doesn't this test the physical width? If so, then I'm not sure that 20
even exists, and that we can support 24.

> default:
> dev_err(dai->dev, "Unsupported physical sample width: %d\n",
> params_physical_width(params));
> @@ -440,7 +445,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
> sr = 0;
> wss = 0;
> break;
> -
> + case 20:
> + sr = 1;
> + wss = 1;
> + break;
> + case 24:
> + sr = 2;
> + wss = 2;
> + break;
> + case 32:
> + sr = 4;
> + wss = 4;
> + break;

This doesn't really works, wss being the slot size, and you can have a
different slot size and sample size. I have a patch that reworks this,
I'll send it.
signature.asc

Maxime Ripard

unread,
Jun 4, 2019, 4:21:32 AM6/4/19
to codek...@gmail.com, we...@csie.org, linux...@googlegroups.com, linux-ar...@lists.infradead.org, lgir...@gmail.com, bro...@kernel.org, linux-...@vger.kernel.org, alsa-...@alsa-project.org, be1...@iperbole.bo.it
On Mon, Jun 03, 2019 at 07:47:35PM +0200, codek...@gmail.com wrote:
> From: Marcus Cooper <codek...@gmail.com>
>
> Bypass the regmap cache when flushing the i2s FIFOs and modify the tables
> to reflect this.
>
> Signed-off-by: Marcus Cooper <codek...@gmail.com>
> ---
> sound/soc/sunxi/sun4i-i2s.c | 29 +++++++++--------------------
> 1 file changed, 9 insertions(+), 20 deletions(-)
>
> diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
> index 351b8021173b..92828a84902d 100644
> --- a/sound/soc/sunxi/sun4i-i2s.c
> +++ b/sound/soc/sunxi/sun4i-i2s.c
> @@ -595,9 +595,11 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
> {
> /* Flush RX FIFO */
> + regcache_cache_bypass(i2s->regmap, true);
> regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
> SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
> SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
> + regcache_cache_bypass(i2s->regmap, false);

Your commit log should say why you need to do this in the first place.

> @@ -771,13 +775,7 @@ static const struct snd_soc_component_driver sun4i_i2s_component = {
>
> static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg)
> {
> - switch (reg) {
> - case SUN4I_I2S_FIFO_TX_REG:
> - return false;
> -
> - default:
> - return true;
> - }
> + return true;

That doesn't seem related?
signature.asc

Code Kipper

unread,
Jun 4, 2019, 4:43:37 AM6/4/19
to Maxime Ripard, Chen-Yu Tsai, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
On Tue, 4 Jun 2019 at 09:58, Maxime Ripard <maxime...@bootlin.com> wrote:
>
> On Mon, Jun 03, 2019 at 07:47:32PM +0200, codek...@gmail.com wrote:
> > From: Marcus Cooper <codek...@gmail.com>
> >
> > The i2s block supports multi-lane i2s output however this functionality
> > is only possible in earlier SoCs where the pins are exposed and for
> > the i2s block used for HDMI audio on the later SoCs.
> >
> > To enable this functionality, an optional property has been added to
> > the bindings.
> >
> > Signed-off-by: Marcus Cooper <codek...@gmail.com>
>
> I'd like to have Mark's input on this, but I'm really worried about
> the interaction with the proper TDM support.
>
> Our fundamental issue is that the controller can have up to 8
> channels, but either on 4 lines (instead of 1), or 8 channels on 1
> (like proper TDM) (or any combination between the two, but that should
> be pretty rare).

I understand...maybe the TDM needs to be extended to support this to consider
channel mapping and multiple transfer lines. I was thinking about the later when
someone was requesting support on IIRC a while ago, I thought masking might
of been a solution. These can wait as the only consumer at the moment is
LibreELEC and we can patch it there.
Do you have any ideas Master?
CK

Christopher Obbard

unread,
Jun 4, 2019, 5:03:00 AM6/4/19
to Code Kipper, Maxime Ripard, Chen-Yu Tsai, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
On Tue, 4 Jun 2019 at 09:43, Code Kipper <codek...@gmail.com> wrote:
>
> On Tue, 4 Jun 2019 at 09:58, Maxime Ripard <maxime...@bootlin.com> wrote:
> >
> > On Mon, Jun 03, 2019 at 07:47:32PM +0200, codek...@gmail.com wrote:
> > > From: Marcus Cooper <codek...@gmail.com>
> > >
> > > The i2s block supports multi-lane i2s output however this functionality
> > > is only possible in earlier SoCs where the pins are exposed and for
> > > the i2s block used for HDMI audio on the later SoCs.
> > >
> > > To enable this functionality, an optional property has been added to
> > > the bindings.
> > >
> > > Signed-off-by: Marcus Cooper <codek...@gmail.com>
> >
> > I'd like to have Mark's input on this, but I'm really worried about
> > the interaction with the proper TDM support.
> >
> > Our fundamental issue is that the controller can have up to 8
> > channels, but either on 4 lines (instead of 1), or 8 channels on 1
> > (like proper TDM) (or any combination between the two, but that should
> > be pretty rare).
>
> I understand...maybe the TDM needs to be extended to support this to consider
> channel mapping and multiple transfer lines. I was thinking about the later when
> someone was requesting support on IIRC a while ago, I thought masking might
> of been a solution. These can wait as the only consumer at the moment is
> LibreELEC and we can patch it there.

Hi Marcus,

FWIW, the TI McASP driver has support for TDM & (i think?) multiple
transfer lines which are called serializers.
Maybe this can help with inspiration?
see https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/ti/davinci-mcasp.c
sample DTS:

&mcasp0 {
#sound-dai-cells = <0>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mcasp0_pins>;

op-mode = <0>;
tdm-slots = <8>;
serial-dir = <
2 0 1 0
0 0 0 0
0 0 0 0
0 0 0 0
>;
tx-num-evt = <1>;
rx-num-evt = <1>;
};


Cheers!
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi...@googlegroups.com.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/CAEKpxB%3DRdYF9eEvAJ%2BR7sT6OtdtBWjhMM1am%2BEhaN%3D9ZO9Gd2A%40mail.gmail.com.

Code Kipper

unread,
Jun 4, 2019, 5:33:25 AM6/4/19
to Maxime Ripard, Chen-Yu Tsai, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
On Tue, 4 Jun 2019 at 09:46, Maxime Ripard <maxime...@bootlin.com> wrote:
>
> On Mon, Jun 03, 2019 at 07:47:30PM +0200, codek...@gmail.com wrote:
> > From: Marcus Cooper <codek...@gmail.com>
> >
> > We have a number of flags used to identify the functionality
> > of the IP block found on the sun8i-h3 and later devices. As it
> > is only neccessary to identify this new block then replace
> > these flags with just one.
> >
> > Signed-off-by: Marcus Cooper <codek...@gmail.com>
>
> This carries exactly the same meaning than the compatible, so this is
> entirely redundant.
>
> The more I think of it, the more I fell like we should have function
> pointers instead, and have hooks to deal with these kind of things.
>
> I've been working a lot on that driver recently, and there's some many
> parameters and regmap_fields that it becomes pretty hard to work on.
Hi Maxime,
let's sync with what you're doing as you're more lightly to see it
through to delivery!
I was trying to clean up the driver as some of this seemed a bit unnecessary,
hooks sounds like the way forward,
CK

Code Kipper

unread,
Jun 4, 2019, 5:38:58 AM6/4/19
to Christopher Obbard, Maxime Ripard, Chen-Yu Tsai, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
Thanks, this looks good.
CK

Code Kipper

unread,
Jun 4, 2019, 7:46:32 AM6/4/19
to Chen-Yu Tsai, Maxime Ripard, linux-sunxi, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
On Tue, 4 Jun 2019 at 09:53, Chen-Yu Tsai <we...@csie.org> wrote:
>
> On Tue, Jun 4, 2019 at 1:47 AM <codek...@gmail.com> wrote:
> >
> > From: Marcus Cooper <codek...@gmail.com>
> >
> > On the newer SoCs this is set by default to transfer a 0 after
> > each sample in each slot. However the platform that this driver
> > was developed on had the default setting where it padded the
> > audio gain with zeros. This isn't a problem whilst we have only
> > support for 16bit audio but with larger sample resolution rates
> > in the pipeline then it should be fixed to also pad. Without this
> > the audio gets distorted.
>
> Curious, both the A10 and A20 manuals say the default value for this
> field is 0, which means 0 padding.
>
> sun4i_i2s_reg_defaults[] also has that field set to 0.
>
> You're saying you are seeing the field set to 1?

On the newer SoCs (H3 onwards) this setting defaults to 3 which is
"Transfer 0 after each sample in each slot" which resulted in distortion.
Setting SEXT to 0 "Zeros or audio gain padding at LSB" alligns the
setup with that of the earlier block and fixed the issue we were hearing.
It's really noticeable with HDMI audio.
BR,
CK

Mark Brown

unread,
Jun 5, 2019, 10:30:45 AM6/5/19
to Marcus Cooper, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Chen-Yu Tsai, lgir...@gmail.com, linux-ar...@lists.infradead.org, linux-...@vger.kernel.org, linux...@googlegroups.com, Mark Brown, maxime...@free-electrons.com, Maxime Ripard
The patch

ASoC: sun4i-i2s: Fix sun8i tx channel offset mask

has been applied to the asoc tree at

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2

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 7e46169a5f35762f335898a75d1b8a242f2ae0f5 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codek...@gmail.com>
Date: Mon, 3 Jun 2019 19:47:27 +0200
Subject: [PATCH] ASoC: sun4i-i2s: Fix sun8i tx channel offset mask

Although not causing any noticeable issues, the mask for the
channel offset is covering too many bits.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
Acked-by: Maxime Ripard <maxime...@bootlin.com>
Acked-by: Chen-Yu Tsai <we...@csie.org>
Signed-off-by: Mark Brown <bro...@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d5ec1a20499d..8162e107e50b 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -110,7 +110,7 @@

#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
-#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 11)
+#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12)
#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12)
#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
--
2.20.1

Mark Brown

unread,
Jun 5, 2019, 10:30:45 AM6/5/19
to Marcus Cooper, alsa-...@alsa-project.org, be1...@iperbole.bo.it, Chen-Yu Tsai, lgir...@gmail.com, linux-ar...@lists.infradead.org, linux-...@vger.kernel.org, linux...@googlegroups.com, Mark Brown, maxime...@free-electrons.com, Maxime Ripard
The patch

ASoC: sun4i-i2s: Add offset to RX channel select

has been applied to the asoc tree at

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2

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 f9927000cb35f250051f0f1878db12ee2626eea1 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codek...@gmail.com>
Date: Mon, 3 Jun 2019 19:47:28 +0200
Subject: [PATCH] ASoC: sun4i-i2s: Add offset to RX channel select

Whilst testing the capture functionality of the i2s on the newer
SoCs it was noticed that the recording was somewhat distorted.
This was due to the offset not being set correctly on the receiver
side.

Signed-off-by: Marcus Cooper <codek...@gmail.com>
Acked-by: Maxime Ripard <maxime...@bootlin.com>
Acked-by: Chen-Yu Tsai <we...@csie.org>
Signed-off-by: Mark Brown <bro...@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 8162e107e50b..bc128e2a6096 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -460,6 +460,10 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
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_field_write(i2s->field_fmt_mode, val);
--
2.20.1

Jernej Škrabec

unread,
Jul 30, 2019, 1:57:16 PM7/30/19
to linux...@googlegroups.com, codek...@gmail.com, Christopher Obbard, Maxime Ripard, Chen-Yu Tsai, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
Hi!

Dne torek, 04. junij 2019 ob 11:38:44 CEST je Code Kipper napisal(a):
I would really like to see this issue resolved, because HDMI audio support in
mainline Linux for those SoCs is long overdue.

However, there is a possibility to still add HDMI audio suport (stereo only)
even if this issue is not completely solved. If we agree that configuration of
channels would be solved with additional property as Christopher suggested,
support for >2 channels can be left for a later time when support for that
property would be implemented. Currently, stereo HDMI audio support can be
added with a few patches.

I think all I2S cores are really the same, no matter if internally connected
to HDMI controller or routed to pins, so it would make sense to use same
compatible for all of them. It's just that those I2S cores which are routed to
pins can use only one lane and >2 channels can be used only in TDM mode of
operation, if I understand this correctly.

New property would have to be optional, so it's omission would result in same
channel configuration as it is already present, to preserve compatibility with
old device trees. And this mode is already sufficient for stereo HDMI audio
support.

Side note: HDMI audio with current sun4i-i2s driver has a delay (about a
second), supposedly because DW HDMI controller automatically generates CTS
value based on I2S clock (auto CTS value generation is enabled per DesignWare
recomendation for DW HDMI I2S interface). I2S driver from BSP Linux solves
that by having I2S clock output enabled all the time. Should this be flagged
with some additional property in DT?

Best regards,
Jernej

Maxime Ripard

unread,
Jul 31, 2019, 8:29:57 AM7/31/19
to Jernej Škrabec, linux...@googlegroups.com, codek...@gmail.com, Christopher Obbard, Chen-Yu Tsai, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
Yeah, it looks like a good plan.

> Side note: HDMI audio with current sun4i-i2s driver has a delay (about a
> second), supposedly because DW HDMI controller automatically generates CTS
> value based on I2S clock (auto CTS value generation is enabled per DesignWare
> recomendation for DW HDMI I2S interface).

Is that a constant delay during the audio playback, or only at startup?

> I2S driver from BSP Linux solves that by having I2S clock output
> enabled all the time. Should this be flagged with some additional
> property in DT?

I'd say that if the codec has that requirement, then it should be
between the codec and the DAI, the DT doesn't really have anything to
do with this.

Jernej Škrabec

unread,
Aug 1, 2019, 1:32:01 AM8/1/19
to linux...@googlegroups.com, maxime...@bootlin.com, codek...@gmail.com, Christopher Obbard, Chen-Yu Tsai, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
Dne sreda, 31. julij 2019 ob 14:29:53 CEST je Maxime Ripard napisal(a):
I think it's just at startup, e.g. if you're watching movie, audio is in sync,
it's just that first second or so is silent.

>
> > I2S driver from BSP Linux solves that by having I2S clock output
> > enabled all the time. Should this be flagged with some additional
> > property in DT?
>
> I'd say that if the codec has that requirement, then it should be
> between the codec and the DAI, the DT doesn't really have anything to
> do with this.

Ok, but how to communicate that fact to I2S driver then? BSP driver solves
that by using different compatible, but as I said before, I2S cores are not
really different, so this seems wrong.

Best regards,
Jernej


Chen-Yu Tsai

unread,
Aug 6, 2019, 2:22:31 AM8/6/19
to Jernej Škrabec, linux-sunxi, Maxime Ripard, Code Kipper, Christopher Obbard, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
Maybe we could make the DW-HDMI I2S driver require the I2S clock be on all
the time? You wouldn't need any changes to the DT.

ChenYu

Maxime Ripard

unread,
Aug 12, 2019, 6:02:34 AM8/12/19
to Chen-Yu Tsai, Jernej Škrabec, linux-sunxi, Code Kipper, Christopher Obbard, linux-arm-kernel, Liam Girdwood, Mark Brown, linux-kernel, Linux-ALSA, Andrea Venturi (pers)
That's an option, but I'd really like to avoid it if possible.

I guess we could also just add a delay in the powerup path in the HDMI
case? Would it work?

maxime
signature.asc
Reply all
Reply to author
Forward
0 new messages