#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;
struct ov5647_mode {
struct v4l2_mbus_framefmt format;
+ /* Analog crop rectangle. */
+ struct v4l2_rect crop;
+
struct regval_list *reg_list;
unsigned int num_regs;
};
.width = 640,
.height = 480
},
+ .crop = {
+ .left = 0,
+ .top = 0,
+ .width = 1280,
+ .height = 960,
+ },
ov5647_640x480_8bit,
ARRAY_SIZE(ov5647_640x480_8bit)
},
.width = 2592,
.height = 1944
},
+ .crop = {
+ .left = 0,
+ .top = 0,
+ .width = 2592,
+ .height = 1944
+ },
ov5647_2592x1944_10bit,
ARRAY_SIZE(ov5647_2592x1944_10bit)
},
.width = 1920,
.height = 1080
},
+ .crop = {
+ .left = 348,
+ .top = 434,
+ .width = 1928,
+ .height = 1080,
+ },
ov5647_1080p30_10bit,
ARRAY_SIZE(ov5647_1080p30_10bit)
},
.width = 1296,
.height = 972
},
+ .crop = {
+ .left = 0,
+ .top = 0,
+ .width = 2592,
+ .height = 1944,
+ },
ov5647_2x2binned_10bit,
ARRAY_SIZE(ov5647_2x2binned_10bit)
},
.width = 640,
.height = 480
},
+ .crop = {
+ .left = 16,
+ .top = 0,
+ .width = 2560,
+ .height = 1920,
+ },
ov5647_640x480_10bit,
ARRAY_SIZE(ov5647_640x480_10bit)
},
#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);
.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,
};
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;