From 9e6a5b925f3b401c9a047237c0014367655b291a Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 17 Feb 2022 18:08:39 +0000 Subject: [PATCH] media: i2c: ov7251: Add V4L2_CID_VBLANK This is a raw sensor so should be implementing V4L2_CID_VBLANK instead of the frame_interval ops, as per docs at https://www.kernel.org/doc/html/latest/driver-api/media/camera-sensor.html#frame-interval-configuration This driver already implemented the frame_interval ops, so removing them would be a regression. Implement V4L2_CID_VBLANK, with the frame_interval ops setting that control. Signed-off-by: Dave Stevenson --- drivers/media/i2c/ov7251.c | 56 +++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 13 deletions(-) --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -43,6 +43,8 @@ #define OV7251_HTS 0x3a0 #define OV7251_VTS_HIGH 0x380e #define OV7251_VTS_LOW 0x380f +#define OV7251_VTS_MIN_OFFSET 92 +#define OV7251_VTS_MAX 0x7fff #define OV7251_TIMING_FORMAT1 0x3820 #define OV7251_TIMING_FORMAT1_VFLIP BIT(2) #define OV7251_TIMING_FORMAT2 0x3821 @@ -136,6 +138,7 @@ struct ov7251 { struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *exposure; struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; /* Cached register values */ u8 aec_pk_manual; @@ -688,6 +691,19 @@ static int ov7251_set_vflip(struct ov725 return ret; } +static int ov7251_set_vblank(struct ov7251 *ov7251, s32 value) +{ + u16 reg; + u8 val[2]; + + reg = OV7251_VTS_HIGH; + value += ov7251->current_mode->height; + val[0] = (value & 0xff00) >> 8; /* goes to OV7251_VTS_HIGH */ + val[1] = value & 0xff; /* goes to OV7251_VTS_LOW */ + + return ov7251_write_seq_regs(ov7251, reg, val, 2); +} + static int ov7251_set_test_pattern(struct ov7251 *ov7251, s32 value) { u8 val = ov7251->pre_isp_00; @@ -714,9 +730,20 @@ static int ov7251_s_ctrl(struct v4l2_ctr { struct ov7251 *ov7251 = container_of(ctrl->handler, struct ov7251, ctrls); + s64 max; int ret; /* v4l2_ctrl_lock() locks our mutex */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max = ov7251->current_mode->height + ctrl->val - OV7251_EXPOSURE_OFFSET; + __v4l2_ctrl_modify_range(ov7251->exposure, + ov7251->exposure->minimum, max, + ov7251->exposure->step, + ov7251->exposure->default_value); + break; + } if (!pm_runtime_get_if_in_use(ov7251->dev)) return 0; @@ -737,6 +764,9 @@ static int ov7251_s_ctrl(struct v4l2_ctr case V4L2_CID_VFLIP: ret = ov7251_set_vflip(ov7251, ctrl->val); break; + case V4L2_CID_VBLANK: + ret = ov7251_set_vblank(ov7251, ctrl->val); + break; default: ret = -EINVAL; break; @@ -1030,14 +1060,6 @@ static int ov7251_s_stream(struct v4l2_s ov7251->current_mode->height); goto err_power_down; } - ret = ov7251_write_reg(ov7251, OV7251_VTS_HIGH, - ov7251->current_ival->vts >> 8); - if (ret) - goto err_power_down; - ret = ov7251_write_reg(ov7251, OV7251_VTS_LOW, - ov7251->current_ival->vts & 0xff); - if (ret) - goto err_power_down; ret = __v4l2_ctrl_handler_setup(&ov7251->ctrls); if (ret < 0) { dev_err(ov7251->dev, "could not sync v4l2 controls\n"); @@ -1088,12 +1110,13 @@ static int ov7251_set_frame_interval(str ret = __v4l2_ctrl_modify_range(ov7251->exposure, 1, new_ival->vts - OV7251_EXPOSURE_OFFSET, - 1, ov7251->current_mode->exposure_def); + 1, ov7251->exposure->val); if (ret < 0) goto exit; - ret = __v4l2_ctrl_s_ctrl(ov7251->exposure, - ov7251->current_mode->exposure_def); + ret = __v4l2_ctrl_s_ctrl(ov7251->vblank, + new_ival->vts - + ov7251->current_mode->height); if (ret < 0) goto exit; @@ -1233,7 +1256,7 @@ static int ov7251_probe(struct i2c_clien struct v4l2_ctrl *ctrl; struct ov7251 *ov7251; unsigned int rate = 0; - u32 h_blank; + u32 h_blank, v_blank, v_blank_max; int ret; int i; @@ -1314,7 +1337,7 @@ static int ov7251_probe(struct i2c_clien ov7251->current_mode = &ov7251_mode_info_data[0]; ov7251->current_ival = &ov7251_frame_ival_info_data[0]; - v4l2_ctrl_handler_init(&ov7251->ctrls, 10); + v4l2_ctrl_handler_init(&ov7251->ctrls, 11); ov7251->ctrls.lock = &ov7251->lock; v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, @@ -1345,6 +1368,13 @@ static int ov7251_probe(struct i2c_clien if (ov7251->hblank) ov7251->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + v_blank = ov7251->current_ival->vts - ov7251->current_mode->height; + v_blank_max = OV7251_VTS_MAX - ov7251->current_mode->width; + ov7251->vblank = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_VBLANK, + OV7251_VTS_MIN_OFFSET, + v_blank_max, 1, v_blank); + ov7251->sd.ctrl_handler = &ov7251->ctrls; if (ov7251->ctrls.error) {