static irqreturn_t trf7970a_irq()

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;
}