Added SDIO Support for Davinci.  Tested on DM355 EVM with Marvell SD8385 and
SD8686 cards using Libertas SDIO driver. This requires additional patches for
Libertas SDIO interface as indicated in the linux-wireless mailing list and
as referenced in the following links

http://marc.info/?l=linux-wireless&m=127136330220026&w=2
http://marc.info/?l=linux-wireless&m=127136362020814&w=2

Signed-off-by: Alagu Sankar <alagusan...@embwise.com>
---
 drivers/mmc/host/davinci_mmc.c |   98 +++++++++++++++++++++++++++++++++++++--
 1 files changed, 93 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index e4d1591..4afa6bf 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -66,8 +66,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 +135,23 @@
 /* MMCSD Init clock in Hz in opendrain mode */
 #define MMCSD_INIT_CLOCK               200000
 
+/* DAVINCI_SDIOCTL definitions */
+#define SDIOCTL_RDWTRQ_SET    BIT(0)
+#define SDIOCTL_RDWTCR_SET    BIT(1)
+
+/* DAVINCI_SDIOST0 definitions */
+#define SDIOST0_DAT1_HI       BIT(0)
+#define SDIOST0_INTPRD        BIT(1)
+#define SDIOST0_RDWTST        BIT(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 MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
@@ -147,6 +164,8 @@
 
 #define MAX_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 +183,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 +203,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
@@ -866,6 +886,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);
 
@@ -932,6 +965,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 *)dev_id;
+       unsigned int status;
+
+       status = readl(host->base + DAVINCI_SDIOIST);
+       if (status & SDIOIST_IOINT) {
+               dev_dbg(mmc_dev(host->mmc),
+                               "SDIO interrupt status %x\n", status);
+               writel(status | SDIOIST_IOINT,
+                               host->base + DAVINCI_SDIOIST);
+               mmc_signal_sdio_irq(host->mmc);
+       }
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
 {
        struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id;
@@ -1076,11 +1125,34 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc)
        return config->get_ro(pdev->id);
 }
 
+static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct mmc_davinci_host *host = mmc_priv(mmc);
+
+       if (enable) {
+               if (!((readl(host->base + DAVINCI_SDIOST0))
+                                       & SDIOST0_DAT1_HI)) {
+                       writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
+                       mmc_signal_sdio_irq(host->mmc);
+               } else {
+                       host->sdio_int = 1;
+                       writel(readl(host->base + DAVINCI_SDIOIEN) |
+                               SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN);
+               }
+       } else {
+               host->sdio_int = 0;
+               writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN,
+                               host->base + DAVINCI_SDIOIEN);
+       }
+
+}
+
 static struct mmc_host_ops mmc_davinci_ops = {
        .request        = mmc_davinci_request,
        .set_ios        = mmc_davinci_set_ios,
        .get_cd         = mmc_davinci_get_cd,
        .get_ro         = mmc_davinci_get_ro,
+       .enable_sdio_irq = mmc_davinci_enable_sdio_irq,
 };
 
 /*----------------------------------------------------------------------*/
@@ -1209,7 +1281,8 @@ static int __init davinci_mmcsd_probe(struct 
platform_device *pdev)
                host->nr_sg = MAX_NR_SG;
 
        host->use_dma = use_dma;
-       host->irq = irq;
+       host->mmc_irq = irq;
+       host->sdio_irq = platform_get_irq(pdev, 1);
 
        if (host->use_dma && davinci_acquire_dma_channels(host) != 0)
                host->use_dma = 0;
@@ -1272,6 +1345,19 @@ static int __init davinci_mmcsd_probe(struct 
platform_device *pdev)
        if (ret)
                goto out;
 
+       /* Failures in SDIO IRQ registration are ignored as the driver
+        * can still work in polled mode.
+        */
+       if (host->sdio_irq != NO_IRQ) {
+               ret = request_irq(host->sdio_irq,
+                               mmc_davinci_sdio_irq, 0,
+                               DAVINCI_SDIO_IRQ(pdev->id), host);
+               if (ret == 0) {
+                       mmc->caps |= MMC_CAP_SDIO_IRQ;
+                       host->sdio_int = 0;
+               }
+       }
+
        rename_region(mem, mmc_hostname(mmc));
 
        dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n",
@@ -1315,7 +1401,9 @@ static int __exit davinci_mmcsd_remove(struct 
platform_device *pdev)
                mmc_davinci_cpufreq_deregister(host);
 
                mmc_remove_host(host->mmc);
-               free_irq(host->irq, host);
+               free_irq(host->mmc_irq, host);
+               if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+                       free_irq(host->sdio_irq, host);
 
                davinci_release_dma_channels(host);
 
-- 
1.6.0.6

_______________________________________________
Davinci-linux-open-source mailing list
Davinci-linux-open-source@linux.davincidsp.com
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to