752 lines
25 KiB
Plaintext
752 lines
25 KiB
Plaintext
|
From b5cb1681a065bd03b0eb84ca243bc50ab0fa54c1 Mon Sep 17 00:00:00 2001
|
||
|
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||
|
Date: Tue, 17 Sep 2019 17:55:07 +0200
|
||
|
Subject: [PATCH] WIP: I2S improvements (to be mainlined)
|
||
|
|
||
|
Work done by Marcus Cooper (codekipper)
|
||
|
---
|
||
|
sound/soc/sunxi/sun4i-i2s.c | 454 ++++++++++++++++++++++++++++++++----
|
||
|
1 file changed, 412 insertions(+), 42 deletions(-)
|
||
|
|
||
|
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
|
||
|
index d0a8d5810c0a..9a715a6bdbf9 100644
|
||
|
--- a/sound/soc/sunxi/sun4i-i2s.c
|
||
|
+++ b/sound/soc/sunxi/sun4i-i2s.c
|
||
|
@@ -23,7 +23,7 @@
|
||
|
|
||
|
#define SUN4I_I2S_CTRL_REG 0x00
|
||
|
#define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
|
||
|
-#define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
|
||
|
+#define SUN4I_I2S_CTRL_SDO_EN(lines) (((1 << (lines)) - 1) << 8)
|
||
|
#define SUN4I_I2S_CTRL_MODE_MASK BIT(5)
|
||
|
#define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5)
|
||
|
#define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
|
||
|
@@ -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
|
||
|
|
||
|
@@ -100,22 +100,25 @@
|
||
|
#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4)
|
||
|
|
||
|
#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19)
|
||
|
-#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19)
|
||
|
-#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19)
|
||
|
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19)
|
||
|
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19)
|
||
|
#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8)
|
||
|
#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
|
||
|
#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7)
|
||
|
-#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7)
|
||
|
-#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
|
||
|
+#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
|
||
|
|
||
|
#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(chan) ((chan - 1) << 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(chan) (chan - 1)
|
||
|
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) ((chan) - 1)
|
||
|
|
||
|
#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
|
||
|
#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
|
||
|
@@ -123,10 +126,27 @@
|
||
|
#define SUN8I_I2S_TX_CHAN_OFFSET(offset) ((offset) << 12)
|
||
|
#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
|
||
|
#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
|
||
|
+#define SUN8I_I2S_TX_CHAN_SEL_MASK GENMASK(2, 0)
|
||
|
+#define SUN8I_I2S_TX_CHAN_SEL(chan) ((chan) - 1)
|
||
|
|
||
|
#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;
|
||
|
|
||
|
/**
|
||
|
@@ -156,7 +179,16 @@ struct sun4i_i2s_quirks {
|
||
|
s8 (*get_wss)(const struct sun4i_i2s *, int);
|
||
|
int (*set_chan_cfg)(const struct sun4i_i2s *,
|
||
|
const struct snd_pcm_hw_params *);
|
||
|
- int (*set_fmt)(const struct sun4i_i2s *, unsigned int);
|
||
|
+ int (*set_fmt)(struct sun4i_i2s *, unsigned int);
|
||
|
+ void (*set_fmt_sext)(const struct sun4i_i2s *, unsigned int);
|
||
|
+ void (*set_txchanoffset)(const struct sun4i_i2s *, int);
|
||
|
+ void (*set_rxchanoffset)(const struct sun4i_i2s *);
|
||
|
+ void (*set_txchanen)(const struct sun4i_i2s *, int, int);
|
||
|
+ void (*set_rxchanen)(const struct sun4i_i2s *, int);
|
||
|
+ void (*set_txchansel)(const struct sun4i_i2s *, int, int);
|
||
|
+ void (*set_rxchansel)(const struct sun4i_i2s *, int);
|
||
|
+ void (*set_txchanmap)(const struct sun4i_i2s *, int, int);
|
||
|
+ void (*set_rxchanmap)(const struct sun4i_i2s *, int);
|
||
|
};
|
||
|
|
||
|
struct sun4i_i2s {
|
||
|
@@ -169,6 +201,7 @@ struct sun4i_i2s {
|
||
|
unsigned int mclk_freq;
|
||
|
unsigned int slots;
|
||
|
unsigned int slot_width;
|
||
|
+ unsigned int offset;
|
||
|
|
||
|
struct snd_dmaengine_dai_dma_data capture_dma_data;
|
||
|
struct snd_dmaengine_dai_dma_data playback_dma_data;
|
||
|
@@ -354,6 +387,9 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
|
||
|
|
||
|
regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
|
||
|
|
||
|
+ /* Set sign extension to pad out LSB with 0 */
|
||
|
+ i2s->variant->set_fmt_sext(i2s, 0);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -396,8 +432,8 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
|
||
|
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);
|
||
|
+ i2s->variant->set_txchanmap(i2s, 0, 0x76543210);
|
||
|
+ i2s->variant->set_rxchanmap(i2s, 0x3210);
|
||
|
|
||
|
/* Configure the channels */
|
||
|
regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
|
||
|
@@ -421,16 +457,12 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
|
||
|
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);
|
||
|
+ i2s->variant->set_txchanmap(i2s, 0, 0x76543210);
|
||
|
+ i2s->variant->set_rxchanmap(i2s, 0x3210);
|
||
|
|
||
|
/* Configure the channels */
|
||
|
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
|
||
|
- SUN4I_I2S_CHAN_SEL_MASK,
|
||
|
- SUN4I_I2S_CHAN_SEL(channels));
|
||
|
- regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
|
||
|
- SUN4I_I2S_CHAN_SEL_MASK,
|
||
|
- SUN4I_I2S_CHAN_SEL(channels));
|
||
|
+ i2s->variant->set_txchansel(i2s, 0, channels);
|
||
|
+ i2s->variant->set_rxchansel(i2s, channels);
|
||
|
|
||
|
regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
|
||
|
SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
|
||
|
@@ -448,7 +480,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
|
||
|
break;
|
||
|
|
||
|
case SND_SOC_DAIFMT_I2S:
|
||
|
- lrck_period = params_physical_width(params);
|
||
|
+ if (i2s->slot_width)
|
||
|
+ lrck_period = i2s->slot_width;
|
||
|
+ else
|
||
|
+ lrck_period = params_physical_width(params);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
@@ -466,6 +501,166 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static void sun8i_i2s_set_txchanoffset(const struct sun4i_i2s *i2s, int output)
|
||
|
+{
|
||
|
+ if (output >= 0 && output < 4)
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
|
||
|
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
|
||
|
+ SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun8i_i2s_set_rxchanoffset(const struct sun4i_i2s *i2s)
|
||
|
+{
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_RX_CHAN_SEL_REG,
|
||
|
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
|
||
|
+ SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun50i_h6_i2s_set_txchanoffset(const struct sun4i_i2s *i2s, int output)
|
||
|
+{
|
||
|
+ if (output >= 0 && output < 4)
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(i2s->offset));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun50i_h6_i2s_set_rxchanoffset(const struct sun4i_i2s *i2s)
|
||
|
+{
|
||
|
+ 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(i2s->offset));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun8i_i2s_set_txchanen(const struct sun4i_i2s *i2s, int output,
|
||
|
+ int channel)
|
||
|
+{
|
||
|
+ if (output >= 0 && output < 4)
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
|
||
|
+ SUN8I_I2S_TX_CHAN_EN_MASK,
|
||
|
+ SUN8I_I2S_TX_CHAN_EN(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun8i_i2s_set_rxchanen(const struct sun4i_i2s *i2s, int channel)
|
||
|
+{
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_RX_CHAN_SEL_REG,
|
||
|
+ SUN8I_I2S_TX_CHAN_EN_MASK,
|
||
|
+ SUN8I_I2S_TX_CHAN_EN(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun50i_h6_i2s_set_txchanen(const struct sun4i_i2s *i2s, int output,
|
||
|
+ int channel)
|
||
|
+{
|
||
|
+ if (output >= 0 && output < 4)
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_EN_MASK,
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_EN(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun50i_h6_i2s_set_rxchanen(const struct sun4i_i2s *i2s, int channel)
|
||
|
+{
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN50I_H6_I2S_RX_CHAN_SEL_REG,
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_EN_MASK,
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_EN(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun4i_i2s_set_txchansel(const struct sun4i_i2s *i2s, int output,
|
||
|
+ int channel)
|
||
|
+{
|
||
|
+ /* Configure the channels */
|
||
|
+ regmap_write(i2s->regmap,
|
||
|
+ SUN4I_I2S_TX_CHAN_SEL_REG,
|
||
|
+ SUN4I_I2S_CHAN_SEL(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun8i_i2s_set_txchansel(const struct sun4i_i2s *i2s, int output,
|
||
|
+ int channel)
|
||
|
+{
|
||
|
+ if (output >= 0 && output < 4)
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL_MASK,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun4i_i2s_set_rxchansel(const struct sun4i_i2s *i2s, int channel)
|
||
|
+{
|
||
|
+ /* Configure the channels */
|
||
|
+ regmap_write(i2s->regmap,
|
||
|
+ SUN4I_I2S_RX_CHAN_SEL_REG,
|
||
|
+ SUN4I_I2S_CHAN_SEL(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun8i_i2s_set_rxchansel(const struct sun4i_i2s *i2s, int channel)
|
||
|
+{
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_RX_CHAN_SEL_REG,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL_MASK,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun50i_h6_i2s_set_txchansel(const struct sun4i_i2s *i2s, int output,
|
||
|
+ int channel)
|
||
|
+{
|
||
|
+ if (output >= 0 && output < 4)
|
||
|
+ regmap_update_bits(i2s->regmap,
|
||
|
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_SEL(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun50i_h6_i2s_set_rxchansel(const struct sun4i_i2s *i2s, int channel)
|
||
|
+{
|
||
|
+ 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(channel));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun4i_i2s_set_txchanmap(const struct sun4i_i2s *i2s, int output,
|
||
|
+ int channel)
|
||
|
+{
|
||
|
+ regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, channel);
|
||
|
+}
|
||
|
+
|
||
|
+static void sun8i_i2s_set_txchanmap(const struct sun4i_i2s *i2s, int output,
|
||
|
+ int channel)
|
||
|
+{
|
||
|
+ if (output >= 0 && output < 4)
|
||
|
+ regmap_write(i2s->regmap,
|
||
|
+ SUN8I_I2S_TX_CHAN_MAP_REG + (output * 4), channel);
|
||
|
+}
|
||
|
+
|
||
|
+static void sun4i_i2s_set_rxchanmap(const struct sun4i_i2s *i2s, int channel)
|
||
|
+{
|
||
|
+ regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, channel);
|
||
|
+}
|
||
|
+
|
||
|
+static void sun8i_i2s_set_rxchanmap(const struct sun4i_i2s *i2s, int channel)
|
||
|
+{
|
||
|
+ regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, channel);
|
||
|
+}
|
||
|
+
|
||
|
+static void sun50i_h6_i2s_set_txchanmap(const struct sun4i_i2s *i2s, int output,
|
||
|
+ int channel)
|
||
|
+{
|
||
|
+ if (output >= 0 && output < 4)
|
||
|
+ regmap_write(i2s->regmap,
|
||
|
+ SUN50I_H6_I2S_TX_CHAN_MAP1_REG + (output * 8), channel);
|
||
|
+}
|
||
|
+
|
||
|
+static void sun50i_h6_i2s_set_rxchanmap(const struct sun4i_i2s *i2s, int channel)
|
||
|
+{
|
||
|
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, channel);
|
||
|
+}
|
||
|
+
|
||
|
static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
|
||
|
struct snd_pcm_hw_params *params,
|
||
|
struct snd_soc_dai *dai)
|
||
|
@@ -477,6 +672,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
|
||
|
unsigned int slots = channels;
|
||
|
int ret, sr, wss;
|
||
|
u32 width;
|
||
|
+ int lines;
|
||
|
|
||
|
if (i2s->slots)
|
||
|
slots = i2s->slots;
|
||
|
@@ -490,10 +686,82 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||
|
+ if (channels > dai->driver->playback.channels_max ||
|
||
|
+ channels < dai->driver->playback.channels_min) {
|
||
|
+ dev_err(dai->dev, "Unsupported number of channels: %d\n",
|
||
|
+ channels);
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ lines = (channels + 1) / 2;
|
||
|
+
|
||
|
+ /* Enable the required output lines */
|
||
|
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
|
||
|
+ SUN4I_I2S_CTRL_SDO_EN_MASK,
|
||
|
+ SUN4I_I2S_CTRL_SDO_EN(lines));
|
||
|
+
|
||
|
+ i2s->variant->set_txchanmap(i2s, 0, 0x10);
|
||
|
+ i2s->variant->set_txchansel(i2s, 0, channels > 1 ? 2 : 1);
|
||
|
+
|
||
|
+ if (i2s->variant->set_txchanen)
|
||
|
+ i2s->variant->set_txchanen(i2s, 0, 2);
|
||
|
+
|
||
|
+ if (i2s->variant->set_txchanoffset) {
|
||
|
+ 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));
|
||
|
+
|
||
|
+ if (channels > 2) {
|
||
|
+ i2s->variant->set_txchanmap(i2s, 1, 0x32);
|
||
|
+ i2s->variant->set_txchanoffset(i2s, 1);
|
||
|
+ i2s->variant->set_txchansel(i2s, 1,
|
||
|
+ channels > 3 ? 2 : 1);
|
||
|
+ i2s->variant->set_txchanen(i2s, 1, 2);
|
||
|
+ }
|
||
|
+ if (channels > 4) {
|
||
|
+ i2s->variant->set_txchanmap(i2s, 2, 0x54);
|
||
|
+ i2s->variant->set_txchanoffset(i2s, 2);
|
||
|
+ i2s->variant->set_txchansel(i2s, 2,
|
||
|
+ channels > 5 ? 2 : 1);
|
||
|
+ i2s->variant->set_txchanen(i2s, 2, 2);
|
||
|
+ }
|
||
|
+ if (channels > 6) {
|
||
|
+ i2s->variant->set_txchanmap(i2s, 3, 0x76);
|
||
|
+ i2s->variant->set_txchanoffset(i2s, 3);
|
||
|
+ i2s->variant->set_txchansel(i2s, 3,
|
||
|
+ channels > 6 ? 2 : 1);
|
||
|
+ i2s->variant->set_txchanen(i2s, 3, 2);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ if (channels > dai->driver->capture.channels_max ||
|
||
|
+ channels < dai->driver->capture.channels_min) {
|
||
|
+ dev_err(dai->dev, "Unsupported number of channels: %d\n",
|
||
|
+ channels);
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Map the channels for capture */
|
||
|
+ i2s->variant->set_rxchanmap(i2s, 0x10);
|
||
|
+ i2s->variant->set_rxchansel(i2s, channels);
|
||
|
+
|
||
|
+ if (i2s->variant->set_rxchanen)
|
||
|
+ i2s->variant->set_rxchanen(i2s, channels);
|
||
|
+
|
||
|
+ if (i2s->variant->set_rxchanoffset)
|
||
|
+ 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 (params_physical_width(params)) {
|
||
|
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));
|
||
|
@@ -516,7 +784,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
|
||
|
slots, slot_width);
|
||
|
}
|
||
|
|
||
|
-static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||
|
+static int sun4i_i2s_set_soc_fmt(struct sun4i_i2s *i2s,
|
||
|
unsigned int fmt)
|
||
|
{
|
||
|
u32 val;
|
||
|
@@ -589,11 +857,10 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||
|
+static int sun8i_i2s_set_soc_fmt(struct sun4i_i2s *i2s,
|
||
|
unsigned int fmt)
|
||
|
{
|
||
|
u32 mode, val;
|
||
|
- u8 offset;
|
||
|
|
||
|
/*
|
||
|
* DAI clock polarity
|
||
|
@@ -632,27 +899,27 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||
|
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||
|
case SND_SOC_DAIFMT_DSP_A:
|
||
|
mode = SUN8I_I2S_CTRL_MODE_PCM;
|
||
|
- offset = 1;
|
||
|
+ i2s->offset = 1;
|
||
|
break;
|
||
|
|
||
|
case SND_SOC_DAIFMT_DSP_B:
|
||
|
mode = SUN8I_I2S_CTRL_MODE_PCM;
|
||
|
- offset = 0;
|
||
|
+ i2s->offset = 0;
|
||
|
break;
|
||
|
|
||
|
case SND_SOC_DAIFMT_I2S:
|
||
|
mode = SUN8I_I2S_CTRL_MODE_LEFT;
|
||
|
- offset = 1;
|
||
|
+ i2s->offset = 1;
|
||
|
break;
|
||
|
|
||
|
case SND_SOC_DAIFMT_LEFT_J:
|
||
|
mode = SUN8I_I2S_CTRL_MODE_LEFT;
|
||
|
- offset = 0;
|
||
|
+ i2s->offset = 0;
|
||
|
break;
|
||
|
|
||
|
case SND_SOC_DAIFMT_RIGHT_J:
|
||
|
mode = SUN8I_I2S_CTRL_MODE_RIGHT;
|
||
|
- offset = 0;
|
||
|
+ i2s->offset = 0;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
@@ -913,12 +933,8 @@ static int sun8i_i2s_set_soc_fmt(struct sun4i_i2s *i2s,
|
||
|
|
||
|
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,
|
||
|
- SUN8I_I2S_TX_CHAN_OFFSET_MASK,
|
||
|
- SUN8I_I2S_TX_CHAN_OFFSET(offset));
|
||
|
- regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
|
||
|
- SUN8I_I2S_TX_CHAN_OFFSET_MASK,
|
||
|
- SUN8I_I2S_TX_CHAN_OFFSET(offset));
|
||
|
+ i2s->variant->set_txchanoffset(i2s, 0);
|
||
|
+ i2s->variant->set_rxchanoffset(i2s);
|
||
|
|
||
|
/* DAI clock master masks */
|
||
|
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||
|
@@ -691,6 +954,22 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static void sun4i_i2s_set_fmt_sext(const struct sun4i_i2s *i2s,
|
||
|
+ unsigned int sext)
|
||
|
+{
|
||
|
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
|
||
|
+ SUN4I_I2S_FMT1_REG_SEXT_MASK,
|
||
|
+ SUN4I_I2S_FMT1_REG_SEXT(sext));
|
||
|
+}
|
||
|
+
|
||
|
+static void sun8i_i2s_set_fmt_sext(const struct sun4i_i2s *i2s,
|
||
|
+ unsigned int sext)
|
||
|
+{
|
||
|
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
|
||
|
+ SUN8I_I2S_FMT1_REG_SEXT_MASK,
|
||
|
+ SUN8I_I2S_FMT1_REG_SEXT(sext));
|
||
|
+}
|
||
|
+
|
||
|
static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||
|
{
|
||
|
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
|
||
|
@@ -717,9 +996,9 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||
|
static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
|
||
|
{
|
||
|
/* Flush RX FIFO */
|
||
|
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
|
||
|
- SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
|
||
|
- SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
|
||
|
+ regmap_write_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
|
||
|
+ SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
|
||
|
+ SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
|
||
|
|
||
|
/* Clear RX counter */
|
||
|
regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);
|
||
|
@@ -738,9 +1017,9 @@ static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
|
||
|
static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
|
||
|
{
|
||
|
/* Flush TX FIFO */
|
||
|
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
|
||
|
- SUN4I_I2S_FIFO_CTRL_FLUSH_TX,
|
||
|
- SUN4I_I2S_FIFO_CTRL_FLUSH_TX);
|
||
|
+ regmap_write_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
|
||
|
+ SUN4I_I2S_FIFO_CTRL_FLUSH_TX,
|
||
|
+ SUN4I_I2S_FIFO_CTRL_FLUSH_TX);
|
||
|
|
||
|
/* Clear TX counter */
|
||
|
regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0);
|
||
|
@@ -862,6 +1141,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 = {
|
||
|
@@ -869,14 +1152,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,
|
||
|
@@ -971,6 +1254,22 @@ static const struct reg_default sun8i_i2s_reg_defaults[] = {
|
||
|
{ SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
|
||
|
};
|
||
|
|
||
|
+static const struct reg_default sun50i_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,
|
||
|
@@ -998,6 +1297,19 @@ static const struct regmap_config sun8i_i2s_regmap_config = {
|
||
|
.volatile_reg = sun8i_i2s_volatile_reg,
|
||
|
};
|
||
|
|
||
|
+static const struct regmap_config sun50i_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_i2s_reg_defaults,
|
||
|
+ .num_reg_defaults = ARRAY_SIZE(sun50i_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);
|
||
|
@@ -1077,6 +1389,11 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
|
||
|
.get_wss = sun4i_i2s_get_wss,
|
||
|
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
|
||
|
.set_fmt = sun4i_i2s_set_soc_fmt,
|
||
|
+ .set_fmt_sext = sun4i_i2s_set_fmt_sext,
|
||
|
+ .set_txchansel = sun4i_i2s_set_txchansel,
|
||
|
+ .set_rxchansel = sun4i_i2s_set_rxchansel,
|
||
|
+ .set_txchanmap = sun4i_i2s_set_txchanmap,
|
||
|
+ .set_rxchanmap = sun4i_i2s_set_rxchanmap,
|
||
|
};
|
||
|
|
||
|
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
|
||
|
@@ -1095,6 +1412,11 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
|
||
|
.get_wss = sun4i_i2s_get_wss,
|
||
|
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
|
||
|
.set_fmt = sun4i_i2s_set_soc_fmt,
|
||
|
+ .set_fmt_sext = sun4i_i2s_set_fmt_sext,
|
||
|
+ .set_txchansel = sun4i_i2s_set_txchansel,
|
||
|
+ .set_rxchansel = sun4i_i2s_set_rxchansel,
|
||
|
+ .set_txchanmap = sun4i_i2s_set_txchanmap,
|
||
|
+ .set_rxchanmap = sun4i_i2s_set_rxchanmap,
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
@@ -1118,6 +1440,9 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
|
||
|
.get_wss = sun4i_i2s_get_wss,
|
||
|
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
|
||
|
.set_fmt = sun4i_i2s_set_soc_fmt,
|
||
|
+ .set_fmt_sext = sun4i_i2s_set_fmt_sext,
|
||
|
+ .set_txchansel = sun4i_i2s_set_txchansel,
|
||
|
+ .set_rxchansel = sun4i_i2s_set_rxchansel,
|
||
|
};
|
||
|
|
||
|
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
|
||
|
@@ -1136,6 +1461,15 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
|
||
|
.get_wss = sun8i_i2s_get_sr_wss,
|
||
|
.set_chan_cfg = sun8i_i2s_set_chan_cfg,
|
||
|
.set_fmt = sun8i_i2s_set_soc_fmt,
|
||
|
+ .set_fmt_sext = sun8i_i2s_set_fmt_sext,
|
||
|
+ .set_txchanoffset = sun8i_i2s_set_txchanoffset,
|
||
|
+ .set_rxchanoffset = sun8i_i2s_set_rxchanoffset,
|
||
|
+ .set_txchanen = sun8i_i2s_set_txchanen,
|
||
|
+ .set_rxchanen = sun8i_i2s_set_rxchanen,
|
||
|
+ .set_txchansel = sun8i_i2s_set_txchansel,
|
||
|
+ .set_rxchansel = sun8i_i2s_set_rxchansel,
|
||
|
+ .set_txchanmap = sun8i_i2s_set_txchanmap,
|
||
|
+ .set_rxchanmap = sun8i_i2s_set_rxchanmap,
|
||
|
};
|
||
|
|
||
|
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
|
||
|
@@ -1154,6 +1488,38 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
|
||
|
.get_wss = sun4i_i2s_get_wss,
|
||
|
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
|
||
|
.set_fmt = sun4i_i2s_set_soc_fmt,
|
||
|
+ .set_fmt_sext = sun4i_i2s_set_fmt_sext,
|
||
|
+ .set_txchansel = sun4i_i2s_set_txchansel,
|
||
|
+ .set_rxchansel = sun4i_i2s_set_rxchansel,
|
||
|
+ .set_txchanmap = sun4i_i2s_set_txchanmap,
|
||
|
+ .set_rxchanmap = sun4i_i2s_set_rxchanmap,
|
||
|
+};
|
||
|
+
|
||
|
+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_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 = sun8i_i2s_set_chan_cfg,
|
||
|
+ .set_fmt = sun8i_i2s_set_soc_fmt,
|
||
|
+ .set_fmt_sext = sun8i_i2s_set_fmt_sext,
|
||
|
+ .set_txchanoffset = sun50i_h6_i2s_set_txchanoffset,
|
||
|
+ .set_rxchanoffset = sun50i_h6_i2s_set_rxchanoffset,
|
||
|
+ .set_txchanen = sun50i_h6_i2s_set_txchanen,
|
||
|
+ .set_rxchanen = sun50i_h6_i2s_set_rxchanen,
|
||
|
+ .set_txchansel = sun50i_h6_i2s_set_txchansel,
|
||
|
+ .set_rxchansel = sun50i_h6_i2s_set_rxchansel,
|
||
|
+ .set_txchanmap = sun50i_h6_i2s_set_txchanmap,
|
||
|
+ .set_rxchanmap = sun50i_h6_i2s_set_rxchanmap,
|
||
|
};
|
||
|
|
||
|
static int sun4i_i2s_init_regmap_fields(struct device *dev,
|
||
|
@@ -1325,6 +1691,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);
|
||
|
--
|
||
|
2.23.0
|
||
|
|
||
|
From 2da43795f6191505b2dd6e30938c3af4c90bf745 Mon Sep 17 00:00:00 2001
|
||
|
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||
|
Date: Thu, 7 Nov 2019 07:36:11 +0100
|
||
|
Subject: [PATCH] sound: soc: sun4i-i2s: Fix rate calculation
|
||
|
|
||
|
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||
|
---
|
||
|
sound/soc/sunxi/sun4i-i2s.c | 3 +++
|
||
|
1 file changed, 3 insertions(+)
|
||
|
|
||
|
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
|
||
|
index d0a8d5810c0a..6c4241cb6509 100644
|
||
|
--- a/sound/soc/sunxi/sun4i-i2s.c
|
||
|
+++ b/sound/soc/sunxi/sun4i-i2s.c
|
||
|
@@ -334,6 +334,9 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
+ if (i2s->slot_width)
|
||
|
+ slot_width = i2s->slot_width;
|
||
|
+
|
||
|
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
|
||
|
bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
|
||
|
rate, slots, slot_width);
|
||
|
--
|
||
|
2.24.0
|
||
|
|