aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0737-media-i2c-ov7251-Add-V4L2_CID_VBLANK.patch
diff options
context:
space:
mode:
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.patch153
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) {