diff options
author | Pavan Kunapuli <pkunapuli@nvidia.com> | 2011-12-01 00:38:21 +0530 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2011-12-08 17:04:30 +0530 |
commit | 412cfe272238b47776d7211314af8db13fefbf3c (patch) | |
tree | a8d325a13f1807e2722745a85555240b04f23622 /drivers/mmc/host/sdhci-tegra.c | |
parent | 1fde505f2f36168523cd8995f2e605c33df804af (diff) |
mmc: tegra: Enforce platform specific clk limits
Some platforms cannot support higher clocks and result
in CRC errors during read/write transactions. Do not
exceed platform specific clk limits to prevent this.
Bug 908560
Change-Id: I8bff6c6b66ee1018325f90cd7bf3061bd1bc5fdb
Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com>
Reviewed-on: http://git-master/r/67483
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Diffstat (limited to 'drivers/mmc/host/sdhci-tegra.c')
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 777ea7807a3f..cef05c5baa3e 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -78,6 +78,8 @@ struct tegra_sdhci_host { unsigned int vddio_min_uv; /* vddio_max */ unsigned int vddio_max_uv; + /* max clk supported by the platform */ + unsigned int max_clk_limit; }; static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) @@ -269,6 +271,37 @@ static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) return 0; } +static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci, + unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + unsigned int clk_rate; + + if (sdhci->mmc->card && + mmc_card_ddr_mode(sdhci->mmc->card)) { + /* + * In ddr mode, tegra sdmmc controller clock frequency + * should be double the card clock frequency. + */ + clk_rate = clock * 2; + } else { + if (clock <= tegra_sdhost_min_freq) + clk_rate = tegra_sdhost_min_freq; + else if (clock <= tegra_sdhost_std_freq) + clk_rate = tegra_sdhost_std_freq; + else + clk_rate = clock; + } + + if (tegra_host->max_clk_limit && + (clk_rate > tegra_host->max_clk_limit)) + clk_rate = tegra_host->max_clk_limit; + + clk_set_rate(pltfm_host->clk, clk_rate); + sdhci->max_clk = clk_get_rate(pltfm_host->clk); +} + static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock) { int div; @@ -375,13 +408,7 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock) sdhci_writeb(sdhci, ctrl, SDHCI_VENDOR_CLOCK_CNTRL); tegra_host->clk_enabled = true; } - if (clock <= tegra_sdhost_min_freq) - clk_set_rate(pltfm_host->clk, tegra_sdhost_min_freq); - else if (clock <= tegra_sdhost_std_freq) - clk_set_rate(pltfm_host->clk, tegra_sdhost_std_freq); - else - clk_set_rate(pltfm_host->clk, clock); - sdhci->max_clk = clk_get_rate(pltfm_host->clk); + tegra_sdhci_set_clk_rate(sdhci, clock); if (tegra_host->hw_ops->set_card_clock) tegra_host->hw_ops->set_card_clock(sdhci, clock); } else if (!clock && tegra_host->clk_enabled) { @@ -622,6 +649,7 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) pltfm_host->clk = clk; pltfm_host->priv = tegra_host; tegra_host->clk_enabled = true; + tegra_host->max_clk_limit = plat->max_clk_limit; tegra_host->instance = pdev->id; host->mmc->pm_caps = plat->pm_flags; |