diff options
Diffstat (limited to 'drivers/media/i2c/tc358743.c')
-rw-r--r-- | drivers/media/i2c/tc358743.c | 73 |
1 files changed, 61 insertions, 12 deletions
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 3192a334aaab..dcef93e1a3bc 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -87,6 +87,10 @@ struct tc358743_state { struct timer_list timer; struct work_struct work_i2c_poll; + /* debugfs */ + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; + /* edid */ u8 edid_blocks_written; @@ -309,6 +313,10 @@ static int tc358743_get_detected_timings(struct v4l2_subdev *sd, memset(timings, 0, sizeof(struct v4l2_dv_timings)); + /* if HPD is low, ignore any video */ + if (!(i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0)) + return -ENOLINK; + if (no_signal(sd)) { v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); return -ENOLINK; @@ -430,12 +438,35 @@ static void tc358743_erase_bksv(struct v4l2_subdev *sd) /* --------------- AVI infoframe --------------- */ +static ssize_t +tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp, + char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int len; + + if (!is_hdmi(sd)) + return 0; + + if (type != V4L2_DEBUGFS_IF_AVI) + return 0; + + i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1); + len = buf[2] + 4; + if (len > V4L2_DEBUGFS_IF_MAX_LEN) + len = -ENOENT; + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static void print_avi_infoframe(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct device *dev = &client->dev; union hdmi_infoframe frame; - u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; + u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {}; if (!is_hdmi(sd)) { v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); @@ -1521,11 +1552,14 @@ static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; } -static int tc358743_s_dv_timings(struct v4l2_subdev *sd, +static int tc358743_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct tc358743_state *state = to_state(sd); + if (pad != 0) + return -EINVAL; + if (!timings) return -EINVAL; @@ -1553,11 +1587,14 @@ static int tc358743_s_dv_timings(struct v4l2_subdev *sd, return 0; } -static int tc358743_g_dv_timings(struct v4l2_subdev *sd, +static int tc358743_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct tc358743_state *state = to_state(sd); + if (pad != 0) + return -EINVAL; + *timings = state->timings; return 0; @@ -1573,11 +1610,14 @@ static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, &tc358743_timings_cap, NULL, NULL); } -static int tc358743_query_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) +static int tc358743_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *timings) { int ret; + if (pad != 0) + return -EINVAL; + ret = tc358743_get_detected_timings(sd, timings); if (ret) return ret; @@ -1822,9 +1862,6 @@ static const struct v4l2_subdev_core_ops tc358743_core_ops = { static const struct v4l2_subdev_video_ops tc358743_video_ops = { .g_input_status = tc358743_g_input_status, - .s_dv_timings = tc358743_s_dv_timings, - .g_dv_timings = tc358743_g_dv_timings, - .query_dv_timings = tc358743_query_dv_timings, .s_stream = tc358743_s_stream, }; @@ -1834,6 +1871,9 @@ static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { .get_fmt = tc358743_get_fmt, .get_edid = tc358743_g_edid, .set_edid = tc358743_s_edid, + .s_dv_timings = tc358743_s_dv_timings, + .g_dv_timings = tc358743_g_dv_timings, + .query_dv_timings = tc358743_query_dv_timings, .enum_dv_timings = tc358743_enum_dv_timings, .dv_timings_cap = tc358743_dv_timings_cap, .get_mbus_config = tc358743_get_mbus_config, @@ -2110,7 +2150,7 @@ static int tc358743_probe(struct i2c_client *client) tc358743_initial_setup(sd); - tc358743_s_dv_timings(sd, &default_timing); + tc358743_s_dv_timings(sd, 0, &default_timing); tc358743_set_csi_color_space(sd); @@ -2152,6 +2192,11 @@ static int tc358743_probe(struct i2c_client *client) if (err < 0) goto err_work_queues; + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI, sd, + tc358743_debugfs_if_read); + v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); @@ -2159,8 +2204,10 @@ static int tc358743_probe(struct i2c_client *client) err_work_queues: cec_unregister_adapter(state->cec_adap); - if (!state->i2c_client->irq) + if (!state->i2c_client->irq) { + timer_delete(&state->timer); flush_work(&state->work_i2c_poll); + } cancel_delayed_work(&state->delayed_work_enable_hotplug); mutex_destroy(&state->confctl_mutex); err_hdl: @@ -2175,10 +2222,12 @@ static void tc358743_remove(struct i2c_client *client) struct tc358743_state *state = to_state(sd); if (!state->i2c_client->irq) { - del_timer_sync(&state->timer); + timer_delete_sync(&state->timer); flush_work(&state->work_i2c_poll); } cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); + v4l2_debugfs_if_free(state->infoframes); + debugfs_remove_recursive(state->debugfs_dir); cec_unregister_adapter(state->cec_adap); v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); @@ -2188,7 +2237,7 @@ static void tc358743_remove(struct i2c_client *client) } static const struct i2c_device_id tc358743_id[] = { - {"tc358743", 0}, + { "tc358743" }, {} }; |