summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSumit Bhattacharya <sumitb@nvidia.com>2011-06-14 20:16:13 +0530
committerNiket Sirsi <nsirsi@nvidia.com>2011-06-15 21:30:46 -0700
commitc242bcd738fa47f833822f618eff4dbff092bde7 (patch)
tree14f38883041a61227973efe24b4a1a9c8bef42c8
parente38ad73bcc26cd1352443bbadc18e39e613ecea6 (diff)
arm: tegra: disable HDA clocks while not in use
Disable HDA related clocks when device is not connected to HDMI. HDA clocks will be enabled from HDMI driver when HDMI device is hot plugged. Bug 820213 Change-Id: I4e6839aab0dc5277b11c415cbb495766f72442b8 Reviewed-on: http://git-master/r/36517 Tested-by: Sumit Bhattacharya <sumitb@nvidia.com> Reviewed-by: Niranjan Wartikar <nwartikar@nvidia.com> Reviewed-by: Ravindra Lokhande <rlokhande@nvidia.com> Reviewed-by: Scott Peterson <speterson@nvidia.com>
-rw-r--r--drivers/video/tegra/dc/hdmi.c51
-rw-r--r--sound/arm/tegra/hda_tegra.c71
2 files changed, 92 insertions, 30 deletions
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index b3bfac9b52e0..21139cebad6f 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -76,6 +76,9 @@ struct tegra_dc_hdmi_data {
struct clk *disp1_clk;
struct clk *disp2_clk;
+ struct clk *hda_clk;
+ struct clk *hda2codec_clk;
+ struct clk *hda2hdmicodec_clk;
struct switch_dev hpd_switch;
@@ -807,6 +810,29 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc)
goto err_put_clock;
}
+#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ hdmi->hda_clk = clk_get_sys("hda", NULL);
+ if (IS_ERR_OR_NULL(hdmi->hda_clk)) {
+ dev_err(&dc->ndev->dev, "hdmi: can't get hda clock\n");
+ err = -ENOENT;
+ goto err_put_clock;
+ }
+
+ hdmi->hda2codec_clk = clk_get_sys("hda2codec_2x", NULL);
+ if (IS_ERR_OR_NULL(hdmi->hda2codec_clk)) {
+ dev_err(&dc->ndev->dev, "hdmi: can't get hda2codec clock\n");
+ err = -ENOENT;
+ goto err_put_clock;
+ }
+
+ hdmi->hda2hdmicodec_clk = clk_get_sys("hda2hdmi", NULL);
+ if (IS_ERR_OR_NULL(hdmi->hda2hdmicodec_clk)) {
+ dev_err(&dc->ndev->dev, "hdmi: can't get hda2hdmi clock\n");
+ err = -ENOENT;
+ goto err_put_clock;
+ }
+#endif
+
/* TODO: support non-hotplug */
if (request_irq(gpio_to_irq(dc->out->hotplug_gpio), tegra_dc_hdmi_irq,
IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
@@ -873,6 +899,14 @@ err_free_irq:
disable_irq_wake(gpio_to_irq(dc->out->hotplug_gpio));
free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc);
err_put_clock:
+#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ if (!IS_ERR_OR_NULL(hdmi->hda2hdmicodec_clk))
+ clk_put(hdmi->hda2hdmicodec_clk);
+ if (!IS_ERR_OR_NULL(hdmi->hda2codec_clk))
+ clk_put(hdmi->hda2codec_clk);
+ if (!IS_ERR_OR_NULL(hdmi->hda_clk))
+ clk_put(hdmi->hda_clk);
+#endif
if (!IS_ERR_OR_NULL(disp2_clk))
clk_put(disp2_clk);
if (!IS_ERR_OR_NULL(disp1_clk))
@@ -898,6 +932,11 @@ static void tegra_dc_hdmi_destroy(struct tegra_dc *dc)
switch_dev_unregister(&hdmi->hpd_switch);
iounmap(hdmi->base);
release_resource(hdmi->base_res);
+#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ clk_put(hdmi->hda2hdmicodec_clk);
+ clk_put(hdmi->hda2codec_clk);
+ clk_put(hdmi->hda_clk);
+#endif
clk_put(hdmi->clk);
clk_put(hdmi->disp1_clk);
clk_put(hdmi->disp2_clk);
@@ -1337,6 +1376,13 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
clk_enable(hdmi->disp1_clk);
clk_enable(hdmi->disp2_clk);
+#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ /* Enabling HDA clocks before asserting HDA PD and ELDV bits */
+ clk_enable(hdmi->hda_clk);
+ clk_enable(hdmi->hda2codec_clk);
+ clk_enable(hdmi->hda2hdmicodec_clk);
+#endif
+
/* back off multiplier before attaching to parent at new rate. */
oldrate = clk_get_rate(hdmi->clk);
clk_set_rate(hdmi->clk, oldrate / 2);
@@ -1532,6 +1578,11 @@ static void tegra_dc_hdmi_disable(struct tegra_dc *dc)
#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0);
+ // sleep 1ms before disabling clocks to ensure HDA gets the interrupt
+ msleep(1);
+ clk_disable(hdmi->hda2hdmicodec_clk);
+ clk_disable(hdmi->hda2codec_clk);
+ clk_disable(hdmi->hda_clk);
#endif
hdmi->eld_retrieved = false;
tegra_periph_reset_assert(hdmi->clk);
diff --git a/sound/arm/tegra/hda_tegra.c b/sound/arm/tegra/hda_tegra.c
index af1c26c25fca..e43765323ef4 100644
--- a/sound/arm/tegra/hda_tegra.c
+++ b/sound/arm/tegra/hda_tegra.c
@@ -53,6 +53,7 @@ static int enable_msi;
/* Module clock info */
static struct clk *clk_hda, *clk_hda2codec , *clk_hda2hdmicodec;
+static bool is_hda_clk_on = false;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
static char *patch[SNDRV_CARDS];
@@ -448,6 +449,21 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
return 0;
}
+static void nv_tegra_enable_hda_clks(bool on)
+{
+ if (on && !is_hda_clk_on) {
+ clk_enable(clk_hda);
+ clk_enable(clk_hda2codec);
+ clk_enable(clk_hda2hdmicodec);
+ }
+ else if (!on && is_hda_clk_on) {
+ clk_disable(clk_hda2hdmicodec);
+ clk_disable(clk_hda2codec);
+ clk_disable(clk_hda);
+ }
+ is_hda_clk_on = on;
+}
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
/* power-up/down the controller */
void azx_power_notify(struct hda_bus *bus)
@@ -462,11 +478,18 @@ void azx_power_notify(struct hda_bus *bus)
break;
}
}
- if (power_on)
+
+ if (power_on) {
+ nv_tegra_enable_hda_clks(true);
azx_init_chip(chip, 1);
- else if (chip->running && power_save_controller &&
- !bus->power_keep_link_on)
- azx_stop_chip(chip);
+ }
+ else {
+ if (chip->running && power_save_controller &&
+ !bus->power_keep_link_on)
+ azx_stop_chip(chip);
+
+ nv_tegra_enable_hda_clks(false);
+ }
}
#endif /* CONFIG_SND_HDA_POWER_SAVE */
@@ -475,15 +498,6 @@ void azx_power_notify(struct hda_bus *bus)
/*
* power management
*/
-static int nv_tegra_hda_controller_suspend(struct platform_device *pdev)
-{
- clk_disable(clk_hda2hdmicodec);
- clk_disable(clk_hda2codec);
- clk_disable(clk_hda);
-
- return 0;
-}
-
static int nv_tegra_azx_suspend(struct platform_device *pdev,
pm_message_t state)
{
@@ -491,26 +505,23 @@ static int nv_tegra_azx_suspend(struct platform_device *pdev,
struct azx *chip = card->private_data;
int i;
+ nv_tegra_enable_hda_clks(true);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
azx_clear_irq_pending(chip);
for (i = 0; i < HDA_MAX_PCMS; i++)
snd_pcm_suspend_all(chip->pcm[i]);
if (chip->initialized)
snd_hda_suspend(chip->bus);
- azx_stop_chip(chip);
+
+ if (!chip->bus->power_keep_link_on)
+ azx_stop_chip(chip);
+
if (chip->irq >= 0) {
free_irq(chip->irq, chip);
chip->irq = -1;
}
- return nv_tegra_hda_controller_suspend(pdev);
-}
-
-static int nv_tegra_hda_controller_resume(struct platform_device *pdev)
-{
- clk_enable(clk_hda);
- clk_enable(clk_hda2codec);
- clk_enable(clk_hda2hdmicodec);
+ nv_tegra_enable_hda_clks(false);
return 0;
}
@@ -519,21 +530,22 @@ static int nv_tegra_azx_resume(struct platform_device *pdev)
{
struct snd_card *card = dev_get_drvdata(&pdev->dev);
struct azx *chip = card->private_data;
- int rc;
- rc = nv_tegra_hda_controller_resume(pdev);
- if (rc)
- return rc;
+ nv_tegra_enable_hda_clks(true);
chip->msi = 0;
if (azx_acquire_irq(chip, 1) < 0)
return -EIO;
- if (snd_hda_codecs_inuse(chip->bus))
+ if (snd_hda_codecs_inuse(chip->bus) || chip->bus->power_keep_link_on)
azx_init_chip(chip, 1);
snd_hda_resume(chip->bus);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ if (!snd_hda_codecs_inuse(chip->bus))
+ nv_tegra_enable_hda_clks(false);
+
return 0;
}
@@ -783,9 +795,8 @@ static int nv_tegra_hda_controller_init(struct platform_device *pdev)
snd_printk(KERN_ERR T30SFX "%s: can't get hda clock\n", __func__);
return -1;
}
- clk_enable(clk_hda);
- clk_enable(clk_hda2codec);
- clk_enable(clk_hda2hdmicodec);
+ nv_tegra_enable_hda_clks(true);
+
/*Enable the PCI access */
temp = readl(hda_reg + IPFS_HDA_CONFIGURATION_0);
temp |= IPFS_EN_FPCI;