media: i2c: ov5647: Add support for g_selection to reflect cropping/binning
authorDave Stevenson <dave.stevenson@raspberrypi.com>
Wed, 29 Apr 2020 10:46:07 +0000 (11:46 +0100)
committerpopcornmix <popcornmix@gmail.com>
Wed, 1 Jul 2020 15:33:53 +0000 (16:33 +0100)
In order to apply lens shading correctly the client needs to know how
each mode crops or scales the image compared to the full sensor array.
Implement this (based on the imx219 equivalent).

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

index 66b3ee5..e7c7e3a 100644 (file)
 #define VAL_TERM 0xfe
 #define REG_DLY  0xffff
 
-#define OV5647_ROW_START               0x01
-#define OV5647_ROW_START_MIN           0
-#define OV5647_ROW_START_MAX           2004
-#define OV5647_ROW_START_DEF           54
-
-#define OV5647_COLUMN_START            0x02
-#define OV5647_COLUMN_START_MIN                0
-#define OV5647_COLUMN_START_MAX                2750
-#define OV5647_COLUMN_START_DEF                16
-
-#define OV5647_WINDOW_HEIGHT           0x03
-#define OV5647_WINDOW_HEIGHT_MIN       2
-#define OV5647_WINDOW_HEIGHT_MAX       2006
-#define OV5647_WINDOW_HEIGHT_DEF       1944
-
-#define OV5647_WINDOW_WIDTH            0x04
-#define OV5647_WINDOW_WIDTH_MIN                2
-#define OV5647_WINDOW_WIDTH_MAX                2752
-#define OV5647_WINDOW_WIDTH_DEF                2592
+/* OV5647 native and active pixel array size */
+#define OV5647_NATIVE_WIDTH            2624U
+#define OV5647_NATIVE_HEIGHT           1956U
+
+#define OV5647_PIXEL_ARRAY_LEFT                16U
+#define OV5647_PIXEL_ARRAY_TOP         16U
+#define OV5647_PIXEL_ARRAY_WIDTH       2592U
+#define OV5647_PIXEL_ARRAY_HEIGHT      1944U
 
 struct regval_list {
        u16 addr;
@@ -97,6 +86,9 @@ struct regval_list {
 
 struct ov5647_mode {
        struct v4l2_mbus_framefmt       format;
+       /* Analog crop rectangle. */
+       struct v4l2_rect crop;
+
        struct regval_list              *reg_list;
        unsigned int                    num_regs;
 };
@@ -603,6 +595,12 @@ static struct ov5647_mode supported_modes_8bit[] = {
                        .width = 640,
                        .height = 480
                },
+               .crop = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 1280,
+                       .height = 960,
+               },
                ov5647_640x480_8bit,
                ARRAY_SIZE(ov5647_640x480_8bit)
        },
@@ -620,6 +618,12 @@ static struct ov5647_mode supported_modes_10bit[] = {
                        .width = 2592,
                        .height = 1944
                },
+               .crop = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 2592,
+                       .height = 1944
+               },
                ov5647_2592x1944_10bit,
                ARRAY_SIZE(ov5647_2592x1944_10bit)
        },
@@ -635,6 +639,12 @@ static struct ov5647_mode supported_modes_10bit[] = {
                        .width = 1920,
                        .height = 1080
                },
+               .crop = {
+                       .left = 348,
+                       .top = 434,
+                       .width = 1928,
+                       .height = 1080,
+               },
                ov5647_1080p30_10bit,
                ARRAY_SIZE(ov5647_1080p30_10bit)
        },
@@ -649,6 +659,12 @@ static struct ov5647_mode supported_modes_10bit[] = {
                        .width = 1296,
                        .height = 972
                },
+               .crop = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 2592,
+                       .height = 1944,
+               },
                ov5647_2x2binned_10bit,
                ARRAY_SIZE(ov5647_2x2binned_10bit)
        },
@@ -664,6 +680,12 @@ static struct ov5647_mode supported_modes_10bit[] = {
                        .width = 640,
                        .height = 480
                },
+               .crop = {
+                       .left = 16,
+                       .top = 0,
+                       .width = 2560,
+                       .height = 1920,
+               },
                ov5647_640x480_10bit,
                ARRAY_SIZE(ov5647_640x480_10bit)
        },
@@ -971,6 +993,56 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
 #endif
 };
 
+static const struct v4l2_rect *
+__ov5647_get_pad_crop(struct ov5647 *ov5647, struct v4l2_subdev_pad_config *cfg,
+                     unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_crop(&ov5647->sd, cfg, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &ov5647->mode->crop;
+       }
+
+       return NULL;
+}
+
+static int ov5647_get_selection(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_selection *sel)
+{
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP: {
+               struct ov5647 *state = to_state(sd);
+
+               mutex_lock(&state->lock);
+               sel->r = *__ov5647_get_pad_crop(state, cfg, sel->pad,
+                                               sel->which);
+               mutex_unlock(&state->lock);
+
+               return 0;
+       }
+
+       case V4L2_SEL_TGT_NATIVE_SIZE:
+               sel->r.top = 0;
+               sel->r.left = 0;
+               sel->r.width = OV5647_NATIVE_WIDTH;
+               sel->r.height = OV5647_NATIVE_HEIGHT;
+
+               return 0;
+
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               sel->r.top = OV5647_PIXEL_ARRAY_TOP;
+               sel->r.left = OV5647_PIXEL_ARRAY_LEFT;
+               sel->r.width = OV5647_PIXEL_ARRAY_WIDTH;
+               sel->r.height = OV5647_PIXEL_ARRAY_HEIGHT;
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
 static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct ov5647 *state = to_state(sd);
@@ -1122,6 +1194,7 @@ static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
        .enum_mbus_code = ov5647_enum_mbus_code,
        .set_fmt =        ov5647_set_fmt,
        .get_fmt =        ov5647_get_fmt,
+       .get_selection =  ov5647_get_selection,
        .enum_frame_size = ov5647_enum_frame_size,
 };
 
@@ -1170,10 +1243,10 @@ static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
                                v4l2_subdev_get_try_crop(sd, fh->pad, 0);
        struct ov5647 *state = to_state(sd);
 
-       crop->left = OV5647_COLUMN_START_DEF;
-       crop->top = OV5647_ROW_START_DEF;
-       crop->width = OV5647_WINDOW_WIDTH_DEF;
-       crop->height = OV5647_WINDOW_HEIGHT_DEF;
+       crop->left = OV5647_PIXEL_ARRAY_LEFT;
+       crop->top = OV5647_PIXEL_ARRAY_TOP;
+       crop->width = OV5647_PIXEL_ARRAY_WIDTH;
+       crop->height = OV5647_PIXEL_ARRAY_HEIGHT;
 
        /* Set the default format to the same as the sensor. */
        *format = state->mode->format;