diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 66b3ee5cc19092b7fc4f444478b5f90eb711b847..e7c7e3ab4b383b606b09d7887e0e3a1bb9132466 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -70,25 +70,14 @@ #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;