mmc: sdio: Add high speed support to sdio_reset_comm()
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / core / core.c
index 5ae89e48fd85b575cf743363b3a298b49872b7db..9c9bd3c906375c59669dbef7f99616ffd316bab1 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/random.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/wakelock.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -56,6 +57,7 @@
 #define MMC_BKOPS_MAX_TIMEOUT  (4 * 60 * 1000) /* max time to wait in ms */
 
 static struct workqueue_struct *workqueue;
+static struct wake_lock mmc_delayed_work_wake_lock;
 static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 
 /*
@@ -72,6 +74,7 @@ module_param(use_spi_crc, bool, 0);
 static int mmc_schedule_delayed_work(struct delayed_work *work,
                                     unsigned long delay)
 {
+       wake_lock(&mmc_delayed_work_wake_lock);
        return queue_delayed_work(workqueue, work, delay);
 }
 
@@ -2566,6 +2569,7 @@ void mmc_rescan(struct work_struct *work)
        struct mmc_host *host =
                container_of(work, struct mmc_host, detect.work);
        int i;
+       bool extend_wakelock = false;
 
        if (host->trigger_card_event && host->ops->card_event) {
                host->ops->card_event(host);
@@ -2592,6 +2596,12 @@ void mmc_rescan(struct work_struct *work)
 
        host->detect_change = 0;
 
+       /* If the card was removed the bus will be marked
+        * as dead - extend the wakelock so userspace
+        * can respond */
+       if (host->bus_dead)
+               extend_wakelock = 1;
+
        /*
         * Let mmc_bus_put() free the bus/bus_ops if we've found that
         * the card is no longer present.
@@ -2621,14 +2631,20 @@ void mmc_rescan(struct work_struct *work)
 
        mmc_claim_host(host);
        for (i = 0; i < ARRAY_SIZE(freqs); i++) {
-               if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
+               if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
+                       extend_wakelock = true;
                        break;
+               }
                if (freqs[i] <= host->f_min)
                        break;
        }
        mmc_release_host(host);
 
  out:
+       if (extend_wakelock)
+               wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2);
+       else
+               wake_unlock(&mmc_delayed_work_wake_lock);
        if (host->caps & MMC_CAP_NEEDS_POLL)
                mmc_schedule_delayed_work(&host->detect, HZ);
 }
@@ -2832,6 +2848,22 @@ void mmc_init_context_info(struct mmc_host *host)
        init_waitqueue_head(&host->context_info.wait);
 }
 
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
+void mmc_set_embedded_sdio_data(struct mmc_host *host,
+                               struct sdio_cis *cis,
+                               struct sdio_cccr *cccr,
+                               struct sdio_embedded_func *funcs,
+                               int num_funcs)
+{
+       host->embedded_sdio_data.cis = cis;
+       host->embedded_sdio_data.cccr = cccr;
+       host->embedded_sdio_data.funcs = funcs;
+       host->embedded_sdio_data.num_funcs = num_funcs;
+}
+
+EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
+#endif
+
 static int __init mmc_init(void)
 {
        int ret;
@@ -2840,6 +2872,9 @@ static int __init mmc_init(void)
        if (!workqueue)
                return -ENOMEM;
 
+       wake_lock_init(&mmc_delayed_work_wake_lock, WAKE_LOCK_SUSPEND,
+                      "mmc_delayed_work");
+
        ret = mmc_register_bus();
        if (ret)
                goto destroy_workqueue;
@@ -2860,6 +2895,7 @@ unregister_bus:
        mmc_unregister_bus();
 destroy_workqueue:
        destroy_workqueue(workqueue);
+       wake_lock_destroy(&mmc_delayed_work_wake_lock);
 
        return ret;
 }
@@ -2870,6 +2906,7 @@ static void __exit mmc_exit(void)
        mmc_unregister_host_class();
        mmc_unregister_bus();
        destroy_workqueue(workqueue);
+       wake_lock_destroy(&mmc_delayed_work_wake_lock);
 }
 
 subsys_initcall(mmc_init);