summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/sdhci-tegra.c
diff options
context:
space:
mode:
authorPavan Kunapuli <pkunapuli@nvidia.com>2011-11-15 21:03:38 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:50:07 -0800
commit2d919361f68aa22a9759244b8e2ee04f7eefb1cd (patch)
tree616d5ccae7f5911a52ac524e6f1ec9101e8018f2 /drivers/mmc/host/sdhci-tegra.c
parentb223011aff83d1e0dbdb0bc343b378d9d4572f4d (diff)
sdhci: tegra: Add Tegra sd host init after reset
Adding tegra sdhost controller initialization settings and enabling capabilities after reset. Changed the voltage range of SD cards to 2.7V - 3.6V to support the entire valid voltage range rather than only 3.3V. Bug 901938 Change-Id: Ic8dddc62ce6dfab931afbd3e68a2658dc2ec279e Reviewed-on: http://git-master/r/64105 Reviewed-by: Sachin Nikam <snikam@nvidia.com> Tested-by: Naveen Kumar Arepalli <naveenk@nvidia.com> Reviewed-by: Bitan Biswas <bbiswas@nvidia.com> Rebase-Id: Rc03308b4e2b09349e15d3855baa1c32a0f248a5b
Diffstat (limited to 'drivers/mmc/host/sdhci-tegra.c')
-rw-r--r--drivers/mmc/host/sdhci-tegra.c60
1 files changed, 56 insertions, 4 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 18f036b7c369..e8eeeaa12650 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -30,13 +30,24 @@
#include "sdhci-pltfm.h"
#define SDHCI_VENDOR_CLOCK_CNTRL 0x100
+#define SDHCI_VENDOR_CLOCK_CNTRL_SDMMC_CLK 0x1
#define SDHCI_VENDOR_CLOCK_CNTRL_PADPIPE_CLKEN_OVERRIDE 0x8
+#define SDHCI_VENDOR_CLOCK_CNTRL_BASE_CLK_FREQ_SHIFT 8
+
+#define SDHCI_VENDOR_MISC_CNTRL 0x120
+#define SDHCI_VENDOR_MISC_CNTRL_SDMMC_SPARE0_ENABLE_SD_3_0 0x20
static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock);
+static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci);
+
+static unsigned int tegra3_sdhost_max_clk[4] = {
+ 208000000, 104000000, 208000000, 104000000 };
struct tegra_sdhci_hw_ops{
/* Set the internal clk and card clk.*/
void (*set_card_clock)(struct sdhci_host *sdhci, unsigned int clock);
+ /* Post reset vendor registers configuration */
+ void (*sdhost_init)(struct sdhci_host *sdhci);
};
static struct tegra_sdhci_hw_ops tegra_2x_sdhci_ops = {
@@ -44,6 +55,7 @@ static struct tegra_sdhci_hw_ops tegra_2x_sdhci_ops = {
static struct tegra_sdhci_hw_ops tegra_3x_sdhci_ops = {
.set_card_clock = tegra_3x_sdhci_set_card_clock,
+ .sdhost_init = tegra3_sdhci_post_reset_init,
};
struct tegra_sdhci_host {
@@ -52,6 +64,8 @@ struct tegra_sdhci_host {
struct regulator *vdd_slot_reg;
/* Pointer to the chip specific HW ops */
struct tegra_sdhci_hw_ops *hw_ops;
+ /* Host controller instance */
+ unsigned int instance;
};
static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
@@ -69,11 +83,12 @@ static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
if (unlikely(reg == SDHCI_HOST_VERSION)) {
/* Erratum: Version register is invalid in HW. */
return SDHCI_SPEC_200;
}
-
+#endif
return readw(host->ioaddr + reg);
}
@@ -114,6 +129,36 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci)
return gpio_get_value(plat->wp_gpio);
}
+static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci)
+{
+ u16 ctrl;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
+ struct tegra_sdhci_host *tegra_host = pltfm_host->priv;
+
+ /* Set the base clock frequency */
+ ctrl = sdhci_readw(sdhci, SDHCI_VENDOR_CLOCK_CNTRL);
+ ctrl &= ~(0xFF << SDHCI_VENDOR_CLOCK_CNTRL_BASE_CLK_FREQ_SHIFT);
+ ctrl |= (tegra3_sdhost_max_clk[tegra_host->instance] / 1000000) <<
+ SDHCI_VENDOR_CLOCK_CNTRL_BASE_CLK_FREQ_SHIFT;
+ sdhci_writew(sdhci, ctrl, SDHCI_VENDOR_CLOCK_CNTRL);
+
+ /* Enable SDHOST v3.0 support */
+ ctrl = sdhci_readw(sdhci, SDHCI_VENDOR_MISC_CNTRL);
+ ctrl |= SDHCI_VENDOR_MISC_CNTRL_SDMMC_SPARE0_ENABLE_SD_3_0;
+ sdhci_writew(sdhci, ctrl, SDHCI_VENDOR_MISC_CNTRL);
+}
+
+static void tegra_sdhci_reset_exit(struct sdhci_host *sdhci, u8 mask)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
+ struct tegra_sdhci_host *tegra_host = pltfm_host->priv;
+
+ if (mask & SDHCI_RESET_ALL) {
+ if (tegra_host->hw_ops->sdhost_init)
+ tegra_host->hw_ops->sdhost_init(sdhci);
+ }
+}
+
static void sdhci_status_notify_cb(int card_present, void *dev_id)
{
struct sdhci_host *sdhci = (struct sdhci_host *)dev_id;
@@ -265,6 +310,7 @@ static void tegra_sdhci_set_clock(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;
+ u8 ctrl;
pr_debug("%s %s %u enabled=%u\n", __func__,
mmc_hostname(sdhci->mmc), clock, tegra_host->clk_enabled);
@@ -272,7 +318,9 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
if (clock) {
if (!tegra_host->clk_enabled) {
clk_enable(pltfm_host->clk);
- sdhci_writeb(sdhci, 1, SDHCI_VENDOR_CLOCK_CNTRL);
+ ctrl = sdhci_readb(sdhci, SDHCI_VENDOR_CLOCK_CNTRL);
+ ctrl |= SDHCI_VENDOR_CLOCK_CNTRL_SDMMC_CLK;
+ sdhci_writeb(sdhci, ctrl, SDHCI_VENDOR_CLOCK_CNTRL);
tegra_host->clk_enabled = true;
}
if (tegra_host->hw_ops->set_card_clock)
@@ -280,7 +328,9 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
} else if (!clock && tegra_host->clk_enabled) {
if (tegra_host->hw_ops->set_card_clock)
tegra_host->hw_ops->set_card_clock(sdhci, clock);
- sdhci_writeb(sdhci, 0, SDHCI_VENDOR_CLOCK_CNTRL);
+ ctrl = sdhci_readb(sdhci, SDHCI_VENDOR_CLOCK_CNTRL);
+ ctrl &= ~SDHCI_VENDOR_CLOCK_CNTRL_SDMMC_CLK;
+ sdhci_writeb(sdhci, ctrl, SDHCI_VENDOR_CLOCK_CNTRL);
clk_disable(pltfm_host->clk);
tegra_host->clk_enabled = false;
}
@@ -350,6 +400,7 @@ static struct sdhci_ops tegra_sdhci_ops = {
.set_clock = tegra_sdhci_set_clock,
.suspend = tegra_sdhci_suspend,
.resume = tegra_sdhci_resume,
+ .platform_reset_exit = tegra_sdhci_reset_exit,
};
static struct sdhci_pltfm_data sdhci_tegra_pdata = {
@@ -461,7 +512,7 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
tegra_host->vdd_io_reg = NULL;
} else {
rc = regulator_set_voltage(tegra_host->vdd_io_reg,
- 3280000, 3320000);
+ 2700000, 3600000);
if (rc) {
dev_err(mmc_dev(host->mmc), "%s regulator_set_voltage failed: %d",
"vddio_sdmmc", rc);
@@ -492,6 +543,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->instance = pdev->id;
host->mmc->pm_caps = plat->pm_flags;