ASoC: Tegra: Tristate DAP pins
Ravindra Lokhande [Mon, 1 Apr 2013 16:47:40 +0000 (21:47 +0530)]
We need to set DAP pins to normal before starting playback/record and
set it to tristate after playback/record. If we don't tristate then
power leakage can happen.

Bug 1241669
Bug 1258742

Change-Id: Id29382b50d499a966adc4715fe1e36bbcc460853
Signed-off-by: Ravindra Lokhande <rlokhande@nvidia.com>
Reviewed-on: http://git-master/r/215103
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

sound/soc/tegra/tegra_aic325x.c
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_asoc_utils.h
sound/soc/tegra/tegra_max98090.c

index 327285f..f9cbf9f 100644 (file)
@@ -415,6 +415,8 @@ static int tegra_aic325x_startup(struct snd_pcm_substream *substream)
        struct codec_config *bb_info;
        int codec_index;
 
+       tegra_asoc_utils_tristate_dap(i2s->id, false);
+
        if (!i2s->is_dam_used)
                return 0;
 
@@ -503,6 +505,8 @@ static void tegra_aic325x_shutdown(struct snd_pcm_substream *substream)
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
 
+       tegra_asoc_utils_tristate_dap(i2s->id, true);
+
        if (!i2s->is_dam_used)
                return;
 
index a54a503..f3819f3 100644 (file)
 #include <linux/of.h>
 
 #include <mach/clk.h>
+#include <mach/pinmux.h>
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+#include <mach/pinmux-tegra20.h>
+#endif
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+#include <mach/pinmux-tegra30.h>
+#endif
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+#include <mach/pinmux-t11.h>
+#endif
+#ifdef CONFIG_ARCH_TEGRA_14x_SOC
+#include <mach/pinmux-t14.h>
+#endif
 
 #include <sound/soc.h>
 
@@ -34,6 +47,7 @@
 #include "tegra_asoc_utils.h"
 
 int g_is_call_mode;
+static atomic_t dap_ref_count[5];
 
 #ifdef CONFIG_SWITCH
 static bool is_switch_registered;
@@ -46,6 +60,51 @@ enum headset_state {
 };
 #endif
 
+#define TRISTATE_DAP_PORT(n) \
+static void tristate_dap_##n(bool tristate) \
+{ \
+       enum tegra_pingroup fs, sclk, din, dout; \
+       fs = TEGRA_PINGROUP_DAP##n##_FS; \
+       sclk = TEGRA_PINGROUP_DAP##n##_SCLK; \
+       din = TEGRA_PINGROUP_DAP##n##_DIN; \
+       dout = TEGRA_PINGROUP_DAP##n##_DOUT; \
+       if (tristate) { \
+               if (atomic_dec_return(&dap_ref_count[n-1]) == 0) {\
+                       tegra_pinmux_set_tristate(fs, TEGRA_TRI_TRISTATE); \
+                       tegra_pinmux_set_tristate(sclk, TEGRA_TRI_TRISTATE); \
+                       tegra_pinmux_set_tristate(din, TEGRA_TRI_TRISTATE); \
+                       tegra_pinmux_set_tristate(dout, TEGRA_TRI_TRISTATE); \
+               } \
+       } else { \
+               if (atomic_inc_return(&dap_ref_count[n-1]) == 1) {\
+                       tegra_pinmux_set_tristate(fs, TEGRA_TRI_NORMAL); \
+                       tegra_pinmux_set_tristate(sclk, TEGRA_TRI_NORMAL); \
+                       tegra_pinmux_set_tristate(din, TEGRA_TRI_NORMAL); \
+                       tegra_pinmux_set_tristate(dout, TEGRA_TRI_NORMAL); \
+               } \
+       } \
+}
+
+TRISTATE_DAP_PORT(1)
+TRISTATE_DAP_PORT(2)
+
+int tegra_asoc_utils_tristate_dap(int id, bool tristate)
+{
+       switch (id) {
+       case 0:
+               tristate_dap_1(tristate);
+               break;
+       case 1:
+               tristate_dap_2(tristate);
+               break;
+       default:
+               pr_warn("Invalid DAP port\n");
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_asoc_utils_tristate_dap);
+
 bool tegra_is_voice_call_active(void)
 {
        if (g_is_call_mode)
index 6b91828..f59696b 100644 (file)
@@ -74,6 +74,8 @@ int tegra_asoc_switch_register(struct switch_dev *sdev);
 void tegra_asoc_switch_unregister(struct switch_dev *sdev);
 #endif
 
+int tegra_asoc_utils_tristate_dap(int id, bool tristate);
+
 extern int g_is_call_mode;
 
 #endif
index bc7eec5..106384c 100644 (file)
@@ -450,6 +450,8 @@ static int tegra_max98090_startup(struct snd_pcm_substream *substream)
        struct codec_config *bb_info;
        int codec_index;
 
+       tegra_asoc_utils_tristate_dap(i2s->id, false);
+
        if (!i2s->is_dam_used)
                return 0;
 
@@ -550,6 +552,8 @@ static void tegra_max98090_shutdown(struct snd_pcm_substream *substream)
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
 
+       tegra_asoc_utils_tristate_dap(i2s->id, true);
+
        if (!i2s->is_dam_used)
                return;