Enable SDIO IRQ of S3C2410 in MMC

Leon lee astroli.leon at gmail.com
Thu Mar 27 12:52:39 CET 2008


Hi Samuel,
   I appied your patch in
http://svn.openmoko.org/developers/sameo/patches/ar6k-ng/ to
drivers/mmc/host/s3cmci.c.
But I can not get the interrupt from the SDIO card, so I enable IRQ
after initialization.
Now my Neo 1973 can connect to AP with my SDIO wireless card.

Sometimes s3cmci_irq will report S3C2410_SDIDSTA_CRCFAIL or
S3C2410_SDIDSTA_FIFOFAIL.
I will try to find out the root cause.

Thanks for your work.

Leon



diff -urN linux-2.6.24-orig/drivers/mmc/host/s3cmci.c
linux-2.6.24/drivers/mmc/host/s3cmci.c
--- linux-2.6.24-orig/drivers/mmc/host/s3cmci.c	2008-03-27
04:29:52.000000000 -0400
+++ linux-2.6.24/drivers/mmc/host/s3cmci.c	2008-03-27 04:59:22.000000000 -0400
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/mmc/host.h>
 #include <linux/platform_device.h>
+#include <linux/delay.h>
 #include <linux/irq.h>

 #include <asm/dma.h>
@@ -175,7 +176,14 @@

 static inline void clear_imask(struct s3cmci_host *host)
 {
-	writel(0, host->base + host->sdiimsk);
+	u32 newmask;
+
+	if (host->sdio_int)
+		writel(S3C2410_SDIIMSK_SDIOIRQ, host->base + host->sdiimsk);
+	else
+		writel(0, host->base + host->sdiimsk);
+
+	newmask = readl(host->base + host->sdiimsk);
 }

 static inline int get_data_buffer(struct s3cmci_host *host,
@@ -364,8 +372,9 @@
 		}

 		finalize_request(host);
-	} else
-		enable_irq(host->irq);
+	}
+
+	enable_irq(host->irq);
 }

 /*
@@ -416,8 +425,19 @@
 	mci_cclear	= 0;
 	mci_dclear	= 0;

+	if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {
+		if (host->sdio_int) {
+			disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
+			cardint = 1;
+			host->sdio_pending_int = 0;
+		} else {
+			host->sdio_pending_int = 1;
+		}
+		mci_dclear |= S3C2410_SDIDSTA_SDIOIRQDETECT;
+	}
+
 	if ((host->complete_what == COMPLETION_NONE) ||
-			(host->complete_what == COMPLETION_FINALIZE)) {
+	    (host->complete_what == COMPLETION_FINALIZE)) {
 		host->status = "nothing to complete";
 		clear_imask(host);
 		goto irq_out;
@@ -439,7 +459,7 @@

 	if (!host->dodma) {
 		if ((host->pio_active == XFER_WRITE) &&
-				(mci_fsta & S3C2410_SDIFSTA_TFDET)) {
+		    (mci_fsta & S3C2410_SDIFSTA_TFDET)) {

 			disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
 			tasklet_schedule(&host->pio_tasklet);
@@ -493,8 +513,10 @@
 			goto close_transfer;
 		}

-		if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
+		if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) {
 			host->complete_what = COMPLETION_XFERFINISH;
+			host->status = "ok: command response received, xfer to be done";
+		}

 		mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN;
 	}
@@ -703,7 +725,7 @@
 	writel(0, host->base + S3C2410_SDICMDARG);
 	writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
 	writel(0, host->base + S3C2410_SDICMDCON);
-	writel(0, host->base + host->sdiimsk);
+	clear_imask(host);

 	if (cmd->data && cmd->error)
 		cmd->data->error = cmd->error;
@@ -807,6 +829,9 @@
 	if (cmd->flags & MMC_RSP_136)
 		ccon |= S3C2410_SDICMDCON_LONGRSP;

+	if (cmd->data)
+		ccon |= S3C2410_SDICMDCON_WITHDATA;
+
 	writel(ccon, host->base + S3C2410_SDICMDCON);
 }

@@ -861,7 +886,7 @@
 	}

 	if (host->is2440) {
-		dcon |= S3C2440_SDIDCON_DS_WORD;
+		dcon |= S3C2440_SDIDCON_DS_BYTE;
 		dcon |= S3C2440_SDIDCON_DATSTART;
 	}

@@ -1006,7 +1031,6 @@
 	}

 	s3cmci_send_command(host, cmd);
-	enable_irq(host->irq);
 }

 static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -1082,6 +1106,8 @@
 	else
 		mci_con &= ~S3C2410_SDICON_CLOCKTYPE;

+	mci_con |= S3C2410_SDICON_SDIOIRQ;
+
 	writel(mci_con, host->base + S3C2410_SDICON);

 	if ((ios->power_mode == MMC_POWER_ON)
@@ -1119,11 +1145,29 @@
 static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
 	struct s3cmci_host *host = mmc_priv(mmc);
+	u32 con, imask;

-	if (enable)
-		enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
-	else
-		disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
+	con = readl(host->base + S3C2410_SDICON);
+	imask = readl(host->base + host->sdiimsk);
+
+	if (enable) {
+		host->sdio_int = 1;
+		con |= S3C2410_SDICON_SDIOIRQ;
+		imask |= S3C2410_SDIIMSK_SDIOIRQ;
+		if (host->sdio_pending_int) {
+			//printk("We have a pending INT\n");
+			mmc_signal_sdio_irq(host->mmc);
+			host->sdio_pending_int = 0;
+		}
+	} else {
+
+		host->sdio_int = 0;
+		con &= ~S3C2410_SDICON_SDIOIRQ;
+		imask &= ~S3C2410_SDIIMSK_SDIOIRQ;
+	}
+
+	writel(imask, host->base + host->sdiimsk);
+	writel(con, host->base + S3C2410_SDICON);
 }

 static struct mmc_host_ops s3cmci_ops = {
@@ -1178,6 +1222,8 @@
 		host->sdidata_b	= S3C2410_SDIDATA_BYTE;
 		host->clk_div	= 2;
 	}
+
+	host->sdio_int		= 0;
 	host->dodma		= host->pdata->do_dma;
 	host->complete_what 	= COMPLETION_NONE;
 	host->pio_active 	= XFER_NONE;
@@ -1287,6 +1333,10 @@
 		goto free_dmabuf;
 	}

+	mmc_detect_change(host->mmc, 500);
+
+	enable_irq(host->irq);
+
 	platform_set_drvdata(pdev, mmc);

 	dev_info(&pdev->dev, "initialisation done.\n");
diff -urN linux-2.6.24-orig/drivers/mmc/host/s3cmci.h
linux-2.6.24/drivers/mmc/host/s3cmci.h
--- linux-2.6.24-orig/drivers/mmc/host/s3cmci.h	2008-03-27
04:29:52.000000000 -0400
+++ linux-2.6.24/drivers/mmc/host/s3cmci.h	2008-03-27 04:59:29.000000000 -0400
@@ -39,6 +39,9 @@
 	unsigned		sdidata_b;
 	int			dodma;

+	int			sdio_int;
+	int			sdio_pending_int;
+
 	int			dmatogo;

 	struct mmc_request	*mrq;




More information about the openmoko-kernel mailing list