media: i2c: imx290: Add support for V4L2_CID_VBLANK
authorDave Stevenson <dave.stevenson@raspberrypi.com>
Thu, 11 Jun 2020 17:09:12 +0000 (18:09 +0100)
committerpopcornmix <popcornmix@gmail.com>
Wed, 1 Jul 2020 15:34:17 +0000 (16:34 +0100)
In order to calculate framerate and durations userspace needs
the vertical blanking information. This can be configurable,
and indeed the datasheet lists different values for VBLANK for
the 1080p and 720p modes.

Add the new control, and adopt the datasheet values for each mode.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
drivers/media/i2c/imx290.c

index 876ad59..ea0559e 100644 (file)
@@ -38,6 +38,8 @@ enum imx290_clk_index {
 #define IMX290_BLKLEVEL_LOW 0x300a
 #define IMX290_BLKLEVEL_HIGH 0x300b
 #define IMX290_GAIN 0x3014
+#define IMX290_VMAX_LOW 0x3018
+#define IMX290_VMAX_MAX 0x3fff
 #define IMX290_HMAX_LOW 0x301c
 #define IMX290_HMAX_HIGH 0x301d
 #define IMX290_HMAX_MIN_2LANE 4400 /* Min of 4400 pixels = 30fps */
@@ -68,6 +70,7 @@ struct imx290_mode {
        u32 width;
        u32 height;
        u32 hmax;
+       u32 vmax;
        u8 link_freq_index;
 
        const struct imx290_regval *data;
@@ -99,6 +102,7 @@ struct imx290 {
        struct v4l2_ctrl *link_freq;
        struct v4l2_ctrl *pixel_rate;
        struct v4l2_ctrl *hblank;
+       struct v4l2_ctrl *vblank;
 
        struct mutex lock;
 };
@@ -132,8 +136,6 @@ static const char * const imx290_test_pattern_menu[] = {
 
 static const struct imx290_regval imx290_global_init_settings[] = {
        { 0x3007, 0x00 },
-       { 0x3018, 0x65 },
-       { 0x3019, 0x04 },
        { 0x301a, 0x00 },
        { 0x303a, 0x0c },
        { 0x3040, 0x00 },
@@ -360,6 +362,7 @@ static const struct imx290_mode imx290_modes_2lanes[] = {
                .width = 1920,
                .height = 1080,
                .hmax = 0x1130,
+               .vmax = 0x0465,
                .link_freq_index = FREQ_INDEX_1080P,
                .data = imx290_1080p_settings,
                .data_size = ARRAY_SIZE(imx290_1080p_settings),
@@ -373,6 +376,7 @@ static const struct imx290_mode imx290_modes_2lanes[] = {
                .width = 1280,
                .height = 720,
                .hmax = 0x19c8,
+               .vmax = 0x02ee,
                .link_freq_index = FREQ_INDEX_720P,
                .data = imx290_720p_settings,
                .data_size = ARRAY_SIZE(imx290_720p_settings),
@@ -389,6 +393,7 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
                .width = 1920,
                .height = 1080,
                .hmax = 0x0898,
+               .vmax = 0x0465,
                .link_freq_index = FREQ_INDEX_1080P,
                .data = imx290_1080p_settings,
                .data_size = ARRAY_SIZE(imx290_1080p_settings),
@@ -402,6 +407,7 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
                .width = 1280,
                .height = 720,
                .hmax = 0x0ce4,
+               .vmax = 0x02ee,
                .link_freq_index = FREQ_INDEX_720P,
                .data = imx290_720p_settings,
                .data_size = ARRAY_SIZE(imx290_720p_settings),
@@ -543,6 +549,19 @@ static int imx290_set_hmax(struct imx290 *imx290, u32 val)
        return 0;
 }
 
+static int imx290_set_vmax(struct imx290 *imx290, u32 val)
+{
+       u32 vmax = val + imx290->current_mode->height;
+       int ret;
+
+       ret = imx290_write_buffered_reg(imx290, IMX290_VMAX_LOW, 3,
+                                       vmax);
+       if (ret)
+               dev_err(imx290->dev, "Unable to write vmax\n");
+
+       return ret;
+}
+
 /* Stop streaming */
 static int imx290_stop_streaming(struct imx290 *imx290)
 {
@@ -574,6 +593,9 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_HBLANK:
                ret = imx290_set_hmax(imx290, ctrl->val);
                break;
+       case V4L2_CID_VBLANK:
+               ret = imx290_set_vmax(imx290, ctrl->val);
+               break;
        case V4L2_CID_TEST_PATTERN:
                if (ctrl->val) {
                        imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00);
@@ -736,6 +758,12 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
                                                 imx290->hmax_min - mode->width,
                                                 IMX290_HMAX_MAX - mode->width,
                                                 1, mode->hmax - mode->width);
+               if (imx290->vblank)
+                       __v4l2_ctrl_modify_range(imx290->vblank,
+                                                mode->vmax - mode->height,
+                                                IMX290_VMAX_MAX - mode->height,
+                                                1,
+                                                mode->vmax - mode->height);
        }
 
        *format = fmt->format;
@@ -1148,6 +1176,12 @@ static int imx290_probe(struct i2c_client *client)
                                           IMX290_HMAX_MAX - mode->width, 1,
                                           mode->hmax - mode->width);
 
+       imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+                                          V4L2_CID_VBLANK,
+                                          mode->vmax - mode->height,
+                                          IMX290_VMAX_MAX - mode->height, 1,
+                                          mode->vmax - mode->height);
+
        imx290->link_freq =
                v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
                                       V4L2_CID_LINK_FREQ,