| From 82db957f7a037e60d56f38437d5d0e8517cfd3f9 Mon Sep 17 00:00:00 2001 |
| From: Simon Horman <horms@verge.net.au> |
| Date: Thu, 25 Aug 2011 10:27:26 +0900 |
| Subject: mmc: tmio: Provide separate interrupt handlers |
| |
| Provide separate interrupt handlers which may be used by platforms where |
| SDHI has three interrupt sources. |
| |
| This patch also removes the commented-out handling of CRC and other errors. |
| |
| Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de> |
| Acked-by: Magnus Damm <magnus.damm@gmail.com> |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| Signed-off-by: Chris Ball <cjb@laptop.org> |
| (cherry picked from commit 7729c7a232a95360fa17ffe8beb1adb621bc0ba0) |
| |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| --- |
| drivers/mmc/host/tmio_mmc.h | 3 + |
| drivers/mmc/host/tmio_mmc_pio.c | 131 +++++++++++++++++++++++++--------------- |
| 2 files changed, 86 insertions(+), 48 deletions(-) |
| |
| diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h |
| index 1cf8db5..3020f98 100644 |
| --- a/drivers/mmc/host/tmio_mmc.h |
| +++ b/drivers/mmc/host/tmio_mmc.h |
| @@ -97,6 +97,9 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); |
| void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); |
| void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); |
| irqreturn_t tmio_mmc_irq(int irq, void *devid); |
| +irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid); |
| +irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid); |
| +irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid); |
| |
| static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, |
| unsigned long *flags) |
| diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c |
| index f0c7830..6275e3d 100644 |
| --- a/drivers/mmc/host/tmio_mmc_pio.c |
| +++ b/drivers/mmc/host/tmio_mmc_pio.c |
| @@ -545,44 +545,20 @@ out: |
| spin_unlock(&host->lock); |
| } |
| |
| -irqreturn_t tmio_mmc_irq(int irq, void *devid) |
| +static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host, |
| + int *ireg, int *status) |
| { |
| - struct tmio_mmc_host *host = devid; |
| - struct mmc_host *mmc = host->mmc; |
| - struct tmio_mmc_data *pdata = host->pdata; |
| - unsigned int ireg, status; |
| - unsigned int sdio_ireg, sdio_status; |
| - |
| - pr_debug("MMC IRQ begin\n"); |
| - |
| - status = sd_ctrl_read32(host, CTL_STATUS); |
| - ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; |
| + *status = sd_ctrl_read32(host, CTL_STATUS); |
| + *ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; |
| |
| - sdio_ireg = 0; |
| - if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { |
| - sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); |
| - sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & |
| - ~host->sdio_irq_mask; |
| - |
| - sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); |
| - |
| - if (sdio_ireg && !host->sdio_irq_enabled) { |
| - pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", |
| - sdio_status, host->sdio_irq_mask, sdio_ireg); |
| - tmio_mmc_enable_sdio_irq(mmc, 0); |
| - goto out; |
| - } |
| - |
| - if (mmc->caps & MMC_CAP_SDIO_IRQ && |
| - sdio_ireg & TMIO_SDIO_STAT_IOIRQ) |
| - mmc_signal_sdio_irq(mmc); |
| - |
| - if (sdio_ireg) |
| - goto out; |
| - } |
| + pr_debug_status(*status); |
| + pr_debug_status(*ireg); |
| +} |
| |
| - pr_debug_status(status); |
| - pr_debug_status(ireg); |
| +static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host, |
| + int ireg, int status) |
| +{ |
| + struct mmc_host *mmc = host->mmc; |
| |
| /* Card insert / remove attempts */ |
| if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { |
| @@ -592,43 +568,102 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) |
| ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) && |
| !work_pending(&mmc->detect.work)) |
| mmc_detect_change(host->mmc, msecs_to_jiffies(100)); |
| - goto out; |
| + return true; |
| } |
| |
| - /* CRC and other errors */ |
| -/* if (ireg & TMIO_STAT_ERR_IRQ) |
| - * handled |= tmio_error_irq(host, irq, stat); |
| - */ |
| + return false; |
| +} |
| + |
| +irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid) |
| +{ |
| + unsigned int ireg, status; |
| + struct tmio_mmc_host *host = devid; |
| |
| + tmio_mmc_card_irq_status(host, &ireg, &status); |
| + __tmio_mmc_card_detect_irq(host, ireg, status); |
| + |
| + return IRQ_HANDLED; |
| +} |
| +EXPORT_SYMBOL(tmio_mmc_card_detect_irq); |
| + |
| +static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, |
| + int ireg, int status) |
| +{ |
| /* Command completion */ |
| if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { |
| tmio_mmc_ack_mmc_irqs(host, |
| TMIO_STAT_CMDRESPEND | |
| TMIO_STAT_CMDTIMEOUT); |
| tmio_mmc_cmd_irq(host, status); |
| - goto out; |
| + return true; |
| } |
| |
| /* Data transfer */ |
| if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { |
| tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); |
| tmio_mmc_pio_irq(host); |
| - goto out; |
| + return true; |
| } |
| |
| /* Data transfer completion */ |
| if (ireg & TMIO_STAT_DATAEND) { |
| tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND); |
| tmio_mmc_data_irq(host); |
| - goto out; |
| + return true; |
| } |
| |
| - pr_warning("tmio_mmc: Spurious irq, disabling! " |
| - "0x%08x 0x%08x 0x%08x\n", status, host->sdcard_irq_mask, ireg); |
| - pr_debug_status(status); |
| - tmio_mmc_disable_mmc_irqs(host, status & ~host->sdcard_irq_mask); |
| + return false; |
| +} |
| + |
| +irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid) |
| +{ |
| + unsigned int ireg, status; |
| + struct tmio_mmc_host *host = devid; |
| + |
| + tmio_mmc_card_irq_status(host, &ireg, &status); |
| + __tmio_mmc_sdcard_irq(host, ireg, status); |
| + |
| + return IRQ_HANDLED; |
| +} |
| +EXPORT_SYMBOL(tmio_mmc_sdcard_irq); |
| + |
| +irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid) |
| +{ |
| + struct tmio_mmc_host *host = devid; |
| + struct mmc_host *mmc = host->mmc; |
| + struct tmio_mmc_data *pdata = host->pdata; |
| + unsigned int ireg, status; |
| + |
| + if (!(pdata->flags & TMIO_MMC_SDIO_IRQ)) |
| + return IRQ_HANDLED; |
| + |
| + status = sd_ctrl_read16(host, CTL_SDIO_STATUS); |
| + ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask; |
| + |
| + sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL); |
| + |
| + if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) |
| + mmc_signal_sdio_irq(mmc); |
| + |
| + return IRQ_HANDLED; |
| +} |
| +EXPORT_SYMBOL(tmio_mmc_sdio_irq); |
| + |
| +irqreturn_t tmio_mmc_irq(int irq, void *devid) |
| +{ |
| + struct tmio_mmc_host *host = devid; |
| + unsigned int ireg, status; |
| + |
| + pr_debug("MMC IRQ begin\n"); |
| + |
| + tmio_mmc_card_irq_status(host, &ireg, &status); |
| + if (__tmio_mmc_card_detect_irq(host, ireg, status)) |
| + return IRQ_HANDLED; |
| + if (__tmio_mmc_sdcard_irq(host, ireg, status)) |
| + return IRQ_HANDLED; |
| + |
| + tmio_mmc_sdio_irq(irq, devid); |
| |
| -out: |
| return IRQ_HANDLED; |
| } |
| EXPORT_SYMBOL(tmio_mmc_irq); |
| -- |
| 1.7.10.2.565.gbd578b5 |
| |