mmc: dw_mmc: Support voltage changes
[linux-2.6-block.git] / drivers / mmc / host / dw_mmc.c
index 8f216edbdf080d0c51e3eedcf83a75a1886fc9e3..23719249182b0538994a0b1dcf6033bd44b4b5f3 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/irq.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/dw_mmc.h>
 #include <linux/bitops.h>
@@ -234,10 +235,13 @@ err:
 }
 #endif /* defined(CONFIG_DEBUG_FS) */
 
+static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg);
+
 static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct mmc_data *data;
        struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci *host = slot->host;
        const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 cmdr;
        cmd->error = -EINPROGRESS;
@@ -253,6 +257,34 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
        else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
                cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
 
+       if (cmd->opcode == SD_SWITCH_VOLTAGE) {
+               u32 clk_en_a;
+
+               /* Special bit makes CMD11 not die */
+               cmdr |= SDMMC_CMD_VOLT_SWITCH;
+
+               /* Change state to continue to handle CMD11 weirdness */
+               WARN_ON(slot->host->state != STATE_SENDING_CMD);
+               slot->host->state = STATE_SENDING_CMD11;
+
+               /*
+                * We need to disable low power mode (automatic clock stop)
+                * while doing voltage switch so we don't confuse the card,
+                * since stopping the clock is a specific part of the UHS
+                * voltage change dance.
+                *
+                * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be
+                * unconditionally turned back on in dw_mci_setup_bus() if it's
+                * ever called with a non-zero clock.  That shouldn't happen
+                * until the voltage change is all done.
+                */
+               clk_en_a = mci_readl(host, CLKENA);
+               clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id);
+               mci_writel(host, CLKENA, clk_en_a);
+               mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
+                            SDMMC_CMD_PRV_DAT_WAIT, 0);
+       }
+
        if (cmd->flags & MMC_RSP_PRESENT) {
                /* We expect a response, so set this bit */
                cmdr |= SDMMC_CMD_RESP_EXP;
@@ -775,11 +807,15 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
        unsigned int clock = slot->clock;
        u32 div;
        u32 clk_en_a;
+       u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT;
+
+       /* We must continue to set bit 28 in CMD until the change is complete */
+       if (host->state == STATE_WAITING_CMD11_DONE)
+               sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
 
        if (!clock) {
                mci_writel(host, CLKENA, 0);
-               mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               mci_send_cmd(slot, sdmmc_cmd_bits, 0);
        } else if (clock != host->current_speed || force_clkinit) {
                div = host->bus_hz / clock;
                if (host->bus_hz % clock && host->bus_hz > clock)
@@ -803,15 +839,13 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
                mci_writel(host, CLKSRC, 0);
 
                /* inform CIU */
-               mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               mci_send_cmd(slot, sdmmc_cmd_bits, 0);
 
                /* set clock to desired speed */
                mci_writel(host, CLKDIV, div);
 
                /* inform CIU */
-               mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               mci_send_cmd(slot, sdmmc_cmd_bits, 0);
 
                /* enable clock; only low power if no SDIO */
                clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
@@ -820,8 +854,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
                mci_writel(host, CLKENA, clk_en_a);
 
                /* inform CIU */
-               mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               mci_send_cmd(slot, sdmmc_cmd_bits, 0);
 
                /* keep the clock with reflecting clock dividor */
                slot->__clk_old = clock << div;
@@ -897,6 +930,17 @@ static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
 
        slot->mrq = mrq;
 
+       if (host->state == STATE_WAITING_CMD11_DONE) {
+               dev_warn(&slot->mmc->class_dev,
+                        "Voltage change didn't complete\n");
+               /*
+                * this case isn't expected to happen, so we can
+                * either crash here or just try to continue on
+                * in the closest possible state
+                */
+               host->state = STATE_IDLE;
+       }
+
        if (host->state == STATE_IDLE) {
                host->state = STATE_SENDING_CMD;
                dw_mci_start_request(host, slot);
@@ -936,6 +980,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct dw_mci_slot *slot = mmc_priv(mmc);
        const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 regs;
+       int ret;
 
        switch (ios->bus_width) {
        case MMC_BUS_WIDTH_4:
@@ -972,14 +1017,43 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        /* Slot specific timing and width adjustment */
        dw_mci_setup_bus(slot, false);
 
+       if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0)
+               slot->host->state = STATE_IDLE;
+
        switch (ios->power_mode) {
        case MMC_POWER_UP:
+               if (!IS_ERR(mmc->supply.vmmc)) {
+                       ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+                                       ios->vdd);
+                       if (ret) {
+                               dev_err(slot->host->dev,
+                                       "failed to enable vmmc regulator\n");
+                               /*return, if failed turn on vmmc*/
+                               return;
+                       }
+               }
+               if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) {
+                       ret = regulator_enable(mmc->supply.vqmmc);
+                       if (ret < 0)
+                               dev_err(slot->host->dev,
+                                       "failed to enable vqmmc regulator\n");
+                       else
+                               slot->host->vqmmc_enabled = true;
+               }
                set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
                regs = mci_readl(slot->host, PWREN);
                regs |= (1 << slot->id);
                mci_writel(slot->host, PWREN, regs);
                break;
        case MMC_POWER_OFF:
+               if (!IS_ERR(mmc->supply.vmmc))
+                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+
+               if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) {
+                       regulator_disable(mmc->supply.vqmmc);
+                       slot->host->vqmmc_enabled = false;
+               }
+
                regs = mci_readl(slot->host, PWREN);
                regs &= ~(1 << slot->id);
                mci_writel(slot->host, PWREN, regs);
@@ -989,6 +1063,59 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 }
 
+static int dw_mci_card_busy(struct mmc_host *mmc)
+{
+       struct dw_mci_slot *slot = mmc_priv(mmc);
+       u32 status;
+
+       /*
+        * Check the busy bit which is low when DAT[3:0]
+        * (the data lines) are 0000
+        */
+       status = mci_readl(slot->host, STATUS);
+
+       return !!(status & SDMMC_STATUS_BUSY);
+}
+
+static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci *host = slot->host;
+       u32 uhs;
+       u32 v18 = SDMMC_UHS_18V << slot->id;
+       int min_uv, max_uv;
+       int ret;
+
+       /*
+        * Program the voltage.  Note that some instances of dw_mmc may use
+        * the UHS_REG for this.  For other instances (like exynos) the UHS_REG
+        * does no harm but you need to set the regulator directly.  Try both.
+        */
+       uhs = mci_readl(host, UHS_REG);
+       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               min_uv = 2700000;
+               max_uv = 3600000;
+               uhs &= ~v18;
+       } else {
+               min_uv = 1700000;
+               max_uv = 1950000;
+               uhs |= v18;
+       }
+       if (!IS_ERR(mmc->supply.vqmmc)) {
+               ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
+
+               if (ret) {
+                       dev_err(&mmc->class_dev,
+                                        "Regulator set error %d: %d - %d\n",
+                                        ret, min_uv, max_uv);
+                       return ret;
+               }
+       }
+       mci_writel(host, UHS_REG, uhs);
+
+       return 0;
+}
+
 static int dw_mci_get_ro(struct mmc_host *mmc)
 {
        int read_only;
@@ -1131,6 +1258,9 @@ static const struct mmc_host_ops dw_mci_ops = {
        .get_cd                 = dw_mci_get_cd,
        .enable_sdio_irq        = dw_mci_enable_sdio_irq,
        .execute_tuning         = dw_mci_execute_tuning,
+       .card_busy              = dw_mci_card_busy,
+       .start_signal_voltage_switch = dw_mci_switch_voltage,
+
 };
 
 static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
@@ -1154,7 +1284,11 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
                dw_mci_start_request(host, slot);
        } else {
                dev_vdbg(host->dev, "list empty\n");
-               host->state = STATE_IDLE;
+
+               if (host->state == STATE_SENDING_CMD11)
+                       host->state = STATE_WAITING_CMD11_DONE;
+               else
+                       host->state = STATE_IDLE;
        }
 
        spin_unlock(&host->lock);
@@ -1265,8 +1399,10 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
                switch (state) {
                case STATE_IDLE:
+               case STATE_WAITING_CMD11_DONE:
                        break;
 
+               case STATE_SENDING_CMD11:
                case STATE_SENDING_CMD:
                        if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
                                                &host->pending_events))
@@ -1299,6 +1435,14 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        /* fall through */
 
                case STATE_SENDING_DATA:
+                       /*
+                        * We could get a data error and never a transfer
+                        * complete so we'd better check for it here.
+                        *
+                        * Note that we don't really care if we also got a
+                        * transfer complete; stopping the DMA and sending an
+                        * abort won't hurt.
+                        */
                        if (test_and_clear_bit(EVENT_DATA_ERROR,
                                               &host->pending_events)) {
                                dw_mci_stop_dma(host);
@@ -1312,7 +1456,29 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                break;
 
                        set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
+
+                       /*
+                        * Handle an EVENT_DATA_ERROR that might have shown up
+                        * before the transfer completed.  This might not have
+                        * been caught by the check above because the interrupt
+                        * could have gone off between the previous check and
+                        * the check for transfer complete.
+                        *
+                        * Technically this ought not be needed assuming we
+                        * get a DATA_COMPLETE eventually (we'll notice the
+                        * error and end the request), but it shouldn't hurt.
+                        *
+                        * This has the advantage of sending the stop command.
+                        */
+                       if (test_and_clear_bit(EVENT_DATA_ERROR,
+                                              &host->pending_events)) {
+                               dw_mci_stop_dma(host);
+                               send_stop_abort(host, data);
+                               state = STATE_DATA_ERROR;
+                               break;
+                       }
                        prev_state = state = STATE_DATA_BUSY;
+
                        /* fall through */
 
                case STATE_DATA_BUSY:
@@ -1335,6 +1501,22 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                /* stop command for open-ended transfer*/
                                if (data->stop)
                                        send_stop_abort(host, data);
+                       } else {
+                               /*
+                                * If we don't have a command complete now we'll
+                                * never get one since we just reset everything;
+                                * better end the request.
+                                *
+                                * If we do have a command complete we'll fall
+                                * through to the SENDING_STOP command and
+                                * everything will be peachy keen.
+                                */
+                               if (!test_bit(EVENT_CMD_COMPLETE,
+                                             &host->pending_events)) {
+                                       host->cmd = NULL;
+                                       dw_mci_request_end(host, mrq);
+                                       goto unlock;
+                               }
                        }
 
                        /*
@@ -1821,6 +2003,14 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
        }
 
        if (pending) {
+               /* Check volt switch first, since it can look like an error */
+               if ((host->state == STATE_SENDING_CMD11) &&
+                   (pending & SDMMC_INT_VOLT_SWITCH)) {
+                       mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);
+                       pending &= ~SDMMC_INT_VOLT_SWITCH;
+                       dw_mci_cmd_interrupt(host, pending);
+               }
+
                if (pending & DW_MCI_CMD_ERROR_FLAGS) {
                        mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
                        host->cmd_status = pending;
@@ -1926,7 +2116,9 @@ static void dw_mci_work_routine_card(struct work_struct *work)
 
                                        switch (host->state) {
                                        case STATE_IDLE:
+                                       case STATE_WAITING_CMD11_DONE:
                                                break;
+                                       case STATE_SENDING_CMD11:
                                        case STATE_SENDING_CMD:
                                                mrq->cmd->error = -ENOMEDIUM;
                                                if (!mrq->data)
@@ -2064,7 +2256,13 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                mmc->f_max = freq[1];
        }
 
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       /*if there are external regulators, get them*/
+       ret = mmc_regulator_get_supply(mmc);
+       if (ret == -EPROBE_DEFER)
+               goto err_setup_bus;
+
+       if (!mmc->ocr_avail)
+               mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
@@ -2130,7 +2328,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 
 err_setup_bus:
        mmc_free_host(mmc);
-       return -EINVAL;
+       return ret;
 }
 
 static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
@@ -2423,24 +2621,6 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
-       host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
-       if (IS_ERR(host->vmmc)) {
-               ret = PTR_ERR(host->vmmc);
-               if (ret == -EPROBE_DEFER)
-                       goto err_clk_ciu;
-
-               dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
-               host->vmmc = NULL;
-       } else {
-               ret = regulator_enable(host->vmmc);
-               if (ret) {
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(host->dev,
-                                       "regulator_enable fail: %d\n", ret);
-                       goto err_clk_ciu;
-               }
-       }
-
        host->quirks = host->pdata->quirks;
 
        spin_lock_init(&host->lock);
@@ -2584,8 +2764,6 @@ err_workqueue:
 err_dmaunmap:
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
-       if (host->vmmc)
-               regulator_disable(host->vmmc);
 
 err_clk_ciu:
        if (!IS_ERR(host->ciu_clk))
@@ -2621,9 +2799,6 @@ void dw_mci_remove(struct dw_mci *host)
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
 
-       if (host->vmmc)
-               regulator_disable(host->vmmc);
-
        if (!IS_ERR(host->ciu_clk))
                clk_disable_unprepare(host->ciu_clk);
 
@@ -2640,9 +2815,6 @@ EXPORT_SYMBOL(dw_mci_remove);
  */
 int dw_mci_suspend(struct dw_mci *host)
 {
-       if (host->vmmc)
-               regulator_disable(host->vmmc);
-
        return 0;
 }
 EXPORT_SYMBOL(dw_mci_suspend);
@@ -2651,15 +2823,6 @@ int dw_mci_resume(struct dw_mci *host)
 {
        int i, ret;
 
-       if (host->vmmc) {
-               ret = regulator_enable(host->vmmc);
-               if (ret) {
-                       dev_err(host->dev,
-                               "failed to enable regulator: %d\n", ret);
-                       return ret;
-               }
-       }
-
        if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) {
                ret = -ENODEV;
                return ret;