Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34057087 authored by Jaiju Yesudasan's avatar Jaiju Yesudasan Committed by Gerrit - the friendly Code Review server
Browse files

adv7481: Fix interrupt handling



ADV7481 raises back-to-back interrupts on cable connect and
disconnect. The IRQ bottom half has to check the interrupt status
register in a loop and service all events that have been raised,
rather than relying on the top half getting scheduled for each event.

Suggested-by: default avatarResmi Rajendran <resmir@qti.qualcomm.com>
Signed-off-by: default avatarJaiju Yesudasan <cjaijuy@codeaurora.org>
Change-Id: I388d951fa5ed8ac22db9358e86de74d0b83c5a50
parent 29d696ad
Loading
Loading
Loading
Loading
+112 −108
Original line number Diff line number Diff line
@@ -532,6 +532,7 @@ static void adv7481_irq_delay_work(struct work_struct *work)
			state->device_num, int_raw_status);
	state->cec_detected = ADV_REG_GETFIELD(int_raw_status, IO_INT_CEC_ST);

	while (int_raw_status) {
		if (ADV_REG_GETFIELD(int_raw_status, IO_INTRQ1_RAW)) {
			int lock_status = -1;
			struct v4l2_event event = {0};
@@ -564,13 +565,15 @@ static void adv7481_irq_delay_work(struct work_struct *work)
					state->i2c_sdp_addr, SDP_RW_MAP_REG,
					0x01);
				sdp_sts = adv7481_rd_byte(&state->i2c_client,
				state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
					state->i2c_sdp_addr,
					SDP_RO_MAIN_STATUS1_ADDR);
				pr_debug("%s: dev: %d got sdp status: 0x%x\n",
					__func__, state->device_num, sdp_sts);
				adv7481_wr_byte(&state->i2c_client,
					state->i2c_sdp_addr, SDP_RW_MAP_REG,
					0x00);
			if (ADV_REG_GETFIELD(sdp_sts, SDP_RO_MAIN_IN_LOCK)) {
				if (ADV_REG_GETFIELD(sdp_sts,
					SDP_RO_MAIN_IN_LOCK)) {
					lock_status = 0;
					pr_debug(
					"%s: set lock_status SDP_IN_LOCK:0x%x\n",
@@ -591,7 +594,8 @@ static void adv7481_irq_delay_work(struct work_struct *work)
					state->i2c_sdp_addr, SDP_RW_MAP_REG,
					0x00);
			} else {
			if (ADV_REG_GETFIELD(int_status, IO_CP_LOCK_CP_ST) &&
				if (ADV_REG_GETFIELD(int_status,
						IO_CP_LOCK_CP_ST) &&
					ADV_REG_GETFIELD(raw_status,
						IO_CP_LOCK_CP_RAW)) {
					lock_status = 0;
@@ -599,7 +603,8 @@ static void adv7481_irq_delay_work(struct work_struct *work)
					"%s: set lock_status IO_CP_LOCK_CP_RAW:0x%x\n",
					__func__, lock_status);
				}
			if (ADV_REG_GETFIELD(int_status, IO_CP_UNLOCK_CP_ST) &&
				if (ADV_REG_GETFIELD(int_status,
						IO_CP_UNLOCK_CP_ST) &&
					ADV_REG_GETFIELD(raw_status,
						IO_CP_UNLOCK_CP_RAW)) {
					lock_status = 1;
@@ -638,6 +643,9 @@ static void adv7481_irq_delay_work(struct work_struct *work)
				state->i2c_io_addr,
				IO_HDMI_LVL_RAW_STATUS_3_ADDR);

			adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
				IO_HDMI_LVL_INT_CLEAR_3_ADDR, int_status);

			pr_debug("%s: dev: %d got hdmi lvl int status 3: 0x%x\n",
				__func__, state->device_num, int_status);
			pr_debug("%s: dev: %d got hdmi lvl raw status 3: 0x%x\n",
@@ -672,14 +680,10 @@ static void adv7481_irq_delay_work(struct work_struct *work)
				}
			}
		}
	/* Clear all other interrupts */
	adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
		IO_HDMI_LVL_INT_CLEAR_1_ADDR, 0xFF);
	adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
		IO_HDMI_LVL_INT_CLEAR_2_ADDR, 0xFF);
	adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
		IO_HDMI_LVL_INT_CLEAR_3_ADDR, 0xFF);

		int_raw_status = adv7481_rd_byte(&state->i2c_client,
				state->i2c_io_addr,
				IO_REG_INT_RAW_STATUS_ADDR);
	}
	mutex_unlock(&state->mutex);
}