[PATCH 15/25] ASoC: sun8i-codec: Support the TDM slot binding

From: Samuel Holland
Date: Wed Sep 30 2020 - 22:12:58 EST


Now that BCLK and LRCK rate calculations can handle any
hardware-supported slot width and number of slots, enable
support for overriding these parameters from the device tree.

Signed-off-by: Samuel Holland <samuel@xxxxxxxxxxxx>
---
sound/soc/sunxi/sun8i-codec.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 78feed37aa42..0a53dc0c34d0 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -94,25 +94,31 @@
#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4)
#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2)

enum {
AIF1,
NAIFS
};

+struct sun8i_codec_aif {
+ unsigned int slots;
+ unsigned int slot_width;
+};
+
struct sun8i_codec_quirks {
bool legacy_widgets : 1;
bool lrck_inversion : 1;
};

struct sun8i_codec {
struct regmap *regmap;
struct clk *clk_module;
const struct sun8i_codec_quirks *quirks;
+ struct sun8i_codec_aif aifs[NAIFS];
};

static int sun8i_codec_runtime_resume(struct device *dev)
{
struct sun8i_codec *scodec = dev_get_drvdata(dev);
int ret;

regcache_cache_only(scodec->regmap, false);
@@ -256,16 +262,32 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)

regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);

return 0;
}

+static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+ struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+ if (slot_width && !is_power_of_2(slot_width))
+ return -EINVAL;
+
+ aif->slots = slots;
+ aif->slot_width = slot_width;
+
+ return 0;
+}
+
struct sun8i_codec_clk_div {
u8 div;
u8 val;
};

static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
{ .div = 1, .val = 0 },
{ .div = 2, .val = 1 },
@@ -316,18 +338,19 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
return order_base_2(div);
}

static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
- unsigned int slots = params_channels(params);
- unsigned int slot_width = params_width(params);
+ struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+ unsigned int slots = aif->slots ?: params_channels(params);
+ unsigned int slot_width = aif->slot_width ?: params_width(params);
int lrck_div_order, sample_rate, word_size;
u8 bclk_div;

/* word size */
switch (params_width(params)) {
case 8:
word_size = 0x0;
break;
@@ -371,16 +394,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);

return 0;
}

static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
.set_fmt = sun8i_codec_set_fmt,
+ .set_tdm_slot = sun8i_codec_set_tdm_slot,
.hw_params = sun8i_codec_hw_params,
};

static struct snd_soc_dai_driver sun8i_codec_dais[] = {
{
.name = "sun8i-codec-aif1",
.id = AIF1,
.ops = &sun8i_codec_dai_ops,
--
2.26.2