static irqreturn_t qcom_swrm_irq_handler()

in qcom.c [493:608]


static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
{
	struct qcom_swrm_ctrl *swrm = dev_id;
	u32 value, intr_sts, intr_sts_masked, slave_status;
	u32 i;
	int devnum;
	int ret = IRQ_HANDLED;

	swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts);
	intr_sts_masked = intr_sts & swrm->intr_mask;

	do {
		for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
			value = intr_sts_masked & BIT(i);
			if (!value)
				continue;

			switch (value) {
			case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ:
				devnum = qcom_swrm_get_alert_slave_dev_num(swrm);
				if (devnum < 0) {
					dev_err_ratelimited(swrm->dev,
					    "no slave alert found.spurious interrupt\n");
				} else {
					sdw_handle_slave_status(&swrm->bus, swrm->status);
				}

				break;
			case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED:
			case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS:
				dev_err_ratelimited(swrm->dev, "%s: SWR new slave attached\n",
					__func__);
				swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, &slave_status);
				if (swrm->slave_status == slave_status) {
					dev_err(swrm->dev, "Slave status not changed %x\n",
						slave_status);
				} else {
					qcom_swrm_get_device_status(swrm);
					qcom_swrm_enumerate(&swrm->bus);
					sdw_handle_slave_status(&swrm->bus, swrm->status);
				}
				break;
			case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET:
				dev_err_ratelimited(swrm->dev,
						"%s: SWR bus clsh detected\n",
						__func__);
				swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET;
				swrm->reg_write(swrm, SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
				break;
			case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW:
				swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
				dev_err_ratelimited(swrm->dev,
					"%s: SWR read FIFO overflow fifo status 0x%x\n",
					__func__, value);
				break;
			case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW:
				swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
				dev_err_ratelimited(swrm->dev,
					"%s: SWR read FIFO underflow fifo status 0x%x\n",
					__func__, value);
				break;
			case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW:
				swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
				dev_err(swrm->dev,
					"%s: SWR write FIFO overflow fifo status %x\n",
					__func__, value);
				swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
				break;
			case SWRM_INTERRUPT_STATUS_CMD_ERROR:
				swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
				dev_err_ratelimited(swrm->dev,
					"%s: SWR CMD error, fifo status 0x%x, flushing fifo\n",
					__func__, value);
				swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
				break;
			case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION:
				dev_err_ratelimited(swrm->dev,
						"%s: SWR Port collision detected\n",
						__func__);
				swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION;
				swrm->reg_write(swrm,
					SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
				break;
			case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH:
				dev_err_ratelimited(swrm->dev,
					"%s: SWR read enable valid mismatch\n",
					__func__);
				swrm->intr_mask &=
					~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH;
				swrm->reg_write(swrm,
					SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
				break;
			case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED:
				complete(&swrm->broadcast);
				break;
			case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2:
				break;
			case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2:
				break;
			case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP:
				break;
			default:
				dev_err_ratelimited(swrm->dev,
						"%s: SWR unknown interrupt value: %d\n",
						__func__, value);
				ret = IRQ_NONE;
				break;
			}
		}
		swrm->reg_write(swrm, SWRM_INTERRUPT_CLEAR, intr_sts);
		swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts);
		intr_sts_masked = intr_sts & swrm->intr_mask;
	} while (intr_sts_masked);

	return ret;
}