Merge tag 'for-linus-3.11-merge-window-part-2' of git://git.kernel.org/pub/scm/linux...
[deliverable/linux.git] / drivers / mmc / host / mmci.c
index f4f3038c1df08e2d5934014875abe38782f67db6..c3785edc0e92c851d3c36a0481a1b2936f92fc63 100644 (file)
@@ -61,6 +61,7 @@ static unsigned int fmax = 515633;
  * @pwrreg_powerup: power up value for MMCIPOWER register
  * @signal_direction: input/out direction of bus signals can be indicated
  * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
+ * @busy_detect: true if busy detection on dat0 is supported
  */
 struct variant_data {
        unsigned int            clkreg;
@@ -74,6 +75,7 @@ struct variant_data {
        u32                     pwrreg_powerup;
        bool                    signal_direction;
        bool                    pwrreg_clkgate;
+       bool                    busy_detect;
 };
 
 static struct variant_data variant_arm = {
@@ -132,6 +134,7 @@ static struct variant_data variant_ux500 = {
        .pwrreg_powerup         = MCI_PWR_ON,
        .signal_direction       = true,
        .pwrreg_clkgate         = true,
+       .busy_detect            = true,
 };
 
 static struct variant_data variant_ux500v2 = {
@@ -146,8 +149,28 @@ static struct variant_data variant_ux500v2 = {
        .pwrreg_powerup         = MCI_PWR_ON,
        .signal_direction       = true,
        .pwrreg_clkgate         = true,
+       .busy_detect            = true,
 };
 
+static int mmci_card_busy(struct mmc_host *mmc)
+{
+       struct mmci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+       int busy = 0;
+
+       pm_runtime_get_sync(mmc_dev(mmc));
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY)
+               busy = 1;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       pm_runtime_mark_last_busy(mmc_dev(mmc));
+       pm_runtime_put_autosuspend(mmc_dev(mmc));
+
+       return busy;
+}
+
 /*
  * Validate mmc prerequisites
  */
@@ -188,6 +211,20 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
        }
 }
 
+/*
+ * This must be called with host->lock held
+ */
+static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
+{
+       /* Keep ST Micro busy mode if enabled */
+       datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE;
+
+       if (host->datactrl_reg != datactrl) {
+               host->datactrl_reg = datactrl;
+               writel(datactrl, host->base + MMCIDATACTRL);
+       }
+}
+
 /*
  * This must be called with host->lock held
  */
@@ -196,6 +233,9 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
        struct variant_data *variant = host->variant;
        u32 clk = variant->clkreg;
 
+       /* Make sure cclk reflects the current calculated clock */
+       host->cclk = 0;
+
        if (desired) {
                if (desired >= host->mclk) {
                        clk = MCI_CLK_BYPASS;
@@ -230,6 +270,9 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
                /* clk |= MCI_CLK_PWRSAVE; */
        }
 
+       /* Set actual clock for debug */
+       host->mmc->actual_clock = host->cclk;
+
        if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
                clk |= MCI_4BIT_BUS;
        if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
@@ -275,7 +318,7 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
 
 static void mmci_stop_data(struct mmci_host *host)
 {
-       writel(0, host->base + MMCIDATACTRL);
+       mmci_write_datactrlreg(host, 0);
        mmci_set_mask1(host, 0);
        host->data = NULL;
 }
@@ -304,10 +347,8 @@ static void mmci_dma_setup(struct mmci_host *host)
        const char *rxname, *txname;
        dma_cap_mask_t mask;
 
-       if (!plat || !plat->dma_filter) {
-               dev_info(mmc_dev(host->mmc), "no DMA platform data\n");
-               return;
-       }
+       host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
+       host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
 
        /* initialize pre request cookie */
        host->next_data.cookie = 1;
@@ -316,30 +357,33 @@ static void mmci_dma_setup(struct mmci_host *host)
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       /*
-        * If only an RX channel is specified, the driver will
-        * attempt to use it bidirectionally, however if it is
-        * is specified but cannot be located, DMA will be disabled.
-        */
-       if (plat->dma_rx_param) {
-               host->dma_rx_channel = dma_request_channel(mask,
+       if (plat && plat->dma_filter) {
+               if (!host->dma_rx_channel && plat->dma_rx_param) {
+                       host->dma_rx_channel = dma_request_channel(mask,
                                                           plat->dma_filter,
                                                           plat->dma_rx_param);
-               /* E.g if no DMA hardware is present */
-               if (!host->dma_rx_channel)
-                       dev_err(mmc_dev(host->mmc), "no RX DMA channel\n");
-       }
+                       /* E.g if no DMA hardware is present */
+                       if (!host->dma_rx_channel)
+                               dev_err(mmc_dev(host->mmc), "no RX DMA channel\n");
+               }
 
-       if (plat->dma_tx_param) {
-               host->dma_tx_channel = dma_request_channel(mask,
+               if (!host->dma_tx_channel && plat->dma_tx_param) {
+                       host->dma_tx_channel = dma_request_channel(mask,
                                                           plat->dma_filter,
                                                           plat->dma_tx_param);
-               if (!host->dma_tx_channel)
-                       dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n");
-       } else {
-               host->dma_tx_channel = host->dma_rx_channel;
+                       if (!host->dma_tx_channel)
+                               dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n");
+               }
        }
 
+       /*
+        * If only an RX channel is specified, the driver will
+        * attempt to use it bidirectionally, however if it is
+        * is specified but cannot be located, DMA will be disabled.
+        */
+       if (host->dma_rx_channel && !host->dma_tx_channel)
+               host->dma_tx_channel = host->dma_rx_channel;
+
        if (host->dma_rx_channel)
                rxname = dma_chan_name(host->dma_rx_channel);
        else
@@ -552,7 +596,7 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
        datactrl |= MCI_DPSM_DMAENABLE;
 
        /* Trigger the DMA transfer */
-       writel(datactrl, host->base + MMCIDATACTRL);
+       mmci_write_datactrlreg(host, datactrl);
 
        /*
         * Let the MMCI say when the data is ended and it's time
@@ -750,7 +794,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
                irqmask = MCI_TXFIFOHALFEMPTYMASK;
        }
 
-       writel(datactrl, base + MMCIDATACTRL);
+       mmci_write_datactrlreg(host, datactrl);
        writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
        mmci_set_mask1(host, irqmask);
 }
@@ -842,7 +886,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
                        /* The error clause is handled above, success! */
                        data->bytes_xfered = data->blksz * data->blocks;
 
-               if (!data->stop) {
+               if (!data->stop || host->mrq->sbc) {
                        mmci_request_end(host, data->mrq);
                } else {
                        mmci_start_command(host, data->stop, 0);
@@ -855,6 +899,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
             unsigned int status)
 {
        void __iomem *base = host->base;
+       bool sbc = (cmd == host->mrq->sbc);
 
        host->cmd = NULL;
 
@@ -869,7 +914,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
                cmd->resp[3] = readl(base + MMCIRESPONSE3);
        }
 
-       if (!cmd->data || cmd->error) {
+       if ((!sbc && !cmd->data) || cmd->error) {
                if (host->data) {
                        /* Terminate the DMA transfer */
                        if (dma_inprogress(host)) {
@@ -878,7 +923,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
                        }
                        mmci_stop_data(host);
                }
-               mmci_request_end(host, cmd->mrq);
+               mmci_request_end(host, host->mrq);
+       } else if (sbc) {
+               mmci_start_command(host, host->mrq->cmd, 0);
        } else if (!(cmd->data->flags & MMC_DATA_READ)) {
                mmci_start_data(host, cmd->data);
        }
@@ -1119,7 +1166,10 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        if (mrq->data && mrq->data->flags & MMC_DATA_READ)
                mmci_start_data(host, mrq->data);
 
-       mmci_start_command(host, mrq->cmd, 0);
+       if (mrq->sbc)
+               mmci_start_command(host, mrq->sbc, 0);
+       else
+               mmci_start_command(host, mrq->cmd, 0);
 
        spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -1143,9 +1193,10 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (!IS_ERR(mmc->supply.vmmc))
                        mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
 
-               if (!IS_ERR(mmc->supply.vqmmc) &&
-                   regulator_is_enabled(mmc->supply.vqmmc))
+               if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
                        regulator_disable(mmc->supply.vqmmc);
+                       host->vqmmc_enabled = false;
+               }
 
                break;
        case MMC_POWER_UP:
@@ -1161,12 +1212,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
                break;
        case MMC_POWER_ON:
-               if (!IS_ERR(mmc->supply.vqmmc) &&
-                   !regulator_is_enabled(mmc->supply.vqmmc)) {
+               if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
                        ret = regulator_enable(mmc->supply.vqmmc);
                        if (ret < 0)
                                dev_err(mmc_dev(mmc),
                                        "failed to enable vqmmc regulator\n");
+                       else
+                               host->vqmmc_enabled = true;
                }
 
                pwr |= MCI_PWR_ON;
@@ -1251,6 +1303,39 @@ static int mmci_get_cd(struct mmc_host *mmc)
        return status;
 }
 
+static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       int ret = 0;
+
+       if (!IS_ERR(mmc->supply.vqmmc)) {
+
+               pm_runtime_get_sync(mmc_dev(mmc));
+
+               switch (ios->signal_voltage) {
+               case MMC_SIGNAL_VOLTAGE_330:
+                       ret = regulator_set_voltage(mmc->supply.vqmmc,
+                                               2700000, 3600000);
+                       break;
+               case MMC_SIGNAL_VOLTAGE_180:
+                       ret = regulator_set_voltage(mmc->supply.vqmmc,
+                                               1700000, 1950000);
+                       break;
+               case MMC_SIGNAL_VOLTAGE_120:
+                       ret = regulator_set_voltage(mmc->supply.vqmmc,
+                                               1100000, 1300000);
+                       break;
+               }
+
+               if (ret)
+                       dev_warn(mmc_dev(mmc), "Voltage switch failed\n");
+
+               pm_runtime_mark_last_busy(mmc_dev(mmc));
+               pm_runtime_put_autosuspend(mmc_dev(mmc));
+       }
+
+       return ret;
+}
+
 static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
 {
        struct mmci_host *host = dev_id;
@@ -1260,13 +1345,14 @@ static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static const struct mmc_host_ops mmci_ops = {
+static struct mmc_host_ops mmci_ops = {
        .request        = mmci_request,
        .pre_req        = mmci_pre_request,
        .post_req       = mmci_post_request,
        .set_ios        = mmci_set_ios,
        .get_ro         = mmci_get_ro,
        .get_cd         = mmci_get_cd,
+       .start_signal_voltage_switch = mmci_sig_volt_switch,
 };
 
 #ifdef CONFIG_OF
@@ -1362,16 +1448,15 @@ static int mmci_probe(struct amba_device *dev,
        dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
        dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
 
-       host->clk = clk_get(&dev->dev, NULL);
+       host->clk = devm_clk_get(&dev->dev, NULL);
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
-               host->clk = NULL;
                goto host_free;
        }
 
        ret = clk_prepare_enable(host->clk);
        if (ret)
-               goto clk_free;
+               goto host_free;
 
        host->plat = plat;
        host->variant = variant;
@@ -1396,6 +1481,11 @@ static int mmci_probe(struct amba_device *dev,
                goto clk_disable;
        }
 
+       if (variant->busy_detect) {
+               mmci_ops.card_busy = mmci_card_busy;
+               mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
+       }
+
        mmc->ops = &mmci_ops;
        /*
         * The ARM and ST versions of the block have slightly different
@@ -1576,8 +1666,6 @@ static int mmci_probe(struct amba_device *dev,
        iounmap(host->base);
  clk_disable:
        clk_disable_unprepare(host->clk);
- clk_free:
-       clk_put(host->clk);
  host_free:
        mmc_free_host(mmc);
  rel_regions:
@@ -1623,7 +1711,6 @@ static int mmci_remove(struct amba_device *dev)
 
                iounmap(host->base);
                clk_disable_unprepare(host->clk);
-               clk_put(host->clk);
 
                mmc_free_host(mmc);
 
This page took 0.033656 seconds and 5 git commands to generate.