asoc: tegra: power optimisations for ardbeg/laguna
Nikesh Oswal [Tue, 18 Jun 2013 14:17:12 +0000 (19:17 +0530)]
1. Add dynamic enabling/tristating of DAP
2. Turn codec clock off/on in suspend/resume
3. disable/enable headphone detcetion interrupts
in suspend/resume

Bug 1256430

Change-Id: Id37dd4819ed34f65ece06da89ea258fa3cf20536
Signed-off-by: Nikesh Oswal <noswal@nvidia.com>
Reviewed-on: http://git-master/r/241918
Reviewed-by: Seema Khowala <seemaj@nvidia.com>
Tested-by: Seema Khowala <seemaj@nvidia.com>

arch/arm/mach-tegra/board-ardbeg-pinmux-t11x.h
arch/arm/mach-tegra/board-ardbeg-pinmux-t12x.h
arch/arm/mach-tegra/board-laguna-pinmux-t11x.h
arch/arm/mach-tegra/board-laguna-pinmux-t12x.h
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_rt5639.c
sound/soc/tegra/tegra_rt5645.c

index cefebbd..d904d3d 100644 (file)
@@ -27,16 +27,17 @@ static __initdata struct tegra_pingroup_config ardbeg_pinmux_common[] = {
        DEFAULT_PINMUX(CLK1_OUT,      EXTPERIPH1,  NORMAL,    NORMAL,   OUTPUT),
 
        /* I2S0 pinmux */
-       DEFAULT_PINMUX(DAP1_DIN,      I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_DOUT,     I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_FS,       I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_SCLK,     I2S0,        NORMAL,    NORMAL,   INPUT),
+       DEFAULT_PINMUX(DAP1_DIN,      I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_DOUT,     I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_FS,       I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_SCLK,     I2S0,        NORMAL,    TRISTATE,   INPUT),
 
        /* I2S1 pinmux */
-       DEFAULT_PINMUX(DAP2_DIN,      I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_DOUT,     I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_FS,       I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_SCLK,     I2S1,        NORMAL,    NORMAL,   INPUT),
+       /*Tristated by default, will be turned on/off as required by audio machine driver*/
+       DEFAULT_PINMUX(DAP2_DIN,      I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_DOUT,     I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_FS,       I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_SCLK,     I2S1,        NORMAL,    TRISTATE,   INPUT),
 
        /* CLDVFS pinmux */
        DEFAULT_PINMUX(DVFS_PWM,      CLDVFS,      NORMAL,    NORMAL,   OUTPUT),
@@ -152,10 +153,11 @@ static __initdata struct tegra_pingroup_config ardbeg_pinmux_common[] = {
        DEFAULT_PINMUX(CLK3_OUT,      EXTPERIPH3,  NORMAL,    NORMAL,   OUTPUT),
 
        /* I2S3 pinmux */
-       DEFAULT_PINMUX(DAP4_DIN,      I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_DOUT,     I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_FS,       I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_SCLK,     I2S3,        NORMAL,    NORMAL,   INPUT),
+       /*Tristated by default, will be turned on/off as required by audio machine driver*/
+       DEFAULT_PINMUX(DAP4_DIN,      I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_DOUT,     I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_FS,       I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_SCLK,     I2S3,        NORMAL,    TRISTATE,   INPUT),
 
        /* I2C1 pinmux */
        I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
index 29fa108..1ba21ac 100644 (file)
@@ -27,16 +27,17 @@ static __initdata struct tegra_pingroup_config ardbeg_pinmux_common[] = {
        DEFAULT_PINMUX(DAP_MCLK1,     EXTPERIPH1,  NORMAL,    NORMAL,   OUTPUT),
 
        /* I2S0 pinmux */
-       DEFAULT_PINMUX(DAP1_DIN,      I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_DOUT,     I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_FS,       I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_SCLK,     I2S0,        NORMAL,    NORMAL,   INPUT),
+       DEFAULT_PINMUX(DAP1_DIN,      I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_DOUT,     I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_FS,       I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_SCLK,     I2S0,        NORMAL,    TRISTATE,   INPUT),
 
        /* I2S1 pinmux */
-       DEFAULT_PINMUX(DAP2_DIN,      I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_DOUT,     I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_FS,       I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_SCLK,     I2S1,        NORMAL,    NORMAL,   INPUT),
+       /*Tristated by default, will be turned on/off as required by audio machine driver*/
+       DEFAULT_PINMUX(DAP2_DIN,      I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_DOUT,     I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_FS,       I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_SCLK,     I2S1,        NORMAL,    TRISTATE,   INPUT),
 
        /* CLDVFS pinmux */
        DEFAULT_PINMUX(DVFS_PWM,      CLDVFS,      NORMAL,    NORMAL,   OUTPUT),
@@ -155,10 +156,11 @@ static __initdata struct tegra_pingroup_config ardbeg_pinmux_common[] = {
        DEFAULT_PINMUX(CLK3_OUT,      EXTPERIPH3,  NORMAL,    NORMAL,   OUTPUT),
 
        /* I2S3 pinmux */
-       DEFAULT_PINMUX(DAP4_DIN,      I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_DOUT,     I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_FS,       I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_SCLK,     I2S3,        NORMAL,    NORMAL,   INPUT),
+       /*Tristated by default, will be turned on/off as required by audio machine driver*/
+       DEFAULT_PINMUX(DAP4_DIN,      I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_DOUT,     I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_FS,       I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_SCLK,     I2S3,        NORMAL,    TRISTATE,   INPUT),
 
        /* I2C1 pinmux */
        I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
index fd306ae..8d918f2 100644 (file)
@@ -27,16 +27,17 @@ static __initdata struct tegra_pingroup_config laguna_pinmux_common[] = {
        DEFAULT_PINMUX(CLK1_OUT,      EXTPERIPH1,  NORMAL,    NORMAL,   OUTPUT),
 
        /* I2S0 pinmux */
-       DEFAULT_PINMUX(DAP1_DIN,      I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_DOUT,     I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_FS,       I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_SCLK,     I2S0,        NORMAL,    NORMAL,   INPUT),
+       DEFAULT_PINMUX(DAP1_DIN,      I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_DOUT,     I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_FS,       I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_SCLK,     I2S0,        NORMAL,    TRISTATE,   INPUT),
 
        /* I2S1 pinmux */
-       DEFAULT_PINMUX(DAP2_DIN,      I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_DOUT,     I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_FS,       I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_SCLK,     I2S1,        NORMAL,    NORMAL,   INPUT),
+       /*Tristated by default, will be turned on/off as required by audio machine driver*/
+       DEFAULT_PINMUX(DAP2_DIN,      I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_DOUT,     I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_FS,       I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_SCLK,     I2S1,        NORMAL,    TRISTATE,   INPUT),
 
        /* CLDVFS pinmux */
        DEFAULT_PINMUX(DVFS_PWM,      CLDVFS,      NORMAL,    NORMAL,   OUTPUT),
@@ -154,10 +155,11 @@ static __initdata struct tegra_pingroup_config laguna_pinmux_common[] = {
        DEFAULT_PINMUX(CLK3_OUT,      EXTPERIPH3,  NORMAL,    NORMAL,   OUTPUT),
 
        /* I2S3 pinmux */
-       DEFAULT_PINMUX(DAP4_DIN,      I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_DOUT,     I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_FS,       I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_SCLK,     I2S3,        NORMAL,    NORMAL,   INPUT),
+       /*Tristated by default, will be turned on/off as required by audio machine driver*/
+       DEFAULT_PINMUX(DAP4_DIN,      I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_DOUT,     I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_FS,       I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_SCLK,     I2S3,        NORMAL,    TRISTATE,   INPUT),
 
        /* I2C1 pinmux */
        I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
index 40767e2..60ece66 100644 (file)
@@ -30,16 +30,17 @@ static __initdata struct tegra_pingroup_config laguna_pinmux_common[] = {
        DEFAULT_PINMUX(DAP_MCLK1_REQ, SATA,        NORMAL,    NORMAL,   OUTPUT),
 
        /* I2S0 pinmux */
-       DEFAULT_PINMUX(DAP1_DIN,      I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_DOUT,     I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_FS,       I2S0,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP1_SCLK,     I2S0,        NORMAL,    NORMAL,   INPUT),
+       DEFAULT_PINMUX(DAP1_DIN,      I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_DOUT,     I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_FS,       I2S0,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP1_SCLK,     I2S0,        NORMAL,    TRISTATE,   INPUT),
 
        /* I2S1 pinmux */
-       DEFAULT_PINMUX(DAP2_DIN,      I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_DOUT,     I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_FS,       I2S1,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP2_SCLK,     I2S1,        NORMAL,    NORMAL,   INPUT),
+       /*Tristated by default, will be turned on/off as required by audio machine driver*/
+       DEFAULT_PINMUX(DAP2_DIN,      I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_DOUT,     I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_FS,       I2S1,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP2_SCLK,     I2S1,        NORMAL,    TRISTATE,   INPUT),
 
        /* CLDVFS pinmux */
        DEFAULT_PINMUX(DVFS_PWM,      CLDVFS,      NORMAL,    NORMAL,   OUTPUT),
@@ -164,10 +165,11 @@ static __initdata struct tegra_pingroup_config laguna_pinmux_common[] = {
        DEFAULT_PINMUX(CLK3_OUT,      EXTPERIPH3,  NORMAL,    NORMAL,   OUTPUT),
 
        /* I2S3 pinmux */
-       DEFAULT_PINMUX(DAP4_DIN,      I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_DOUT,     I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_FS,       I2S3,        NORMAL,    NORMAL,   INPUT),
-       DEFAULT_PINMUX(DAP4_SCLK,     I2S3,        NORMAL,    NORMAL,   INPUT),
+       /*Tristated by default, will be turned on/off as required by audio machine driver*/
+       DEFAULT_PINMUX(DAP4_DIN,      I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_DOUT,     I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_FS,       I2S3,        NORMAL,    TRISTATE,   INPUT),
+       DEFAULT_PINMUX(DAP4_SCLK,     I2S3,        NORMAL,    TRISTATE,   INPUT),
 
        /* I2C1 pinmux */
        I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
index 8994163..30479f6 100644 (file)
@@ -91,6 +91,15 @@ static void tristate_dap_##n(bool tristate) \
 
 TRISTATE_DAP_PORT(1)
 TRISTATE_DAP_PORT(2)
+/*I2S2 and I2S3 for other chips do not map to DAP3 and DAP4 (also
+these pinmux dont exist for other chips), they map to some
+other pinmux*/
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)\
+               || defined(CONFIG_ARCH_TEGRA_12x_SOC)\
+               || defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       TRISTATE_DAP_PORT(3)
+       TRISTATE_DAP_PORT(4)
+#endif
 
 int tegra_asoc_utils_tristate_dap(int id, bool tristate)
 {
@@ -101,6 +110,19 @@ int tegra_asoc_utils_tristate_dap(int id, bool tristate)
        case 1:
                tristate_dap_2(tristate);
                break;
+/*I2S2 and I2S3 for other chips do not map to DAP3 and DAP4 (also
+these pinmux dont exist for other chips), they map to some
+other pinmux*/
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)\
+       || defined(CONFIG_ARCH_TEGRA_12x_SOC)\
+       || defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       case 2:
+               tristate_dap_3(tristate);
+               break;
+       case 3:
+               tristate_dap_4(tristate);
+               break;
+#endif
        default:
                pr_warn("Invalid DAP port\n");
                break;
index 894a479..ebee70c 100644 (file)
@@ -85,8 +85,29 @@ struct tegra_rt5639 {
        struct regulator *spk_reg;
        struct regulator *mic_reg;
        struct regulator *dmic_reg;
+       struct snd_soc_card *pcard;
 };
 
+static int tegra_rt5639_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       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, false);
+
+       return 0;
+}
+
+static void tegra_rt5639_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       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);
+}
+
 static int tegra_rt5639_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params)
 {
@@ -361,11 +382,15 @@ static int tegra_hw_free(struct snd_pcm_substream *substream)
 static struct snd_soc_ops tegra_rt5639_ops = {
        .hw_params = tegra_rt5639_hw_params,
        .hw_free = tegra_hw_free,
+       .startup = tegra_rt5639_startup,
+       .shutdown = tegra_rt5639_shutdown,
 };
 
 static struct snd_soc_ops tegra_rt5639_bt_sco_ops = {
        .hw_params = tegra_bt_sco_hw_params,
        .hw_free = tegra_hw_free,
+       .startup = tegra_rt5639_startup,
+       .shutdown = tegra_rt5639_shutdown,
 };
 
 static struct snd_soc_ops tegra_spdif_ops = {
@@ -663,15 +688,68 @@ static struct snd_soc_dai_link tegra_rt5639_dai[NUM_DAI_LINKS] = {
        },
 };
 
+static int tegra_rt5639_suspend_post(struct snd_soc_card *card)
+{
+       struct snd_soc_jack_gpio *gpio = &tegra_rt5639_hp_jack_gpio;
+       struct tegra_rt5639 *machine = snd_soc_card_get_drvdata(card);
+       int i, suspend_allowed = 1;
+
+       /*In Voice Call we ignore suspend..so check for that*/
+       for (i = 0; i < machine->pcard->num_links; i++) {
+               if (machine->pcard->dai_link[i].ignore_suspend) {
+                       suspend_allowed = 0;
+                       break;
+               }
+       }
+
+       if (suspend_allowed) {
+               /*Disable the irq so that device goes to suspend*/
+               if (gpio_is_valid(gpio->gpio))
+                       disable_irq(gpio_to_irq(gpio->gpio));
+               /*This may be required if dapm setbias level is not called in
+               some cases, may be due to a wrong dapm map*/
+               if (machine->clock_enabled) {
+                       machine->clock_enabled = 0;
+                       tegra_asoc_utils_clk_disable(&machine->util_data);
+               }
+               /*TODO: Disable Audio Regulators*/
+       }
+
+       return 0;
+}
+
 static int tegra_rt5639_resume_pre(struct snd_soc_card *card)
 {
        int val;
        struct snd_soc_jack_gpio *gpio = &tegra_rt5639_hp_jack_gpio;
+       struct tegra_rt5639 *machine = snd_soc_card_get_drvdata(card);
+       int i, suspend_allowed = 1;
 
-       if (gpio_is_valid(gpio->gpio)) {
-               val = gpio_get_value(gpio->gpio);
-               val = gpio->invert ? !val : val;
-               snd_soc_jack_report(gpio->jack, val, gpio->report);
+       /*In Voice Call we ignore suspend..so check for that*/
+       for (i = 0; i < machine->pcard->num_links; i++) {
+               if (machine->pcard->dai_link[i].ignore_suspend) {
+                       suspend_allowed = 0;
+                       break;
+               }
+       }
+
+       if (suspend_allowed) {
+               /*Convey jack status after resume and
+               re-enable the interrupts*/
+               if (gpio_is_valid(gpio->gpio)) {
+                       val = gpio_get_value(gpio->gpio);
+                       val = gpio->invert ? !val : val;
+                       snd_soc_jack_report(gpio->jack, val, gpio->report);
+                       enable_irq(gpio_to_irq(gpio->gpio));
+               }
+               /*This may be required if dapm setbias level is not called in
+               some cases, may be due to a wrong dapm map*/
+               if (!machine->clock_enabled &&
+                               machine->bias_level != SND_SOC_BIAS_OFF) {
+                       machine->clock_enabled = 1;
+                       tegra_asoc_utils_clk_enable(&machine->util_data);
+               }
+               /*TODO: Enable Audio Regulators*/
        }
 
        return 0;
@@ -713,6 +791,7 @@ static struct snd_soc_card snd_soc_tegra_rt5639 = {
        .owner = THIS_MODULE,
        .dai_link = tegra_rt5639_dai,
        .num_links = ARRAY_SIZE(tegra_rt5639_dai),
+       .suspend_post = tegra_rt5639_suspend_post,
        .resume_pre = tegra_rt5639_resume_pre,
        .set_bias_level = tegra_rt5639_set_bias_level,
        .set_bias_level_post = tegra_rt5639_set_bias_level_post,
@@ -812,14 +891,14 @@ static int tegra_rt5639_driver_probe(struct platform_device *pdev)
        }
 
        machine->pdata = pdata;
+       machine->pcard = card;
+       machine->bias_level = SND_SOC_BIAS_STANDBY;
+       machine->clock_enabled = 1;
 
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
        if (ret)
                goto err_free_machine;
 
-       machine->bias_level = SND_SOC_BIAS_STANDBY;
-       machine->clock_enabled = 1;
-
        /*
        *codec_reg - its a GPIO (in the form of a fixed regulator) that enables
        *the basic(I2C) power for the codec and must be ON always
index bceff6a..cfe696d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tegra_rt5645.c - Tegra machine ASoC driver for boards using ALC5640 codec.
+ * tegra_rt5645.c - Tegra machine ASoC driver for boards using ALC5645 codec.
  *
  * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
  * This program is free software; you can redistribute it and/or
@@ -85,8 +85,29 @@ struct tegra_rt5645 {
        struct regulator *spk_reg;
        struct regulator *mic_reg;
        struct regulator *dmic_reg;
+       struct snd_soc_card *pcard;
 };
 
+static int tegra_rt5645_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       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, false);
+
+       return 0;
+}
+
+static void tegra_rt5645_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       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);
+}
+
 static int tegra_rt5645_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params)
 {
@@ -361,11 +382,15 @@ static int tegra_hw_free(struct snd_pcm_substream *substream)
 static struct snd_soc_ops tegra_rt5645_ops = {
        .hw_params = tegra_rt5645_hw_params,
        .hw_free = tegra_hw_free,
+       .startup = tegra_rt5645_startup,
+       .shutdown = tegra_rt5645_shutdown,
 };
 
 static struct snd_soc_ops tegra_rt5645_bt_sco_ops = {
        .hw_params = tegra_bt_sco_hw_params,
        .hw_free = tegra_hw_free,
+       .startup = tegra_rt5645_startup,
+       .shutdown = tegra_rt5645_shutdown,
 };
 
 static struct snd_soc_ops tegra_spdif_ops = {
@@ -663,15 +688,69 @@ static struct snd_soc_dai_link tegra_rt5645_dai[NUM_DAI_LINKS] = {
        },
 };
 
+static int tegra_rt5645_suspend_post(struct snd_soc_card *card)
+{
+       struct snd_soc_jack_gpio *gpio = &tegra_rt5645_hp_jack_gpio;
+       struct tegra_rt5645 *machine = snd_soc_card_get_drvdata(card);
+       int i, suspend_allowed = 1;
+
+       /*In Voice Call we ignore suspend..so check for that*/
+       for (i = 0; i < machine->pcard->num_links; i++) {
+               if (machine->pcard->dai_link[i].ignore_suspend) {
+                       suspend_allowed = 0;
+                       break;
+               }
+       }
+
+       if (suspend_allowed) {
+               /*Disable the irq so that device goes to suspend*/
+               if (gpio_is_valid(gpio->gpio))
+                       disable_irq(gpio_to_irq(gpio->gpio));
+
+               /*This may be required if dapm setbias level is not called in
+               some cases, may be due to a wrong dapm map*/
+               if (machine->clock_enabled) {
+                       machine->clock_enabled = 0;
+                       tegra_asoc_utils_clk_disable(&machine->util_data);
+               }
+               /*TODO: Disable Audio Regulators*/
+       }
+
+       return 0;
+}
+
 static int tegra_rt5645_resume_pre(struct snd_soc_card *card)
 {
        int val;
        struct snd_soc_jack_gpio *gpio = &tegra_rt5645_hp_jack_gpio;
+       struct tegra_rt5645 *machine = snd_soc_card_get_drvdata(card);
+       int i, suspend_allowed = 1;
 
-       if (gpio_is_valid(gpio->gpio)) {
-               val = gpio_get_value(gpio->gpio);
-               val = gpio->invert ? !val : val;
-               snd_soc_jack_report(gpio->jack, val, gpio->report);
+       /*In Voice Call we ignore suspend..so check for that*/
+       for (i = 0; i < machine->pcard->num_links; i++) {
+               if (machine->pcard->dai_link[i].ignore_suspend) {
+                       suspend_allowed = 0;
+                       break;
+               }
+       }
+
+       if (suspend_allowed) {
+               /*Convey jack status after resume and
+               re-enable the interrupts*/
+               if (gpio_is_valid(gpio->gpio)) {
+                       val = gpio_get_value(gpio->gpio);
+                       val = gpio->invert ? !val : val;
+                       snd_soc_jack_report(gpio->jack, val, gpio->report);
+                       enable_irq(gpio_to_irq(gpio->gpio));
+               }
+               /*This may be required if dapm setbias level is not called in
+               some cases, may be due to a wrong dapm map*/
+               if (!machine->clock_enabled &&
+                               machine->bias_level != SND_SOC_BIAS_OFF) {
+                       machine->clock_enabled = 1;
+                       tegra_asoc_utils_clk_enable(&machine->util_data);
+               }
+               /*TODO: Enable Audio Regulators*/
        }
 
        return 0;
@@ -713,6 +792,7 @@ static struct snd_soc_card snd_soc_tegra_rt5645 = {
        .owner = THIS_MODULE,
        .dai_link = tegra_rt5645_dai,
        .num_links = ARRAY_SIZE(tegra_rt5645_dai),
+       .suspend_post = tegra_rt5645_suspend_post,
        .resume_pre = tegra_rt5645_resume_pre,
        .set_bias_level = tegra_rt5645_set_bias_level,
        .set_bias_level_post = tegra_rt5645_set_bias_level_post,
@@ -812,14 +892,14 @@ static int tegra_rt5645_driver_probe(struct platform_device *pdev)
        }
 
        machine->pdata = pdata;
+       machine->pcard = card;
+       machine->bias_level = SND_SOC_BIAS_STANDBY;
+       machine->clock_enabled = 1;
 
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
        if (ret)
                goto err_free_machine;
 
-       machine->bias_level = SND_SOC_BIAS_STANDBY;
-       machine->clock_enabled = 1;
-
        /*
        *codec_reg - its a GPIO (in the form of a fixed regulator) that enables
        *the basic(I2C) power for the codec and must be ON always