soc: codecs: rt5639: Implement i2c shutdown
[linux-2.6.git] / sound / soc / tegra / tegra30_dam.c
index d308179..91ea896 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Author: Nikesh Oswal <noswal@nvidia.com>
  * Copyright (C) 2011 - NVIDIA, Inc.
+ * Copyright (C) 2012-2014, NVIDIA CORPORATION. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -27,6 +28,7 @@
 #include <linux/platform_device.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <sound/soc.h>
 #include "tegra30_dam.h"
@@ -54,6 +56,261 @@ struct tegra30_dam_src_step_table  step_table[] = {
        { 48000, 16000, 0 },
 };
 
+#ifndef CONFIG_ARCH_TEGRA_3x_SOC
+int coefRam16To44[64] = {
+                               0x156105, // IIR Filter + interpolation
+                               0x0000d649,
+                               0x00e87afb, 0xff5f69d0, 0x003df3cf,
+                               0x007ce488, 0xff99a5c8, 0x0056a6a0,
+                               0x00344928, 0xffcba3e5, 0x006be470,
+                               0x00137aa7, 0xffe60276, 0x00773410,
+                               0x0005fa2a, 0xfff1ac11, 0x007c795b,
+                               0x00012d36, 0xfff5eca2, 0x007f10ef,
+                               0x2,
+                               0x21a102, // IIR Filter + interplation
+                               0x00000e00,
+                               0x00e2e000,0xff6e1a00,0x002aaa00,
+                               0x00610a00,0xff5dda00,0x003ccc00,
+                               0x00163a00,0xff3c0400,0x00633200,
+                               0x3,
+                               0x2c0204, // Farrow Filter
+                               0x000aaaab,
+                               0xffaaaaab,
+                               0xfffaaaab,
+                               0x00555555,
+                               0xff600000,
+                               0xfff55555,
+                               0x00155555,
+                               0x00055555,
+                               0xffeaaaab,
+                               0x00200000,
+                               0x005101, //IIR Filter + Decimator
+                               8252,
+                               16067893,-13754014,5906912,
+                               13037808,-13709975,7317389,
+                               1,
+                               0,0,0,0,0,
+                               0,0,0,0,0,0
+};
+
+int coefRam8To48[64] = {
+                               0x156105, // interpolation + FIlter
+                               0x0000d649,
+                               0x00e87afb, 0xff5f69d0, 0x003df3cf,
+                               0x007ce488, 0xff99a5c8, 0x0056a6a0,
+                               0x00344928, 0xffcba3e5, 0x006be470,
+                               0x00137aa7, 0xffe60276, 0x00773410,
+                               0x0005fa2a, 0xfff1ac11, 0x007c795b,
+                               0x00012d36, 0xfff5eca2, 0x007f10ef,
+                               0x2, // ouptut gain
+                               0x00a102, // filter + interpolation
+                               0x00000e00,
+                               0x00e2e000,0xff6e1a00,0x002aaa00,
+                               0x00610a00,0xff5dda00,0x003ccc00,
+                               0x00163a00,0xff3c0400,0x00633200,
+                               0x3,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0
+};
+
+int coefRam16To48[64] = {
+                               0x00a105, // interpolation + Filter
+                               1924,
+                               13390190,-13855175,5952947,
+                               1289485,-12761191,6540917,
+                               -4787304,-11454255,7249439,
+                               -7239963,-10512732,7776366,
+                               -8255332,-9999487,8101770,
+                               -8632155,-9817625,8305531,
+                               0x3,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0,0,
+                               0,0
+};
+
+int coefRam44To16[64] = {
+                               0x126104, // IIR Filter + interp0lation
+                               2802,
+                               5762750,-14772125,6628868,
+                               -9304342,-14504578,7161825,
+                               -12409641,-14227678,7732611,
+                               -13291674,-14077653,8099947,
+                               -13563385,-14061743,8309372,
+                               2,
+                               0x1d9204, // Farrwo Filter + Decimation
+                               0x000aaaab,
+                               0xffaaaaab,
+                               0xfffaaaab,
+                               0x00555555,
+                               0xff600000,
+                               0xfff55555,
+                               0x00155555,
+                               0x00055555,
+                               0xffeaaaab,
+                               0x00200000,
+                               0x005105, // IIR Filter+decimation
+                               0x0000d649,
+                               0x00e87afb, 0xff5f69d0, 0x003df3cf,
+                               0x007ce488, 0xff99a5c8, 0x0056a6a0,
+                               0x00344928, 0xffcba3e5, 0x006be470,
+                               0x00137aa7, 0xffe60276, 0x00773410,
+                               0x0005fa2a, 0xfff1ac11, 0x007c795b,
+                               0x00012d36, 0xfff5eca2, 0x007f10ef,
+                               0x1,
+                               0,0,0,0,0,
+                               0,0,0,0,0,
+                               0,0,0,0
+};
+
+int coefRam44To8[64] = {
+                               0x120104, // IIR Filter
+                               2802,
+                               5762750,-14772125,6628868,
+                               -9304342,-14504578,7161825,
+                               -12409641,-14227678,7732611,
+                               -13291674,-14077653,8099947,
+                               -13563385,-14061743,8309372,
+                               1,
+                               0x1d9204, // Farrwo Filter
+                               0x000aaaab,
+                               0xffaaaaab,
+                               0xfffaaaab,
+                               0x00555555,
+                               0xff600000,
+                               0xfff55555,
+                               0x00155555,
+                               0x00055555,
+                               0xffeaaaab,
+                               0x00200000,
+                               0x005105, // IIR Filter
+                               0x0000d649,
+                               0x00e87afb, 0xff5f69d0, 0x003df3cf,
+                               0x007ce488, 0xff99a5c8, 0x0056a6a0,
+                               0x00344928, 0xffcba3e5, 0x006be470,
+                               0x00137aa7, 0xffe60276, 0x00773410,
+                               0x0005fa2a, 0xfff1ac11, 0x007c795b,
+                               0x00012d36, 0xfff5eca2, 0x007f10ef,
+                               0x1,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0,0
+};
+
+int coefRam48To16[64] = {
+                               0x009105, // IIR FIlter + Decimation
+                               1924,
+                               13390190,-13855175,5952947,
+                               1289485,-12761191,6540917,
+                               -4787304,-11454255,7249439,
+                               -7239963,-10512732,7776366,
+                               -8255332,-9999487,8101770,
+                               -8632155,-9817625,8305531,
+                               0x1,
+                               0,0,0,
+                               0,0,0,0,0,0,0,0,
+                               0,0,0,0,0,0,0,0,
+                               0,0,0,0,0,0,0,0,
+                               0,0,0,0,0,0,0,0,
+                               0,0,0,0,0,0,0,0
+};
+
+int coefRam48To8[64] = {
+                               0x0c9102,       //IIR Filter + decimation
+                               0x00000e00,
+                               0x00e2e000,0xff6e1a00,0x002aaa00,
+                               0x00610a00,0xff5dda00,0x003ccc00,
+                               0x00163a00,0xff3c0400,0x00633200,
+                               0x1,
+                               0x005105,   //IIR Filter + Decimator
+                               0x0000d649,
+                               0x00e87afb, 0xff5f69d0, 0x003df3cf,
+                               0x007ce488, 0xff99a5c8, 0x0056a6a0,
+                               0x00344928, 0xffcba3e5, 0x006be470,
+                               0x00137aa7, 0xffe60276, 0x00773410,
+                               0x0005fa2a, 0xfff1ac11, 0x007c795b,
+                               0x00012d36, 0xfff5eca2, 0x007f10ef,
+                               0x1, // ouptut gain
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0
+};
+
+int coefRam8To44[64] = {
+                               0x0156105, // IIR filter +interpllation
+                               0x0000d649,
+                               0x00e87afb, 0xff5f69d0, 0x003df3cf,
+                               0x007ce488, 0xff99a5c8, 0x0056a6a0,
+                               0x00344928, 0xffcba3e5, 0x006be470,
+                               0x00137aa7, 0xffe60276, 0x00773410,
+                               0x0005fa2a, 0xfff1ac11, 0x007c795b,
+                               0x00012d36, 0xfff5eca2, 0x007f10ef,
+                               0x2, // ouptut gain
+                               0x21a102, // filter + interp0lation
+                               0x00000e00,
+                               0x00e2e000,0xff6e1a00,0x002aaa00,
+                               0x00610a00,0xff5dda00,0x003ccc00,
+                               0x00163a00,0xff3c0400,0x00633200,
+                               0x3,
+                               0x000204,
+                               0x000aaaab,
+                               0xffaaaaab,
+                               0xfffaaaab,
+                               0x00555555,
+                               0xff600000,
+                               0xfff55555,
+                               0x00155555,
+                               0x00055555,
+                               0xffeaaaab,
+                               0x00200000,
+                               0,0,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0,
+                               0,0,0,0,0,0
+};
+
+int coefRam8To16[64] = {
+                               0x00006105, // interpolation + IIR Filter
+                               0x0000d649, // input gain
+                               0x00e87afb, 0xff5f69d0, 0x003df3cf,
+                               0x007ce488, 0xff99a5c8, 0x0056a6a0,
+                               0x00344928, 0xffcba3e5, 0x006be470,
+                               0x00137aa7, 0xffe60276, 0x00773410,
+                               0x0005fa2a, 0xfff1ac11, 0x007c795b,
+                               0x00012d36, 0xfff5eca2, 0x007f10ef,
+                               0x00000002, // ouptut gain
+};
+
+int coefRam16To8[64] = {
+                               0x00005105,   //IIR Filter + Decimator
+                               0x0000d649, //input gain
+                               0x00e87afb, 0xff5f69d0, 0x003df3cf,
+                               0x007ce488, 0xff99a5c8, 0x0056a6a0,
+                               0x00344928, 0xffcba3e5, 0x006be470,
+                               0x00137aa7, 0xffe60276, 0x00773410,
+                               0x0005fa2a, 0xfff1ac11, 0x007c795b,
+                               0x00012d36, 0xfff5eca2, 0x007f10ef,
+                               0x00000001, // ouptut gain
+};
+#endif
+
 static void tegra30_dam_set_output_samplerate(struct tegra30_dam_context *dam,
                int fsout);
 static void tegra30_dam_set_input_samplerate(struct tegra30_dam_context *dam,
@@ -84,7 +341,7 @@ int tegra30_dam_resume(int ifc)
        int i = 0;
        struct tegra30_dam_context *dam;
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
                return -EINVAL;
 
        dam = dams_cont_info[ifc];
@@ -112,7 +369,7 @@ void tegra30_dam_disable_clock(int ifc)
 {
        struct tegra30_dam_context *dam;
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
                return;
 
        dam =  dams_cont_info[ifc];
@@ -124,7 +381,7 @@ int tegra30_dam_enable_clock(int ifc)
 {
        struct tegra30_dam_context *dam;
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
                return -EINVAL;
 
        dam =  dams_cont_info[ifc];
@@ -158,6 +415,7 @@ static int tegra30_dam_show(struct seq_file *s, void *unused)
        struct tegra30_dam_context *dam = s->private;
        int i;
 
+       tegra30_ahub_enable_clocks();
        clk_enable(dam->dam_clk);
 
        for (i = 0; i < ARRAY_SIZE(regs); i++) {
@@ -166,6 +424,7 @@ static int tegra30_dam_show(struct seq_file *s, void *unused)
        }
 
        clk_disable(dam->dam_clk);
+       tegra30_ahub_disable_clocks();
 
        return 0;
 }
@@ -229,7 +488,8 @@ int tegra30_dam_allocate_channel(int ifc, int chid)
 {
        struct tegra30_dam_context *dam = NULL;
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC) ||
+               (chid < dam_ch_in0) || (chid >= dam_ch_maxnum))
                return -EINVAL;
 
        dam =  dams_cont_info[ifc];
@@ -246,7 +506,8 @@ int tegra30_dam_free_channel(int ifc, int chid)
 {
        struct tegra30_dam_context *dam = NULL;
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC) ||
+               (chid < dam_ch_in0) || (chid >= dam_ch_maxnum))
                return -EINVAL;
 
        dam =  dams_cont_info[ifc];
@@ -263,7 +524,7 @@ int tegra30_dam_free_controller(int ifc)
 {
        struct tegra30_dam_context *dam = NULL;
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
                return -EINVAL;
 
        dam =  dams_cont_info[ifc];
@@ -281,7 +542,7 @@ void tegra30_dam_set_samplerate(int ifc, int chid, int samplerate)
 {
        struct tegra30_dam_context *dam = dams_cont_info[ifc];
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
                return;
 
        switch (chid) {
@@ -389,7 +650,7 @@ void tegra30_dam_ch0_set_step(struct tegra30_dam_context *dam, int step)
 int tegra30_dam_set_gain(int ifc, int chid, int gain)
 {
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
                return -EINVAL;
 
        switch (chid) {
@@ -415,13 +676,24 @@ int tegra30_dam_set_acif(int ifc, int chid, unsigned int audio_channels,
        unsigned int reg;
        unsigned int value = 0;
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
                return -EINVAL;
 
+#ifndef CONFIG_ARCH_TEGRA_3x_SOC
+       /*ch0 takes input as mono always*/
+       if ((chid == dam_ch_in0) &&
+               ((client_channels != 1)))
+               return -EINVAL;
+       /*as per dam spec file chout is fixed to 32 bits*/
+       /*so accept ch0, ch1 and chout as 32bit always*/
+       if (client_bits != 32)
+               return -EINVAL;
+#else
        /*ch0 takes input as mono/16bit always*/
        if ((chid == dam_ch_in0) &&
                ((client_channels != 1) || (client_bits != 16)))
                return -EINVAL;
+#endif
 
        value |= TEGRA30_CIF_MONOCONV_COPY;
        value |= TEGRA30_CIF_STEREOCONV_CH0;
@@ -452,14 +724,216 @@ int tegra30_dam_set_acif(int ifc, int chid, unsigned int audio_channels,
        return 0;
 }
 
+#ifndef CONFIG_ARCH_TEGRA_3x_SOC
+void tegra30_dam_write_coeff_ram(int ifc, int fsin, int fsout)
+{
+       u32 val;
+       int i, *coefRam = NULL;
+
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
+               return;
+
+       tegra30_dam_writel(dams_cont_info[ifc], 0x00002000,
+                       TEGRA30_DAM_AUDIORAMCTL_DAM_CTRL_0);
+
+       switch(fsin) {
+               case TEGRA30_AUDIO_SAMPLERATE_8000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_48000)
+                               coefRam = coefRam8To48;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_44100)
+                               coefRam = coefRam8To44;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               coefRam = coefRam8To16;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_16000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_48000)
+                               coefRam = coefRam16To48;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_44100)
+                               coefRam = coefRam16To44;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               coefRam = coefRam16To8;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_44100:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               coefRam = coefRam44To8;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               coefRam = coefRam44To16;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_48000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               coefRam = coefRam48To8;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               coefRam = coefRam48To16;
+                       break;
+
+               default:
+                       break;
+       }
+
+       tegra30_dam_writel(dams_cont_info[ifc], 0x00005000,
+                       TEGRA30_DAM_AUDIORAMCTL_DAM_CTRL_0);
+
+       for (i = 0; i < 64; i++) {
+               val = coefRam[i];
+               tegra30_dam_writel(dams_cont_info[ifc], val,
+                               TEGRA30_DAM_AUDIORAMCTL_DAM_DATA_0);
+       }
+}
+
+void tegra30_dam_set_farrow_param(int ifc, int fsin, int fsout)
+{
+       u32 val = TEGRA30_FARROW_PARAM_RESET;
+
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
+               return;
+
+       switch(fsin) {
+               case TEGRA30_AUDIO_SAMPLERATE_8000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_48000)
+                               val = TEGRA30_FARROW_PARAM_1;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_44100)
+                               val = TEGRA30_FARROW_PARAM_2;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               val = TEGRA30_FARROW_PARAM_1;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_16000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_48000)
+                               val = TEGRA30_FARROW_PARAM_1;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_44100)
+                               val = TEGRA30_FARROW_PARAM_2;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               val = TEGRA30_FARROW_PARAM_1;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_44100:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               val = TEGRA30_FARROW_PARAM_3;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               val = TEGRA30_FARROW_PARAM_3;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_48000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               val = TEGRA30_FARROW_PARAM_1;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               val = TEGRA30_FARROW_PARAM_1;
+                       break;
+
+               default:
+                       break;
+       }
+
+       tegra30_dam_writel(dams_cont_info[ifc], val,
+                       TEGRA30_DAM_FARROW_PARAM_0);
+}
+
+void tegra30_dam_set_biquad_fixed_coef(int ifc)
+{
+       u32 val = TEGRA30_DAM_CH0_BIQUAD_FIXED_COEF_0_VAL;
+
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
+               return;
+
+       tegra30_dam_writel(dams_cont_info[ifc], val,
+                       TEGRA30_DAM_CH0_BIQUAD_FIXED_COEF_0);
+}
+
+void tegra30_dam_enable_coeff_ram(int ifc)
+{
+       u32 val;
+
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
+               return;
+
+       val = tegra30_dam_readl(dams_cont_info[ifc], TEGRA30_DAM_CH0_CTRL);
+       val |= TEGRA30_DAM_CH0_CTRL_COEFF_RAM_ENABLE;
+
+       tegra30_dam_writel(dams_cont_info[ifc], val, TEGRA30_DAM_CH0_CTRL);
+}
+
+void tegra30_dam_set_filter_stages(int ifc, int fsin, int fsout)
+{
+       u32 val;
+       int filt_stages = 0;
+
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
+               return;
+
+       val = tegra30_dam_readl(dams_cont_info[ifc], TEGRA30_DAM_CH0_CTRL);
+
+       switch(fsin) {
+               case TEGRA30_AUDIO_SAMPLERATE_8000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_48000)
+                               filt_stages = 1;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_44100)
+                               filt_stages = 2;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               filt_stages = 0;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_16000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_48000)
+                               filt_stages = 0;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_44100)
+                               filt_stages = 3;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               filt_stages = 0;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_44100:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               filt_stages = 2;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               filt_stages = 2;
+                       break;
+
+               case TEGRA30_AUDIO_SAMPLERATE_48000:
+                       if (fsout == TEGRA30_AUDIO_SAMPLERATE_8000)
+                               filt_stages = 1;
+                       else if (fsout == TEGRA30_AUDIO_SAMPLERATE_16000)
+                               filt_stages = 0;
+                       break;
+
+               default:
+                       break;
+       }
+
+       val |= filt_stages << TEGRA30_DAM_CH0_CTRL_FILT_STAGES_SHIFT;
+
+       tegra30_dam_writel(dams_cont_info[ifc], val, TEGRA30_DAM_CH0_CTRL);
+}
+
+void tegra30_dam_enable_stereo_mixing(int ifc)
+{
+       u32 val;
+
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC))
+               return;
+
+       val = tegra30_dam_readl(dams_cont_info[ifc], TEGRA30_DAM_CTRL);
+       val |= TEGRA30_DAM_CTRL_STEREO_MIXING_ENABLE;
+
+       tegra30_dam_writel(dams_cont_info[ifc], val, TEGRA30_DAM_CTRL);
+}
+#endif
+
 void tegra30_dam_enable(int ifc, int on, int chid)
 {
        u32 old_val, val, enreg;
-       struct tegra30_dam_context *dam = dams_cont_info[ifc];
+       u32 old_val_dam, val_dam;
+       int dcnt = 10;
+       struct tegra30_dam_context *dam;
 
-       if (ifc >= TEGRA30_NR_DAM_IFC)
+       if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC) ||
+           (chid < dam_ch_in0) || (chid >= dam_ch_maxnum))
                return;
 
+       dam = dams_cont_info[ifc];
+
        if (chid == dam_ch_in0)
                enreg = TEGRA30_DAM_CH0_CTRL;
        else
@@ -476,24 +950,51 @@ void tegra30_dam_enable(int ifc, int on, int chid)
                        val &= ~TEGRA30_DAM_CH0_CTRL_EN;
        }
 
-       if (val != old_val)
-               tegra30_dam_writel(dam, val, enreg);
-
-       old_val = val = tegra30_dam_readl(dam, TEGRA30_DAM_CTRL);
+       old_val_dam = val_dam = tegra30_dam_readl(dam, TEGRA30_DAM_CTRL);
 
        if (dam->ch_enable_refcnt[dam_ch_in0] ||
                dam->ch_enable_refcnt[dam_ch_in1])
-               val |= TEGRA30_DAM_CTRL_DAM_EN;
+               val_dam |= TEGRA30_DAM_CTRL_DAM_EN;
        else
-               val &= ~TEGRA30_DAM_CTRL_DAM_EN;
+               val_dam &= ~TEGRA30_DAM_CTRL_DAM_EN;
 
-       if (old_val != val)
-               tegra30_dam_writel(dam, val, TEGRA30_DAM_CTRL);
+       if (val != old_val) {
+               tegra30_dam_writel(dam, val, enreg);
+
+               if (!on) {
+                       if (chid == dam_ch_in0) {
+                               while (!tegra30_ahub_dam_ch0_is_empty(ifc)
+                                       && dcnt--)
+                                       udelay(100);
+
+                               dcnt = 10;
+                       }
+                       else {
+                               while (!tegra30_ahub_dam_ch1_is_empty(ifc)
+                                       && dcnt--)
+                                       udelay(100);
+
+                               dcnt = 10;
+                       }
+               }
+       }
+
+       if (old_val_dam != val_dam) {
+               tegra30_dam_writel(dam, val_dam, TEGRA30_DAM_CTRL);
+               if (!on) {
+                       while (!tegra30_ahub_dam_tx_is_empty(ifc) && dcnt--)
+                               udelay(100);
+
+                       dcnt = 10;
+               }
+       }
 }
 
-void tegra30_dam_ch0_set_datasync(struct tegra30_dam_context *dam, int datasync)
+void tegra30_dam_ch0_set_datasync(int ifc, int datasync)
 {
        u32 val;
+       struct tegra30_dam_context *dam;
+       dam =  dams_cont_info[ifc];
 
        val = tegra30_dam_readl(dam, TEGRA30_DAM_CH0_CTRL);
        val &= ~TEGRA30_DAM_CH0_CTRL_DATA_SYNC_MASK;
@@ -501,9 +1002,11 @@ void tegra30_dam_ch0_set_datasync(struct tegra30_dam_context *dam, int datasync)
        tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_CTRL);
 }
 
-void tegra30_dam_ch1_set_datasync(struct tegra30_dam_context *dam, int datasync)
+void tegra30_dam_ch1_set_datasync(int ifc, int datasync)
 {
        u32 val;
+       struct tegra30_dam_context *dam;
+       dam =  dams_cont_info[ifc];
 
        val = tegra30_dam_readl(dam, TEGRA30_DAM_CH1_CTRL);
        val &= ~TEGRA30_DAM_CH1_CTRL_DATA_SYNC_MASK;
@@ -554,7 +1057,7 @@ static int __devinit tegra30_dam_probe(struct platform_device *pdev)
                goto err_free;
        }
        clkm_rate = clk_get_rate(clk_get_parent(dam->dam_clk));
-       while (clkm_rate > 12000000)
+       while (clkm_rate > 13000000)
                clkm_rate >>= 1;
 
        clk_set_rate(dam->dam_clk,clkm_rate);