Merge remote-tracking branch 'aosp/android-3.0' into develop-3.0-jb
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / core / core.c
old mode 100644 (file)
new mode 100755 (executable)
index 08d08e4..3f3615c
@@ -22,6 +22,7 @@
 #include <linux/scatterlist.h>
 #include <linux/log2.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 #include <linux/wakelock.h>
 
 #include <linux/mmc/card.h>
@@ -39,7 +40,6 @@
 #include "sdio_ops.h"
 
 static struct workqueue_struct *workqueue;
-static struct wake_lock mmc_delayed_work_wake_lock;
 
 /*
  * Enabling software CRCs on the data blocks can be a significant (30%)
@@ -49,13 +49,29 @@ static struct wake_lock mmc_delayed_work_wake_lock;
 int use_spi_crc = 1;
 module_param(use_spi_crc, bool, 0);
 
+/*
+ * We normally treat cards as removed during suspend if they are not
+ * known to be on a non-removable bus, to avoid the risk of writing
+ * back data to a different card after resume.  Allow this to be
+ * overridden if necessary.
+ */
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+int mmc_assume_removable;
+#else
+int mmc_assume_removable = 1;
+#endif
+EXPORT_SYMBOL(mmc_assume_removable);
+module_param_named(removable, mmc_assume_removable, bool, 0644);
+MODULE_PARM_DESC(
+       removable,
+       "MMC/SD cards are removable and may be removed during suspend");
+
 /*
  * Internal function. Schedule delayed work in the MMC work queue.
  */
 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);
 }
 
@@ -116,6 +132,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
 
                if (mrq->done)
                        mrq->done(mrq);
+
+               mmc_host_clk_release(host);
        }
 }
 
@@ -150,8 +168,6 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 
        WARN_ON(!host->claimed);
 
-       led_trigger_event(host->led, LED_FULL);
-
        mrq->cmd->error = 0;
        mrq->cmd->mrq = mrq;
        if (mrq->data) {
@@ -176,6 +192,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
                        mrq->stop->mrq = mrq;
                }
        }
+       mmc_host_clk_hold(host);
+       led_trigger_event(host->led, LED_FULL);
        host->ops->request(host, mrq);
 }
 
@@ -195,6 +213,11 @@ static void mmc_wait_done(struct mmc_request *mrq)
  */
 void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 {
+#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD)
+       unsigned long datasize, waittime = 0xFFFF;
+       u32 multi, unit;
+#endif
+
        DECLARE_COMPLETION_ONSTACK(complete);
 
        mrq->done_data = &complete;
@@ -202,7 +225,51 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 
        mmc_start_request(host, mrq);
 
+#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD)
+    if( strncmp( mmc_hostname(host) ,"mmc0" , strlen("mmc0")) ) 
+    {
+        multi = (mrq->cmd->retries>0)?mrq->cmd->retries:1;
+        waittime = wait_for_completion_timeout(&complete,HZ*7*multi); //sdio; for cmd dead. Modifyed by xbw at 2011-06-02
+    }
+    else
+    {   
+        //calculate the timeout value for SDMMC; added by xbw at 2011-09-27
+        if(mrq->data)
+        {
+            unit = 2*(1<<20);// unit=2MB
+            datasize = mrq->data->blksz*mrq->data->blocks;
+            multi = datasize/unit;
+            multi += (datasize%unit)?1:0;
+            multi = (multi>0) ? multi : 1;
+            multi += (mrq->cmd->retries>0)?1:0;
+            waittime = wait_for_completion_timeout(&complete,HZ*7*multi); //It should be longer than bottom driver's time,due to the sum of two cmd time.
+                                                                          //modifyed by xbw at 2011-10-08
+                                                                          //
+                                                                          //example:
+                                                                          //rk29_sdmmc_request_end..2336...   CMD12 wait busy timeout!!!!! ====xbw=[sd_mmc]====
+                                                                          //mmc_wait_for_req..236.. !!!!! wait for CMD25 timeout ===xbw[mmc0]===
+        }
+        else
+        {
+            multi = (mrq->cmd->retries>0)?mrq->cmd->retries:1;
+            waittime = wait_for_completion_timeout(&complete,HZ*7*multi);
+        }
+    }
+    
+    if(waittime <= 1)
+    {
+        host->doneflag = 0;
+        mrq->cmd->error = -EIO;
+
+        if(0 == mrq->cmd->retries)
+        {
+            printk(KERN_WARNING "%s..%d.. !!!!! wait for CMD%d timeout [%s]\n",\
+                __FUNCTION__, __LINE__, mrq->cmd->opcode, mmc_hostname(host));
+        }
+    }
+#else
        wait_for_completion(&complete);
+#endif
 }
 
 EXPORT_SYMBOL(mmc_wait_for_req);
@@ -219,12 +286,10 @@ EXPORT_SYMBOL(mmc_wait_for_req);
  */
 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
 {
-       struct mmc_request mrq;
+       struct mmc_request mrq = {0};
 
        WARN_ON(!host->claimed);
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-
        memset(cmd->resp, 0, sizeof(cmd->resp));
        cmd->retries = retries;
 
@@ -281,8 +346,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)
                        /*
@@ -509,7 +575,14 @@ int mmc_try_claim_host(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_try_claim_host);
 
-static void mmc_do_release_host(struct mmc_host *host)
+/**
+ *     mmc_do_release_host - release a claimed host
+ *     @host: mmc host to release
+ *
+ *     If you successfully claimed a host, this function will
+ *     release it again.
+ */
+void mmc_do_release_host(struct mmc_host *host)
 {
        unsigned long flags;
 
@@ -524,6 +597,7 @@ static void mmc_do_release_host(struct mmc_host *host)
                wake_up(&host->wq);
        }
 }
+EXPORT_SYMBOL(mmc_do_release_host);
 
 void mmc_host_deeper_disable(struct work_struct *work)
 {
@@ -600,6 +674,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);
 }
 
@@ -608,15 +684,17 @@ static inline void mmc_set_ios(struct mmc_host *host)
  */
 void mmc_set_chip_select(struct mmc_host *host, int mode)
 {
+       mmc_host_clk_hold(host);
        host->ios.chip_select = mode;
        mmc_set_ios(host);
+       mmc_host_clk_release(host);
 }
 
 /*
  * Sets the host clock to the highest possible frequency that
  * is below "hz".
  */
-void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
 {
        WARN_ON(hz < host->f_min);
 
@@ -627,13 +705,77 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
        mmc_set_ios(host);
 }
 
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+{
+       mmc_host_clk_hold(host);
+       __mmc_set_clock(host, hz);
+       mmc_host_clk_release(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.
  */
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
 {
+       mmc_host_clk_hold(host);
        host->ios.bus_mode = mode;
        mmc_set_ios(host);
+       mmc_host_clk_release(host);
 }
 
 /*
@@ -641,8 +783,10 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
  */
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
 {
+       mmc_host_clk_hold(host);
        host->ios.bus_width = width;
        mmc_set_ios(host);
+       mmc_host_clk_release(host);
 }
 
 /**
@@ -758,8 +902,9 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
 
 /**
  * mmc_regulator_set_ocr - set regulator to match host->ios voltage
- * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
+ * @mmc: the host to regulate
  * @supply: regulator to use
+ * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
  *
  * Returns zero on success, else negative errno.
  *
@@ -767,15 +912,12 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
  * a particular supply voltage.  This would normally be called from the
  * set_ios() method.
  */
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+                       struct regulator *supply,
+                       unsigned short vdd_bit)
 {
        int                     result = 0;
        int                     min_uV, max_uV;
-       int                     enabled;
-
-       enabled = regulator_is_enabled(supply);
-       if (enabled < 0)
-               return enabled;
 
        if (vdd_bit) {
                int             tmp;
@@ -806,17 +948,25 @@ int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
                else
                        result = 0;
 
-               if (result == 0 && !enabled)
+               if (result == 0 && !mmc->regulator_enabled) {
                        result = regulator_enable(supply);
-       } else if (enabled) {
+                       if (!result)
+                               mmc->regulator_enabled = true;
+               }
+       } else if (mmc->regulator_enabled) {
                result = regulator_disable(supply);
+               if (result == 0)
+                       mmc->regulator_enabled = false;
        }
 
+       if (result)
+               dev_err(mmc_dev(mmc),
+                       "could not set regulator OCR (%d)\n", result);
        return result;
 }
 EXPORT_SYMBOL(mmc_regulator_set_ocr);
 
-#endif
+#endif /* CONFIG_REGULATOR */
 
 /*
  * Mask off any voltages we don't support and select
@@ -834,8 +984,10 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
 
                ocr &= 3 << bit;
 
+               mmc_host_clk_hold(host);
                host->ios.vdd = bit;
                mmc_set_ios(host);
+               mmc_host_clk_release(host);
        } else {
                pr_warning("%s: host doesn't support card's voltages\n",
                                mmc_hostname(host));
@@ -845,13 +997,58 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
        return ocr;
 }
 
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
+{
+       struct mmc_command cmd = {0};
+       int err = 0;
+
+       BUG_ON(!host);
+
+       /*
+        * Send CMD11 only if the request is to switch the card to
+        * 1.8V signalling.
+        */
+       if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
+               cmd.opcode = SD_SWITCH_VOLTAGE;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+               err = mmc_wait_for_cmd(host, &cmd, 0);
+               if (err)
+                       return err;
+
+               if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
+                       return -EIO;
+       }
+
+       host->ios.signal_voltage = signal_voltage;
+
+       if (host->ops->start_signal_voltage_switch)
+               err = host->ops->start_signal_voltage_switch(host, &host->ios);
+
+       return err;
+}
+
 /*
  * Select timing parameters for host.
  */
 void mmc_set_timing(struct mmc_host *host, unsigned int timing)
 {
+       mmc_host_clk_hold(host);
        host->ios.timing = timing;
        mmc_set_ios(host);
+       mmc_host_clk_release(host);
+}
+
+/*
+ * Select appropriate driver type for host.
+ */
+void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
+{
+       mmc_host_clk_hold(host);
+       host->ios.drv_type = drv_type;
+       mmc_set_ios(host);
+       mmc_host_clk_release(host);
 }
 
 /*
@@ -869,6 +1066,8 @@ static void mmc_power_up(struct mmc_host *host)
 {
        int bit;
 
+       mmc_host_clk_hold(host);
+
        /* If ocr is set, we use it */
        if (host->ocr)
                bit = ffs(host->ocr) - 1;
@@ -893,13 +1092,12 @@ static void mmc_power_up(struct mmc_host *host)
         * to reach the minimum voltage.
         */
        mmc_delay(10);
-
-       if (host->f_min > 400000) {
-               pr_warning("%s: Minimum clock frequency too high for "
-                               "identification mode\n", mmc_hostname(host));
-               host->ios.clock = host->f_min;
-       } else
-               host->ios.clock = 400000;
+       
+#if defined(CONFIG_SDMMC_RK29) || !defined(CONFIG_SDMMC_RK29_OLD)   //Modifyed by xbw at 2011-11-17
+    host->ios.clock = host->f_min;
+#else
+       host->ios.clock = host->f_init;
+#endif
 
        host->ios.power_mode = MMC_POWER_ON;
        mmc_set_ios(host);
@@ -909,12 +1107,23 @@ static void mmc_power_up(struct mmc_host *host)
         * time required to reach a stable voltage.
         */
        mmc_delay(10);
+
+       mmc_host_clk_release(host);
 }
 
-static void mmc_power_off(struct mmc_host *host)
+void mmc_power_off(struct mmc_host *host)
 {
+       mmc_host_clk_hold(host);
+
        host->ios.clock = 0;
        host->ios.vdd = 0;
+
+       /*
+        * Reset ocr mask to be the highest possible voltage supported for
+        * this mmc host. This value will be used at next power up.
+        */
+       host->ocr = 1 << (fls(host->ocr_avail) - 1);
+
        if (!mmc_host_is_spi(host)) {
                host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
                host->ios.chip_select = MMC_CS_DONTCARE;
@@ -923,6 +1132,8 @@ static void mmc_power_off(struct mmc_host *host)
        host->ios.bus_width = MMC_BUS_WIDTH_1;
        host->ios.timing = MMC_TIMING_LEGACY;
        mmc_set_ios(host);
+
+       mmc_host_clk_release(host);
 }
 
 /*
@@ -964,6 +1175,36 @@ static inline void mmc_bus_put(struct mmc_host *host)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+int mmc_resume_bus(struct mmc_host *host)
+{
+       unsigned long flags;
+
+       if (!mmc_bus_needs_resume(host))
+               return -EINVAL;
+
+       printk("%s: Starting deferred resume\n", mmc_hostname(host));
+       spin_lock_irqsave(&host->lock, flags);
+       host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME;
+       host->rescan_disable = 0;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       mmc_bus_get(host);
+       if (host->bus_ops && !host->bus_dead) {
+               mmc_power_up(host);
+               BUG_ON(!host->bus_ops->resume);
+               host->bus_ops->resume(host);
+       }
+
+       if (host->bus_ops->detect && !host->bus_dead)
+               host->bus_ops->detect(host);
+
+       mmc_bus_put(host);
+       printk("%s: Deferred resume completed\n", mmc_hostname(host));
+       return 0;
+}
+
+EXPORT_SYMBOL(mmc_resume_bus);
+
 /*
  * Assign a mmc bus handler to a host. Only one bus handler may control a
  * host at any given time.
@@ -990,8 +1231,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
 }
 
 /*
- * Remove the current bus handler from a host. Assumes that there are
- * no interesting cards left, so the bus is powered down.
+ * Remove the current bus handler from a host.
  */
 void mmc_detach_bus(struct mmc_host *host)
 {
@@ -1008,8 +1248,6 @@ void mmc_detach_bus(struct mmc_host *host)
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       mmc_power_off(host);
-
        mmc_bus_put(host);
 }
 
@@ -1032,99 +1270,598 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
+       wake_lock(&host->detect_wake_lock);
        mmc_schedule_delayed_work(&host->detect, delay);
 }
 
 EXPORT_SYMBOL(mmc_detect_change);
 
+void mmc_init_erase(struct mmc_card *card)
+{
+       unsigned int sz;
+
+       if (is_power_of_2(card->erase_size))
+               card->erase_shift = ffs(card->erase_size) - 1;
+       else
+               card->erase_shift = 0;
 
-void mmc_rescan(struct work_struct *work)
+       /*
+        * It is possible to erase an arbitrarily large area of an SD or MMC
+        * card.  That is not desirable because it can take a long time
+        * (minutes) potentially delaying more important I/O, and also the
+        * timeout calculations become increasingly hugely over-estimated.
+        * Consequently, 'pref_erase' is defined as a guide to limit erases
+        * to that size and alignment.
+        *
+        * For SD cards that define Allocation Unit size, limit erases to one
+        * Allocation Unit at a time.  For MMC cards that define High Capacity
+        * Erase Size, whether it is switched on or not, limit to that size.
+        * Otherwise just have a stab at a good value.  For modern cards it
+        * will end up being 4MiB.  Note that if the value is too small, it
+        * can end up taking longer to erase.
+        */
+       if (mmc_card_sd(card) && card->ssr.au) {
+               card->pref_erase = card->ssr.au;
+               card->erase_shift = ffs(card->ssr.au) - 1;
+       } else if (card->ext_csd.hc_erase_size) {
+               card->pref_erase = card->ext_csd.hc_erase_size;
+       } else {
+               sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
+               if (sz < 128)
+                       card->pref_erase = 512 * 1024 / 512;
+               else if (sz < 512)
+                       card->pref_erase = 1024 * 1024 / 512;
+               else if (sz < 1024)
+                       card->pref_erase = 2 * 1024 * 1024 / 512;
+               else
+                       card->pref_erase = 4 * 1024 * 1024 / 512;
+               if (card->pref_erase < card->erase_size)
+                       card->pref_erase = card->erase_size;
+               else {
+                       sz = card->pref_erase % card->erase_size;
+                       if (sz)
+                               card->pref_erase += card->erase_size - sz;
+               }
+       }
+}
+
+static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
+                                         unsigned int arg, unsigned int qty)
 {
-       struct mmc_host *host =
-               container_of(work, struct mmc_host, detect.work);
-       u32 ocr;
-       int err;
-       int extend_wakelock = 0;
+       unsigned int erase_timeout;
 
-       mmc_bus_get(host);
+       if (card->ext_csd.erase_group_def & 1) {
+               /* High Capacity Erase Group Size uses HC timeouts */
+               if (arg == MMC_TRIM_ARG)
+                       erase_timeout = card->ext_csd.trim_timeout;
+               else
+                       erase_timeout = card->ext_csd.hc_erase_timeout;
+       } else {
+               /* CSD Erase Group Size uses write timeout */
+               unsigned int mult = (10 << card->csd.r2w_factor);
+               unsigned int timeout_clks = card->csd.tacc_clks * mult;
+               unsigned int timeout_us;
+
+               /* Avoid overflow: e.g. tacc_ns=80000000 mult=1280 */
+               if (card->csd.tacc_ns < 1000000)
+                       timeout_us = (card->csd.tacc_ns * mult) / 1000;
+               else
+                       timeout_us = (card->csd.tacc_ns / 1000) * mult;
 
-       /* if there is a card registered, check whether it is still present */
-       if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)
-               host->bus_ops->detect(host);
+               /*
+                * ios.clock is only a target.  The real clock rate might be
+                * less but not that much less, so fudge it by multiplying by 2.
+                */
+               timeout_clks <<= 1;
+               timeout_us += (timeout_clks * 1000) /
+                             (mmc_host_clk_rate(card->host) / 1000);
 
-       mmc_bus_put(host);
+               erase_timeout = timeout_us / 1000;
 
+               /*
+                * Theoretically, the calculation could underflow so round up
+                * to 1ms in that case.
+                */
+               if (!erase_timeout)
+                       erase_timeout = 1;
+       }
 
-       mmc_bus_get(host);
+       /* Multiplier for secure operations */
+       if (arg & MMC_SECURE_ARGS) {
+               if (arg == MMC_SECURE_ERASE_ARG)
+                       erase_timeout *= card->ext_csd.sec_erase_mult;
+               else
+                       erase_timeout *= card->ext_csd.sec_trim_mult;
+       }
 
-       /* if there still is a card present, stop here */
-       if (host->bus_ops != NULL) {
-               mmc_bus_put(host);
-               goto out;
+       erase_timeout *= qty;
+
+       /*
+        * Ensure at least a 1 second timeout for SPI as per
+        * 'mmc_set_data_timeout()'
+        */
+       if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
+               erase_timeout = 1000;
+
+       return erase_timeout;
+}
+
+static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
+                                        unsigned int arg,
+                                        unsigned int qty)
+{
+       unsigned int erase_timeout;
+
+       if (card->ssr.erase_timeout) {
+               /* Erase timeout specified in SD Status Register (SSR) */
+               erase_timeout = card->ssr.erase_timeout * qty +
+                               card->ssr.erase_offset;
+       } else {
+               /*
+                * Erase timeout not specified in SD Status Register (SSR) so
+                * use 250ms per write block.
+                */
+               erase_timeout = 250 * qty;
        }
 
-       /* detect a newly inserted card */
+       /* Must not be less than 1 second */
+       if (erase_timeout < 1000)
+               erase_timeout = 1000;
+
+       return erase_timeout;
+}
+
+static unsigned int mmc_erase_timeout(struct mmc_card *card,
+                                     unsigned int arg,
+                                     unsigned int qty)
+{
+       if (mmc_card_sd(card))
+               return mmc_sd_erase_timeout(card, arg, qty);
+       else
+               return mmc_mmc_erase_timeout(card, arg, qty);
+}
+
+static int mmc_do_erase(struct mmc_card *card, unsigned int from,
+                       unsigned int to, unsigned int arg)
+{
+       struct mmc_command cmd = {0};
+       unsigned int qty = 0;
+       int err;
 
        /*
-        * Only we can add a new handler, so it's safe to
-        * release the lock here.
+        * qty is used to calculate the erase timeout which depends on how many
+        * erase groups (or allocation units in SD terminology) are affected.
+        * We count erasing part of an erase group as one erase group.
+        * For SD, the allocation units are always a power of 2.  For MMC, the
+        * erase group size is almost certainly also power of 2, but it does not
+        * seem to insist on that in the JEDEC standard, so we fall back to
+        * division in that case.  SD may not specify an allocation unit size,
+        * in which case the timeout is based on the number of write blocks.
+        *
+        * Note that the timeout for secure trim 2 will only be correct if the
+        * number of erase groups specified is the same as the total of all
+        * preceding secure trim 1 commands.  Since the power may have been
+        * lost since the secure trim 1 commands occurred, it is generally
+        * impossible to calculate the secure trim 2 timeout correctly.
         */
-       mmc_bus_put(host);
+       if (card->erase_shift)
+               qty += ((to >> card->erase_shift) -
+                       (from >> card->erase_shift)) + 1;
+       else if (mmc_card_sd(card))
+               qty += to - from + 1;
+       else
+               qty += ((to / card->erase_size) -
+                       (from / card->erase_size)) + 1;
 
-       if (host->ops->get_cd && host->ops->get_cd(host) == 0)
+       if (!mmc_card_blockaddr(card)) {
+               from <<= 9;
+               to <<= 9;
+       }
+
+       if (mmc_card_sd(card))
+               cmd.opcode = SD_ERASE_WR_BLK_START;
+       else
+               cmd.opcode = MMC_ERASE_GROUP_START;
+       cmd.arg = from;
+       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+       err = mmc_wait_for_cmd(card->host, &cmd, 0);
+       if (err) {
+               printk(KERN_ERR "mmc_erase: group start error %d, "
+                      "status %#x\n", err, cmd.resp[0]);
+               err = -EINVAL;
                goto out;
+       }
 
-       mmc_claim_host(host);
+       memset(&cmd, 0, sizeof(struct mmc_command));
+       if (mmc_card_sd(card))
+               cmd.opcode = SD_ERASE_WR_BLK_END;
+       else
+               cmd.opcode = MMC_ERASE_GROUP_END;
+       cmd.arg = to;
+       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+       err = mmc_wait_for_cmd(card->host, &cmd, 0);
+       if (err) {
+               printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n",
+                      err, cmd.resp[0]);
+               err = -EINVAL;
+               goto out;
+       }
+
+       memset(&cmd, 0, sizeof(struct mmc_command));
+       cmd.opcode = MMC_ERASE;
+       cmd.arg = arg;
+       cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+       cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
+       err = mmc_wait_for_cmd(card->host, &cmd, 0);
+       if (err) {
+               printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n",
+                      err, cmd.resp[0]);
+               err = -EIO;
+               goto out;
+       }
+
+       if (mmc_host_is_spi(card->host))
+               goto out;
+
+       do {
+               memset(&cmd, 0, sizeof(struct mmc_command));
+               cmd.opcode = MMC_SEND_STATUS;
+               cmd.arg = card->rca << 16;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+               /* Do not retry else we can't see errors */
+               err = mmc_wait_for_cmd(card->host, &cmd, 0);
+               if (err || (cmd.resp[0] & 0xFDF92000)) {
+                       printk(KERN_ERR "error %d requesting status %#x\n",
+                               err, cmd.resp[0]);
+                       err = -EIO;
+                       goto out;
+               }
+       } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
+                R1_CURRENT_STATE(cmd.resp[0]) == 7);
+out:
+       return err;
+}
+
+/**
+ * mmc_erase - erase sectors.
+ * @card: card to erase
+ * @from: first sector to erase
+ * @nr: number of sectors to erase
+ * @arg: erase command argument (SD supports only %MMC_ERASE_ARG)
+ *
+ * Caller must claim host before calling this function.
+ */
+int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
+             unsigned int arg)
+{
+       unsigned int rem, to = from + nr;
+
+       if (!(card->host->caps & MMC_CAP_ERASE) ||
+           !(card->csd.cmdclass & CCC_ERASE))
+               return -EOPNOTSUPP;
 
+       if (!card->erase_size)
+               return -EOPNOTSUPP;
+
+       if (mmc_card_sd(card) && arg != MMC_ERASE_ARG)
+               return -EOPNOTSUPP;
+
+       if ((arg & MMC_SECURE_ARGS) &&
+           !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN))
+               return -EOPNOTSUPP;
+
+       if ((arg & MMC_TRIM_ARGS) &&
+           !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN))
+               return -EOPNOTSUPP;
+
+       if (arg == MMC_SECURE_ERASE_ARG) {
+               if (from % card->erase_size || nr % card->erase_size)
+                       return -EINVAL;
+       }
+
+       if (arg == MMC_ERASE_ARG) {
+               rem = from % card->erase_size;
+               if (rem) {
+                       rem = card->erase_size - rem;
+                       from += rem;
+                       if (nr > rem)
+                               nr -= rem;
+                       else
+                               return 0;
+               }
+               rem = nr % card->erase_size;
+               if (rem)
+                       nr -= rem;
+       }
+
+       if (nr == 0)
+               return 0;
+
+       to = from + nr;
+
+       if (to <= from)
+               return -EINVAL;
+
+       /* 'from' and 'to' are inclusive */
+       to -= 1;
+
+       return mmc_do_erase(card, from, to, arg);
+}
+EXPORT_SYMBOL(mmc_erase);
+
+int mmc_can_erase(struct mmc_card *card)
+{
+       if ((card->host->caps & MMC_CAP_ERASE) &&
+           (card->csd.cmdclass & CCC_ERASE) && card->erase_size)
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(mmc_can_erase);
+
+int mmc_can_trim(struct mmc_card *card)
+{
+       if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(mmc_can_trim);
+
+int mmc_can_secure_erase_trim(struct mmc_card *card)
+{
+       if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(mmc_can_secure_erase_trim);
+
+int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
+                           unsigned int nr)
+{
+       if (!card->erase_size)
+               return 0;
+       if (from % card->erase_size || nr % card->erase_size)
+               return 0;
+       return 1;
+}
+EXPORT_SYMBOL(mmc_erase_group_aligned);
+
+int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
+{
+       struct mmc_command cmd = {0};
+
+       if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+               return 0;
+
+       cmd.opcode = MMC_SET_BLOCKLEN;
+       cmd.arg = blocklen;
+       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+       return mmc_wait_for_cmd(card->host, &cmd, 5);
+}
+EXPORT_SYMBOL(mmc_set_blocklen);
+
+static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
+{
+       host->f_init = freq;
+
+#if defined(CONFIG_SDMMC_RK29) || !defined(CONFIG_SDMMC_RK29_OLD)   //Modifyed by xbw at 2011-11-17            
+       int init_ret=0;
+#endif
+
+#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 sends CMD52 to reset card.  Since we do not know
+        * if the card is being re-initialized, just send it.  CMD52
+        * should be ignored by SD/eMMC cards.
+        */
+#if defined(CONFIG_SDMMC_RK29) || !defined(CONFIG_SDMMC_RK29_OLD)   //Modifyed by xbw at 2011-11-17    
+//the process is default for rockchip SDK. noted by xbw at 2011-11-17
+
+/* Order's important: probe SDIO, then SD, then MMC */
+
+#if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
+    if( strncmp( mmc_hostname(host) ,"mmc0" , strlen("mmc0")) )
+    {
+           //sdio_reset(host);//make no sense; noteed by xbw at 2011-12-14
+       mmc_go_idle(host);
+
+       if (!(init_ret=mmc_attach_sdio(host)))
+       {
+           printk(KERN_INFO "%s..%d..  ===== Initialize SDIO successfully. [%s]\n",\
+               __FUNCTION__,  __LINE__, mmc_hostname(host));
+               return 0;
+       }
+       else
+       {
+           if(0xFF!=init_ret)
+           {
+                printk(KERN_WARNING "\n=====\n %s..%d..  ===== Initialize SDIO-card unsuccessfully!!! [%s]\n=====\n",\
+                       __FUNCTION__,  __LINE__, mmc_hostname(host));
+
+                    goto freq_out;   
+           }
+       }
+    }
+    else
+    {
+        mmc_go_idle(host);
+    }
+#else
+    //sdio_reset(host); //make no sense; noteed by xbw at 2011-12-14
+       mmc_go_idle(host);
+
+       if (!(init_ret=mmc_attach_sdio(host)))
+       {
+           printk(KERN_INFO "%s..%d..  ===== Initialize SDIO successfully. [%s]\n",\
+               __FUNCTION__,  __LINE__, mmc_hostname(host));
+               return 0;
+       }
+       else
+       {
+           if(0xFF!=init_ret)
+           {
+                printk(KERN_WARNING "\n=====\n %s..%d..  ===== Initialize SDIO-card unsuccessfully!!! [%s]\n=====\n",\
+                       __FUNCTION__,  __LINE__, mmc_hostname(host));
+
+                    goto freq_out;   
+           }
+       }
+#endif // #end--#if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
+
+    if (!(init_ret=mmc_attach_sd(host)))
+    {
+        printk(KERN_INFO "%s..%d..  ===== Initialize SD-card successfully. [%s]\n",\
+            __FUNCTION__,  __LINE__, mmc_hostname(host));
+            
+           return 0;
+       }
+       else
+       {
+           if(0xFF!=init_ret)
+           {
+                 printk(KERN_WARNING "\n=====\n%s..%d..  ===== Initialize SD-card unsuccessfully! [%s]\n====\n",\
+                       __FUNCTION__,  __LINE__, mmc_hostname(host));
+
+                    goto freq_out;   
+           }
+       }
+
+
+       if (!(init_ret=mmc_attach_mmc(host)))
+       {
+           printk(KERN_INFO "%s...%d..  ===== Initialize MMC-card successfully. [%s]\n",\
+               __FUNCTION__,  __LINE__, mmc_hostname(host));
+
+           return 0;
+       }
+       else
+       {
+           if(0xFF!=init_ret)
+           {
+                printk(KERN_WARNING "\n =====\n%s..%d..  ===== Initialize MMC-card unsuccessfully!!! [%s]\n======\n",\
+                   __FUNCTION__,  __LINE__, mmc_hostname(host));
+                   
+                    goto freq_out;   
+           }
+       }               
+       
+freq_out:
+       mmc_power_off(host);
+       return -EIO;
+
+#else  // the default process in ICS.
+
+    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;
+#endif 
+
+}
+
+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);
+       int i;
+       bool extend_wakelock = false;
+
+       if (host->rescan_disable)
+               return;
+
+       mmc_bus_get(host);
+
        /*
-        * First we search for SDIO...
+        * if there is a _removable_ card registered, check whether it is
+        * still present
         */
-       err = mmc_send_io_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_sdio(host, ocr))
-                       mmc_power_off(host);
+       if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
+           && !(host->caps & MMC_CAP_NONREMOVABLE))
+               host->bus_ops->detect(host);
+
+       /* 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;
-               goto out;
-       }
 
        /*
-        * ...then normal SD...
+        * Let mmc_bus_put() free the bus/bus_ops if we've found that
+        * the card is no longer present.
         */
-       err = mmc_send_app_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_sd(host, ocr))
-                       mmc_power_off(host);
-               extend_wakelock = 1;
+       mmc_bus_put(host);
+       mmc_bus_get(host);
+
+       /* if there still is a card present, stop here */
+       if (host->bus_ops != NULL) {
+               mmc_bus_put(host);
                goto out;
        }
 
        /*
-        * ...and finally MMC.
+        * Only we can add a new handler, so it's safe to
+        * release the lock here.
         */
-       err = mmc_send_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_mmc(host, ocr))
-                       mmc_power_off(host);
-               extend_wakelock = 1;
+       mmc_bus_put(host);
+
+#if defined(CONFIG_SDMMC_RK29) || !defined(CONFIG_SDMMC_RK29_OLD)   //Modifyed by xbw at 2011-11-17
+    printk(KERN_INFO "\n%s...%d..  ===== mmc_rescan Begin....[%s]\n",__FILE__, __LINE__, mmc_hostname(host));
+#endif
+
+       if (host->ops->get_cd && host->ops->get_cd(host) == 0)
+       {
+#if defined(CONFIG_SDMMC_RK29) || !defined(CONFIG_SDMMC_RK29_OLD)   //Modifyed by xbw at 2011-11-17
+        printk(KERN_WARNING "\n=================\n%s..%d..  ====find no SDMMC host. [%s]\n", \
+               __FUNCTION__, __LINE__, mmc_hostname(host));
+#endif
+
                goto out;
        }
 
+       mmc_claim_host(host);
+
+#if defined(CONFIG_SDMMC_RK29) || !defined(CONFIG_SDMMC_RK29_OLD)   //Modifyed by xbw at 2011-11-17
+    if (!mmc_rescan_try_freq(host, host->f_min)) 
+        extend_wakelock = true;
+
+#else  
+       for (i = 0; i < ARRAY_SIZE(freqs); i++) {
+               if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
+                       extend_wakelock = true;
+                       break;
+               }
+               if (freqs[i] <= host->f_min)
+                       break;
+       }
+#endif
+
        mmc_release_host(host);
-       mmc_power_off(host);
 
-out:
+ out:
        if (extend_wakelock)
-               wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2);
+               wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
        else
-               wake_unlock(&mmc_delayed_work_wake_lock);
-
-       if (host->caps & MMC_CAP_NEEDS_POLL)
+               wake_unlock(&host->detect_wake_lock);
+       if (host->caps & MMC_CAP_NEEDS_POLL) {
+               wake_lock(&host->detect_wake_lock);
                mmc_schedule_delayed_work(&host->detect, HZ);
+       }
 }
 
 void mmc_start_host(struct mmc_host *host)
@@ -1144,9 +1881,13 @@ void mmc_stop_host(struct mmc_host *host)
 
        if (host->caps & MMC_CAP_DISABLE)
                cancel_delayed_work(&host->disable);
-       cancel_delayed_work(&host->detect);
+       if (cancel_delayed_work_sync(&host->detect))
+               wake_unlock(&host->detect_wake_lock);
        mmc_flush_scheduled_work();
 
+       /* clear pm flags now and let card drivers set them as needed */
+       host->pm_flags = 0;
+
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
                if (host->bus_ops->remove)
@@ -1154,6 +1895,7 @@ void mmc_stop_host(struct mmc_host *host)
 
                mmc_claim_host(host);
                mmc_detach_bus(host);
+               mmc_power_off(host);
                mmc_release_host(host);
                mmc_bus_put(host);
                return;
@@ -1165,37 +1907,45 @@ void mmc_stop_host(struct mmc_host *host)
        mmc_power_off(host);
 }
 
-void mmc_power_save_host(struct mmc_host *host)
+int mmc_power_save_host(struct mmc_host *host)
 {
+       int ret = 0;
+
        mmc_bus_get(host);
 
        if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
                mmc_bus_put(host);
-               return;
+               return -EINVAL;
        }
 
        if (host->bus_ops->power_save)
-               host->bus_ops->power_save(host);
+               ret = host->bus_ops->power_save(host);
 
        mmc_bus_put(host);
 
        mmc_power_off(host);
+
+       return ret;
 }
 EXPORT_SYMBOL(mmc_power_save_host);
 
-void mmc_power_restore_host(struct mmc_host *host)
+int mmc_power_restore_host(struct mmc_host *host)
 {
+       int ret;
+
        mmc_bus_get(host);
 
        if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
                mmc_bus_put(host);
-               return;
+               return -EINVAL;
        }
 
        mmc_power_up(host);
-       host->bus_ops->power_restore(host);
+       ret = host->bus_ops->power_restore(host);
 
        mmc_bus_put(host);
+
+       return ret;
 }
 EXPORT_SYMBOL(mmc_power_restore_host);
 
@@ -1244,21 +1994,28 @@ EXPORT_SYMBOL(mmc_card_can_sleep);
 /**
  *     mmc_suspend_host - suspend a host
  *     @host: mmc host
- *     @state: suspend mode (PM_SUSPEND_xxx)
  */
-int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
+int mmc_suspend_host(struct mmc_host *host)
 {
        int err = 0;
 
+       if (mmc_bus_needs_resume(host))
+               return 0;
+
        if (host->caps & MMC_CAP_DISABLE)
                cancel_delayed_work(&host->disable);
-       cancel_delayed_work(&host->detect);
+       if (cancel_delayed_work(&host->detect))
+               wake_unlock(&host->detect_wake_lock);
        mmc_flush_scheduled_work();
 
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
                if (host->bus_ops->suspend)
                        err = host->bus_ops->suspend(host);
+
+#if defined(CONFIG_SDMMC_RK29) && defined(CONFIG_SDMMC_RK29_OLD)
+               //deleted all detail code. //fix the crash bug when error occur during suspend. Modiefyed by xbw at 2012-08-09
+#else
                if (err == -ENOSYS || !host->bus_ops->resume) {
                        /*
                         * We simply "remove" the card in this case.
@@ -1268,13 +2025,17 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
                                host->bus_ops->remove(host);
                        mmc_claim_host(host);
                        mmc_detach_bus(host);
+                       mmc_power_off(host);
                        mmc_release_host(host);
+                       host->pm_flags = 0;
                        err = 0;
                }
+#endif
+               flush_delayed_work(&host->disable);
        }
        mmc_bus_put(host);
 
-       if (!err)
+       if (!err && !mmc_card_keep_power(host))
                mmc_power_off(host);
 
        return err;
@@ -1291,37 +2052,108 @@ int mmc_resume_host(struct mmc_host *host)
        int err = 0;
 
        mmc_bus_get(host);
+       if (mmc_bus_manual_resume(host)) {
+               host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
+               mmc_bus_put(host);
+               return 0;
+       }
+
        if (host->bus_ops && !host->bus_dead) {
-               mmc_power_up(host);
-               mmc_select_voltage(host, host->ocr);
+               if (!mmc_card_keep_power(host)) {
+                       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);
+#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD)
+        //panic if the card is being removed during the resume, deleted by xbw at 2011-06-20
+               host->bus_ops->resume(host);
+
+#else
                err = host->bus_ops->resume(host);
                if (err) {
                        printk(KERN_WARNING "%s: error %d during resume "
                                            "(card was removed?)\n",
                                            mmc_hostname(host), err);
-                       if (host->bus_ops->remove)
-                               host->bus_ops->remove(host);
-                       mmc_claim_host(host);
-                       mmc_detach_bus(host);
-                       mmc_release_host(host);
-                       /* no need to bother upper layers */
                        err = 0;
                }
+#endif
        }
+       host->pm_flags &= ~MMC_PM_KEEP_POWER;
        mmc_bus_put(host);
 
-       /*
-        * We add a slight delay here so that resume can progress
-        * in parallel.
-        */
-       mmc_detect_change(host, 1);
-
        return err;
 }
-
 EXPORT_SYMBOL(mmc_resume_host);
 
+/* Do the card removal on suspend if card is assumed removeable
+ * Do that in pm notifier while userspace isn't yet frozen, so we will be able
+   to sync the card.
+*/
+int mmc_pm_notify(struct notifier_block *notify_block,
+                                       unsigned long mode, void *unused)
+{
+       struct mmc_host *host = container_of(
+               notify_block, struct mmc_host, pm_notify);
+       unsigned long flags;
+
+
+       switch (mode) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+
+               spin_lock_irqsave(&host->lock, flags);
+               if (mmc_bus_needs_resume(host)) {
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       break;
+               }
+               host->rescan_disable = 1;
+               spin_unlock_irqrestore(&host->lock, flags);
+               if (cancel_delayed_work_sync(&host->detect))
+                       wake_unlock(&host->detect_wake_lock);
+
+               if (!host->bus_ops || host->bus_ops->suspend)
+                       break;
+
+               mmc_claim_host(host);
+
+               if (host->bus_ops->remove)
+                       host->bus_ops->remove(host);
+
+               mmc_detach_bus(host);
+               mmc_power_off(host);
+               mmc_release_host(host);
+               host->pm_flags = 0;
+               break;
+
+       case PM_POST_SUSPEND:
+       case PM_POST_HIBERNATION:
+       case PM_POST_RESTORE:
+
+               spin_lock_irqsave(&host->lock, flags);
+               if (mmc_bus_manual_resume(host)) {
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       break;
+               }
+               host->rescan_disable = 0;
+               spin_unlock_irqrestore(&host->lock, flags);
+               mmc_detect_change(host, 0);
+
+       }
+
+       return 0;
+}
 #endif
 
 #ifdef CONFIG_MMC_EMBEDDED_SDIO
@@ -1344,9 +2176,7 @@ static int __init mmc_init(void)
 {
        int ret;
 
-       wake_lock_init(&mmc_delayed_work_wake_lock, WAKE_LOCK_SUSPEND, "mmc_delayed_work");
-
-       workqueue = create_singlethread_workqueue("kmmcd");
+       workqueue = alloc_ordered_workqueue("kmmcd", 0);
        if (!workqueue)
                return -ENOMEM;
 
@@ -1380,7 +2210,6 @@ 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);