summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaiju Yesudasan <cjaijuy@codeaurora.org>2017-03-02 23:29:02 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2017-05-26 01:40:33 -0700
commit54dbacb5eb34ccc21ecc3c4f433cd6b607531202 (patch)
tree7709f21c194642f756ab3c86848dd77da0e4ef0a
parent25af46edc5435c2f910dac2bc7a6899e09ea1cec (diff)
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
-rw-r--r--drivers/media/i2c/adv7481.c222
1 files changed, 113 insertions, 109 deletions
diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c
index 5cdea6b5dc3b..6758c2b62d88 100644
--- a/drivers/media/i2c/adv7481.c
+++ b/drivers/media/i2c/adv7481.c
@@ -532,155 +532,159 @@ 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);
- if (ADV_REG_GETFIELD(int_raw_status, IO_INTRQ1_RAW)) {
- int lock_status = -1;
- struct v4l2_event event = {0};
- int *ptr = (int *)event.u.data;
-
- pr_debug("%s: dev: %d got intrq1_raw\n", __func__,
- state->device_num);
- int_status = adv7481_rd_byte(&state->i2c_client,
- state->i2c_io_addr,
- IO_REG_DATAPATH_INT_STATUS_ADDR);
-
- raw_status = adv7481_rd_byte(&state->i2c_client,
- state->i2c_io_addr,
- IO_REG_DATAPATH_RAW_STATUS_ADDR);
-
- adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
- IO_REG_DATAPATH_INT_CLEAR_ADDR, int_status);
-
- pr_debug("%s: dev: %d got datapath int status: 0x%x\n",
- __func__, state->device_num, int_status);
+ while (int_raw_status) {
+ if (ADV_REG_GETFIELD(int_raw_status, IO_INTRQ1_RAW)) {
+ int lock_status = -1;
+ struct v4l2_event event = {0};
+ int *ptr = (int *)event.u.data;
+
+ pr_debug("%s: dev: %d got intrq1_raw\n", __func__,
+ state->device_num);
+ int_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_STATUS_ADDR);
+
+ raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_DATAPATH_RAW_STATUS_ADDR);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_CLEAR_ADDR, int_status);
+
+ pr_debug("%s: dev: %d got datapath int status: 0x%x\n",
+ __func__, state->device_num, int_status);
- pr_debug("%s: dev: %d got datapath raw status: 0x%x\n",
- __func__, state->device_num, raw_status);
+ pr_debug("%s: dev: %d got datapath raw status: 0x%x\n",
+ __func__, state->device_num, raw_status);
- if (ADV_REG_GETFIELD(int_status, IO_INT_SD_ST) &&
- ADV_REG_GETFIELD(raw_status, IO_INT_SD_RAW)) {
- uint8_t sdp_sts = 0;
+ if (ADV_REG_GETFIELD(int_status, IO_INT_SD_ST) &&
+ ADV_REG_GETFIELD(raw_status, IO_INT_SD_RAW)) {
+ uint8_t sdp_sts = 0;
- adv7481_wr_byte(&state->i2c_client,
+ adv7481_wr_byte(&state->i2c_client,
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);
- pr_debug("%s: dev: %d got sdp status: 0x%x\n",
+ sdp_sts = adv7481_rd_byte(&state->i2c_client,
+ 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,
+ 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)) {
- lock_status = 0;
- pr_debug(
- "%s: set lock_status SDP_IN_LOCK:0x%x\n",
- __func__, lock_status);
- } else {
- lock_status = 1;
- pr_debug(
- "%s: set lock_status SDP_UNLOCK:0x%x\n",
- __func__, lock_status);
- }
- adv7481_wr_byte(&state->i2c_client,
+ 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",
+ __func__, lock_status);
+ } else {
+ lock_status = 1;
+ pr_debug(
+ "%s: set lock_status SDP_UNLOCK:0x%x\n",
+ __func__, lock_status);
+ }
+ adv7481_wr_byte(&state->i2c_client,
state->i2c_sdp_addr, SDP_RW_MAP_REG,
0x20);
- adv7481_wr_byte(&state->i2c_client,
+ adv7481_wr_byte(&state->i2c_client,
state->i2c_sdp_addr,
SDP_RW_LOCK_UNLOCK_CLR_ADDR, sdp_sts);
- adv7481_wr_byte(&state->i2c_client,
+ adv7481_wr_byte(&state->i2c_client,
state->i2c_sdp_addr, SDP_RW_MAP_REG,
0x00);
- } else {
- if (ADV_REG_GETFIELD(int_status, IO_CP_LOCK_CP_ST) &&
- ADV_REG_GETFIELD(raw_status,
+ } else {
+ if (ADV_REG_GETFIELD(int_status,
+ IO_CP_LOCK_CP_ST) &&
+ ADV_REG_GETFIELD(raw_status,
IO_CP_LOCK_CP_RAW)) {
- lock_status = 0;
- pr_debug(
- "%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) &&
- ADV_REG_GETFIELD(raw_status,
+ lock_status = 0;
+ pr_debug(
+ "%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) &&
+ ADV_REG_GETFIELD(raw_status,
IO_CP_UNLOCK_CP_RAW)) {
- lock_status = 1;
- pr_debug(
- "%s: set lock_status IO_CP_UNLOCK_CP_RAW:0x%x\n",
- __func__, lock_status);
+ lock_status = 1;
+ pr_debug(
+ "%s: set lock_status IO_CP_UNLOCK_CP_RAW:0x%x\n",
+ __func__, lock_status);
+ }
}
- }
- if (lock_status >= 0) {
- ptr[0] = adv7481_inp_to_ba(state->mode);
- ptr[1] = lock_status;
- event.type = lock_status ?
- V4L2_EVENT_MSM_BA_SIGNAL_LOST_LOCK :
- V4L2_EVENT_MSM_BA_SIGNAL_IN_LOCK;
- v4l2_subdev_notify(&state->sd,
- event.type, &event);
+ if (lock_status >= 0) {
+ ptr[0] = adv7481_inp_to_ba(state->mode);
+ ptr[1] = lock_status;
+ event.type = lock_status ?
+ V4L2_EVENT_MSM_BA_SIGNAL_LOST_LOCK :
+ V4L2_EVENT_MSM_BA_SIGNAL_IN_LOCK;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
}
- }
- if (ADV_REG_GETFIELD(int_raw_status, IO_INT_HDMI_ST)) {
- int cable_detected = 0;
- struct v4l2_event event = {0};
- int *ptr = (int *)event.u.data;
+ if (ADV_REG_GETFIELD(int_raw_status, IO_INT_HDMI_ST)) {
+ int cable_detected = 0;
+ struct v4l2_event event = {0};
+ int *ptr = (int *)event.u.data;
- ptr[0] = adv7481_inp_to_ba(state->mode);
+ ptr[0] = adv7481_inp_to_ba(state->mode);
- pr_debug("%s: dev: %d got int_hdmi_st\n", __func__,
+ pr_debug("%s: dev: %d got int_hdmi_st\n", __func__,
state->device_num);
- int_status = adv7481_rd_byte(&state->i2c_client,
+ int_status = adv7481_rd_byte(&state->i2c_client,
state->i2c_io_addr,
IO_HDMI_LVL_INT_STATUS_3_ADDR);
- raw_status = adv7481_rd_byte(&state->i2c_client,
+ raw_status = adv7481_rd_byte(&state->i2c_client,
state->i2c_io_addr,
IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- pr_debug("%s: dev: %d got hdmi lvl int status 3: 0x%x\n",
+ 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",
+ pr_debug("%s: dev: %d got hdmi lvl raw status 3: 0x%x\n",
__func__, state->device_num, raw_status);
- if (ADV_REG_GETFIELD(int_status, IO_CABLE_DET_A_ST)) {
- cable_detected = ADV_REG_GETFIELD(raw_status,
- IO_CABLE_DET_A_RAW);
- pr_debug("%s: set cable_detected: 0x%x\n",
+ if (ADV_REG_GETFIELD(int_status, IO_CABLE_DET_A_ST)) {
+ cable_detected = ADV_REG_GETFIELD(raw_status,
+ IO_CABLE_DET_A_RAW);
+ pr_debug("%s: set cable_detected: 0x%x\n",
__func__, cable_detected);
- ptr[1] = cable_detected;
- event.type = V4L2_EVENT_MSM_BA_CABLE_DETECT;
- v4l2_subdev_notify(&state->sd,
- event.type, &event);
- }
- /* Assumption is that vertical sync int
- * is the last one to come
- */
- if (ADV_REG_GETFIELD(int_status, IO_V_LOCKED_ST)) {
- if (ADV_REG_GETFIELD(raw_status,
- IO_TMDSPLL_LCK_A_RAW) &&
- ADV_REG_GETFIELD(raw_status,
- IO_V_LOCKED_RAW) &&
- ADV_REG_GETFIELD(raw_status,
- IO_DE_REGEN_LCK_RAW)) {
- pr_debug("%s: port settings changed\n",
- __func__);
- event.type =
- V4L2_EVENT_MSM_BA_PORT_SETTINGS_CHANGED;
+ ptr[1] = cable_detected;
+ event.type = V4L2_EVENT_MSM_BA_CABLE_DETECT;
v4l2_subdev_notify(&state->sd,
event.type, &event);
}
+ /* Assumption is that vertical sync int
+ * is the last one to come
+ */
+ if (ADV_REG_GETFIELD(int_status, IO_V_LOCKED_ST)) {
+ if (ADV_REG_GETFIELD(raw_status,
+ IO_TMDSPLL_LCK_A_RAW) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_V_LOCKED_RAW) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_DE_REGEN_LCK_RAW)) {
+ pr_debug("%s: port settings changed\n",
+ __func__);
+ event.type =
+ V4L2_EVENT_MSM_BA_PORT_SETTINGS_CHANGED;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ }
}
+ int_raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_INT_RAW_STATUS_ADDR);
}
- /* 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);
-
mutex_unlock(&state->mutex);
}