Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 963ddc63 authored by Javier Martin's avatar Javier Martin Committed by Mauro Carvalho Chehab
Browse files

[media] media: tvp5150: Add cropping support

parent d994c46d
Loading
Loading
Loading
Loading
+122 −5
Original line number Diff line number Diff line
@@ -17,6 +17,13 @@

#include "tvp5150_reg.h"

#define TVP5150_H_MAX		720
#define TVP5150_V_MAX_525_60	480
#define TVP5150_V_MAX_OTHERS	576
#define TVP5150_MAX_CROP_LEFT	511
#define TVP5150_MAX_CROP_TOP	127
#define TVP5150_CROP_SHIFT	2

MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
@@ -29,6 +36,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
struct tvp5150 {
	struct v4l2_subdev sd;
	struct v4l2_ctrl_handler hdl;
	struct v4l2_rect rect;

	v4l2_std_id norm;	/* Current set standard */
	u32 input;
@@ -732,6 +740,13 @@ static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
	if (decoder->norm == std)
		return 0;

	/* Change cropping height limits */
	if (std & V4L2_STD_525_60)
		decoder->rect.height = TVP5150_V_MAX_525_60;
	else
		decoder->rect.height = TVP5150_V_MAX_OTHERS;


	return tvp5150_set_std(sd, std);
}

@@ -828,11 +843,8 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
	else
		std = decoder->norm;

	f->width = 720;
	if (std & V4L2_STD_525_60)
		f->height = 480;
	else
		f->height = 576;
	f->width = decoder->rect.width;
	f->height = decoder->rect.height;

	f->code = V4L2_MBUS_FMT_YUYV8_2X8;
	f->field = V4L2_FIELD_SEQ_TB;
@@ -843,6 +855,99 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
	return 0;
}

static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
	struct v4l2_rect rect = a->c;
	struct tvp5150 *decoder = to_tvp5150(sd);
	v4l2_std_id std;
	int hmax;

	v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
		__func__, rect.left, rect.top, rect.width, rect.height);

	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	/* tvp5150 has some special limits */
	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
	rect.width = clamp(rect.width,
			   TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
			   TVP5150_H_MAX - rect.left);
	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);

	/* Calculate height based on current standard */
	if (decoder->norm == V4L2_STD_ALL)
		std = tvp5150_read_std(sd);
	else
		std = decoder->norm;

	if (std & V4L2_STD_525_60)
		hmax = TVP5150_V_MAX_525_60;
	else
		hmax = TVP5150_V_MAX_OTHERS;

	rect.height = clamp(rect.height,
			    hmax - TVP5150_MAX_CROP_TOP - rect.top,
			    hmax - rect.top);

	tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
	tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
		      rect.top + rect.height - hmax);
	tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB,
		      rect.left >> TVP5150_CROP_SHIFT);
	tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB,
		      rect.left | (1 << TVP5150_CROP_SHIFT));
	tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB,
		      (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
		      TVP5150_CROP_SHIFT);
	tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB,
		      rect.left + rect.width - TVP5150_MAX_CROP_LEFT);

	decoder->rect = rect;

	return 0;
}

static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);

	a->c	= decoder->rect;
	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;

	return 0;
}

static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
	v4l2_std_id std;

	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	a->bounds.left			= 0;
	a->bounds.top			= 0;
	a->bounds.width			= TVP5150_H_MAX;

	/* Calculate height based on current standard */
	if (decoder->norm == V4L2_STD_ALL)
		std = tvp5150_read_std(sd);
	else
		std = decoder->norm;

	if (std & V4L2_STD_525_60)
		a->bounds.height = TVP5150_V_MAX_525_60;
	else
		a->bounds.height = TVP5150_V_MAX_OTHERS;

	a->defrect			= a->bounds;
	a->pixelaspect.numerator	= 1;
	a->pixelaspect.denominator	= 1;

	return 0;
}

/****************************************************************************
			I2C Command
 ****************************************************************************/
@@ -998,6 +1103,9 @@ static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
	.enum_mbus_fmt = tvp5150_enum_mbus_fmt,
	.s_mbus_fmt = tvp5150_mbus_fmt,
	.try_mbus_fmt = tvp5150_mbus_fmt,
	.s_crop = tvp5150_s_crop,
	.g_crop = tvp5150_g_crop,
	.cropcap = tvp5150_cropcap,
};

static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
@@ -1083,6 +1191,15 @@ static int tvp5150_probe(struct i2c_client *c,
	}
	v4l2_ctrl_handler_setup(&core->hdl);

	/* Default is no cropping */
	core->rect.top = 0;
	if (tvp5150_read_std(sd) & V4L2_STD_525_60)
		core->rect.height = TVP5150_V_MAX_525_60;
	else
		core->rect.height = TVP5150_V_MAX_OTHERS;
	core->rect.left = 0;
	core->rect.width = TVP5150_H_MAX;

	if (debug > 1)
		tvp5150_log_status(sd);
	return 0;