From cc98edd171647ea54a2c77a892846bd202cb0b28 Mon Sep 17 00:00:00 2001
From: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Date: Wed, 17 Jun 2009 00:41:03 +0200
Subject: [PATCH 47/48] soc-camera: switch to s_crop v4l2-subdev video operation

Remove set_crop soc-camera device method and switch to s_crop from v4l2-subdev
video operations. Also extend non-i2c drivers to also hold a pointer to their
v4l2-subdev instance in control device driver-data, i.e., in
dev_get_drvdata((struct device *)to_soc_camera_control(icd))

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 drivers/media/video/mt9m001.c              |   23 +++---
 drivers/media/video/mt9m111.c              |    9 +-
 drivers/media/video/mt9t031.c              |    9 +-
 drivers/media/video/mt9v022.c              |   23 +++---
 drivers/media/video/mx1_camera.c           |    8 ++-
 drivers/media/video/mx3_camera.c           |    7 +-
 drivers/media/video/ov772x.c               |   19 -----
 drivers/media/video/pxa_camera.c           |    7 +-
 drivers/media/video/sh_mobile_ceu_camera.c |  110 ++++++++++++++-------------
 drivers/media/video/soc_camera.c           |    4 +-
 drivers/media/video/soc_camera_platform.c  |   28 ++++----
 drivers/media/video/tw9910.c               |   31 ++++----
 include/media/soc_camera.h                 |    3 +-
 13 files changed, 142 insertions(+), 139 deletions(-)

diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index d4f7935..fb1b580 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -194,11 +194,12 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
 	return soc_camera_apply_sensor_flags(icl, flags);
 }
 
-static int mt9m001_set_crop(struct soc_camera_device *icd,
-			    struct v4l2_rect *rect)
+static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct v4l2_rect *rect = &a->c;
+	struct i2c_client *client = sd->priv;
 	struct mt9m001 *mt9m001 = to_mt9m001(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 	int ret;
 	const u16 hblank = 9, vblank = 25;
 
@@ -239,15 +240,17 @@ 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->rect_current.left,
-		.top	= icd->rect_current.top,
-		.width	= f->fmt.pix.width,
-		.height	= f->fmt.pix.height,
+	struct v4l2_crop a = {
+		.c = {
+			.left	= icd->rect_current.left,
+			.top	= icd->rect_current.top,
+			.width	= f->fmt.pix.width,
+			.height	= f->fmt.pix.height,
+		},
 	};
 
 	/* No support for scaling so far, just crop. TODO: use skipping */
-	return mt9m001_set_crop(icd, &rect);
+	return mt9m001_s_crop(sd, &a);
 }
 
 static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
@@ -367,7 +370,6 @@ static const struct v4l2_queryctrl mt9m001_controls[] = {
 static struct soc_camera_ops mt9m001_ops = {
 	.init			= mt9m001_init,
 	.release		= mt9m001_release,
-	.set_crop		= mt9m001_set_crop,
 	.set_bus_param		= mt9m001_set_bus_param,
 	.query_bus_param	= mt9m001_query_bus_param,
 	.controls		= mt9m001_controls,
@@ -581,6 +583,7 @@ static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
 	.s_stream	= mt9m001_s_stream,
 	.s_fmt		= mt9m001_s_fmt,
 	.try_fmt	= mt9m001_try_fmt,
+	.s_crop		= mt9m001_s_crop,
 };
 
 static struct v4l2_subdev_ops mt9m001_subdev_ops = {
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 45101fd..bef4151 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -395,11 +395,12 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
 	return 0;
 }
 
-static int mt9m111_set_crop(struct soc_camera_device *icd,
-			    struct v4l2_rect *rect)
+static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct v4l2_rect *rect = &a->c;
+	struct i2c_client *client = sd->priv;
 	struct mt9m111 *mt9m111 = to_mt9m111(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 	int ret;
 
 	dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
@@ -601,7 +602,6 @@ static struct soc_camera_ops mt9m111_ops = {
 	.init			= mt9m111_init,
 	.resume			= mt9m111_resume,
 	.release		= mt9m111_release,
-	.set_crop		= mt9m111_set_crop,
 	.query_bus_param	= mt9m111_query_bus_param,
 	.set_bus_param		= mt9m111_set_bus_param,
 	.controls		= mt9m111_controls,
@@ -908,6 +908,7 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
 static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
 	.s_fmt		= mt9m111_s_fmt,
 	.try_fmt	= mt9m111_try_fmt,
+	.s_crop		= mt9m111_s_crop,
 };
 
 static struct v4l2_subdev_ops mt9m111_subdev_ops = {
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index c7ff439..3bfc008 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -321,11 +321,12 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
 	return ret < 0 ? ret : 0;
 }
 
-static int mt9t031_set_crop(struct soc_camera_device *icd,
-			    struct v4l2_rect *rect)
+static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct v4l2_rect *rect = &a->c;
+	struct i2c_client *client = sd->priv;
 	struct mt9t031 *mt9t031 = to_mt9t031(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 
 	/* Make sure we don't exceed sensor limits */
 	if (rect->left + rect->width > icd->rect_max.left + icd->rect_max.width)
@@ -503,7 +504,6 @@ static const struct v4l2_queryctrl mt9t031_controls[] = {
 static struct soc_camera_ops mt9t031_ops = {
 	.init			= mt9t031_init,
 	.release		= mt9t031_release,
-	.set_crop		= mt9t031_set_crop,
 	.set_bus_param		= mt9t031_set_bus_param,
 	.query_bus_param	= mt9t031_query_bus_param,
 	.controls		= mt9t031_controls,
@@ -697,6 +697,7 @@ static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
 	.s_stream	= mt9t031_s_stream,
 	.s_fmt		= mt9t031_s_fmt,
 	.try_fmt	= mt9t031_try_fmt,
+	.s_crop		= mt9t031_s_crop,
 };
 
 static struct v4l2_subdev_ops mt9t031_subdev_ops = {
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 828dcac..b51ca0d 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -248,10 +248,11 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
 		width_flag;
 }
 
-static int mt9v022_set_crop(struct soc_camera_device *icd,
-			    struct v4l2_rect *rect)
+static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct v4l2_rect *rect = &a->c;
+	struct i2c_client *client = sd->priv;
+	struct soc_camera_device *icd = client->dev.platform_data;
 	int ret;
 
 	/* Like in example app. Contradicts the datasheet though */
@@ -297,11 +298,13 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
 	struct mt9v022 *mt9v022 = to_mt9v022(client);
 	struct soc_camera_device *icd = client->dev.platform_data;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
-	struct v4l2_rect rect = {
-		.left	= icd->rect_current.left,
-		.top	= icd->rect_current.top,
-		.width	= pix->width,
-		.height	= pix->height,
+	struct v4l2_crop a = {
+		.c = {
+			.left	= icd->rect_current.left,
+			.top	= icd->rect_current.top,
+			.width	= pix->width,
+			.height	= pix->height,
+		},
 	};
 
 	/* The caller provides a supported format, as verified per call to
@@ -325,7 +328,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
 	}
 
 	/* No support for scaling on this camera, just crop. */
-	return mt9v022_set_crop(icd, &rect);
+	return mt9v022_s_crop(sd, &a);
 }
 
 static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
@@ -460,7 +463,6 @@ static const struct v4l2_queryctrl mt9v022_controls[] = {
 
 static struct soc_camera_ops mt9v022_ops = {
 	.init			= mt9v022_init,
-	.set_crop		= mt9v022_set_crop,
 	.set_bus_param		= mt9v022_set_bus_param,
 	.query_bus_param	= mt9v022_query_bus_param,
 	.controls		= mt9v022_controls,
@@ -706,6 +708,7 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
 	.s_stream	= mt9v022_s_stream,
 	.s_fmt		= mt9v022_s_fmt,
 	.try_fmt	= mt9v022_try_fmt,
+	.s_crop		= mt9v022_s_crop,
 };
 
 static struct v4l2_subdev_ops mt9v022_subdev_ops = {
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index a410192..825163b 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -467,9 +467,13 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
 }
 
 static int mx1_camera_set_crop(struct soc_camera_device *icd,
-			       struct v4l2_rect *rect)
+			       struct v4l2_crop *a)
 {
-	return icd->ops->set_crop(icd, rect);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct device *control = to_soc_camera_control(icd);
+	struct v4l2_subdev *sd = dev_get_drvdata(control);
+
+	return v4l2_subdev_call(sd, video, s_crop, a);
 }
 
 static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 4d0facb..b178583 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -780,10 +780,13 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
 }
 
 static int mx3_camera_set_crop(struct soc_camera_device *icd,
-			       struct v4l2_rect *rect)
+			       struct v4l2_crop *a)
 {
+	struct v4l2_rect *rect = &a->c;
 	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct device *control = to_soc_camera_control(icd);
+	struct v4l2_subdev *sd = dev_get_drvdata(control);
 
 	/*
 	 * We now know pixel formats and can decide upon DMA-channel(s)
@@ -797,7 +800,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
 
 	configure_geometry(mx3_cam, rect);
 
-	return icd->ops->set_crop(icd, rect);
+	return v4l2_subdev_call(sd, video, s_crop, a);
 }
 
 static int mx3_camera_set_fmt(struct soc_camera_device *icd,
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 03488f9..bbe6f2d 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -955,24 +955,6 @@ ov772x_set_fmt_error:
 	return ret;
 }
 
-/* Cannot crop, just return the current geometry */
-static int ov772x_set_crop(struct soc_camera_device *icd,
-			   struct v4l2_rect *rect)
-{
-	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-	struct ov772x_priv *priv = to_ov772x(client);
-
-	if (!priv->fmt || !priv->win)
-		return -EINVAL;
-
-	rect->left = 0;
-	rect->top = 0;
-	rect->width = priv->win->width;
-	rect->height = priv->win->height;
-
-	return 0;
-}
-
 static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
 {
 	struct i2c_client *client = sd->priv;
@@ -1060,7 +1042,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd,
 }
 
 static struct soc_camera_ops ov772x_ops = {
-	.set_crop		= ov772x_set_crop,
 	.set_bus_param		= ov772x_set_bus_param,
 	.query_bus_param	= ov772x_query_bus_param,
 	.controls		= ov772x_controls,
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index fcf0421..690a0b1 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -1292,10 +1292,13 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
 }
 
 static int pxa_camera_set_crop(struct soc_camera_device *icd,
-			       struct v4l2_rect *rect)
+			       struct v4l2_crop *a)
 {
+	struct v4l2_rect *rect = &a->c;
 	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 	struct pxa_camera_dev *pcdev = ici->priv;
+	struct device *control = to_soc_camera_control(icd);
+	struct v4l2_subdev *sd = dev_get_drvdata(control);
 	struct soc_camera_sense sense = {
 		.master_clock = pcdev->mclk,
 		.pixel_clock_max = pcdev->ciclk / 4,
@@ -1306,7 +1309,7 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
 	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
 		icd->sense = &sense;
 
-	ret = icd->ops->set_crop(icd, rect);
+	ret = v4l2_subdev_call(sd, video, s_crop, a);
 
 	icd->sense = NULL;
 
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 1ecc9d0..0ff2c8d 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -850,12 +850,16 @@ static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2)
  * 3. if (2) failed, try to request the maximum image
  */
 static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
-				  struct v4l2_rect *rect)
+				  struct v4l2_crop *a)
 {
+	struct v4l2_rect *rect = &a->c;
 	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 	struct sh_mobile_ceu_dev *pcdev = ici->priv;
-	struct v4l2_rect cam_rect, target, cam_max;
+	struct v4l2_crop cam_crop;
+	struct v4l2_rect *cam_rect = &cam_crop.c, target, cam_max;
 	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct device *control = to_soc_camera_control(icd);
+	struct v4l2_subdev *sd = dev_get_drvdata(control);
 	unsigned int hscale = pcdev->cflcr & 0xffff;
 	unsigned int vscale = (pcdev->cflcr >> 16) & 0xffff;
 	unsigned short width, height;
@@ -863,80 +867,80 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
 	int ret;
 
 	/* Scale back up into client units */
-	cam_rect.left	= size_src(rect->left, hscale);
-	cam_rect.width	= size_src(rect->width, hscale);
-	cam_rect.top	= size_src(rect->top, vscale);
-	cam_rect.height	= size_src(rect->height, vscale);
+	cam_rect->left	= size_src(rect->left, hscale);
+	cam_rect->width	= size_src(rect->width, hscale);
+	cam_rect->top	= size_src(rect->top, vscale);
+	cam_rect->height	= size_src(rect->height, vscale);
 
-	target = cam_rect;
+	target = *cam_rect;
 
 	capsr = capture_save_reset(pcdev);
 	dev_dbg(&icd->dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
 
 	/* First attempt - see if the client can deliver a perfect result */
-	ret = icd->ops->set_crop(icd, &cam_rect);
+	ret = v4l2_subdev_call(sd, video, s_crop, &cam_crop);
 	if (!ret && !memcmp(&target, &cam_rect, sizeof(target))) {
 		dev_dbg(&icd->dev, "Camera S_CROP successful for %ux%u@%u:%u\n",
-			cam_rect.width, cam_rect.height,
-			cam_rect.left, cam_rect.top);
+			cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
 		goto ceu_set_rect;
 	}
 
 	/* Try to fix cropping, that camera hasn't managed to do */
 	dev_dbg(&icd->dev, "Fix camera S_CROP %d for %ux%u@%u:%u"
 		" to %ux%u@%u:%u\n",
-		ret, cam_rect.width, cam_rect.height,
-		cam_rect.left, cam_rect.top,
+		ret, cam_rect->width, cam_rect->height,
+		cam_rect->left, cam_rect->top,
 		target.width, target.height, target.left, target.top);
 
 	/*
 	 * Popular special case - some cameras can only handle fixed sizes like
 	 * QVGA, VGA,... Take care to avoid infinite loop.
 	 */
-	width = max(cam_rect.width, 1);
-	height = max(cam_rect.height, 1);
+	width = max(cam_rect->width, 1);
+	height = max(cam_rect->height, 1);
 	cam_max.width = size_src(icd->rect_max.width, hscale);
 	cam_max.left = size_src(icd->rect_max.left, hscale);
 	cam_max.height = size_src(icd->rect_max.height, vscale);
 	cam_max.top = size_src(icd->rect_max.top, vscale);
-	while (!ret && (is_smaller(&cam_rect, &target) ||
-			is_inside(&cam_rect, &target)) &&
+	while (!ret && (is_smaller(cam_rect, &target) ||
+			is_inside(cam_rect, &target)) &&
 	       cam_max.width >= width && cam_max.height >= height) {
 
 		width *= 2;
 		height *= 2;
-		cam_rect.width = width;
-		cam_rect.height = height;
+		cam_rect->width = width;
+		cam_rect->height = height;
 
 		/* We do not know what the camera is capable of, play safe */
-		if (cam_rect.left > target.left)
-			cam_rect.left = cam_max.left;
+		if (cam_rect->left > target.left)
+			cam_rect->left = cam_max.left;
 
-		if (cam_rect.left + cam_rect.width < target.left + target.width)
-			cam_rect.width = target.left + target.width -
-				cam_rect.left;
+		if (cam_rect->left + cam_rect->width < target.left + target.width)
+			cam_rect->width = target.left + target.width -
+				cam_rect->left;
 
-		if (cam_rect.top > target.top)
-			cam_rect.top = cam_max.top;
+		if (cam_rect->top > target.top)
+			cam_rect->top = cam_max.top;
 
-		if (cam_rect.top + cam_rect.height < target.top + target.height)
-			cam_rect.height = target.top + target.height -
-				cam_rect.top;
+		if (cam_rect->top + cam_rect->height < target.top + target.height)
+			cam_rect->height = target.top + target.height -
+				cam_rect->top;
 
-		if (cam_rect.width + cam_rect.left >
+		if (cam_rect->width + cam_rect->left >
 		    cam_max.width + cam_max.left)
-			cam_rect.left = max(cam_max.width + cam_max.left -
-					    cam_rect.width, cam_max.left);
+			cam_rect->left = max(cam_max.width + cam_max.left -
+					     cam_rect->width, cam_max.left);
 
-		if (cam_rect.height + cam_rect.top >
+		if (cam_rect->height + cam_rect->top >
 		    cam_max.height + cam_max.top)
-			cam_rect.top = max(cam_max.height + cam_max.top -
-					   cam_rect.height, cam_max.top);
+			cam_rect->top = max(cam_max.height + cam_max.top -
+					    cam_rect->height, cam_max.top);
 
-		ret = icd->ops->set_crop(icd, &cam_rect);
+		ret = v4l2_subdev_call(sd, video, s_crop, &cam_crop);
 		dev_dbg(&icd->dev, "Camera S_CROP %d for %ux%u@%u:%u\n",
-			ret, cam_rect.width, cam_rect.height,
-			cam_rect.left, cam_rect.top);
+			ret, cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
 	}
 
 	/*
@@ -945,30 +949,30 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
 	 */
 	if ((ret < 0 && (is_smaller(&icd->rect_current, rect) ||
 			 is_inside(&icd->rect_current, rect))) ||
-	    is_smaller(&cam_rect, &target) || is_inside(&cam_rect, &target)) {
+	    is_smaller(cam_rect, &target) || is_inside(cam_rect, &target)) {
 		/*
 		 * The camera failed to configure a suitable cropping,
 		 * we cannot use the current rectangle, set to max
 		 */
-		cam_rect = cam_max;
-		ret = icd->ops->set_crop(icd, &cam_rect);
+		*cam_rect = cam_max;
+		ret = v4l2_subdev_call(sd, video, s_crop, &cam_crop);
 		dev_dbg(&icd->dev, "Camera S_CROP %d for max %ux%u@%u:%u\n",
-			ret, cam_rect.width, cam_rect.height,
-			cam_rect.left, cam_rect.top);
-		if (ret < 0)
+			ret, cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
 			/* All failed, hopefully resume current capture */
 			goto resume_capture;
 
 		/* Finally, adjust the target rectangle */
-		if (target.width > cam_rect.width)
-			target.width = cam_rect.width;
-		if (target.height > cam_rect.height)
-			target.height = cam_rect.height;
-		if (target.left + target.width > cam_rect.left + cam_rect.width)
-			target.left = cam_rect.left + cam_rect.width -
+		if (target.width > cam_rect->width)
+			target.width = cam_rect->width;
+		if (target.height > cam_rect->height)
+			target.height = cam_rect->height;
+		if (target.left + target.width > cam_rect->left + cam_rect->width)
+			target.left = cam_rect->left + cam_rect->width -
 				target.width;
-		if (target.top + target.height > cam_rect.top + cam_rect.height)
-			target.top = cam_rect.top + cam_rect.height -
+		if (target.top + target.height > cam_rect->top + cam_rect->height)
+			target.top = cam_rect->top + cam_rect->height -
 				target.height;
 	}
 
@@ -982,14 +986,14 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
 	 */
 	dev_dbg(&icd->dev,
 		"SH S_CROP from %ux%u@%u:%u to %ux%u@%u:%u, scale to %ux%u@%u:%u\n",
-		cam_rect.width, cam_rect.height, cam_rect.left, cam_rect.top,
+		cam_rect->width, cam_rect->height, cam_rect->left, cam_rect->top,
 		target.width, target.height, target.left, target.top,
 		rect->width, rect->height, rect->left, rect->top);
 
 	ret = 0;
 
 ceu_set_rect:
-	cam->camera_rect = cam_rect;
+	cam->camera_rect = *cam_rect;
 
 	rect->width	= size_dst(target.width, hscale);
 	rect->left	= size_dst(target.left, hscale);
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 1145eb5..fa01cf4 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -797,7 +797,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
 		rect.top = icd->rect_max.height + icd->rect_max.top -
 			rect.height;
 
-	ret = ici->ops->set_crop(icd, &rect);
+	ret = ici->ops->set_crop(icd, a);
 	if (!ret)
 		icd->rect_current = rect;
 
@@ -970,7 +970,7 @@ static int soc_camera_probe(struct device *dev)
 
 		/* FIXME: this is racy, have to use driver-binding notification */
 		control = to_soc_camera_control(icd);
-		if (!control || !control->driver ||
+		if (!control || !control->driver || !dev_get_drvdata(control) ||
 		    !try_module_get(control->driver->owner)) {
 			icl->del_device(icl);
 			goto enodrv;
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index a4f6a26..9c661a3 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -25,10 +25,15 @@ struct soc_camera_platform_priv {
 	struct soc_camera_data_format format;
 };
 
-static struct soc_camera_platform_info *
-soc_camera_platform_get_info(struct soc_camera_device *icd)
+static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev_get_drvdata(&icd->dev));
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	return container_of(subdev, struct soc_camera_platform_priv, subdev);
+}
+
+static struct soc_camera_platform_info *get_info(struct soc_camera_device *icd)
+{
+	struct platform_device *pdev = to_platform_device(to_soc_camera_control(icd));
 	return pdev->dev.platform_data;
 }
 
@@ -47,16 +52,10 @@ static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd,
 static unsigned long
 soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
 {
-	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	struct soc_camera_platform_info *p = get_info(icd);
 	return p->bus_param;
 }
 
-static int soc_camera_platform_set_crop(struct soc_camera_device *icd,
-					struct v4l2_rect *rect)
-{
-	return 0;
-}
-
 static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
 				       struct v4l2_format *f)
 {
@@ -71,7 +70,7 @@ static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
 static void soc_camera_platform_video_probe(struct soc_camera_device *icd,
 					    struct platform_device *pdev)
 {
-	struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev);
+	struct soc_camera_platform_priv *priv = get_priv(pdev);
 	struct soc_camera_platform_info *p = pdev->dev.platform_data;
 
 	priv->format.name = p->format_name;
@@ -96,7 +95,6 @@ static struct v4l2_subdev_ops platform_subdev_ops = {
 };
 
 static struct soc_camera_ops soc_camera_platform_ops = {
-	.set_crop		= soc_camera_platform_set_crop,
 	.set_bus_param		= soc_camera_platform_set_bus_param,
 	.query_bus_param	= soc_camera_platform_query_bus_param,
 };
@@ -124,7 +122,9 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
 
 	icd = to_soc_camera_dev(p->dev);
   
-	platform_set_drvdata(pdev, priv);
+	/* soc-camera convention: control's drvdata points to the subdev */
+	platform_set_drvdata(pdev, &priv->subdev);
+	/* Set the control device reference */
 	dev_set_drvdata(&icd->dev, &pdev->dev);
 
 	icd->width_min		= 0;
@@ -158,7 +158,7 @@ evdrs:
 
 static int soc_camera_platform_remove(struct platform_device *pdev)
 {
-	struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev);
+	struct soc_camera_platform_priv *priv = get_priv(pdev);
 	struct soc_camera_platform_info *p = pdev->dev.platform_data;
 	struct soc_camera_device *icd = to_soc_camera_dev(p->dev);
 
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index 735d0bd..b6b1546 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -616,11 +616,12 @@ static int tw9910_s_register(struct v4l2_subdev *sd,
 }
 #endif
 
-static int tw9910_set_crop(struct soc_camera_device *icd,
-			   struct v4l2_rect *rect)
+static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct v4l2_rect *rect = &a->c;
+	struct i2c_client *client = sd->priv;
 	struct tw9910_priv *priv = to_tw9910(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 	int                 ret  = -EINVAL;
 	u8                  val;
 
@@ -716,15 +717,15 @@ tw9910_set_fmt_error:
 
 static int tw9910_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_pix_format *pix = &f->fmt.pix;
-	/* See tw9910_set_crop() - no proper cropping support */
-	struct v4l2_rect rect = {
-		.left	= 0,
-		.top	= 0,
-		.width	= pix->width,
-		.height	= pix->height,
+	/* See tw9910_s_crop() - no proper cropping support */
+	struct v4l2_crop a = {
+		.c = {
+			.left	= 0,
+			.top	= 0,
+			.width	= pix->width,
+			.height	= pix->height,
+		},
 	};
 	int i, ret;
 
@@ -738,10 +739,10 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
 	if (i == ARRAY_SIZE(tw9910_color_fmt))
 		return -EINVAL;
 
-	ret = tw9910_set_crop(icd, &rect);
+	ret = tw9910_s_crop(sd, &a);
 	if (!ret) {
-		pix->width = rect.width;
-		pix->height = rect.height;
+		pix->width = a.c.width;
+		pix->height = a.c.height;
 	}
 	return ret;
 }
@@ -821,7 +822,6 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
 }
 
 static struct soc_camera_ops tw9910_ops = {
-	.set_crop		= tw9910_set_crop,
 	.set_bus_param		= tw9910_set_bus_param,
 	.query_bus_param	= tw9910_query_bus_param,
 	.enum_input		= tw9910_enum_input,
@@ -840,6 +840,7 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
 	.s_stream	= tw9910_s_stream,
 	.s_fmt		= tw9910_s_fmt,
 	.try_fmt	= tw9910_try_fmt,
+	.s_crop		= tw9910_s_crop,
 };
 
 static struct v4l2_subdev_ops tw9910_subdev_ops = {
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 7c44d40..0bad8f1 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -76,7 +76,7 @@ struct soc_camera_host_ops {
 	int (*get_formats)(struct soc_camera_device *, int,
 			   struct soc_camera_format_xlate *);
 	void (*put_formats)(struct soc_camera_device *);
-	int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *);
+	int (*set_crop)(struct soc_camera_device *, struct v4l2_crop *);
 	int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
 	int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
 	void (*init_videobuf)(struct videobuf_queue *,
@@ -185,7 +185,6 @@ struct soc_camera_ops {
 	int (*resume)(struct soc_camera_device *);
 	int (*init)(struct soc_camera_device *);
 	int (*release)(struct soc_camera_device *);
-	int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *);
 	unsigned long (*query_bus_param)(struct soc_camera_device *);
 	int (*set_bus_param)(struct soc_camera_device *, unsigned long);
 	int (*get_chip_id)(struct soc_camera_device *,
-- 
1.6.2.4

