This amp supports TDM mode, so implement the set_tdm_slot operation to
let the SoC driver configure the TDM slot number, width, and masks.

Signed-off-by: Val Packett <[email protected]>
---
 sound/soc/codecs/aw88261.c | 88 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/aw88261.h | 53 +++++++++++++++++++++++
 2 files changed, 141 insertions(+)

diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
index 2064e72b51af..7b0e778f5a25 100644
--- a/sound/soc/codecs/aw88261.c
+++ b/sound/soc/codecs/aw88261.c
@@ -10,6 +10,7 @@
 
 #include <linux/i2c.h>
 #include <linux/firmware.h>
+#include <linux/bitops.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <sound/soc.h>
@@ -181,6 +182,30 @@ static int aw88261_dev_configure_syspll(struct aw88261 
*aw88261)
        struct aw_device *aw_dev = aw88261->aw_pa;
        int ret;
 
+       /* Configure TDM slots (I2S is represented as no slots) */
+       ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL2_REG,
+                       ~AW88261_SLOT_NUM_MASK, aw88261->slot_num_value);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL2_REG,
+                       ~AW88261_I2S_TX_SLOTVLD_MASK,
+                       aw88261->tx_slotvld_mask);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL2_REG,
+                       ~AW88261_I2S_RXL_SLOTVLD_MASK,
+                       aw88261->rxl_slotvld_mask);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL2_REG,
+                       ~AW88261_I2S_RXR_SLOTVLD_MASK,
+                       aw88261->rxr_slotvld_mask);
+       if (ret)
+               return ret;
+
        /* PLL divider must be used for 8/16/32 kHz modes */
        ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
                        ~AW88261_CCO_MUX_MASK, aw88261->cco_mux_value);
@@ -710,9 +735,11 @@ static int aw88261_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_DSP_A:
                aw88261->md_value = AW88261_I2SMD_PHILIPS_STANDARD_VALUE;
                break;
        case SND_SOC_DAIFMT_MSB:
+       case SND_SOC_DAIFMT_DSP_B:
                aw88261->md_value = AW88261_I2SMD_MSB_JUSTIFIED_VALUE;
                break;
        case SND_SOC_DAIFMT_LSB:
@@ -819,9 +846,68 @@ static int aw88261_hw_params(struct snd_pcm_substream 
*substream,
        return 0;
 }
 
+static int aw88261_set_tdm_slot(struct snd_soc_dai *dai,
+       unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+       struct snd_soc_component *component = dai->component;
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+       int bit;
+
+       switch (slots) {
+       case 0:
+               aw88261->slot_num_value = AW88261_SLOT_NUM_I2S_MODE_VALUE;
+               break;
+       case 1:
+               aw88261->slot_num_value = AW88261_SLOT_NUM_TDM1S_VALUE;
+               break;
+       case 2:
+               aw88261->slot_num_value = AW88261_SLOT_NUM_TDM2S_VALUE;
+               break;
+       case 4:
+               aw88261->slot_num_value = AW88261_SLOT_NUM_TDM4S_VALUE;
+               break;
+       case 6:
+               aw88261->slot_num_value = AW88261_SLOT_NUM_TDM6S_VALUE;
+               break;
+       case 8:
+               aw88261->slot_num_value = AW88261_SLOT_NUM_TDM8S_VALUE;
+               break;
+       case 16:
+               aw88261->slot_num_value = AW88261_SLOT_NUM_TDM16S_VALUE;
+               break;
+       default:
+               dev_err(aw88261->aw_pa->dev, "unsupported slot count %d\n", 
slots);
+               return -EINVAL;
+       }
+
+       if (tx_mask != 0) {
+               if ((bit = __ffs(tx_mask)) > 15)
+                       return -EINVAL;
+
+               aw88261->tx_slotvld_mask = bit << 
AW88261_I2S_TX_SLOTVLD_START_BIT;
+       }
+
+       if (rx_mask != 0) {
+               if ((bit = __ffs(rx_mask)) > 15)
+                       return -EINVAL;
+
+               aw88261->rxl_slotvld_mask = bit << 
AW88261_I2S_RXL_SLOTVLD_START_BIT;
+       }
+
+       if ((rx_mask & ~BIT(bit)) != 0) {
+               if ((bit = __ffs(rx_mask & ~BIT(bit))) > 15)
+                       return -EINVAL;
+
+               aw88261->rxr_slotvld_mask = bit << 
AW88261_I2S_RXR_SLOTVLD_START_BIT;
+       }
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops aw88261_dai_ops = {
        .set_fmt = aw88261_set_fmt,
        .hw_params = aw88261_hw_params,
+       .set_tdm_slot   = aw88261_set_tdm_slot,
 };
 
 static struct snd_soc_dai_driver aw88261_dai[] = {
@@ -1363,12 +1449,14 @@ static int aw88261_i2c_probe(struct i2c_client *i2c)
                return -ENOMEM;
 
        /* set defaults */
+       aw88261->slot_num_value = AW88261_SLOT_NUM_I2S_MODE_VALUE;
        aw88261->sr_value = AW88261_I2SSR_48KHZ_VALUE;
        aw88261->cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE;
        aw88261->fs_value = AW88261_I2SFS_24_BITS_VALUE;
        aw88261->bck_value = AW88261_I2SBCK_64FS_VALUE;
        aw88261->bck_inv_value = AW88261_BCKINV_NOT_INVERT_VALUE;
        aw88261->md_value = AW88261_I2SMD_PHILIPS_STANDARD_VALUE;
+       aw88261->rxr_slotvld_mask = 1 << AW88261_I2S_RXR_SLOTVLD_START_BIT;
 
        mutex_init(&aw88261->lock);
 
diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h
index 3d7483d625a9..02820795d434 100644
--- a/sound/soc/codecs/aw88261.h
+++ b/sound/soc/codecs/aw88261.h
@@ -368,6 +368,54 @@
 #define AW88261_I2SSR_192KHZ_VALUE             \
        (AW88261_I2SSR_192KHZ << AW88261_I2SSR_START_BIT)
 
+#define AW88261_SLOT_NUM_START_BIT     (12)
+#define AW88261_SLOT_NUM_BITS_LEN      (3)
+#define AW88261_SLOT_NUM_MASK  \
+       (~(((1<<AW88261_SLOT_NUM_BITS_LEN)-1) << AW88261_SLOT_NUM_START_BIT))
+
+#define AW88261_SLOT_NUM_I2S_MODE      (0)
+#define AW88261_SLOT_NUM_I2S_MODE_VALUE        \
+       (AW88261_SLOT_NUM_I2S_MODE << AW88261_SLOT_NUM_START_BIT)
+
+#define AW88261_SLOT_NUM_TDM1S (1)
+#define AW88261_SLOT_NUM_TDM1S_VALUE   \
+       (AW88261_SLOT_NUM_TDM1S << AW88261_SLOT_NUM_START_BIT)
+
+#define AW88261_SLOT_NUM_TDM2S (2)
+#define AW88261_SLOT_NUM_TDM2S_VALUE   \
+       (AW88261_SLOT_NUM_TDM2S << AW88261_SLOT_NUM_START_BIT)
+
+#define AW88261_SLOT_NUM_TDM4S (3)
+#define AW88261_SLOT_NUM_TDM4S_VALUE   \
+       (AW88261_SLOT_NUM_TDM4S << AW88261_SLOT_NUM_START_BIT)
+
+#define AW88261_SLOT_NUM_TDM6S (4)
+#define AW88261_SLOT_NUM_TDM6S_VALUE   \
+       (AW88261_SLOT_NUM_TDM6S << AW88261_SLOT_NUM_START_BIT)
+
+#define AW88261_SLOT_NUM_TDM8S (5)
+#define AW88261_SLOT_NUM_TDM8S_VALUE   \
+       (AW88261_SLOT_NUM_TDM8S << AW88261_SLOT_NUM_START_BIT)
+
+#define AW88261_SLOT_NUM_TDM16S        (6)
+#define AW88261_SLOT_NUM_TDM16S_VALUE  \
+       (AW88261_SLOT_NUM_TDM16S << AW88261_SLOT_NUM_START_BIT)
+
+#define AW88261_I2S_TX_SLOTVLD_START_BIT       (8)
+#define AW88261_I2S_TX_SLOTVLD_BITS_LEN        (4)
+#define AW88261_I2S_TX_SLOTVLD_MASK    \
+       (~(((1<<AW88261_I2S_TX_SLOTVLD_BITS_LEN)-1) << 
AW88261_I2S_TX_SLOTVLD_START_BIT))
+
+#define AW88261_I2S_RXR_SLOTVLD_START_BIT      (4)
+#define AW88261_I2S_RXR_SLOTVLD_BITS_LEN       (4)
+#define AW88261_I2S_RXR_SLOTVLD_MASK   \
+       (~(((1<<AW88261_I2S_RXR_SLOTVLD_BITS_LEN)-1) << 
AW88261_I2S_RXR_SLOTVLD_START_BIT))
+
+#define AW88261_I2S_RXL_SLOTVLD_START_BIT      (0)
+#define AW88261_I2S_RXL_SLOTVLD_BITS_LEN       (4)
+#define AW88261_I2S_RXL_SLOTVLD_MASK   \
+       (~(((1<<AW88261_I2S_RXL_SLOTVLD_BITS_LEN)-1) << 
AW88261_I2S_RXL_SLOTVLD_START_BIT))
+
 #define AW88261_CCO_MUX_START_BIT      (6)
 #define AW88261_CCO_MUX_BITS_LEN       (1)
 #define AW88261_CCO_MUX_MASK           \
@@ -565,6 +613,11 @@ struct aw88261 {
        unsigned int bck_inv_value;
        unsigned int md_value;
 
+       unsigned int slot_num_value;
+       unsigned int tx_slotvld_mask;
+       unsigned int rxl_slotvld_mask;
+       unsigned int rxr_slotvld_mask;
+
        bool phase_sync;
 };
 
-- 
2.53.0


Reply via email to