struct snd_pcm_substream *substreams[2];
        unsigned int dai_fmt;
 
+       u32 iec958_status;
+
        /* Audio can not be enabled due to missing parameter(s) */
        bool    missing_audio_param;
 
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+               return 0;
+
        dev_dbg(mcasp->dev,
                 "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
                 __func__, tx_mask, rx_mask, slots, slot_width);
                mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
                               RXROT(7));
                mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
+       } else {
+               /*
+                * according to the TRM it should be TXROT=0, this one works:
+                * 16 bit to 23-8 (TXROT=6, rotate 24 bits)
+                * 24 bit to 23-0 (TXROT=0, rotate 0 bits)
+                *
+                * TXROT = 0 only works with 24bit samples
+                */
+               tx_rotate = (sample_width / 4 + 2) & 0x7;
+
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
+                              TXROT(7));
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(15),
+                              TXSSZ(0x0F));
        }
 
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
        u8 tx_ser = 0;
        u8 rx_ser = 0;
        u8 slots = mcasp->tdm_slots;
-       u8 max_active_serializers = (channels + slots - 1) / slots;
-       u8 max_rx_serializers, max_tx_serializers;
+       u8 max_active_serializers, max_rx_serializers, max_tx_serializers;
        int active_serializers, numevt;
        u32 reg;
+
+       /* In DIT mode we only allow maximum of one serializers for now */
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+               max_active_serializers = 1;
+       else
+               max_active_serializers = (channels + slots - 1) / slots;
+
        /* Default configuration */
        if (mcasp->version < MCASP_VERSION_3)
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
 static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
                              unsigned int rate)
 {
-       u32 cs_value = 0;
-       u8 *cs_bytes = (u8*) &cs_value;
+       u8 *cs_bytes = (u8 *)&mcasp->iec958_status;
 
-       /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
-          and LSB first */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
+       if (!mcasp->dat_port)
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
+       else
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
 
        /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
 
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, 0xFFFF);
+
        /* Set the TX tdm : for all the slots */
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
 
 
        mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
 
-       /* Only 44100 and 48000 are valid, both have the same setting */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
-
-       /* Enable the DIT */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
-
        /* Set S/PDIF channel status bits */
-       cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
-       cs_bytes[1] = IEC958_AES1_CON_PCM_CODER;
-
+       cs_bytes[3] &= ~IEC958_AES3_CON_FS;
        switch (rate) {
        case 22050:
                cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
                cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
                break;
        default:
-               printk(KERN_WARNING "unsupported sampling rate: %d\n", rate);
+               dev_err(mcasp->dev, "unsupported sampling rate: %d\n", rate);
                return -EINVAL;
        }
 
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, mcasp->iec958_status);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, mcasp->iec958_status);
+
+       /* Enable the DIT */
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
 
        return 0;
 }
                int slots = mcasp->tdm_slots;
                int rate = params_rate(params);
                int sbits = params_width(params);
+               unsigned int bclk_target;
 
                if (mcasp->slot_width)
                        sbits = mcasp->slot_width;
 
+               if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
+                       bclk_target = rate * sbits * slots;
+               else
+                       bclk_target = rate * 128;
+
                davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq,
-                                          rate * sbits * slots, true);
+                                          bclk_target, true);
        }
 
        ret = mcasp_common_hw_param(mcasp, substream->stream,
        .set_tdm_slot   = davinci_mcasp_set_tdm_slot,
 };
 
+static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+
+       return 0;
+}
+
+static int davinci_mcasp_iec958_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *uctl)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       memcpy(uctl->value.iec958.status, &mcasp->iec958_status,
+              sizeof(mcasp->iec958_status));
+
+       return 0;
+}
+
+static int davinci_mcasp_iec958_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *uctl)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       memcpy(&mcasp->iec958_status, uctl->value.iec958.status,
+              sizeof(mcasp->iec958_status));
+
+       return 0;
+}
+
+static int davinci_mcasp_iec958_con_mask_get(struct snd_kcontrol *kcontrol,
+                                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       memset(ucontrol->value.iec958.status, 0xff, sizeof(mcasp->iec958_status));
+       return 0;
+}
+
+static const struct snd_kcontrol_new davinci_mcasp_iec958_ctls[] = {
+       {
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+               .info = davinci_mcasp_iec958_info,
+               .get = davinci_mcasp_iec958_get,
+               .put = davinci_mcasp_iec958_put,
+       }, {
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
+               .info = davinci_mcasp_iec958_info,
+               .get = davinci_mcasp_iec958_con_mask_get,
+       },
+};
+
+static void davinci_mcasp_init_iec958_status(struct davinci_mcasp *mcasp)
+{
+       unsigned char *cs = (u8 *)&mcasp->iec958_status;
+
+       cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+       cs[1] = IEC958_AES1_CON_PCM_CODER;
+       cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
+       cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
+}
+
 static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
        dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
        dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
 
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
+               davinci_mcasp_init_iec958_status(mcasp);
+               snd_soc_add_dai_controls(dai, davinci_mcasp_iec958_ctls,
+                                        ARRAY_SIZE(davinci_mcasp_iec958_ctls));
+       }
+
        return 0;
 }
 
                        .channels_min   = 1,
                        .channels_max   = 384,
                        .rates          = DAVINCI_MCASP_RATES,
-                       .formats        = DAVINCI_MCASP_PCM_FMTS,
+                       .formats        = SNDRV_PCM_FMTBIT_S16_LE |
+                                         SNDRV_PCM_FMTBIT_S24_LE,
                },
                .ops            = &davinci_mcasp_dai_ops,
        },
                } else {
                        mcasp->tdm_slots = pdata->tdm_slots;
                }
+       } else {
+               mcasp->tdm_slots = 32;
        }
 
        mcasp->num_serializer = pdata->num_serializer;