==============
SDIO support in the MMC framework seems to involve no more than just
being able to report SDIO irqs. Here's (untested) code to do that.
# REVISIT -- errata doc, usage note 2.1.5, sez:
# - issue: must check SDIOIST.IONT and sample SDIOST0.DAT1 to detect
# level triggered SDIO using edge detect in ctrlr, given races
# between irq enable at sdio card and (then) controller
# - before enable: sample DAT1 (INTPRD=1, DAT1=1)
# ... may have been raised before enabled in ctrlr
# - does sdio_irq() clear irq status as it reads it?
# ... mask irq before signaling irq
---
drivers/mmc/host/davinci_mmc.c | 53 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
@@ -163,6 +163,7 @@ struct mmc_davinci_host {
void __iomem *base;
struct resource *mem_res;
int irq;
+ int sdio_irq;
unsigned char bus_mode;
#define DAVINCI_MMC_DATADIR_NONE 0
@@ -1011,6 +1012,35 @@ static irqreturn_t mmc_davinci_irq(int i
return IRQ_HANDLED;
}
+static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id)
+{
+ struct mmc_davinci_host *host = dev_id;
+ u32 sdiost;
+
+ sdiost = readl(host->base + DAVINCI_SDIOST);
+ if (sdiost & BIT(0))
+ mmc_signal_sdio_irq(host->mmc);
+ return IRQ_HANDLED;
+}
+
+static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct mmc_davinci_host *host = mmc_priv(mmc);
+ u32 sdioen;
+
+ /* FIXME card may already be issuing (level) IRQ ... so when
+ * enabling, check DAT1 here and handle the case where we won't
+ * trigger since the edge already happened.
+ */
+
+ sdioen = readl(host->base + DAVINCI_SDIOEN);
+ if (!enable)
+ sdioen &= ~BIT(0);
+ else
+ sdioen |= BIT(0);
+ writel(sdioen, host->base + DAVINCI_SDIOEN);
+}
+
static int mmc_davinci_get_cd(struct mmc_host *mmc)
{
struct platform_device *pdev = to_platform_device(mmc->parent);
@@ -1036,6 +1066,7 @@ static struct mmc_host_ops mmc_davinci_o
.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,
};
/*----------------------------------------------------------------------*/
@@ -1058,6 +1089,8 @@ static void __init init_mmcsd_host(struc
writel(0x1FFF, host->base + DAVINCI_MMCTOR);
writel(0xFFFF, host->base + DAVINCI_MMCTOD);
+ writel(0, host->base + DAVINCI_SDIOEN);
+
writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_DATRST,
host->base + DAVINCI_MMCCTL);
writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_CMDRST,
@@ -1132,9 +1165,24 @@ static int __init davinci_mmcsd_probe(st
/* REVISIT: someday, support IRQ-driven card detection. */
mmc->caps |= MMC_CAP_NEEDS_POLL;
- if (!pdata || pdata->wires == 4 || pdata->wires == 0)
+ if (!pdata || pdata->wires == 4 || pdata->wires == 0) {
mmc->caps |= MMC_CAP_4_BIT_DATA;
+ /* for now, no support for IRQs (on DAT1) except
+ * when 4-wire mode is supported.
+ * REVISIT there's a DAT2 read-wait IRQ too ...
+ */
+ host->sdio_irq = platform_get_irq(pdev, 1);
+ if (host->sdio_irq > 0) {
+ ret = request_irq(host->sdio_irq,
+ mmc_davinci_sdio_irq, 0,
+ mmc_hostname(mmc), host);
+ if (ret == 0)
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
+ }
+ }
+
+
host->version = pdata->version;
mmc->ops = &mmc_davinci_ops;
@@ -1215,6 +1263,9 @@ static int __exit davinci_mmcsd_remove(s
platform_set_drvdata(pdev, NULL);
if (host) {
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+ free_irq(host->sdio_irq, host);
+
mmc_remove_host(host->mmc);
free_irq(host->irq, host);