asoc: tegra: ALC5640 machine: Add support for setting bias level
Manoj Gangwal [Fri, 4 May 2012 14:19:23 +0000 (19:19 +0530)]
Allow setting bias level to turn off clock extern1 when codec
is idle.

Bug 964287

Reviewed on: http://git-master/r/#change,93950

Change-Id: Icc11e8bfb359b432f0bfd9ba214877259188de2b
Signed-off-by: Manoj Gangwal <mgangwal@nvidia.com>
Reviewed-on: http://git-master/r/99659
Reviewed-by: Automatic_Commit_Validation_User
Tested-by: Hunk Lin <hulin@nvidia.com>
Reviewed-by: Scott Peterson <speterson@nvidia.com>

sound/soc/tegra/tegra_rt5640.c

index f002f6d..72be76f 100644 (file)
@@ -69,6 +69,8 @@ struct tegra_rt5640 {
 #ifdef CONFIG_SWITCH
        int jack_status;
 #endif
+       enum snd_soc_bias_level bias_level;
+       volatile int clock_enabled;
 };
 
 static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream,
@@ -532,6 +534,9 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd)
                machine->gpio_requested |= GPIO_HP_DET;
        }
 
+       machine->bias_level = SND_SOC_BIAS_STANDBY;
+       machine->clock_enabled = 1;
+
        ret = snd_soc_add_card_controls(card, cardhu_controls,
                        ARRAY_SIZE(cardhu_controls));
        if (ret < 0)
@@ -596,6 +601,36 @@ static int tegra_rt5640_resume_pre(struct snd_soc_card *card)
        return 0;
 }
 
+static int tegra_rt5640_set_bias_level(struct snd_soc_card *card,
+       struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+       struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+
+       if (machine->bias_level == SND_SOC_BIAS_OFF &&
+               level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) {
+               machine->clock_enabled = 1;
+               tegra_asoc_utils_clk_enable(&machine->util_data);
+               machine->bias_level = level;
+       }
+
+       return 0;
+}
+
+static int tegra_rt5640_set_bias_level_post(struct snd_soc_card *card,
+       struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+       struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+
+       if (machine->bias_level != SND_SOC_BIAS_OFF &&
+               level == SND_SOC_BIAS_OFF && machine->clock_enabled) {
+               machine->clock_enabled = 0;
+               tegra_asoc_utils_clk_disable(&machine->util_data);
+       }
+
+       machine->bias_level = level;
+
+       return 0 ;
+}
 
 static struct snd_soc_card snd_soc_tegra_rt5640 = {
        .name = "tegra-rt5640",
@@ -603,6 +638,8 @@ static struct snd_soc_card snd_soc_tegra_rt5640 = {
        .dai_link = tegra_rt5640_dai,
        .num_links = ARRAY_SIZE(tegra_rt5640_dai),
        .resume_pre = tegra_rt5640_resume_pre,
+       .set_bias_level = tegra_rt5640_set_bias_level,
+       .set_bias_level_post = tegra_rt5640_set_bias_level_post,
 };
 
 static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
@@ -660,7 +697,7 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, machine);
-
+       card->dapm.idle_bias_off = 1;
        ret = snd_soc_register_card(card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",