summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/sdhci-tegra.c
diff options
context:
space:
mode:
authorPavan Kunapuli <pkunapuli@nvidia.com>2011-12-01 00:38:21 +0530
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-08 17:04:30 +0530
commit412cfe272238b47776d7211314af8db13fefbf3c (patch)
treea8d325a13f1807e2722745a85555240b04f23622 /drivers/mmc/host/sdhci-tegra.c
parent1fde505f2f36168523cd8995f2e605c33df804af (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.c42
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;