[PATCH] Davinci SDIO Support

2010-03-16 Thread alagusankar
From: Alagu Sankar alagusan...@embwise.com

Added SDIO Support for Davinci Platforms.  This is tested with DM355 and DM365
EVM platforms using Libertas driver with SD8686 and SD8688 SDIO WiFi cards.
There is a hack to support Libertas firmware download. This hack may not be
required for other SDIO cards.

Signed-off-by: alagusan...@embwise.com
---
 drivers/mmc/host/davinci_mmc.c |  131 
 1 files changed, 120 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 933cd42..2836ad1 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -32,6 +32,7 @@
 #include linux/delay.h
 #include linux/dma-mapping.h
 #include linux/mmc/mmc.h
+#include linux/mmc/card.h
 
 #include mach/mmc.h
 #include mach/edma.h
@@ -66,8 +67,8 @@
 #define DAVINCI_MMCBLNC  0x60
 #define DAVINCI_SDIOCTL  0x64
 #define DAVINCI_SDIOST0  0x68
-#define DAVINCI_SDIOEN   0x6C
-#define DAVINCI_SDIOST   0x70
+#define DAVINCI_SDIOIEN  0x6C
+#define DAVINCI_SDIOIST  0x70
 #define DAVINCI_MMCFIFOCTL   0x74 /* FIFO Control Register */
 
 /* DAVINCI_MMCCTL definitions */
@@ -135,6 +136,23 @@
 /* MMCSD Init clock in Hz in opendrain mode */
 #define MMCSD_INIT_CLOCK   20
 
+/* DAVINCI_SDIOCTL definitions */
+#define SDIOCTL_RDWTRQ_SETBIT(0)
+#define SDIOCTL_RDWTCR_SETBIT(1)
+
+/* DAVINCI_SDIOST0 definitions */
+#define SDIOST0_DAT1_HI   BIT(0)
+#define SDIOST0_INTPRDBIT(1)
+#define SDIOST0_RDWTSTBIT(2)
+
+/* DAVINCI_SDIOIEN definitions */
+#define SDIOIEN_IOINTEN   BIT(0)
+#define SDIOIEN_RWSEN BIT(1)
+
+/* DAVINCI_SDIOIST definitions */
+#define SDIOIST_IOINT BIT(0)
+#define SDIOIST_RWS   BIT(1)
+
 /*
  * One scatterlist dma segment is at most MAX_CCNT rw_threshold units,
  * and we handle up to NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
@@ -147,6 +165,8 @@
 
 #define NR_SG  16
 
+#define DAVINCI_SDIO_IRQ(dev_id)   (((dev_id) == 0) ? sdio0 : sdio1)
+
 static unsigned rw_threshold = 32;
 module_param(rw_threshold, uint, S_IRUGO);
 MODULE_PARM_DESC(rw_threshold,
@@ -164,7 +184,7 @@ struct mmc_davinci_host {
unsigned int mmc_input_clk;
void __iomem *base;
struct resource *mem_res;
-   int irq;
+   int mmc_irq, sdio_irq;
unsigned char bus_mode;
 
 #define DAVINCI_MMC_DATADIR_NONE   0
@@ -184,6 +204,7 @@ struct mmc_davinci_host {
u32 rxdma, txdma;
bool use_dma;
bool do_dma;
+   bool sdio_int;
 
/* Scatterlist DMA uses one or more parameter RAM entries:
 * the main one (associated with rxdma or txdma) plus zero or
@@ -670,6 +691,24 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, 
struct mmc_request *req)
host-buffer = NULL;
host-bytes_left = data-blocks * data-blksz;
 
+/*
+ * Hack for overcoming the 2ms delay required by Libertas helper
+ * firmware download.  Without this delay the primary firmware load fails
+ * without an error.  Not having the delay does not result in host
+ * controller error (or) helper firmware download error.  But will result
+ * in primary firmware load error.
+ *
+ * May not be required for usage with other SDIO client drivers and
+ * should be removed after identifying the root cause in consultation
+ * with the libertas developers.
+ */
+   if (host-mmc-card) {
+   if (mmc_card_sdio(host-mmc-card)) {
+   if ((data-blksz == 64))
+   mdelay(2);
+   }
+   }
+
/* For now we try to use DMA whenever we won't need partial FIFO
 * reads or writes, either for the whole transfer (as tested here)
 * or for any individual scatterlist segment (tested when we call
@@ -862,6 +901,19 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, 
struct mmc_data *data)
 {
host-data = NULL;
 
+   if (host-mmc-caps  MMC_CAP_SDIO_IRQ) {
+   /* SDIO Interrupt Detection work-around as suggested by
+* Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata
+* 2.1.5)
+* Signal SDIO interrupt only if it is enabled by core
+*/
+   if (host-sdio_int  (!((readl(host-base + DAVINCI_SDIOST0))
+SDIOST0_DAT1_HI))) {
+   writel(SDIOIST_IOINT, host-base + DAVINCI_SDIOIST);
+   mmc_signal_sdio_irq(host-mmc);
+   }
+   }
+
if (host-do_dma) {
davinci_abort_dma(host);
 
@@ -928,6 +980,22 @@ davinci_abort_data(struct mmc_davinci_host *host, struct 
mmc_data *data)
mmc_davinci_reset_ctrl(host, 0);
 }
 
+static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id)
+{
+   struct mmc_davinci_host *host = (struct mmc_davinci_host 

[PATCH] Davinci SDIO Support

2010-03-15 Thread alagusankar
From: Alagu Sankar alagusan...@embwise.com

Added SDIO Support for Davinci Platforms.  This is tested with DM355 and DM365
EVM platforms using Libertas driver with SD8686 and SD8688 SDIO WiFi cards.
There is a hack to support Libertas firmware download. This hack may not be
required for other SDIO cards.

Signed-off-by: alagusan...@embwise.com
---
 drivers/mmc/host/davinci_mmc.c |  131 
 1 files changed, 120 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 933cd42..2836ad1 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -32,6 +32,7 @@
 #include linux/delay.h
 #include linux/dma-mapping.h
 #include linux/mmc/mmc.h
+#include linux/mmc/card.h
 
 #include mach/mmc.h
 #include mach/edma.h
@@ -66,8 +67,8 @@
 #define DAVINCI_MMCBLNC  0x60
 #define DAVINCI_SDIOCTL  0x64
 #define DAVINCI_SDIOST0  0x68
-#define DAVINCI_SDIOEN   0x6C
-#define DAVINCI_SDIOST   0x70
+#define DAVINCI_SDIOIEN  0x6C
+#define DAVINCI_SDIOIST  0x70
 #define DAVINCI_MMCFIFOCTL   0x74 /* FIFO Control Register */
 
 /* DAVINCI_MMCCTL definitions */
@@ -135,6 +136,23 @@
 /* MMCSD Init clock in Hz in opendrain mode */
 #define MMCSD_INIT_CLOCK   20
 
+/* DAVINCI_SDIOCTL definitions */
+#define SDIOCTL_RDWTRQ_SETBIT(0)
+#define SDIOCTL_RDWTCR_SETBIT(1)
+
+/* DAVINCI_SDIOST0 definitions */
+#define SDIOST0_DAT1_HI   BIT(0)
+#define SDIOST0_INTPRDBIT(1)
+#define SDIOST0_RDWTSTBIT(2)
+
+/* DAVINCI_SDIOIEN definitions */
+#define SDIOIEN_IOINTEN   BIT(0)
+#define SDIOIEN_RWSEN BIT(1)
+
+/* DAVINCI_SDIOIST definitions */
+#define SDIOIST_IOINT BIT(0)
+#define SDIOIST_RWS   BIT(1)
+
 /*
  * One scatterlist dma segment is at most MAX_CCNT rw_threshold units,
  * and we handle up to NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
@@ -147,6 +165,8 @@
 
 #define NR_SG  16
 
+#define DAVINCI_SDIO_IRQ(dev_id)   (((dev_id) == 0) ? sdio0 : sdio1)
+
 static unsigned rw_threshold = 32;
 module_param(rw_threshold, uint, S_IRUGO);
 MODULE_PARM_DESC(rw_threshold,
@@ -164,7 +184,7 @@ struct mmc_davinci_host {
unsigned int mmc_input_clk;
void __iomem *base;
struct resource *mem_res;
-   int irq;
+   int mmc_irq, sdio_irq;
unsigned char bus_mode;
 
 #define DAVINCI_MMC_DATADIR_NONE   0
@@ -184,6 +204,7 @@ struct mmc_davinci_host {
u32 rxdma, txdma;
bool use_dma;
bool do_dma;
+   bool sdio_int;
 
/* Scatterlist DMA uses one or more parameter RAM entries:
 * the main one (associated with rxdma or txdma) plus zero or
@@ -670,6 +691,24 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, 
struct mmc_request *req)
host-buffer = NULL;
host-bytes_left = data-blocks * data-blksz;
 
+/*
+ * Hack for overcoming the 2ms delay required by Libertas helper
+ * firmware download.  Without this delay the primary firmware load fails
+ * without an error.  Not having the delay does not result in host
+ * controller error (or) helper firmware download error.  But will result
+ * in primary firmware load error.
+ *
+ * May not be required for usage with other SDIO client drivers and
+ * should be removed after identifying the root cause in consultation
+ * with the libertas developers.
+ */
+   if (host-mmc-card) {
+   if (mmc_card_sdio(host-mmc-card)) {
+   if ((data-blksz == 64))
+   mdelay(2);
+   }
+   }
+
/* For now we try to use DMA whenever we won't need partial FIFO
 * reads or writes, either for the whole transfer (as tested here)
 * or for any individual scatterlist segment (tested when we call
@@ -862,6 +901,19 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, 
struct mmc_data *data)
 {
host-data = NULL;
 
+   if (host-mmc-caps  MMC_CAP_SDIO_IRQ) {
+   /* SDIO Interrupt Detection work-around as suggested by
+* Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata
+* 2.1.5)
+* Signal SDIO interrupt only if it is enabled by core
+*/
+   if (host-sdio_int  (!((readl(host-base + DAVINCI_SDIOST0))
+SDIOST0_DAT1_HI))) {
+   writel(SDIOIST_IOINT, host-base + DAVINCI_SDIOIST);
+   mmc_signal_sdio_irq(host-mmc);
+   }
+   }
+
if (host-do_dma) {
davinci_abort_dma(host);
 
@@ -928,6 +980,22 @@ davinci_abort_data(struct mmc_davinci_host *host, struct 
mmc_data *data)
mmc_davinci_reset_ctrl(host, 0);
 }
 
+static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id)
+{
+   struct mmc_davinci_host *host = (struct mmc_davinci_host