in host/omap.c [719:852]
static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
{
struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
u16 status;
int end_command;
int end_transfer;
int transfer_error, cmd_error;
if (host->cmd == NULL && host->data == NULL) {
status = OMAP_MMC_READ(host, STAT);
dev_info(mmc_dev(host->slots[0]->mmc),
"Spurious IRQ 0x%04x\n", status);
if (status != 0) {
OMAP_MMC_WRITE(host, STAT, status);
OMAP_MMC_WRITE(host, IE, 0);
}
return IRQ_HANDLED;
}
end_command = 0;
end_transfer = 0;
transfer_error = 0;
cmd_error = 0;
while ((status = OMAP_MMC_READ(host, STAT)) != 0) {
int cmd;
OMAP_MMC_WRITE(host, STAT, status);
if (host->cmd != NULL)
cmd = host->cmd->opcode;
else
cmd = -1;
dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
status, cmd);
mmc_omap_report_irq(host, status);
if (host->total_bytes_left) {
if ((status & OMAP_MMC_STAT_A_FULL) ||
(status & OMAP_MMC_STAT_END_OF_DATA))
mmc_omap_xfer_data(host, 0);
if (status & OMAP_MMC_STAT_A_EMPTY)
mmc_omap_xfer_data(host, 1);
}
if (status & OMAP_MMC_STAT_END_OF_DATA)
end_transfer = 1;
if (status & OMAP_MMC_STAT_DATA_TOUT) {
dev_dbg(mmc_dev(host->mmc), "data timeout (CMD%d)\n",
cmd);
if (host->data) {
host->data->error = -ETIMEDOUT;
transfer_error = 1;
}
}
if (status & OMAP_MMC_STAT_DATA_CRC) {
if (host->data) {
host->data->error = -EILSEQ;
dev_dbg(mmc_dev(host->mmc),
"data CRC error, bytes left %d\n",
host->total_bytes_left);
transfer_error = 1;
} else {
dev_dbg(mmc_dev(host->mmc), "data CRC error\n");
}
}
if (status & OMAP_MMC_STAT_CMD_TOUT) {
/* Timeouts are routine with some commands */
if (host->cmd) {
struct mmc_omap_slot *slot =
host->current_slot;
if (slot == NULL ||
!mmc_omap_cover_is_open(slot))
dev_err(mmc_dev(host->mmc),
"command timeout (CMD%d)\n",
cmd);
host->cmd->error = -ETIMEDOUT;
end_command = 1;
cmd_error = 1;
}
}
if (status & OMAP_MMC_STAT_CMD_CRC) {
if (host->cmd) {
dev_err(mmc_dev(host->mmc),
"command CRC error (CMD%d, arg 0x%08x)\n",
cmd, host->cmd->arg);
host->cmd->error = -EILSEQ;
end_command = 1;
cmd_error = 1;
} else
dev_err(mmc_dev(host->mmc),
"command CRC error without cmd?\n");
}
if (status & OMAP_MMC_STAT_CARD_ERR) {
dev_dbg(mmc_dev(host->mmc),
"ignoring card status error (CMD%d)\n",
cmd);
end_command = 1;
}
/*
* NOTE: On 1610 the END_OF_CMD may come too early when
* starting a write
*/
if ((status & OMAP_MMC_STAT_END_OF_CMD) &&
(!(status & OMAP_MMC_STAT_A_EMPTY))) {
end_command = 1;
}
}
if (cmd_error && host->data) {
del_timer(&host->cmd_abort_timer);
host->abort = 1;
OMAP_MMC_WRITE(host, IE, 0);
disable_irq_nosync(host->irq);
queue_work(host->mmc_omap_wq, &host->cmd_abort_work);
return IRQ_HANDLED;
}
if (end_command && host->cmd)
mmc_omap_cmd_done(host, host->cmd);
if (host->data != NULL) {
if (transfer_error)
mmc_omap_xfer_done(host, host->data);
else if (end_transfer)
mmc_omap_end_of_data(host, host->data);
}
return IRQ_HANDLED;
}