From b6f32263403ee12d24999185652c77176ed17784 Mon Sep 17 00:00:00 2001
From: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Date: Thu, 28 May 2009 14:52:49 +0200
Subject: [PATCH 15/42] soc-camera: use struct v4l2_rect in struct soc_camera_device

Switch to using struct v4l2_rect in struct soc_camera_device for uniformity and
simplicity.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 drivers/media/video/mt9m001.c              |   30 +++++++------
 drivers/media/video/mt9m111.c              |   20 ++++----
 drivers/media/video/mt9t031.c              |   49 ++++++++++++----------
 drivers/media/video/mt9v022.c              |   24 +++++-----
 drivers/media/video/mx1_camera.c           |   10 ++--
 drivers/media/video/mx3_camera.c           |   25 ++++++-----
 drivers/media/video/ov772x.c               |    6 +-
 drivers/media/video/pxa_camera.c           |   14 +++---
 drivers/media/video/sh_mobile_ceu_camera.c |   28 +++++++-----
 drivers/media/video/soc_camera.c           |   62 ++++++++++++++++------------
 drivers/media/video/soc_camera_platform.c  |   12 +++---
 drivers/media/video/tw9910.c               |   38 ++++++++++-------
 include/media/soc_camera.h                 |   10 +----
 13 files changed, 174 insertions(+), 154 deletions(-)

diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 2a73dac..8b36a74 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -240,8 +240,8 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
 	struct i2c_client *client = sd->priv;
 	struct soc_camera_device *icd = client->dev.platform_data;
 	struct v4l2_rect rect = {
-		.left	= icd->x_current,
-		.top	= icd->y_current,
+		.left	= icd->rect_current.left,
+		.top	= icd->rect_current.top,
 		.width	= f->fmt.pix.width,
 		.height	= f->fmt.pix.height,
 	};
@@ -467,11 +467,13 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 	case V4L2_CID_EXPOSURE_AUTO:
 		if (ctrl->value) {
 			const u16 vblank = 25;
-			if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height +
+			if (reg_write(client, MT9M001_SHUTTER_WIDTH,
+				      icd->rect_current.height +
 				      icd->y_skip_top + vblank) < 0)
 				return -EIO;
 			qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
-			icd->exposure = (524 + (icd->height + icd->y_skip_top + vblank - 1) *
+			icd->exposure = (524 + (icd->rect_current.height +
+						icd->y_skip_top + vblank - 1) *
 					 (qctrl->maximum - qctrl->minimum)) /
 				1048 + qctrl->minimum;
 			mt9m001->autoexposure = 1;
@@ -613,16 +615,16 @@ static int mt9m001_probe(struct i2c_client *client,
 	v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
 
 	/* Second stage probe - when a capture adapter is there */
-	icd->ops	= &mt9m001_ops;
-	icd->x_min	= 20;
-	icd->y_min	= 12;
-	icd->x_current	= 20;
-	icd->y_current	= 12;
-	icd->width_min	= 48;
-	icd->width_max	= 1280;
-	icd->height_min	= 32;
-	icd->height_max	= 1024;
-	icd->y_skip_top	= 1;
+	icd->ops		= &mt9m001_ops;
+	icd->rect_max.left	= 20;
+	icd->rect_max.top	= 12;
+	icd->rect_max.width	= 1280;
+	icd->rect_max.height	= 1024;
+	icd->rect_current.left	= 20;
+	icd->rect_current.top	= 12;
+	icd->width_min		= 48;
+	icd->height_min		= 32;
+	icd->y_skip_top		= 1;
 	/* Simulated autoexposure. If enabled, we calculate shutter width
 	 * ourselves in the driver based on vertical blanking and frame width */
 	mt9m001->autoexposure = 1;
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 29f976a..45101fd 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -948,16 +948,16 @@ static int mt9m111_probe(struct i2c_client *client,
 	v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
 
 	/* Second stage probe - when a capture adapter is there */
-	icd->ops	= &mt9m111_ops;
-	icd->x_min	= MT9M111_MIN_DARK_COLS;
-	icd->y_min	= MT9M111_MIN_DARK_ROWS;
-	icd->x_current	= icd->x_min;
-	icd->y_current	= icd->y_min;
-	icd->width_min	= MT9M111_MIN_DARK_ROWS;
-	icd->width_max	= MT9M111_MAX_WIDTH;
-	icd->height_min	= MT9M111_MIN_DARK_COLS;
-	icd->height_max	= MT9M111_MAX_HEIGHT;
-	icd->y_skip_top	= 0;
+	icd->ops		= &mt9m111_ops;
+	icd->rect_max.left	= MT9M111_MIN_DARK_COLS;
+	icd->rect_max.top	= MT9M111_MIN_DARK_ROWS;
+	icd->rect_max.width	= MT9M111_MAX_WIDTH;
+	icd->rect_max.height	= MT9M111_MAX_HEIGHT;
+	icd->rect_current.left	= icd->rect_max.left;
+	icd->rect_current.top	= icd->rect_max.top;
+	icd->width_min		= MT9M111_MIN_DARK_ROWS;
+	icd->height_min		= MT9M111_MIN_DARK_COLS;
+	icd->y_skip_top		= 0;
 
 	ret = mt9m111_video_probe(icd, client);
 	if (ret) {
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index 27a5edd..dc3eb65 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -222,12 +222,12 @@ static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
 static void recalculate_limits(struct soc_camera_device *icd,
 			       u16 xskip, u16 yskip)
 {
-	icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
-	icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
+	icd->rect_max.left = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
+	icd->rect_max.top = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
 	icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip;
 	icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip;
-	icd->width_max = MT9T031_MAX_WIDTH / xskip;
-	icd->height_max = MT9T031_MAX_HEIGHT / yskip;
+	icd->rect_max.width = MT9T031_MAX_WIDTH / xskip;
+	icd->rect_max.height = MT9T031_MAX_HEIGHT / yskip;
 }
 
 static int mt9t031_set_params(struct soc_camera_device *icd,
@@ -241,11 +241,13 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
 		vblank = MT9T031_VERTICAL_BLANK;
 
 	/* Make sure we don't exceed sensor limits */
-	if (rect->left + rect->width > icd->width_max)
-		rect->left = (icd->width_max - rect->width) / 2 + icd->x_min;
+	if (rect->left + rect->width > icd->rect_max.width)
+		rect->left = (icd->rect_max.width - rect->width) / 2 +
+			icd->rect_max.left;
 
-	if (rect->top + rect->height > icd->height_max)
-		rect->top = (icd->height_max - rect->height) / 2 + icd->y_min;
+	if (rect->top + rect->height > icd->rect_max.height)
+		rect->top = (icd->rect_max.height - rect->height) / 2 +
+			icd->rect_max.top;
 
 	width = rect->width * xskip;
 	height = rect->height * yskip;
@@ -346,8 +348,8 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
 	int ret;
 	u16 xskip, yskip;
 	struct v4l2_rect rect = {
-		.left	= icd->x_current,
-		.top	= icd->y_current,
+		.left	= icd->rect_current.left,
+		.top	= icd->rect_current.top,
 		.width	= f->fmt.pix.width,
 		.height	= f->fmt.pix.height,
 	};
@@ -618,12 +620,13 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 		if (ctrl->value) {
 			const u16 vblank = MT9T031_VERTICAL_BLANK;
 			const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
-			if (set_shutter(client, icd->height +
+			if (set_shutter(client, icd->rect_current.height +
 					icd->y_skip_top + vblank) < 0)
 				return -EIO;
 			qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
-			icd->exposure = (shutter_max / 2 + (icd->height +
-					 icd->y_skip_top + vblank - 1) *
+			icd->exposure = (shutter_max / 2 +
+					 (icd->rect_current.height +
+					  icd->y_skip_top + vblank - 1) *
 					 (qctrl->maximum - qctrl->minimum)) /
 				shutter_max + qctrl->minimum;
 			mt9t031->autoexposure = 1;
@@ -726,16 +729,16 @@ static int mt9t031_probe(struct i2c_client *client,
 	v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
 
 	/* Second stage probe - when a capture adapter is there */
-	icd->ops	= &mt9t031_ops;
-	icd->x_min	= MT9T031_COLUMN_SKIP;
-	icd->y_min	= MT9T031_ROW_SKIP;
-	icd->x_current	= icd->x_min;
-	icd->y_current	= icd->y_min;
-	icd->width_min	= MT9T031_MIN_WIDTH;
-	icd->width_max	= MT9T031_MAX_WIDTH;
-	icd->height_min	= MT9T031_MIN_HEIGHT;
-	icd->height_max	= MT9T031_MAX_HEIGHT;
-	icd->y_skip_top	= 0;
+	icd->ops		= &mt9t031_ops;
+	icd->rect_max.left	= MT9T031_COLUMN_SKIP;
+	icd->rect_max.top	= MT9T031_ROW_SKIP;
+	icd->rect_current.left	= icd->rect_max.left;
+	icd->rect_current.top	= icd->rect_max.top;
+	icd->width_min		= MT9T031_MIN_WIDTH;
+	icd->rect_max.width	= MT9T031_MAX_WIDTH;
+	icd->height_min		= MT9T031_MIN_HEIGHT;
+	icd->rect_max.height	= MT9T031_MAX_HEIGHT;
+	icd->y_skip_top		= 0;
 	/* Simulated autoexposure. If enabled, we calculate shutter width
 	 * ourselves in the driver based on vertical blanking and frame width */
 	mt9t031->autoexposure = 1;
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 3cb9f0f..d2b0981 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -298,8 +298,8 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
 	struct soc_camera_device *icd = client->dev.platform_data;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_rect rect = {
-		.left	= icd->x_current,
-		.top	= icd->y_current,
+		.left	= icd->rect_current.left,
+		.top	= icd->rect_current.top,
 		.width	= pix->width,
 		.height	= pix->height,
 	};
@@ -741,16 +741,16 @@ static int mt9v022_probe(struct i2c_client *client,
 
 	mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
 
-	icd->ops	= &mt9v022_ops;
-	icd->x_min	= 1;
-	icd->y_min	= 4;
-	icd->x_current	= 1;
-	icd->y_current	= 4;
-	icd->width_min	= 48;
-	icd->width_max	= 752;
-	icd->height_min	= 32;
-	icd->height_max	= 480;
-	icd->y_skip_top	= 1;
+	icd->ops		= &mt9v022_ops;
+	icd->rect_max.left	= 1;
+	icd->rect_max.top	= 4;
+	icd->rect_max.width	= 752;
+	icd->rect_max.height	= 480;
+	icd->rect_current.left	= 1;
+	icd->rect_current.top	= 4;
+	icd->width_min		= 48;
+	icd->height_min		= 32;
+	icd->y_skip_top		= 1;
 
 	ret = mt9v022_video_probe(icd, client);
 	if (ret) {
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index ea4ceae..948a471 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -126,7 +126,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 {
 	struct soc_camera_device *icd = vq->priv_data;
 
-	*size = icd->width * icd->height *
+	*size = icd->rect_current.width * icd->rect_current.height *
 		((icd->current_fmt->depth + 7) >> 3);
 
 	if (!*count)
@@ -178,12 +178,12 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
 	buf->inwork = 1;
 
 	if (buf->fmt	!= icd->current_fmt ||
-	    vb->width	!= icd->width ||
-	    vb->height	!= icd->height ||
+	    vb->width	!= icd->rect_current.width ||
+	    vb->height	!= icd->rect_current.height ||
 	    vb->field	!= field) {
 		buf->fmt	= icd->current_fmt;
-		vb->width	= icd->width;
-		vb->height	= icd->height;
+		vb->width	= icd->rect_current.width;
+		vb->height	= icd->rect_current.height;
 		vb->field	= field;
 		vb->state	= VIDEOBUF_NEEDS_INIT;
 	}
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 677d355..6c3b7f9 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -220,7 +220,7 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 	if (!mx3_cam->idmac_channel[0])
 		return -EINVAL;
 
-	*size = icd->width * icd->height * bpp;
+	*size = icd->rect_current.width * icd->rect_current.height * bpp;
 
 	if (!*count)
 		*count = 32;
@@ -241,7 +241,7 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
 	struct mx3_camera_buffer *buf =
 		container_of(vb, struct mx3_camera_buffer, vb);
 	/* current_fmt _must_ always be set */
-	size_t new_size = icd->width * icd->height *
+	size_t new_size = icd->rect_current.width * icd->rect_current.height *
 		((icd->current_fmt->depth + 7) >> 3);
 	int ret;
 
@@ -251,12 +251,12 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
 	 */
 
 	if (buf->fmt	!= icd->current_fmt ||
-	    vb->width	!= icd->width ||
-	    vb->height	!= icd->height ||
+	    vb->width	!= icd->rect_current.width ||
+	    vb->height	!= icd->rect_current.height ||
 	    vb->field	!= field) {
 		buf->fmt	= icd->current_fmt;
-		vb->width	= icd->width;
-		vb->height	= icd->height;
+		vb->width	= icd->rect_current.width;
+		vb->height	= icd->rect_current.height;
 		vb->field	= field;
 		if (vb->state != VIDEOBUF_NEEDS_INIT)
 			free_buffer(vq, buf);
@@ -354,9 +354,9 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq,
 
 	/* This is the configuration of one sg-element */
 	video->out_pixel_fmt	= fourcc_to_ipu_pix(data_fmt->fourcc);
-	video->out_width	= icd->width;
-	video->out_height	= icd->height;
-	video->out_stride	= icd->width;
+	video->out_width	= icd->rect_current.width;
+	video->out_height	= icd->rect_current.height;
+	video->out_stride	= icd->rect_current.width;
 
 #ifdef DEBUG
 	/* helps to see what DMA actually has written */
@@ -538,7 +538,8 @@ static bool channel_change_requested(struct soc_camera_device *icd,
 	struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
 
 	/* Do buffers have to be re-allocated or channel re-configured? */
-	return ichan && rect->width * rect->height > icd->width * icd->height;
+	return ichan && rect->width * rect->height >
+		icd->rect_current.width * icd->rect_current.height;
 }
 
 static int test_platform_param(struct mx3_camera_dev *mx3_cam,
@@ -808,8 +809,8 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
 	const struct soc_camera_format_xlate *xlate;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_rect rect = {
-		.left	= icd->x_current,
-		.top	= icd->y_current,
+		.left	= icd->rect_current.left,
+		.top	= icd->rect_current.top,
 		.width	= pix->width,
 		.height	= pix->height,
 	};
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 4c550f9..3417398 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -1120,9 +1120,9 @@ static int ov772x_probe(struct i2c_client *client,
 
 	v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
 
-	icd->ops        = &ov772x_ops;
-	icd->width_max  = MAX_WIDTH;
-	icd->height_max = MAX_HEIGHT;
+	icd->ops		= &ov772x_ops;
+	icd->rect_max.width	= MAX_WIDTH;
+	icd->rect_max.height	= MAX_HEIGHT;
 
 	ret = ov772x_video_probe(icd, client);
 	if (ret) {
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index bdc0d85..0e4daaa 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -239,7 +239,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 
 	dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
 
-	*size = roundup(icd->width * icd->height *
+	*size = roundup(icd->rect_current.width * icd->rect_current.height *
 			((icd->current_fmt->depth + 7) >> 3), 8);
 
 	if (0 == *count)
@@ -443,12 +443,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
 	buf->inwork = 1;
 
 	if (buf->fmt	!= icd->current_fmt ||
-	    vb->width	!= icd->width ||
-	    vb->height	!= icd->height ||
+	    vb->width	!= icd->rect_current.width ||
+	    vb->height	!= icd->rect_current.height ||
 	    vb->field	!= field) {
 		buf->fmt	= icd->current_fmt;
-		vb->width	= icd->width;
-		vb->height	= icd->height;
+		vb->width	= icd->rect_current.width;
+		vb->height	= icd->rect_current.height;
 		vb->field	= field;
 		vb->state	= VIDEOBUF_NEEDS_INIT;
 	}
@@ -1118,7 +1118,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 	if (cicr0 & CICR0_ENB)
 		__raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0);
 
-	cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
+	cicr1 = CICR1_PPL_VAL(icd->rect_current.width - 1) | bpp | dw;
 
 	switch (pixfmt) {
 	case V4L2_PIX_FMT_YUV422P:
@@ -1147,7 +1147,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 	}
 
 	cicr2 = 0;
-	cicr3 = CICR3_LPF_VAL(icd->height - 1) |
+	cicr3 = CICR3_LPF_VAL(icd->rect_current.height - 1) |
 		CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
 	cicr4 |= pcdev->mclk_divisor;
 
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 72d62f5..4cf64f9 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -147,7 +147,8 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,
 	struct sh_mobile_ceu_dev *pcdev = ici->priv;
 	int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;
 
-	*size = PAGE_ALIGN(icd->width * icd->height * bytes_per_pixel);
+	*size = PAGE_ALIGN(icd->rect_current.width * icd->rect_current.height *
+			   bytes_per_pixel);
 
 	if (0 == *count)
 		*count = 2;
@@ -206,7 +207,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
 	phys_addr_top = videobuf_to_dma_contig(pcdev->active);
 	ceu_write(pcdev, CDAYR, phys_addr_top);
 	if (pcdev->is_interlaced) {
-		phys_addr_bottom = phys_addr_top + icd->width;
+		phys_addr_bottom = phys_addr_top + icd->rect_current.width;
 		ceu_write(pcdev, CDBYR, phys_addr_bottom);
 	}
 
@@ -215,10 +216,12 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
 	case V4L2_PIX_FMT_NV21:
 	case V4L2_PIX_FMT_NV16:
 	case V4L2_PIX_FMT_NV61:
-		phys_addr_top += icd->width * icd->height;
+		phys_addr_top += icd->rect_current.width *
+			icd->rect_current.height;
 		ceu_write(pcdev, CDACR, phys_addr_top);
 		if (pcdev->is_interlaced) {
-			phys_addr_bottom = phys_addr_top + icd->width;
+			phys_addr_bottom = phys_addr_top +
+				icd->rect_current.width;
 			ceu_write(pcdev, CDBCR, phys_addr_bottom);
 		}
 	}
@@ -252,12 +255,12 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
 	BUG_ON(NULL == icd->current_fmt);
 
 	if (buf->fmt	!= icd->current_fmt ||
-	    vb->width	!= icd->width ||
-	    vb->height	!= icd->height ||
+	    vb->width	!= icd->rect_current.width ||
+	    vb->height	!= icd->rect_current.height ||
 	    vb->field	!= field) {
 		buf->fmt	= icd->current_fmt;
-		vb->width	= icd->width;
-		vb->height	= icd->height;
+		vb->width	= icd->rect_current.width;
+		vb->height	= icd->rect_current.height;
 		vb->field	= field;
 		vb->state	= VIDEOBUF_NEEDS_INIT;
 	}
@@ -476,17 +479,18 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
 	mdelay(1);
 
 	if (yuv_mode) {
-		width = icd->width * 2;
+		width = icd->rect_current.width * 2;
 		width = buswidth == 16 ? width / 2 : width;
-		cfszr_width = cdwdr_width = icd->width;
+		cfszr_width = cdwdr_width = icd->rect_current.width;
 	} else {
-		width = icd->width * ((icd->current_fmt->depth + 7) >> 3);
+		width = icd->rect_current.width *
+			((icd->current_fmt->depth + 7) >> 3);
 		width = buswidth == 16 ? width / 2 : width;
 		cfszr_width = buswidth == 8 ? width / 2 : width;
 		cdwdr_width = buswidth == 16 ? width * 2 : width;
 	}
 
-	height = icd->height;
+	height = icd->rect_current.height;
 	if (pcdev->is_interlaced) {
 		height /= 2;
 		cdwdr_width *= 2;
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index b3fb8f2..5028023 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -288,17 +288,17 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
 		return -EINVAL;
 	}
 
-	icd->width		= pix->width;
-	icd->height		= pix->height;
-	icf->vb_vidq.field	=
-		icd->field	= pix->field;
+	icd->rect_current.width		= pix->width;
+	icd->rect_current.height	= pix->height;
+	icf->vb_vidq.field		=
+		icd->field		= pix->field;
 
 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
 			 f->type);
 
 	dev_dbg(&icd->dev, "set width: %d height: %d\n",
-		icd->width, icd->height);
+		icd->rect_current.width, icd->rect_current.height);
 
 	/* set physical bus parameters */
 	return ici->ops->set_bus_param(icd, pix->pixelformat);
@@ -341,8 +341,8 @@ static int soc_camera_open(struct file *file)
 		struct v4l2_format f = {
 			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			.fmt.pix = {
-				.width		= icd->width,
-				.height		= icd->height,
+				.width		= icd->rect_current.width,
+				.height		= icd->rect_current.height,
 				.field		= icd->field,
 			},
 		};
@@ -553,8 +553,8 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
 
 	WARN_ON(priv != file->private_data);
 
-	pix->width		= icd->width;
-	pix->height		= icd->height;
+	pix->width		= icd->rect_current.width;
+	pix->height		= icd->rect_current.height;
 	pix->field		= icf->vb_vidq.field;
 	pix->pixelformat	= icd->current_fmt->fourcc;
 	pix->bytesperline	= pix->width *
@@ -718,12 +718,9 @@ static int soc_camera_cropcap(struct file *file, void *fh,
 	struct soc_camera_device *icd = icf->icd;
 
 	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	a->bounds.left			= icd->x_min;
-	a->bounds.top			= icd->y_min;
-	a->bounds.width			= icd->width_max;
-	a->bounds.height		= icd->height_max;
-	a->defrect.left			= icd->x_min;
-	a->defrect.top			= icd->y_min;
+	a->bounds			= icd->rect_max;
+	a->defrect.left			= icd->rect_max.left;
+	a->defrect.top			= icd->rect_max.top;
 	a->defrect.width		= DEFAULT_WIDTH;
 	a->defrect.height		= DEFAULT_HEIGHT;
 	a->pixelaspect.numerator	= 1;
@@ -738,11 +735,8 @@ static int soc_camera_g_crop(struct file *file, void *fh,
 	struct soc_camera_file *icf = file->private_data;
 	struct soc_camera_device *icd = icf->icd;
 
-	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	a->c.left	= icd->x_current;
-	a->c.top	= icd->y_current;
-	a->c.width	= icd->width;
-	a->c.height	= icd->height;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->c	= icd->rect_current;
 
 	return 0;
 }
@@ -761,13 +755,29 @@ static int soc_camera_s_crop(struct file *file, void *fh,
 	/* Cropping is allowed during a running capture, guard consistency */
 	mutex_lock(&icf->vb_vidq.vb_lock);
 
+	if (a->c.width > icd->rect_max.width)
+		a->c.width = icd->rect_max.width;
+
+	if (a->c.width < icd->width_min)
+		a->c.width = icd->width_min;
+
+	if (a->c.height > icd->rect_max.height)
+		a->c.height = icd->rect_max.height;
+
+	if (a->c.height < icd->height_min)
+		a->c.height = icd->height_min;
+
+	if (a->c.width + a->c.left > icd->rect_max.width + icd->rect_max.left)
+		a->c.left = icd->rect_max.width + icd->rect_max.left -
+			a->c.width;
+
+	if (a->c.height + a->c.top > icd->rect_max.height + icd->rect_max.top)
+		a->c.top = icd->rect_max.height + icd->rect_max.top -
+			a->c.height;
+
 	ret = ici->ops->set_crop(icd, &a->c);
-	if (!ret) {
-		icd->width	= a->c.width;
-		icd->height	= a->c.height;
-		icd->x_current	= a->c.left;
-		icd->y_current	= a->c.top;
-	}
+	if (!ret)
+		icd->rect_current = a->c;
 
 	mutex_unlock(&icf->vb_vidq.vb_lock);
 
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index 8168cf4..9e406c1 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -127,12 +127,12 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, priv);
 	dev_set_drvdata(&icd->dev, &pdev->dev);
 
-	icd->width_min	= 0;
-	icd->width_max	= p->format.width;
-	icd->height_min	= 0;
-	icd->height_max	= p->format.height;
-	icd->y_skip_top	= 0;
-	icd->ops	= &soc_camera_platform_ops;
+	icd->width_min		= 0;
+	icd->rect_max.width	= p->format.width;
+	icd->height_min		= 0;
+	icd->rect_max.height	= p->format.height;
+	icd->y_skip_top		= 0;
+	icd->ops		= &soc_camera_platform_ops;
 
 	ici = to_soc_camera_host(icd->dev.parent);
 
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index a006df1..7199e0f 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -715,8 +715,8 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
 	struct soc_camera_device *icd = client->dev.platform_data;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_rect rect = {
-		.left	= icd->x_current,
-		.top	= icd->y_current,
+		.left	= icd->rect_current.left,
+		.top	= icd->rect_current.top,
 		.width	= pix->width,
 		.height	= pix->height,
 	};
@@ -840,6 +840,19 @@ static struct v4l2_subdev_ops tw9910_subdev_ops = {
  * i2c_driver function
  */
 
+static void limit_to_scale(struct soc_camera_device *icd,
+			   const struct tw9910_scale_ctrl *scale)
+{
+	if (scale->width > icd->rect_max.width)
+		icd->rect_max.width  = scale->width;
+	if (scale->width < icd->width_min)
+		icd->width_min = scale->width;
+	if (scale->height > icd->rect_max.height)
+		icd->rect_max.height = scale->height;
+	if (scale->height < icd->height_min)
+		icd->height_min = scale->height;
+}
+
 static int tw9910_probe(struct i2c_client *client,
 			const struct i2c_device_id *did)
 
@@ -885,25 +898,18 @@ static int tw9910_probe(struct i2c_client *client,
 	/*
 	 * set width and height
 	 */
-	icd->width_max  = tw9910_ntsc_scales[0].width; /* set default */
+	icd->rect_max.width  = tw9910_ntsc_scales[0].width; /* set default */
 	icd->width_min  = tw9910_ntsc_scales[0].width;
-	icd->height_max = tw9910_ntsc_scales[0].height;
+	icd->rect_max.height = tw9910_ntsc_scales[0].height;
 	icd->height_min = tw9910_ntsc_scales[0].height;
 
 	scale = tw9910_ntsc_scales;
-	for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++) {
-		icd->width_max  = max(scale[i].width,  icd->width_max);
-		icd->width_min  = min(scale[i].width,  icd->width_min);
-		icd->height_max = max(scale[i].height, icd->height_max);
-		icd->height_min = min(scale[i].height, icd->height_min);
-	}
+	for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++)
+		limit_to_scale(icd, scale + i);
+
 	scale = tw9910_pal_scales;
-	for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++) {
-		icd->width_max  = max(scale[i].width,  icd->width_max);
-		icd->width_min  = min(scale[i].width,  icd->width_min);
-		icd->height_max = max(scale[i].height, icd->height_max);
-		icd->height_min = min(scale[i].height, icd->height_min);
-	}
+	for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++)
+		limit_to_scale(icd, scale + i);
 
 	ret = tw9910_video_probe(icd, client);
 	if (ret) {
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 2d116bb..f623c01 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -22,16 +22,10 @@ struct soc_camera_device {
 	struct list_head list;
 	struct device dev;
 	struct device *pdev;		/* Platform device */
-	unsigned short width;		/* Current window */
-	unsigned short height;		/* sizes */
-	unsigned short x_min;		/* Camera capabilities */
-	unsigned short y_min;
-	unsigned short x_current;	/* Current window location */
-	unsigned short y_current;
+	struct v4l2_rect rect_current;	/* Current window */
+	struct v4l2_rect rect_max;	/* Maximum window */
 	unsigned short width_min;
-	unsigned short width_max;
 	unsigned short height_min;
-	unsigned short height_max;
 	unsigned short y_skip_top;	/* Lines to skip at the top */
 	unsigned short gain;
 	unsigned short exposure;
-- 
1.6.2.4

