diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-04 07:59:18 +0200 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 21:25:52 +0200 |
commit | f75979b77fb20b01522d8fab96dfc76cc9f42420 (patch) | |
tree | e5c4c4fdf04b2fbf079c0be25edfc416279b072e /drivers/mmc/host/sdhci.c | |
parent | 15b82b46de358a574c2a6a6dea4c8076bef7ac43 (diff) | |
download | blackbird-op-linux-f75979b77fb20b01522d8fab96dfc76cc9f42420.tar.gz blackbird-op-linux-f75979b77fb20b01522d8fab96dfc76cc9f42420.zip |
sdhci: sdio interrupt support
Add support for relaying the sdio interrupt signal from the card.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c63edc5c17e4..228ce42371dc 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -800,10 +800,35 @@ static int sdhci_get_ro(struct mmc_host *mmc) return !(present & SDHCI_WRITE_PROTECT); } +static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct sdhci_host *host; + unsigned long flags; + u32 ier; + + host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + + ier = readl(host->ioaddr + SDHCI_INT_ENABLE); + + ier &= ~SDHCI_INT_CARD_INT; + if (enable) + ier |= SDHCI_INT_CARD_INT; + + writel(ier, host->ioaddr + SDHCI_INT_ENABLE); + writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); + + mmiowb(); + + spin_unlock_irqrestore(&host->lock, flags); +} + static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, .get_ro = sdhci_get_ro, + .enable_sdio_irq = sdhci_enable_sdio_irq, }; /*****************************************************************************\ @@ -1012,6 +1037,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) irqreturn_t result; struct sdhci_host* host = dev_id; u32 intmask; + int cardint = 0; spin_lock(&host->lock); @@ -1056,6 +1082,11 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~SDHCI_INT_BUS_POWER; + if (intmask & SDHCI_INT_CARD_INT) + cardint = 1; + + intmask &= ~SDHCI_INT_CARD_INT; + if (intmask) { printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), intmask); @@ -1070,6 +1101,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) out: spin_unlock(&host->lock); + /* + * We have to delay this as it calls back into the driver. + */ + if (cardint) + mmc_signal_sdio_irq(host->mmc); + return result; } @@ -1309,7 +1346,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED; |