]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/mmc/host/sh_mmcif.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / mmc / host / sh_mmcif.c
index ddd09840520b69c5cba9d5673c3d6e1b51abeed4..12884c270171d2e81e5a87c2854e0005cdf085cb 100644 (file)
  *
  */
 
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
+#include <linux/dmaengine.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
 #include <linux/mmc/sh_mmcif.h>
+#include <linux/pagemap.h>
+#include <linux/platform_device.h>
 
 #define DRIVER_NAME    "sh_mmcif"
 #define DRIVER_VERSION "2010-04-28"
 /* CE_BLOCK_SET */
 #define BLOCK_SIZE_MASK                0x0000ffff
 
-/* CE_CLK_CTRL */
-#define CLK_ENABLE             (1 << 24) /* 1: output mmc clock */
-#define CLK_CLEAR              ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
-#define CLK_SUP_PCLK           ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
-#define SRSPTO_256             ((1 << 13) | (0 << 12)) /* resp timeout */
-#define SRBSYTO_29             ((1 << 11) | (1 << 10) |        \
-                                (1 << 9) | (1 << 8)) /* resp busy timeout */
-#define SRWDTO_29              ((1 << 7) | (1 << 6) |          \
-                                (1 << 5) | (1 << 4)) /* read/write timeout */
-#define SCCSTO_29              ((1 << 3) | (1 << 2) |          \
-                                (1 << 1) | (1 << 0)) /* ccs timeout */
-
-/* CE_BUF_ACC */
-#define BUF_ACC_DMAWEN         (1 << 25)
-#define BUF_ACC_DMAREN         (1 << 24)
-#define BUF_ACC_BUSW_32                (0 << 17)
-#define BUF_ACC_BUSW_16                (1 << 17)
-#define BUF_ACC_ATYP           (1 << 16)
-
 /* CE_INT */
 #define INT_CCSDE              (1 << 29)
 #define INT_CMD12DRE           (1 << 26)
                                 STS2_AC12BSYTO | STS2_RSPBSYTO |       \
                                 STS2_AC12RSPTO | STS2_RSPTO)
 
-/* CE_VERSION */
-#define SOFT_RST_ON            (1 << 31)
-#define SOFT_RST_OFF           (0 << 31)
-
 #define CLKDEV_EMMC_DATA       52000000 /* 52MHz */
 #define CLKDEV_MMC_DATA                20000000 /* 20MHz */
 #define CLKDEV_INIT            400000   /* 400 KHz */
 struct sh_mmcif_host {
        struct mmc_host *mmc;
        struct mmc_data *data;
-       struct mmc_command *cmd;
        struct platform_device *pd;
        struct clk *hclk;
        unsigned int clk;
        int bus_width;
-       u16 wait_int;
-       u16 sd_error;
+       bool sd_error;
        long timeout;
        void __iomem *addr;
-       wait_queue_head_t intr_wait;
-};
+       struct completion intr_wait;
 
+       /* DMA support */
+       struct dma_chan         *chan_rx;
+       struct dma_chan         *chan_tx;
+       struct completion       dma_complete;
+       unsigned int            dma_sglen;
+};
 
 static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
                                        unsigned int reg, u32 val)
@@ -201,6 +184,188 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
        writel(~val & readl(host->addr + reg), host->addr + reg);
 }
 
+static void mmcif_dma_complete(void *arg)
+{
+       struct sh_mmcif_host *host = arg;
+       dev_dbg(&host->pd->dev, "Command completed\n");
+
+       if (WARN(!host->data, "%s: NULL data in DMA completion!\n",
+                dev_name(&host->pd->dev)))
+               return;
+
+       if (host->data->flags & MMC_DATA_READ)
+               dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen,
+                            DMA_FROM_DEVICE);
+       else
+               dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen,
+                            DMA_TO_DEVICE);
+
+       complete(&host->dma_complete);
+}
+
+static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
+{
+       struct scatterlist *sg = host->data->sg;
+       struct dma_async_tx_descriptor *desc = NULL;
+       struct dma_chan *chan = host->chan_rx;
+       dma_cookie_t cookie = -EINVAL;
+       int ret;
+
+       ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_FROM_DEVICE);
+       if (ret > 0) {
+               host->dma_sglen = ret;
+               desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+                       DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       }
+
+       if (desc) {
+               desc->callback = mmcif_dma_complete;
+               desc->callback_param = host;
+               cookie = desc->tx_submit(desc);
+               if (cookie < 0) {
+                       desc = NULL;
+                       ret = cookie;
+               } else {
+                       sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN);
+                       chan->device->device_issue_pending(chan);
+               }
+       }
+       dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
+               __func__, host->data->sg_len, ret, cookie);
+
+       if (!desc) {
+               /* DMA failed, fall back to PIO */
+               if (ret >= 0)
+                       ret = -EIO;
+               host->chan_rx = NULL;
+               host->dma_sglen = 0;
+               dma_release_channel(chan);
+               /* Free the Tx channel too */
+               chan = host->chan_tx;
+               if (chan) {
+                       host->chan_tx = NULL;
+                       dma_release_channel(chan);
+               }
+               dev_warn(&host->pd->dev,
+                        "DMA failed: %d, falling back to PIO\n", ret);
+               sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+       }
+
+       dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
+               desc, cookie, host->data->sg_len);
+}
+
+static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
+{
+       struct scatterlist *sg = host->data->sg;
+       struct dma_async_tx_descriptor *desc = NULL;
+       struct dma_chan *chan = host->chan_tx;
+       dma_cookie_t cookie = -EINVAL;
+       int ret;
+
+       ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_TO_DEVICE);
+       if (ret > 0) {
+               host->dma_sglen = ret;
+               desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+                       DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       }
+
+       if (desc) {
+               desc->callback = mmcif_dma_complete;
+               desc->callback_param = host;
+               cookie = desc->tx_submit(desc);
+               if (cookie < 0) {
+                       desc = NULL;
+                       ret = cookie;
+               } else {
+                       sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN);
+                       chan->device->device_issue_pending(chan);
+               }
+       }
+       dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
+               __func__, host->data->sg_len, ret, cookie);
+
+       if (!desc) {
+               /* DMA failed, fall back to PIO */
+               if (ret >= 0)
+                       ret = -EIO;
+               host->chan_tx = NULL;
+               host->dma_sglen = 0;
+               dma_release_channel(chan);
+               /* Free the Rx channel too */
+               chan = host->chan_rx;
+               if (chan) {
+                       host->chan_rx = NULL;
+                       dma_release_channel(chan);
+               }
+               dev_warn(&host->pd->dev,
+                        "DMA failed: %d, falling back to PIO\n", ret);
+               sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+       }
+
+       dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d\n", __func__,
+               desc, cookie);
+}
+
+static bool sh_mmcif_filter(struct dma_chan *chan, void *arg)
+{
+       dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
+       chan->private = arg;
+       return true;
+}
+
+static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
+                                struct sh_mmcif_plat_data *pdata)
+{
+       host->dma_sglen = 0;
+
+       /* We can only either use DMA for both Tx and Rx or not use it at all */
+       if (pdata->dma) {
+               dma_cap_mask_t mask;
+
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+
+               host->chan_tx = dma_request_channel(mask, sh_mmcif_filter,
+                                                   &pdata->dma->chan_priv_tx);
+               dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__,
+                       host->chan_tx);
+
+               if (!host->chan_tx)
+                       return;
+
+               host->chan_rx = dma_request_channel(mask, sh_mmcif_filter,
+                                                   &pdata->dma->chan_priv_rx);
+               dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__,
+                       host->chan_rx);
+
+               if (!host->chan_rx) {
+                       dma_release_channel(host->chan_tx);
+                       host->chan_tx = NULL;
+                       return;
+               }
+
+               init_completion(&host->dma_complete);
+       }
+}
+
+static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
+{
+       sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+       /* Descriptors are freed automatically */
+       if (host->chan_tx) {
+               struct dma_chan *chan = host->chan_tx;
+               host->chan_tx = NULL;
+               dma_release_channel(chan);
+       }
+       if (host->chan_rx) {
+               struct dma_chan *chan = host->chan_rx;
+               host->chan_rx = NULL;
+               dma_release_channel(chan);
+       }
+
+       host->dma_sglen = 0;
+}
 
 static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
 {
@@ -239,13 +404,12 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
        u32 state1, state2;
        int ret, timeout = 10000000;
 
-       host->sd_error = 0;
-       host->wait_int = 0;
+       host->sd_error = false;
 
        state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1);
        state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2);
-       pr_debug("%s: ERR HOST_STS1 = %08x\n", DRIVER_NAME, state1);
-       pr_debug("%s: ERR HOST_STS2 = %08x\n", DRIVER_NAME, state2);
+       dev_dbg(&host->pd->dev, "ERR HOST_STS1 = %08x\n", state1);
+       dev_dbg(&host->pd->dev, "ERR HOST_STS2 = %08x\n", state2);
 
        if (state1 & STS1_CMDSEQ) {
                sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
@@ -253,8 +417,8 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
                while (1) {
                        timeout--;
                        if (timeout < 0) {
-                               pr_err(DRIVER_NAME": Forceed end of " \
-                                       "command sequence timeout err\n");
+                               dev_err(&host->pd->dev,
+                                       "Forceed end of command sequence timeout err\n");
                                return -EIO;
                        }
                        if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
@@ -263,18 +427,18 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
                        mdelay(1);
                }
                sh_mmcif_sync_reset(host);
-               pr_debug(DRIVER_NAME": Forced end of command sequence\n");
+               dev_dbg(&host->pd->dev, "Forced end of command sequence\n");
                return -EIO;
        }
 
        if (state2 & STS2_CRC_ERR) {
-               pr_debug(DRIVER_NAME": Happened CRC error\n");
+               dev_dbg(&host->pd->dev, ": Happened CRC error\n");
                ret = -EIO;
        } else if (state2 & STS2_TIMEOUT_ERR) {
-               pr_debug(DRIVER_NAME": Happened Timeout error\n");
+               dev_dbg(&host->pd->dev, ": Happened Timeout error\n");
                ret = -ETIMEDOUT;
        } else {
-               pr_debug(DRIVER_NAME": Happened End/Index error\n");
+               dev_dbg(&host->pd->dev, ": Happened End/Index error\n");
                ret = -EIO;
        }
        return ret;
@@ -287,17 +451,13 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host,
        long time;
        u32 blocksize, i, *p = sg_virt(data->sg);
 
-       host->wait_int = 0;
-
        /* buf read enable */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
-       time = wait_event_interruptible_timeout(host->intr_wait,
-                       host->wait_int == 1 ||
-                       host->sd_error == 1, host->timeout);
-       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+                       host->timeout);
+       if (time <= 0 || host->sd_error)
                return sh_mmcif_error_manage(host);
 
-       host->wait_int = 0;
        blocksize = (BLOCK_SIZE_MASK &
                        sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
        for (i = 0; i < blocksize / 4; i++)
@@ -305,13 +465,11 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host,
 
        /* buffer read end */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
-       time = wait_event_interruptible_timeout(host->intr_wait,
-                       host->wait_int == 1 ||
-                       host->sd_error == 1, host->timeout);
-       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+                       host->timeout);
+       if (time <= 0 || host->sd_error)
                return sh_mmcif_error_manage(host);
 
-       host->wait_int = 0;
        return 0;
 }
 
@@ -326,19 +484,15 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
                                                     MMCIF_CE_BLOCK_SET);
        for (j = 0; j < data->sg_len; j++) {
                p = sg_virt(data->sg);
-               host->wait_int = 0;
                for (sec = 0; sec < data->sg->length / blocksize; sec++) {
                        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
                        /* buf read enable */
-                       time = wait_event_interruptible_timeout(host->intr_wait,
-                               host->wait_int == 1 ||
-                               host->sd_error == 1, host->timeout);
+                       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+                               host->timeout);
 
-                       if (host->wait_int != 1 &&
-                           (time == 0 || host->sd_error != 0))
+                       if (time <= 0 || host->sd_error)
                                return sh_mmcif_error_manage(host);
 
-                       host->wait_int = 0;
                        for (i = 0; i < blocksize / 4; i++)
                                *p++ = sh_mmcif_readl(host->addr,
                                                      MMCIF_CE_DATA);
@@ -356,17 +510,14 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host,
        long time;
        u32 blocksize, i, *p = sg_virt(data->sg);
 
-       host->wait_int = 0;
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
 
        /* buf write enable */
-       time = wait_event_interruptible_timeout(host->intr_wait,
-                       host->wait_int == 1 ||
-                       host->sd_error == 1, host->timeout);
-       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+                       host->timeout);
+       if (time <= 0 || host->sd_error)
                return sh_mmcif_error_manage(host);
 
-       host->wait_int = 0;
        blocksize = (BLOCK_SIZE_MASK &
                        sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
        for (i = 0; i < blocksize / 4; i++)
@@ -375,13 +526,11 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host,
        /* buffer write end */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
 
-       time = wait_event_interruptible_timeout(host->intr_wait,
-                       host->wait_int == 1 ||
-                       host->sd_error == 1, host->timeout);
-       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+                       host->timeout);
+       if (time <= 0 || host->sd_error)
                return sh_mmcif_error_manage(host);
 
-       host->wait_int = 0;
        return 0;
 }
 
@@ -397,19 +546,15 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
 
        for (j = 0; j < data->sg_len; j++) {
                p = sg_virt(data->sg);
-               host->wait_int = 0;
                for (sec = 0; sec < data->sg->length / blocksize; sec++) {
                        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
                        /* buf write enable*/
-                       time = wait_event_interruptible_timeout(host->intr_wait,
-                               host->wait_int == 1 ||
-                               host->sd_error == 1, host->timeout);
+                       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+                               host->timeout);
 
-                       if (host->wait_int != 1 &&
-                           (time == 0 || host->sd_error != 0))
+                       if (time <= 0 || host->sd_error)
                                return sh_mmcif_error_manage(host);
 
-                       host->wait_int = 0;
                        for (i = 0; i < blocksize / 4; i++)
                                sh_mmcif_writel(host->addr,
                                                MMCIF_CE_DATA, *p++);
@@ -457,7 +602,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                tmp |= CMD_SET_RTYP_17B;
                break;
        default:
-               pr_err(DRIVER_NAME": Not support type response.\n");
+               dev_err(&host->pd->dev, "Unsupported response type.\n");
                break;
        }
        switch (opc) {
@@ -485,7 +630,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                        tmp |= CMD_SET_DATW_8;
                        break;
                default:
-                       pr_err(DRIVER_NAME": Not support bus width.\n");
+                       dev_err(&host->pd->dev, "Unsupported bus width.\n");
                        break;
                }
        }
@@ -513,10 +658,10 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
        return opc = ((opc << 24) | tmp);
 }
 
-static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
+static int sh_mmcif_data_trans(struct sh_mmcif_host *host,
                                struct mmc_request *mrq, u32 opc)
 {
-       u32 ret;
+       int ret;
 
        switch (opc) {
        case MMC_READ_MULTIPLE_BLOCK:
@@ -533,7 +678,7 @@ static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
                ret = sh_mmcif_single_read(host, mrq);
                break;
        default:
-               pr_err(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
+               dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc);
                ret = -EINVAL;
                break;
        }
@@ -547,8 +692,6 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        int ret = 0, mask = 0;
        u32 opc = cmd->opcode;
 
-       host->cmd = cmd;
-
        switch (opc) {
        /* respons busy check */
        case MMC_SWITCH:
@@ -579,13 +722,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
        /* set arg */
        sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
-       host->wait_int = 0;
        /* set cmd */
        sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
 
-       time = wait_event_interruptible_timeout(host->intr_wait,
-               host->wait_int == 1 || host->sd_error == 1, host->timeout);
-       if (host->wait_int != 1 && time == 0) {
+       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+               host->timeout);
+       if (time <= 0) {
                cmd->error = sh_mmcif_error_manage(host);
                return;
        }
@@ -597,26 +739,34 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
                        cmd->error = -ETIMEDOUT;
                        break;
                default:
-                       pr_debug("%s: Cmd(d'%d) err\n",
-                                       DRIVER_NAME, cmd->opcode);
+                       dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n",
+                                       cmd->opcode);
                        cmd->error = sh_mmcif_error_manage(host);
                        break;
                }
-               host->sd_error = 0;
-               host->wait_int = 0;
+               host->sd_error = false;
                return;
        }
        if (!(cmd->flags & MMC_RSP_PRESENT)) {
-               cmd->error = ret;
-               host->wait_int = 0;
+               cmd->error = 0;
                return;
        }
-       if (host->wait_int == 1) {
-               sh_mmcif_get_response(host, cmd);
-               host->wait_int = 0;
-       }
+       sh_mmcif_get_response(host, cmd);
        if (host->data) {
-               ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
+               if (!host->dma_sglen) {
+                       ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
+               } else {
+                       long time =
+                               wait_for_completion_interruptible_timeout(&host->dma_complete,
+                                                                         host->timeout);
+                       if (!time)
+                               ret = -ETIMEDOUT;
+                       else if (time < 0)
+                               ret = time;
+                       sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
+                                       BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+                       host->dma_sglen = 0;
+               }
                if (ret < 0)
                        mrq->data->bytes_xfered = 0;
                else
@@ -636,20 +786,18 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
        else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
                sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
        else {
-               pr_err(DRIVER_NAME": not support stop cmd\n");
+               dev_err(&host->pd->dev, "unsupported stop cmd\n");
                cmd->error = sh_mmcif_error_manage(host);
                return;
        }
 
-       time = wait_event_interruptible_timeout(host->intr_wait,
-                       host->wait_int == 1 ||
-                       host->sd_error == 1, host->timeout);
-       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) {
+       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+                       host->timeout);
+       if (time <= 0 || host->sd_error) {
                cmd->error = sh_mmcif_error_manage(host);
                return;
        }
        sh_mmcif_get_cmd12response(host, cmd);
-       host->wait_int = 0;
        cmd->error = 0;
 }
 
@@ -676,6 +824,15 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
                break;
        }
        host->data = mrq->data;
+       if (mrq->data) {
+               if (mrq->data->flags & MMC_DATA_READ) {
+                       if (host->chan_rx)
+                               sh_mmcif_start_dma_rx(host);
+               } else {
+                       if (host->chan_tx)
+                               sh_mmcif_start_dma_tx(host);
+               }
+       }
        sh_mmcif_start_cmd(host, mrq, mrq->cmd);
        host->data = NULL;
 
@@ -735,7 +892,7 @@ static void sh_mmcif_detect(struct mmc_host *mmc)
 static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
 {
        struct sh_mmcif_host *host = dev_id;
-       u32 state = 0;
+       u32 state;
        int err = 0;
 
        state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
@@ -774,17 +931,19 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
                err = 1;
        } else {
-               pr_debug("%s: Not support int\n", DRIVER_NAME);
+               dev_dbg(&host->pd->dev, "Not support int\n");
                sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
                err = 1;
        }
        if (err) {
-               host->sd_error = 1;
-               pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state);
+               host->sd_error = true;
+               dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
        }
-       host->wait_int = 1;
-       wake_up(&host->intr_wait);
+       if (state & ~(INT_CMD12RBE | INT_CMD12CRE))
+               complete(&host->intr_wait);
+       else
+               dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state);
 
        return IRQ_HANDLED;
 }
@@ -793,8 +952,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
 {
        int ret = 0, irq[2];
        struct mmc_host *mmc;
-       struct sh_mmcif_host *host = NULL;
-       struct sh_mmcif_plat_data *pd = NULL;
+       struct sh_mmcif_host *host;
+       struct sh_mmcif_plat_data *pd;
        struct resource *res;
        void __iomem *reg;
        char clk_name[8];
@@ -802,7 +961,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        irq[0] = platform_get_irq(pdev, 0);
        irq[1] = platform_get_irq(pdev, 1);
        if (irq[0] < 0 || irq[1] < 0) {
-               pr_err(DRIVER_NAME": Get irq error\n");
+               dev_err(&pdev->dev, "Get irq error\n");
                return -ENXIO;
        }
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -815,7 +974,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "ioremap error.\n");
                return -ENOMEM;
        }
-       pd = (struct sh_mmcif_plat_data *)(pdev->dev.platform_data);
+       pd = pdev->dev.platform_data;
        if (!pd) {
                dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
                ret = -ENXIO;
@@ -842,7 +1001,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        host->clk = clk_get_rate(host->hclk);
        host->pd = pdev;
 
-       init_waitqueue_head(&host->intr_wait);
+       init_completion(&host->intr_wait);
 
        mmc->ops = &sh_mmcif_ops;
        mmc->f_max = host->clk;
@@ -858,33 +1017,37 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_MMC_HIGHSPEED;
        if (pd->caps)
                mmc->caps |= pd->caps;
-       mmc->max_segs = 128;
+       mmc->max_segs = 32;
        mmc->max_blk_size = 512;
-       mmc->max_blk_count = 65535;
-       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_req_size = PAGE_CACHE_SIZE * mmc->max_segs;
+       mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size;
        mmc->max_seg_size = mmc->max_req_size;
 
        sh_mmcif_sync_reset(host);
        platform_set_drvdata(pdev, host);
+
+       /* See if we also get DMA */
+       sh_mmcif_request_dma(host, pd);
+
        mmc_add_host(mmc);
 
        ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
        if (ret) {
-               pr_err(DRIVER_NAME": request_irq error (sh_mmc:error)\n");
+               dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
                goto clean_up2;
        }
        ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
        if (ret) {
                free_irq(irq[0], host);
-               pr_err(DRIVER_NAME": request_irq error (sh_mmc:int)\n");
+               dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
                goto clean_up2;
        }
 
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
        sh_mmcif_detect(host->mmc);
 
-       pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION);
-       pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME,
+       dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
+       dev_dbg(&pdev->dev, "chip ver H'%04x\n",
                sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
        return ret;
 
@@ -903,20 +1066,22 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
        struct sh_mmcif_host *host = platform_get_drvdata(pdev);
        int irq[2];
 
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
-
-       irq[0] = platform_get_irq(pdev, 0);
-       irq[1] = platform_get_irq(pdev, 1);
+       mmc_remove_host(host->mmc);
+       sh_mmcif_release_dma(host);
 
        if (host->addr)
                iounmap(host->addr);
 
-       platform_set_drvdata(pdev, NULL);
-       mmc_remove_host(host->mmc);
+       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+
+       irq[0] = platform_get_irq(pdev, 0);
+       irq[1] = platform_get_irq(pdev, 1);
 
        free_irq(irq[0], host);
        free_irq(irq[1], host);
 
+       platform_set_drvdata(pdev, NULL);
+
        clk_disable(host->hclk);
        mmc_free_host(host->mmc);
 
@@ -947,5 +1112,5 @@ module_exit(sh_mmcif_exit);
 
 MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS(DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");