diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.15/950-0737-media-i2c-ov7251-Add-V4L2_CID_VBLANK.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.15/950-0737-media-i2c-ov7251-Add-V4L2_CID_VBLANK.patch | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.15/950-0737-media-i2c-ov7251-Add-V4L2_CID_VBLANK.patch b/target/linux/bcm27xx/patches-5.15/950-0737-media-i2c-ov7251-Add-V4L2_CID_VBLANK.patch new file mode 100644 index 0000000000..c4c3c221d7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.15/950-0737-media-i2c-ov7251-Add-V4L2_CID_VBLANK.patch @@ -0,0 +1,153 @@ +From 9e6a5b925f3b401c9a047237c0014367655b291a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson <dave.stevenson@raspberrypi.com> +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 <dave.stevenson@raspberrypi.com> +--- + 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) { |