summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeepesh Gujarathi <dgujarathi@nvidia.com>2010-04-16 19:33:37 +0530
committerJanne Hellsten <jhellsten@nvidia.com>2010-04-29 05:23:39 -0700
commite4261d92e175b814d2abd7dab4978da07944cfc3 (patch)
tree96fa4eb6c6d4c5c5f365145897de46965ce752d2
parentd444b79200ae8b4ca60c1e0f031103c502de22a1 (diff)
tegra mmc: enable/diable sdio controller clock
The sd controller clock will be switch on/off on a per transaction basis, this will ensure that the clock is off during OSIdle which should inturn help better DVFS results. fix for Bug:673699 Change-Id: If479fe4aea6ae2c00818c84b43fc38a66437c643 Reviewed-on: http://git-master/r/1242 Reviewed-by: Janne Hellsten <jhellsten@nvidia.com> Tested-by: Janne Hellsten <jhellsten@nvidia.com>
-rwxr-xr-xdrivers/mmc/host/sdhci-tegra.c42
-rwxr-xr-xdrivers/mmc/host/sdhci.c6
2 files changed, 35 insertions, 13 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index a7dcb74c06b6..3216d98329f8 100755
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -52,11 +52,24 @@ struct tegra_sdhci
NvU32 cd_polarity;
NvRmGpioInterruptHandle cd_int;
NvU32 MaxClock;
+ NvBool SdioControllerClkEnabled;
#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET
NvU32 StartOffset;
#endif
};
+static NvError
+tegra_sdhci_set_controller_clk(struct tegra_sdhci *t_sdhci, NvBool enable)
+{
+ NvError e = NvSuccess;
+ if (t_sdhci->SdioControllerClkEnabled != enable) {
+ t_sdhci->SdioControllerClkEnabled = enable;
+ e = (NvRmPowerModuleClockControl(s_hRmGlobal, t_sdhci->ModId,
+ 0, enable));
+ }
+ return e;
+}
+
static int tegra_sdhci_enable_dma(struct sdhci_host *host)
{
return 0;
@@ -133,11 +146,11 @@ static unsigned int tegra_sdhci_get_maxclock(struct sdhci_host *host)
static int tegra_sdhci_set_clock(struct sdhci_host *host,
unsigned int clock)
{
+ NvError err;
struct tegra_sdhci *t_sdhci;
t_sdhci = sdhci_priv(host);
if (clock) {
- NvError err;
NvU32 min, max, target, actual_freq;
min = 400;
max = clock / 1000;
@@ -146,15 +159,23 @@ static int tegra_sdhci_set_clock(struct sdhci_host *host,
if (max < min) max = min;
if (target < min) target = min;
+ /* enable clock to sdio controller */
+ err = tegra_sdhci_set_controller_clk(t_sdhci, NV_TRUE);
+ if (err) goto fail;
+
err = NvRmPowerModuleClockConfig(s_hRmGlobal,
t_sdhci->ModId, 0, min, max, &target, 1,
&actual_freq, 0);
- if (err==NvSuccess)
- return 1;
+ if (err) goto fail;
} else {
- /* TODO Do we need to shutdown the clock? */
+ /* disable clock to sdio controller */
+ err = tegra_sdhci_set_controller_clk(t_sdhci, NV_FALSE);
+ if (err) goto fail;
}
- return 0;
+ return 1; /* return success */
+fail:
+ pr_err("tegra_sdhci_set_clock failed with error %d\n", err);
+ return 0; /* upper layer expects return value 0 in case of failure */
}
static struct sdhci_ops tegra_sdhci_ops = {
@@ -200,6 +221,7 @@ int __init tegra_sdhci_probe(struct platform_device *pdev)
host->pdev = pdev;
host->sdhost = sdhost;
host->ModId = ModId;
+ host->SdioControllerClkEnabled = NV_FALSE;
#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET
if (pdata)
host->StartOffset = pdata->StartOffset;
@@ -254,7 +276,7 @@ int __init tegra_sdhci_probe(struct platform_device *pdev)
err2 = NvRmPowerModuleClockConfig(s_hRmGlobal, ModId, 0,
min, max, &target, 1, &host->MaxClock, 0);
- err3 = NvRmPowerModuleClockControl(s_hRmGlobal, ModId, 0, NV_TRUE);
+ err3 = tegra_sdhci_set_controller_clk(host, NV_TRUE);
if (err1 || err2 || err3) {
goto fail;
}
@@ -339,8 +361,7 @@ static int __devexit tegra_sdhci_remove(struct platform_device *pdev)
if (host->hSdioHandle)
NvOdmSdioClose(host->hSdioHandle);
(void)NvRmSetModuleTristate(s_hRmGlobal, host->ModId, NV_TRUE);
- (void)NvRmPowerModuleClockControl(s_hRmGlobal,
- host->ModId, 0, NV_FALSE);
+ (void)tegra_sdhci_set_controller_clk(host, NV_FALSE);
if (host->wp_pin)
NvRmGpioReleasePinHandles(s_hGpioGlobal, &host->wp_pin, 1);
@@ -366,7 +387,7 @@ static int tegra_sdhci_suspend(struct platform_device *pdev, pm_message_t state)
if (t_sdhci->sdhost->card_type != MMC_TYPE_SDIO) {
ret = sdhci_suspend_host(t_sdhci->sdhost,state);
if (ret)
- printk("sdhci_suspend_host failed with error %d\n", ret);
+ pr_err("sdhci_suspend_host failed with error %d\n", ret);
}
return ret;
@@ -378,11 +399,10 @@ static int tegra_sdhci_resume(struct platform_device *pdev)
struct tegra_sdhci *t_sdhci;
t_sdhci = platform_get_drvdata(pdev);
-
if (t_sdhci->sdhost->card_type != MMC_TYPE_SDIO) {
ret = sdhci_resume_host(t_sdhci->sdhost);
if (ret)
- printk("sdhci_resume_host failed with error %d\n", ret);
+ pr_err("sdhci_resume_host failed with error %d\n", ret);
}
return ret;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index df4c4bcfe431..f0860595c21d 100755
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -933,9 +933,11 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
- if (clock == 0)
+ if (clock == 0) {
+ if (host->ops->set_clock)
+ div = host->ops->set_clock(host, 0);
goto out;
-
+ }
host->last_clock = clock;
div = 0;