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 <sam...@sholland.org>
---
 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

Reply via email to