#define I2SLVL1ADDR    0x34
 #define I2SLVL2ADDR    0x38
 #define I2SLVL3ADDR    0x3c
+#define I2SSTR1                0x40
+#define I2SVER         0x44
+#define I2SFIC2                0x48
+#define I2STDM         0x4c
 
 #define CON_RSTCLR             (1 << 31)
 #define CON_FRXOFSTATUS                (1 << 26)
 #define MOD_BCLK_MASK          3
 #define MOD_8BIT               (1 << 0)
 
+#define EXYNOS5420_MOD_LRP_SHIFT       15
+#define EXYNOS5420_MOD_SDF_SHIFT       6
+#define EXYNOS5420_MOD_RCLK_SHIFT      4
+#define EXYNOS5420_MOD_BCLK_SHIFT      0
+#define EXYNOS5420_MOD_BCLK_64FS       4
+#define EXYNOS5420_MOD_BCLK_96FS       5
+#define EXYNOS5420_MOD_BCLK_128FS      6
+#define EXYNOS5420_MOD_BCLK_192FS      7
+#define EXYNOS5420_MOD_BCLK_256FS      8
+#define EXYNOS5420_MOD_BCLK_MASK       0xf
+
 #define MOD_CDCLKCON           (1 << 12)
 
 #define PSR_PSREN              (1 << 15)
 
 /* Read RCLK of I2S (in multiples of LRCLK) */
 static inline unsigned get_rfs(struct i2s_dai *i2s)
 {
-       u32 rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
+       u32 rfs;
+
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM)
+               rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT;
+       else
+               rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
        rfs &= MOD_RCLK_MASK;
 
        switch (rfs) {
 static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
 {
        u32 mod = readl(i2s->addr + I2SMOD);
-       int rfs_shift =  MOD_RCLK_SHIFT;
+       int rfs_shift;
 
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM)
+               rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT;
+       else
+               rfs_shift = MOD_RCLK_SHIFT;
        mod &= ~(MOD_RCLK_MASK << rfs_shift);
 
        switch (rfs) {
 /* Read Bit-Clock of I2S (in multiples of LRCLK) */
 static inline unsigned get_bfs(struct i2s_dai *i2s)
 {
-       u32 bfs =  readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
-       bfs &= MOD_BCLK_MASK;
+       u32 bfs;
+
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+               bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT;
+               bfs &= EXYNOS5420_MOD_BCLK_MASK;
+       } else {
+               bfs =  readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
+               bfs &= MOD_BCLK_MASK;
+       }
 
        switch (bfs) {
+       case 8: return 256;
+       case 7: return 192;
+       case 6: return 128;
+       case 5: return 96;
+       case 4: return 64;
        case 3: return 24;
        case 2: return 16;
        case 1: return 48;
 static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
 {
        u32 mod = readl(i2s->addr + I2SMOD);
-       int bfs_shift = MOD_BCLK_SHIFT;
+       int bfs_shift;
+       int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM;
 
-       mod &= ~(MOD_BCLK_MASK << bfs_shift);
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+               bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT;
+               mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift);
+       } else {
+               bfs_shift = MOD_BCLK_SHIFT;
+               mod &= ~(MOD_BCLK_MASK << bfs_shift);
+       }
+
+       /* Non-TDM I2S controllers do not support BCLK > 48 * FS */
+       if (!tdm && bfs > 48) {
+               dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n");
+               return;
+       }
 
        switch (bfs) {
        case 48:
        case 16:
                mod |= (MOD_BCLK_16FS << bfs_shift);
                break;
+       case 64:
+               mod |= (EXYNOS5420_MOD_BCLK_64FS << bfs_shift);
+               break;
+       case 96:
+               mod |= (EXYNOS5420_MOD_BCLK_96FS << bfs_shift);
+               break;
+       case 128:
+               mod |= (EXYNOS5420_MOD_BCLK_128FS << bfs_shift);
+               break;
+       case 192:
+               mod |= (EXYNOS5420_MOD_BCLK_192FS << bfs_shift);
+               break;
+       case 256:
+               mod |= (EXYNOS5420_MOD_BCLK_256FS << bfs_shift);
+               break;
        default:
                dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
                return;
 {
        struct i2s_dai *i2s = to_info(dai);
        u32 mod = readl(i2s->addr + I2SMOD);
-       int lrp_shift = MOD_LRP_SHIFT, sdf_shift = MOD_SDF_SHIFT;
-       int sdf_mask, lrp_rlow;
+       int lrp_shift, sdf_shift, sdf_mask, lrp_rlow;
        u32 tmp = 0;
 
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+               lrp_shift = EXYNOS5420_MOD_LRP_SHIFT;
+               sdf_shift = EXYNOS5420_MOD_SDF_SHIFT;
+       } else {
+               lrp_shift = MOD_LRP_SHIFT;
+               sdf_shift = MOD_SDF_SHIFT;
+       }
+
        sdf_mask = MOD_SDF_MASK << sdf_shift;
        lrp_rlow = MOD_LR_RLOW << lrp_shift;
 
        .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
 };
 
+static const struct samsung_i2s_dai_data i2sv6_dai_type = {
+       .dai_type = TYPE_PRI,
+       .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
+                       QUIRK_SUPPORTS_TDM,
+};
+
 static const struct samsung_i2s_dai_data samsung_dai_type_pri = {
        .dai_type = TYPE_PRI,
 };
        }, {
                .compatible = "samsung,s5pv210-i2s",
                .data = &i2sv5_dai_type,
+       }, {
+               .compatible = "samsung,exynos5420-i2s",
+               .data = &i2sv6_dai_type,
        },
        {},
 };