diff options
-rw-r--r-- | drivers/mmc/host/mmci.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 4f37c5d57df..c8b4bd71fad 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -179,8 +179,20 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) static void mmci_stop_data(struct mmci_host *host) { u32 clk; + unsigned int datactrl = 0; - writel(0, host->base + MMCIDATACTRL); + /* + * The ST Micro variants has a special bit + * to enable SDIO mode. This bit must remain set even when not + * doing data transfers, otherwise no SDIO interrupts can be + * received. + */ + if (host->variant->sdio && + host->mmc->card && + mmc_card_sdio(host->mmc->card)) + datactrl |= MCI_ST_DPSM_SDIOEN; + + writel(datactrl, host->base + MMCIDATACTRL); mmci_set_mask1(host, 0); /* Needed for DDR */ @@ -528,7 +540,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) if (mmc_card_sdio(host->mmc->card)) { /* * The ST Micro variants has a special bit - * to enable SDIO. + * to enable SDIO mode. This bit is set the first time + * a SDIO data transfer is done and must remain set + * after the data transfer is completed. The reason is + * because of otherwise no SDIO interrupts can be + * received. */ datactrl |= MCI_ST_DPSM_SDIOEN; @@ -845,6 +861,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); + if (status & MCI_ST_SDIOIT) + mmc_signal_sdio_irq(host->mmc); + data = host->data; if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) @@ -998,11 +1017,35 @@ static irqreturn_t mmci_cd_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static void mmci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + unsigned long flags; + struct mmci_host *host = mmc_priv(mmc); + + if (enable) { + /* + * Since the host is not claimed when doing enable + * we must handle it here. + */ + spin_lock_irqsave(&host->lock, flags); + + writel((readl(host->base + MMCIMASK0) | MCI_ST_SDIOIT), + (host->base + MMCIMASK0)); + + spin_unlock_irqrestore(&host->lock, flags); + } else { + /* We assumes the host is claimed when doing disable. */ + writel((readl(host->base + MMCIMASK0) & ~MCI_ST_SDIOIT), + (host->base + MMCIMASK0)); + } +} + static const struct mmc_host_ops mmci_ops = { .request = mmci_request, .set_ios = mmci_set_ios, .get_ro = mmci_get_ro, .get_cd = mmci_get_cd, + .enable_sdio_irq = mmci_enable_sdio_irq, }; static int __devinit mmci_probe(struct amba_device *dev, |