media: i2c: imx290: Add support for V4L2_CID_VBLANK
[platform/kernel/linux-rpi.git] / 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,