]> Pileus Git - ~andy/linux/blobdiff - drivers/media/i2c/ad9389b.c
[media] ad9389b: remove rx-sense irq dependency
[~andy/linux] / drivers / media / i2c / ad9389b.c
index b06a7e54ee0d25100f1f01abcac7ddc70e8489df..cca77585247d8a06c2ee8e2271aebe82903e92ea 100644 (file)
@@ -66,11 +66,6 @@ MODULE_LICENSE("GPL");
 **********************************************************************
 */
 
-struct i2c_reg_value {
-       u8 reg;
-       u8 value;
-};
-
 struct ad9389b_state_edid {
        /* total number of blocks */
        u32 blocks;
@@ -143,14 +138,14 @@ static int ad9389b_wr(struct v4l2_subdev *sd, u8 reg, u8 val)
                if (ret == 0)
                        return 0;
        }
-       v4l2_err(sd, "I2C Write Problem\n");
+       v4l2_err(sd, "%s: failed reg 0x%x, val 0x%x\n", __func__, reg, val);
        return ret;
 }
 
 /* To set specific bits in the register, a clear-mask is given (to be AND-ed),
    and then the value-mask (to be OR-ed). */
 static inline void ad9389b_wr_and_or(struct v4l2_subdev *sd, u8 reg,
-                                               u8 clr_mask, u8 val_mask)
+                                    u8 clr_mask, u8 val_mask)
 {
        ad9389b_wr(sd, reg, (ad9389b_rd(sd, reg) & clr_mask) | val_mask);
 }
@@ -321,12 +316,12 @@ static int ad9389b_s_ctrl(struct v4l2_ctrl *ctrl)
        struct ad9389b_state *state = get_ad9389b_state(sd);
 
        v4l2_dbg(1, debug, sd,
-               "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
+                "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
 
        if (state->hdmi_mode_ctrl == ctrl) {
                /* Set HDMI or DVI-D */
                ad9389b_wr_and_or(sd, 0xaf, 0xfd,
-                               ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
+                                 ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
                return 0;
        }
        if (state->rgb_quantization_range_ctrl == ctrl)
@@ -387,61 +382,57 @@ static int ad9389b_log_status(struct v4l2_subdev *sd)
        v4l2_info(sd, "chip revision %d\n", state->chip_revision);
        v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off");
        v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n",
-                       (ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ?
-                                                       "detected" : "no",
-                       (ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ?
-                                                       "detected" : "no",
-                       edid->segments ? "found" : "no", edid->blocks);
-       if (state->have_monitor) {
-               v4l2_info(sd, "%s output %s\n",
-                                 (ad9389b_rd(sd, 0xaf) & 0x02) ?
-                                 "HDMI" : "DVI-D",
-                                 (ad9389b_rd(sd, 0xa1) & 0x3c) ?
-                                 "disabled" : "enabled");
-       }
+                 (ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ?
+                 "detected" : "no",
+                 (ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ?
+                 "detected" : "no",
+                 edid->segments ? "found" : "no", edid->blocks);
+       v4l2_info(sd, "%s output %s\n",
+                 (ad9389b_rd(sd, 0xaf) & 0x02) ?
+                 "HDMI" : "DVI-D",
+                 (ad9389b_rd(sd, 0xa1) & 0x3c) ?
+                 "disabled" : "enabled");
        v4l2_info(sd, "ad9389b: %s\n", (ad9389b_rd(sd, 0xb8) & 0x40) ?
-                                       "encrypted" : "no encryption");
+                 "encrypted" : "no encryption");
        v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n",
-                       states[ad9389b_rd(sd, 0xc8) & 0xf],
-                       errors[ad9389b_rd(sd, 0xc8) >> 4],
-                       state->edid_detect_counter,
-                       ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96));
+                 states[ad9389b_rd(sd, 0xc8) & 0xf],
+                 errors[ad9389b_rd(sd, 0xc8) >> 4],
+                 state->edid_detect_counter,
+                 ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96));
        manual_gear = ad9389b_rd(sd, 0x98) & 0x80;
        v4l2_info(sd, "ad9389b: RGB quantization: %s range\n",
-                       ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full");
+                 ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full");
        v4l2_info(sd, "ad9389b: %s gear %d\n",
                  manual_gear ? "manual" : "automatic",
                  manual_gear ? ((ad9389b_rd(sd, 0x98) & 0x70) >> 4) :
-                               ((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1));
-       if (state->have_monitor) {
-               if (ad9389b_rd(sd, 0xaf) & 0x02) {
-                       /* HDMI only */
-                       u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80;
-                       u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
-                                ad9389b_rd(sd, 0x02) << 8 |
-                                ad9389b_rd(sd, 0x03);
-                       u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2;
-                       u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f;
-                       u32 CTS;
-
-                       if (manual_cts)
-                               CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 |
-                                      ad9389b_rd(sd, 0x08) << 8 |
-                                      ad9389b_rd(sd, 0x09);
-                       else
-                               CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 |
-                                      ad9389b_rd(sd, 0x05) << 8 |
-                                      ad9389b_rd(sd, 0x06);
-                       N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
-                            ad9389b_rd(sd, 0x02) << 8 |
-                            ad9389b_rd(sd, 0x03);
-
-                       v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n",
-                               manual_cts ? "manual" : "automatic", N, CTS);
-
-                       v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n",
-                               vic_detect, vic_sent);
-               }
+                 ((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1));
+       if (ad9389b_rd(sd, 0xaf) & 0x02) {
+               /* HDMI only */
+               u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80;
+               u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
+                       ad9389b_rd(sd, 0x02) << 8 |
+                       ad9389b_rd(sd, 0x03);
+               u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2;
+               u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f;
+               u32 CTS;
+
+               if (manual_cts)
+                       CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 |
+                             ad9389b_rd(sd, 0x08) << 8 |
+                             ad9389b_rd(sd, 0x09);
+               else
+                       CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 |
+                             ad9389b_rd(sd, 0x05) << 8 |
+                             ad9389b_rd(sd, 0x06);
+               N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
+                   ad9389b_rd(sd, 0x02) << 8 |
+                   ad9389b_rd(sd, 0x03);
+
+               v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n",
+                         manual_cts ? "manual" : "automatic", N, CTS);
+
+               v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n",
+                         vic_detect, vic_sent);
        }
        if (state->dv_timings.type == V4L2_DV_BT_656_1120)
                v4l2_print_dv_timings(sd->name, "timings: ",
@@ -486,7 +477,7 @@ static int ad9389b_s_power(struct v4l2_subdev *sd, int on)
        }
        if (i > 1)
                v4l2_dbg(1, debug, sd,
-                       "needed %d retries to powerup the ad9389b\n", i);
+                        "needed %d retries to powerup the ad9389b\n", i);
 
        /* Select chip: AD9389B */
        ad9389b_wr_and_or(sd, 0xba, 0xef, 0x10);
@@ -556,14 +547,16 @@ static int ad9389b_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
        irq_status = ad9389b_rd(sd, 0x96);
        /* clear detected interrupts */
        ad9389b_wr(sd, 0x96, irq_status);
+       /* enable interrupts */
+       ad9389b_set_isr(sd, true);
+
+       v4l2_dbg(1, debug, sd, "%s: irq_status 0x%x\n", __func__, irq_status);
 
-       if (irq_status & (MASK_AD9389B_HPD_INT | MASK_AD9389B_MSEN_INT))
+       if (irq_status & (MASK_AD9389B_HPD_INT))
                ad9389b_check_monitor_present_status(sd);
        if (irq_status & MASK_AD9389B_EDID_RDY_INT)
                ad9389b_check_edid_status(sd);
 
-       /* enable interrupts */
-       ad9389b_set_isr(sd, true);
        *handled = true;
        return 0;
 }
@@ -599,7 +592,7 @@ static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
        if (edid->blocks + edid->start_block >= state->edid.segments * 2)
                edid->blocks = state->edid.segments * 2 - edid->start_block;
        memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
-                               128 * edid->blocks);
+              128 * edid->blocks);
        return 0;
 }
 
@@ -612,8 +605,6 @@ static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = {
 /* Enable/disable ad9389b output */
 static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct ad9389b_state *state = get_ad9389b_state(sd);
-
        v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
 
        ad9389b_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c));
@@ -621,7 +612,6 @@ static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
                ad9389b_check_monitor_present_status(sd);
        } else {
                ad9389b_s_power(sd, 0);
-               state->have_monitor = false;
        }
        return 0;
 }
@@ -686,14 +676,14 @@ static int ad9389b_g_dv_timings(struct v4l2_subdev *sd,
 }
 
 static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
-                       struct v4l2_enum_dv_timings *timings)
+                                  struct v4l2_enum_dv_timings *timings)
 {
        return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap,
                        NULL, NULL);
 }
 
 static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd,
-                       struct v4l2_dv_timings_cap *cap)
+                                 struct v4l2_dv_timings_cap *cap)
 {
        *cap = ad9389b_timings_cap;
        return 0;
@@ -724,15 +714,15 @@ static int ad9389b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
        u32 N;
 
        switch (freq) {
-       case 32000: N = 4096; break;
-       case 44100: N = 6272; break;
-       case 48000: N = 6144; break;
-       case 88200: N = 12544; break;
-       case 96000: N = 12288; break;
+       case 32000:  N = 4096;  break;
+       case 44100:  N = 6272;  break;
+       case 48000:  N = 6144;  break;
+       case 88200:  N = 12544; break;
+       case 96000:  N = 12288; break;
        case 176400: N = 25088; break;
        case 192000: N = 24576; break;
        default:
-               return -EINVAL;
+            return -EINVAL;
        }
 
        /* Set N (used with CTS to regenerate the audio clock) */
@@ -748,15 +738,15 @@ static int ad9389b_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
        u32 i2s_sf;
 
        switch (freq) {
-       case 32000: i2s_sf = 0x30; break;
-       case 44100: i2s_sf = 0x00; break;
-       case 48000: i2s_sf = 0x20; break;
-       case 88200: i2s_sf = 0x80; break;
-       case 96000: i2s_sf = 0xa0; break;
+       case 32000:  i2s_sf = 0x30; break;
+       case 44100:  i2s_sf = 0x00; break;
+       case 48000:  i2s_sf = 0x20; break;
+       case 88200:  i2s_sf = 0x80; break;
+       case 96000:  i2s_sf = 0xa0; break;
        case 176400: i2s_sf = 0xc0; break;
        case 192000: i2s_sf = 0xe0; break;
        default:
-               return -EINVAL;
+            return -EINVAL;
        }
 
        /* Set sampling frequency for I2S audio to 48 kHz */
@@ -800,7 +790,7 @@ static const struct v4l2_subdev_ops ad9389b_ops = {
 
 /* ----------------------------------------------------------------------- */
 static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd,
-                                                       int segment, u8 *buf)
+                                 int segment, u8 *buf)
 {
        int i, j;
 
@@ -826,8 +816,8 @@ static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd,
 static void ad9389b_edid_handler(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
-       struct ad9389b_state *state = container_of(dwork,
-                       struct ad9389b_state, edid_handler);
+       struct ad9389b_state *state =
+               container_of(dwork, struct ad9389b_state, edid_handler);
        struct v4l2_subdev *sd = &state->sd;
        struct ad9389b_edid_detect ed;
 
@@ -845,11 +835,10 @@ static void ad9389b_edid_handler(struct work_struct *work)
                if (state->edid.read_retries) {
                        state->edid.read_retries--;
                        v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__);
-                       state->have_monitor = false;
                        ad9389b_s_power(sd, false);
                        ad9389b_s_power(sd, true);
                        queue_delayed_work(state->work_queue,
-                                       &state->edid_handler, EDID_DELAY);
+                                          &state->edid_handler, EDID_DELAY);
                        return;
                }
        }
@@ -922,42 +911,28 @@ static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
        u8 status = ad9389b_rd(sd, 0x42);
 
        v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n",
-                        __func__,
-                        status,
-                        status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "",
-                        status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : "");
+                __func__,
+                status,
+                status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "",
+                status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : "");
 
-       if ((status & MASK_AD9389B_HPD_DETECT) &&
-           ((status & MASK_AD9389B_MSEN_DETECT) || state->edid.segments)) {
-               v4l2_dbg(1, debug, sd,
-                               "%s: hotplug and (rx-sense or edid)\n", __func__);
-               if (!state->have_monitor) {
-                       v4l2_dbg(1, debug, sd, "%s: monitor detected\n", __func__);
-                       state->have_monitor = true;
-                       ad9389b_set_isr(sd, true);
-                       if (!ad9389b_s_power(sd, true)) {
-                               v4l2_dbg(1, debug, sd,
-                                       "%s: monitor detected, powerup failed\n", __func__);
-                               return;
-                       }
-                       ad9389b_setup(sd);
-                       ad9389b_notify_monitor_detect(sd);
-                       state->edid.read_retries = EDID_MAX_RETRIES;
-                       queue_delayed_work(state->work_queue,
-                                       &state->edid_handler, EDID_DELAY);
-               }
-       } else if (status & MASK_AD9389B_HPD_DETECT) {
+       if (status & MASK_AD9389B_HPD_DETECT) {
                v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__);
+               state->have_monitor = true;
+               if (!ad9389b_s_power(sd, true)) {
+                       v4l2_dbg(1, debug, sd,
+                                "%s: monitor detected, powerup failed\n", __func__);
+                       return;
+               }
+               ad9389b_setup(sd);
+               ad9389b_notify_monitor_detect(sd);
                state->edid.read_retries = EDID_MAX_RETRIES;
                queue_delayed_work(state->work_queue,
-                               &state->edid_handler, EDID_DELAY);
+                                  &state->edid_handler, EDID_DELAY);
        } else if (!(status & MASK_AD9389B_HPD_DETECT)) {
                v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__);
-               if (state->have_monitor) {
-                       v4l2_dbg(1, debug, sd, "%s: monitor not detected\n", __func__);
-                       state->have_monitor = false;
-                       ad9389b_notify_monitor_detect(sd);
-               }
+               state->have_monitor = false;
+               ad9389b_notify_monitor_detect(sd);
                ad9389b_s_power(sd, false);
                memset(&state->edid, 0, sizeof(struct ad9389b_state_edid));
        }
@@ -966,6 +941,10 @@ static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
        v4l2_ctrl_s_ctrl(state->hotplug_ctrl, ad9389b_have_hotplug(sd) ? 0x1 : 0x0);
        v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, ad9389b_have_rx_sense(sd) ? 0x1 : 0x0);
        v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
+
+       /* update with setting from ctrls */
+       ad9389b_s_ctrl(state->rgb_quantization_range_ctrl);
+       ad9389b_s_ctrl(state->hdmi_mode_ctrl);
 }
 
 static bool edid_block_verify_crc(u8 *edid_block)
@@ -978,7 +957,7 @@ static bool edid_block_verify_crc(u8 *edid_block)
        return sum == 0;
 }
 
-static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
+static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment)
 {
        struct ad9389b_state *state = get_ad9389b_state(sd);
        u32 blocks = state->edid.blocks;
@@ -992,6 +971,25 @@ static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
        return false;
 }
 
+static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
+{
+       static const u8 hdmi_header[] = {
+               0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
+       };
+       struct ad9389b_state *state = get_ad9389b_state(sd);
+       u8 *data = state->edid.data;
+       int i;
+
+       if (segment)
+               return true;
+
+       for (i = 0; i < ARRAY_SIZE(hdmi_header); i++)
+               if (data[i] != hdmi_header[i])
+                       return false;
+
+       return true;
+}
+
 static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
 {
        struct ad9389b_state *state = get_ad9389b_state(sd);
@@ -1000,7 +998,7 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
        u8 edidRdy = ad9389b_rd(sd, 0xc5);
 
        v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n",
-                        __func__, EDID_MAX_RETRIES - state->edid.read_retries);
+                __func__, EDID_MAX_RETRIES - state->edid.read_retries);
 
        if (!(edidRdy & MASK_AD9389B_EDID_RDY))
                return false;
@@ -1013,16 +1011,16 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
        v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment);
        ad9389b_edid_rd(sd, 256, &state->edid.data[segment * 256]);
        ad9389b_dbg_dump_edid(2, debug, sd, segment,
-                       &state->edid.data[segment * 256]);
+                             &state->edid.data[segment * 256]);
        if (segment == 0) {
                state->edid.blocks = state->edid.data[0x7e] + 1;
                v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n",
-                               __func__, state->edid.blocks);
+                        __func__, state->edid.blocks);
        }
-       if (!edid_segment_verify_crc(sd, segment)) {
+       if (!edid_verify_crc(sd, segment) ||
+           !edid_verify_header(sd, segment)) {
                /* edid crc error, force reread of edid segment */
-               v4l2_err(sd, "%s: edid crc error\n", __func__);
-               state->have_monitor = false;
+               v4l2_err(sd, "%s: edid crc or header error\n", __func__);
                ad9389b_s_power(sd, false);
                ad9389b_s_power(sd, true);
                return false;
@@ -1032,12 +1030,12 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
        if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) {
                /* Request next EDID segment */
                v4l2_dbg(1, debug, sd, "%s: request segment %d\n",
-                               __func__, state->edid.segments);
+                        __func__, state->edid.segments);
                ad9389b_wr(sd, 0xc9, 0xf);
                ad9389b_wr(sd, 0xc4, state->edid.segments);
                state->edid.read_retries = EDID_MAX_RETRIES;
                queue_delayed_work(state->work_queue,
-                               &state->edid_handler, EDID_DELAY);
+                                  &state->edid_handler, EDID_DELAY);
                return false;
        }
 
@@ -1081,7 +1079,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
                return -EIO;
 
        v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n",
-                       client->addr << 1);
+               client->addr << 1);
 
        state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (!state)
@@ -1140,7 +1138,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
                goto err_entity;
        }
        v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n",
-                       ad9389b_rd(sd, 0x41), state->chip_revision);
+                ad9389b_rd(sd, 0x41), state->chip_revision);
 
        state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1));
        if (state->edid_i2c_client == NULL) {
@@ -1163,7 +1161,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
        ad9389b_set_isr(sd, true);
 
        v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
-                         client->addr << 1, client->adapter->name);
+                 client->addr << 1, client->adapter->name);
        return 0;
 
 err_unreg: