{
        struct i2s_clk_config_data *config = &dev->config;
 
-       i2s_write_reg(dev->i2s_base, IER, 1);
+       u32 reg = IER_IEN;
+
+       if (dev->tdm_slots) {
+               reg |= (dev->tdm_slots - 1) << IER_TDM_SLOTS_SHIFT;
+               reg |= IER_INTF_TYPE;
+               reg |= dev->frame_offset << IER_FRAME_OFF_SHIFT;
+       }
+
+       i2s_write_reg(dev->i2s_base, IER, reg);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                i2s_write_reg(dev->i2s_base, ITER, 1);
                                      dev->xfer_resolution);
                        i2s_write_reg(dev->i2s_base, TFCR(ch_reg),
                                      dev->fifo_th - 1);
-                       i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+                       i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN |
+                                     dev->tdm_mask << TER_TXSLOT_SHIFT);
                } else {
                        i2s_write_reg(dev->i2s_base, RCR(ch_reg),
                                      dev->xfer_resolution);
                        i2s_write_reg(dev->i2s_base, RFCR(ch_reg),
                                      dev->fifo_th - 1);
-                       i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+                       i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN |
+                                     dev->tdm_mask << RER_RXSLOT_SHIFT);
                }
 
        }
                return -EINVAL;
        }
 
+       if (dev->tdm_slots)
+               config->data_width = 32;
+
        config->chan_nr = params_channels(params);
 
        switch (config->chan_nr) {
                ret = -EINVAL;
                break;
        }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               dev->frame_offset = 1;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               dev->frame_offset = 0;
+               break;
+       default:
+               dev_err(dev->dev, "DAI format unsupported");
+               return -EINVAL;
+       }
+
        return ret;
 }
 
+static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai,    unsigned int tx_mask,
+                          unsigned int rx_mask, int slots, int slot_width)
+{
+       struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+
+       if (slot_width != 32)
+               return -EINVAL;
+
+       if (slots < 0 || slots > 16)
+               return -EINVAL;
+
+       if (rx_mask != tx_mask)
+               return -EINVAL;
+
+       if (!rx_mask)
+               return -EINVAL;
+
+       dev->tdm_slots = slots;
+       dev->tdm_mask = rx_mask;
+
+       dev->l_reg = RSLOT_TSLOT(ffs(rx_mask) - 1);
+       dev->r_reg = RSLOT_TSLOT(fls(rx_mask) - 1);
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
        .hw_params      = dw_i2s_hw_params,
        .prepare        = dw_i2s_prepare,
        .trigger        = dw_i2s_trigger,
        .set_fmt        = dw_i2s_set_fmt,
+       .set_tdm_slot   = dw_i2s_set_tdm_slot,
 };
 
 #ifdef CONFIG_PM
                if (irq >= 0) {
                        ret = dw_pcm_register(pdev);
                        dev->use_pio = true;
+                       dev->l_reg = LRBR_LTHR(0);
+                       dev->r_reg = RRBR_RTHR(0);
                } else {
                        ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
                                        0);
 
        int i; \
 \
        for (i = 0; i < dev->fifo_th; i++) { \
-               iowrite32(p[tx_ptr][0], dev->i2s_base + LRBR_LTHR(0)); \
-               iowrite32(p[tx_ptr][1], dev->i2s_base + RRBR_RTHR(0)); \
+               iowrite32(p[tx_ptr][0], dev->i2s_base + dev->l_reg); \
+               iowrite32(p[tx_ptr][1], dev->i2s_base + dev->r_reg); \
                period_pos++; \
                if (++tx_ptr >= runtime->buffer_size) \
                        tx_ptr = 0; \
        int i; \
 \
        for (i = 0; i < dev->fifo_th; i++) { \
-               p[rx_ptr][0] = ioread32(dev->i2s_base + LRBR_LTHR(0)); \
-               p[rx_ptr][1] = ioread32(dev->i2s_base + RRBR_RTHR(0)); \
+               p[rx_ptr][0] = ioread32(dev->i2s_base + dev->l_reg); \
+               p[rx_ptr][1] = ioread32(dev->i2s_base + dev->r_reg); \
                period_pos++; \
                if (++rx_ptr >= runtime->buffer_size) \
                        rx_ptr = 0; \
 
 #define RXFFR          0x014
 #define TXFFR          0x018
 
+/* Enable register fields */
+#define IER_TDM_SLOTS_SHIFT    8
+#define IER_FRAME_OFF_SHIFT    5
+#define IER_FRAME_OFF  BIT(5)
+#define IER_INTF_TYPE  BIT(1)
+#define IER_IEN                BIT(0)
+
 /* Interrupt status register fields */
 #define ISR_TXFO       BIT(5)
 #define ISR_TXFE       BIT(4)
 #define TFCR(x)                (0x40 * x + 0x04C)
 #define RFF(x)         (0x40 * x + 0x050)
 #define TFF(x)         (0x40 * x + 0x054)
+#define RSLOT_TSLOT(x) (0x4 * (x) + 0x224)
+
+/* Receive enable register fields */
+#define RER_RXSLOT_SHIFT       8
+#define RER_RXCHEN     BIT(0)
+
+/* Transmit enable register fields */
+#define TER_TXSLOT_SHIFT       8
+#define TER_TXCHEN     BIT(0)
 
 /* I2SCOMPRegisters */
 #define I2S_COMP_PARAM_2       0x01F0
        u32 ccr;
        u32 xfer_resolution;
        u32 fifo_th;
+       u32 l_reg;
+       u32 r_reg;
 
        /* data related to DMA transfers b/w i2s and DMAC */
        union dw_i2s_snd_dma_data play_dma_data;
 
        /* data related to PIO transfers */
        bool use_pio;
+
+       /* data related to TDM mode */
+       u32 tdm_slots;
+       u32 tdm_mask;
+       u32 frame_offset;
+
        struct snd_pcm_substream __rcu *tx_substream;
        struct snd_pcm_substream __rcu *rx_substream;
        unsigned int (*tx_fn)(struct dw_i2s_dev *dev,