This is an automatic generated email to let you know that the following patch 
were queued:

Subject: media: ov2680: Add vblank control
Author:  Hans de Goede <hdego...@redhat.com>
Date:    Mon Apr 15 15:03:16 2024 +0200

Add vblank control to allow changing the framerate /
higher exposure values.

Reviewed-by: Kieran Bingham <kieran.bing...@ideasonboard.com>
Signed-off-by: Hans de Goede <hdego...@redhat.com>
Signed-off-by: Sakari Ailus <sakari.ai...@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl>

 drivers/media/i2c/ov2680.c | 56 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 7 deletions(-)

---

diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
index ad04e7d5f1f4..5847122dc01b 100644
--- a/drivers/media/i2c/ov2680.c
+++ b/drivers/media/i2c/ov2680.c
@@ -75,6 +75,8 @@
 #define OV2680_ACTIVE_START_TOP                        8
 #define OV2680_MIN_CROP_WIDTH                  2
 #define OV2680_MIN_CROP_HEIGHT                 2
+#define OV2680_MIN_VBLANK                      4
+#define OV2680_MAX_VBLANK                      0xffff
 
 /* Fixed pre-div of 1/2 */
 #define OV2680_PLL_PREDIV0                     2
@@ -84,7 +86,7 @@
 
 /* 66MHz pixel clock: 66MHz / 1704 * 1294 = 30fps */
 #define OV2680_PIXELS_PER_LINE                 1704
-#define OV2680_LINES_PER_FRAME                 1294
+#define OV2680_LINES_PER_FRAME_30FPS           1294
 
 /* Max exposure time is VTS - 8 */
 #define OV2680_INTEGRATION_TIME_MARGIN         8
@@ -127,6 +129,7 @@ struct ov2680_ctrls {
        struct v4l2_ctrl *test_pattern;
        struct v4l2_ctrl *link_freq;
        struct v4l2_ctrl *pixel_rate;
+       struct v4l2_ctrl *vblank;
 };
 
 struct ov2680_mode {
@@ -394,8 +397,7 @@ static int ov2680_set_mode(struct ov2680_dev *sensor)
                  sensor->mode.v_output_size, &ret);
        cci_write(sensor->regmap, OV2680_REG_TIMING_HTS,
                  OV2680_PIXELS_PER_LINE, &ret);
-       cci_write(sensor->regmap, OV2680_REG_TIMING_VTS,
-                 OV2680_LINES_PER_FRAME, &ret);
+       /* VTS gets set by the vblank ctrl */
        cci_write(sensor->regmap, OV2680_REG_ISP_X_WIN, 0, &ret);
        cci_write(sensor->regmap, OV2680_REG_ISP_Y_WIN, 0, &ret);
        cci_write(sensor->regmap, OV2680_REG_X_INC, inc, &ret);
@@ -469,6 +471,15 @@ static int ov2680_exposure_set(struct ov2680_dev *sensor, 
u32 exp)
                         NULL);
 }
 
+static int ov2680_exposure_update_range(struct ov2680_dev *sensor)
+{
+       int exp_max = sensor->mode.fmt.height + sensor->ctrls.vblank->val -
+                     OV2680_INTEGRATION_TIME_MARGIN;
+
+       return __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max,
+                                       1, exp_max);
+}
+
 static int ov2680_stream_enable(struct ov2680_dev *sensor)
 {
        int ret;
@@ -635,7 +646,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
        struct v4l2_mbus_framefmt *try_fmt;
        const struct v4l2_rect *crop;
        unsigned int width, height;
-       int ret = 0;
+       int def, max, ret = 0;
 
        crop = __ov2680_get_pad_crop(sensor, sd_state, format->pad,
                                     format->which);
@@ -664,6 +675,21 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
        sensor->mode.fmt = format->format;
        ov2680_calc_mode(sensor);
 
+       /* vblank range is height dependent adjust and reset to default */
+       max = OV2680_MAX_VBLANK - height;
+       def = OV2680_LINES_PER_FRAME_30FPS - height;
+       ret = __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV2680_MIN_VBLANK,
+                                      max, 1, def);
+       if (ret)
+               goto unlock;
+
+       ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, def);
+       if (ret)
+               goto unlock;
+
+       /* exposure range depends on vts which may have changed */
+       ret = ov2680_exposure_update_range(sensor);
+
 unlock:
        mutex_unlock(&sensor->lock);
 
@@ -833,6 +859,13 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
        struct ov2680_dev *sensor = to_ov2680_dev(sd);
        int ret;
 
+       /* Update exposure range on vblank changes */
+       if (ctrl->id == V4L2_CID_VBLANK) {
+               ret = ov2680_exposure_update_range(sensor);
+               if (ret)
+                       return ret;
+       }
+
        /* Only apply changes to the controls if the device is powered up */
        if (!pm_runtime_get_if_in_use(sensor->sd.dev)) {
                ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
@@ -855,6 +888,10 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_TEST_PATTERN:
                ret = ov2680_test_pattern_set(sensor, ctrl->val);
                break;
+       case V4L2_CID_VBLANK:
+               ret = cci_write(sensor->regmap, OV2680_REG_TIMING_VTS,
+                               sensor->mode.fmt.height + ctrl->val, NULL);
+               break;
        default:
                ret = -EINVAL;
                break;
@@ -913,8 +950,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
        const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops;
        struct ov2680_ctrls *ctrls = &sensor->ctrls;
        struct v4l2_ctrl_handler *hdl = &ctrls->handler;
-       int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN;
-       int ret = 0;
+       int def, max, ret = 0;
 
        v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_subdev_ops);
        sensor->sd.internal_ops = &ov2680_internal_ops;
@@ -939,8 +975,9 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
                                        ARRAY_SIZE(test_pattern_menu) - 1,
                                        0, 0, test_pattern_menu);
 
+       max = OV2680_LINES_PER_FRAME_30FPS - OV2680_INTEGRATION_TIME_MARGIN;
        ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
-                                           0, exp_max, 1, exp_max);
+                                           0, max, 1, max);
 
        ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
                                        0, 1023, 1, 250);
@@ -951,6 +988,11 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
                                              0, sensor->pixel_rate,
                                              1, sensor->pixel_rate);
 
+       max = OV2680_MAX_VBLANK - OV2680_DEFAULT_HEIGHT;
+       def = OV2680_LINES_PER_FRAME_30FPS - OV2680_DEFAULT_HEIGHT;
+       ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
+                                         OV2680_MIN_VBLANK, max, 1, def);
+
        if (hdl->error) {
                ret = hdl->error;
                goto cleanup_entity;

Reply via email to