Skip to content

Commit 8fbfd38

Browse files
jernejskcodekipper
authored andcommitted
ASoC: sun4i-i2s: Add support for H6 I2S
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>
1 parent 20b4d42 commit 8fbfd38

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

sound/soc/sunxi/sun4i-i2s.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,21 @@
121121
#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
122122
#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
123123

124+
/* Defines required for sun50i-h6 support */
125+
#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK GENMASK(21, 20)
126+
#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset) ((offset) << 20)
127+
#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK GENMASK(19, 16)
128+
#define SUN50I_H6_I2S_TX_CHAN_SEL(chan) ((chan - 1) << 16)
129+
#define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(19, 16)
130+
#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1))
131+
132+
#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG 0x44
133+
#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG 0x48
134+
135+
#define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64
136+
#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68
137+
#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG 0x6C
138+
124139
struct sun4i_i2s;
125140

126141
/**
@@ -445,6 +460,25 @@ static void sun8i_i2s_set_rxchanoffset(const struct sun4i_i2s *i2s)
445460
SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset));
446461
}
447462

463+
static void sun50i_h6_i2s_set_txchanoffset(const struct sun4i_i2s *i2s, int output)
464+
{
465+
if (output >= 0 && output < 4) {
466+
regmap_update_bits(i2s->regmap,
467+
SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
468+
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
469+
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(i2s->offset));
470+
}
471+
472+
}
473+
474+
static void sun50i_h6_i2s_set_rxchanoffset(const struct sun4i_i2s *i2s)
475+
{
476+
regmap_update_bits(i2s->regmap,
477+
SUN8I_I2S_RX_CHAN_SEL_REG,
478+
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
479+
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(i2s->offset));
480+
}
481+
448482
static void sun8i_i2s_set_txchanen(const struct sun4i_i2s *i2s, int output,
449483
int channel)
450484
{
@@ -464,6 +498,26 @@ static void sun8i_i2s_set_rxchanen(const struct sun4i_i2s *i2s, int channel)
464498
SUN8I_I2S_TX_CHAN_EN(channel));
465499
}
466500

501+
502+
static void sun50i_h6_i2s_set_txchanen(const struct sun4i_i2s *i2s, int output,
503+
int channel)
504+
{
505+
if (output >= 0 && output < 4) {
506+
regmap_update_bits(i2s->regmap,
507+
SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
508+
SUN50I_H6_I2S_TX_CHAN_EN_MASK,
509+
SUN50I_H6_I2S_TX_CHAN_EN(channel));
510+
}
511+
}
512+
513+
static void sun50i_h6_i2s_set_rxchanen(const struct sun4i_i2s *i2s, int channel)
514+
{
515+
regmap_update_bits(i2s->regmap,
516+
SUN8I_I2S_RX_CHAN_SEL_REG,
517+
SUN50I_H6_I2S_TX_CHAN_EN_MASK,
518+
SUN50I_H6_I2S_TX_CHAN_EN(channel));
519+
}
520+
467521
static void sun4i_i2s_set_txchansel(const struct sun4i_i2s *i2s, int output,
468522
int channel)
469523
{
@@ -500,6 +554,25 @@ static void sun8i_i2s_set_rxchansel(const struct sun4i_i2s *i2s, int channel)
500554
SUN8I_I2S_TX_CHAN_SEL(channel));
501555
}
502556

557+
static void sun50i_h6_i2s_set_txchansel(const struct sun4i_i2s *i2s, int output,
558+
int channel)
559+
{
560+
if (output >= 0 && output < 4) {
561+
regmap_update_bits(i2s->regmap,
562+
SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
563+
SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
564+
SUN50I_H6_I2S_TX_CHAN_SEL(channel));
565+
}
566+
}
567+
568+
static void sun50i_h6_i2s_set_rxchansel(const struct sun4i_i2s *i2s, int channel)
569+
{
570+
regmap_update_bits(i2s->regmap,
571+
SUN8I_I2S_RX_CHAN_SEL_REG,
572+
SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
573+
SUN50I_H6_I2S_TX_CHAN_SEL(channel));
574+
}
575+
503576
static void sun4i_i2s_set_txchanmap(const struct sun4i_i2s *i2s, int output,
504577
int channel)
505578
{
@@ -525,6 +598,20 @@ static void sun8i_i2s_set_rxchanmap(const struct sun4i_i2s *i2s, int channel)
525598
regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, channel);
526599
}
527600

601+
static void sun50i_h6_i2s_set_txchanmap(const struct sun4i_i2s *i2s, int output,
602+
int channel)
603+
{
604+
if (output >= 0 && output < 4) {
605+
regmap_write(i2s->regmap,
606+
SUN50I_H6_I2S_TX_CHAN_MAP1_REG + (output * 8), channel);
607+
}
608+
}
609+
610+
static void sun50i_h6_i2s_set_rxchanmap(const struct sun4i_i2s *i2s, int channel)
611+
{
612+
regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, channel);
613+
}
614+
528615
static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
529616
struct snd_pcm_hw_params *params,
530617
struct snd_soc_dai *dai)
@@ -998,6 +1085,22 @@ static const struct reg_default sun8i_i2s_reg_defaults[] = {
9981085
{ SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
9991086
};
10001087

1088+
static const struct reg_default sun50i_i2s_reg_defaults[] = {
1089+
{ SUN4I_I2S_CTRL_REG, 0x00060000 },
1090+
{ SUN4I_I2S_FMT0_REG, 0x00000033 },
1091+
{ SUN4I_I2S_FMT1_REG, 0x00000030 },
1092+
{ SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
1093+
{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
1094+
{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
1095+
{ SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
1096+
{ SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
1097+
{ SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 },
1098+
{ SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 },
1099+
{ SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },
1100+
{ SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },
1101+
{ SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },
1102+
};
1103+
10011104
static const struct regmap_config sun4i_i2s_regmap_config = {
10021105
.reg_bits = 32,
10031106
.reg_stride = 4,
@@ -1025,6 +1128,19 @@ static const struct regmap_config sun8i_i2s_regmap_config = {
10251128
.volatile_reg = sun8i_i2s_volatile_reg,
10261129
};
10271130

1131+
static const struct regmap_config sun50i_i2s_regmap_config = {
1132+
.reg_bits = 32,
1133+
.reg_stride = 4,
1134+
.val_bits = 32,
1135+
.max_register = SUN50I_H6_I2S_RX_CHAN_MAP1_REG,
1136+
.cache_type = REGCACHE_FLAT,
1137+
.reg_defaults = sun50i_i2s_reg_defaults,
1138+
.num_reg_defaults = ARRAY_SIZE(sun50i_i2s_reg_defaults),
1139+
.writeable_reg = sun4i_i2s_wr_reg,
1140+
.readable_reg = sun8i_i2s_rd_reg,
1141+
.volatile_reg = sun8i_i2s_volatile_reg,
1142+
};
1143+
10281144
static int sun4i_i2s_runtime_resume(struct device *dev)
10291145
{
10301146
struct sun4i_i2s *i2s = dev_get_drvdata(dev);
@@ -1199,6 +1315,33 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
11991315
.set_rxchanmap = sun4i_i2s_set_rxchanmap,
12001316
};
12011317

1318+
static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = {
1319+
.has_reset = true,
1320+
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
1321+
.sun4i_i2s_regmap = &sun50i_i2s_regmap_config,
1322+
.has_fmt_set_lrck_period = true,
1323+
.has_chcfg = true,
1324+
.has_chsel_tx_chen = true,
1325+
.has_chsel_offset = true,
1326+
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
1327+
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
1328+
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
1329+
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
1330+
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
1331+
.field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5),
1332+
.get_sr = sun8i_i2s_get_sr_wss,
1333+
.get_wss = sun8i_i2s_get_sr_wss,
1334+
.set_format = sun8i_i2s_set_format,
1335+
.set_txchanoffset = sun50i_h6_i2s_set_txchanoffset,
1336+
.set_rxchanoffset = sun50i_h6_i2s_set_rxchanoffset,
1337+
.set_txchanen = sun50i_h6_i2s_set_txchanen,
1338+
.set_rxchanen = sun50i_h6_i2s_set_rxchanen,
1339+
.set_txchansel = sun50i_h6_i2s_set_txchansel,
1340+
.set_rxchansel = sun50i_h6_i2s_set_rxchansel,
1341+
.set_txchanmap = sun50i_h6_i2s_set_txchanmap,
1342+
.set_rxchanmap = sun50i_h6_i2s_set_rxchanmap,
1343+
};
1344+
12021345
static int sun4i_i2s_init_regmap_fields(struct device *dev,
12031346
struct sun4i_i2s *i2s)
12041347
{
@@ -1391,6 +1534,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
13911534
.compatible = "allwinner,sun50i-a64-codec-i2s",
13921535
.data = &sun50i_a64_codec_i2s_quirks,
13931536
},
1537+
{
1538+
.compatible = "allwinner,sun50i-h6-i2s",
1539+
.data = &sun50i_h6_i2s_quirks,
1540+
},
13941541
{}
13951542
};
13961543
MODULE_DEVICE_TABLE(of, sun4i_i2s_match);

0 commit comments

Comments
 (0)