Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh...
[pandora-kernel.git] / drivers / mmc / core / core.c
index a3a780f..6625c05 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/scatterlist.h>
 #include <linux/log2.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -130,6 +131,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
 
                if (mrq->done)
                        mrq->done(mrq);
+
+               mmc_host_clk_gate(host);
        }
 }
 
@@ -190,6 +193,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
                        mrq->stop->mrq = mrq;
                }
        }
+       mmc_host_clk_ungate(host);
        host->ops->request(host, mrq);
 }
 
@@ -295,8 +299,9 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
                unsigned int timeout_us, limit_us;
 
                timeout_us = data->timeout_ns / 1000;
-               timeout_us += data->timeout_clks * 1000 /
-                       (card->host->ios.clock / 1000);
+               if (mmc_host_clk_rate(card->host))
+                       timeout_us += data->timeout_clks * 1000 /
+                               (mmc_host_clk_rate(card->host) / 1000);
 
                if (data->flags & MMC_DATA_WRITE)
                        /*
@@ -614,6 +619,8 @@ static inline void mmc_set_ios(struct mmc_host *host)
                 ios->power_mode, ios->chip_select, ios->vdd,
                 ios->bus_width, ios->timing);
 
+       if (ios->clock > 0)
+               mmc_set_ungated(host);
        host->ops->set_ios(host, ios);
 }
 
@@ -641,6 +648,61 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
        mmc_set_ios(host);
 }
 
+#ifdef CONFIG_MMC_CLKGATE
+/*
+ * This gates the clock by setting it to 0 Hz.
+ */
+void mmc_gate_clock(struct mmc_host *host)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->clk_lock, flags);
+       host->clk_old = host->ios.clock;
+       host->ios.clock = 0;
+       host->clk_gated = true;
+       spin_unlock_irqrestore(&host->clk_lock, flags);
+       mmc_set_ios(host);
+}
+
+/*
+ * This restores the clock from gating by using the cached
+ * clock value.
+ */
+void mmc_ungate_clock(struct mmc_host *host)
+{
+       /*
+        * We should previously have gated the clock, so the clock shall
+        * be 0 here! The clock may however be 0 during initialization,
+        * when some request operations are performed before setting
+        * the frequency. When ungate is requested in that situation
+        * we just ignore the call.
+        */
+       if (host->clk_old) {
+               BUG_ON(host->ios.clock);
+               /* This call will also set host->clk_gated to false */
+               mmc_set_clock(host, host->clk_old);
+       }
+}
+
+void mmc_set_ungated(struct mmc_host *host)
+{
+       unsigned long flags;
+
+       /*
+        * We've been given a new frequency while the clock is gated,
+        * so make sure we regard this as ungating it.
+        */
+       spin_lock_irqsave(&host->clk_lock, flags);
+       host->clk_gated = false;
+       spin_unlock_irqrestore(&host->clk_lock, flags);
+}
+
+#else
+void mmc_set_ungated(struct mmc_host *host)
+{
+}
+#endif
+
 /*
  * Change the bus mode (open drain/push-pull) of a host.
  */
@@ -1424,35 +1486,57 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 }
 EXPORT_SYMBOL(mmc_set_blocklen);
 
+static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
+{
+       host->f_init = freq;
+
+#ifdef CONFIG_MMC_DEBUG
+       pr_info("%s: %s: trying to init card at %u Hz\n",
+               mmc_hostname(host), __func__, host->f_init);
+#endif
+       mmc_power_up(host);
+       sdio_reset(host);
+       mmc_go_idle(host);
+
+       mmc_send_if_cond(host, host->ocr_avail);
+
+       /* Order's important: probe SDIO, then SD, then MMC */
+       if (!mmc_attach_sdio(host))
+               return 0;
+       if (!mmc_attach_sd(host))
+               return 0;
+       if (!mmc_attach_mmc(host))
+               return 0;
+
+       mmc_power_off(host);
+       return -EIO;
+}
+
 void mmc_rescan(struct work_struct *work)
 {
+       static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
        struct mmc_host *host =
                container_of(work, struct mmc_host, detect.work);
-       u32 ocr;
-       int err;
-       unsigned long flags;
        int i;
-       const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
-
-       spin_lock_irqsave(&host->lock, flags);
 
-       if (host->rescan_disable) {
-               spin_unlock_irqrestore(&host->lock, flags);
+       if (host->rescan_disable)
                return;
-       }
-
-       spin_unlock_irqrestore(&host->lock, flags);
-
 
        mmc_bus_get(host);
 
-       /* if there is a card registered, check whether it is still present */
-       if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)
+       /*
+        * if there is a _removable_ card registered, check whether it is
+        * still present
+        */
+       if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
+           && mmc_card_is_removable(host))
                host->bus_ops->detect(host);
 
+       /*
+        * Let mmc_bus_put() free the bus/bus_ops if we've found that
+        * the card is no longer present.
+        */
        mmc_bus_put(host);
-
-
        mmc_bus_get(host);
 
        /* if there still is a card present, stop here */
@@ -1461,8 +1545,6 @@ void mmc_rescan(struct work_struct *work)
                goto out;
        }
 
-       /* detect a newly inserted card */
-
        /*
         * Only we can add a new handler, so it's safe to
         * release the lock here.
@@ -1472,72 +1554,16 @@ void mmc_rescan(struct work_struct *work)
        if (host->ops->get_cd && host->ops->get_cd(host) == 0)
                goto out;
 
+       mmc_claim_host(host);
        for (i = 0; i < ARRAY_SIZE(freqs); i++) {
-               mmc_claim_host(host);
-
-               if (freqs[i] >= host->f_min)
-                       host->f_init = freqs[i];
-               else if (!i || freqs[i-1] > host->f_min)
-                       host->f_init = host->f_min;
-               else {
-                       mmc_release_host(host);
-                       goto out;
-               }
-#ifdef CONFIG_MMC_DEBUG
-               pr_info("%s: %s: trying to init card at %u Hz\n",
-                       mmc_hostname(host), __func__, host->f_init);
-#endif
-               mmc_power_up(host);
-               sdio_reset(host);
-               mmc_go_idle(host);
-
-               mmc_send_if_cond(host, host->ocr_avail);
-
-               /*
-                * First we search for SDIO...
-                */
-               err = mmc_send_io_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_sdio(host, ocr)) {
-                               mmc_claim_host(host);
-                               /*
-                                * Try SDMEM (but not MMC) even if SDIO
-                                * is broken.
-                                */
-                               if (mmc_send_app_op_cond(host, 0, &ocr))
-                                       goto out_fail;
-
-                               if (mmc_attach_sd(host, ocr))
-                                       mmc_power_off(host);
-                       }
-                       goto out;
-               }
-
-               /*
-                * ...then normal SD...
-                */
-               err = mmc_send_app_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_sd(host, ocr))
-                               mmc_power_off(host);
-                       goto out;
-               }
-
-               /*
-                * ...and finally MMC.
-                */
-               err = mmc_send_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_mmc(host, ocr))
-                               mmc_power_off(host);
-                       goto out;
-               }
-
-out_fail:
-               mmc_release_host(host);
-               mmc_power_off(host);
+               if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
+                       break;
+               if (freqs[i] < host->f_min)
+                       break;
        }
-out:
+       mmc_release_host(host);
+
+ out:
        if (host->caps & MMC_CAP_NEEDS_POLL)
                mmc_schedule_delayed_work(&host->detect, HZ);
 }
@@ -1721,6 +1747,18 @@ int mmc_resume_host(struct mmc_host *host)
                if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
                        mmc_power_up(host);
                        mmc_select_voltage(host, host->ocr);
+                       /*
+                        * Tell runtime PM core we just powered up the card,
+                        * since it still believes the card is powered off.
+                        * Note that currently runtime PM is only enabled
+                        * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
+                        */
+                       if (mmc_card_sdio(host->card) &&
+                           (host->caps & MMC_CAP_POWER_OFF_CARD)) {
+                               pm_runtime_disable(&host->card->dev);
+                               pm_runtime_set_active(&host->card->dev);
+                               pm_runtime_enable(&host->card->dev);
+                       }
                }
                BUG_ON(!host->bus_ops->resume);
                err = host->bus_ops->resume(host);