Merge tag 'mmc-updates-for-3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-drm-fsl-dcu.git] / drivers / mmc / host / mmci.c
index 9e8a482310d8fce94e418afad22e3b25daab6d12..f32057972dd77fe9a7487f74aa2ab727c2126db6 100644 (file)
@@ -62,6 +62,7 @@ static unsigned int fmax = 515633;
  * @signal_direction: input/out direction of bus signals can be indicated
  * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
  * @busy_detect: true if busy detection on dat0 is supported
+ * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
  */
 struct variant_data {
        unsigned int            clkreg;
@@ -76,6 +77,7 @@ struct variant_data {
        bool                    signal_direction;
        bool                    pwrreg_clkgate;
        bool                    busy_detect;
+       bool                    pwrreg_nopower;
 };
 
 static struct variant_data variant_arm = {
@@ -109,6 +111,7 @@ static struct variant_data variant_u300 = {
        .pwrreg_powerup         = MCI_PWR_ON,
        .signal_direction       = true,
        .pwrreg_clkgate         = true,
+       .pwrreg_nopower         = true,
 };
 
 static struct variant_data variant_nomadik = {
@@ -121,6 +124,7 @@ static struct variant_data variant_nomadik = {
        .pwrreg_powerup         = MCI_PWR_ON,
        .signal_direction       = true,
        .pwrreg_clkgate         = true,
+       .pwrreg_nopower         = true,
 };
 
 static struct variant_data variant_ux500 = {
@@ -135,6 +139,7 @@ static struct variant_data variant_ux500 = {
        .signal_direction       = true,
        .pwrreg_clkgate         = true,
        .busy_detect            = true,
+       .pwrreg_nopower         = true,
 };
 
 static struct variant_data variant_ux500v2 = {
@@ -150,6 +155,7 @@ static struct variant_data variant_ux500v2 = {
        .signal_direction       = true,
        .pwrreg_clkgate         = true,
        .busy_detect            = true,
+       .pwrreg_nopower         = true,
 };
 
 static int mmci_card_busy(struct mmc_host *mmc)
@@ -189,6 +195,21 @@ static int mmci_validate_data(struct mmci_host *host,
        return 0;
 }
 
+static void mmci_reg_delay(struct mmci_host *host)
+{
+       /*
+        * According to the spec, at least three feedback clock cycles
+        * of max 52 MHz must pass between two writes to the MMCICLOCK reg.
+        * Three MCLK clock cycles must pass between two MMCIPOWER reg writes.
+        * Worst delay time during card init is at 100 kHz => 30 us.
+        * Worst delay time when up and running is at 25 MHz => 120 ns.
+        */
+       if (host->cclk < 25000000)
+               udelay(30);
+       else
+               ndelay(120);
+}
+
 /*
  * This must be called with host->lock held
  */
@@ -1264,6 +1285,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        mmci_set_clkreg(host, ios->clock);
        mmci_write_pwrreg(host, pwr);
+       mmci_reg_delay(host);
 
        spin_unlock_irqrestore(&host->lock, flags);
 
@@ -1510,23 +1532,6 @@ static int mmci_probe(struct amba_device *dev,
                mmc->f_max = min(host->mclk, fmax);
        dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
 
-       host->pinctrl = devm_pinctrl_get(&dev->dev);
-       if (IS_ERR(host->pinctrl)) {
-               ret = PTR_ERR(host->pinctrl);
-               goto clk_disable;
-       }
-
-       host->pins_default = pinctrl_lookup_state(host->pinctrl,
-                       PINCTRL_STATE_DEFAULT);
-
-       /* enable pins to be muxed in and configured */
-       if (!IS_ERR(host->pins_default)) {
-               ret = pinctrl_select_state(host->pinctrl, host->pins_default);
-               if (ret)
-                       dev_warn(&dev->dev, "could not set default pins\n");
-       } else
-               dev_warn(&dev->dev, "could not get default pinstate\n");
-
        /* Get regulators and the supported OCR mask */
        mmc_regulator_get_supply(mmc);
        if (!mmc->ocr_avail)
@@ -1751,6 +1756,41 @@ static int mmci_resume(struct device *dev)
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
+static void mmci_save(struct mmci_host *host)
+{
+       unsigned long flags;
+
+       if (host->variant->pwrreg_nopower) {
+               spin_lock_irqsave(&host->lock, flags);
+
+               writel(0, host->base + MMCIMASK0);
+               writel(0, host->base + MMCIDATACTRL);
+               writel(0, host->base + MMCIPOWER);
+               writel(0, host->base + MMCICLOCK);
+               mmci_reg_delay(host);
+
+               spin_unlock_irqrestore(&host->lock, flags);
+       }
+
+}
+
+static void mmci_restore(struct mmci_host *host)
+{
+       unsigned long flags;
+
+       if (host->variant->pwrreg_nopower) {
+               spin_lock_irqsave(&host->lock, flags);
+
+               writel(host->clk_reg, host->base + MMCICLOCK);
+               writel(host->datactrl_reg, host->base + MMCIDATACTRL);
+               writel(host->pwr_reg, host->base + MMCIPOWER);
+               writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+               mmci_reg_delay(host);
+
+               spin_unlock_irqrestore(&host->lock, flags);
+       }
+}
+
 static int mmci_runtime_suspend(struct device *dev)
 {
        struct amba_device *adev = to_amba_device(dev);
@@ -1758,6 +1798,8 @@ static int mmci_runtime_suspend(struct device *dev)
 
        if (mmc) {
                struct mmci_host *host = mmc_priv(mmc);
+               pinctrl_pm_select_sleep_state(dev);
+               mmci_save(host);
                clk_disable_unprepare(host->clk);
        }
 
@@ -1772,6 +1814,8 @@ static int mmci_runtime_resume(struct device *dev)
        if (mmc) {
                struct mmci_host *host = mmc_priv(mmc);
                clk_prepare_enable(host->clk);
+               mmci_restore(host);
+               pinctrl_pm_select_default_state(dev);
        }
 
        return 0;