]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: calculate hsmmc data timeout accurately
authorAdrian Hunter <ext-adrian.hunter@nokia.com>
Thu, 16 Oct 2008 13:37:23 +0000 (16:37 +0300)
committerTony Lindgren <tony@atomide.com>
Tue, 28 Oct 2008 16:56:58 +0000 (09:56 -0700)
The data timeout can be calculated from the clock
rate and timing values given by the card.  At
present the timeout is set to the maximum value,
about 2.7 secs.  When dealing with cards that do have
errors, this causes large unnecessary delays because
the correct timeout may be around 10 millisecs.

Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
drivers/mmc/host/omap_hsmmc.c

index 8fb677e94c469f73aad91c6ff97819f3ebcbb6e7..942f68d115da2bbfeeed5f604e6414e98a8ad9a9 100644 (file)
@@ -64,6 +64,9 @@
 #define ICS                    0x2
 #define CEN                    (1<<2)
 #define CLKD_MASK              0x0000FFC0
+#define CLKD_SHIFT             6
+#define DTO_MASK               0x000F0000
+#define DTO_SHIFT              16
 #define INT_EN_MASK            0x307F0033
 #define INIT_STREAM            (1<<1)
 #define DP_SELECT              (1<<21)
@@ -661,6 +664,42 @@ mmc_omap_start_dma_transfer(struct mmc_omap_host *host, struct mmc_request *req)
        return 0;
 }
 
+static void set_data_timeout(struct mmc_omap_host *host,
+                            struct mmc_request *req)
+{
+       unsigned int timeout, cycle_ns;
+       uint32_t reg, clkd, dto = 0;
+
+       reg = OMAP_HSMMC_READ(host->base, SYSCTL);
+       clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
+       if (clkd == 0)
+               clkd = 1;
+
+       cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
+       timeout = req->data->timeout_ns / cycle_ns;
+       timeout += req->data->timeout_clks;
+       if (timeout) {
+               while ((timeout & 0x80000000) == 0) {
+                       dto += 1;
+                       timeout <<= 1;
+               }
+               dto = 31 - dto;
+               timeout <<= 1;
+               if (timeout && dto)
+                       dto += 1;
+               if (dto >= 13)
+                       dto -= 13;
+               else
+                       dto = 0;
+               if (dto > 14)
+                       dto = 14;
+       }
+
+       reg &= ~DTO_MASK;
+       reg |= dto << DTO_SHIFT;
+       OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
+}
+
 /*
  * Configure block length for MMC/SD cards and initiate the transfer.
  */
@@ -678,6 +717,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
 
        OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
                                        | (req->data->blocks << 16));
+       set_data_timeout(host, req);
 
        host->datadir = (req->data->flags & MMC_DATA_WRITE) ?
                        OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ;