mmc: sdhci-tegra: add platform code for UHS signaling
Pradeep Goudagunta [Tue, 15 Nov 2011 18:45:18 +0000 (23:45 +0530)]
Tegra SD controller requires clk divisor to be set to 1 for
DDR50 mode.

Bug 899940

Change-Id: Ibc15e5f61b11e2e87b78eade8d004ff2c56b3b74
Reviewed-on: http://git-master/r/64510
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>

Rebase-Id: Rf958d23dedd38a3d84efaf555d5ec0a31678da37

drivers/mmc/host/sdhci-tegra.c

index e91a54c..72ef8e1 100644 (file)
@@ -154,6 +154,43 @@ static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci)
        sdhci_writew(sdhci, ctrl, SDHCI_VENDOR_MISC_CNTRL);
 }
 
+static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
+               unsigned int uhs)
+{
+       u16 clk, ctrl_2;
+       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+       /* Select Bus Speed Mode for host */
+       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+       switch (uhs) {
+       case MMC_TIMING_UHS_SDR12:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+               break;
+       case MMC_TIMING_UHS_SDR25:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+               break;
+       case MMC_TIMING_UHS_SDR50:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+               break;
+       case MMC_TIMING_UHS_SDR104:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+               break;
+       case MMC_TIMING_UHS_DDR50:
+               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+               break;
+       }
+
+       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+       if (uhs == MMC_TIMING_UHS_DDR50) {
+               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+               clk &= ~(0xFF << SDHCI_DIVIDER_SHIFT);
+               clk |= 1 << SDHCI_DIVIDER_SHIFT;
+               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+       }
+       return 0;
+}
+
 static void tegra_sdhci_reset_exit(struct sdhci_host *sdhci, u8 mask)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
@@ -240,6 +277,10 @@ static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int
 
        if (clock == 0)
                goto out;
+       if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_DDR50) {
+               div = 1;
+               goto set_clk;
+       }
 
        if (sdhci->version >= SDHCI_SPEC_300) {
                /* Version 3.00 divisors must be a multiple of 2. */
@@ -268,7 +309,7 @@ static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int
         * - Wait for 5 usec and do a dummy write.
         * - Poll for clk stable and disable PADPIPE_CLK_OVERRIDE.
         */
-
+set_clk:
        /* Enable PADPIPE clk override */
        ctrl = sdhci_readb(sdhci, SDHCI_VENDOR_CLOCK_CNTRL);
        ctrl |= SDHCI_VENDOR_CLOCK_CNTRL_PADPIPE_CLKEN_OVERRIDE;
@@ -407,6 +448,7 @@ static struct sdhci_ops tegra_sdhci_ops = {
        .suspend    = tegra_sdhci_suspend,
        .resume     = tegra_sdhci_resume,
        .platform_reset_exit = tegra_sdhci_reset_exit,
+       .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
 };
 
 static struct sdhci_pltfm_data sdhci_tegra_pdata = {
@@ -568,6 +610,8 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
 
        host->mmc->caps |= MMC_CAP_ERASE;
        host->mmc->caps |= MMC_CAP_DISABLE;
+       /* enable 1/8V DDR capable */
+       host->mmc->caps |= MMC_CAP_1_8V_DDR;
        if (plat->is_8bit)
                host->mmc->caps |= MMC_CAP_8_BIT_DATA;
        host->mmc->caps |= MMC_CAP_SDIO_IRQ;