#include <linux/platform_device.h>
 #include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
 #include <linux/scatterlist.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
                host->set_clk_div(host->pdev, (clk>>22) & 1);
 
        sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
+       msleep(10);
 }
 
 static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
        return ret;
 }
 
-static void tmio_mmc_set_power(struct tmio_mmc_host *host, struct mmc_ios *ios)
+static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd)
 {
        struct mmc_host *mmc = host->mmc;
+       int ret = 0;
+
+       /* .set_ios() is returning void, so, no chance to report an error */
 
        if (host->set_pwr)
-               host->set_pwr(host->pdev, ios->power_mode != MMC_POWER_OFF);
+               host->set_pwr(host->pdev, 1);
+
+       if (!IS_ERR(mmc->supply.vmmc)) {
+               ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+               /*
+                * Attention: empiric value. With a b43 WiFi SDIO card this
+                * delay proved necessary for reliable card-insertion probing.
+                * 100us were not enough. Is this the same 140us delay, as in
+                * tmio_mmc_set_ios()?
+                */
+               udelay(200);
+       }
+       /*
+        * It seems, VccQ should be switched on after Vcc, this is also what the
+        * omap_hsmmc.c driver does.
+        */
+       if (!IS_ERR(mmc->supply.vqmmc) && !ret) {
+               regulator_enable(mmc->supply.vqmmc);
+               udelay(200);
+       }
+}
+
+static void tmio_mmc_power_off(struct tmio_mmc_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       if (!IS_ERR(mmc->supply.vqmmc))
+               regulator_disable(mmc->supply.vqmmc);
+
        if (!IS_ERR(mmc->supply.vmmc))
-               /* Errors ignored... */
-               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
-                                     ios->power_mode ? ios->vdd : 0);
+               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+
+       if (host->set_pwr)
+               host->set_pwr(host->pdev, 0);
 }
 
 /* Set MMC clock / power.
                if (!host->power) {
                        tmio_mmc_clk_update(mmc);
                        pm_runtime_get_sync(dev);
-                       host->power = true;
                }
                tmio_mmc_set_clock(host, ios->clock);
-               /* power up SD bus */
-               tmio_mmc_set_power(host, ios);
+               if (!host->power) {
+                       /* power up SD card and the bus */
+                       tmio_mmc_power_on(host, ios->vdd);
+                       host->power = true;
+               }
                /* start bus clock */
                tmio_mmc_clk_start(host);
        } else if (ios->power_mode != MMC_POWER_UP) {
-               if (ios->power_mode == MMC_POWER_OFF)
-                       tmio_mmc_set_power(host, ios);
                if (host->power) {
                        struct tmio_mmc_data *pdata = host->pdata;
+                       if (ios->power_mode == MMC_POWER_OFF)
+                               tmio_mmc_power_off(host);
                        tmio_mmc_clk_stop(host);
                        host->power = false;
                        pm_runtime_put(dev);