diff options
author | Pavan Kunapuli <pkunapuli@nvidia.com> | 2011-11-15 21:03:38 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:50:07 -0800 |
commit | 2d919361f68aa22a9759244b8e2ee04f7eefb1cd (patch) | |
tree | 616d5ccae7f5911a52ac524e6f1ec9101e8018f2 /drivers/mmc/host/sdhci-tegra.c | |
parent | b223011aff83d1e0dbdb0bc343b378d9d4572f4d (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.c | 60 |
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; |