[PATCH 0/3] ASoC: sun4i-i2s: Support for Allwinner R329 and D1 SoCs
This series extends the sun4i-i2s binding and driver to support some newer versions of the hardware. Each instance of the hardwar now has multiple input/output pins, and channels can be muxed between them. Since so far the driver only supports a "default" linear channel map, the driver changes are minimal.
Samuel Holland (3): ASoC: dt-bindings: sun4i-i2s: Add compatibles for R329 and D1 ASoC: sun4i-i2s: Update registers for more channels ASoC: sun4i-i2s: Add support for the R329/D1 variant
.../sound/allwinner,sun4i-a10-i2s.yaml | 5 ++ sound/soc/sunxi/sun4i-i2s.c | 68 +++++++++++++++---- 2 files changed, 59 insertions(+), 14 deletions(-)
R329 contains I2S controllers which are similar to, but are incompatible with, the H6 variant, because they change the layout of the RX channel mapping registers. The D1 contains I2S controllers which appear to be identical to those in the R329.
Signed-off-by: Samuel Holland samuel@sholland.org ---
.../devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml index 7d48ea094c66..c21c807b667c 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml @@ -31,6 +31,10 @@ properties: - const: allwinner,sun50i-a64-i2s - const: allwinner,sun8i-h3-i2s - const: allwinner,sun50i-h6-i2s + - const: allwinner,sun50i-r329-i2s + - items: + - const: allwinner,sun20i-d1-i2s + - const: allwinner,sun50i-r329-i2s
reg: maxItems: 1 @@ -67,6 +71,7 @@ allOf: - allwinner,sun8i-h3-i2s - allwinner,sun50i-a64-codec-i2s - allwinner,sun50i-h6-i2s + - allwinner,sun50i-r329-i2s
then: required:
H6 expands the number of channels in each direction to 16, so the slot number fields need to be expanded from 3 to 4 bits each.
R329/D1 expand that further by allowing each of the 16 slots to map to any of 4 data pins. For TX, the configuration of each pin is independent, so there is a copy of the mapping registers for each pin. For RX, each of the 16 slots can map to only one pin, so the registers were changed to add the pin selection inline with the channel mapping.
Signed-off-by: Samuel Holland samuel@sholland.org ---
sound/soc/sunxi/sun4i-i2s.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 1e9116cd365e..7da8a16955a1 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -115,9 +115,9 @@ #define SUN8I_I2S_FIFO_TX_REG 0x20
#define SUN8I_I2S_CHAN_CFG_REG 0x30 -#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(6, 4) +#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(7, 4) #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) ((chan - 1) << 4) -#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(2, 0) +#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(3, 0) #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1)
#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44 @@ -138,13 +138,19 @@ #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_TX_CHAN_SEL_REG(pin) (0x34 + 4 * (pin)) +#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG(pin) (0x44 + 8 * (pin)) +#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG(pin) (0x48 + 8 * (pin))
#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
+#define SUN50I_R329_I2S_RX_CHAN_MAP0_REG 0x68 +#define SUN50I_R329_I2S_RX_CHAN_MAP1_REG 0x6c +#define SUN50I_R329_I2S_RX_CHAN_MAP2_REG 0x70 +#define SUN50I_R329_I2S_RX_CHAN_MAP3_REG 0x74 + struct sun4i_i2s;
/** @@ -523,13 +529,13 @@ static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, unsigned int lrck_period;
/* Map the channels for playback and capture */ - regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0xFEDCBA98); - regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210); + regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0xFEDCBA98); + regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x76543210); regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98); 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, + regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), 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, @@ -563,7 +569,7 @@ static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), SUN50I_H6_I2S_TX_CHAN_EN_MASK, SUN50I_H6_I2S_TX_CHAN_EN(channels));
@@ -1210,9 +1216,9 @@ static const struct reg_default sun50i_h6_i2s_reg_defaults[] = { { 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_TX_CHAN_SEL_REG(0), 0x00000000 }, + { SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0x00000000 }, + { SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 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 },
This adds a new set of quirks to set the right RX channel map. Since that is the only change to the register layout, reuse the H6 regmap config by extending its last register. R329 support is added by its compatible string. D1 uses R329 as its fallback compatible, so no additional code change is needed for it.
Signed-off-by: Samuel Holland samuel@sholland.org ---
sound/soc/sunxi/sun4i-i2s.c | 40 ++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 7da8a16955a1..7047f71629ab 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -181,6 +181,9 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_wss; struct reg_field field_fmt_sr;
+ unsigned int num_din_pins; + unsigned int num_dout_pins; + const struct sun4i_i2s_clk_div *bclk_dividers; unsigned int num_bclk_dividers; const struct sun4i_i2s_clk_div *mclk_dividers; @@ -531,8 +534,15 @@ static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0xFEDCBA98); regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x76543210); - regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98); - regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210); + if (i2s->variant->num_din_pins > 1) { + regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP0_REG, 0x0F0E0D0C); + regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP1_REG, 0x0B0A0908); + regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP2_REG, 0x07060504); + regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP3_REG, 0x03020100); + } else { + regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98); + regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210); + }
/* Configure the channels */ regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), @@ -1255,7 +1265,7 @@ 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, + .max_register = SUN50I_R329_I2S_RX_CHAN_MAP3_REG, .cache_type = REGCACHE_FLAT, .reg_defaults = sun50i_h6_i2s_reg_defaults, .num_reg_defaults = ARRAY_SIZE(sun50i_h6_i2s_reg_defaults), @@ -1440,6 +1450,26 @@ static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = { .set_fmt = sun50i_h6_i2s_set_soc_fmt, };
+static const struct sun4i_i2s_quirks sun50i_r329_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), + .num_din_pins = 4, + .num_dout_pins = 4, + .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) { @@ -1612,6 +1642,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun50i-h6-i2s", .data = &sun50i_h6_i2s_quirks, }, + { + .compatible = "allwinner,sun50i-r329-i2s", + .data = &sun50i_r329_i2s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
On Wed, Feb 02, 2022 at 08:01:12PM -0600, Samuel Holland wrote:
This series extends the sun4i-i2s binding and driver to support some newer versions of the hardware. Each instance of the hardwar now has multiple input/output pins, and channels can be muxed between them. Since so far the driver only supports a "default" linear channel map, the driver changes are minimal.
Acked-by: Maxime Ripard maxime@cerno.tech
Maxime
On Wed, 2 Feb 2022 20:01:12 -0600, Samuel Holland wrote:
This series extends the sun4i-i2s binding and driver to support some newer versions of the hardware. Each instance of the hardwar now has multiple input/output pins, and channels can be muxed between them. Since so far the driver only supports a "default" linear channel map, the driver changes are minimal.
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/3] ASoC: dt-bindings: sun4i-i2s: Add compatibles for R329 and D1 commit: 7f97b2ad948343c3be543d12c2965f74bddc34c7 [2/3] ASoC: sun4i-i2s: Update registers for more channels commit: c8bbc1de9088fedb5d71db7d185c37db18feb2e1 [3/3] ASoC: sun4i-i2s: Add support for the R329/D1 variant commit: e2ce580f1fffc009807da73adf7dc86912ab6a19
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
participants (3)
-
Mark Brown
-
Maxime Ripard
-
Samuel Holland