static void int_callback(struct urb *urb) { struct ushc_data *ushc = urb->context; u8 status, last_status; if (urb->status < 0) return; status = ushc->int_data->status; last_status = ushc->last_status; ushc->last_status = status; /* * Ignore the card interrupt status on interrupt transfers that * were submitted while card interrupts where disabled. * * This avoid occasional spurious interrupts when enabling * interrupts immediately after clearing the source on the card. */ if (!test_and_clear_bit(IGNORE_NEXT_INT, &ushc->flags) && test_bit(INT_EN, &ushc->flags) && status & USHC_INT_STATUS_SDIO_INT) { mmc_signal_sdio_irq(ushc->mmc); } if ((status ^ last_status) & USHC_INT_STATUS_CARD_PRESENT) mmc_detect_change(ushc->mmc, msecs_to_jiffies(100)); if (!test_bit(INT_EN, &ushc->flags)) set_bit(IGNORE_NEXT_INT, &ushc->flags); usb_submit_urb(ushc->int_urb, GFP_ATOMIC); }
static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_ssp *ssp = &host->ssp; unsigned long flags; spin_lock_irqsave(&host->lock, flags); host->sdio_irq_en = enable; if (enable) { writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); writel(BM_SSP_CTRL1_SDIO_IRQ_EN, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_SET); } else { writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); writel(BM_SSP_CTRL1_SDIO_IRQ_EN, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); } spin_unlock_irqrestore(&host->lock, flags); if (enable && readl(ssp->base + HW_SSP_STATUS(ssp)) & BM_SSP_STATUS_SDIO_IRQ) mmc_signal_sdio_irq(host->mmc); }
static irqreturn_t rk28_sdio_mci_irq(int irq, void *devid) { volatile u32 ints, raw_ints; struct rk28_sdio_priv *priv = (struct rk28_sdio_priv *)devid; struct mmc_command *mmc_cmd = priv->mrq->cmd; disable_irq(irq); ints = rk28_host_readl(priv, SDMMC_MINTSTS); raw_ints = rk28_host_readl(priv, SDMMC_RINTSTS); if (raw_ints & ALL_ERRORS) { printk("CMD: %d <arg=%x> FAIL raw_ints: %x masked ints: %x\n", mmc_cmd->opcode, mmc_cmd->arg, raw_ints, ints); //if (raw_ints & (INT_RTO | INT_DRTO | INT_HTO)) // mmc_cmd->error = -ETIMEDOUT; //else mmc_cmd->error = -EIO; if ((priv->dma_chan != -1) && (mmc_cmd->opcode == 53)) rk28_sdio_dma_done(0, (void *)priv); mmc_request_done(priv->mmc, priv->mrq); rk28_host_writel(priv, SDMMC_RINTSTS, (raw_ints & ALL_ERRORS) | INT_CD | INT_DTO); goto out; } if (ints & INT_CD) { mmc_cmd->resp[0] = rk28_host_readl(priv, SDMMC_RESP0); if (mmc_cmd->opcode != 53) { mmc_request_done(priv->mmc, priv->mrq); } rk28_host_writel(priv, SDMMC_RINTSTS, INT_CD); } if (ints & INT_DTO) { mmc_cmd->data->bytes_xfered = (mmc_cmd->data->blocks * mmc_cmd->data->blksz); mmc_request_done(priv->mmc, priv->mrq); rk28_host_writel(priv, SDMMC_RINTSTS, INT_DTO); } out: if (ints & INT_SDIO) { mmc_signal_sdio_irq(priv->mmc); rk28_host_writel(priv, SDMMC_RINTSTS, INT_SDIO); } enable_irq(irq); return IRQ_HANDLED; }
/** * s3cmci_check_sdio_irq - test whether the SDIO IRQ is being signalled * @host: The host to check. * * Test to see if the SDIO interrupt is being signalled in case the * controller has failed to re-detect a card interrupt. Read GPE8 and * see if it is low and if so, signal a SDIO interrupt. * * This is currently called if a request is finished (we assume that the * bus is now idle) and when the SDIO IRQ is enabled in case the IRQ is * already being indicated. */ static void s3cmci_check_sdio_irq(struct s3cmci_host *host) { if (host->sdio_irqen) { if (gpio_get_value(S3C2410_GPE(8)) == 0) { pr_debug("%s: signalling irq\n", __func__); mmc_signal_sdio_irq(host->mmc); } } }
/* * ubicom32sd_mmc_enable_sdio_irq */ static void ubicom32sd_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); ud->int_en = enable; if (enable && ud->int_pend) { ud->int_pend = 0; mmc_signal_sdio_irq(mmc); } }
/* * Handle completion of command and data transfers. */ static irqreturn_t ak98_sdio_irq(int irq, void *dev_id) { struct ak98_mci_host *host = dev_id; u32 status; int ret = 0; PK("+%s ", __func__); spin_lock(&host->lock); do { struct mmc_command *cmd; struct mmc_data *data; status = readl(host->base + AK98MCISTATUS); PK(" status= 0x%08x\n", status); #ifdef AKMCI_INNERFIFO_PIO if (host->data) ak98_sdio_pio_irq(host, status); #endif cmd = host->cmd; if (status & (MCI_RESPCRCFAIL|MCI_RESPTIMEOUT|MCI_CMDSENT|MCI_RESPEND) && cmd) ak98_sdio_cmd_irq(host, cmd, status); data = host->data; if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_DATAEND|MCI_DATABLOCKEND|MCI_STARTBIT_ERR) && data) ak98_sdio_data_irq(host, data, status); if (status & MCI_SDIOINT) { /*must disable sdio irq ,than read status to clear the sdio status, else sdio irq will come again. */ ak98_enable_sdio_irq(host->mmc,0); readl(host->base + AK98MCISTATUS); mmc_signal_sdio_irq(host->mmc); } ret = 1; } while (0); spin_unlock(&host->lock); PK("-%s, irqmask: 0x%08x\n", __func__, readl(host->base + AK98MCIMASK)); return IRQ_RETVAL(ret); }
static void sslsd_evt(void *ctx, sd_cmd_p ev) { sslsd_host *host = ctx; if (ev > SDHC_EVT_MAX) { sslsd_cmd_done(host, ev); } else if (ev == SDHC_EVT_INS || ev == SDHC_EVT_REM) { mmc_detect_change(host->mmc, 0); } else if (ev == SDHC_EVT_IO) { //printk("sslsd: evt err - IO interrupt\n"); mmc_signal_sdio_irq(host->mmc); } }
static irqreturn_t msmsdcc_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; void __iomem *base = host->base; u32 status; int ret = 0; int cardint = 0; spin_lock(&host->lock); do { status = readl(base + MMCISTATUS); status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); writel(status, base + MMCICLEAR); msmsdcc_handle_irq_data(host, status, base); if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT) && host->curr.cmd) { msmsdcc_do_cmdirq(host, status); } if (status & MCI_SDIOINTOPER) { cardint = 1; status &= ~MCI_SDIOINTOPER; } ret = 1; } while (status); spin_unlock(&host->lock); /* * We have to delay handling the card interrupt as it calls * back into the driver. */ if (cardint) mmc_signal_sdio_irq(host->mmc); return IRQ_RETVAL(ret); }
static irqreturn_t sunximmc_irq(int irq, void *dev_id) { struct sunxi_mmc_host *smc_host = dev_id; unsigned long iflags; spin_lock_irqsave(&smc_host->lock, iflags); smc_host->sdio_int = 0; if (smc_host->cd_mode == CARD_DETECT_BY_DATA3) { smc_host->change = 0; } sdxc_check_status(smc_host); if (smc_host->wait == SDC_WAIT_FINALIZE) { tasklet_schedule(&smc_host->tasklet); } spin_unlock_irqrestore(&smc_host->lock, iflags); /* sdio interrupt call */ if (smc_host->sdio_int) { mmc_signal_sdio_irq(smc_host->mmc); // SMC_MSG("- sdio int -\n"); } /* card detect change */ if (smc_host->cd_mode == CARD_DETECT_BY_DATA3) { if (smc_host->change) { mmc_detect_change(smc_host->mmc, msecs_to_jiffies(300)); } } return IRQ_HANDLED; }
static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) { struct mxs_mmc_host *host = dev_id; struct mmc_command *cmd = host->cmd; struct mmc_data *data = host->data; struct mxs_ssp *ssp = &host->ssp; u32 stat; spin_lock(&host->lock); stat = readl(ssp->base + HW_SSP_CTRL1(ssp)); writel(stat & MXS_MMC_IRQ_BITS, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); spin_unlock(&host->lock); if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) mmc_signal_sdio_irq(host->mmc); if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ) cmd->error = -ETIMEDOUT; else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ) cmd->error = -EIO; if (data) { if (stat & (BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | BM_SSP_CTRL1_RECV_TIMEOUT_IRQ)) data->error = -ETIMEDOUT; else if (stat & BM_SSP_CTRL1_DATA_CRC_IRQ) data->error = -EILSEQ; else if (stat & (BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)) data->error = -EIO; } return IRQ_HANDLED; }
/* * ubicom32sd_interrupt */ static irqreturn_t ubicom32sd_interrupt(int irq, void *dev) { struct mmc_host *mmc = (struct mmc_host *)dev; struct mmc_request *mrq; struct ubicom32sd_data *ud; u32_t int_status; if (!mmc) { return IRQ_HANDLED; } ud = (struct ubicom32sd_data *)mmc_priv(mmc); if (!ud) { return IRQ_HANDLED; } int_status = ud->regs->int_status; ud->regs->int_status &= ~int_status; if (int_status & SDTIO_VP_INT_STATUS_SDIO_INT) { if (ud->int_en) { ud->int_pend = 0; mmc_signal_sdio_irq(mmc); } else { ud->int_pend++; } } if (!(int_status & SDTIO_VP_INT_STATUS_DONE)) { return IRQ_HANDLED; } mrq = ud->mrq; if (!mrq) { sd_printk("%s: Spurious interrupt", mmc_hostname(mmc)); return IRQ_HANDLED; } ud->mrq = NULL; /* * SDTIO_VP_INT_DONE */ if (mrq->cmd->flags & MMC_RSP_PRESENT) { struct mmc_command *cmd = mrq->cmd; cmd->error = 0; if ((cmd->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_CRC)) { cmd->error = -EILSEQ; sd_printk("%s:\t\t\tRSP CRC Error\n", mmc_hostname(mmc)); } else if (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT) { cmd->error = -ETIMEDOUT; sd_printk("%s:\t\t\tRSP Timeout\n", mmc_hostname(mmc)); goto done; } else if (cmd->flags & MMC_RSP_136) { cmd->resp[0] = ud->regs->cmd_rsp0; cmd->resp[1] = ud->regs->cmd_rsp1; cmd->resp[2] = ud->regs->cmd_rsp2; cmd->resp[3] = ud->regs->cmd_rsp3; } else { cmd->resp[0] = ud->regs->cmd_rsp0; } sd_printk("%s:\t\t\tResponse %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); } if (mrq->data) { struct mmc_data *data = mrq->data; if (int_status & SDTIO_VP_INT_STATUS_DATA_TIMEOUT) { data->error = -ETIMEDOUT; sd_printk("%s:\t\t\tData Timeout\n", mmc_hostname(mmc)); goto done; } else if (int_status & SDTIO_VP_INT_STATUS_DATA_CRC_ERR) { data->error = -EILSEQ; sd_printk("%s:\t\t\tData CRC\n", mmc_hostname(mmc)); goto done; } else if (int_status & SDTIO_VP_INT_STATUS_DATA_PROG_ERR) { data->error = -EILSEQ; sd_printk("%s:\t\t\tData Program Error\n", mmc_hostname(mmc)); goto done; } else { data->error = 0; data->bytes_xfered = ud->regs->data_bytes_transferred; } } if (mrq->stop && (mrq->stop->flags & MMC_RSP_PRESENT)) { struct mmc_command *stop = mrq->stop; stop->error = 0; if ((stop->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_CRC)) { stop->error = -EILSEQ; sd_printk("%s:\t\t\tStop RSP CRC Error\n", mmc_hostname(mmc)); } else if (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT) { stop->error = -ETIMEDOUT; sd_printk("%s:\t\t\tStop RSP Timeout\n", mmc_hostname(mmc)); goto done; } else if (stop->flags & MMC_RSP_136) { stop->resp[0] = ud->regs->stop_rsp0; stop->resp[1] = ud->regs->stop_rsp1; stop->resp[2] = ud->regs->stop_rsp2; stop->resp[3] = ud->regs->stop_rsp3; } else { stop->resp[0] = ud->regs->stop_rsp0; } sd_printk("%s:\t\t\tStop Response %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), stop->resp[0], stop->resp[1], stop->resp[2], stop->resp[3], stop->error); } done: mmc_request_done(mmc, mrq); return IRQ_HANDLED; }
static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id) { irqreturn_t result = IRQ_NONE; struct bcm2835_host *host = dev_id; u32 unexpected = 0, early = 0; int loops = 0; #ifndef CONFIG_ARCH_BCM2835 int cardint = 0; #endif spin_lock(&host->lock); for (loops = 0; loops < 1; loops++) { u32 intmask, handled; intmask = bcm2835_sdhost_read(host, SDHSTS); handled = intmask & (SDHSTS_BUSY_IRPT | SDHSTS_BLOCK_IRPT | SDHSTS_SDIO_IRPT | SDHSTS_DATA_FLAG); if ((handled == SDHSTS_DATA_FLAG) && (loops == 0) && !host->data) { pr_err("%s: sdhost_irq data interrupt 0x%08x even " "though no data operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); bcm2835_sdhost_dumpregs(host); } if (!handled) break; if (loops) early |= handled; result = IRQ_HANDLED; /* Clear all interrupts and notifications */ bcm2835_sdhost_write(host, intmask, SDHSTS); if (intmask & SDHSTS_BUSY_IRPT) handled |= bcm2835_sdhost_busy_irq(host, intmask); /* There is no true data interrupt status bit, so it is necessary to qualify the data flag with the interrupt enable bit */ if ((intmask & SDHSTS_DATA_FLAG) && (host->hcfg & SDHCFG_DATA_IRPT_EN)) handled |= bcm2835_sdhost_data_irq(host, intmask); if (intmask & SDHSTS_BLOCK_IRPT) handled |= bcm2835_sdhost_block_irq(host, intmask); if (intmask & SDHSTS_SDIO_IRPT) { #ifndef CONFIG_ARCH_BCM2835 cardint = 1; #else bcm2835_sdhost_enable_sdio_irq_nolock(host, false); host->thread_isr |= SDHSTS_SDIO_IRPT; result = IRQ_WAKE_THREAD; #endif } unexpected |= (intmask & ~handled); } mmiowb(); spin_unlock(&host->lock); if (early) pr_debug("%s: early %x (loops %d)\n", mmc_hostname(host->mmc), early, loops); if (unexpected) { pr_err("%s: unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), unexpected); bcm2835_sdhost_dumpregs(host); } #ifndef CONFIG_ARCH_BCM2835 if (cardint) mmc_signal_sdio_irq(host->mmc); #endif return result; }
static irqreturn_t msmsdcc_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; void __iomem *base = host->base; u32 status; int ret = 0; int cardint = 0; spin_lock(&host->lock); do { struct mmc_data *data; status = readl(base + MMCISTATUS); #if IRQ_DEBUG msmsdcc_print_status(host, "irq0-r", status); #endif status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); writel(status, base + MMCICLEAR); #if IRQ_DEBUG msmsdcc_print_status(host, "irq0-p", status); #endif data = host->curr.data; if (data) { /* Check for data errors */ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT| MCI_TXUNDERRUN|MCI_RXOVERRUN)) { msmsdcc_data_err(host, data, status); host->curr.data_xfered = 0; if (host->dma.sg) msm_dmov_stop_cmd(host->dma.channel, &host->dma.hdr, 0); else { msmsdcc_stop_data(host); if (!data->stop) msmsdcc_request_end(host, data->mrq); else msmsdcc_start_command(host, data->stop, 0); } } /* Check for data done */ if (!host->curr.got_dataend && (status & MCI_DATAEND)) host->curr.got_dataend = 1; if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND)) { host->curr.got_datablkend = 1; } if (host->curr.got_dataend && host->curr.got_datablkend) { /* * If DMA is still in progress, we complete * via the completion handler */ if (!host->dma.busy) { /* * There appears to be an issue in the * controller where if you request a * small block transfer (< fifo size), * you may get your DATAEND/DATABLKEND * irq without the PIO data irq. * * Check to see if theres still data * to be read, and simulate a PIO irq. */ if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) msmsdcc_pio_irq(1, host); msmsdcc_stop_data(host); if (!data->error) host->curr.data_xfered = host->curr.xfer_size; if (!data->stop) msmsdcc_request_end(host, data->mrq); else msmsdcc_start_command(host, data->stop, 0); } } } if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT) && host->curr.cmd) { msmsdcc_do_cmdirq(host, status); } if (status & MCI_SDIOINTOPER) { cardint = 1; status &= ~MCI_SDIOINTOPER; } ret = 1; } while (status); spin_unlock(&host->lock); /* * We have to delay handling the card interrupt as it calls * back into the driver. */ if (cardint) { mmc_signal_sdio_irq(host->mmc); } return IRQ_RETVAL(ret); }
static irqreturn_t pmpmci_irq(int irq, void *dev_id) { struct pmpmci_host *host = dev_id; struct sd_data_s *sd_data= host->platdata; struct mmc_command *cmd; u32 status; extern void gp_gpio_dump(); status = sd_data->ops->getStatus(&(sd_data->info)); //printk("\ninterrupt occur: sd irq status=%x.", status); //halSd_DumpReg(&sd_data->info); //gp_gpio_dump(); if (status & SD_MMC_S_CARDINT) /* sdio */ { //printk("\nSDIO interrupt occur: sd irq status=%x.", status); mmc_signal_sdio_irq(host->mmc); goto irq_out; } if (!host->mrq) { printk("no active mrq\n"); sd_data->ops->intrpt_enable(&(sd_data->info), SD_MMC_INT_CMDCOM | SD_MMC_INT_DATACOM | SD_MMC_INT_CMDBUFFULL | SD_MMC_INT_DATABUFFULL | SD_MMC_INT_DATABUFEMPTY , 0); goto irq_out; } cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd; if (!cmd) { printk("no active cmd\n"); sd_data->ops->intrpt_enable(&(sd_data->info), SD_MMC_INT_CMDCOM | SD_MMC_INT_DATACOM | SD_MMC_INT_CMDBUFFULL | SD_MMC_INT_DATABUFFULL | SD_MMC_INT_DATABUFEMPTY , 0); goto irq_out; } if (host->mrq && (status & SD_MMC_S_RSP_TIMEOUT)) { if (status & SD_MMC_S_CMDCOM) host->mrq->cmd->error = -ETIMEDOUT; else if (status & SD_MMC_S_DATCOM) host->mrq->data->error = -ETIMEDOUT; sd_data->ops->intrpt_enable(&(sd_data->info), SD_MMC_INT_CMDCOM | SD_MMC_INT_DATACOM | SD_MMC_INT_CMDBUFFULL | SD_MMC_INT_DATABUFFULL | SD_MMC_INT_DATABUFEMPTY , 0); //tasklet_schedule(&host->finish_task); pmpmci_finish_request(host); printk("\n%s(),%d.", __FUNCTION__, __LINE__); } else if ((status & SD_MMC_S_CMDCOM) && !(cmd->flags & MMC_RSP_PRESENT)) // Cmd complete without Response { if (host->status == HOST_S_CMD) { #if 0 pmpmci_cmd_complete(host, status); sd_data->ops->intrpt_enable(&(sd_data->info), SD_MMC_INT_CMDCOM | SD_MMC_INT_CMDBUFFULL, 0); #else sd_data->ops->intrpt_enable(&(sd_data->info), SD_MMC_INT_CMDCOM | SD_MMC_INT_CMDBUFFULL, 0); host->status = HOST_S_CMD_COM; if(host->thread_task_flags) printk("\n!!!WARNING:last thread_task_flags not clear!!!."); host->thread_task_flags |= status; wake_up_process(host->thread); #endif } } else if ((status & SD_MMC_S_CMDBUFFULL) && (cmd->flags & MMC_RSP_PRESENT)) // Cmd complete with Response { if ((host->status == HOST_S_CMD) || (host->status == HOST_S_STOP)) { #if 0 pmpmci_resp_complete(host, status); /*while(!(sd_data->ops->getStatus(&(sd_data->info)) & SD_MMC_S_CMDCOM));*/ pmpmci_cmd_complete(host, status); sd_data->ops->intrpt_enable(&(sd_data->info), SD_MMC_INT_CMDCOM | SD_MMC_INT_CMDBUFFULL, 0); #ifndef OLD_DATA_MODE if(host->flags & (HOST_F_XMIT | HOST_F_RECV)) { //printk("\nwake dat thread in irq, flags=%x.", host->flags); if(host->thread_task_flags) printk("\n!!!WARNING:last thread_task_flags not clear!!!."); host->thread_task_flags |= status; wake_up_process(host->thread); } #endif #else sd_data->ops->intrpt_enable(&(sd_data->info), SD_MMC_INT_CMDCOM | SD_MMC_INT_CMDBUFFULL, 0); host->status = HOST_S_CMD_COM; if(host->thread_task_flags) printk("\n!!!WARNING:last thread_task_flags not clear!!!."); host->thread_task_flags |= status; wake_up_process(host->thread); #endif } } #if 0 else if (!(host->flags & HOST_F_DMA)) { if ((host->flags & HOST_F_XMIT) && (status & SD_MMC_S_DATABUFEMPTY)){ #ifndef OLD_DATA_MODE host->thread_task_flags |= SDIO_TASK_SEND_PIO; wake_up_process(host->thread); #else pmpmci_send_pio(host); #endif } else if ((host->flags & HOST_F_RECV) && (status & SD_MMC_S_DATABUFFULL)){ #ifndef OLD_DATA_MODE host->thread_task_flags |= SDIO_TASK_RECV_PIO; wake_up_process(host->thread); #else pmpmci_receive_pio(host); #endif } } #endif irq_out: sd_data->ops->clearStatus(&(sd_data->info),SD_MMC_S_CLRALL); return IRQ_HANDLED; }
static irqreturn_t jz_mmc_irq(int irq, void *devid) { struct jz4740_mmc_host *host = devid; uint16_t irq_reg, status, tmp; unsigned long flags; irqreturn_t ret = IRQ_HANDLED; irq_reg = readw(host->base + JZ_REG_MMC_IREG); tmp = irq_reg; spin_lock_irqsave(&host->lock, flags); irq_reg &= ~host->irq_mask; spin_unlock_irqrestore(&host->lock, flags); tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ | JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); if (tmp != irq_reg) { dev_warn(&host->pdev->dev, "Sparse irq: %x\n", tmp & ~irq_reg); writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG); } if (irq_reg & JZ_MMC_IRQ_SDIO) { writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG); mmc_signal_sdio_irq(host->mmc); } if (!host->req || !host->cmd) { goto handled; } spin_lock_irqsave(&host->lock, flags); if (!host->waiting) { spin_unlock_irqrestore(&host->lock, flags); goto handled; } host->waiting = 0; spin_unlock_irqrestore(&host->lock, flags); del_timer(&host->timeout_timer); status = readl(host->base + JZ_REG_MMC_STATUS); if (status & JZ_MMC_STATUS_TIMEOUT_RES) { host->cmd->error = -ETIMEDOUT; } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { host->cmd->error = -EIO; } else if(status & (JZ_MMC_STATUS_CRC_READ_ERROR | JZ_MMC_STATUS_CRC_WRITE_ERROR)) { host->cmd->data->error = -EIO; } else if(status & (JZ_MMC_STATUS_CRC_READ_ERROR | JZ_MMC_STATUS_CRC_WRITE_ERROR)) { host->cmd->data->error = -EIO; } if (irq_reg & JZ_MMC_IRQ_END_CMD_RES) { jz4740_mmc_disable_irq(host, JZ_MMC_IRQ_END_CMD_RES); writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG); ret = IRQ_WAKE_THREAD; } return ret; handled: writew(0xff, host->base + JZ_REG_MMC_IREG); return IRQ_HANDLED; }
static irqreturn_t at91_mci_irq(int irq, void *devid) { struct at91mci_host *host = devid; int completed = 0; unsigned int int_status, int_mask; int_status = at91_mci_read(host, AT91_MCI_SR); int_mask = at91_mci_read(host, AT91_MCI_IMR); pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask, int_status & int_mask); int_status = int_status & int_mask; if (int_status & AT91_MCI_ERRORS) { completed = 1; if (int_status & AT91_MCI_UNRE) pr_debug("MMC: Underrun error\n"); if (int_status & AT91_MCI_OVRE) pr_debug("MMC: Overrun error\n"); if (int_status & AT91_MCI_DTOE) pr_debug("MMC: Data timeout\n"); if (int_status & AT91_MCI_DCRCE) pr_debug("MMC: CRC error in data\n"); if (int_status & AT91_MCI_RTOE) pr_debug("MMC: Response timeout\n"); if (int_status & AT91_MCI_RENDE) pr_debug("MMC: Response end bit error\n"); if (int_status & AT91_MCI_RCRCE) pr_debug("MMC: Response CRC error\n"); if (int_status & AT91_MCI_RDIRE) pr_debug("MMC: Response direction error\n"); if (int_status & AT91_MCI_RINDE) pr_debug("MMC: Response index error\n"); } else { if (int_status & AT91_MCI_TXBUFE) { pr_debug("TX buffer empty\n"); at91_mci_handle_transmitted(host); } if (int_status & AT91_MCI_ENDRX) { pr_debug("ENDRX\n"); at91_mci_post_dma_read(host); } if (int_status & AT91_MCI_RXBUFF) { pr_debug("RX buffer full\n"); at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX); completed = 1; } if (int_status & AT91_MCI_ENDTX) pr_debug("Transmit has ended\n"); if (int_status & AT91_MCI_NOTBUSY) { pr_debug("Card is ready\n"); at91_mci_update_bytes_xfered(host); completed = 1; } if (int_status & AT91_MCI_DTIP) pr_debug("Data transfer in progress\n"); if (int_status & AT91_MCI_BLKE) { pr_debug("Block transfer has ended\n"); if (host->request->data && host->request->data->blocks > 1) { completed = 1; } else { at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); } } if (int_status & AT91_MCI_SDIOIRQA) mmc_signal_sdio_irq(host->mmc); if (int_status & AT91_MCI_SDIOIRQB) mmc_signal_sdio_irq(host->mmc); if (int_status & AT91_MCI_TXRDY) pr_debug("Ready to transmit\n"); if (int_status & AT91_MCI_RXRDY) pr_debug("Ready to receive\n"); if (int_status & AT91_MCI_CMDRDY) { pr_debug("Command ready\n"); completed = at91_mci_handle_cmdrdy(host); } } if (completed) { pr_debug("Completed command\n"); at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); at91_mci_completed_command(host, int_status); } else at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); return IRQ_HANDLED; }
static irqreturn_t msmsdcc_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; void __iomem *base = host->base; u32 status; int ret = 0; int timer = 0; spin_lock(&host->lock); do { struct mmc_command *cmd; struct mmc_data *data; if (timer) { timer = 0; msmsdcc_delay(host); } status = readl(host->base + MMCISTATUS); #if IRQ_DEBUG msmsdcc_print_status(host, "irq0-r", status); #endif status &= (readl(host->base + MMCIMASK0) | MCI_DATABLOCKENDMASK); writel(status, host->base + MMCICLEAR); #if IRQ_DEBUG msmsdcc_print_status(host, "irq0-p", status); #endif if ((host->plat->dummy52_required) && (host->dummy_52_state == DUMMY_52_STATE_SENT)) { if (status & MCI_PROGDONE) { host->dummy_52_state = DUMMY_52_STATE_NONE; host->curr.cmd = NULL; spin_unlock(&host->lock); msmsdcc_request_start(host, host->curr.mrq); return IRQ_HANDLED; } break; } data = host->curr.data; #ifdef CONFIG_MMC_MSM_SDIO_SUPPORT if (status & MCI_SDIOINTROPE) mmc_signal_sdio_irq(host->mmc); #endif /* * Check for proper command response */ cmd = host->curr.cmd; if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT | MCI_PROGDONE)) && cmd) { host->curr.cmd = NULL; cmd->resp[0] = readl(base + MMCIRESPONSE0); cmd->resp[1] = readl(base + MMCIRESPONSE1); cmd->resp[2] = readl(base + MMCIRESPONSE2); cmd->resp[3] = readl(base + MMCIRESPONSE3); if (status & MCI_CMDTIMEOUT) { #if VERBOSE_COMMAND_TIMEOUTS pr_err("%s: Command timeout\n", mmc_hostname(host->mmc)); #endif cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc)); cmd->error = -EILSEQ; } if (!cmd->data || cmd->error) { if (host->curr.data && host->dma.sg) msm_dmov_stop_cmd(host->dma.channel, &host->dma.hdr, 0); else if (host->curr.data) { /* Non DMA */ msmsdcc_stop_data(host); timer |= msmsdcc_request_end(host, cmd->mrq); } else { /* host->data == NULL */ if (!cmd->error && host->prog_enable) { if (status & MCI_PROGDONE) { host->prog_scan = 0; host->prog_enable = 0; timer |= msmsdcc_request_end( host, cmd->mrq); } else host->curr.cmd = cmd; } else { if (host->prog_enable) { host->prog_scan = 0; host->prog_enable = 0; } timer |= msmsdcc_request_end( host, cmd->mrq); } } } else if (cmd->data) { if (!(cmd->data->flags & MMC_DATA_READ)) msmsdcc_start_data(host, cmd->data, NULL, 0); } } if (data) { /* Check for data errors */ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT| MCI_TXUNDERRUN|MCI_RXOVERRUN)) { msmsdcc_data_err(host, data, status); host->curr.data_xfered = 0; if (host->dma.sg) msm_dmov_stop_cmd(host->dma.channel, &host->dma.hdr, 0); else { msmsdcc_reset_and_restore(host); if (host->curr.data) msmsdcc_stop_data(host); if (!data->stop) timer |= msmsdcc_request_end(host, data->mrq); else { msmsdcc_start_command(host, data->stop, 0); timer = 1; } } } /* Check for data done */ if (!host->curr.got_dataend && (status & MCI_DATAEND)) host->curr.got_dataend = 1; if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND)) { host->curr.got_datablkend = 1; } if (host->curr.got_dataend && host->curr.got_datablkend) { /* * If DMA is still in progress, we complete * via the completion handler */ if (!host->dma.busy) { /* * There appears to be an issue in the * controller where if you request a * small block transfer (< fifo size), * you may get your DATAEND/DATABLKEND * irq without the PIO data irq. * * Check to see if theres still data * to be read, and simulate a PIO irq. */ if (readl(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) msmsdcc_pio_irq(1, host); msmsdcc_stop_data(host); if (!data->error) host->curr.data_xfered = host->curr.xfer_size; if (!data->stop) timer |= msmsdcc_request_end( host, data->mrq); else { #if defined (CONFIG_MACH_ACER_A1) while ((host->pdev_id == 1) && (data->flags & MMC_DATA_WRITE) && (gpio_get_value(SDCC1_DATA_0) == 0)) { udelay(5); } #endif msmsdcc_start_command(host, data->stop, 0); timer = 1; } } } } ret = 1; } while (status); spin_unlock(&host->lock); return IRQ_RETVAL(ret); }