[PATCH v3 00/19] Add Allwinner H3/H5/H6/A64 HDMI audio
Hi,
New test done by Maxime using TDM show that's LRCK is indeed inverted so I drop the patch reverted in v2.
And HDMI requires an inverted LRCK so let's readd the frame-inversion in the device-tree.
I have also added a patch to change set_chan_cfg.
Please note that I can't test TDM and only have a Allwinner H6. So test and comment on other Allwinner chips are welcome!
Regards, Clement
Change since v2: - rebase on next-20200918 - drop revert LRCK polarity patch - readd simple-audio-card,frame-inversion in dts - Add patch for changing set_chan_cfg params
Change since v1: - rebase on next-20200828 - add revert LRCK polarity - remove all simple-audio-card,frame-inversion in dts - add Ondrej patches for Orange Pi board - Add arm64 defconfig patch
Clément Péron (4): ASoC: sun4i-i2s: Change set_chan_cfg params ASoC: sun4i-i2s: Fix sun8i volatile regs arm64: dts: allwinner: h6: Enable HDMI sound for Beelink GS1 arm64: defconfig: Enable Allwinner i2s driver
Jernej Skrabec (3): ASoC: sun4i-i2s: Add support for H6 I2S dt-bindings: ASoC: sun4i-i2s: Add H6 compatible arm64: dts: allwinner: h6: Add HDMI audio node
Marcus Cooper (9): ASoC: sun4i-i2s: Set sign extend sample ASoc: sun4i-i2s: Add 20 and 24 bit support arm: dts: sunxi: h3/h5: Add DAI node for HDMI arm: dts: sunxi: h3/h5: Add HDMI audio arm64: dts: allwinner: a64: Add DAI node for HDMI arm64: dts: allwinner: a64: Add HDMI audio arm: sun8i: h3: Add HDMI audio to Orange Pi 2 arm: sun8i: h3: Add HDMI audio to Beelink X2 arm64: dts: allwinner: a64: Add HDMI audio to Pine64
Ondrej Jirman (3): arm64: dts: allwinner: Enable HDMI audio on Orange Pi PC 2 ARM: dts: sun8i-h3: Enable HDMI audio on Orange Pi PC/One arm64: dts: sun50i-h6-orangepi-3: Enable HDMI audio
.../sound/allwinner,sun4i-a10-i2s.yaml | 2 + arch/arm/boot/dts/sun8i-h3-beelink-x2.dts | 8 + arch/arm/boot/dts/sun8i-h3-orangepi-2.dts | 8 + arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 8 + arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 8 + arch/arm/boot/dts/sunxi-h3-h5.dtsi | 33 +++ .../boot/dts/allwinner/sun50i-a64-pine64.dts | 8 + arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 34 +++ .../dts/allwinner/sun50i-h5-orangepi-pc2.dts | 8 + .../dts/allwinner/sun50i-h6-beelink-gs1.dts | 8 + .../dts/allwinner/sun50i-h6-orangepi-3.dts | 8 + arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 33 +++ arch/arm64/configs/defconfig | 1 + sound/soc/sunxi/sun4i-i2s.c | 280 ++++++++++++++++-- 14 files changed, 427 insertions(+), 20 deletions(-)
From: Jernej Skrabec jernej.skrabec@siol.net
H6 I2S is very similar to that in H3, except it supports up to 16 channels.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- sound/soc/sunxi/sun4i-i2s.c | 218 ++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index f23ff29e7c1d..348057464bed 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -124,6 +124,21 @@ #define SUN8I_I2S_RX_CHAN_SEL_REG 0x54 #define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
+/* Defines required for sun50i-h6 support */ +#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK GENMASK(21, 20) +#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset) ((offset) << 20) +#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK GENMASK(19, 16) +#define SUN50I_H6_I2S_TX_CHAN_SEL(chan) ((chan - 1) << 16) +#define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(15, 0) +#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1)) + +#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG 0x44 +#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG 0x48 + +#define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64 +#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68 +#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG 0x6C + struct sun4i_i2s;
/** @@ -474,6 +489,62 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, return 0; }
+static int sun50i_h6_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; + unsigned int lrck_period; + + if (i2s->slots) + slots = i2s->slots; + + /* Map the channels for playback and capture */ + regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210); + regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210); + + /* Configure the channels */ + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN50I_H6_I2S_TX_CHAN_SEL_MASK, + SUN50I_H6_I2S_TX_CHAN_SEL(channels)); + regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG, + SUN50I_H6_I2S_TX_CHAN_SEL_MASK, + SUN50I_H6_I2S_TX_CHAN_SEL(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)); + + 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, + SUN50I_H6_I2S_TX_CHAN_EN_MASK, + SUN50I_H6_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) @@ -699,6 +770,102 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, return 0; }
+static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) +{ + 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_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; + 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, + SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK, + SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG, + SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK, + SUN50I_H6_I2S_TX_CHAN_SEL_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); @@ -979,6 +1146,22 @@ static const struct reg_default sun8i_i2s_reg_defaults[] = { { SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 }, };
+static const struct reg_default sun50i_h6_i2s_reg_defaults[] = { + { SUN4I_I2S_CTRL_REG, 0x00060000 }, + { SUN4I_I2S_FMT0_REG, 0x00000033 }, + { SUN4I_I2S_FMT1_REG, 0x00000030 }, + { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, + { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, + { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, + { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 }, + { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 }, + { SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 }, + { SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 }, + { SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 }, + { SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 }, + { SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 }, +}; + static const struct regmap_config sun4i_i2s_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1006,6 +1189,19 @@ static const struct regmap_config sun8i_i2s_regmap_config = { .volatile_reg = sun8i_i2s_volatile_reg, };
+static const struct regmap_config sun50i_h6_i2s_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN50I_H6_I2S_RX_CHAN_MAP1_REG, + .cache_type = REGCACHE_FLAT, + .reg_defaults = sun50i_h6_i2s_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(sun50i_h6_i2s_reg_defaults), + .writeable_reg = sun4i_i2s_wr_reg, + .readable_reg = sun8i_i2s_rd_reg, + .volatile_reg = sun8i_i2s_volatile_reg, +}; + static int sun4i_i2s_runtime_resume(struct device *dev) { struct sun4i_i2s *i2s = dev_get_drvdata(dev); @@ -1164,6 +1360,24 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .set_fmt = sun4i_i2s_set_soc_fmt, };
+static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = { + .has_reset = true, + .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, + .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config, + .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 = sun50i_h6_i2s_set_chan_cfg, + .set_fmt = sun50i_h6_i2s_set_soc_fmt, +}; + static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1333,6 +1547,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun50i-a64-codec-i2s", .data = &sun50i_a64_codec_i2s_quirks, }, + { + .compatible = "allwinner,sun50i-h6-i2s", + .data = &sun50i_h6_i2s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
On 9/20/20 1:07 PM, Clément Péron wrote:
From: Jernej Skrabec jernej.skrabec@siol.net
H6 I2S is very similar to that in H3, except it supports up to 16 channels.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com
sound/soc/sunxi/sun4i-i2s.c | 218 ++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index f23ff29e7c1d..348057464bed 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c
...
@@ -699,6 +770,102 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, return 0; }
+static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
unsigned int fmt)
+{
- 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;
- }
Maxime's testing that showed LRCK inversion was necessary was done on the H6. So in addition to dropping the patch that removed the LRCK inversion for other sun8i variants, you need to re-add it to this patch for the H6 variant.
Cheers, Samuel
- 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_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;
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,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
- regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
SUN50I_H6_I2S_TX_CHAN_SEL_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);
...
Hi Samuel,
On Sun, 20 Sep 2020 at 20:39, Samuel Holland samuel@sholland.org wrote:
On 9/20/20 1:07 PM, Clément Péron wrote:
From: Jernej Skrabec jernej.skrabec@siol.net
H6 I2S is very similar to that in H3, except it supports up to 16 channels.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com
sound/soc/sunxi/sun4i-i2s.c | 218 ++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index f23ff29e7c1d..348057464bed 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c
...
@@ -699,6 +770,102 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, return 0; }
+static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
unsigned int fmt)
+{
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;
}
Maxime's testing that showed LRCK inversion was necessary was done on the H6. So in addition to dropping the patch that removed the LRCK inversion for other sun8i variants, you need to re-add it to this patch for the H6 variant.
Thanks, you're right! Clement
Cheers, Samuel
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_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;
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,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
SUN50I_H6_I2S_TX_CHAN_SEL_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);
...
As slots and slot_width can be overwritter in case set_tdm() is called. Avoid to have this logic in set_chan_cfg().
Instead pass the required values as params to set_chan_cfg().
This also fix a bug when i2s->slot_width is set for TDM but not properly used in set_chan_cfg().
Suggested-by: Samuel Holland samuel@sholland.org Signed-off-by: Clément Péron peron.clem@gmail.com --- sound/soc/sunxi/sun4i-i2s.c | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 348057464bed..246d4a45edae 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -177,8 +177,8 @@ struct sun4i_i2s_quirks { 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 *, - const struct snd_pcm_hw_params *); + int (*set_chan_cfg)(const struct sun4i_i2s *, unsigned int, + unsigned int, unsigned int); int (*set_fmt)(const struct sun4i_i2s *, unsigned int); };
@@ -414,10 +414,9 @@ static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width) }
static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, - const struct snd_pcm_hw_params *params) + unsigned int channels, unsigned int slots, + unsigned int slot_width) { - unsigned int channels = params_channels(params); - /* 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); @@ -434,15 +433,11 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, }
static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, - const struct snd_pcm_hw_params *params) + unsigned int channels, unsigned int slots, + unsigned int slot_width) { - unsigned int channels = params_channels(params); - unsigned int slots = channels; unsigned int lrck_period;
- if (i2s->slots) - slots = i2s->slots; - /* 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); @@ -467,11 +462,11 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, 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; + lrck_period = slot_width * slots; break;
case SND_SOC_DAIFMT_I2S: - lrck_period = params_physical_width(params); + lrck_period = slot_width; break;
default: @@ -490,15 +485,11 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, }
static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, - const struct snd_pcm_hw_params *params) + unsigned int channels, unsigned int slots, + unsigned int slot_width) { - unsigned int channels = params_channels(params); - unsigned int slots = channels; unsigned int lrck_period;
- if (i2s->slots) - slots = i2s->slots; - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210); regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210); @@ -523,11 +514,11 @@ static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, 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; + lrck_period = slot_width * slots; break;
case SND_SOC_DAIFMT_I2S: - lrck_period = params_physical_width(params); + lrck_period = slot_width; break;
default: @@ -563,7 +554,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (i2s->slot_width) slot_width = i2s->slot_width;
- ret = i2s->variant->set_chan_cfg(i2s, params); + ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width); if (ret < 0) { dev_err(dai->dev, "Invalid channel configuration\n"); return ret;
From: Jernej Skrabec jernej.skrabec@siol.net
H6 I2S is very similar to H3, except that it supports up to 16 channels and thus few registers have fields on different position.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com Acked-by: Maxime Ripard mripard@kernel.org Acked-by: Rob Herring robh@kernel.org --- .../devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml index 112ae00d63c1..606ad2d884a8 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml @@ -24,6 +24,7 @@ properties: - items: - const: allwinner,sun50i-a64-i2s - const: allwinner,sun8i-h3-i2s + - const: allwinner,sun50i-h6-i2s
reg: maxItems: 1 @@ -59,6 +60,7 @@ allOf: - allwinner,sun8i-a83t-i2s - allwinner,sun8i-h3-i2s - allwinner,sun50i-a64-codec-i2s + - allwinner,sun50i-h6-i2s
then: required:
From: Marcus Cooper codekipper@gmail.com
On the newer SoCs such as the H3 and A64 this is set by default to transfer a 0 after each sample in each slot. However the A10 and A20 SoCs that this driver was developed on had a default setting where it padded the audio gain with zeros.
This isn't a problem while we have only support for 16bit audio but with larger sample resolution rates in the pipeline then SEXT bits should be cleared so that they also pad at the LSB. Without this the audio gets distorted.
Set sign extend sample for all the sunxi generations even if they are not affected. This will keep consistency and avoid relying on default.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- sound/soc/sunxi/sun4i-i2s.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 246d4a45edae..57a68222f99a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -48,6 +48,9 @@ #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
#define SUN4I_I2S_FMT1_REG 0x08 +#define SUN4I_I2S_FMT1_REG_SEXT_MASK BIT(8) +#define SUN4I_I2S_FMT1_REG_SEXT(sext) ((sext) << 8) + #define SUN4I_I2S_FIFO_TX_REG 0x0c #define SUN4I_I2S_FIFO_RX_REG 0x10
@@ -105,6 +108,9 @@ #define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) #define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
+#define SUN8I_I2S_FMT1_REG_SEXT_MASK GENMASK(5, 4) +#define SUN8I_I2S_FMT1_REG_SEXT(sext) ((sext) << 4) + #define SUN8I_I2S_INT_STA_REG 0x0c #define SUN8I_I2S_FIFO_TX_REG 0x20
@@ -656,6 +662,7 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, } regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, SUN4I_I2S_CTRL_MODE_MASK, val); + return 0; }
@@ -758,6 +765,11 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, val);
+ /* Set sign extension to pad out LSB with 0 */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG, + SUN8I_I2S_FMT1_REG_SEXT_MASK, + SUN8I_I2S_FMT1_REG_SEXT(0)); + return 0; }
@@ -854,6 +866,11 @@ static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, val);
+ /* Set sign extension to pad out LSB with 0 */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG, + SUN8I_I2S_FMT1_REG_SEXT_MASK, + SUN8I_I2S_FMT1_REG_SEXT(0)); + return 0; }
From: Marcus Cooper codekipper@gmail.com
Extend the functionality of the driver to include support of 20 and 24 bits per sample.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com Acked-by: Maxime Ripard mripard@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 57a68222f99a..ce4913f0ffe4 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -570,6 +570,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, case 16: width = DMA_SLAVE_BUSWIDTH_2_BYTES; break; + case 32: + width = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; default: dev_err(dai->dev, "Unsupported physical sample width: %d\n", params_physical_width(params)); @@ -1045,6 +1048,10 @@ 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) + static struct snd_soc_dai_driver sun4i_i2s_dai = { .probe = sun4i_i2s_dai_probe, .capture = { @@ -1052,14 +1059,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = { .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SUN4I_FORMATS, }, .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SUN4I_FORMATS, }, .ops = &sun4i_i2s_dai_ops, .symmetric_rates = 1,
On 9/20/20 1:07 PM, Clément Péron wrote:
From: Marcus Cooper codekipper@gmail.com
Extend the functionality of the driver to include support of 20 and 24 bits per sample.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com Acked-by: Maxime Ripard mripard@kernel.org
sound/soc/sunxi/sun4i-i2s.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
As I have mentioned before, if you want to support a 32-bit slot width on sun4i variants (which patch 2 does via TDM and this patch does via PCM format), you need to fix sun4i_i2s_get_wss() to return "3", not "4", for a 32-bit input.
Cheers, Samuel
Hi Samuel,
On Sun, 20 Sep 2020 at 20:45, Samuel Holland samuel@sholland.org wrote:
On 9/20/20 1:07 PM, Clément Péron wrote:
From: Marcus Cooper codekipper@gmail.com
Extend the functionality of the driver to include support of 20 and 24 bits per sample.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com Acked-by: Maxime Ripard mripard@kernel.org
sound/soc/sunxi/sun4i-i2s.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
As I have mentioned before, if you want to support a 32-bit slot width on sun4i variants (which patch 2 does via TDM and this patch does via PCM format), you need to fix sun4i_i2s_get_wss() to return "3", not "4", for a 32-bit input.
Sorry I didn't get it the first time.
Is using a switch case is a correct solution?
static s8 sun4i_i2s_get_wss(const struct sun4i_i2s *i2s, int width) { switch (width) { case 16: return 0x0; case 20: return 0x1; case 24: return 0x2; case 32: return 0x3; }
return -EINVAL; }
Clement
Cheers, Samuel
The FIFO TX reg is volatile and sun8i i2s register mapping is different from sun4i.
Even if in this case it's doesn't create an issue, Avoid setting some regs that are undefined in sun8i.
Signed-off-by: Clément Péron peron.clem@gmail.com Acked-by: Maxime Ripard mripard@kernel.org --- sound/soc/sunxi/sun4i-i2s.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index ce4913f0ffe4..a35be0e2baf5 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1126,12 +1126,19 @@ static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg) { - if (reg == SUN8I_I2S_INT_STA_REG) + switch (reg) { + case SUN4I_I2S_FIFO_CTRL_REG: + case SUN4I_I2S_FIFO_RX_REG: + case SUN4I_I2S_FIFO_STA_REG: + case SUN4I_I2S_RX_CNT_REG: + case SUN4I_I2S_TX_CNT_REG: + case SUN8I_I2S_FIFO_TX_REG: + case SUN8I_I2S_INT_STA_REG: return true; - if (reg == SUN8I_I2S_FIFO_TX_REG) - return false;
- return sun4i_i2s_volatile_reg(dev, reg); + default: + return false; + } }
static const struct reg_default sun4i_i2s_reg_defaults[] = {
On 9/20/20 1:07 PM, Clément Péron wrote:
The FIFO TX reg is volatile and sun8i i2s register mapping is different from sun4i.
Even if in this case it's doesn't create an issue, Avoid setting some regs that are undefined in sun8i.
Signed-off-by: Clément Péron peron.clem@gmail.com Acked-by: Maxime Ripard mripard@kernel.org
sound/soc/sunxi/sun4i-i2s.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index ce4913f0ffe4..a35be0e2baf5 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1126,12 +1126,19 @@ static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg) {
- if (reg == SUN8I_I2S_INT_STA_REG)
- switch (reg) {
- case SUN4I_I2S_FIFO_CTRL_REG:
Please check if this breaks audio recording with runtime PM enabled. I noticed this with an older revision of the series that also changed sun4i_i2s_volatile_reg. Marking SUN4I_I2S_FIFO_CTRL_REG as volatile broke setting of SUN4I_I2S_FIFO_CTRL_TX_MODE/RX_MODE, because the set_fmt() callback is not run with a runtime PM reference held, and volatile registers are not written by regcache_sync() during sun4i_i2s_runtime_resume().
As a workaround, I moved the TX_MODE/RX_MODE initialization to hw_params(), but I am not sure it is the right thing to do:
https://github.com/smaeul/linux/commit/5e40ac610986.patch
Cheers, Samuel
- case SUN4I_I2S_FIFO_RX_REG:
- case SUN4I_I2S_FIFO_STA_REG:
- case SUN4I_I2S_RX_CNT_REG:
- case SUN4I_I2S_TX_CNT_REG:
- case SUN8I_I2S_FIFO_TX_REG:
- case SUN8I_I2S_INT_STA_REG: return true;
if (reg == SUN8I_I2S_FIFO_TX_REG)
return false;
return sun4i_i2s_volatile_reg(dev, reg);
- default:
return false;
- }
}
static const struct reg_default sun4i_i2s_reg_defaults[] = {
Hi Samuel,
On Sun, 20 Sep 2020 at 20:52, Samuel Holland samuel@sholland.org wrote:
On 9/20/20 1:07 PM, Clément Péron wrote:
The FIFO TX reg is volatile and sun8i i2s register mapping is different from sun4i.
Even if in this case it's doesn't create an issue, Avoid setting some regs that are undefined in sun8i.
Signed-off-by: Clément Péron peron.clem@gmail.com Acked-by: Maxime Ripard mripard@kernel.org
sound/soc/sunxi/sun4i-i2s.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index ce4913f0ffe4..a35be0e2baf5 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1126,12 +1126,19 @@ static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg) {
if (reg == SUN8I_I2S_INT_STA_REG)
switch (reg) {
case SUN4I_I2S_FIFO_CTRL_REG:
Please check if this breaks audio recording with runtime PM enabled. I noticed this with an older revision of the series that also changed sun4i_i2s_volatile_reg. Marking SUN4I_I2S_FIFO_CTRL_REG as volatile broke setting of SUN4I_I2S_FIFO_CTRL_TX_MODE/RX_MODE, because the set_fmt() callback is not run with a runtime PM reference held, and volatile registers are not written by regcache_sync() during sun4i_i2s_runtime_resume().
As a workaround, I moved the TX_MODE/RX_MODE initialization to hw_params(), but I am not sure it is the right thing to do:
Thanks for the catch, I never tried to suspend/resume my board actually. But your explanation and the fix seems legit to me.
I don't think it's a workaround as settings the fifo size is not related to set_fmt and could also be set in hw_params.
I will add your fix in the next version.
Regards, Clement
https://github.com/smaeul/linux/commit/5e40ac610986.patch
Cheers, Samuel
case SUN4I_I2S_FIFO_RX_REG:
case SUN4I_I2S_FIFO_STA_REG:
case SUN4I_I2S_RX_CNT_REG:
case SUN4I_I2S_TX_CNT_REG:
case SUN8I_I2S_FIFO_TX_REG:
case SUN8I_I2S_INT_STA_REG: return true;
if (reg == SUN8I_I2S_FIFO_TX_REG)
return false;
return sun4i_i2s_volatile_reg(dev, reg);
default:
return false;
}
}
static const struct reg_default sun4i_i2s_reg_defaults[] = {
From: Jernej Skrabec jernej.skrabec@siol.net
Add a simple-soundcard to link audio between HDMI and I2S.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 33 ++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi index 28c77d6872f6..a8853ee7885a 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi @@ -67,6 +67,25 @@ de: display-engine { status = "disabled"; };
+ hdmi_sound: hdmi-sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "sun50i-h6-hdmi"; + simple-audio-card,mclk-fs = <128>; + simple-audio-card,frame-inversion; + status = "disabled"; + + simple-audio-card,codec { + sound-dai = <&hdmi>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s1>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; + }; + osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; @@ -609,6 +628,19 @@ mdio: mdio { }; };
+ i2s1: i2s@5091000 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun50i-h6-i2s"; + reg = <0x05091000 0x1000>; + interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>; + clock-names = "apb", "mod"; + dmas = <&dma 4>, <&dma 4>; + resets = <&ccu RST_BUS_I2S1>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + spdif: spdif@5093000 { #sound-dai-cells = <0>; compatible = "allwinner,sun50i-h6-spdif"; @@ -739,6 +771,7 @@ ohci3: usb@5311400 { };
hdmi: hdmi@6000000 { + #sound-dai-cells = <0>; compatible = "allwinner,sun50i-h6-dw-hdmi"; reg = <0x06000000 0x10000>; reg-io-width = <1>;
Now that HDMI sound node is available in the SoC dtsi. Enable it for this board.
Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts index 3f7ceeb1a767..049c21718846 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts @@ -118,6 +118,14 @@ hdmi_out_con: endpoint { }; };
+&hdmi_sound { + status = "okay"; +}; + +&i2s1 { + status = "okay"; +}; + &mdio { ext_rgmii_phy: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22";
From: Marcus Cooper codekipper@gmail.com
Add the new DAI block for I2S2 which is used for HDMI audio.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm/boot/dts/sunxi-h3-h5.dtsi | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi index 22d533d18992..3dca6d89cab9 100644 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi @@ -662,6 +662,19 @@ i2s1: i2s@1c22400 { status = "disabled"; };
+ i2s2: i2s@1c22800 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-h3-i2s"; + reg = <0x01c22800 0x400>; + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>; + clock-names = "apb", "mod"; + dmas = <&dma 27>, <&dma 27>; + resets = <&ccu RST_BUS_I2S2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + codec: codec@1c22c00 { #sound-dai-cells = <0>; compatible = "allwinner,sun8i-h3-codec";
From: Marcus Cooper codekipper@gmail.com
Add a simple-soundcard to link audio between HDMI and I2S.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm/boot/dts/sunxi-h3-h5.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi index 3dca6d89cab9..7168e9412410 100644 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi @@ -105,6 +105,25 @@ de: display-engine { status = "disabled"; };
+ hdmi_sound: hdmi-sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "sun8i-h3-hdmi"; + simple-audio-card,mclk-fs = <128>; + simple-audio-card,frame-inversion; + status = "disabled"; + + simple-audio-card,codec { + sound-dai = <&hdmi>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s2>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; + }; + soc { compatible = "simple-bus"; #address-cells = <1>; @@ -806,6 +825,7 @@ csi: camera@1cb0000 { };
hdmi: hdmi@1ee0000 { + #sound-dai-cells = <0>; compatible = "allwinner,sun8i-h3-dw-hdmi", "allwinner,sun8i-a83t-dw-hdmi"; reg = <0x01ee0000 0x10000>;
From: Marcus Cooper codekipper@gmail.com
Add the new DAI block for I2S2 which is used for HDMI audio.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index dc238814013c..51cc30e84e26 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -846,6 +846,20 @@ i2s1: i2s@1c22400 { status = "disabled"; };
+ i2s2: i2s@1c22800 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun50i-a64-i2s", + "allwinner,sun8i-h3-i2s"; + reg = <0x01c22800 0x400>; + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>; + clock-names = "apb", "mod"; + resets = <&ccu RST_BUS_I2S2>; + dma-names = "rx", "tx"; + dmas = <&dma 27>, <&dma 27>; + status = "disabled"; + }; + dai: dai@1c22c00 { #sound-dai-cells = <0>; compatible = "allwinner,sun50i-a64-codec-i2s";
From: Marcus Cooper codekipper@gmail.com
Add a simple-soundcard to link audio between HDMI and I2S.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 51cc30e84e26..ba8a84e6e993 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -102,6 +102,25 @@ de: display-engine { status = "disabled"; };
+ hdmi_sound: hdmi-sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "sun50i-a64-hdmi"; + simple-audio-card,mclk-fs = <128>; + simple-audio-card,frame-inversion; + status = "disabled"; + + simple-audio-card,codec { + sound-dai = <&hdmi>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s2>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; + }; + osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; @@ -1157,6 +1176,7 @@ deinterlace: deinterlace@1e00000 { };
hdmi: hdmi@1ee0000 { + #sound-dai-cells = <0>; compatible = "allwinner,sun50i-a64-dw-hdmi", "allwinner,sun8i-a83t-dw-hdmi"; reg = <0x01ee0000 0x10000>;
From: Marcus Cooper codekipper@gmail.com
Enable HDMI audio on the Orange Pi 2.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm/boot/dts/sun8i-h3-orangepi-2.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts index 597c425d08ec..64e8e2829f27 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts @@ -144,6 +144,14 @@ hdmi_out_con: endpoint { }; };
+&hdmi_sound { + status = "okay"; +}; + +&i2s2 { + status = "okay"; +}; + &ir { pinctrl-names = "default"; pinctrl-0 = <&r_ir_rx_pin>;
From: Marcus Cooper codekipper@gmail.com
Enable HDMI audio on the Beelink X2.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm/boot/dts/sun8i-h3-beelink-x2.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts index 45a24441ff18..f9bec6935120 100644 --- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts +++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts @@ -142,6 +142,14 @@ hdmi_out_con: endpoint { }; };
+&hdmi_sound { + status = "okay"; +}; + +&i2s2 { + status = "okay"; +}; + &ir { linux,rc-map-name = "rc-tanix-tx3mini"; pinctrl-names = "default";
From: Marcus Cooper codekipper@gmail.com
Enable HDMI audio on Pine64.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts index 329cf276561e..b54b02e59085 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts @@ -99,6 +99,10 @@ hdmi_out_con: endpoint { }; };
+&hdmi_sound { + status = "okay"; +}; + &i2c1 { status = "okay"; }; @@ -107,6 +111,10 @@ &i2c1_pins { bias-pull-up; };
+&i2s2 { + status = "okay"; +}; + &mdio { ext_rmii_phy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22";
From: Ondrej Jirman megous@megous.com
The board has HDMI output, enable audio on it.
Signed-off-by: Ondrej Jirman megous@megous.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts index 7d7aad18f078..e6ed8774a17f 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts @@ -144,6 +144,14 @@ hdmi_out_con: endpoint { }; };
+&hdmi_sound { + status = "okay"; +}; + +&i2s2 { + status = "okay"; +}; + &ir { pinctrl-names = "default"; pinctrl-0 = <&r_ir_rx_pin>;
From: Ondrej Jirman megous@megous.com
The board has HDMI output, enable audio on it.
Signed-off-by: Ondrej Jirman megous@megous.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 8 ++++++++ arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 8 ++++++++ 2 files changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts index 4759ba3f2986..a5b45655fcf6 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts @@ -146,6 +146,14 @@ hdmi_out_con: endpoint { }; };
+&hdmi_sound { + status = "okay"; +}; + +&i2s2 { + status = "okay"; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts index 5aff8ecc66cb..ebb12a6f3a9f 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts @@ -146,6 +146,14 @@ hdmi_out_con: endpoint { }; };
+&hdmi_sound { + status = "okay"; +}; + +&i2s2 { + status = "okay"; +}; + &ir { pinctrl-names = "default"; pinctrl-0 = <&r_ir_rx_pin>;
From: Ondrej Jirman megous@megous.com
The board has HDMI output, enable audio on it.
Signed-off-by: Ondrej Jirman megous@megous.com Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts index 15c9dd8c4479..193587e78031 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts @@ -128,6 +128,14 @@ hdmi_out_con: endpoint { }; };
+&hdmi_sound { + status = "okay"; +}; + +&i2s1 { + status = "okay"; +}; + &mmc0 { vmmc-supply = <®_cldo1>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
Enable Allwinner I2S driver for arm64 defconfig.
Signed-off-by: Clément Péron peron.clem@gmail.com --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 63003ec116ee..9a3c3bbe60e4 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -696,6 +696,7 @@ CONFIG_SND_SOC_ROCKCHIP_RT5645=m CONFIG_SND_SOC_RK3399_GRU_SOUND=m CONFIG_SND_SOC_SAMSUNG=y CONFIG_SND_SOC_RCAR=m +CONFIG_SND_SUN4I_I2S=m CONFIG_SND_SUN4I_SPDIF=m CONFIG_SND_SOC_TEGRA=m CONFIG_SND_SOC_TEGRA210_AHUB=m
participants (2)
-
Clément Péron
-
Samuel Holland