* [RFC PATCH 00/15] adv7604: fixes @ 2013-12-10 13:23 Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil 0 siblings, 1 reply; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media This patch series updates the adv7604 driver with the latest fixes from our internal tree. Regards, Hans ^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH 01/15] adv7604: add support for all the digital input ports 2013-12-10 13:23 [RFC PATCH 00/15] adv7604: fixes Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 02/15] adv7604: add hdmi driver strength adjustment Hans Verkuil ` (13 more replies) 0 siblings, 14 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> The adv7604 supports four digital input ports. This patch adds support for all of them, instead of just port A. Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 266 ++++++++++++++++++++++++++------------------ include/media/adv7604.h | 20 ++-- 2 files changed, 168 insertions(+), 118 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index a324106b..6372d31 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -53,8 +53,6 @@ MODULE_LICENSE("GPL"); /* ADV7604 system clock frequency */ #define ADV7604_fsc (28636360) -#define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI) - /* ********************************************************************** * @@ -67,10 +65,13 @@ struct adv7604_state { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler hdl; - enum adv7604_mode mode; + enum adv7604_input_port selected_input; struct v4l2_dv_timings timings; - u8 edid[256]; - unsigned edid_blocks; + struct { + u8 edid[256]; + u32 present; + unsigned blocks; + } edid; struct v4l2_fract aspect_ratio; u32 rgb_quantization_range; struct workqueue_struct *work_queues; @@ -516,7 +517,7 @@ static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); - v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)1); + v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); } static inline int edid_write_block(struct v4l2_subdev *sd, @@ -529,8 +530,6 @@ static inline int edid_write_block(struct v4l2_subdev *sd, v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); - v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)0); - /* Disables I2C access to internal EDID ram from DDC port */ rep_write_and_or(sd, 0x77, 0xf0, 0x0); @@ -541,22 +540,19 @@ static inline int edid_write_block(struct v4l2_subdev *sd, return err; /* adv7604 calculates the checksums and enables I2C access to internal - EDID ram from DDC port. */ - rep_write_and_or(sd, 0x77, 0xf0, 0x1); + EDID RAM from DDC port. */ + rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); for (i = 0; i < 1000; i++) { - if (rep_read(sd, 0x7d) & 1) + if (rep_read(sd, 0x7d) & state->edid.present) break; mdelay(1); } if (i == 1000) { - v4l_err(client, "error enabling edid\n"); + v4l_err(client, "error enabling edid (0x%x)\n", state->edid.present); return -EIO; } - /* enable hotplug after 100 ms */ - queue_delayed_work(state->work_queues, - &state->delayed_work_enable_hotplug, HZ / 10); return 0; } @@ -574,6 +570,11 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); } +static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) +{ + return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val); +} + static inline int test_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); @@ -623,6 +624,26 @@ static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) /* ----------------------------------------------------------------------- */ +static inline bool is_analog_input(struct v4l2_subdev *sd) +{ + struct adv7604_state *state = to_state(sd); + + return state->selected_input == ADV7604_INPUT_VGA_RGB || + state->selected_input == ADV7604_INPUT_VGA_COMP; +} + +static inline bool is_digital_input(struct v4l2_subdev *sd) +{ + struct adv7604_state *state = to_state(sd); + + return state->selected_input == ADV7604_INPUT_HDMI_PORT_A || + state->selected_input == ADV7604_INPUT_HDMI_PORT_B || + state->selected_input == ADV7604_INPUT_HDMI_PORT_C || + state->selected_input == ADV7604_INPUT_HDMI_PORT_D; +} + +/* ----------------------------------------------------------------------- */ + #ifdef CONFIG_VIDEO_ADV_DEBUG static void adv7604_inv_register(struct v4l2_subdev *sd) { @@ -748,10 +769,13 @@ static int adv7604_s_register(struct v4l2_subdev *sd, static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); + u8 reg_io_6f = io_read(sd, 0x6f); - /* port A only */ return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, - ((io_read(sd, 0x6f) & 0x10) >> 4)); + ((reg_io_6f & 0x10) >> 4) | + ((reg_io_6f & 0x08) >> 2) | + (reg_io_6f & 0x04) | + ((reg_io_6f & 0x02) << 2)); } static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, @@ -759,12 +783,11 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, const struct adv7604_video_standards *predef_vid_timings, const struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); int i; for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings, - DIGITAL_INPUT ? 250000 : 1000000)) + is_digital_input(sd) ? 250000 : 1000000)) continue; io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */ io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + @@ -799,27 +822,22 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, cp_write(sd, 0xab, 0x00); cp_write(sd, 0xac, 0x00); - switch (state->mode) { - case ADV7604_MODE_COMP: - case ADV7604_MODE_GR: + if (is_analog_input(sd)) { err = find_and_set_predefined_video_timings(sd, 0x01, adv7604_prim_mode_comp, timings); if (err) err = find_and_set_predefined_video_timings(sd, 0x02, adv7604_prim_mode_gr, timings); - break; - case ADV7604_MODE_HDMI: + } else if (is_digital_input(sd)) { err = find_and_set_predefined_video_timings(sd, 0x05, adv7604_prim_mode_hdmi_comp, timings); if (err) err = find_and_set_predefined_video_timings(sd, 0x06, adv7604_prim_mode_hdmi_gr, timings); - break; - default: - v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", - __func__, state->mode); + } else { + v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", + __func__, state->selected_input); err = -1; - break; } @@ -846,9 +864,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, v4l2_dbg(2, debug, sd, "%s\n", __func__); - switch (state->mode) { - case ADV7604_MODE_COMP: - case ADV7604_MODE_GR: + if (is_analog_input(sd)) { /* auto graphics */ io_write(sd, 0x00, 0x07); /* video std */ io_write(sd, 0x01, 0x02); /* prim mode */ @@ -858,33 +874,28 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ - if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { + if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); - break; - } /* active video - horizontal timing */ cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff); cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | - ((cp_start_eav >> 8) & 0x0f)); + ((cp_start_eav >> 8) & 0x0f)); cp_write(sd, 0xa4, cp_start_eav & 0xff); /* active video - vertical timing */ cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | - ((cp_end_vbi >> 8) & 0xf)); + ((cp_end_vbi >> 8) & 0xf)); cp_write(sd, 0xa7, cp_end_vbi & 0xff); - break; - case ADV7604_MODE_HDMI: + } else if (is_digital_input(sd)) { /* set default prim_mode/vid_std for HDMI according to [REF_03, c. 4.2] */ io_write(sd, 0x00, 0x02); /* video std */ io_write(sd, 0x01, 0x06); /* prim mode */ - break; - default: - v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", - __func__, state->mode); - break; + } else { + v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", + __func__, state->selected_input); } cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); @@ -900,7 +911,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: /* automatic */ - if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) { + if (is_digital_input(sd) && !(hdmi_read(sd, 0x05) & 0x80)) { /* receiving DVI-D signal */ /* ADV7604 selects RGB limited range regardless of @@ -983,8 +994,9 @@ static inline bool no_power(struct v4l2_subdev *sd) static inline bool no_signal_tmds(struct v4l2_subdev *sd) { - /* TODO port B, C and D */ - return !(io_read(sd, 0x6a) & 0x10); + struct adv7604_state *state = to_state(sd); + + return !(io_read(sd, 0x6a) & (0x10 >> state->selected_input)); } static inline bool no_lock_tmds(struct v4l2_subdev *sd) @@ -1011,7 +1023,6 @@ static inline bool no_lock_stdi(struct v4l2_subdev *sd) static inline bool no_signal(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); bool ret; ret = no_power(sd); @@ -1019,7 +1030,7 @@ static inline bool no_signal(struct v4l2_subdev *sd) ret |= no_lock_stdi(sd); ret |= no_lock_sspd(sd); - if (DIGITAL_INPUT) { + if (is_digital_input(sd)) { ret |= no_lock_tmds(sd); ret |= no_signal_tmds(sd); } @@ -1036,13 +1047,11 @@ static inline bool no_lock_cp(struct v4l2_subdev *sd) static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status) { - struct adv7604_state *state = to_state(sd); - *status = 0; *status |= no_power(sd) ? V4L2_IN_ST_NO_POWER : 0; *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; if (no_lock_cp(sd)) - *status |= DIGITAL_INPUT ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK; + *status |= is_digital_input(sd) ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK; v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); @@ -1157,13 +1166,11 @@ static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, struct v4l2_dv_timings_cap *cap) { - struct adv7604_state *state = to_state(sd); - cap->type = V4L2_DV_BT_656_1120; cap->bt.max_width = 1920; cap->bt.max_height = 1200; cap->bt.min_pixelclock = 25000000; - if (DIGITAL_INPUT) + if (is_digital_input(sd)) cap->bt.max_pixelclock = 225000000; else cap->bt.max_pixelclock = 170000000; @@ -1179,12 +1186,11 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); int i; for (i = 0; adv7604_timings[i].bt.width; i++) { if (v4l2_match_dv_timings(timings, &adv7604_timings[i], - DIGITAL_INPUT ? 250000 : 1000000)) { + is_digital_input(sd) ? 250000 : 1000000)) { *timings = adv7604_timings[i]; break; } @@ -1216,7 +1222,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, bt->interlaced = stdi.interlaced ? V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; - if (DIGITAL_INPUT) { + if (is_digital_input(sd)) { uint32_t freq; timings->type = V4L2_DV_BT_656_1120; @@ -1305,8 +1311,8 @@ found: return -ENOLINK; } - if ((!DIGITAL_INPUT && bt->pixelclock > 170000000) || - (DIGITAL_INPUT && bt->pixelclock > 225000000)) { + if ((is_analog_input(sd) && bt->pixelclock > 170000000) || + (is_digital_input(sd) && bt->pixelclock > 225000000)) { v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n", __func__, (u32)bt->pixelclock); return -ERANGE; @@ -1331,8 +1337,8 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, bt = &timings->bt; - if ((!DIGITAL_INPUT && bt->pixelclock > 170000000) || - (DIGITAL_INPUT && bt->pixelclock > 225000000)) { + if ((is_analog_input(sd) && bt->pixelclock > 170000000) || + (is_digital_input(sd) && bt->pixelclock > 225000000)) { v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n", __func__, (u32)bt->pixelclock); return -ERANGE; @@ -1374,22 +1380,18 @@ static void enable_input(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); - switch (state->mode) { - case ADV7604_MODE_COMP: - case ADV7604_MODE_GR: + if (is_analog_input(sd)) { /* enable */ io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ - break; - case ADV7604_MODE_HDMI: + } else if (is_digital_input(sd)) { /* enable */ + hdmi_write_and_or(sd, 0x00, 0xfc, state->selected_input); hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */ hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ - break; - default: - v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", - __func__, state->mode); - break; + } else { + v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", + __func__, state->selected_input); } } @@ -1405,9 +1407,7 @@ static void select_input(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); - switch (state->mode) { - case ADV7604_MODE_COMP: - case ADV7604_MODE_GR: + if (is_analog_input(sd)) { /* reset ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ @@ -1433,9 +1433,9 @@ static void select_input(struct v4l2_subdev *sd) cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */ cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ - break; + } else if (is_digital_input(sd)) { + hdmi_write(sd, 0x00, state->selected_input & 0x03); - case ADV7604_MODE_HDMI: /* set ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ @@ -1461,12 +1461,9 @@ static void select_input(struct v4l2_subdev *sd) cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */ cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */ - - break; - default: - v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", - __func__, state->mode); - break; + } else { + v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", + __func__, state->selected_input); } } @@ -1477,7 +1474,7 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input); - state->mode = input; + state->selected_input = input; disable_input(sd); @@ -1524,7 +1521,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) fmt_change = io_read(sd, 0x43) & 0x98; if (fmt_change) io_write(sd, 0x44, fmt_change); - fmt_change_digital = DIGITAL_INPUT ? (io_read(sd, 0x6b) & 0xc0) : 0; + fmt_change_digital = is_digital_input(sd) ? (io_read(sd, 0x6b) & 0xc0) : 0; if (fmt_change_digital) io_write(sd, 0x6c, fmt_change_digital); if (fmt_change || fmt_change_digital) { @@ -1545,7 +1542,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) *handled = true; } /* tx 5v detect */ - tx_5v = io_read(sd, 0x70) & 0x10; + tx_5v = io_read(sd, 0x70) & 0x1e; if (tx_5v) { v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); io_write(sd, 0x71, tx_5v); @@ -1559,19 +1556,41 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) { struct adv7604_state *state = to_state(sd); + u8 *data = NULL; - if (edid->pad != 0) + if (edid->pad > ADV7604_EDID_PORT_D) return -EINVAL; if (edid->blocks == 0) return -EINVAL; - if (edid->start_block >= state->edid_blocks) + if (edid->blocks > 2) return -EINVAL; - if (edid->start_block + edid->blocks > state->edid_blocks) - edid->blocks = state->edid_blocks - edid->start_block; + if (edid->start_block > 1) + return -EINVAL; + if (edid->start_block == 1) + edid->blocks = 1; if (!edid->edid) return -EINVAL; - memcpy(edid->edid + edid->start_block * 128, - state->edid + edid->start_block * 128, + + if (edid->blocks > state->edid.blocks) + edid->blocks = state->edid.blocks; + + switch (edid->pad) { + case ADV7604_EDID_PORT_A: + case ADV7604_EDID_PORT_B: + case ADV7604_EDID_PORT_C: + case ADV7604_EDID_PORT_D: + if (state->edid.present & (1 << edid->pad)) + data = state->edid.edid; + break; + default: + return -EINVAL; + break; + } + if (!data) + return -ENODATA; + + memcpy(edid->edid, + data + edid->start_block * 128, edid->blocks * 128); return 0; } @@ -1581,33 +1600,50 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi struct adv7604_state *state = to_state(sd); int err; - if (edid->pad != 0) + if (edid->pad > ADV7604_EDID_PORT_D) return -EINVAL; if (edid->start_block != 0) return -EINVAL; if (edid->blocks == 0) { /* Pull down the hotplug pin */ - v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)0); + state->edid.present &= ~(1 << edid->pad); + v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); /* Disables I2C access to internal EDID ram from DDC port */ rep_write_and_or(sd, 0x77, 0xf0, 0x0); - state->edid_blocks = 0; + state->edid.blocks = 0; /* Fall back to a 16:9 aspect ratio */ state->aspect_ratio.numerator = 16; state->aspect_ratio.denominator = 9; + v4l2_dbg(2, debug, sd, "%s: clear edid\n", __func__); return 0; } - if (edid->blocks > 2) + if (edid->blocks > 2) { + edid->blocks = 2; return -E2BIG; + } if (!edid->edid) return -EINVAL; - memcpy(state->edid, edid->edid, 128 * edid->blocks); - state->edid_blocks = edid->blocks; + + cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); + state->edid.present &= ~(1 << edid->pad); + v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); + + memcpy(state->edid.edid, edid->edid, 128 * edid->blocks); + state->edid.blocks = edid->blocks; state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15], edid->edid[0x16]); - err = edid_write_block(sd, 128 * edid->blocks, state->edid); - if (err < 0) + state->edid.present |= edid->pad; + + err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid); + if (err < 0) { v4l2_err(sd, "error %d writing edid\n", err); - return err; + return err; + } + + /* enable hotplug after 100 ms */ + queue_delayed_work(state->work_queues, + &state->delayed_work_enable_hotplug, HZ / 10); + return 0; } /*********** avi info frame CEA-861-E **************/ @@ -1690,15 +1726,21 @@ static int adv7604_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "-----Chip status-----\n"); v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); v4l2_info(sd, "Connector type: %s\n", state->connector_hdmi ? - "HDMI" : (DIGITAL_INPUT ? "DVI-D" : "DVI-A")); - v4l2_info(sd, "EDID: %s\n", ((rep_read(sd, 0x7d) & 0x01) && - (rep_read(sd, 0x77) & 0x01)) ? "enabled" : "disabled "); + "HDMI" : (is_digital_input(sd) ? "DVI-D" : "DVI-A")); + v4l2_info(sd, "EDID enabled port A: %s, B: %s, C: %s, D: %s\n", + ((rep_read(sd, 0x7d) & 0x01) ? "Yes" : "No"), + ((rep_read(sd, 0x7d) & 0x02) ? "Yes" : "No"), + ((rep_read(sd, 0x7d) & 0x04) ? "Yes" : "No"), + ((rep_read(sd, 0x7d) & 0x08) ? "Yes" : "No")); v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? "enabled" : "disabled"); v4l2_info(sd, "-----Signal status-----\n"); - v4l2_info(sd, "Cable detected (+5V power): %s\n", - (io_read(sd, 0x6f) & 0x10) ? "true" : "false"); + v4l2_info(sd, "Cable detected (+5V power) port A: %s, B: %s, C: %s, D: %s\n", + ((io_read(sd, 0x6f) & 0x10) ? "Yes" : "No"), + ((io_read(sd, 0x6f) & 0x08) ? "Yes" : "No"), + ((io_read(sd, 0x6f) & 0x04) ? "Yes" : "No"), + ((io_read(sd, 0x6f) & 0x02) ? "Yes" : "No")); v4l2_info(sd, "TMDS signal detected: %s\n", no_signal_tmds(sd) ? "false" : "true"); v4l2_info(sd, "TMDS signal locked: %s\n", @@ -1744,11 +1786,14 @@ static int adv7604_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "Color space conversion: %s\n", csc_coeff_sel_rb[cp_read(sd, 0xfc) >> 4]); - if (!DIGITAL_INPUT) + if (!is_digital_input(sd)) return 0; v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); - v4l2_info(sd, "HDCP encrypted content: %s\n", (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false"); + v4l2_info(sd, "Digital video port selected: %c\n", + (hdmi_read(sd, 0x00) & 0x03) + 'A'); + v4l2_info(sd, "HDCP encrypted content: %s\n", + (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false"); v4l2_info(sd, "HDCP keys read: %s%s\n", (hdmi_read(sd, 0x04) & 0x20) ? "yes" : "no", (hdmi_read(sd, 0x04) & 0x10) ? "ERROR" : ""); @@ -1906,6 +1951,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd) ADI recommended setting [REF_01, c. 2.3.3] */ cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution for digital formats */ + rep_write(sd, 0x76, 0xc0); /* SPA location for port B, C and D */ /* TODO from platform data */ afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ @@ -1918,7 +1964,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd) io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */ io_write(sd, 0x6e, 0xc0); /* Enable V_LOCKED and DE_REGEN_LCK interrupts */ - io_write(sd, 0x73, 0x10); /* Enable CABLE_DET_A_ST (+5v) interrupt */ + io_write(sd, 0x73, 0x1e); /* Enable CABLE_DET_A_ST (+5v) interrupts */ return v4l2_ctrl_handler_setup(sd->ctrl_handler); } @@ -2020,7 +2066,7 @@ static int adv7604_probe(struct i2c_client *client, /* private controls */ state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, - V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); + V4L2_CID_DV_RX_POWER_PRESENT, 0, 0x0f, 0, 0); state->rgb_quantization_range_ctrl = v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops, V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, diff --git a/include/media/adv7604.h b/include/media/adv7604.h index dc004bc..0c96e16 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h @@ -131,16 +131,20 @@ struct adv7604_platform_data { u8 i2c_vdp; }; -/* - * Mode of operation. - * This is used as the input argument of the s_routing video op. - */ -enum adv7604_mode { - ADV7604_MODE_COMP, - ADV7604_MODE_GR, - ADV7604_MODE_HDMI, +enum adv7604_input_port { + ADV7604_INPUT_HDMI_PORT_A, + ADV7604_INPUT_HDMI_PORT_B, + ADV7604_INPUT_HDMI_PORT_C, + ADV7604_INPUT_HDMI_PORT_D, + ADV7604_INPUT_VGA_RGB, + ADV7604_INPUT_VGA_COMP, }; +#define ADV7604_EDID_PORT_A 0 +#define ADV7604_EDID_PORT_B 1 +#define ADV7604_EDID_PORT_C 2 +#define ADV7604_EDID_PORT_D 3 + #define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000) #define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CLASS_BASE + 0x1001) #define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002) -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 02/15] adv7604: add hdmi driver strength adjustment 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 03/15] adv7604: support 1366x768 DMT Reduced Blanking Hans Verkuil ` (12 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mikhail Khelik, Hans Verkuil From: Mikhail Khelik <mkhelik@cisco.com> The driver strength is board dependent, so set it from the platform_data. Signed-off-by: Mikhail Khelik <mkhelik@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 7 ++++++- include/media/adv7604.h | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 6372d31..99734b2 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1942,7 +1942,12 @@ static int adv7604_core_init(struct v4l2_subdev *sd) /* TODO from platform data */ cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ io_write(sd, 0x06, 0xa6); /* positive VS and HS */ - io_write(sd, 0x14, 0x7f); /* Drive strength adjusted to max */ + + /* Adjust drive strength */ + io_write(sd, 0x14, 0x40 | pdata->dr_str << 4 | + pdata->dr_str_clk << 2 | + pdata->dr_str_sync); + cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */ cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold - diff --git a/include/media/adv7604.h b/include/media/adv7604.h index 0c96e16..0e13d1b 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h @@ -110,6 +110,11 @@ struct adv7604_platform_data { unsigned replicate_av_codes:1; unsigned invert_cbcr:1; + /* IO register 0x14 */ + unsigned dr_str:2; + unsigned dr_str_clk:2; + unsigned dr_str_sync:2; + /* IO register 0x30 */ unsigned output_bus_lsb_to_msb:1; -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 03/15] adv7604: support 1366x768 DMT Reduced Blanking 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 02/15] adv7604: add hdmi driver strength adjustment Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 04/15] adv7604: adv7604_s_register clean up Hans Verkuil ` (11 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Martin Bugge, Hans Verkuil From: Martin Bugge <marbugge@cisco.com> Signed-off-by: Martin Bugge <marbugge@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 99734b2..417468c 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -161,6 +161,7 @@ static const struct v4l2_dv_timings adv7604_timings[] = { V4L2_DV_BT_DMT_1792X1344P60, V4L2_DV_BT_DMT_1856X1392P60, V4L2_DV_BT_DMT_1920X1200P60_RB, + V4L2_DV_BT_DMT_1366X768P60_RB, V4L2_DV_BT_DMT_1366X768P60, V4L2_DV_BT_DMT_1920X1080P60, { }, -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 04/15] adv7604: adv7604_s_register clean up. 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 02/15] adv7604: add hdmi driver strength adjustment Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 03/15] adv7604: support 1366x768 DMT Reduced Blanking Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 05/15] adv7604: Receive CEA formats as RGB on VGA (RGB) input Hans Verkuil ` (10 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Hans Verkuil From: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 417468c..37f3994 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -718,45 +718,47 @@ static int adv7604_g_register(struct v4l2_subdev *sd, static int adv7604_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { + u8 val = reg->val & 0xff; + switch (reg->reg >> 8) { case 0: - io_write(sd, reg->reg & 0xff, reg->val & 0xff); + io_write(sd, reg->reg & 0xff, val); break; case 1: - avlink_write(sd, reg->reg & 0xff, reg->val & 0xff); + avlink_write(sd, reg->reg & 0xff, val); break; case 2: - cec_write(sd, reg->reg & 0xff, reg->val & 0xff); + cec_write(sd, reg->reg & 0xff, val); break; case 3: - infoframe_write(sd, reg->reg & 0xff, reg->val & 0xff); + infoframe_write(sd, reg->reg & 0xff, val); break; case 4: - esdp_write(sd, reg->reg & 0xff, reg->val & 0xff); + esdp_write(sd, reg->reg & 0xff, val); break; case 5: - dpp_write(sd, reg->reg & 0xff, reg->val & 0xff); + dpp_write(sd, reg->reg & 0xff, val); break; case 6: - afe_write(sd, reg->reg & 0xff, reg->val & 0xff); + afe_write(sd, reg->reg & 0xff, val); break; case 7: - rep_write(sd, reg->reg & 0xff, reg->val & 0xff); + rep_write(sd, reg->reg & 0xff, val); break; case 8: - edid_write(sd, reg->reg & 0xff, reg->val & 0xff); + edid_write(sd, reg->reg & 0xff, val); break; case 9: - hdmi_write(sd, reg->reg & 0xff, reg->val & 0xff); + hdmi_write(sd, reg->reg & 0xff, val); break; case 0xa: - test_write(sd, reg->reg & 0xff, reg->val & 0xff); + test_write(sd, reg->reg & 0xff, val); break; case 0xb: - cp_write(sd, reg->reg & 0xff, reg->val & 0xff); + cp_write(sd, reg->reg & 0xff, val); break; case 0xc: - vdp_write(sd, reg->reg & 0xff, reg->val & 0xff); + vdp_write(sd, reg->reg & 0xff, val); break; default: v4l2_info(sd, "Register %03llx not supported\n", reg->reg); -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 05/15] adv7604: Receive CEA formats as RGB on VGA (RGB) input 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (2 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 04/15] adv7604: adv7604_s_register clean up Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 06/15] adv7604: select YPbPr if RGB_RANGE_FULL/LIMITED is set for VGA_COMP inputs Hans Verkuil ` (9 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> If the input is ADV7604_INPUT_VGA_RGB and RGB quantization range is set to V4L2_DV_RGB_RANGE_AUTO, video with CEA timings will be received as RGB. For ADV7604_INPUT_VGA_COMP, automatic CSC mode will be selected. See table 44 on page 205 in "ADV7604 Hardware Manual, Rev. F, August 2010" for details. Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 50 ++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 37f3994..7187378 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -911,25 +911,41 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); + v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n", + __func__, state->rgb_quantization_range); + switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: - /* automatic */ - if (is_digital_input(sd) && !(hdmi_read(sd, 0x05) & 0x80)) { - /* receiving DVI-D signal */ - - /* ADV7604 selects RGB limited range regardless of - input format (CE/IT) in automatic mode */ - if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { - /* RGB limited range (16-235) */ - io_write_and_or(sd, 0x02, 0x0f, 0x00); - - } else { - /* RGB full range (0-255) */ - io_write_and_or(sd, 0x02, 0x0f, 0x10); - } - } else { - /* receiving HDMI or analog signal, set automode */ + if (state->selected_input == ADV7604_INPUT_VGA_RGB) { + /* Receiving analog RGB signal + * Set RGB full range (0-255) */ + io_write_and_or(sd, 0x02, 0x0f, 0x10); + break; + } + + if (state->selected_input == ADV7604_INPUT_VGA_COMP) { + /* Receiving analog YPbPr signal + * Set automode */ + io_write_and_or(sd, 0x02, 0x0f, 0xf0); + break; + } + + if (hdmi_read(sd, 0x05) & 0x80) { + /* Receiving HDMI signal + * Set automode */ io_write_and_or(sd, 0x02, 0x0f, 0xf0); + break; + } + + /* Receiving DVI-D signal + * ADV7604 selects RGB limited range regardless of + * input format (CE/IT) in automatic mode */ + if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { + /* RGB limited range (16-235) */ + io_write_and_or(sd, 0x02, 0x0f, 0x00); + } else { + /* RGB full range (0-255) */ + io_write_and_or(sd, 0x02, 0x0f, 0x10); } break; case V4L2_DV_RGB_RANGE_LIMITED: @@ -1709,7 +1725,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd) char *input_color_space_txt[16] = { "RGB limited range (16-235)", "RGB full range (0-255)", "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", - "XvYCC Bt.601", "XvYCC Bt.709", + "xvYCC Bt.601", "xvYCC Bt.709", "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", "invalid", "invalid", "invalid", "invalid", "invalid", "invalid", "invalid", "automatic" -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 06/15] adv7604: select YPbPr if RGB_RANGE_FULL/LIMITED is set for VGA_COMP inputs 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (3 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 05/15] adv7604: Receive CEA formats as RGB on VGA (RGB) input Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 07/15] adv7604: set CEC address (SPA) in EDID Hans Verkuil ` (8 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 7187378..b53373b 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -949,17 +949,26 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) } break; case V4L2_DV_RGB_RANGE_LIMITED: - /* RGB limited range (16-235) */ - io_write_and_or(sd, 0x02, 0x0f, 0x00); + if (state->selected_input == ADV7604_INPUT_VGA_COMP) { + /* YCrCb limited range (16-235) */ + io_write_and_or(sd, 0x02, 0x0f, 0x20); + } else { + /* RGB limited range (16-235) */ + io_write_and_or(sd, 0x02, 0x0f, 0x00); + } break; case V4L2_DV_RGB_RANGE_FULL: - /* RGB full range (0-255) */ - io_write_and_or(sd, 0x02, 0x0f, 0x10); + if (state->selected_input == ADV7604_INPUT_VGA_COMP) { + /* YCrCb full range (0-255) */ + io_write_and_or(sd, 0x02, 0x0f, 0x60); + } else { + /* RGB full range (0-255) */ + io_write_and_or(sd, 0x02, 0x0f, 0x10); + } break; } } - static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 07/15] adv7604: set CEC address (SPA) in EDID 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (4 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 06/15] adv7604: select YPbPr if RGB_RANGE_FULL/LIMITED is set for VGA_COMP inputs Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 08/15] adv7604: improve EDID handling Hans Verkuil ` (7 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 83 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index b53373b..5e40a60 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -72,6 +72,7 @@ struct adv7604_state { u32 present; unsigned blocks; } edid; + u16 spa_port_a; struct v4l2_fract aspect_ratio; u32 rgb_quantization_range; struct workqueue_struct *work_queues; @@ -531,9 +532,6 @@ static inline int edid_write_block(struct v4l2_subdev *sd, v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); - /* Disables I2C access to internal EDID ram from DDC port */ - rep_write_and_or(sd, 0x77, 0xf0, 0x0); - for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, I2C_SMBUS_BLOCK_MAX, val + i); @@ -1623,9 +1621,39 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi return 0; } +static int get_edid_spa_location(struct v4l2_subdev *sd, const u8 *edid) +{ + u8 d; + + if ((edid[0x7e] != 1) || + (edid[0x80] != 0x02) || + (edid[0x81] != 0x03)) { + return -1; + } + + /* search Vendor Specific Data Block (tag 3) */ + d = edid[0x82] & 0x7f; + if (d > 4) { + int i = 0x84; + int end = 0x80 + d; + + do { + u8 tag = edid[i] >> 5; + u8 len = edid[i] & 0x1f; + + if ((tag == 3) && (len >= 5)) + return i + 4; + i += len + 1; + } while (i < end); + } + return -1; +} + static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) { struct adv7604_state *state = to_state(sd); + int spa_loc = get_edid_spa_location(sd, edid->edid); + int tmp = 0; int err; if (edid->pad > ADV7604_EDID_PORT_D) @@ -1633,16 +1661,20 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi if (edid->start_block != 0) return -EINVAL; if (edid->blocks == 0) { - /* Pull down the hotplug pin */ + /* Disable hotplug and I2C access to EDID RAM from DDC port */ state->edid.present &= ~(1 << edid->pad); v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); - /* Disables I2C access to internal EDID ram from DDC port */ - rep_write_and_or(sd, 0x77, 0xf0, 0x0); - state->edid.blocks = 0; + rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); + /* Fall back to a 16:9 aspect ratio */ state->aspect_ratio.numerator = 16; state->aspect_ratio.denominator = 9; - v4l2_dbg(2, debug, sd, "%s: clear edid\n", __func__); + + if (!state->edid.present) + state->edid.blocks = 0; + + v4l2_dbg(2, debug, sd, "%s: clear EDID pad %d, edid.present = 0x%x\n", + __func__, edid->pad, state->edid.present); return 0; } if (edid->blocks > 2) { @@ -1652,19 +1684,45 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi if (!edid->edid) return -EINVAL; + /* Disable hotplug and I2C access to EDID RAM from DDC port */ cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); - state->edid.present &= ~(1 << edid->pad); - v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); + v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp); + rep_write_and_or(sd, 0x77, 0xf0, 0x00); + + v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", + __func__, edid->pad, state->edid.present); + switch (edid->pad) { + case ADV7604_EDID_PORT_A: + state->spa_port_a = edid->edid[spa_loc]; + break; + case ADV7604_EDID_PORT_B: + rep_write(sd, 0x70, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); + rep_write(sd, 0x71, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); + break; + case ADV7604_EDID_PORT_C: + rep_write(sd, 0x72, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); + rep_write(sd, 0x73, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); + break; + case ADV7604_EDID_PORT_D: + rep_write(sd, 0x74, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); + rep_write(sd, 0x75, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); + break; + } + rep_write(sd, 0x76, (spa_loc < 0) ? 0x00 : spa_loc); + rep_write_and_or(sd, 0x77, 0xbf, (spa_loc < 0) ? 0x00 : (spa_loc >> 2) & 0x40); + + if (spa_loc > 0) + edid->edid[spa_loc] = state->spa_port_a; memcpy(state->edid.edid, edid->edid, 128 * edid->blocks); state->edid.blocks = edid->blocks; state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15], edid->edid[0x16]); - state->edid.present |= edid->pad; + state->edid.present |= 1 << edid->pad; err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid); if (err < 0) { - v4l2_err(sd, "error %d writing edid\n", err); + v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad); return err; } @@ -1984,7 +2042,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd) ADI recommended setting [REF_01, c. 2.3.3] */ cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution for digital formats */ - rep_write(sd, 0x76, 0xc0); /* SPA location for port B, C and D */ /* TODO from platform data */ afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 08/15] adv7604: improve EDID handling 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (5 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 07/15] adv7604: set CEC address (SPA) in EDID Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 09/15] adv7604: remove connector type. Never used for anything useful Hans Verkuil ` (6 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> - split edid_write_block() - do not use edid->edid before the validity check - Return -EINVAL if edid->pad is invalid - Save both registers for SPA port A - Set SPA location to default value if it is not found Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 94 ++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 5e40a60..4ce3815 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -72,7 +72,7 @@ struct adv7604_state { u32 present; unsigned blocks; } edid; - u16 spa_port_a; + u16 spa_port_a[2]; struct v4l2_fract aspect_ratio; u32 rgb_quantization_range; struct workqueue_struct *work_queues; @@ -510,22 +510,9 @@ static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) return 0; } -static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct adv7604_state *state = container_of(dwork, struct adv7604_state, - delayed_work_enable_hotplug); - struct v4l2_subdev *sd = &state->sd; - - v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); - - v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); -} - static inline int edid_write_block(struct v4l2_subdev *sd, unsigned len, const u8 *val) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct adv7604_state *state = to_state(sd); int err = 0; int i; @@ -535,24 +522,19 @@ static inline int edid_write_block(struct v4l2_subdev *sd, for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, I2C_SMBUS_BLOCK_MAX, val + i); - if (err) - return err; + return err; +} - /* adv7604 calculates the checksums and enables I2C access to internal - EDID RAM from DDC port. */ - rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); +static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct adv7604_state *state = container_of(dwork, struct adv7604_state, + delayed_work_enable_hotplug); + struct v4l2_subdev *sd = &state->sd; - for (i = 0; i < 1000; i++) { - if (rep_read(sd, 0x7d) & state->edid.present) - break; - mdelay(1); - } - if (i == 1000) { - v4l_err(client, "error enabling edid (0x%x)\n", state->edid.present); - return -EIO; - } + v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); - return 0; + v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); } static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) @@ -1621,7 +1603,7 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi return 0; } -static int get_edid_spa_location(struct v4l2_subdev *sd, const u8 *edid) +static int get_edid_spa_location(const u8 *edid) { u8 d; @@ -1652,9 +1634,10 @@ static int get_edid_spa_location(struct v4l2_subdev *sd, const u8 *edid) static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) { struct adv7604_state *state = to_state(sd); - int spa_loc = get_edid_spa_location(sd, edid->edid); + int spa_loc; int tmp = 0; int err; + int i; if (edid->pad > ADV7604_EDID_PORT_D) return -EINVAL; @@ -1684,35 +1667,43 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi if (!edid->edid) return -EINVAL; + v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", + __func__, edid->pad, state->edid.present); + /* Disable hotplug and I2C access to EDID RAM from DDC port */ cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp); rep_write_and_or(sd, 0x77, 0xf0, 0x00); - v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", - __func__, edid->pad, state->edid.present); + spa_loc = get_edid_spa_location(edid->edid); + if (spa_loc < 0) + spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ + switch (edid->pad) { case ADV7604_EDID_PORT_A: - state->spa_port_a = edid->edid[spa_loc]; + state->spa_port_a[0] = edid->edid[spa_loc]; + state->spa_port_a[1] = edid->edid[spa_loc + 1]; break; case ADV7604_EDID_PORT_B: - rep_write(sd, 0x70, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); - rep_write(sd, 0x71, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); + rep_write(sd, 0x70, edid->edid[spa_loc]); + rep_write(sd, 0x71, edid->edid[spa_loc + 1]); break; case ADV7604_EDID_PORT_C: - rep_write(sd, 0x72, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); - rep_write(sd, 0x73, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); + rep_write(sd, 0x72, edid->edid[spa_loc]); + rep_write(sd, 0x73, edid->edid[spa_loc + 1]); break; case ADV7604_EDID_PORT_D: - rep_write(sd, 0x74, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); - rep_write(sd, 0x75, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); + rep_write(sd, 0x74, edid->edid[spa_loc]); + rep_write(sd, 0x75, edid->edid[spa_loc + 1]); break; + default: + return -EINVAL; } - rep_write(sd, 0x76, (spa_loc < 0) ? 0x00 : spa_loc); - rep_write_and_or(sd, 0x77, 0xbf, (spa_loc < 0) ? 0x00 : (spa_loc >> 2) & 0x40); + rep_write(sd, 0x76, spa_loc & 0xff); + rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); - if (spa_loc > 0) - edid->edid[spa_loc] = state->spa_port_a; + edid->edid[spa_loc] = state->spa_port_a[0]; + edid->edid[spa_loc + 1] = state->spa_port_a[1]; memcpy(state->edid.edid, edid->edid, 128 * edid->blocks); state->edid.blocks = edid->blocks; @@ -1726,6 +1717,21 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi return err; } + /* adv7604 calculates the checksums and enables I2C access to internal + EDID RAM from DDC port. */ + rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); + + for (i = 0; i < 1000; i++) { + if (rep_read(sd, 0x7d) & state->edid.present) + break; + mdelay(1); + } + if (i == 1000) { + v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present); + return -EIO; + } + + /* enable hotplug after 100 ms */ queue_delayed_work(state->work_queues, &state->delayed_work_enable_hotplug, HZ / 10); -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 09/15] adv7604: remove connector type. Never used for anything useful. 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (6 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 08/15] adv7604: improve EDID handling Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 10/15] adv7604: return immediately if the new input is equal to what is configured Hans Verkuil ` (5 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> May also be wrong if the receiver is connected to more than one connector. Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 4 ---- include/media/adv7604.h | 3 --- 2 files changed, 7 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 4ce3815..7d95a28 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -77,7 +77,6 @@ struct adv7604_state { u32 rgb_quantization_range; struct workqueue_struct *work_queues; struct delayed_work delayed_work_enable_hotplug; - bool connector_hdmi; bool restart_stdi_once; u32 prev_input_status; @@ -1817,8 +1816,6 @@ static int adv7604_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "-----Chip status-----\n"); v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); - v4l2_info(sd, "Connector type: %s\n", state->connector_hdmi ? - "HDMI" : (is_digital_input(sd) ? "DVI-D" : "DVI-A")); v4l2_info(sd, "EDID enabled port A: %s, B: %s, C: %s, D: %s\n", ((rep_read(sd, 0x7d) & 0x01) ? "Yes" : "No"), ((rep_read(sd, 0x7d) & 0x02) ? "Yes" : "No"), @@ -2138,7 +2135,6 @@ static int adv7604_probe(struct i2c_client *client, sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7604_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - state->connector_hdmi = pdata->connector_hdmi; /* i2c access to adv7604? */ if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) { diff --git a/include/media/adv7604.h b/include/media/adv7604.h index 0e13d1b..0162c31 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h @@ -80,9 +80,6 @@ enum adv7604_op_format_sel { /* Platform dependent definition */ struct adv7604_platform_data { - /* connector - HDMI or DVI? */ - unsigned connector_hdmi:1; - /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */ unsigned disable_pwrdnb:1; -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 10/15] adv7604: return immediately if the new input is equal to what is configured 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (7 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 09/15] adv7604: remove connector type. Never used for anything useful Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 11/15] adv7604: remove debouncing of ADV7604_FMT_CHANGE events Hans Verkuil ` (4 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 7d95a28..fa98229 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1479,7 +1479,11 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, { struct adv7604_state *state = to_state(sd); - v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input); + v4l2_dbg(2, debug, sd, "%s: input %d, selected input %d", + __func__, input, state->selected_input); + + if (input == state->selected_input) + return 0; state->selected_input = input; @@ -1524,6 +1528,8 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) u8 fmt_change, fmt_change_digital, tx_5v; u32 input_status; + v4l2_dbg(2, debug, sd, "%s: ", __func__); + /* format change */ fmt_change = io_read(sd, 0x43) & 0x98; if (fmt_change) @@ -2124,6 +2130,7 @@ static int adv7604_probe(struct i2c_client *client, /* initialize variables */ state->restart_stdi_once = true; state->prev_input_status = ~0; + state->selected_input = ~0; /* platform data */ if (!pdata) { -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 11/15] adv7604: remove debouncing of ADV7604_FMT_CHANGE events 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (8 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 10/15] adv7604: return immediately if the new input is equal to what is configured Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 12/15] adv7604: improve HDMI audio handling Hans Verkuil ` (3 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> ADV7604_FMT_CHANGE events was debounced in adv7604_isr() to avoid that a receiver with a unstable input signal would block the event handling for other inputs. This solution was prone to errors. A better protection agains interrupt blocking is to delay the call of the interrupt service routine in the adv7604 driver if too many interrupts are received within a given time. Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index fa98229..50f0279 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -78,7 +78,6 @@ struct adv7604_state { struct workqueue_struct *work_queues; struct delayed_work delayed_work_enable_hotplug; bool restart_stdi_once; - u32 prev_input_status; /* i2c clients */ struct i2c_client *i2c_avlink; @@ -1524,9 +1523,7 @@ static int adv7604_g_mbus_fmt(struct v4l2_subdev *sd, static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { - struct adv7604_state *state = to_state(sd); u8 fmt_change, fmt_change_digital, tx_5v; - u32 input_status; v4l2_dbg(2, debug, sd, "%s: ", __func__); @@ -1534,22 +1531,17 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) fmt_change = io_read(sd, 0x43) & 0x98; if (fmt_change) io_write(sd, 0x44, fmt_change); + fmt_change_digital = is_digital_input(sd) ? (io_read(sd, 0x6b) & 0xc0) : 0; if (fmt_change_digital) io_write(sd, 0x6c, fmt_change_digital); + if (fmt_change || fmt_change_digital) { v4l2_dbg(1, debug, sd, "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n", __func__, fmt_change, fmt_change_digital); - adv7604_g_input_status(sd, &input_status); - if (input_status != state->prev_input_status) { - v4l2_dbg(1, debug, sd, - "%s: input_status = 0x%x, prev_input_status = 0x%x\n", - __func__, input_status, state->prev_input_status); - state->prev_input_status = input_status; - v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL); - } + v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL); if (handled) *handled = true; @@ -2129,7 +2121,6 @@ static int adv7604_probe(struct i2c_client *client, /* initialize variables */ state->restart_stdi_once = true; - state->prev_input_status = ~0; state->selected_input = ~0; /* platform data */ -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 12/15] adv7604: improve HDMI audio handling 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (9 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 11/15] adv7604: remove debouncing of ADV7604_FMT_CHANGE events Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 13/15] adv7604: set restart_stdi_once flag when signal is lost Hans Verkuil ` (2 subsequent siblings) 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> - Mute audio before switching inputs to avoid noise/pops - Mute audio if audio FIFO over-/underflows (AD Recommended setting) - Reset FIFO if it over-/underflows (AD Recommended setting) Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 50f0279..cbeda0f 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1387,14 +1387,12 @@ static void enable_input(struct v4l2_subdev *sd) struct adv7604_state *state = to_state(sd); if (is_analog_input(sd)) { - /* enable */ io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ } else if (is_digital_input(sd)) { - /* enable */ hdmi_write_and_or(sd, 0x00, 0xfc, state->selected_input); - hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */ hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ + hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */ } else { v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", __func__, state->selected_input); @@ -1403,9 +1401,9 @@ static void enable_input(struct v4l2_subdev *sd) static void disable_input(struct v4l2_subdev *sd) { - /* disable */ + hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio */ + msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */ io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ - hdmi_write(sd, 0x1a, 0x1a); /* Mute audio */ hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ } @@ -2044,6 +2042,11 @@ static int adv7604_core_init(struct v4l2_subdev *sd) cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution for digital formats */ + /* HDMI audio */ + hdmi_write_and_or(sd, 0x15, 0xfc, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */ + hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */ + hdmi_write_and_or(sd, 0x68, 0xf9, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */ + /* TODO from platform data */ afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 13/15] adv7604: set restart_stdi_once flag when signal is lost. 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (10 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 12/15] adv7604: improve HDMI audio handling Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 14/15] adv7604: adjust gain and offset for DVI-D signals Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 15/15] adv7604: Enable HDMI_MODE interrupt Hans Verkuil 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Martin Bugge, Mats Randgaard, Hans Verkuil From: Martin Bugge <marbugge@cisco.com> If the restart_stdi_once trick fails to find a valid format the flag was never reset. Signed-off-by: Martin Bugge <marbugge@cisco.com> Cc: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index cbeda0f..0e69b24 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1216,6 +1216,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, memset(timings, 0, sizeof(struct v4l2_dv_timings)); if (no_signal(sd)) { + state->restart_stdi_once = true; v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); return -ENOLINK; } -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 14/15] adv7604: adjust gain and offset for DVI-D signals 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (11 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 13/15] adv7604: set restart_stdi_once flag when signal is lost Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 15/15] adv7604: Enable HDMI_MODE interrupt Hans Verkuil 13 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> If the input signal is DVI-D and quantization range is RGB full range, gain and offset must be adjusted to get the right range on the output. Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 98 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 0e69b24..c195a92 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -885,12 +885,72 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, cp_write(sd, 0xac, (height & 0x0f) << 4); } +static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c) +{ + struct adv7604_state *state = to_state(sd); + u8 offset_buf[4]; + + if (auto_offset) { + offset_a = 0x3ff; + offset_b = 0x3ff; + offset_c = 0x3ff; + } + + v4l2_dbg(2, debug, sd, "%s: %s offset: a = 0x%x, b = 0x%x, c = 0x%x\n", + __func__, auto_offset ? "Auto" : "Manual", + offset_a, offset_b, offset_c); + + offset_buf[0] = (cp_read(sd, 0x77) & 0xc0) | ((offset_a & 0x3f0) >> 4); + offset_buf[1] = ((offset_a & 0x00f) << 4) | ((offset_b & 0x3c0) >> 6); + offset_buf[2] = ((offset_b & 0x03f) << 2) | ((offset_c & 0x300) >> 8); + offset_buf[3] = offset_c & 0x0ff; + + /* Registers must be written in this order with no i2c access in between */ + if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf)) + v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); +} + +static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c) +{ + struct adv7604_state *state = to_state(sd); + u8 gain_buf[4]; + u8 gain_man = 1; + u8 agc_mode_man = 1; + + if (auto_gain) { + gain_man = 0; + agc_mode_man = 0; + gain_a = 0x100; + gain_b = 0x100; + gain_c = 0x100; + } + + v4l2_dbg(2, debug, sd, "%s: %s gain: a = 0x%x, b = 0x%x, c = 0x%x\n", + __func__, auto_gain ? "Auto" : "Manual", + gain_a, gain_b, gain_c); + + gain_buf[0] = ((gain_man << 7) | (agc_mode_man << 6) | ((gain_a & 0x3f0) >> 4)); + gain_buf[1] = (((gain_a & 0x00f) << 4) | ((gain_b & 0x3c0) >> 6)); + gain_buf[2] = (((gain_b & 0x03f) << 2) | ((gain_c & 0x300) >> 8)); + gain_buf[3] = ((gain_c & 0x0ff)); + + /* Registers must be written in this order with no i2c access in between */ + if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf)) + v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); +} + static void set_rgb_quantization_range(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); + bool rgb_output = io_read(sd, 0x02) & 0x02; + bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; + + v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", + __func__, state->rgb_quantization_range, + rgb_output, hdmi_signal); - v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n", - __func__, state->rgb_quantization_range); + adv7604_set_gain(sd, true, 0x0, 0x0, 0x0); + adv7604_set_offset(sd, true, 0x0, 0x0, 0x0); switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: @@ -908,7 +968,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) break; } - if (hdmi_read(sd, 0x05) & 0x80) { + if (hdmi_signal) { /* Receiving HDMI signal * Set automode */ io_write_and_or(sd, 0x02, 0x0f, 0xf0); @@ -924,24 +984,45 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) } else { /* RGB full range (0-255) */ io_write_and_or(sd, 0x02, 0x0f, 0x10); + + if (is_digital_input(sd) && rgb_output) { + adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); + } else { + adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0); + adv7604_set_offset(sd, false, 0x70, 0x70, 0x70); + } } break; case V4L2_DV_RGB_RANGE_LIMITED: if (state->selected_input == ADV7604_INPUT_VGA_COMP) { /* YCrCb limited range (16-235) */ io_write_and_or(sd, 0x02, 0x0f, 0x20); - } else { - /* RGB limited range (16-235) */ - io_write_and_or(sd, 0x02, 0x0f, 0x00); + break; } + + /* RGB limited range (16-235) */ + io_write_and_or(sd, 0x02, 0x0f, 0x00); + break; case V4L2_DV_RGB_RANGE_FULL: if (state->selected_input == ADV7604_INPUT_VGA_COMP) { /* YCrCb full range (0-255) */ io_write_and_or(sd, 0x02, 0x0f, 0x60); + break; + } + + /* RGB full range (0-255) */ + io_write_and_or(sd, 0x02, 0x0f, 0x10); + + if (is_analog_input(sd) || hdmi_signal) + break; + + /* Adjust gain/offset for DVI-D signals only */ + if (rgb_output) { + adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); } else { - /* RGB full range (0-255) */ - io_write_and_or(sd, 0x02, 0x0f, 0x10); + adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0); + adv7604_set_offset(sd, false, 0x70, 0x70, 0x70); } break; } @@ -1367,7 +1448,6 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, set_rgb_quantization_range(sd); - if (debug > 1) v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ", timings, true); -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 15/15] adv7604: Enable HDMI_MODE interrupt 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil ` (12 preceding siblings ...) 2013-12-10 13:23 ` [RFC PATCH 14/15] adv7604: adjust gain and offset for DVI-D signals Hans Verkuil @ 2013-12-10 13:23 ` Hans Verkuil 2013-12-17 13:14 ` [RFC PATCH 16/15] adv7604: return immediately if the new timings are equal to what is configured Hans Verkuil ` (2 more replies) 13 siblings, 3 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-10 13:23 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil From: Mats Randgaard <matrandg@cisco.com> Some sources are initially detected as DVI, and change to HDMI later. This must be detected to set the right RGB quantization range. Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index c195a92..cfeaaaf 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1602,18 +1602,25 @@ static int adv7604_g_mbus_fmt(struct v4l2_subdev *sd, static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { - u8 fmt_change, fmt_change_digital, tx_5v; + const u8 irq_reg_0x43 = io_read(sd, 0x43); + const u8 irq_reg_0x6b = io_read(sd, 0x6b); + const u8 irq_reg_0x70 = io_read(sd, 0x70); + u8 fmt_change_digital; + u8 fmt_change; + u8 tx_5v; + + if (irq_reg_0x43) + io_write(sd, 0x44, irq_reg_0x43); + if (irq_reg_0x70) + io_write(sd, 0x71, irq_reg_0x70); + if (irq_reg_0x6b) + io_write(sd, 0x6c, irq_reg_0x6b); v4l2_dbg(2, debug, sd, "%s: ", __func__); /* format change */ - fmt_change = io_read(sd, 0x43) & 0x98; - if (fmt_change) - io_write(sd, 0x44, fmt_change); - - fmt_change_digital = is_digital_input(sd) ? (io_read(sd, 0x6b) & 0xc0) : 0; - if (fmt_change_digital) - io_write(sd, 0x6c, fmt_change_digital); + fmt_change = irq_reg_0x43 & 0x98; + fmt_change_digital = is_digital_input(sd) ? (irq_reg_0x6b & 0xc0) : 0; if (fmt_change || fmt_change_digital) { v4l2_dbg(1, debug, sd, @@ -1625,6 +1632,15 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) if (handled) *handled = true; } + /* HDMI/DVI mode */ + if (irq_reg_0x6b & 0x01) { + v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__, + (io_read(sd, 0x6a) & 0x01) ? "HDMI" : "DVI"); + set_rgb_quantization_range(sd); + if (handled) + *handled = true; + } + /* tx 5v detect */ tx_5v = io_read(sd, 0x70) & 0x1e; if (tx_5v) { @@ -2138,7 +2154,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd) io_write(sd, 0x40, 0xc2); /* Configure INT1 */ io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */ - io_write(sd, 0x6e, 0xc0); /* Enable V_LOCKED and DE_REGEN_LCK interrupts */ + io_write(sd, 0x6e, 0xc1); /* Enable V_LOCKED, DE_REGEN_LCK, HDMI_MODE interrupts */ io_write(sd, 0x73, 0x1e); /* Enable CABLE_DET_A_ST (+5v) interrupts */ return v4l2_ctrl_handler_setup(sd->ctrl_handler); -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 16/15] adv7604: return immediately if the new timings are equal to what is configured 2013-12-10 13:23 ` [RFC PATCH 15/15] adv7604: Enable HDMI_MODE interrupt Hans Verkuil @ 2013-12-17 13:14 ` Hans Verkuil 2013-12-17 13:15 ` [RFC PATCH 17/15] adv7604: sync polarities from platform data Hans Verkuil 2013-12-17 13:15 ` [RFC PATCH 18/15] adv7604: initialize timings to CEA 640x480p59.94 Hans Verkuil 2 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-17 13:14 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index cfeaaaf..a1fa9a0 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1423,6 +1423,11 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, if (!timings) return -EINVAL; + if (v4l2_match_dv_timings(&state->timings, timings, 0)) { + v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); + return 0; + } + bt = &timings->bt; if ((is_analog_input(sd) && bt->pixelclock > 170000000) || -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 17/15] adv7604: sync polarities from platform data 2013-12-10 13:23 ` [RFC PATCH 15/15] adv7604: Enable HDMI_MODE interrupt Hans Verkuil 2013-12-17 13:14 ` [RFC PATCH 16/15] adv7604: return immediately if the new timings are equal to what is configured Hans Verkuil @ 2013-12-17 13:15 ` Hans Verkuil 2013-12-17 13:15 ` [RFC PATCH 18/15] adv7604: initialize timings to CEA 640x480p59.94 Hans Verkuil 2 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-17 13:15 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil Signed-off-by: Martin Bugge <marbugge@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 5 +++-- include/media/adv7604.h | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index a1fa9a0..3f40616 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2126,9 +2126,10 @@ static int adv7604_core_init(struct v4l2_subdev *sd) pdata->replicate_av_codes << 1 | pdata->invert_cbcr << 0); - /* TODO from platform data */ cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ - io_write(sd, 0x06, 0xa6); /* positive VS and HS */ + + /* VS, HS polarities */ + io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 | pdata->inv_hs_pol << 1); /* Adjust drive strength */ io_write(sd, 0x14, 0x40 | pdata->dr_str << 4 | diff --git a/include/media/adv7604.h b/include/media/adv7604.h index 0162c31..053b13c 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h @@ -107,6 +107,10 @@ struct adv7604_platform_data { unsigned replicate_av_codes:1; unsigned invert_cbcr:1; + /* IO register 0x06 */ + unsigned inv_vs_pol:1; + unsigned inv_hs_pol:1; + /* IO register 0x14 */ unsigned dr_str:2; unsigned dr_str_clk:2; -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH 18/15] adv7604: initialize timings to CEA 640x480p59.94. 2013-12-10 13:23 ` [RFC PATCH 15/15] adv7604: Enable HDMI_MODE interrupt Hans Verkuil 2013-12-17 13:14 ` [RFC PATCH 16/15] adv7604: return immediately if the new timings are equal to what is configured Hans Verkuil 2013-12-17 13:15 ` [RFC PATCH 17/15] adv7604: sync polarities from platform data Hans Verkuil @ 2013-12-17 13:15 ` Hans Verkuil 2 siblings, 0 replies; 19+ messages in thread From: Hans Verkuil @ 2013-12-17 13:15 UTC (permalink / raw) To: linux-media; +Cc: Mats Randgaard, Hans Verkuil This timing must be supported by all HDMI equipment, so that's a reasonable default. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> --- drivers/media/i2c/adv7604.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 3f40616..f063162 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2207,6 +2207,8 @@ static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, static int adv7604_probe(struct i2c_client *client, const struct i2c_device_id *id) { + static const struct v4l2_dv_timings cea640x480 = + V4L2_DV_BT_CEA_640X480P59_94; struct adv7604_state *state; struct adv7604_platform_data *pdata = client->dev.platform_data; struct v4l2_ctrl_handler *hdl; @@ -2234,7 +2236,8 @@ static int adv7604_probe(struct i2c_client *client, v4l_err(client, "No platform data!\n"); return -ENODEV; } - memcpy(&state->pdata, pdata, sizeof(state->pdata)); + state->pdata = *pdata; + state->timings = cea640x480; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7604_ops); -- 1.8.4.rc3 ^ permalink raw reply related [flat|nested] 19+ messages in thread
end of thread, other threads:[~2013-12-17 13:17 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-12-10 13:23 [RFC PATCH 00/15] adv7604: fixes Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 01/15] adv7604: add support for all the digital input ports Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 02/15] adv7604: add hdmi driver strength adjustment Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 03/15] adv7604: support 1366x768 DMT Reduced Blanking Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 04/15] adv7604: adv7604_s_register clean up Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 05/15] adv7604: Receive CEA formats as RGB on VGA (RGB) input Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 06/15] adv7604: select YPbPr if RGB_RANGE_FULL/LIMITED is set for VGA_COMP inputs Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 07/15] adv7604: set CEC address (SPA) in EDID Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 08/15] adv7604: improve EDID handling Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 09/15] adv7604: remove connector type. Never used for anything useful Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 10/15] adv7604: return immediately if the new input is equal to what is configured Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 11/15] adv7604: remove debouncing of ADV7604_FMT_CHANGE events Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 12/15] adv7604: improve HDMI audio handling Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 13/15] adv7604: set restart_stdi_once flag when signal is lost Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 14/15] adv7604: adjust gain and offset for DVI-D signals Hans Verkuil 2013-12-10 13:23 ` [RFC PATCH 15/15] adv7604: Enable HDMI_MODE interrupt Hans Verkuil 2013-12-17 13:14 ` [RFC PATCH 16/15] adv7604: return immediately if the new timings are equal to what is configured Hans Verkuil 2013-12-17 13:15 ` [RFC PATCH 17/15] adv7604: sync polarities from platform data Hans Verkuil 2013-12-17 13:15 ` [RFC PATCH 18/15] adv7604: initialize timings to CEA 640x480p59.94 Hans Verkuil
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox