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
This commit is contained in:
commit
d466706b9d
@ -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:
|
||||
|
@ -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_RX_CHAN_MAP0_REG, 0xFEDCBA98);
|
||||
regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user