diff options
author | Harry Hong <hhong@nvidia.com> | 2011-07-04 17:27:22 +0900 |
---|---|---|
committer | Manish Tuteja <mtuteja@nvidia.com> | 2011-07-07 07:51:14 -0700 |
commit | b333ee2704eb1d62ae6301e5da60ae4af268b586 (patch) | |
tree | 14ed67fb0ce28b60616d15650dd2d75666c432d0 | |
parent | ad3f030e457f9a59501cc0d546b23dc7b038bb88 (diff) |
mmc: sdhci-tegra: Correct clock setting at set_clk
-Setting the minimum clock at enabling clock
-Enabling controller clock before MMC_POWER_UP to ensure
proper register read/write
-Limit max sdio clk to 24MHz for wifi on whistler.
whistler only supports up to 24MHz.
bug 834281
bug 845180
Change-Id: I9993a8bd9ab99af21c81d42f91175279f91cf0e4
Reviewed-on: http://git-master/r/39525
Tested-by: Harry Hong <hhong@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 42 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 10 |
2 files changed, 39 insertions, 13 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 977b6dde22d7..44e27409140e 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -32,6 +32,7 @@ #define DRIVER_NAME "sdhci-tegra" +#define SDHCI_TEGRA_MIN_CONTROLLER_CLOCK 12000000 #define SDHCI_VENDOR_CLOCK_CNTRL 0x100 struct tegra_sdhci_host { @@ -44,6 +45,7 @@ struct tegra_sdhci_host { int card_present; int cd_gpio; int cd_gpio_polarity; + unsigned int clk_limit; }; static irqreturn_t carddetect_irq(int irq, void *data) @@ -70,17 +72,35 @@ static int tegra_sdhci_enable_dma(struct sdhci_host *host) return 0; } -static void tegra_sdhci_enable_clock(struct tegra_sdhci_host *host, int enable) +static void tegra_sdhci_enable_clock(struct tegra_sdhci_host *host, int clock) { - if (enable && !host->clk_enabled) { - clk_enable(host->clk); - sdhci_writeb(host->sdhci, 1, SDHCI_VENDOR_CLOCK_CNTRL); - host->clk_enabled = 1; - } else if (!enable && host->clk_enabled) { - sdhci_writeb(host->sdhci, 0, SDHCI_VENDOR_CLOCK_CNTRL); + u8 val; + + if (clock) { + if (!host->clk_enabled) { + clk_enable(host->clk); + val = sdhci_readb(host->sdhci, SDHCI_VENDOR_CLOCK_CNTRL); + val |= 1; + sdhci_writeb(host->sdhci, val, SDHCI_VENDOR_CLOCK_CNTRL); + host->clk_enabled = 1; + } + if (host->clk_limit && (clock > host->clk_limit)) + clock = host->clk_limit; + if (clock < SDHCI_TEGRA_MIN_CONTROLLER_CLOCK) + clk_set_rate(host->clk, SDHCI_TEGRA_MIN_CONTROLLER_CLOCK); + else + clk_set_rate(host->clk, clock); + } else if (host->clk_enabled) { + val = sdhci_readb(host->sdhci, SDHCI_VENDOR_CLOCK_CNTRL); + val &= ~(0x1); + sdhci_writeb(host->sdhci, val, SDHCI_VENDOR_CLOCK_CNTRL); clk_disable(host->clk); host->clk_enabled = 0; } + if (host->clk_enabled) + host->sdhci->max_clk = clk_get_rate(host->clk); + else + host->sdhci->max_clk = 0; } static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock) @@ -153,6 +173,7 @@ static int __devinit tegra_sdhci_probe(struct platform_device *pdev) host->wp_gpio = plat->wp_gpio; host->cd_gpio = plat->cd_gpio; host->cd_gpio_polarity = plat->cd_gpio_polarity; + host->clk_limit = plat->clk_limit; host->clk = clk_get(&pdev->dev, plat->clk_id); if (IS_ERR(host->clk)) { @@ -356,7 +377,6 @@ static int tegra_sdhci_resume(struct platform_device *pdev) { struct tegra_sdhci_host *host = platform_get_drvdata(pdev); int ret; - u8 pwr; if (host->card_always_on && is_card_sdio(host->sdhci->mmc->card)) { int ret = 0; @@ -378,11 +398,7 @@ static int tegra_sdhci_resume(struct platform_device *pdev) return 0; } - tegra_sdhci_enable_clock(host, 1); - - pwr = SDHCI_POWER_ON; - sdhci_writeb(host->sdhci, pwr, SDHCI_POWER_CONTROL); - host->sdhci->pwr = 0; + tegra_sdhci_enable_clock(host, SDHCI_TEGRA_MIN_CONTROLLER_CLOCK); ret = sdhci_resume_host(host->sdhci); if (ret) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index fc941132b921..be49445cf578 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -988,6 +988,16 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) u16 clk; unsigned long timeout; + /* + * Controller clock should be enabled before MMC_POWER_UP to do + * register read/writes. + */ + if ((clock == 0) && (host->mmc->ios.power_mode == MMC_POWER_UP)) { + if (host->ops->set_clock) + host->ops->set_clock(host, host->mmc->f_min); + return; + } + if (clock && clock == host->clock) return; |