omap_hsmmc: minor tweaks
[pandora-kernel.git] / drivers / mmc / host / omap_hsmmc.c
index 26e9f6e..8a585f6 100644 (file)
@@ -584,7 +584,7 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
                irq_mask &= ~DTO_ENABLE;
 
        OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-       OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
+       OMAP_HSMMC_WRITE(host->base, ISE, host->use_dma ? irq_mask : 0);
        OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
 }
 
@@ -1140,19 +1140,15 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
        struct mmc_data *data;
        int end_cmd = 0, end_trans = 0;
 
-       if (!host->req_in_progress) {
-               do {
-                       OMAP_HSMMC_WRITE(host->base, STAT, status);
-                       /* Flush posted write */
-                       status = OMAP_HSMMC_READ(host->base, STAT);
-               } while (status & INT_EN_MASK);
+       if (unlikely(!host->req_in_progress)) {
+               OMAP_HSMMC_WRITE(host->base, STAT, status);
                return;
        }
 
        data = host->data;
        dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
 
-       if (status & ERR) {
+       if (unlikely(status & ERR)) {
                omap_hsmmc_dbg_report_irq(host, status);
                if ((status & CMD_TIMEOUT) ||
                        (status & CMD_CRC)) {
@@ -1453,8 +1449,8 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
 {
        int dma_len;
 
-       if (!next && data->host_cookie &&
-           data->host_cookie != host->next_data.cookie) {
+       if (unlikely(!next && data->host_cookie &&
+           data->host_cookie != host->next_data.cookie)) {
                pr_warning("[%s] invalid cookie: data->host_cookie %d"
                       " host->next_data.cookie %d\n",
                       __func__, data->host_cookie, host->next_data.cookie);
@@ -1474,7 +1470,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
        }
 
 
-       if (dma_len == 0)
+       if (unlikely(dma_len == 0))
                return -EINVAL;
 
        if (next) {
@@ -1500,10 +1496,10 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
                struct scatterlist *sgl;
 
                sgl = data->sg + i;
-               if (sgl->length % data->blksz)
+               if (unlikely(sgl->length % data->blksz))
                        return -EINVAL;
        }
-       if ((data->blksz % 4) != 0)
+       if (unlikely((data->blksz % 4) != 0))
                /* REVISIT: The MMC buffer increments only when MSB is written.
                 * Return error for blksz which is non multiple of four.
                 */
@@ -1513,14 +1509,14 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
 
        ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
                               "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
-       if (ret != 0) {
+       if (unlikely(ret != 0)) {
                dev_err(mmc_dev(host->mmc),
                        "%s: omap_request_dma() failed with %d\n",
                        mmc_hostname(host->mmc), ret);
                return ret;
        }
        ret = omap_hsmmc_pre_dma_transfer(host, data, NULL);
-       if (ret)
+       if (unlikely(ret))
                return ret;
 
        host->dma_ch = dma_ch;
@@ -1613,6 +1609,62 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
                        mrq->data->host_cookie = 0;
 }
 
+#define BWR (1 << 4)
+#define BRR (1 << 5)
+
+static noinline void omap_hsmmc_request_do_pio(struct mmc_host *mmc,
+       struct mmc_request *req)
+{
+       struct omap_hsmmc_host *host = mmc_priv(mmc);
+       u32 *data = sg_virt(req->data->sg);
+       u32 len = req->data->sg->length;
+       int stat;
+       int i;
+
+       for (i = 0; i < 10000000; i++) {
+               stat = OMAP_HSMMC_READ(host->base, STAT);
+               if (stat == 0)
+                       continue;
+
+               //dev_err(mmc_dev(host->mmc), "stat %x, l %d\n", stat, i);
+
+               if (stat & (DATA_TIMEOUT | DATA_CRC))
+                       omap_hsmmc_reset_controller_fsm(host, SRD);
+
+               if (stat & ERR) {
+                       req->cmd->error =
+                       req->data->error = -EINVAL; // ?
+                       omap_hsmmc_xfer_done(host, host->data);
+                       return;
+               }
+       
+               if (req->data->flags & MMC_DATA_WRITE) {
+                       while (len > 0 && (stat & BWR)) {
+                               OMAP_HSMMC_WRITE(host->base, DATA, *data++);
+                               len -= 4;
+                       }
+               } else {
+                       while (len > 0 && (stat & BRR)) {
+                               *data++ = OMAP_HSMMC_READ(host->base, DATA);
+                               len -= 4;
+                       }
+               }
+
+               if ((stat & CC) && host->cmd)
+                       omap_hsmmc_cmd_done(host, host->cmd);
+               if ((stat & TC) && host->mrq) {
+                       omap_hsmmc_xfer_done(host, host->data);
+                       break;
+               }
+       }
+
+       if (len > 0) {
+               req->cmd->error =
+               req->data->error = -ETIMEDOUT;
+               omap_hsmmc_xfer_done(host, req->data);
+       }
+}
+
 /*
  * Request function. for read/write operation
  */
@@ -1623,7 +1675,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
 
        BUG_ON(host->req_in_progress);
        BUG_ON(host->dma_ch != -1);
-       if (host->protect_card) {
+       if (unlikely(host->protect_card)) {
                if (host->reqs_blocked < 3) {
                        /*
                         * Ensure the controller is left in a consistent
@@ -1642,10 +1694,19 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                return;
        } else if (host->reqs_blocked)
                host->reqs_blocked = 0;
+
+       /* pandora wifi hack.. */
+       if (host->id == OMAP_MMC3_DEVID && req->data != NULL
+           && req->data->sg_len == 1 && req->data->sg->length <= 16) {
+               host->use_dma = 0;
+       } else {
+               host->use_dma = 1;
+       }
+
        WARN_ON(host->mrq != NULL);
        host->mrq = req;
        err = omap_hsmmc_prepare_data(host, req);
-       if (err) {
+       if (unlikely(err)) {
                req->cmd->error = err;
                if (req->data)
                        req->data->error = err;
@@ -1655,6 +1716,9 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
        }
 
        omap_hsmmc_start_command(host, req->cmd, req->data);
+
+       if (host->use_dma == 0)
+               omap_hsmmc_request_do_pio(mmc, req);
 }
 
 /* Routine to configure clock values. Exposed API to core */