Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
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);

}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
/**
 * 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);
		}
	}
}
Exemplo n.º 5
0
/*
 * 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);
	}
}
Exemplo n.º 6
0
/*
 * 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);
}
Exemplo n.º 7
0
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);
	}
}
Exemplo n.º 8
0
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);
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
/*
 * 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;
}
Exemplo n.º 12
0
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);
}
Exemplo n.º 14
0
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;
}
Exemplo n.º 15
0
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;
}
Exemplo n.º 16
0
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;
}
Exemplo n.º 17
0
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);
}