diff mbox

media: Add support for arbitrary resolution for the ov5642 camera driver

Message ID alpine.DEB.2.02.1108171551040.17540@ipanema (mailing list archive)
State New, archived
Headers show

Commit Message

Bastian Hecht Aug. 17, 2011, 3:53 p.m. UTC
This patch adds the ability to get arbitrary resolutions with a width
up to 2592 and a height up to 720 pixels instead of the standard 1280x720
only.

Signed-off-by: Bastian Hecht <hechtb@gmail.com>
---

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Laurent Pinchart Aug. 28, 2011, 5:49 p.m. UTC | #1
Hi Bastian,

Thanks for the patch.

On Wednesday 17 August 2011 17:53:42 Bastian Hecht wrote:
> This patch adds the ability to get arbitrary resolutions with a width
> up to 2592 and a height up to 720 pixels instead of the standard 1280x720
> only.
> 
> Signed-off-by: Bastian Hecht <hechtb@gmail.com>
> ---
> 
> diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
> index 6410bda..1b40d90 100644
> --- a/drivers/media/video/ov5642.c
> +++ b/drivers/media/video/ov5642.c
> @@ -14,8 +14,10 @@
>   * published by the Free Software Foundation.
>   */
> 
> +#include <linux/bitops.h>
>  #include <linux/delay.h>
>  #include <linux/i2c.h>
> +#include <linux/kernel.h>
>  #include <linux/slab.h>
>  #include <linux/videodev2.h>
> 
> @@ -28,13 +30,25 @@
>  #define REG_CHIP_ID_HIGH		0x300a
>  #define REG_CHIP_ID_LOW			0x300b
> 
> +#define REG_RED_GAIN_HIGH		0x3400
> +#define REG_RED_GAIN_LOW		0x3401
> +#define REG_BLUE_GAIN_HIGH		0x3404
> +#define REG_BLUE_GAIN_LOW		0x3405
> +#define REG_AWB_MANUAL			0x3406
> +#define REG_EXP_HIGH			0x3500
> +#define REG_EXP_MIDDLE			0x3501
> +#define REG_EXP_LOW			0x3502
> +#define REG_EXP_GAIN_CTRL		0x3503
> +#define REG_GAIN			0x350b

This belongs to the second patch.

> +#define REG_EXTEND_FRAME_TIME_HIGH	0x350c
> +#define REG_EXTEND_FRAME_TIME_LOW	0x350d
>  #define REG_WINDOW_START_X_HIGH		0x3800
>  #define REG_WINDOW_START_X_LOW		0x3801
>  #define REG_WINDOW_START_Y_HIGH		0x3802
>  #define REG_WINDOW_START_Y_LOW		0x3803
>  #define REG_WINDOW_WIDTH_HIGH		0x3804
>  #define REG_WINDOW_WIDTH_LOW		0x3805
> -#define REG_WINDOW_HEIGHT_HIGH 		0x3806
> +#define REG_WINDOW_HEIGHT_HIGH		0x3806
>  #define REG_WINDOW_HEIGHT_LOW		0x3807
>  #define REG_OUT_WIDTH_HIGH		0x3808
>  #define REG_OUT_WIDTH_LOW		0x3809
> @@ -44,19 +58,56 @@
>  #define REG_OUT_TOTAL_WIDTH_LOW		0x380d
>  #define REG_OUT_TOTAL_HEIGHT_HIGH	0x380e
>  #define REG_OUT_TOTAL_HEIGHT_LOW	0x380f
> +#define REG_FLIP_SUBSAMPLE		0x3818
> +#define REG_OUTPUT_FORMAT		0x4300
> +#define REG_ISP_CTRL_01			0x5001
> +#define REG_DIGITAL_EFFECTS		0x5580
> +#define REG_HUE_COS			0x5581
> +#define REG_HUE_SIN			0x5582
> +#define REG_BLUE_SATURATION		0x5583
> +#define REG_RED_SATURATION		0x5584
> +#define REG_CONTRAST			0x5588
> +#define REG_BRIGHTNESS			0x5589
> +#define REG_D_E_AUXILLARY		0x558a
> +#define REG_AVG_WINDOW_END_X_HIGH	0x5682
> +#define REG_AVG_WINDOW_END_X_LOW	0x5683
> +#define REG_AVG_WINDOW_END_Y_HIGH	0x5686
> +#define REG_AVG_WINDOW_END_Y_LOW	0x5687

So does this.

> +
> +/* active pixel array size */
> +#define OV5642_SENSOR_SIZE_X	2592
> +#define OV5642_SENSOR_SIZE_Y	1944
> +
> +/* current maximum working size */
> +#define OV5642_MAX_WIDTH	OV5642_SENSOR_SIZE_X
> +#define OV5642_MAX_HEIGHT	720
> +
> +/* default sizes */
> +#define OV5642_DEFAULT_WIDTH	1280
> +#define OV5642_DEFAULT_HEIGHT	OV5642_MAX_HEIGHT
> +
> +/* minimum extra blanking */
> +#define BLANKING_EXTRA_WIDTH		500
> +#define BLANKING_EXTRA_HEIGHT		20
> 
>  /*
> - * define standard resolution.
> - * Works currently only for up to 720 lines
> - * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720
> + * the sensor's autoexposure is buggy when setting total_height low.
> + * It tries to expose longer than 1 frame period without taking care of it
> + * and this leads to weird output. So we set 1000 lines as minimum.
>   */
> 
> -#define OV5642_WIDTH		1280
> -#define OV5642_HEIGHT		720
> -#define OV5642_TOTAL_WIDTH	3200
> -#define OV5642_TOTAL_HEIGHT	2000
> -#define OV5642_SENSOR_SIZE_X	2592
> -#define OV5642_SENSOR_SIZE_Y	1944
> +#define BLANKING_MIN_HEIGHT		1000
> +
> +/*
> + * About OV5642 resolution, cropping and binning:
> + * This sensor supports it all, at least in the feature description.
> + * Unfortunately, no combination of appropriate registers settings could
> make + * the chip work the intended way. As it works with predefined
> register lists, + * some undocumented registers are presumably changed
> there to achieve their + * goals.
> + * This driver currently only works for resolutions up to 720 lines with a
> + * 1:1 scale. Hopefully these restrictions will be removed in the future.
> + */

Can you please move this comment above the OV5642_MAX_WIDTH and 
OV5642_MAX_HEIGHT definitions ?

>  struct regval_list {
>  	u16 reg_num;
> @@ -105,10 +156,8 @@ static struct regval_list ov5642_default_regs_init[] =
> { { 0x471d, 0x5  },
>  	{ 0x4708, 0x6  },
>  	{ 0x370c, 0xa0 },
> -	{ 0x5687, 0x94 },

Unless I'm mistaken, this register value is removed and isn't replaced by 
anything in this patch or the next one. Is that intentional ?

>  	{ 0x501f, 0x0  },
>  	{ 0x5000, 0x4f },
> -	{ 0x5001, 0xcf },

This one is replaced by 0xff. I'm not sure how that's related to this patch. 
Could you please check all modifications to the ov5642_default_regs_init[] and 
ov5642_default_regs_finalise[] arrays ? Some probably need to move to the next 
patch, and others don't seem to be related to any of the two patches.

>  	{ 0x4300, 0x30 },
>  	{ 0x4300, 0x30 },
>  	{ 0x460b, 0x35 },
> @@ -121,11 +170,8 @@ static struct regval_list ov5642_default_regs_init[] =
> { { 0x4402, 0x90 },
>  	{ 0x460c, 0x22 },
>  	{ 0x3815, 0x44 },
> -	{ 0x3503, 0x7  },
>  	{ 0x3501, 0x73 },
>  	{ 0x3502, 0x80 },
> -	{ 0x350b, 0x0  },
> -	{ 0x3818, 0xc8 },
>  	{ 0x3824, 0x11 },
>  	{ 0x3a00, 0x78 },
>  	{ 0x3a1a, 0x4  },
> @@ -140,12 +186,6 @@ static struct regval_list ov5642_default_regs_init[] =
> { { 0x350d, 0xd0 },
>  	{ 0x3a0d, 0x8  },
>  	{ 0x3a0e, 0x6  },
> -	{ 0x3500, 0x0  },
> -	{ 0x3501, 0x0  },
> -	{ 0x3502, 0x0  },
> -	{ 0x350a, 0x0  },
> -	{ 0x350b, 0x0  },
> -	{ 0x3503, 0x0  },
>  	{ 0x3a0f, 0x3c },
>  	{ 0x3a10, 0x32 },
>  	{ 0x3a1b, 0x3c },
> @@ -298,7 +338,7 @@ static struct regval_list ov5642_default_regs_init[] =
> { { 0x54b7, 0xdf },
>  	{ 0x5402, 0x3f },
>  	{ 0x5403, 0x0  },
> -	{ 0x3406, 0x0  },
> +	{ REG_AWB_MANUAL, 0x0  },
>  	{ 0x5180, 0xff },
>  	{ 0x5181, 0x52 },
>  	{ 0x5182, 0x11 },
> @@ -515,7 +555,6 @@ static struct regval_list ov5642_default_regs_init[] =
> { { 0x5088, 0x0  },
>  	{ 0x5089, 0x0  },
>  	{ 0x302b, 0x0  },
> -	{ 0x3503, 0x7  },
>  	{ 0x3011, 0x8  },
>  	{ 0x350c, 0x2  },
>  	{ 0x350d, 0xe4 },
> @@ -526,7 +565,6 @@ static struct regval_list ov5642_default_regs_init[] =
> {
> 
>  static struct regval_list ov5642_default_regs_finalise[] = {
>  	{ 0x3810, 0xc2 },
> -	{ 0x3818, 0xc9 },
>  	{ 0x381c, 0x10 },
>  	{ 0x381d, 0xa0 },
>  	{ 0x381e, 0x5  },
> @@ -541,23 +579,20 @@ static struct regval_list
> ov5642_default_regs_finalise[] = { { 0x3a0d, 0x2  },
>  	{ 0x3a0e, 0x1  },
>  	{ 0x401c, 0x4  },
> -	{ 0x5682, 0x5  },
> -	{ 0x5683, 0x0  },
> -	{ 0x5686, 0x2  },
> -	{ 0x5687, 0xcc },
> -	{ 0x5001, 0x4f },
> +	{ REG_ISP_CTRL_01, 0xff },
> +	{ REG_DIGITAL_EFFECTS, 0x6 },
>  	{ 0x589b, 0x6  },
>  	{ 0x589a, 0xc5 },
> -	{ 0x3503, 0x0  },
> +	{ REG_EXP_GAIN_CTRL, 0x0  },
>  	{ 0x460c, 0x20 },
>  	{ 0x460b, 0x37 },
>  	{ 0x471c, 0xd0 },
>  	{ 0x471d, 0x5  },
>  	{ 0x3815, 0x1  },
> -	{ 0x3818, 0xc1 },
> +	{ REG_FLIP_SUBSAMPLE, 0xc1 },
>  	{ 0x501f, 0x0  },
>  	{ 0x5002, 0xe0 },
> -	{ 0x4300, 0x32 }, /* UYVY */
> +	{ REG_OUTPUT_FORMAT, 0x32 },
>  	{ 0x3002, 0x1c },
>  	{ 0x4800, 0x14 },
>  	{ 0x4801, 0xf  },
> @@ -578,9 +613,20 @@ struct ov5642_datafmt {
>  	enum v4l2_colorspace		colorspace;
>  };
> 
> +/* the output resolution and blanking information */
> +struct ov5642_out_size {
> +	int width;
> +	int height;
> +	int total_width;
> +	int total_height;
> +};
> +
>  struct ov5642 {
>  	struct v4l2_subdev		subdev;
> +
>  	const struct ov5642_datafmt	*fmt;
> +	struct v4l2_rect                crop_rect;
> +	struct ov5642_out_size		out_size;
>  };
> 
>  static const struct ov5642_datafmt ov5642_colour_fmts[] = {
> @@ -593,8 +639,7 @@ static struct ov5642 *to_ov5642(const struct i2c_client
> *client) }
> 
>  /* Find a data format by a pixel code in an array */
> -static const struct ov5642_datafmt
> -			*ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
> +static const struct ov5642_datafmt *ov5642_find_datafmt(enum
> v4l2_mbus_pixelcode code) {

checkpatch.pl won't be happy.

>  	int i;
> 
> @@ -641,6 +686,26 @@ static int reg_write(struct i2c_client *client, u16
> reg, u8 val)
> 
>  	return 0;
>  }
> +
> +/*
> + * convenience function to write 16 bit register values that are split up
> + * into two consecutive high and low parts
> + */
> +static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
> +{
> +	int ret;
> +	u8 val8;
> +
> +	val8 = val16 >> 8;
> +	ret = reg_write(client, reg, val8);

You can use val16 >> 8 directly as a function argument and get rid of the val8 
variable.

> +	if (ret)
> +		return ret;
> +	val8 = val16 & 0x00ff;
> +	ret = reg_write(client, reg + 1, val8);
> +
> +	return ret;

return reg_write(...) should be fine.

> +}
> +
>  #ifdef CONFIG_VIDEO_ADV_DEBUG
>  static int ov5642_get_register(struct v4l2_subdev *sd, struct
> v4l2_dbg_register *reg) {
> @@ -684,68 +749,72 @@ static int ov5642_write_array(struct i2c_client
> *client, return 0;
>  }
> 
> -static int ov5642_set_resolution(struct i2c_client *client)
> +static int ov5642_set_resolution(struct v4l2_subdev *sd)
>  {
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	struct ov5642 *priv = to_ov5642(client);
> +	int width = priv->out_size.width;
> +	int height = priv->out_size.height;
> +	int total_width = priv->out_size.total_width;
> +	int total_height = priv->out_size.total_height;
> +	int start_x = (OV5642_SENSOR_SIZE_X - width) / 2;
> +	int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2;
>  	int ret;
> -	u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8;
> -	u8 start_x_low  = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff;
> -	u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8;
> -	u8 start_y_low  = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff;
> -
> -	u8 width_high	= OV5642_WIDTH  >> 8;
> -	u8 width_low	= OV5642_WIDTH  & 0xff;
> -	u8 height_high	= OV5642_HEIGHT >> 8;
> -	u8 height_low	= OV5642_HEIGHT & 0xff;
> -
> -	u8 total_width_high  = OV5642_TOTAL_WIDTH  >> 8;
> -	u8 total_width_low   = OV5642_TOTAL_WIDTH  & 0xff;
> -	u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8;
> -	u8 total_height_low  = OV5642_TOTAL_HEIGHT & 0xff;
> -
> -	ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high);
> -	if (!ret)
> -		ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low);
> -	if (!ret)
> -		ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high);
> -	if (!ret)
> -		ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low);
> 
> +	/* This should set the starting point for cropping. Doesn't work so far.
> */ +	ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x);
>  	if (!ret)
> -		ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high);
> -	if (!ret)
> -		ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low);
> +		ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y);
> +	if (!ret) {
> +		priv->crop_rect.left = start_x;
> +		priv->crop_rect.top = start_y;
> +	}
> +
>  	if (!ret)
> -		ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high);
> +		ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width);
>  	if (!ret)
> -		ret = reg_write(client, REG_WINDOW_HEIGHT_LOW,  height_low);
> +		ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height);
> +	if (ret)
> +		return ret;
> +	priv->crop_rect.width = width;
> +	priv->crop_rect.height = height;
> 
> +	/* Set the output window size. Only 1:1 scale is supported so far. */
> +	ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width);
>  	if (!ret)
> -		ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high);
> -	if (!ret)
> -		ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low);
> +		ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height);
> +
> +	/* Total width = output size + blanking */
>  	if (!ret)
> -		ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high);
> +		ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width);
>  	if (!ret)
> -		ret = reg_write(client, REG_OUT_HEIGHT_LOW,  height_low);
> +		ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height);
> 
> +	/* set the maximum integration time */
>  	if (!ret)
> -		ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high);
> -	if (!ret)
> -		ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low);
> +		ret = reg_write16(client, REG_EXTEND_FRAME_TIME_HIGH,
> +								total_height);
> +
> +	/* Sets the window for AWB calculations */
>  	if (!ret)
> -		ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high);
> +		ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width);
>  	if (!ret)
> -		ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW,  total_height_low);
> +		ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height);
> 
>  	return ret;
>  }
> 
> -static int ov5642_try_fmt(struct v4l2_subdev *sd,
> -			  struct v4l2_mbus_framefmt *mf)
> +static int ov5642_try_fmt(struct v4l2_subdev *sd, struct
> v4l2_mbus_framefmt *mf) {
> -	const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
> +	const struct ov5642_datafmt *fmt   = ov5642_find_datafmt(mf->code);
> 
> -	dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n",
> +	dev_dbg(sd->v4l2_dev->dev, "%s(%u) request width: %u heigth: %u\n",
> +			__func__, mf->code, mf->width, mf->height);
> +
> +	v4l_bound_align_image(&mf->width, 48, OV5642_MAX_WIDTH, 1,
> +			      &mf->height, 32, OV5642_MAX_HEIGHT, 1, 0);
> +
> +	dev_dbg(sd->v4l2_dev->dev, "%s(%u) return width: %u heigth: %u\n",
>  			__func__, mf->code, mf->width, mf->height);
> 
>  	if (!fmt) {
> @@ -753,20 +822,16 @@ static int ov5642_try_fmt(struct v4l2_subdev *sd,
>  		mf->colorspace	= ov5642_colour_fmts[0].colorspace;
>  	}
> 
> -	mf->width	= OV5642_WIDTH;
> -	mf->height	= OV5642_HEIGHT;
>  	mf->field	= V4L2_FIELD_NONE;
> 
>  	return 0;
>  }
> 
> -static int ov5642_s_fmt(struct v4l2_subdev *sd,
> -			struct v4l2_mbus_framefmt *mf)
> +static int ov5642_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
> *mf) {
>  	struct i2c_client *client = v4l2_get_subdevdata(sd);
>  	struct ov5642 *priv = to_ov5642(client);
> -
> -	dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
> +	int ret;
> 
>  	/* MIPI CSI could have changed the format, double-check */
>  	if (!ov5642_find_datafmt(mf->code))
> @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd,
> 
>  	ov5642_try_fmt(sd, mf);
> 
> +	priv->out_size.width		= mf->width;
> +	priv->out_size.height		= mf->height;

It looks like to me (but I may be wrong) that you achieve different 
resolutions using cropping, not scaling. If that's correct you should 
implement s_crop support and refuse changing the resolution through s_fmt.

> +	priv->out_size.total_width	= mf->width + BLANKING_EXTRA_WIDTH;
> +	priv->out_size.total_height	= max_t(int, mf->height +
> +							BLANKING_EXTRA_HEIGHT,
> +							BLANKING_MIN_HEIGHT);

As you only use those two values once, maybe you can compute them in 
ov5642_set_resolution() instead of storing them in the device data structure.

> +	priv->crop_rect.width		= mf->width;
> +	priv->crop_rect.height		= mf->height;
> +
>  	priv->fmt = ov5642_find_datafmt(mf->code);
> 
> -	ov5642_write_array(client, ov5642_default_regs_init);
> -	ov5642_set_resolution(client);
> -	ov5642_write_array(client, ov5642_default_regs_finalise);
> +	ret = ov5642_write_array(client, ov5642_default_regs_init);
> +	if (!ret)
> +		ret = ov5642_set_resolution(sd);
> +	if (!ret)
> +		ret = ov5642_write_array(client, ov5642_default_regs_finalise);
> 
> -	return 0;
> +	return ret;
>  }
> 
> -static int ov5642_g_fmt(struct v4l2_subdev *sd,
> -			struct v4l2_mbus_framefmt *mf)
> +static int ov5642_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
> *mf) {
>  	struct i2c_client *client = v4l2_get_subdevdata(sd);
>  	struct ov5642 *priv = to_ov5642(client);
> @@ -793,10 +868,12 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd,
> 
>  	mf->code	= fmt->code;
>  	mf->colorspace	= fmt->colorspace;
> -	mf->width	= OV5642_WIDTH;
> -	mf->height	= OV5642_HEIGHT;
> +	mf->width	= priv->out_size.width;
> +	mf->height	= priv->out_size.height;
>  	mf->field	= V4L2_FIELD_NONE;
> 
> +	dev_dbg(sd->v4l2_dev->dev, "%s return width: %u heigth: %u\n", __func__,
> +			mf->width, mf->height);

Isn't that a bit too verbose ? Printing the format in a debug message in the 
s_fmt handler is useful, but maybe doing it in g_fmt is a bit too much.

>  	return 0;
>  }
> 
> @@ -829,14 +906,17 @@ static int ov5642_g_chip_ident(struct v4l2_subdev
> *sd,
> 
>  static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
>  {
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	struct ov5642 *priv = to_ov5642(client);
>  	struct v4l2_rect *rect = &a->c;
> -
>  	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
> -	rect->top	= 0;
> -	rect->left	= 0;
> -	rect->width	= OV5642_WIDTH;
> -	rect->height	= OV5642_HEIGHT;
> +	rect->top	= priv->crop_rect.top;
> +	rect->left	= priv->crop_rect.left;
> +	rect->width	= priv->crop_rect.width;
> +	rect->height	= priv->crop_rect.height;

rect = priv->crop_rect;

should do.

> 
> +	dev_dbg(sd->v4l2_dev->dev, "%s crop width: %u heigth: %u\n", __func__,
> +			rect->width, rect->height);

Same comment as for g_fmt.

>  	return 0;
>  }
> 
> @@ -844,8 +924,8 @@ static int ov5642_cropcap(struct v4l2_subdev *sd,
> struct v4l2_cropcap *a) {
>  	a->bounds.left			= 0;
>  	a->bounds.top			= 0;
> -	a->bounds.width			= OV5642_WIDTH;
> -	a->bounds.height		= OV5642_HEIGHT;
> +	a->bounds.width			= OV5642_MAX_WIDTH;
> +	a->bounds.height		= OV5642_MAX_HEIGHT;
>  	a->defrect			= a->bounds;
>  	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
>  	a->pixelaspect.numerator	= 1;
> @@ -858,9 +938,8 @@ static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
>  				struct v4l2_mbus_config *cfg)
>  {
>  	cfg->type = V4L2_MBUS_CSI2;
> -	cfg->flags = V4L2_MBUS_CSI2_2_LANE |
> -		V4L2_MBUS_CSI2_CHANNEL_0 |
> -		V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
> +	cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
> +					V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
> 
>  	return 0;
>  }
> @@ -941,8 +1020,15 @@ static int ov5642_probe(struct i2c_client *client,
> 
>  	v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
> 
> -	icd->ops	= NULL;
> -	priv->fmt	= &ov5642_colour_fmts[0];
> +	icd->ops		= NULL;
> +	priv->fmt		= &ov5642_colour_fmts[0];
> +
> +	priv->crop_rect.width	= OV5642_DEFAULT_WIDTH;
> +	priv->crop_rect.height	= OV5642_DEFAULT_HEIGHT;
> +	priv->crop_rect.left	= (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
> +	priv->crop_rect.top	= (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
> +	priv->out_size.width	= OV5642_DEFAULT_WIDTH;
> +	priv->out_size.height	= OV5642_DEFAULT_HEIGHT;
> 
>  	ret = ov5642_video_probe(icd, client);
>  	if (ret < 0)
> @@ -951,6 +1037,7 @@ static int ov5642_probe(struct i2c_client *client,
>  	return 0;
> 
>  error:
> +	icd->ops = NULL;
>  	kfree(priv);
>  	return ret;
>  }
> @@ -961,6 +1048,7 @@ static int ov5642_remove(struct i2c_client *client)
>  	struct soc_camera_device *icd = client->dev.platform_data;
>  	struct soc_camera_link *icl = to_soc_camera_link(icd);
> 
> +	icd->ops = NULL;
>  	if (icl->free_bus)
>  		icl->free_bus(icl);
>  	kfree(priv);
Guennadi Liakhovetski Aug. 29, 2011, 12:18 p.m. UTC | #2
Hi Laurent

On Sun, 28 Aug 2011, Laurent Pinchart wrote:

[snip]

> > @@ -593,8 +639,7 @@ static struct ov5642 *to_ov5642(const struct i2c_client
> > *client) }
> > 
> >  /* Find a data format by a pixel code in an array */
> > -static const struct ov5642_datafmt
> > -			*ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
> > +static const struct ov5642_datafmt *ov5642_find_datafmt(enum
> > v4l2_mbus_pixelcode code) {
> 
> checkpatch.pl won't be happy.

Since the lift of the hard 80-char limit, I often find lines of 86 characters 
more acceptable than their split versions.

[snip]

> > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd,
> > 
> >  	ov5642_try_fmt(sd, mf);
> > 
> > +	priv->out_size.width		= mf->width;
> > +	priv->out_size.height		= mf->height;
> 
> It looks like to me (but I may be wrong) that you achieve different 
> resolutions using cropping, not scaling. If that's correct you should 
> implement s_crop support and refuse changing the resolution through s_fmt.

As the patch explains (I think) on several occasions, currently only the 
1:1 scale is supported, and it was our deliberate choice to implement this 
using the scaling API

> > @@ -793,10 +868,12 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd,
> > 
> >  	mf->code	= fmt->code;
> >  	mf->colorspace	= fmt->colorspace;
> > -	mf->width	= OV5642_WIDTH;
> > -	mf->height	= OV5642_HEIGHT;
> > +	mf->width	= priv->out_size.width;
> > +	mf->height	= priv->out_size.height;
> >  	mf->field	= V4L2_FIELD_NONE;
> > 
> > +	dev_dbg(sd->v4l2_dev->dev, "%s return width: %u heigth: %u\n", __func__,
> > +			mf->width, mf->height);
> 
> Isn't that a bit too verbose ? Printing the format in a debug message in the 
> s_fmt handler is useful, but maybe doing it in g_fmt is a bit too much.

This is a dev_dbg()... Personally, as long as they don't clutter the source 
code needlessly, compile without warnings and have their typos fixed (;-)) 
I don't have problems with an odd instance, even if I don't really perceive 
its output as particularly useful:-)

[snip]

> > +	dev_dbg(sd->v4l2_dev->dev, "%s crop width: %u heigth: %u\n", __func__,
> > +			rect->width, rect->height);
> 
> Same comment as for g_fmt.

same reply:-)

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Laurent Pinchart Aug. 29, 2011, 12:26 p.m. UTC | #3
Hi Guennadi,

On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> 
> [snip]
> 
> > > @@ -593,8 +639,7 @@ static struct ov5642 *to_ov5642(const struct
> > > i2c_client *client) }
> > > 
> > >  /* Find a data format by a pixel code in an array */
> > > 
> > > -static const struct ov5642_datafmt
> > > -			*ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
> > > +static const struct ov5642_datafmt *ov5642_find_datafmt(enum
> > > v4l2_mbus_pixelcode code) {
> > 
> > checkpatch.pl won't be happy.
> 
> Since the lift of the hard 80-char limit, I often find lines of 86
> characters more acceptable than their split versions.

When has that been lifted ?

> [snip]
> 
> > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd,
> > > 
> > >  	ov5642_try_fmt(sd, mf);
> > > 
> > > +	priv->out_size.width		= mf->width;
> > > +	priv->out_size.height		= mf->height;
> > 
> > It looks like to me (but I may be wrong) that you achieve different
> > resolutions using cropping, not scaling. If that's correct you should
> > implement s_crop support and refuse changing the resolution through
> > s_fmt.
> 
> As the patch explains (I think) on several occasions, currently only the
> 1:1 scale is supported, and it was our deliberate choice to implement this
> using the scaling API

If you implement cropping, you should use the crop API, not the scaling API 
:-)

> > > @@ -793,10 +868,12 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd,
> > > 
> > >  	mf->code	= fmt->code;
> > >  	mf->colorspace	= fmt->colorspace;
> > > 
> > > -	mf->width	= OV5642_WIDTH;
> > > -	mf->height	= OV5642_HEIGHT;
> > > +	mf->width	= priv->out_size.width;
> > > +	mf->height	= priv->out_size.height;
> > > 
> > >  	mf->field	= V4L2_FIELD_NONE;
> > > 
> > > +	dev_dbg(sd->v4l2_dev->dev, "%s return width: %u heigth: %u\n",
> > > __func__, +			mf->width, mf->height);
> > 
> > Isn't that a bit too verbose ? Printing the format in a debug message in
> > the s_fmt handler is useful, but maybe doing it in g_fmt is a bit too
> > much.
> 
> This is a dev_dbg()... Personally, as long as they don't clutter the source
> code needlessly, compile without warnings and have their typos fixed (;-))

Removing it is a good way to fix the typo :-)

> I don't have problems with an odd instance, even if I don't really perceive
> its output as particularly useful:-)
Guennadi Liakhovetski Aug. 29, 2011, 12:34 p.m. UTC | #4
On Mon, 29 Aug 2011, Laurent Pinchart wrote:

> Hi Guennadi,
> 
> On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > 
> > [snip]
> > 
> > > > @@ -593,8 +639,7 @@ static struct ov5642 *to_ov5642(const struct
> > > > i2c_client *client) }
> > > > 
> > > >  /* Find a data format by a pixel code in an array */
> > > > 
> > > > -static const struct ov5642_datafmt
> > > > -			*ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
> > > > +static const struct ov5642_datafmt *ov5642_find_datafmt(enum
> > > > v4l2_mbus_pixelcode code) {
> > > 
> > > checkpatch.pl won't be happy.
> > 
> > Since the lift of the hard 80-char limit, I often find lines of 86
> > characters more acceptable than their split versions.
> 
> When has that been lifted ?

Sorry, don't have a link at hand, a few months ago, either beginning of 
this or end of last year, perhaps. There has been a lengthy discussion on 
multiple lists, mainly lkml, the common mood was, that 80 chars wasn't 
meaningful anymore, but I'm not sure what exact actions have been executed 
to document this.

> 
> > [snip]
> > 
> > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd,
> > > > 
> > > >  	ov5642_try_fmt(sd, mf);
> > > > 
> > > > +	priv->out_size.width		= mf->width;
> > > > +	priv->out_size.height		= mf->height;
> > > 
> > > It looks like to me (but I may be wrong) that you achieve different
> > > resolutions using cropping, not scaling. If that's correct you should
> > > implement s_crop support and refuse changing the resolution through
> > > s_fmt.
> > 
> > As the patch explains (I think) on several occasions, currently only the
> > 1:1 scale is supported, and it was our deliberate choice to implement this
> > using the scaling API
> 
> If you implement cropping, you should use the crop API, not the scaling API 
> :-)

It's changing both - input and output sizes.

> 
> > > > @@ -793,10 +868,12 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd,
> > > > 
> > > >  	mf->code	= fmt->code;
> > > >  	mf->colorspace	= fmt->colorspace;
> > > > 
> > > > -	mf->width	= OV5642_WIDTH;
> > > > -	mf->height	= OV5642_HEIGHT;
> > > > +	mf->width	= priv->out_size.width;
> > > > +	mf->height	= priv->out_size.height;
> > > > 
> > > >  	mf->field	= V4L2_FIELD_NONE;
> > > > 
> > > > +	dev_dbg(sd->v4l2_dev->dev, "%s return width: %u heigth: %u\n",
> > > > __func__, +			mf->width, mf->height);
> > > 
> > > Isn't that a bit too verbose ? Printing the format in a debug message in
> > > the s_fmt handler is useful, but maybe doing it in g_fmt is a bit too
> > > much.
> > 
> > This is a dev_dbg()... Personally, as long as they don't clutter the source
> > code needlessly, compile without warnings and have their typos fixed (;-))
> 
> Removing it is a good way to fix the typo :-)
> 
> > I don't have problems with an odd instance, even if I don't really perceive
> > its output as particularly useful:-)

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Laurent Pinchart Aug. 29, 2011, 12:48 p.m. UTC | #5
Hi Guennadi,

On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > 
> > > [snip]
> > > 
> > > > > @@ -593,8 +639,7 @@ static struct ov5642 *to_ov5642(const struct
> > > > > i2c_client *client) }
> > > > > 
> > > > >  /* Find a data format by a pixel code in an array */
> > > > > 
> > > > > -static const struct ov5642_datafmt
> > > > > -			*ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
> > > > > +static const struct ov5642_datafmt *ov5642_find_datafmt(enum
> > > > > v4l2_mbus_pixelcode code) {
> > > > 
> > > > checkpatch.pl won't be happy.
> > > 
> > > Since the lift of the hard 80-char limit, I often find lines of 86
> > > characters more acceptable than their split versions.
> > 
> > When has that been lifted ?
> 
> Sorry, don't have a link at hand, a few months ago, either beginning of
> this or end of last year, perhaps. There has been a lengthy discussion on
> multiple lists, mainly lkml, the common mood was, that 80 chars wasn't
> meaningful anymore, but I'm not sure what exact actions have been executed
> to document this.

I remember the discussion but I wasn't sure if anything had been decided and 
set in stone.

> > > [snip]
> > > 
> > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct v4l2_subdev
> > > > > *sd,
> > > > > 
> > > > >  	ov5642_try_fmt(sd, mf);
> > > > > 
> > > > > +	priv->out_size.width		= mf->width;
> > > > > +	priv->out_size.height		= mf->height;
> > > > 
> > > > It looks like to me (but I may be wrong) that you achieve different
> > > > resolutions using cropping, not scaling. If that's correct you should
> > > > implement s_crop support and refuse changing the resolution through
> > > > s_fmt.
> > > 
> > > As the patch explains (I think) on several occasions, currently only
> > > the 1:1 scale is supported, and it was our deliberate choice to
> > > implement this using the scaling API
> > 
> > If you implement cropping, you should use the crop API, not the scaling
> > API
> > 
> > :-)
> 
> It's changing both - input and output sizes.

Sure, but it's still cropping.
Guennadi Liakhovetski Aug. 30, 2011, 8:55 a.m. UTC | #6
On Mon, 29 Aug 2011, Laurent Pinchart wrote:

> Hi Guennadi,
> 
> On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > 
> > > > [snip]
> > > > 
> > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct v4l2_subdev
> > > > > > *sd,
> > > > > > 
> > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > 
> > > > > > +	priv->out_size.width		= mf->width;
> > > > > > +	priv->out_size.height		= mf->height;
> > > > > 
> > > > > It looks like to me (but I may be wrong) that you achieve different
> > > > > resolutions using cropping, not scaling. If that's correct you should
> > > > > implement s_crop support and refuse changing the resolution through
> > > > > s_fmt.
> > > > 
> > > > As the patch explains (I think) on several occasions, currently only
> > > > the 1:1 scale is supported, and it was our deliberate choice to
> > > > implement this using the scaling API
> > > 
> > > If you implement cropping, you should use the crop API, not the scaling
> > > API
> > > 
> > > :-)
> > 
> > It's changing both - input and output sizes.
> 
> Sure, but it's still cropping.

Why? Isn't it a matter of the PoV? It changes the output window, i.e., 
implements S_FMT. And S_FMT is by far more important / widely used than 
S_CROP. Refusing to change the output window and always just returning the 
== crop size wouldn't be polite, IMHO. Don't think many users would guess 
to use S_CROP. Standard applications a la mplayer don't use S_CROP at all.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus Aug. 30, 2011, 12:33 p.m. UTC | #7
On Mon, Aug 29, 2011 at 02:18:50PM +0200, Guennadi Liakhovetski wrote:
> Hi Laurent
> 
> On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> 
> [snip]
> 
> > > @@ -593,8 +639,7 @@ static struct ov5642 *to_ov5642(const struct i2c_client
> > > *client) }
> > > 
> > >  /* Find a data format by a pixel code in an array */
> > > -static const struct ov5642_datafmt
> > > -			*ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
> > > +static const struct ov5642_datafmt *ov5642_find_datafmt(enum
> > > v4l2_mbus_pixelcode code) {
> > 
> > checkpatch.pl won't be happy.
> 
> Since the lift of the hard 80-char limit, I often find lines of 86 characters 
> more acceptable than their split versions.

It's not lifted, and it's still a rule. It's only that exceptions are
nowadays allowed to that rule where they make sense.

> > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd,
> > > 
> > >  	ov5642_try_fmt(sd, mf);
> > > 
> > > +	priv->out_size.width		= mf->width;
> > > +	priv->out_size.height		= mf->height;
> > 
> > It looks like to me (but I may be wrong) that you achieve different 
> > resolutions using cropping, not scaling. If that's correct you should 
> > implement s_crop support and refuse changing the resolution through s_fmt.
> 
> As the patch explains (I think) on several occasions, currently only the 
> 1:1 scale is supported, and it was our deliberate choice to implement this 
> using the scaling API

As there is a subdev op to implement crop (s_crop) it should be used instead.
Otherwise any application thinks that the hardware can actually do scaling
but instead it crops. The above looks like gross misuse of the API to me.

Is there any particular reason why you think it should be implemented this
way?
Laurent Pinchart Aug. 30, 2011, 12:46 p.m. UTC | #8
Hi Guennadi,

On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
> On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > > 
> > > > > [snip]
> > > > > 
> > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
> > > > > > > v4l2_subdev *sd,
> > > > > > > 
> > > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > > 
> > > > > > > +	priv->out_size.width		= mf->width;
> > > > > > > +	priv->out_size.height		= mf->height;
> > > > > > 
> > > > > > It looks like to me (but I may be wrong) that you achieve
> > > > > > different resolutions using cropping, not scaling. If that's
> > > > > > correct you should implement s_crop support and refuse changing
> > > > > > the resolution through s_fmt.
> > > > > 
> > > > > As the patch explains (I think) on several occasions, currently
> > > > > only the 1:1 scale is supported, and it was our deliberate choice
> > > > > to implement this using the scaling API
> > > > 
> > > > If you implement cropping, you should use the crop API, not the
> > > > scaling API
> > > > 
> > > > :-)
> > > 
> > > It's changing both - input and output sizes.
> > 
> > Sure, but it's still cropping.
> 
> Why? Isn't it a matter of the PoV?

No it isn't. Cropping is cropping, regardless of how you look at it.

> It changes the output window, i.e., implements S_FMT. And S_FMT is by far
> more important / widely used than S_CROP. Refusing to change the output
> window and always just returning the == crop size wouldn't be polite, IMHO.

If your sensor has no scaler the output size is equal to the crop rectangle. 
There's no way around that, and there's no reason to have the driver behave 
otherwise.

> Don't think many users would guess to use S_CROP.

Users who want to crop use S_CROP.

> Standard applications a la mplayer don't use S_CROP at all.

That's because they don't want to crop. mplayer expects the driver to perform 
scaling when it calls S_FMT, and users won't be happy if you crop instead.
Guennadi Liakhovetski Aug. 30, 2011, 1:13 p.m. UTC | #9
(also replying to a similar comment by Sakari)

On Tue, 30 Aug 2011, Laurent Pinchart wrote:

> Hi Guennadi,
> 
> On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
> > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > > > 
> > > > > > [snip]
> > > > > > 
> > > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
> > > > > > > > v4l2_subdev *sd,
> > > > > > > > 
> > > > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > > > 
> > > > > > > > +	priv->out_size.width		= mf->width;
> > > > > > > > +	priv->out_size.height		= mf->height;
> > > > > > > 
> > > > > > > It looks like to me (but I may be wrong) that you achieve
> > > > > > > different resolutions using cropping, not scaling. If that's
> > > > > > > correct you should implement s_crop support and refuse changing
> > > > > > > the resolution through s_fmt.
> > > > > > 
> > > > > > As the patch explains (I think) on several occasions, currently
> > > > > > only the 1:1 scale is supported, and it was our deliberate choice
> > > > > > to implement this using the scaling API
> > > > > 
> > > > > If you implement cropping, you should use the crop API, not the
> > > > > scaling API
> > > > > 
> > > > > :-)
> > > > 
> > > > It's changing both - input and output sizes.
> > > 
> > > Sure, but it's still cropping.
> > 
> > Why? Isn't it a matter of the PoV?
> 
> No it isn't. Cropping is cropping, regardless of how you look at it.
> 
> > It changes the output window, i.e., implements S_FMT. And S_FMT is by far
> > more important / widely used than S_CROP. Refusing to change the output
> > window and always just returning the == crop size wouldn't be polite, IMHO.
> 
> If your sensor has no scaler the output size is equal to the crop rectangle. 
> There's no way around that, and there's no reason to have the driver behave 
> otherwise.
> 
> > Don't think many users would guess to use S_CROP.
> 
> Users who want to crop use S_CROP.
> 
> > Standard applications a la mplayer don't use S_CROP at all.
> 
> That's because they don't want to crop. mplayer expects the driver to perform 
> scaling when it calls S_FMT, and users won't be happy if you crop instead.

So, here's my opinion, based on the V4L2 spec. I'm going to base on this 
and pull this patch into my tree and let Mauro decide, unless he expresses 
his negative opinion before that.

The spec defines S_FMT as an operation to set the output (in case of a 
capture device) frame format. Which this driver clearly does. The output 
format should be set, using scaling, however, if the driver or the 
hardware are unable to preserve the exact same input rectangle to satisfy 
the request, the driver is also allowed to change the cropping rectangle 
_as much as necessary_ - S_FMT takes precedence. This has been discussed 
before, and the conclusion was - of the two geometry calls (S_FMT and 
S_CROP) the last call overrides previous setting of the opposite geometry.

It also defines S_CROP as an operation to set the cropping rectangle. The 
driver is also allowed to change the output window, if it cannot be 
preserved. Similarly, the last call wins.

Ideally in this situation I would implement both S_CROP and S_FMT and let 
both change the opposite window as needed, which in this case means set it 
equal to the one, being configured. Since most applications are primarily 
interested in the S_FMT call to configure their user interface, I find it 
a wrong approach to refuse S_FMT and always return the current cropping 
rectangle. In such a case the application will possibly be stuck with some 
default output rectangle, because it certainly will _not_ guess to use 
S_CROP to configure it. Whereas if we implement S_FMT with a constant 1:1 
scale the application will get the required UI size. I agree, that 
changing the view area, while changing the output window, is not exactly 
what the user expects, but it's better than presenting all applications 
with a fixed, possibly completely unsuitable, UI window.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Laurent Pinchart Aug. 30, 2011, 1:26 p.m. UTC | #10
Hi Mauro,

Could you please comment on this ? In a nutshell (and from my biased point of 
view), the question is "can cropping be configured using S_FMT instead of 
S_CROP ?". The answer is of course no :-)

On Tuesday 30 August 2011 15:13:25 Guennadi Liakhovetski wrote:
> On Tue, 30 Aug 2011, Laurent Pinchart wrote:
> > On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
> > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > > > > 
> > > > > > > [snip]
> > > > > > > 
> > > > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
> > > > > > > > > v4l2_subdev *sd,
> > > > > > > > > 
> > > > > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > > > > 
> > > > > > > > > +	priv->out_size.width		= mf->width;
> > > > > > > > > +	priv->out_size.height		= mf->height;
> > > > > > > > 
> > > > > > > > It looks like to me (but I may be wrong) that you achieve
> > > > > > > > different resolutions using cropping, not scaling. If that's
> > > > > > > > correct you should implement s_crop support and refuse
> > > > > > > > changing the resolution through s_fmt.
> > > > > > > 
> > > > > > > As the patch explains (I think) on several occasions, currently
> > > > > > > only the 1:1 scale is supported, and it was our deliberate
> > > > > > > choice to implement this using the scaling API
> > > > > > 
> > > > > > If you implement cropping, you should use the crop API, not the
> > > > > > scaling API
> > > > > > 
> > > > > > :-)
> > > > > 
> > > > > It's changing both - input and output sizes.
> > > > 
> > > > Sure, but it's still cropping.
> > > 
> > > Why? Isn't it a matter of the PoV?
> > 
> > No it isn't. Cropping is cropping, regardless of how you look at it.
> > 
> > > It changes the output window, i.e., implements S_FMT. And S_FMT is by
> > > far more important / widely used than S_CROP. Refusing to change the
> > > output window and always just returning the == crop size wouldn't be
> > > polite, IMHO.
> > 
> > If your sensor has no scaler the output size is equal to the crop
> > rectangle. There's no way around that, and there's no reason to have the
> > driver behave otherwise.
> > 
> > > Don't think many users would guess to use S_CROP.
> > 
> > Users who want to crop use S_CROP.
> > 
> > > Standard applications a la mplayer don't use S_CROP at all.
> > 
> > That's because they don't want to crop. mplayer expects the driver to
> > perform scaling when it calls S_FMT, and users won't be happy if you
> > crop instead.
> 
> So, here's my opinion, based on the V4L2 spec. I'm going to base on this
> and pull this patch into my tree and let Mauro decide, unless he expresses
> his negative opinion before that.
> 
> The spec defines S_FMT as an operation to set the output (in case of a
> capture device) frame format. Which this driver clearly does. The output
> format should be set, using scaling, however, if the driver or the
> hardware are unable to preserve the exact same input rectangle to satisfy
> the request, the driver is also allowed to change the cropping rectangle
> _as much as necessary_ - S_FMT takes precedence. This has been discussed
> before, and the conclusion was - of the two geometry calls (S_FMT and
> S_CROP) the last call overrides previous setting of the opposite geometry.
> 
> It also defines S_CROP as an operation to set the cropping rectangle. The
> driver is also allowed to change the output window, if it cannot be
> preserved. Similarly, the last call wins.
> 
> Ideally in this situation I would implement both S_CROP and S_FMT and let
> both change the opposite window as needed, which in this case means set it
> equal to the one, being configured. Since most applications are primarily
> interested in the S_FMT call to configure their user interface, I find it
> a wrong approach to refuse S_FMT and always return the current cropping
> rectangle. In such a case the application will possibly be stuck with some
> default output rectangle, because it certainly will _not_ guess to use
> S_CROP to configure it. Whereas if we implement S_FMT with a constant 1:1
> scale the application will get the required UI size. I agree, that
> changing the view area, while changing the output window, is not exactly
> what the user expects, but it's better than presenting all applications
> with a fixed, possibly completely unsuitable, UI window.
Laurent Pinchart Aug. 30, 2011, 1:28 p.m. UTC | #11
Hi Guennadi,

On Tuesday 30 August 2011 15:13:25 Guennadi Liakhovetski wrote:
> On Tue, 30 Aug 2011, Laurent Pinchart wrote:
> > On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
> > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > > > > 
> > > > > > > [snip]
> > > > > > > 
> > > > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
> > > > > > > > > v4l2_subdev *sd,
> > > > > > > > > 
> > > > > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > > > > 
> > > > > > > > > +	priv->out_size.width		= mf->width;
> > > > > > > > > +	priv->out_size.height		= mf->height;
> > > > > > > > 
> > > > > > > > It looks like to me (but I may be wrong) that you achieve
> > > > > > > > different resolutions using cropping, not scaling. If that's
> > > > > > > > correct you should implement s_crop support and refuse
> > > > > > > > changing the resolution through s_fmt.
> > > > > > > 
> > > > > > > As the patch explains (I think) on several occasions, currently
> > > > > > > only the 1:1 scale is supported, and it was our deliberate
> > > > > > > choice to implement this using the scaling API
> > > > > > 
> > > > > > If you implement cropping, you should use the crop API, not the
> > > > > > scaling API
> > > > > > 
> > > > > > :-)
> > > > > 
> > > > > It's changing both - input and output sizes.
> > > > 
> > > > Sure, but it's still cropping.
> > > 
> > > Why? Isn't it a matter of the PoV?
> > 
> > No it isn't. Cropping is cropping, regardless of how you look at it.
> > 
> > > It changes the output window, i.e., implements S_FMT. And S_FMT is by
> > > far more important / widely used than S_CROP. Refusing to change the
> > > output window and always just returning the == crop size wouldn't be
> > > polite, IMHO.
> > 
> > If your sensor has no scaler the output size is equal to the crop
> > rectangle. There's no way around that, and there's no reason to have the
> > driver behave otherwise.
> > 
> > > Don't think many users would guess to use S_CROP.
> > 
> > Users who want to crop use S_CROP.
> > 
> > > Standard applications a la mplayer don't use S_CROP at all.
> > 
> > That's because they don't want to crop. mplayer expects the driver to
> > perform scaling when it calls S_FMT, and users won't be happy if you
> > crop instead.
> 
> So, here's my opinion, based on the V4L2 spec. I'm going to base on this
> and pull this patch into my tree and let Mauro decide, unless he expresses
> his negative opinion before that.

I've also made other comments. I expect at least a v2 that addresses them.
Guennadi Liakhovetski Aug. 30, 2011, 1:36 p.m. UTC | #12
On Tue, 30 Aug 2011, Laurent Pinchart wrote:

> Hi Guennadi,
> 
> On Tuesday 30 August 2011 15:13:25 Guennadi Liakhovetski wrote:
> > On Tue, 30 Aug 2011, Laurent Pinchart wrote:
> > > On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
> > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > > > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > > > > > 
> > > > > > > > [snip]
> > > > > > > > 
> > > > > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
> > > > > > > > > > v4l2_subdev *sd,
> > > > > > > > > > 
> > > > > > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > > > > > 
> > > > > > > > > > +	priv->out_size.width		= mf->width;
> > > > > > > > > > +	priv->out_size.height		= mf->height;
> > > > > > > > > 
> > > > > > > > > It looks like to me (but I may be wrong) that you achieve
> > > > > > > > > different resolutions using cropping, not scaling. If that's
> > > > > > > > > correct you should implement s_crop support and refuse
> > > > > > > > > changing the resolution through s_fmt.
> > > > > > > > 
> > > > > > > > As the patch explains (I think) on several occasions, currently
> > > > > > > > only the 1:1 scale is supported, and it was our deliberate
> > > > > > > > choice to implement this using the scaling API
> > > > > > > 
> > > > > > > If you implement cropping, you should use the crop API, not the
> > > > > > > scaling API
> > > > > > > 
> > > > > > > :-)
> > > > > > 
> > > > > > It's changing both - input and output sizes.
> > > > > 
> > > > > Sure, but it's still cropping.
> > > > 
> > > > Why? Isn't it a matter of the PoV?
> > > 
> > > No it isn't. Cropping is cropping, regardless of how you look at it.
> > > 
> > > > It changes the output window, i.e., implements S_FMT. And S_FMT is by
> > > > far more important / widely used than S_CROP. Refusing to change the
> > > > output window and always just returning the == crop size wouldn't be
> > > > polite, IMHO.
> > > 
> > > If your sensor has no scaler the output size is equal to the crop
> > > rectangle. There's no way around that, and there's no reason to have the
> > > driver behave otherwise.
> > > 
> > > > Don't think many users would guess to use S_CROP.
> > > 
> > > Users who want to crop use S_CROP.
> > > 
> > > > Standard applications a la mplayer don't use S_CROP at all.
> > > 
> > > That's because they don't want to crop. mplayer expects the driver to
> > > perform scaling when it calls S_FMT, and users won't be happy if you
> > > crop instead.
> > 
> > So, here's my opinion, based on the V4L2 spec. I'm going to base on this
> > and pull this patch into my tree and let Mauro decide, unless he expresses
> > his negative opinion before that.
> 
> I've also made other comments. I expect at least a v2 that addresses them.

Of course, (most of) your other comments are valid and they will be 
addressed.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bastian Hecht Aug. 30, 2011, 1:38 p.m. UTC | #13
Hello Laurent and others,

2011/8/30 Laurent Pinchart <laurent.pinchart@ideasonboard.com>:
> Hi Guennadi,
>
> On Tuesday 30 August 2011 15:13:25 Guennadi Liakhovetski wrote:
>> On Tue, 30 Aug 2011, Laurent Pinchart wrote:
>> > On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
>> > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
>> > > > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
>> > > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
>> > > > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
>> > > > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
>> > > > > > >
>> > > > > > > [snip]
>> > > > > > >
>> > > > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
>> > > > > > > > > v4l2_subdev *sd,
>> > > > > > > > >
>> > > > > > > > >       ov5642_try_fmt(sd, mf);
>> > > > > > > > >
>> > > > > > > > > +     priv->out_size.width            = mf->width;
>> > > > > > > > > +     priv->out_size.height           = mf->height;
>> > > > > > > >
>> > > > > > > > It looks like to me (but I may be wrong) that you achieve
>> > > > > > > > different resolutions using cropping, not scaling. If that's
>> > > > > > > > correct you should implement s_crop support and refuse
>> > > > > > > > changing the resolution through s_fmt.
>> > > > > > >
>> > > > > > > As the patch explains (I think) on several occasions, currently
>> > > > > > > only the 1:1 scale is supported, and it was our deliberate
>> > > > > > > choice to implement this using the scaling API
>> > > > > >
>> > > > > > If you implement cropping, you should use the crop API, not the
>> > > > > > scaling API
>> > > > > >
>> > > > > > :-)
>> > > > >
>> > > > > It's changing both - input and output sizes.
>> > > >
>> > > > Sure, but it's still cropping.
>> > >
>> > > Why? Isn't it a matter of the PoV?
>> >
>> > No it isn't. Cropping is cropping, regardless of how you look at it.
>> >
>> > > It changes the output window, i.e., implements S_FMT. And S_FMT is by
>> > > far more important / widely used than S_CROP. Refusing to change the
>> > > output window and always just returning the == crop size wouldn't be
>> > > polite, IMHO.
>> >
>> > If your sensor has no scaler the output size is equal to the crop
>> > rectangle. There's no way around that, and there's no reason to have the
>> > driver behave otherwise.
>> >
>> > > Don't think many users would guess to use S_CROP.
>> >
>> > Users who want to crop use S_CROP.
>> >
>> > > Standard applications a la mplayer don't use S_CROP at all.
>> >
>> > That's because they don't want to crop. mplayer expects the driver to
>> > perform scaling when it calls S_FMT, and users won't be happy if you
>> > crop instead.
>>
>> So, here's my opinion, based on the V4L2 spec. I'm going to base on this
>> and pull this patch into my tree and let Mauro decide, unless he expresses
>> his negative opinion before that.
>
> I've also made other comments. I expect at least a v2 that addresses them.

Being the author I should drop a note too, I guess. Currently I'm
working on all the comments and preparing a new set of patches. I will
of course either implement the suggestion or reply to it in 1 or 2
days.

As far as the cropping/scaling discussion is going on - I wait until
you agreed on something (what is probably not happening though ;)
before adressing it directly in the code. I don't have a real own
opinion here as I am too unexperienced. If the arguments are balanced
I would prefer leaving the code as it is :-)  but I'm open to change
it if necessary.

best regards,

 Bastian


> --
> Regards,
>
> Laurent Pinchart
>
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hans Verkuil Aug. 30, 2011, 1:46 p.m. UTC | #14
On Tuesday, August 30, 2011 15:13:25 Guennadi Liakhovetski wrote:
> (also replying to a similar comment by Sakari)
> 
> On Tue, 30 Aug 2011, Laurent Pinchart wrote:
> 
> > Hi Guennadi,
> > 
> > On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
> > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > > > > 
> > > > > > > [snip]
> > > > > > > 
> > > > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
> > > > > > > > > v4l2_subdev *sd,
> > > > > > > > > 
> > > > > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > > > > 
> > > > > > > > > +	priv->out_size.width		= mf->width;
> > > > > > > > > +	priv->out_size.height		= mf->height;
> > > > > > > > 
> > > > > > > > It looks like to me (but I may be wrong) that you achieve
> > > > > > > > different resolutions using cropping, not scaling. If that's
> > > > > > > > correct you should implement s_crop support and refuse 
changing
> > > > > > > > the resolution through s_fmt.
> > > > > > > 
> > > > > > > As the patch explains (I think) on several occasions, currently
> > > > > > > only the 1:1 scale is supported, and it was our deliberate 
choice
> > > > > > > to implement this using the scaling API
> > > > > > 
> > > > > > If you implement cropping, you should use the crop API, not the
> > > > > > scaling API
> > > > > > 
> > > > > > :-)
> > > > > 
> > > > > It's changing both - input and output sizes.
> > > > 
> > > > Sure, but it's still cropping.
> > > 
> > > Why? Isn't it a matter of the PoV?
> > 
> > No it isn't. Cropping is cropping, regardless of how you look at it.
> > 
> > > It changes the output window, i.e., implements S_FMT. And S_FMT is by 
far
> > > more important / widely used than S_CROP. Refusing to change the output
> > > window and always just returning the == crop size wouldn't be polite, 
IMHO.
> > 
> > If your sensor has no scaler the output size is equal to the crop 
rectangle. 
> > There's no way around that, and there's no reason to have the driver 
behave 
> > otherwise.
> > 
> > > Don't think many users would guess to use S_CROP.
> > 
> > Users who want to crop use S_CROP.
> > 
> > > Standard applications a la mplayer don't use S_CROP at all.
> > 
> > That's because they don't want to crop. mplayer expects the driver to 
perform 
> > scaling when it calls S_FMT, and users won't be happy if you crop instead.
> 
> So, here's my opinion, based on the V4L2 spec. I'm going to base on this 
> and pull this patch into my tree and let Mauro decide, unless he expresses 
> his negative opinion before that.
> 
> The spec defines S_FMT as an operation to set the output (in case of a 
> capture device) frame format. Which this driver clearly does. The output 
> format should be set, using scaling, however, if the driver or the 
> hardware are unable to preserve the exact same input rectangle to satisfy 
> the request, the driver is also allowed to change the cropping rectangle 
> _as much as necessary_ - S_FMT takes precedence. This has been discussed 
> before, and the conclusion was - of the two geometry calls (S_FMT and 
> S_CROP) the last call overrides previous setting of the opposite geometry.
> 
> It also defines S_CROP as an operation to set the cropping rectangle. The 
> driver is also allowed to change the output window, if it cannot be 
> preserved. Similarly, the last call wins.
> 
> Ideally in this situation I would implement both S_CROP and S_FMT and let 
> both change the opposite window as needed, which in this case means set it 
> equal to the one, being configured. Since most applications are primarily 
> interested in the S_FMT call to configure their user interface, I find it 
> a wrong approach to refuse S_FMT and always return the current cropping 
> rectangle. In such a case the application will possibly be stuck with some 
> default output rectangle, because it certainly will _not_ guess to use 
> S_CROP to configure it. Whereas if we implement S_FMT with a constant 1:1 
> scale the application will get the required UI size. I agree, that 
> changing the view area, while changing the output window, is not exactly 
> what the user expects, but it's better than presenting all applications 
> with a fixed, possibly completely unsuitable, UI window.

The problem with S_FMT changing the crop rectangle (and I assume we are not
talking about small pixel tweaks to make the hardware happy) is that the
crop operation actually removes part of the frame. That's not something you
would expect S_FMT to do, ever. Such an operation has to be explicitly
requested by the user.

It's also why properly written applications (e.g. capture-example.c) has
code like this to reset the crop rectangle before starting streaming:

        if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                crop.c = cropcap.defrect; /* reset to default */

                if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
                        switch (errno) {
                        case EINVAL:
                                /* Cropping not supported. */
                                break;
                        default:
                                /* Errors ignored. */
                                break;
                        }
                }
        }

(Hmm, capture-example.c should also test for ENOTTY since we changed the
error code).

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski Aug. 30, 2011, 2:24 p.m. UTC | #15
Hi Hans

On Tue, 30 Aug 2011, Hans Verkuil wrote:

> On Tuesday, August 30, 2011 15:13:25 Guennadi Liakhovetski wrote:
> > (also replying to a similar comment by Sakari)
> > 
> > On Tue, 30 Aug 2011, Laurent Pinchart wrote:
> > 
> > > Hi Guennadi,
> > > 
> > > On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
> > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > > > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > > > > > 
> > > > > > > > [snip]
> > > > > > > > 
> > > > > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
> > > > > > > > > > v4l2_subdev *sd,
> > > > > > > > > > 
> > > > > > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > > > > > 
> > > > > > > > > > +	priv->out_size.width		= mf->width;
> > > > > > > > > > +	priv->out_size.height		= mf->height;
> > > > > > > > > 
> > > > > > > > > It looks like to me (but I may be wrong) that you achieve
> > > > > > > > > different resolutions using cropping, not scaling. If that's
> > > > > > > > > correct you should implement s_crop support and refuse 
> changing
> > > > > > > > > the resolution through s_fmt.
> > > > > > > > 
> > > > > > > > As the patch explains (I think) on several occasions, currently
> > > > > > > > only the 1:1 scale is supported, and it was our deliberate 
> choice
> > > > > > > > to implement this using the scaling API
> > > > > > > 
> > > > > > > If you implement cropping, you should use the crop API, not the
> > > > > > > scaling API
> > > > > > > 
> > > > > > > :-)
> > > > > > 
> > > > > > It's changing both - input and output sizes.
> > > > > 
> > > > > Sure, but it's still cropping.
> > > > 
> > > > Why? Isn't it a matter of the PoV?
> > > 
> > > No it isn't. Cropping is cropping, regardless of how you look at it.
> > > 
> > > > It changes the output window, i.e., implements S_FMT. And S_FMT is by 
> far
> > > > more important / widely used than S_CROP. Refusing to change the output
> > > > window and always just returning the == crop size wouldn't be polite, 
> IMHO.
> > > 
> > > If your sensor has no scaler the output size is equal to the crop 
> rectangle. 
> > > There's no way around that, and there's no reason to have the driver 
> behave 
> > > otherwise.
> > > 
> > > > Don't think many users would guess to use S_CROP.
> > > 
> > > Users who want to crop use S_CROP.
> > > 
> > > > Standard applications a la mplayer don't use S_CROP at all.
> > > 
> > > That's because they don't want to crop. mplayer expects the driver to 
> perform 
> > > scaling when it calls S_FMT, and users won't be happy if you crop instead.
> > 
> > So, here's my opinion, based on the V4L2 spec. I'm going to base on this 
> > and pull this patch into my tree and let Mauro decide, unless he expresses 
> > his negative opinion before that.
> > 
> > The spec defines S_FMT as an operation to set the output (in case of a 
> > capture device) frame format. Which this driver clearly does. The output 
> > format should be set, using scaling, however, if the driver or the 
> > hardware are unable to preserve the exact same input rectangle to satisfy 
> > the request, the driver is also allowed to change the cropping rectangle 
> > _as much as necessary_ - S_FMT takes precedence. This has been discussed 
> > before, and the conclusion was - of the two geometry calls (S_FMT and 
> > S_CROP) the last call overrides previous setting of the opposite geometry.
> > 
> > It also defines S_CROP as an operation to set the cropping rectangle. The 
> > driver is also allowed to change the output window, if it cannot be 
> > preserved. Similarly, the last call wins.
> > 
> > Ideally in this situation I would implement both S_CROP and S_FMT and let 
> > both change the opposite window as needed, which in this case means set it 
> > equal to the one, being configured. Since most applications are primarily 
> > interested in the S_FMT call to configure their user interface, I find it 
> > a wrong approach to refuse S_FMT and always return the current cropping 
> > rectangle. In such a case the application will possibly be stuck with some 
> > default output rectangle, because it certainly will _not_ guess to use 
> > S_CROP to configure it. Whereas if we implement S_FMT with a constant 1:1 
> > scale the application will get the required UI size. I agree, that 
> > changing the view area, while changing the output window, is not exactly 
> > what the user expects, but it's better than presenting all applications 
> > with a fixed, possibly completely unsuitable, UI window.
> 
> The problem with S_FMT changing the crop rectangle (and I assume we are not
> talking about small pixel tweaks to make the hardware happy) is that the
> crop operation actually removes part of the frame. That's not something you
> would expect S_FMT to do, ever. Such an operation has to be explicitly
> requested by the user.
> 
> It's also why properly written applications (e.g. capture-example.c) has
> code like this to reset the crop rectangle before starting streaming:
> 
>         if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
>                 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>                 crop.c = cropcap.defrect; /* reset to default */
> 
>                 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
>                         switch (errno) {
>                         case EINVAL:
>                                 /* Cropping not supported. */
>                                 break;
>                         default:
>                                 /* Errors ignored. */
>                                 break;
>                         }
>                 }
>         }
> 
> (Hmm, capture-example.c should also test for ENOTTY since we changed the
> error code).

I agree, that preserving input rectangle == output rectangle in reply to 
S_FMT is not nice, and should be avoided, wherever possible. Still, I 
prefer this to sticking with just one fixed output geometry, especially 
since (1) the spec doesn't prohibit this behaviour, (2) there are already 
precedents in the mainline.

Maybe, a bit of hardware background would help: the sensor is actually 
supposed to be able to both crop and scale, and we did try to implement 
scales other than 1:1, but the chip just refused to produce anything 
meaningful.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hans Verkuil Aug. 30, 2011, 2:36 p.m. UTC | #16
On Tuesday, August 30, 2011 16:24:55 Guennadi Liakhovetski wrote:
> Hi Hans
> 
> On Tue, 30 Aug 2011, Hans Verkuil wrote:
> 
> > On Tuesday, August 30, 2011 15:13:25 Guennadi Liakhovetski wrote:
> > > (also replying to a similar comment by Sakari)
> > > 
> > > On Tue, 30 Aug 2011, Laurent Pinchart wrote:
> > > 
> > > > Hi Guennadi,
> > > > 
> > > > On Tuesday 30 August 2011 10:55:08 Guennadi Liakhovetski wrote:
> > > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > > On Monday 29 August 2011 14:34:53 Guennadi Liakhovetski wrote:
> > > > > > > On Mon, 29 Aug 2011, Laurent Pinchart wrote:
> > > > > > > > On Monday 29 August 2011 14:18:50 Guennadi Liakhovetski wrote:
> > > > > > > > > On Sun, 28 Aug 2011, Laurent Pinchart wrote:
> > > > > > > > > 
> > > > > > > > > [snip]
> > > > > > > > > 
> > > > > > > > > > > @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct
> > > > > > > > > > > v4l2_subdev *sd,
> > > > > > > > > > > 
> > > > > > > > > > >  	ov5642_try_fmt(sd, mf);
> > > > > > > > > > > 
> > > > > > > > > > > +	priv->out_size.width		= mf->width;
> > > > > > > > > > > +	priv->out_size.height		= mf->height;
> > > > > > > > > > 
> > > > > > > > > > It looks like to me (but I may be wrong) that you achieve
> > > > > > > > > > different resolutions using cropping, not scaling. If 
that's
> > > > > > > > > > correct you should implement s_crop support and refuse 
> > changing
> > > > > > > > > > the resolution through s_fmt.
> > > > > > > > > 
> > > > > > > > > As the patch explains (I think) on several occasions, 
currently
> > > > > > > > > only the 1:1 scale is supported, and it was our deliberate 
> > choice
> > > > > > > > > to implement this using the scaling API
> > > > > > > > 
> > > > > > > > If you implement cropping, you should use the crop API, not 
the
> > > > > > > > scaling API
> > > > > > > > 
> > > > > > > > :-)
> > > > > > > 
> > > > > > > It's changing both - input and output sizes.
> > > > > > 
> > > > > > Sure, but it's still cropping.
> > > > > 
> > > > > Why? Isn't it a matter of the PoV?
> > > > 
> > > > No it isn't. Cropping is cropping, regardless of how you look at it.
> > > > 
> > > > > It changes the output window, i.e., implements S_FMT. And S_FMT is 
by 
> > far
> > > > > more important / widely used than S_CROP. Refusing to change the 
output
> > > > > window and always just returning the == crop size wouldn't be 
polite, 
> > IMHO.
> > > > 
> > > > If your sensor has no scaler the output size is equal to the crop 
> > rectangle. 
> > > > There's no way around that, and there's no reason to have the driver 
> > behave 
> > > > otherwise.
> > > > 
> > > > > Don't think many users would guess to use S_CROP.
> > > > 
> > > > Users who want to crop use S_CROP.
> > > > 
> > > > > Standard applications a la mplayer don't use S_CROP at all.
> > > > 
> > > > That's because they don't want to crop. mplayer expects the driver to 
> > perform 
> > > > scaling when it calls S_FMT, and users won't be happy if you crop 
instead.
> > > 
> > > So, here's my opinion, based on the V4L2 spec. I'm going to base on this 
> > > and pull this patch into my tree and let Mauro decide, unless he 
expresses 
> > > his negative opinion before that.
> > > 
> > > The spec defines S_FMT as an operation to set the output (in case of a 
> > > capture device) frame format. Which this driver clearly does. The output 
> > > format should be set, using scaling, however, if the driver or the 
> > > hardware are unable to preserve the exact same input rectangle to 
satisfy 
> > > the request, the driver is also allowed to change the cropping rectangle 
> > > _as much as necessary_ - S_FMT takes precedence. This has been discussed 
> > > before, and the conclusion was - of the two geometry calls (S_FMT and 
> > > S_CROP) the last call overrides previous setting of the opposite 
geometry.
> > > 
> > > It also defines S_CROP as an operation to set the cropping rectangle. 
The 
> > > driver is also allowed to change the output window, if it cannot be 
> > > preserved. Similarly, the last call wins.
> > > 
> > > Ideally in this situation I would implement both S_CROP and S_FMT and 
let 
> > > both change the opposite window as needed, which in this case means set 
it 
> > > equal to the one, being configured. Since most applications are 
primarily 
> > > interested in the S_FMT call to configure their user interface, I find 
it 
> > > a wrong approach to refuse S_FMT and always return the current cropping 
> > > rectangle. In such a case the application will possibly be stuck with 
some 
> > > default output rectangle, because it certainly will _not_ guess to use 
> > > S_CROP to configure it. Whereas if we implement S_FMT with a constant 
1:1 
> > > scale the application will get the required UI size. I agree, that 
> > > changing the view area, while changing the output window, is not exactly 
> > > what the user expects, but it's better than presenting all applications 
> > > with a fixed, possibly completely unsuitable, UI window.
> > 
> > The problem with S_FMT changing the crop rectangle (and I assume we are 
not
> > talking about small pixel tweaks to make the hardware happy) is that the
> > crop operation actually removes part of the frame. That's not something 
you
> > would expect S_FMT to do, ever. Such an operation has to be explicitly
> > requested by the user.
> > 
> > It's also why properly written applications (e.g. capture-example.c) has
> > code like this to reset the crop rectangle before starting streaming:
> > 
> >         if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
> >                 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> >                 crop.c = cropcap.defrect; /* reset to default */
> > 
> >                 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
> >                         switch (errno) {
> >                         case EINVAL:
> >                                 /* Cropping not supported. */
> >                                 break;
> >                         default:
> >                                 /* Errors ignored. */
> >                                 break;
> >                         }
> >                 }
> >         }
> > 
> > (Hmm, capture-example.c should also test for ENOTTY since we changed the
> > error code).
> 
> I agree, that preserving input rectangle == output rectangle in reply to 
> S_FMT is not nice, and should be avoided, wherever possible. Still, I 
> prefer this to sticking with just one fixed output geometry, especially 
> since (1) the spec doesn't prohibit this behaviour,

Hmm, I think it should be prohibited. Few drivers actually implement crop,
and fewer applications use it. So I'm not surprised the spec doesn't go into 
much detail.

> (2) there are already 
> precedents in the mainline.

Which precedents? My guess is that any driver that does this was either not
(or poorly) reviewed, or everyone just missed it.

> Maybe, a bit of hardware background would help: the sensor is actually 
> supposed to be able to both crop and scale, and we did try to implement 
> scales other than 1:1, but the chip just refused to produce anything 
> meaningful.

I still don't see any reason why S_FMT would suddenly crop on such a sensor.
It's completely unexpected and the user does not get what he expects.

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski Aug. 30, 2011, 2:57 p.m. UTC | #17
On Tue, 30 Aug 2011, Hans Verkuil wrote:

> On Tuesday, August 30, 2011 16:24:55 Guennadi Liakhovetski wrote:
> > Hi Hans
> > 
> > On Tue, 30 Aug 2011, Hans Verkuil wrote:

[snip]

> > > The problem with S_FMT changing the crop rectangle (and I assume we are not
> > > talking about small pixel tweaks to make the hardware happy) is that the
> > > crop operation actually removes part of the frame. That's not something you
> > > would expect S_FMT to do, ever. Such an operation has to be explicitly
> > > requested by the user.
> > > 
> > > It's also why properly written applications (e.g. capture-example.c) has
> > > code like this to reset the crop rectangle before starting streaming:
> > > 
> > >         if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
> > >                 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> > >                 crop.c = cropcap.defrect; /* reset to default */
> > > 
> > >                 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
> > >                         switch (errno) {
> > >                         case EINVAL:
> > >                                 /* Cropping not supported. */
> > >                                 break;
> > >                         default:
> > >                                 /* Errors ignored. */
> > >                                 break;
> > >                         }
> > >                 }
> > >         }
> > > 
> > > (Hmm, capture-example.c should also test for ENOTTY since we changed the
> > > error code).
> > 
> > I agree, that preserving input rectangle == output rectangle in reply to 
> > S_FMT is not nice, and should be avoided, wherever possible. Still, I 
> > prefer this to sticking with just one fixed output geometry, especially 
> > since (1) the spec doesn't prohibit this behaviour,
> 
> Hmm, I think it should be prohibited. Few drivers actually implement crop,
> and fewer applications use it. So I'm not surprised the spec doesn't go into 
> much detail.
> 
> > (2) there are already 
> > precedents in the mainline.
> 
> Which precedents? My guess is that any driver that does this was either not
> (or poorly) reviewed, or everyone just missed it.

My first two sensor drivers mt9m001 and mt9v022 do this, but, I suspect, I 
didn't invent it at that time, I think, I copied it from somewhere, cannot 
say for sure though anymore.

> > Maybe, a bit of hardware background would help: the sensor is actually 
> > supposed to be able to both crop and scale, and we did try to implement 
> > scales other than 1:1, but the chip just refused to produce anything 
> > meaningful.
> 
> I still don't see any reason why S_FMT would suddenly crop on such a sensor.
> It's completely unexpected and the user does not get what he expects.

Good, let's make it simple for all (except Bastian) then: Bastian, sorry 
for having misguided you, please, switch to .s_crop().

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bastian Hecht Aug. 30, 2011, 3:28 p.m. UTC | #18
2011/8/30 Guennadi Liakhovetski <g.liakhovetski@gmx.de>:
> On Tue, 30 Aug 2011, Hans Verkuil wrote:
>
>> On Tuesday, August 30, 2011 16:24:55 Guennadi Liakhovetski wrote:
>> > Hi Hans
>> >
>> > On Tue, 30 Aug 2011, Hans Verkuil wrote:
>
> [snip]
>
>> > > The problem with S_FMT changing the crop rectangle (and I assume we are not
>> > > talking about small pixel tweaks to make the hardware happy) is that the
>> > > crop operation actually removes part of the frame. That's not something you
>> > > would expect S_FMT to do, ever. Such an operation has to be explicitly
>> > > requested by the user.
>> > >
>> > > It's also why properly written applications (e.g. capture-example.c) has
>> > > code like this to reset the crop rectangle before starting streaming:
>> > >
>> > >         if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
>> > >                 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> > >                 crop.c = cropcap.defrect; /* reset to default */
>> > >
>> > >                 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
>> > >                         switch (errno) {
>> > >                         case EINVAL:
>> > >                                 /* Cropping not supported. */
>> > >                                 break;
>> > >                         default:
>> > >                                 /* Errors ignored. */
>> > >                                 break;
>> > >                         }
>> > >                 }
>> > >         }
>> > >
>> > > (Hmm, capture-example.c should also test for ENOTTY since we changed the
>> > > error code).
>> >
>> > I agree, that preserving input rectangle == output rectangle in reply to
>> > S_FMT is not nice, and should be avoided, wherever possible. Still, I
>> > prefer this to sticking with just one fixed output geometry, especially
>> > since (1) the spec doesn't prohibit this behaviour,
>>
>> Hmm, I think it should be prohibited. Few drivers actually implement crop,
>> and fewer applications use it. So I'm not surprised the spec doesn't go into
>> much detail.
>>
>> > (2) there are already
>> > precedents in the mainline.
>>
>> Which precedents? My guess is that any driver that does this was either not
>> (or poorly) reviewed, or everyone just missed it.
>
> My first two sensor drivers mt9m001 and mt9v022 do this, but, I suspect, I
> didn't invent it at that time, I think, I copied it from somewhere, cannot
> say for sure though anymore.
>
>> > Maybe, a bit of hardware background would help: the sensor is actually
>> > supposed to be able to both crop and scale, and we did try to implement
>> > scales other than 1:1, but the chip just refused to produce anything
>> > meaningful.
>>
>> I still don't see any reason why S_FMT would suddenly crop on such a sensor.
>> It's completely unexpected and the user does not get what he expects.
>
> Good, let's make it simple for all (except Bastian) then: Bastian, sorry
> for having misguided you, please, switch to .s_crop().

Sure, no problem. So s_fmt() shall be not available at all then,
right? Instead the cropping rectangle can be changed and the output
rectangle is adjusted accordingly.

best regards,

 Bastian

> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> http://www.open-technology.de/
>
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski Aug. 30, 2011, 3:34 p.m. UTC | #19
On Tue, 30 Aug 2011, Bastian Hecht wrote:

> 2011/8/30 Guennadi Liakhovetski <g.liakhovetski@gmx.de>:
> > On Tue, 30 Aug 2011, Hans Verkuil wrote:
> >
> >> On Tuesday, August 30, 2011 16:24:55 Guennadi Liakhovetski wrote:
> >> > Hi Hans
> >> >
> >> > On Tue, 30 Aug 2011, Hans Verkuil wrote:
> >
> > [snip]
> >
> >> > > The problem with S_FMT changing the crop rectangle (and I assume we are not
> >> > > talking about small pixel tweaks to make the hardware happy) is that the
> >> > > crop operation actually removes part of the frame. That's not something you
> >> > > would expect S_FMT to do, ever. Such an operation has to be explicitly
> >> > > requested by the user.
> >> > >
> >> > > It's also why properly written applications (e.g. capture-example.c) has
> >> > > code like this to reset the crop rectangle before starting streaming:
> >> > >
> >> > >         if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
> >> > >                 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> >> > >                 crop.c = cropcap.defrect; /* reset to default */
> >> > >
> >> > >                 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
> >> > >                         switch (errno) {
> >> > >                         case EINVAL:
> >> > >                                 /* Cropping not supported. */
> >> > >                                 break;
> >> > >                         default:
> >> > >                                 /* Errors ignored. */
> >> > >                                 break;
> >> > >                         }
> >> > >                 }
> >> > >         }
> >> > >
> >> > > (Hmm, capture-example.c should also test for ENOTTY since we changed the
> >> > > error code).
> >> >
> >> > I agree, that preserving input rectangle == output rectangle in reply to
> >> > S_FMT is not nice, and should be avoided, wherever possible. Still, I
> >> > prefer this to sticking with just one fixed output geometry, especially
> >> > since (1) the spec doesn't prohibit this behaviour,
> >>
> >> Hmm, I think it should be prohibited. Few drivers actually implement crop,
> >> and fewer applications use it. So I'm not surprised the spec doesn't go into
> >> much detail.
> >>
> >> > (2) there are already
> >> > precedents in the mainline.
> >>
> >> Which precedents? My guess is that any driver that does this was either not
> >> (or poorly) reviewed, or everyone just missed it.
> >
> > My first two sensor drivers mt9m001 and mt9v022 do this, but, I suspect, I
> > didn't invent it at that time, I think, I copied it from somewhere, cannot
> > say for sure though anymore.
> >
> >> > Maybe, a bit of hardware background would help: the sensor is actually
> >> > supposed to be able to both crop and scale, and we did try to implement
> >> > scales other than 1:1, but the chip just refused to produce anything
> >> > meaningful.
> >>
> >> I still don't see any reason why S_FMT would suddenly crop on such a sensor.
> >> It's completely unexpected and the user does not get what he expects.
> >
> > Good, let's make it simple for all (except Bastian) then: Bastian, sorry
> > for having misguided you, please, switch to .s_crop().
> 
> Sure, no problem. So s_fmt() shall be not available at all then,
> right? Instead the cropping rectangle can be changed and the output
> rectangle is adjusted accordingly.

I would keep .s_fmt() and just return the current configuration from it.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Laurent Pinchart Aug. 30, 2011, 3:43 p.m. UTC | #20
Hi Guennadi,

On Tuesday 30 August 2011 17:34:05 Guennadi Liakhovetski wrote:
> On Tue, 30 Aug 2011, Bastian Hecht wrote:
> > 2011/8/30 Guennadi Liakhovetski <g.liakhovetski@gmx.de>:
> > > On Tue, 30 Aug 2011, Hans Verkuil wrote:
> > >> On Tuesday, August 30, 2011 16:24:55 Guennadi Liakhovetski wrote:
> > >> > Hi Hans
> > > 
> > >> > On Tue, 30 Aug 2011, Hans Verkuil wrote:
> > > [snip]
> > > 
> > >> > > The problem with S_FMT changing the crop rectangle (and I assume
> > >> > > we are not talking about small pixel tweaks to make the hardware
> > >> > > happy) is that the crop operation actually removes part of the
> > >> > > frame. That's not something you would expect S_FMT to do, ever.
> > >> > > Such an operation has to be explicitly requested by the user.
> > >> > > 
> > >> > > It's also why properly written applications (e.g.
> > >> > > capture-example.c) has code like this to reset the crop rectangle
> > >> > > before starting streaming:
> > >> > > 
> > >> > >         if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
> > >> > >                 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> > >> > >                 crop.c = cropcap.defrect; /* reset to default */
> > >> > > 
> > >> > >                 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
> > >> > >                         switch (errno) {
> > >> > >                         case EINVAL:
> > >> > >                                 /* Cropping not supported. */
> > >> > >                                 break;
> > >> > >                         default:
> > >> > >                                 /* Errors ignored. */
> > >> > >                                 break;
> > >> > >                         }
> > >> > >                 }
> > >> > >         }
> > >> > > 
> > >> > > (Hmm, capture-example.c should also test for ENOTTY since we
> > >> > > changed the error code).
> > >> > 
> > >> > I agree, that preserving input rectangle == output rectangle in
> > >> > reply to S_FMT is not nice, and should be avoided, wherever
> > >> > possible. Still, I prefer this to sticking with just one fixed
> > >> > output geometry, especially since (1) the spec doesn't prohibit
> > >> > this behaviour,
> > >> 
> > >> Hmm, I think it should be prohibited. Few drivers actually implement
> > >> crop, and fewer applications use it. So I'm not surprised the spec
> > >> doesn't go into much detail.
> > >> 
> > >> > (2) there are already
> > >> > precedents in the mainline.
> > >> 
> > >> Which precedents? My guess is that any driver that does this was
> > >> either not (or poorly) reviewed, or everyone just missed it.
> > > 
> > > My first two sensor drivers mt9m001 and mt9v022 do this, but, I
> > > suspect, I didn't invent it at that time, I think, I copied it from
> > > somewhere, cannot say for sure though anymore.
> > > 
> > >> > Maybe, a bit of hardware background would help: the sensor is
> > >> > actually supposed to be able to both crop and scale, and we did try
> > >> > to implement scales other than 1:1, but the chip just refused to
> > >> > produce anything meaningful.
> > >> 
> > >> I still don't see any reason why S_FMT would suddenly crop on such a
> > >> sensor. It's completely unexpected and the user does not get what he
> > >> expects.
> > > 
> > > Good, let's make it simple for all (except Bastian) then: Bastian,
> > > sorry for having misguided you, please, switch to .s_crop().
> > 
> > Sure, no problem. So s_fmt() shall be not available at all then,
> > right? Instead the cropping rectangle can be changed and the output
> > rectangle is adjusted accordingly.
> 
> I would keep .s_fmt() and just return the current configuration from it.

That's what I would do as well. Having no .s_fmt() would be very confusing for 
applications and/or bridges.
Bastian Hecht Aug. 31, 2011, 3 p.m. UTC | #21
Hello Laurent,

2011/8/28 Laurent Pinchart <laurent.pinchart@ideasonboard.com>:
> Hi Bastian,
>
> Thanks for the patch.
>

[snip]

>>
>> +#define REG_RED_GAIN_HIGH            0x3400
>> +#define REG_RED_GAIN_LOW             0x3401
>> +#define REG_BLUE_GAIN_HIGH           0x3404
>> +#define REG_BLUE_GAIN_LOW            0x3405
>> +#define REG_AWB_MANUAL                       0x3406
>> +#define REG_EXP_HIGH                 0x3500
>> +#define REG_EXP_MIDDLE                       0x3501
>> +#define REG_EXP_LOW                  0x3502
>> +#define REG_EXP_GAIN_CTRL            0x3503
>> +#define REG_GAIN                     0x350b
>
> This belongs to the second patch.

Yes, I've changed it.

>> +#define REG_EXTEND_FRAME_TIME_HIGH   0x350c
>> +#define REG_EXTEND_FRAME_TIME_LOW    0x350d
>>  #define REG_WINDOW_START_X_HIGH              0x3800
>>  #define REG_WINDOW_START_X_LOW               0x3801
>>  #define REG_WINDOW_START_Y_HIGH              0x3802
>>  #define REG_WINDOW_START_Y_LOW               0x3803
>>  #define REG_WINDOW_WIDTH_HIGH                0x3804
>>  #define REG_WINDOW_WIDTH_LOW         0x3805
>> -#define REG_WINDOW_HEIGHT_HIGH               0x3806
>> +#define REG_WINDOW_HEIGHT_HIGH               0x3806
>>  #define REG_WINDOW_HEIGHT_LOW                0x3807
>>  #define REG_OUT_WIDTH_HIGH           0x3808
>>  #define REG_OUT_WIDTH_LOW            0x3809
>> @@ -44,19 +58,56 @@
>>  #define REG_OUT_TOTAL_WIDTH_LOW              0x380d
>>  #define REG_OUT_TOTAL_HEIGHT_HIGH    0x380e
>>  #define REG_OUT_TOTAL_HEIGHT_LOW     0x380f
>> +#define REG_FLIP_SUBSAMPLE           0x3818
>> +#define REG_OUTPUT_FORMAT            0x4300
>> +#define REG_ISP_CTRL_01                      0x5001
>> +#define REG_DIGITAL_EFFECTS          0x5580
>> +#define REG_HUE_COS                  0x5581
>> +#define REG_HUE_SIN                  0x5582
>> +#define REG_BLUE_SATURATION          0x5583
>> +#define REG_RED_SATURATION           0x5584
>> +#define REG_CONTRAST                 0x5588
>> +#define REG_BRIGHTNESS                       0x5589
>> +#define REG_D_E_AUXILLARY            0x558a
>> +#define REG_AVG_WINDOW_END_X_HIGH    0x5682
>> +#define REG_AVG_WINDOW_END_X_LOW     0x5683
>> +#define REG_AVG_WINDOW_END_Y_HIGH    0x5686
>> +#define REG_AVG_WINDOW_END_Y_LOW     0x5687
>
> So does this.

Changed as well.

>> +
>> +/* active pixel array size */
>> +#define OV5642_SENSOR_SIZE_X 2592
>> +#define OV5642_SENSOR_SIZE_Y 1944
>> +
>> +/* current maximum working size */
>> +#define OV5642_MAX_WIDTH     OV5642_SENSOR_SIZE_X
>> +#define OV5642_MAX_HEIGHT    720
>> +
>> +/* default sizes */
>> +#define OV5642_DEFAULT_WIDTH 1280
>> +#define OV5642_DEFAULT_HEIGHT        OV5642_MAX_HEIGHT
>> +
>> +/* minimum extra blanking */
>> +#define BLANKING_EXTRA_WIDTH         500
>> +#define BLANKING_EXTRA_HEIGHT                20
>>
>>  /*
>> - * define standard resolution.
>> - * Works currently only for up to 720 lines
>> - * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720
>> + * the sensor's autoexposure is buggy when setting total_height low.
>> + * It tries to expose longer than 1 frame period without taking care of it
>> + * and this leads to weird output. So we set 1000 lines as minimum.
>>   */
>>
>> -#define OV5642_WIDTH         1280
>> -#define OV5642_HEIGHT                720
>> -#define OV5642_TOTAL_WIDTH   3200
>> -#define OV5642_TOTAL_HEIGHT  2000
>> -#define OV5642_SENSOR_SIZE_X 2592
>> -#define OV5642_SENSOR_SIZE_Y 1944
>> +#define BLANKING_MIN_HEIGHT          1000
>> +
>> +/*
>> + * About OV5642 resolution, cropping and binning:
>> + * This sensor supports it all, at least in the feature description.
>> + * Unfortunately, no combination of appropriate registers settings could
>> make + * the chip work the intended way. As it works with predefined
>> register lists, + * some undocumented registers are presumably changed
>> there to achieve their + * goals.
>> + * This driver currently only works for resolutions up to 720 lines with a
>> + * 1:1 scale. Hopefully these restrictions will be removed in the future.
>> + */
>
> Can you please move this comment above the OV5642_MAX_WIDTH and
> OV5642_MAX_HEIGHT definitions ?

Ok, done.

>>  struct regval_list {
>>       u16 reg_num;
>> @@ -105,10 +156,8 @@ static struct regval_list ov5642_default_regs_init[] =
>> { { 0x471d, 0x5  },
>>       { 0x4708, 0x6  },
>>       { 0x370c, 0xa0 },
>> -     { 0x5687, 0x94 },
>
> Unless I'm mistaken, this register value is removed and isn't replaced by
> anything in this patch or the next one. Is that intentional ?

This was a cropping offset. It is done now dynamically.

>>       { 0x501f, 0x0  },
>>       { 0x5000, 0x4f },
>> -     { 0x5001, 0xcf },
>
> This one is replaced by 0xff. I'm not sure how that's related to this patch.
> Could you please check all modifications to the ov5642_default_regs_init[] and
> ov5642_default_regs_finalise[] arrays ? Some probably need to move to the next
> patch, and others don't seem to be related to any of the two patches.

There are 2 reasons why the registers are changed: 1st) values are
calculated dynamically now. 2nd) the register list contains
duplicates. It changes some registers multiple times with different
values each time. I tried to clean this up.
I've done it this way now: I left the original register list untouched
for this patch, as the modifications belong belong almost all to the
controls.

>>       { 0x4300, 0x30 },
>>       { 0x4300, 0x30 },
>>       { 0x460b, 0x35 },
>> @@ -121,11 +170,8 @@ static struct regval_list ov5642_default_regs_init[] =
>> { { 0x4402, 0x90 },
>>       { 0x460c, 0x22 },
>>       { 0x3815, 0x44 },
>> -     { 0x3503, 0x7  },
>>       { 0x3501, 0x73 },
>>       { 0x3502, 0x80 },
>> -     { 0x350b, 0x0  },
>> -     { 0x3818, 0xc8 },
>>       { 0x3824, 0x11 },
>>       { 0x3a00, 0x78 },
>>       { 0x3a1a, 0x4  },
>> @@ -140,12 +186,6 @@ static struct regval_list ov5642_default_regs_init[] =
>> { { 0x350d, 0xd0 },
>>       { 0x3a0d, 0x8  },
>>       { 0x3a0e, 0x6  },
>> -     { 0x3500, 0x0  },
>> -     { 0x3501, 0x0  },
>> -     { 0x3502, 0x0  },
>> -     { 0x350a, 0x0  },
>> -     { 0x350b, 0x0  },
>> -     { 0x3503, 0x0  },
>>       { 0x3a0f, 0x3c },
>>       { 0x3a10, 0x32 },
>>       { 0x3a1b, 0x3c },
>> @@ -298,7 +338,7 @@ static struct regval_list ov5642_default_regs_init[] =
>> { { 0x54b7, 0xdf },
>>       { 0x5402, 0x3f },
>>       { 0x5403, 0x0  },
>> -     { 0x3406, 0x0  },
>> +     { REG_AWB_MANUAL, 0x0  },
>>       { 0x5180, 0xff },
>>       { 0x5181, 0x52 },
>>       { 0x5182, 0x11 },
>> @@ -515,7 +555,6 @@ static struct regval_list ov5642_default_regs_init[] =
>> { { 0x5088, 0x0  },
>>       { 0x5089, 0x0  },
>>       { 0x302b, 0x0  },
>> -     { 0x3503, 0x7  },
>>       { 0x3011, 0x8  },
>>       { 0x350c, 0x2  },
>>       { 0x350d, 0xe4 },
>> @@ -526,7 +565,6 @@ static struct regval_list ov5642_default_regs_init[] =
>> {
>>
>>  static struct regval_list ov5642_default_regs_finalise[] = {
>>       { 0x3810, 0xc2 },
>> -     { 0x3818, 0xc9 },
>>       { 0x381c, 0x10 },
>>       { 0x381d, 0xa0 },
>>       { 0x381e, 0x5  },
>> @@ -541,23 +579,20 @@ static struct regval_list
>> ov5642_default_regs_finalise[] = { { 0x3a0d, 0x2  },
>>       { 0x3a0e, 0x1  },
>>       { 0x401c, 0x4  },
>> -     { 0x5682, 0x5  },
>> -     { 0x5683, 0x0  },
>> -     { 0x5686, 0x2  },
>> -     { 0x5687, 0xcc },
>> -     { 0x5001, 0x4f },
>> +     { REG_ISP_CTRL_01, 0xff },
>> +     { REG_DIGITAL_EFFECTS, 0x6 },
>>       { 0x589b, 0x6  },
>>       { 0x589a, 0xc5 },
>> -     { 0x3503, 0x0  },
>> +     { REG_EXP_GAIN_CTRL, 0x0  },
>>       { 0x460c, 0x20 },
>>       { 0x460b, 0x37 },
>>       { 0x471c, 0xd0 },
>>       { 0x471d, 0x5  },
>>       { 0x3815, 0x1  },
>> -     { 0x3818, 0xc1 },
>> +     { REG_FLIP_SUBSAMPLE, 0xc1 },
>>       { 0x501f, 0x0  },
>>       { 0x5002, 0xe0 },
>> -     { 0x4300, 0x32 }, /* UYVY */
>> +     { REG_OUTPUT_FORMAT, 0x32 },
>>       { 0x3002, 0x1c },
>>       { 0x4800, 0x14 },
>>       { 0x4801, 0xf  },
>> @@ -578,9 +613,20 @@ struct ov5642_datafmt {
>>       enum v4l2_colorspace            colorspace;
>>  };
>>
>> +/* the output resolution and blanking information */
>> +struct ov5642_out_size {
>> +     int width;
>> +     int height;
>> +     int total_width;
>> +     int total_height;
>> +};
>> +
>>  struct ov5642 {
>>       struct v4l2_subdev              subdev;
>> +
>>       const struct ov5642_datafmt     *fmt;
>> +     struct v4l2_rect                crop_rect;
>> +     struct ov5642_out_size          out_size;
>>  };
>>
>>  static const struct ov5642_datafmt ov5642_colour_fmts[] = {
>> @@ -593,8 +639,7 @@ static struct ov5642 *to_ov5642(const struct i2c_client
>> *client) }
>>
>>  /* Find a data format by a pixel code in an array */
>> -static const struct ov5642_datafmt
>> -                     *ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
>> +static const struct ov5642_datafmt *ov5642_find_datafmt(enum
>> v4l2_mbus_pixelcode code) {
>
> checkpatch.pl won't be happy.

Well, I broke it.

>>       int i;
>>
>> @@ -641,6 +686,26 @@ static int reg_write(struct i2c_client *client, u16
>> reg, u8 val)
>>
>>       return 0;
>>  }
>> +
>> +/*
>> + * convenience function to write 16 bit register values that are split up
>> + * into two consecutive high and low parts
>> + */
>> +static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
>> +{
>> +     int ret;
>> +     u8 val8;
>> +
>> +     val8 = val16 >> 8;
>> +     ret = reg_write(client, reg, val8);
>
> You can use val16 >> 8 directly as a function argument and get rid of the val8
> variable.

Ok, changed.

>> +     if (ret)
>> +             return ret;
>> +     val8 = val16 & 0x00ff;
>> +     ret = reg_write(client, reg + 1, val8);
>> +
>> +     return ret;
>
> return reg_write(...) should be fine.

Changed.

>> +}
>> +
>>  #ifdef CONFIG_VIDEO_ADV_DEBUG
>>  static int ov5642_get_register(struct v4l2_subdev *sd, struct
>> v4l2_dbg_register *reg) {
>> @@ -684,68 +749,72 @@ static int ov5642_write_array(struct i2c_client
>> *client, return 0;
>>  }
>>
>> -static int ov5642_set_resolution(struct i2c_client *client)
>> +static int ov5642_set_resolution(struct v4l2_subdev *sd)
>>  {
>> +     struct i2c_client *client = v4l2_get_subdevdata(sd);
>> +     struct ov5642 *priv = to_ov5642(client);
>> +     int width = priv->out_size.width;
>> +     int height = priv->out_size.height;
>> +     int total_width = priv->out_size.total_width;
>> +     int total_height = priv->out_size.total_height;
>> +     int start_x = (OV5642_SENSOR_SIZE_X - width) / 2;
>> +     int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2;
>>       int ret;
>> -     u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8;
>> -     u8 start_x_low  = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff;
>> -     u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8;
>> -     u8 start_y_low  = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff;
>> -
>> -     u8 width_high   = OV5642_WIDTH  >> 8;
>> -     u8 width_low    = OV5642_WIDTH  & 0xff;
>> -     u8 height_high  = OV5642_HEIGHT >> 8;
>> -     u8 height_low   = OV5642_HEIGHT & 0xff;
>> -
>> -     u8 total_width_high  = OV5642_TOTAL_WIDTH  >> 8;
>> -     u8 total_width_low   = OV5642_TOTAL_WIDTH  & 0xff;
>> -     u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8;
>> -     u8 total_height_low  = OV5642_TOTAL_HEIGHT & 0xff;
>> -
>> -     ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high);
>> -     if (!ret)
>> -             ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low);
>> -     if (!ret)
>> -             ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high);
>> -     if (!ret)
>> -             ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low);
>>
>> +     /* This should set the starting point for cropping. Doesn't work so far.
>> */ +  ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x);
>>       if (!ret)
>> -             ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high);
>> -     if (!ret)
>> -             ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low);
>> +             ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y);
>> +     if (!ret) {
>> +             priv->crop_rect.left = start_x;
>> +             priv->crop_rect.top = start_y;
>> +     }
>> +
>>       if (!ret)
>> -             ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high);
>> +             ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width);
>>       if (!ret)
>> -             ret = reg_write(client, REG_WINDOW_HEIGHT_LOW,  height_low);
>> +             ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height);
>> +     if (ret)
>> +             return ret;
>> +     priv->crop_rect.width = width;
>> +     priv->crop_rect.height = height;
>>
>> +     /* Set the output window size. Only 1:1 scale is supported so far. */
>> +     ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width);
>>       if (!ret)
>> -             ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high);
>> -     if (!ret)
>> -             ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low);
>> +             ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height);
>> +
>> +     /* Total width = output size + blanking */
>>       if (!ret)
>> -             ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high);
>> +             ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width);
>>       if (!ret)
>> -             ret = reg_write(client, REG_OUT_HEIGHT_LOW,  height_low);
>> +             ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height);
>>
>> +     /* set the maximum integration time */
>>       if (!ret)
>> -             ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high);
>> -     if (!ret)
>> -             ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low);
>> +             ret = reg_write16(client, REG_EXTEND_FRAME_TIME_HIGH,
>> +                                                             total_height);
>> +
>> +     /* Sets the window for AWB calculations */
>>       if (!ret)
>> -             ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high);
>> +             ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width);
>>       if (!ret)
>> -             ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW,  total_height_low);
>> +             ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height);
>>
>>       return ret;
>>  }
>>
>> -static int ov5642_try_fmt(struct v4l2_subdev *sd,
>> -                       struct v4l2_mbus_framefmt *mf)
>> +static int ov5642_try_fmt(struct v4l2_subdev *sd, struct
>> v4l2_mbus_framefmt *mf) {
>> -     const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
>> +     const struct ov5642_datafmt *fmt   = ov5642_find_datafmt(mf->code);
>>
>> -     dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n",
>> +     dev_dbg(sd->v4l2_dev->dev, "%s(%u) request width: %u heigth: %u\n",
>> +                     __func__, mf->code, mf->width, mf->height);
>> +
>> +     v4l_bound_align_image(&mf->width, 48, OV5642_MAX_WIDTH, 1,
>> +                           &mf->height, 32, OV5642_MAX_HEIGHT, 1, 0);
>> +
>> +     dev_dbg(sd->v4l2_dev->dev, "%s(%u) return width: %u heigth: %u\n",
>>                       __func__, mf->code, mf->width, mf->height);
>>
>>       if (!fmt) {
>> @@ -753,20 +822,16 @@ static int ov5642_try_fmt(struct v4l2_subdev *sd,
>>               mf->colorspace  = ov5642_colour_fmts[0].colorspace;
>>       }
>>
>> -     mf->width       = OV5642_WIDTH;
>> -     mf->height      = OV5642_HEIGHT;
>>       mf->field       = V4L2_FIELD_NONE;
>>
>>       return 0;
>>  }
>>
>> -static int ov5642_s_fmt(struct v4l2_subdev *sd,
>> -                     struct v4l2_mbus_framefmt *mf)
>> +static int ov5642_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
>> *mf) {
>>       struct i2c_client *client = v4l2_get_subdevdata(sd);
>>       struct ov5642 *priv = to_ov5642(client);
>> -
>> -     dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
>> +     int ret;
>>
>>       /* MIPI CSI could have changed the format, double-check */
>>       if (!ov5642_find_datafmt(mf->code))
>> @@ -774,17 +839,27 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd,
>>
>>       ov5642_try_fmt(sd, mf);
>>
>> +     priv->out_size.width            = mf->width;
>> +     priv->out_size.height           = mf->height;
>
> It looks like to me (but I may be wrong) that you achieve different
> resolutions using cropping, not scaling. If that's correct you should
> implement s_crop support and refuse changing the resolution through s_fmt.

Well we had that discussion :-)
Now it is handled by s_crop and s_fmt just returns the current settings.

>> +     priv->out_size.total_width      = mf->width + BLANKING_EXTRA_WIDTH;
>> +     priv->out_size.total_height     = max_t(int, mf->height +
>> +                                                     BLANKING_EXTRA_HEIGHT,
>> +                                                     BLANKING_MIN_HEIGHT);
>
> As you only use those two values once, maybe you can compute them in
> ov5642_set_resolution() instead of storing them in the device data structure.

I agree in general. As I use it with the next patch, I wonder if this
cosmetic inaccuracy is tolerable.

>> +     priv->crop_rect.width           = mf->width;
>> +     priv->crop_rect.height          = mf->height;
>> +
>>       priv->fmt = ov5642_find_datafmt(mf->code);
>>
>> -     ov5642_write_array(client, ov5642_default_regs_init);
>> -     ov5642_set_resolution(client);
>> -     ov5642_write_array(client, ov5642_default_regs_finalise);
>> +     ret = ov5642_write_array(client, ov5642_default_regs_init);
>> +     if (!ret)
>> +             ret = ov5642_set_resolution(sd);
>> +     if (!ret)
>> +             ret = ov5642_write_array(client, ov5642_default_regs_finalise);
>>
>> -     return 0;
>> +     return ret;
>>  }
>>
>> -static int ov5642_g_fmt(struct v4l2_subdev *sd,
>> -                     struct v4l2_mbus_framefmt *mf)
>> +static int ov5642_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
>> *mf) {
>>       struct i2c_client *client = v4l2_get_subdevdata(sd);
>>       struct ov5642 *priv = to_ov5642(client);
>> @@ -793,10 +868,12 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd,
>>
>>       mf->code        = fmt->code;
>>       mf->colorspace  = fmt->colorspace;
>> -     mf->width       = OV5642_WIDTH;
>> -     mf->height      = OV5642_HEIGHT;
>> +     mf->width       = priv->out_size.width;
>> +     mf->height      = priv->out_size.height;
>>       mf->field       = V4L2_FIELD_NONE;
>>
>> +     dev_dbg(sd->v4l2_dev->dev, "%s return width: %u heigth: %u\n", __func__,
>> +                     mf->width, mf->height);
>
> Isn't that a bit too verbose ? Printing the format in a debug message in the
> s_fmt handler is useful, but maybe doing it in g_fmt is a bit too much.

Removed.

>>       return 0;
>>  }
>>
>> @@ -829,14 +906,17 @@ static int ov5642_g_chip_ident(struct v4l2_subdev
>> *sd,
>>
>>  static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
>>  {
>> +     struct i2c_client *client = v4l2_get_subdevdata(sd);
>> +     struct ov5642 *priv = to_ov5642(client);
>>       struct v4l2_rect *rect = &a->c;
>> -
>>       a->type         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> -     rect->top       = 0;
>> -     rect->left      = 0;
>> -     rect->width     = OV5642_WIDTH;
>> -     rect->height    = OV5642_HEIGHT;
>> +     rect->top       = priv->crop_rect.top;
>> +     rect->left      = priv->crop_rect.left;
>> +     rect->width     = priv->crop_rect.width;
>> +     rect->height    = priv->crop_rect.height;
>
> rect = priv->crop_rect;
>
> should do.

Changed.

>>
>> +     dev_dbg(sd->v4l2_dev->dev, "%s crop width: %u heigth: %u\n", __func__,
>> +                     rect->width, rect->height);
>
> Same comment as for g_fmt.

Removed as well.

>>       return 0;
>>  }
>>
>> @@ -844,8 +924,8 @@ static int ov5642_cropcap(struct v4l2_subdev *sd,
>> struct v4l2_cropcap *a) {
>>       a->bounds.left                  = 0;
>>       a->bounds.top                   = 0;
>> -     a->bounds.width                 = OV5642_WIDTH;
>> -     a->bounds.height                = OV5642_HEIGHT;
>> +     a->bounds.width                 = OV5642_MAX_WIDTH;
>> +     a->bounds.height                = OV5642_MAX_HEIGHT;
>>       a->defrect                      = a->bounds;
>>       a->type                         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>>       a->pixelaspect.numerator        = 1;
>> @@ -858,9 +938,8 @@ static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
>>                               struct v4l2_mbus_config *cfg)
>>  {
>>       cfg->type = V4L2_MBUS_CSI2;
>> -     cfg->flags = V4L2_MBUS_CSI2_2_LANE |
>> -             V4L2_MBUS_CSI2_CHANNEL_0 |
>> -             V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
>> +     cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
>> +                                     V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
>>
>>       return 0;
>>  }
>> @@ -941,8 +1020,15 @@ static int ov5642_probe(struct i2c_client *client,
>>
>>       v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
>>
>> -     icd->ops        = NULL;
>> -     priv->fmt       = &ov5642_colour_fmts[0];
>> +     icd->ops                = NULL;
>> +     priv->fmt               = &ov5642_colour_fmts[0];
>> +
>> +     priv->crop_rect.width   = OV5642_DEFAULT_WIDTH;
>> +     priv->crop_rect.height  = OV5642_DEFAULT_HEIGHT;
>> +     priv->crop_rect.left    = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
>> +     priv->crop_rect.top     = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
>> +     priv->out_size.width    = OV5642_DEFAULT_WIDTH;
>> +     priv->out_size.height   = OV5642_DEFAULT_HEIGHT;
>>
>>       ret = ov5642_video_probe(icd, client);
>>       if (ret < 0)
>> @@ -951,6 +1037,7 @@ static int ov5642_probe(struct i2c_client *client,
>>       return 0;
>>
>>  error:
>> +     icd->ops = NULL;
>>       kfree(priv);
>>       return ret;
>>  }
>> @@ -961,6 +1048,7 @@ static int ov5642_remove(struct i2c_client *client)
>>       struct soc_camera_device *icd = client->dev.platform_data;
>>       struct soc_camera_link *icl = to_soc_camera_link(icd);
>>
>> +     icd->ops = NULL;
>>       if (icl->free_bus)
>>               icl->free_bus(icl);
>>       kfree(priv);
>
> --
> Regards,
>
> Laurent Pinchart
>

Thanks for the review,

 Bastian
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
index 6410bda..1b40d90 100644
--- a/drivers/media/video/ov5642.c
+++ b/drivers/media/video/ov5642.c
@@ -14,8 +14,10 @@ 
  * published by the Free Software Foundation.
  */
 
+#include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
@@ -28,13 +30,25 @@ 
 #define REG_CHIP_ID_HIGH		0x300a
 #define REG_CHIP_ID_LOW			0x300b
 
+#define REG_RED_GAIN_HIGH		0x3400
+#define REG_RED_GAIN_LOW		0x3401
+#define REG_BLUE_GAIN_HIGH		0x3404
+#define REG_BLUE_GAIN_LOW		0x3405
+#define REG_AWB_MANUAL			0x3406
+#define REG_EXP_HIGH			0x3500
+#define REG_EXP_MIDDLE			0x3501
+#define REG_EXP_LOW			0x3502
+#define REG_EXP_GAIN_CTRL		0x3503
+#define REG_GAIN			0x350b
+#define REG_EXTEND_FRAME_TIME_HIGH	0x350c
+#define REG_EXTEND_FRAME_TIME_LOW	0x350d
 #define REG_WINDOW_START_X_HIGH		0x3800
 #define REG_WINDOW_START_X_LOW		0x3801
 #define REG_WINDOW_START_Y_HIGH		0x3802
 #define REG_WINDOW_START_Y_LOW		0x3803
 #define REG_WINDOW_WIDTH_HIGH		0x3804
 #define REG_WINDOW_WIDTH_LOW		0x3805
-#define REG_WINDOW_HEIGHT_HIGH 		0x3806
+#define REG_WINDOW_HEIGHT_HIGH		0x3806
 #define REG_WINDOW_HEIGHT_LOW		0x3807
 #define REG_OUT_WIDTH_HIGH		0x3808
 #define REG_OUT_WIDTH_LOW		0x3809
@@ -44,19 +58,56 @@ 
 #define REG_OUT_TOTAL_WIDTH_LOW		0x380d
 #define REG_OUT_TOTAL_HEIGHT_HIGH	0x380e
 #define REG_OUT_TOTAL_HEIGHT_LOW	0x380f
+#define REG_FLIP_SUBSAMPLE		0x3818
+#define REG_OUTPUT_FORMAT		0x4300
+#define REG_ISP_CTRL_01			0x5001
+#define REG_DIGITAL_EFFECTS		0x5580
+#define REG_HUE_COS			0x5581
+#define REG_HUE_SIN			0x5582
+#define REG_BLUE_SATURATION		0x5583
+#define REG_RED_SATURATION		0x5584
+#define REG_CONTRAST			0x5588
+#define REG_BRIGHTNESS			0x5589
+#define REG_D_E_AUXILLARY		0x558a
+#define REG_AVG_WINDOW_END_X_HIGH	0x5682
+#define REG_AVG_WINDOW_END_X_LOW	0x5683
+#define REG_AVG_WINDOW_END_Y_HIGH	0x5686
+#define REG_AVG_WINDOW_END_Y_LOW	0x5687
+
+/* active pixel array size */
+#define OV5642_SENSOR_SIZE_X	2592
+#define OV5642_SENSOR_SIZE_Y	1944
+
+/* current maximum working size */
+#define OV5642_MAX_WIDTH	OV5642_SENSOR_SIZE_X
+#define OV5642_MAX_HEIGHT	720
+
+/* default sizes */
+#define OV5642_DEFAULT_WIDTH	1280
+#define OV5642_DEFAULT_HEIGHT	OV5642_MAX_HEIGHT
+
+/* minimum extra blanking */
+#define BLANKING_EXTRA_WIDTH		500
+#define BLANKING_EXTRA_HEIGHT		20
 
 /*
- * define standard resolution.
- * Works currently only for up to 720 lines
- * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720
+ * the sensor's autoexposure is buggy when setting total_height low.
+ * It tries to expose longer than 1 frame period without taking care of it
+ * and this leads to weird output. So we set 1000 lines as minimum.
  */
 
-#define OV5642_WIDTH		1280
-#define OV5642_HEIGHT		720
-#define OV5642_TOTAL_WIDTH	3200
-#define OV5642_TOTAL_HEIGHT	2000
-#define OV5642_SENSOR_SIZE_X	2592
-#define OV5642_SENSOR_SIZE_Y	1944
+#define BLANKING_MIN_HEIGHT		1000
+
+/*
+ * About OV5642 resolution, cropping and binning:
+ * This sensor supports it all, at least in the feature description.
+ * Unfortunately, no combination of appropriate registers settings could make
+ * the chip work the intended way. As it works with predefined register lists,
+ * some undocumented registers are presumably changed there to achieve their
+ * goals.
+ * This driver currently only works for resolutions up to 720 lines with a
+ * 1:1 scale. Hopefully these restrictions will be removed in the future.
+ */
 
 struct regval_list {
 	u16 reg_num;
@@ -105,10 +156,8 @@  static struct regval_list ov5642_default_regs_init[] = {
 	{ 0x471d, 0x5  },
 	{ 0x4708, 0x6  },
 	{ 0x370c, 0xa0 },
-	{ 0x5687, 0x94 },
 	{ 0x501f, 0x0  },
 	{ 0x5000, 0x4f },
-	{ 0x5001, 0xcf },
 	{ 0x4300, 0x30 },
 	{ 0x4300, 0x30 },
 	{ 0x460b, 0x35 },
@@ -121,11 +170,8 @@  static struct regval_list ov5642_default_regs_init[] = {
 	{ 0x4402, 0x90 },
 	{ 0x460c, 0x22 },
 	{ 0x3815, 0x44 },
-	{ 0x3503, 0x7  },
 	{ 0x3501, 0x73 },
 	{ 0x3502, 0x80 },
-	{ 0x350b, 0x0  },
-	{ 0x3818, 0xc8 },
 	{ 0x3824, 0x11 },
 	{ 0x3a00, 0x78 },
 	{ 0x3a1a, 0x4  },
@@ -140,12 +186,6 @@  static struct regval_list ov5642_default_regs_init[] = {
 	{ 0x350d, 0xd0 },
 	{ 0x3a0d, 0x8  },
 	{ 0x3a0e, 0x6  },
-	{ 0x3500, 0x0  },
-	{ 0x3501, 0x0  },
-	{ 0x3502, 0x0  },
-	{ 0x350a, 0x0  },
-	{ 0x350b, 0x0  },
-	{ 0x3503, 0x0  },
 	{ 0x3a0f, 0x3c },
 	{ 0x3a10, 0x32 },
 	{ 0x3a1b, 0x3c },
@@ -298,7 +338,7 @@  static struct regval_list ov5642_default_regs_init[] = {
 	{ 0x54b7, 0xdf },
 	{ 0x5402, 0x3f },
 	{ 0x5403, 0x0  },
-	{ 0x3406, 0x0  },
+	{ REG_AWB_MANUAL, 0x0  },
 	{ 0x5180, 0xff },
 	{ 0x5181, 0x52 },
 	{ 0x5182, 0x11 },
@@ -515,7 +555,6 @@  static struct regval_list ov5642_default_regs_init[] = {
 	{ 0x5088, 0x0  },
 	{ 0x5089, 0x0  },
 	{ 0x302b, 0x0  },
-	{ 0x3503, 0x7  },
 	{ 0x3011, 0x8  },
 	{ 0x350c, 0x2  },
 	{ 0x350d, 0xe4 },
@@ -526,7 +565,6 @@  static struct regval_list ov5642_default_regs_init[] = {
 
 static struct regval_list ov5642_default_regs_finalise[] = {
 	{ 0x3810, 0xc2 },
-	{ 0x3818, 0xc9 },
 	{ 0x381c, 0x10 },
 	{ 0x381d, 0xa0 },
 	{ 0x381e, 0x5  },
@@ -541,23 +579,20 @@  static struct regval_list ov5642_default_regs_finalise[] = {
 	{ 0x3a0d, 0x2  },
 	{ 0x3a0e, 0x1  },
 	{ 0x401c, 0x4  },
-	{ 0x5682, 0x5  },
-	{ 0x5683, 0x0  },
-	{ 0x5686, 0x2  },
-	{ 0x5687, 0xcc },
-	{ 0x5001, 0x4f },
+	{ REG_ISP_CTRL_01, 0xff },
+	{ REG_DIGITAL_EFFECTS, 0x6 },
 	{ 0x589b, 0x6  },
 	{ 0x589a, 0xc5 },
-	{ 0x3503, 0x0  },
+	{ REG_EXP_GAIN_CTRL, 0x0  },
 	{ 0x460c, 0x20 },
 	{ 0x460b, 0x37 },
 	{ 0x471c, 0xd0 },
 	{ 0x471d, 0x5  },
 	{ 0x3815, 0x1  },
-	{ 0x3818, 0xc1 },
+	{ REG_FLIP_SUBSAMPLE, 0xc1 },
 	{ 0x501f, 0x0  },
 	{ 0x5002, 0xe0 },
-	{ 0x4300, 0x32 }, /* UYVY */
+	{ REG_OUTPUT_FORMAT, 0x32 },
 	{ 0x3002, 0x1c },
 	{ 0x4800, 0x14 },
 	{ 0x4801, 0xf  },
@@ -578,9 +613,20 @@  struct ov5642_datafmt {
 	enum v4l2_colorspace		colorspace;
 };
 
+/* the output resolution and blanking information */
+struct ov5642_out_size {
+	int width;
+	int height;
+	int total_width;
+	int total_height;
+};
+
 struct ov5642 {
 	struct v4l2_subdev		subdev;
+
 	const struct ov5642_datafmt	*fmt;
+	struct v4l2_rect                crop_rect;
+	struct ov5642_out_size		out_size;
 };
 
 static const struct ov5642_datafmt ov5642_colour_fmts[] = {
@@ -593,8 +639,7 @@  static struct ov5642 *to_ov5642(const struct i2c_client *client)
 }
 
 /* Find a data format by a pixel code in an array */
-static const struct ov5642_datafmt
-			*ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
+static const struct ov5642_datafmt *ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
 {
 	int i;
 
@@ -641,6 +686,26 @@  static int reg_write(struct i2c_client *client, u16 reg, u8 val)
 
 	return 0;
 }
+
+/*
+ * convenience function to write 16 bit register values that are split up
+ * into two consecutive high and low parts
+ */
+static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
+{
+	int ret;
+	u8 val8;
+
+	val8 = val16 >> 8;
+	ret = reg_write(client, reg, val8);
+	if (ret)
+		return ret;
+	val8 = val16 & 0x00ff;
+	ret = reg_write(client, reg + 1, val8);
+
+	return ret;
+}
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
@@ -684,68 +749,72 @@  static int ov5642_write_array(struct i2c_client *client,
 	return 0;
 }
 
-static int ov5642_set_resolution(struct i2c_client *client)
+static int ov5642_set_resolution(struct v4l2_subdev *sd)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5642 *priv = to_ov5642(client);
+	int width = priv->out_size.width;
+	int height = priv->out_size.height;
+	int total_width = priv->out_size.total_width;
+	int total_height = priv->out_size.total_height;
+	int start_x = (OV5642_SENSOR_SIZE_X - width) / 2;
+	int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2;
 	int ret;
-	u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8;
-	u8 start_x_low  = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff;
-	u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8;
-	u8 start_y_low  = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff;
-
-	u8 width_high	= OV5642_WIDTH  >> 8;
-	u8 width_low	= OV5642_WIDTH  & 0xff;
-	u8 height_high	= OV5642_HEIGHT >> 8;
-	u8 height_low	= OV5642_HEIGHT & 0xff;
-
-	u8 total_width_high  = OV5642_TOTAL_WIDTH  >> 8;
-	u8 total_width_low   = OV5642_TOTAL_WIDTH  & 0xff;
-	u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8;
-	u8 total_height_low  = OV5642_TOTAL_HEIGHT & 0xff;
-
-	ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high);
-	if (!ret)
-		ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low);
-	if (!ret)
-		ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high);
-	if (!ret)
-		ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low);
 
+	/* This should set the starting point for cropping. Doesn't work so far. */
+	ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x);
 	if (!ret)
-		ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high);
-	if (!ret)
-		ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low);
+		ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y);
+	if (!ret) {
+		priv->crop_rect.left = start_x;
+		priv->crop_rect.top = start_y;
+	}
+
 	if (!ret)
-		ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high);
+		ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width);
 	if (!ret)
-		ret = reg_write(client, REG_WINDOW_HEIGHT_LOW,  height_low);
+		ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height);
+	if (ret)
+		return ret;
+	priv->crop_rect.width = width;
+	priv->crop_rect.height = height;
 
+	/* Set the output window size. Only 1:1 scale is supported so far. */
+	ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width);
 	if (!ret)
-		ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high);
-	if (!ret)
-		ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low);
+		ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height);
+
+	/* Total width = output size + blanking */
 	if (!ret)
-		ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high);
+		ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width);
 	if (!ret)
-		ret = reg_write(client, REG_OUT_HEIGHT_LOW,  height_low);
+		ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height);
 
+	/* set the maximum integration time */
 	if (!ret)
-		ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high);
-	if (!ret)
-		ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low);
+		ret = reg_write16(client, REG_EXTEND_FRAME_TIME_HIGH,
+								total_height);
+
+	/* Sets the window for AWB calculations */
 	if (!ret)
-		ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high);
+		ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width);
 	if (!ret)
-		ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW,  total_height_low);
+		ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height);
 
 	return ret;
 }
 
-static int ov5642_try_fmt(struct v4l2_subdev *sd,
-			  struct v4l2_mbus_framefmt *mf)
+static int ov5642_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 {
-	const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
+	const struct ov5642_datafmt *fmt   = ov5642_find_datafmt(mf->code);
 
-	dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n",
+	dev_dbg(sd->v4l2_dev->dev, "%s(%u) request width: %u heigth: %u\n",
+			__func__, mf->code, mf->width, mf->height);
+
+	v4l_bound_align_image(&mf->width, 48, OV5642_MAX_WIDTH, 1,
+			      &mf->height, 32, OV5642_MAX_HEIGHT, 1, 0);
+
+	dev_dbg(sd->v4l2_dev->dev, "%s(%u) return width: %u heigth: %u\n",
 			__func__, mf->code, mf->width, mf->height);
 
 	if (!fmt) {
@@ -753,20 +822,16 @@  static int ov5642_try_fmt(struct v4l2_subdev *sd,
 		mf->colorspace	= ov5642_colour_fmts[0].colorspace;
 	}
 
-	mf->width	= OV5642_WIDTH;
-	mf->height	= OV5642_HEIGHT;
 	mf->field	= V4L2_FIELD_NONE;
 
 	return 0;
 }
 
-static int ov5642_s_fmt(struct v4l2_subdev *sd,
-			struct v4l2_mbus_framefmt *mf)
+static int ov5642_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov5642 *priv = to_ov5642(client);
-
-	dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+	int ret;
 
 	/* MIPI CSI could have changed the format, double-check */
 	if (!ov5642_find_datafmt(mf->code))
@@ -774,17 +839,27 @@  static int ov5642_s_fmt(struct v4l2_subdev *sd,
 
 	ov5642_try_fmt(sd, mf);
 
+	priv->out_size.width		= mf->width;
+	priv->out_size.height		= mf->height;
+	priv->out_size.total_width	= mf->width + BLANKING_EXTRA_WIDTH;
+	priv->out_size.total_height	= max_t(int, mf->height +
+							BLANKING_EXTRA_HEIGHT,
+							BLANKING_MIN_HEIGHT);
+	priv->crop_rect.width		= mf->width;
+	priv->crop_rect.height		= mf->height;
+
 	priv->fmt = ov5642_find_datafmt(mf->code);
 
-	ov5642_write_array(client, ov5642_default_regs_init);
-	ov5642_set_resolution(client);
-	ov5642_write_array(client, ov5642_default_regs_finalise);
+	ret = ov5642_write_array(client, ov5642_default_regs_init);
+	if (!ret)
+		ret = ov5642_set_resolution(sd);
+	if (!ret)
+		ret = ov5642_write_array(client, ov5642_default_regs_finalise);
 
-	return 0;
+	return ret;
 }
 
-static int ov5642_g_fmt(struct v4l2_subdev *sd,
-			struct v4l2_mbus_framefmt *mf)
+static int ov5642_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov5642 *priv = to_ov5642(client);
@@ -793,10 +868,12 @@  static int ov5642_g_fmt(struct v4l2_subdev *sd,
 
 	mf->code	= fmt->code;
 	mf->colorspace	= fmt->colorspace;
-	mf->width	= OV5642_WIDTH;
-	mf->height	= OV5642_HEIGHT;
+	mf->width	= priv->out_size.width;
+	mf->height	= priv->out_size.height;
 	mf->field	= V4L2_FIELD_NONE;
 
+	dev_dbg(sd->v4l2_dev->dev, "%s return width: %u heigth: %u\n", __func__,
+			mf->width, mf->height);
 	return 0;
 }
 
@@ -829,14 +906,17 @@  static int ov5642_g_chip_ident(struct v4l2_subdev *sd,
 
 static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5642 *priv = to_ov5642(client);
 	struct v4l2_rect *rect = &a->c;
-
 	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	rect->top	= 0;
-	rect->left	= 0;
-	rect->width	= OV5642_WIDTH;
-	rect->height	= OV5642_HEIGHT;
+	rect->top	= priv->crop_rect.top;
+	rect->left	= priv->crop_rect.left;
+	rect->width	= priv->crop_rect.width;
+	rect->height	= priv->crop_rect.height;
 
+	dev_dbg(sd->v4l2_dev->dev, "%s crop width: %u heigth: %u\n", __func__,
+			rect->width, rect->height);
 	return 0;
 }
 
@@ -844,8 +924,8 @@  static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 {
 	a->bounds.left			= 0;
 	a->bounds.top			= 0;
-	a->bounds.width			= OV5642_WIDTH;
-	a->bounds.height		= OV5642_HEIGHT;
+	a->bounds.width			= OV5642_MAX_WIDTH;
+	a->bounds.height		= OV5642_MAX_HEIGHT;
 	a->defrect			= a->bounds;
 	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	a->pixelaspect.numerator	= 1;
@@ -858,9 +938,8 @@  static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
 				struct v4l2_mbus_config *cfg)
 {
 	cfg->type = V4L2_MBUS_CSI2;
-	cfg->flags = V4L2_MBUS_CSI2_2_LANE |
-		V4L2_MBUS_CSI2_CHANNEL_0 |
-		V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+	cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
+					V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
 
 	return 0;
 }
@@ -941,8 +1020,15 @@  static int ov5642_probe(struct i2c_client *client,
 
 	v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
 
-	icd->ops	= NULL;
-	priv->fmt	= &ov5642_colour_fmts[0];
+	icd->ops		= NULL;
+	priv->fmt		= &ov5642_colour_fmts[0];
+
+	priv->crop_rect.width	= OV5642_DEFAULT_WIDTH;
+	priv->crop_rect.height	= OV5642_DEFAULT_HEIGHT;
+	priv->crop_rect.left	= (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
+	priv->crop_rect.top	= (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
+	priv->out_size.width	= OV5642_DEFAULT_WIDTH;
+	priv->out_size.height	= OV5642_DEFAULT_HEIGHT;
 
 	ret = ov5642_video_probe(icd, client);
 	if (ret < 0)
@@ -951,6 +1037,7 @@  static int ov5642_probe(struct i2c_client *client,
 	return 0;
 
 error:
+	icd->ops = NULL;
 	kfree(priv);
 	return ret;
 }
@@ -961,6 +1048,7 @@  static int ov5642_remove(struct i2c_client *client)
 	struct soc_camera_device *icd = client->dev.platform_data;
 	struct soc_camera_link *icl = to_soc_camera_link(icd);
 
+	icd->ops = NULL;
 	if (icl->free_bus)
 		icl->free_bus(icl);
 	kfree(priv);