in trf7970a.c [820:980]
static irqreturn_t trf7970a_irq(int irq, void *dev_id)
{
struct trf7970a *trf = dev_id;
int ret;
u8 status, fifo_bytes, iso_ctrl;
mutex_lock(&trf->lock);
if (trf->state == TRF7970A_ST_RF_OFF) {
mutex_unlock(&trf->lock);
return IRQ_NONE;
}
ret = trf7970a_read_irqstatus(trf, &status);
if (ret) {
mutex_unlock(&trf->lock);
return IRQ_NONE;
}
dev_dbg(trf->dev, "IRQ - state: %d, status: 0x%x\n", trf->state,
status);
if (!status) {
mutex_unlock(&trf->lock);
return IRQ_NONE;
}
switch (trf->state) {
case TRF7970A_ST_IDLE:
case TRF7970A_ST_IDLE_RX_BLOCKED:
/* If initiator and getting interrupts caused by RF noise,
* turn off the receiver to avoid unnecessary interrupts.
* It will be turned back on in trf7970a_send_cmd() when
* the next command is issued.
*/
if (trf->is_initiator && (status & TRF7970A_IRQ_STATUS_ERROR)) {
trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX);
trf->state = TRF7970A_ST_IDLE_RX_BLOCKED;
}
trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
break;
case TRF7970A_ST_WAIT_FOR_TX_FIFO:
if (status & TRF7970A_IRQ_STATUS_TX) {
trf->ignore_timeout =
!cancel_delayed_work(&trf->timeout_work);
trf7970a_fill_fifo(trf);
} else {
trf7970a_send_err_upstream(trf, -EIO);
}
break;
case TRF7970A_ST_WAIT_FOR_RX_DATA:
case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
if (status & TRF7970A_IRQ_STATUS_SRX) {
trf->ignore_timeout =
!cancel_delayed_work(&trf->timeout_work);
trf7970a_drain_fifo(trf, status);
} else if (status & TRF7970A_IRQ_STATUS_FIFO) {
ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS,
&fifo_bytes);
fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
if (ret)
trf7970a_send_err_upstream(trf, ret);
else if (!fifo_bytes)
trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
} else if ((status == TRF7970A_IRQ_STATUS_TX) ||
(!trf->is_initiator &&
(status == (TRF7970A_IRQ_STATUS_TX |
TRF7970A_IRQ_STATUS_NFC_RF)))) {
trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
if (!trf->timeout) {
trf->ignore_timeout =
!cancel_delayed_work(&trf->timeout_work);
trf->rx_skb = ERR_PTR(0);
trf7970a_send_upstream(trf);
break;
}
if (trf->is_initiator)
break;
iso_ctrl = trf->iso_ctrl;
switch (trf->framing) {
case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
trf->iso_ctrl = 0xff; /* Force ISO_CTRL write */
break;
case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
trf->iso_ctrl = 0xff; /* Force ISO_CTRL write */
break;
case NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE:
ret = trf7970a_write(trf,
TRF7970A_SPECIAL_FCN_REG1,
TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL);
if (ret)
goto err_unlock_exit;
trf->special_fcn_reg1 =
TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL;
break;
default:
break;
}
if (iso_ctrl != trf->iso_ctrl) {
ret = trf7970a_write(trf, TRF7970A_ISO_CTRL,
iso_ctrl);
if (ret)
goto err_unlock_exit;
trf->iso_ctrl = iso_ctrl;
}
} else {
trf7970a_send_err_upstream(trf, -EIO);
}
break;
case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
if (status != TRF7970A_IRQ_STATUS_TX)
trf7970a_send_err_upstream(trf, -EIO);
break;
case TRF7970A_ST_LISTENING:
if (status & TRF7970A_IRQ_STATUS_SRX) {
trf->ignore_timeout =
!cancel_delayed_work(&trf->timeout_work);
trf7970a_drain_fifo(trf, status);
} else if (!(status & TRF7970A_IRQ_STATUS_NFC_RF)) {
trf7970a_send_err_upstream(trf, -EIO);
}
break;
case TRF7970A_ST_LISTENING_MD:
if (status & TRF7970A_IRQ_STATUS_SRX) {
trf->ignore_timeout =
!cancel_delayed_work(&trf->timeout_work);
ret = trf7970a_mode_detect(trf, &trf->md_rf_tech);
if (ret) {
trf7970a_send_err_upstream(trf, ret);
} else {
trf->state = TRF7970A_ST_LISTENING;
trf7970a_drain_fifo(trf, status);
}
} else if (!(status & TRF7970A_IRQ_STATUS_NFC_RF)) {
trf7970a_send_err_upstream(trf, -EIO);
}
break;
default:
dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
__func__, trf->state);
}
err_unlock_exit:
mutex_unlock(&trf->lock);
return IRQ_HANDLED;
}