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