Commit c0bc1ca0 authored by Jim Lai's avatar Jim Lai Committed by Hans Verkuil
Browse files

media: hi556: add 2592x1444 resolution



Adding additional cropped 2592x1444 resolution
for QHD output from Hi556 sensor

Also implement the get_selection pad operation for the Hi556 sensor driver.
The supported targets report the sensor's native size, the crop default
rectangle and the crop rectangle.

Signed-off-by: default avatarJim Lai <jim.lai@intel.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent 8255140e
Loading
Loading
Loading
Loading
+148 −2
Original line number Diff line number Diff line
@@ -63,6 +63,14 @@
#define HI556_REG_ISP_TPG_EN		0x01
#define HI556_REG_TEST_PATTERN		0x0201

/* HI556 native and active pixel array size. */
#define HI556_NATIVE_WIDTH		2592U
#define HI556_NATIVE_HEIGHT		1944U
#define HI556_PIXEL_ARRAY_LEFT		0U
#define HI556_PIXEL_ARRAY_TOP		0U
#define HI556_PIXEL_ARRAY_WIDTH	2592U
#define HI556_PIXEL_ARRAY_HEIGHT	1944U

enum {
	HI556_LINK_FREQ_437MHZ_INDEX,
};
@@ -88,6 +96,9 @@ struct hi556_mode {
	/* Frame height in pixels */
	u32 height;

	/* Analog crop rectangle. */
	struct v4l2_rect crop;

	/* Horizontal timining size */
	u32 llp;

@@ -378,6 +389,49 @@ static const struct hi556_reg mode_2592x1944_regs[] = {
	{0x0958, 0xbb80},
};

static const struct hi556_reg mode_2592x1444_regs[] = {
	{0x0a00, 0x0000},
	{0x0b0a, 0x8252},
	{0x0f30, 0xe545},
	{0x0f32, 0x7067},
	{0x004a, 0x0100},
	{0x004c, 0x0000},
	{0x000c, 0x0022},
	{0x0008, 0x0b00},
	{0x005a, 0x0202},
	{0x0012, 0x000e},
	{0x0018, 0x0a33},
	{0x0022, 0x0008},
	{0x0028, 0x0017},
	{0x0024, 0x0122},
	{0x002a, 0x0127},
	{0x0026, 0x012a},
	{0x002c, 0x06cf},
	{0x002e, 0x1111},
	{0x0030, 0x1111},
	{0x0032, 0x1111},
	{0x0006, 0x0821},
	{0x0a22, 0x0000},
	{0x0a12, 0x0a20},
	{0x0a14, 0x05a4},
	{0x003e, 0x0000},
	{0x0074, 0x081f},
	{0x0070, 0x040f},
	{0x0804, 0x0300},
	{0x0806, 0x0100},
	{0x0a04, 0x014a},
	{0x090c, 0x0fdc},
	{0x090e, 0x002d},
	{0x0902, 0x4319},
	{0x0914, 0xc10a},
	{0x0916, 0x071f},
	{0x0918, 0x0408},
	{0x091a, 0x0c0d},
	{0x091c, 0x0f09},
	{0x091e, 0x0a00},
	{0x0958, 0xbb80},
};

static const struct hi556_reg mode_1296x972_regs[] = {
	{0x0a00, 0x0000},
	{0x0b0a, 0x8259},
@@ -450,8 +504,14 @@ static const struct hi556_link_freq_config link_freq_configs[] = {

static const struct hi556_mode supported_modes[] = {
	{
		.width = 2592,
		.height = 1944,
		.width = HI556_PIXEL_ARRAY_WIDTH,
		.height = HI556_PIXEL_ARRAY_HEIGHT,
		.crop = {
			.left = HI556_PIXEL_ARRAY_LEFT,
			.top = HI556_PIXEL_ARRAY_TOP,
			.width = HI556_PIXEL_ARRAY_WIDTH,
			.height = HI556_PIXEL_ARRAY_HEIGHT
		},
		.fll_def = HI556_FLL_30FPS,
		.fll_min = HI556_FLL_30FPS_MIN,
		.llp = 0x0b00,
@@ -461,9 +521,33 @@ static const struct hi556_mode supported_modes[] = {
		},
		.link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX,
	},
	{
		.width = HI556_PIXEL_ARRAY_WIDTH,
		.height = 1444,
		.crop = {
			.left = HI556_PIXEL_ARRAY_LEFT,
			.top = 250,
			.width = HI556_PIXEL_ARRAY_WIDTH,
			.height = 1444
		},
		.fll_def = 0x821,
		.fll_min = 0x821,
		.llp = 0x0b00,
		.reg_list = {
			.num_of_regs = ARRAY_SIZE(mode_2592x1444_regs),
			.regs = mode_2592x1444_regs,
		},
		.link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX,
	},
	{
		.width = 1296,
		.height = 972,
		.crop = {
			.left = HI556_PIXEL_ARRAY_LEFT,
			.top = HI556_PIXEL_ARRAY_TOP,
			.width = HI556_PIXEL_ARRAY_WIDTH,
			.height = HI556_PIXEL_ARRAY_HEIGHT
		},
		.fll_def = HI556_FLL_30FPS,
		.fll_min = HI556_FLL_30FPS_MIN,
		.llp = 0x0b00,
@@ -785,6 +869,58 @@ static int hi556_identify_module(struct hi556 *hi556)
	return 0;
}

static const struct v4l2_rect *
__hi556_get_pad_crop(struct hi556 *hi556,
		     struct v4l2_subdev_state *sd_state,
		     unsigned int pad, enum v4l2_subdev_format_whence which)
{
	switch (which) {
	case V4L2_SUBDEV_FORMAT_TRY:
		return v4l2_subdev_get_try_crop(&hi556->sd, sd_state, pad);
	case V4L2_SUBDEV_FORMAT_ACTIVE:
		return &hi556->cur_mode->crop;
	}

	return NULL;
}

static int hi556_get_selection(struct v4l2_subdev *sd,
			       struct v4l2_subdev_state *sd_state,
			       struct v4l2_subdev_selection *sel)
{
	switch (sel->target) {
	case V4L2_SEL_TGT_CROP: {
		struct hi556 *hi556 = to_hi556(sd);

		mutex_lock(&hi556->mutex);
		sel->r = *__hi556_get_pad_crop(hi556, sd_state, sel->pad,
						sel->which);
		mutex_unlock(&hi556->mutex);

		return 0;
	}

	case V4L2_SEL_TGT_NATIVE_SIZE:
		sel->r.top = 0;
		sel->r.left = 0;
		sel->r.width = HI556_NATIVE_WIDTH;
		sel->r.height = HI556_NATIVE_HEIGHT;

		return 0;

	case V4L2_SEL_TGT_CROP_DEFAULT:
	case V4L2_SEL_TGT_CROP_BOUNDS:
		sel->r.top = HI556_PIXEL_ARRAY_TOP;
		sel->r.left = HI556_PIXEL_ARRAY_LEFT;
		sel->r.width = HI556_PIXEL_ARRAY_WIDTH;
		sel->r.height = HI556_PIXEL_ARRAY_HEIGHT;

		return 0;
	}

	return -EINVAL;
}

static int hi556_start_streaming(struct hi556 *hi556)
{
	struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
@@ -1000,10 +1136,19 @@ static int hi556_enum_frame_size(struct v4l2_subdev *sd,
static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct hi556 *hi556 = to_hi556(sd);
	struct v4l2_rect *try_crop;

	mutex_lock(&hi556->mutex);
	hi556_assign_pad_format(&supported_modes[0],
				v4l2_subdev_get_try_format(sd, fh->state, 0));

	/* Initialize try_crop rectangle. */
	try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
	try_crop->top = HI556_PIXEL_ARRAY_TOP;
	try_crop->left = HI556_PIXEL_ARRAY_LEFT;
	try_crop->width = HI556_PIXEL_ARRAY_WIDTH;
	try_crop->height = HI556_PIXEL_ARRAY_HEIGHT;

	mutex_unlock(&hi556->mutex);

	return 0;
@@ -1016,6 +1161,7 @@ static const struct v4l2_subdev_video_ops hi556_video_ops = {
static const struct v4l2_subdev_pad_ops hi556_pad_ops = {
	.set_fmt = hi556_set_format,
	.get_fmt = hi556_get_format,
	.get_selection = hi556_get_selection,
	.enum_mbus_code = hi556_enum_mbus_code,
	.enum_frame_size = hi556_enum_frame_size,
};