Unverified Commit d466706b authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: sun4i-i2s: Support for Allwinner R329 and D1 SoCs

Merge series from Samuel Holland <samuel@sholland.org>:

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

--
2.33.1
parents ec29170c e2ce580f
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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:
+54 −14
Original line number Diff line number Diff line
@@ -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;

/**
@@ -175,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;
@@ -523,13 +532,20 @@ 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);
	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, 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 +579,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 +1226,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 },
@@ -1249,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),
@@ -1434,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)
{
@@ -1606,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);