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.

Signed-off-by: Jaiju Yesudasan <cjaijuy@codeaurora.org>
Change-Id: I388d951fa5ed8ac22db9358e86de74d0b83c5a50
This commit is contained in:
Jaiju Yesudasan 2017-03-02 23:29:02 +05:30 committed by Gerrit - the friendly Code Review server
parent 25af46edc5
commit 54dbacb5eb

View file

@ -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",
@ -673,14 +681,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);
}