sdhci: tegra: Add Tegra sd host init after reset
Pavan Kunapuli [Tue, 15 Nov 2011 15:33:38 +0000 (20:33 +0530)]
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

drivers/mmc/host/sdhci-tegra.c

index 18f036b..e8eeeaa 100644 (file)
 #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;