diff mbox

[5/5] soc-camera: Convert to a platform driver

Message ID Pine.LNX.4.64.0904151403500.4729@axis700.grange (mailing list archive)
State RFC
Headers show

Commit Message

Guennadi Liakhovetski April 15, 2009, 12:20 p.m. UTC
Convert soc-camera core to a platform driver. With this approach I2C
devices are no longer statically registered in platform code, instead they
are registered dynamically by the soc-camera core, when a match with a
host driver is found. With this patch all platforms and all soc-camera
device drivers are converted too. This is a preparatory step for the
v4l-subdev conversion.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---

Ok, here goes the bad guy. Hit it hard, hit it as hard as you can.

Robert, I addressed your wishes from your previous comments, but kept the 
semicolon rearrangement hunk. I think, it is better not to terminate a 
define with a semicolon, if you like, we can make this a separate patch.

 arch/arm/mach-mx3/pcm037.c                 |   25 ++-
 arch/arm/mach-pxa/em-x270.c                |   21 ++-
 arch/arm/mach-pxa/mioa701.c                |   35 ++--
 arch/arm/mach-pxa/pcm990-baseboard.c       |   52 ++++-
 arch/sh/boards/board-ap325rxa.c            |   55 +++--
 arch/sh/boards/mach-migor/setup.c          |   77 ++++--
 drivers/media/video/mt9m001.c              |  113 ++++-----
 drivers/media/video/mt9m111.c              |  152 ++++++------
 drivers/media/video/mt9t031.c              |  113 ++++-----
 drivers/media/video/mt9v022.c              |  118 +++++-----
 drivers/media/video/mx3_camera.c           |   27 ++-
 drivers/media/video/ov772x.c               |  148 +++++++-----
 drivers/media/video/pxa_camera.c           |   27 ++-
 drivers/media/video/sh_mobile_ceu_camera.c |   13 +-
 drivers/media/video/soc_camera.c           |  364 +++++++++++++++-------------
 drivers/media/video/soc_camera_platform.c  |  112 +++++----
 drivers/media/video/tw9910.c               |  106 +++++----
 include/media/soc_camera.h                 |   30 ++-
 include/media/soc_camera_platform.h        |    5 +-
 19 files changed, 894 insertions(+), 699 deletions(-)

Comments

Robert Jarzmik April 15, 2009, 8:36 p.m. UTC | #1
Guennadi Liakhovetski <g.liakhovetski@gmx.de> writes:

> Convert soc-camera core to a platform driver. With this approach I2C
> devices are no longer statically registered in platform code, instead they
> are registered dynamically by the soc-camera core, when a match with a
> host driver is found. With this patch all platforms and all soc-camera
> device drivers are converted too. This is a preparatory step for the
> v4l-subdev conversion.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
>
> Ok, here goes the bad guy. Hit it hard, hit it as hard as you can.
>

> Robert, I addressed your wishes from your previous comments, but kept the 
> semicolon rearrangement hunk. I think, it is better not to terminate a 
> define with a semicolon, if you like, we can make this a separate patch.
Yep, I'd like to. That's because of merge conflict with current patches through
arm tree. It will be easier for Eric or me to handle that other patch conflict,
thus letting the true v4l patch through.

> @@ -754,20 +756,21 @@ static struct platform_device var = {			\
>  		.platform_data = pdata,			\
>  		.parent	= tparent,			\
>  	},						\
> -};
> +}
>  #define MIO_SIMPLE_DEV(var, strname, pdata)	\
>  	MIO_PARENT_DEV(var, strname, NULL, pdata)
>  
> -MIO_SIMPLE_DEV(mioa701_gpio_keys, "gpio-keys",	    &mioa701_gpio_keys_data)
> +MIO_SIMPLE_DEV(mioa701_gpio_keys, "gpio-keys",	    &mioa701_gpio_keys_data);
>  MIO_PARENT_DEV(mioa701_backlight, "pwm-backlight",  &pxa27x_device_pwm0.dev,
>  		&mioa701_backlight_data);
> -MIO_SIMPLE_DEV(mioa701_led,	  "leds-gpio",	    &gpio_led_info)
> -MIO_SIMPLE_DEV(pxa2xx_pcm,	  "pxa2xx-pcm",	    NULL)
> -MIO_SIMPLE_DEV(pxa2xx_ac97,	  "pxa2xx-ac97",    NULL)
> -MIO_PARENT_DEV(mio_wm9713_codec,  "wm9713-codec",   &pxa2xx_ac97.dev, NULL)
> -MIO_SIMPLE_DEV(mioa701_sound,	  "mioa701-wm9713", NULL)
> -MIO_SIMPLE_DEV(mioa701_board,	  "mioa701-board",  NULL)
> +MIO_SIMPLE_DEV(mioa701_led,	  "leds-gpio",	    &gpio_led_info);
> +MIO_SIMPLE_DEV(pxa2xx_pcm,	  "pxa2xx-pcm",	    NULL);
> +MIO_SIMPLE_DEV(pxa2xx_ac97,	  "pxa2xx-ac97",    NULL);
> +MIO_PARENT_DEV(mio_wm9713_codec,  "wm9713-codec",   &pxa2xx_ac97.dev, NULL);
> +MIO_SIMPLE_DEV(mioa701_sound,	  "mioa701-wm9713", NULL);
> +MIO_SIMPLE_DEV(mioa701_board,	  "mioa701-board",  NULL);

>  MIO_SIMPLE_DEV(gpio_vbus,	  "gpio-vbus",      &gpio_vbus_data);
> +MIO_SIMPLE_DEV(mioa701_camera,	  "soc-camera-pdrv",&iclink[0]);
                                                              \
                                                               -> still broken
                                                          (should be &iclink)
> diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
> @@ -917,6 +921,11 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
>  	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
>  		return -ENODEV;
>  
> +	/* Switch master clock on */
> +	ret = soc_camera_video_start(icd, &client->dev);
> +	if (ret)
> +		return ret;
> +
Well, I'd wish to keep only out "return" point where return value is given back
by another function (ie. have goto evid).
The reason behind is when debuggin, it's easier to put one printk("%d", ret),
and see what happened.

As the legacy mt9m111 style is :
 - either return <immediate value>
 - or if single occurence return func(foo)
 - or error path with gotos
I'd like that "return ret" to be transformed into "goto evid" or the like.

> diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
> @@ -794,103 +791,70 @@ static void scan_add_host(struct soc_camera_host *ici)
>  
>  	list_for_each_entry(icd, &devices, list) {
>  		if (icd->iface == ici->nr) {
> +			int ret;
>  			icd->dev.parent = ici->dev;
> -			device_register_link(icd);
> -		}
> -	}
> -
> -	mutex_unlock(&list_lock);
> -}
> -
> -/* return: 0 if no match found or a match found and
> - * device_register() successful, error code otherwise */
> -static int scan_add_device(struct soc_camera_device *icd)
> -{
> -	struct soc_camera_host *ici;
> -	int ret = 0;
> -
> -	mutex_lock(&list_lock);
> -
> -	list_add_tail(&icd->list, &devices);
> -
> -	/* Watch out for class_for_each_device / class_find_device API by
> -	 * Dave Young <hidave.darkstar@gmail.com> */
> -	list_for_each_entry(ici, &hosts, list) {
> -		if (icd->iface == ici->nr) {
> -			ret = 1;
> -			icd->dev.parent = ici->dev;
> -			break;
> +			dev_set_name(&icd->dev, "%u-%u", icd->iface,
> +				     icd->devnum);
> +			ret = device_register(&icd->dev);
> +			if (ret < 0) {
> +				icd->dev.parent = NULL;
> +				dev_err(&icd->dev,
> +					"Cannot register device: %d\n", ret);
> +			}
>  		}
>  	}
>  
>  	mutex_unlock(&list_lock);
> -
> -	if (ret)
> -		ret = device_register_link(icd);
> -
> -	return ret;
>  }
>  
> +static int video_dev_create(struct soc_camera_device *icd);
> +/* Called during host-driver probe */
>  static int soc_camera_probe(struct device *dev)
>  {
>  	struct soc_camera_device *icd = to_soc_camera_dev(dev);
> -	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
> +	struct soc_camera_link *icl = to_soc_camera_link(icd);
>  	int ret;
> +	struct i2c_client *client;
> +	struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
>  
> -	/*
> -	 * Possible race scenario:
> -	 * modprobe <camera-host-driver> triggers __func__
> -	 * at this moment respective <camera-sensor-driver> gets rmmod'ed
> -	 * to protect take module references.
> -	 */
> -
> -	if (!try_module_get(icd->ops->owner)) {
> -		dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
> -		ret = -EINVAL;
> -		goto emgd;
> -	}
> -
> -	if (!try_module_get(ici->ops->owner)) {
> -		dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
> -		ret = -EINVAL;
> -		goto emgi;
> +	if (!adap) {
> +		ret = -ENODEV;
> +		dev_err(dev, "Cannot get I2C adapter %d\n", icl->i2c_adapter_id);
> +		goto ei2cga;
>  	}
>  
> -	mutex_lock(&icd->video_lock);
> +	dev_info(dev, "Probing %s\n", dev_name(dev));
>  
> -	/* We only call ->add() here to activate and probe the camera.
> -	 * We shall ->remove() and deactivate it immediately afterwards. */
> -	ret = ici->ops->add(icd);
> -	if (ret < 0)
> -		goto eiadd;
> +	client = i2c_new_device(adap, icl->board_info);
> +	if (!client) {
> +		ret = -ENOMEM;
> +		goto ei2cnd;
> +	}
>  
> -	ret = icd->ops->probe(icd);
> -	if (ret >= 0) {
> -		const struct v4l2_queryctrl *qctrl;
> +	/*
> +	 * We set icd drvdata at two locations - here and in
> +	 * soc_camera_video_start(). Depending on the module loading /
> +	 * initialisation order one of these locations will be entered first
> +	 */
> +	/* Use to_i2c_client(dev) to recover the i2c client */
> +	dev_set_drvdata(&icd->dev, &client->dev);
I didn't find any reference to unsetting the driver data. Is it normal ?

I must admit I didn't go fully through soc_camera* ... I'll try harder in the
next days.

Cheers.

--
Robert
--
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
Dongsoo Kim April 16, 2009, 2:19 a.m. UTC | #2
Hello Guennadi,


Reviewing your patch, I've got curious about a thing.
I think your soc camera subsystem is covering multiple camera
devices(sensors) in one target board, but if that is true I'm afraid
I'm confused how to handle them properly.
Because according to your patch, video_dev_create() takes camera
device as parameter and it seems to be creating device node for each
camera devices.
It means, if I have one camera host and several camera devices, there
should be several device nodes for camera devices but cannot be used
at the same time. Because typical camera host(camera interface) can
handle only one camera device at a time. But multiple device nodes
mean "we can open and handle them at the same time".

How about registering camera host device as v4l2 device and make
camera device a input device which could be handled using
VIDIOC_S_INPUT/G_INPUT api?

Actually, I'm working on S3C64xx camera interface driver with soc
camera subsystem, and I'm facing that issue right now because I've got
dual camera on my target board.

I hope you to consider this concept, and also want to know your opinion.
Cheers,

Nate

On Wed, Apr 15, 2009 at 9:20 PM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> Convert soc-camera core to a platform driver. With this approach I2C
> devices are no longer statically registered in platform code, instead they
> are registered dynamically by the soc-camera core, when a match with a
> host driver is found. With this patch all platforms and all soc-camera
> device drivers are converted too. This is a preparatory step for the
> v4l-subdev conversion.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
>
> Ok, here goes the bad guy. Hit it hard, hit it as hard as you can.
>
> Robert, I addressed your wishes from your previous comments, but kept the
> semicolon rearrangement hunk. I think, it is better not to terminate a
> define with a semicolon, if you like, we can make this a separate patch.
>
>  arch/arm/mach-mx3/pcm037.c                 |   25 ++-
>  arch/arm/mach-pxa/em-x270.c                |   21 ++-
>  arch/arm/mach-pxa/mioa701.c                |   35 ++--
>  arch/arm/mach-pxa/pcm990-baseboard.c       |   52 ++++-
>  arch/sh/boards/board-ap325rxa.c            |   55 +++--
>  arch/sh/boards/mach-migor/setup.c          |   77 ++++--
>  drivers/media/video/mt9m001.c              |  113 ++++-----
>  drivers/media/video/mt9m111.c              |  152 ++++++------
>  drivers/media/video/mt9t031.c              |  113 ++++-----
>  drivers/media/video/mt9v022.c              |  118 +++++-----
>  drivers/media/video/mx3_camera.c           |   27 ++-
>  drivers/media/video/ov772x.c               |  148 +++++++-----
>  drivers/media/video/pxa_camera.c           |   27 ++-
>  drivers/media/video/sh_mobile_ceu_camera.c |   13 +-
>  drivers/media/video/soc_camera.c           |  364 +++++++++++++++-------------
>  drivers/media/video/soc_camera_platform.c  |  112 +++++----
>  drivers/media/video/tw9910.c               |  106 +++++----
>  include/media/soc_camera.h                 |   30 ++-
>  include/media/soc_camera_platform.h        |    5 +-
>  19 files changed, 894 insertions(+), 699 deletions(-)
>
> diff --git a/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c
> index 6bfd29a..00ce1eb 100644
> --- a/arch/arm/mach-mx3/pcm037.c
> +++ b/arch/arm/mach-mx3/pcm037.c
> @@ -241,9 +241,17 @@ static int pcm037_camera_power(struct device *dev, int on)
>        return 0;
>  }
>
> +static struct i2c_board_info pcm037_i2c_2_devices[] = {
> +       {
> +               I2C_BOARD_INFO("mt9t031", 0x5d),
> +       },
> +};
> +
>  static struct soc_camera_link iclink = {
> -       .bus_id = 0,                    /* Must match with the camera ID */
> -       .power = pcm037_camera_power,
> +       .bus_id         = 0,            /* Must match with the camera ID */
> +       .power          = pcm037_camera_power,
> +       .board_info     = &pcm037_i2c_2_devices[0],
> +       .i2c_adapter_id = 2,
>  };
>
>  static struct i2c_board_info pcm037_i2c_devices[] = {
> @@ -256,9 +264,10 @@ static struct i2c_board_info pcm037_i2c_devices[] = {
>        }
>  };
>
> -static struct i2c_board_info pcm037_i2c_2_devices[] = {
> -       {
> -               I2C_BOARD_INFO("mt9t031", 0x5d),
> +static struct platform_device pcm037_camera = {
> +       .name   = "soc-camera-pdrv",
> +       .id     = 0,
> +       .dev    = {
>                .platform_data = &iclink,
>        },
>  };
> @@ -338,6 +347,9 @@ static struct platform_device *devices[] __initdata = {
>        &pcm037_flash,
>        &pcm037_eth,
>        &pcm037_sram_device,
> +#if defined(CONFIG_I2C_IMX) || defined(CONFIG_I2C_IMX_MODULE)
> +       &pcm037_camera,
> +#endif
>  };
>
>  static struct ipu_platform_data mx3_ipu_data = {
> @@ -395,9 +407,6 @@ static void __init mxc_board_init(void)
>        i2c_register_board_info(1, pcm037_i2c_devices,
>                        ARRAY_SIZE(pcm037_i2c_devices));
>
> -       i2c_register_board_info(2, pcm037_i2c_2_devices,
> -                       ARRAY_SIZE(pcm037_i2c_2_devices));
> -
>        mxc_register_device(&mxc_i2c_device1, &pcm037_i2c_1_data);
>        mxc_register_device(&mxc_i2c_device2, &pcm037_i2c_2_data);
>  #endif
> diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
> index 920dfb8..d4eb0c7 100644
> --- a/arch/arm/mach-pxa/em-x270.c
> +++ b/arch/arm/mach-pxa/em-x270.c
> @@ -847,14 +847,23 @@ static int em_x270_sensor_power(struct device *dev, int on)
>        return 0;
>  }
>
> -static struct soc_camera_link iclink = {
> -       .bus_id = 0,
> -       .power = em_x270_sensor_power,
> -};
> -
>  static struct i2c_board_info em_x270_i2c_cam_info[] = {
>        {
>                I2C_BOARD_INFO("mt9m111", 0x48),
> +       },
> +};
> +
> +static struct soc_camera_link iclink = {
> +       .bus_id         = 0,
> +       .power          = em_x270_sensor_power,
> +       .board_info     = &em_x270_i2c_cam_info[0],
> +       .i2c_adapter_id = 0,
> +};
> +
> +static struct platform_device em_x270_camera = {
> +       .name   = "soc-camera-pdrv",
> +       .id     = -1,
> +       .dev    = {
>                .platform_data = &iclink,
>        },
>  };
> @@ -866,8 +875,8 @@ static struct i2c_pxa_platform_data em_x270_i2c_info = {
>  static void  __init em_x270_init_camera(void)
>  {
>        pxa_set_i2c_info(&em_x270_i2c_info);
> -       i2c_register_board_info(0, ARRAY_AND_SIZE(em_x270_i2c_cam_info));
>        pxa_set_camera_info(&em_x270_camera_platform_data);
> +       platform_device_register(&em_x270_camera);
>  }
>  #else
>  static inline void em_x270_init_camera(void) {}
> diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
> index 97c93a7..444818b 100644
> --- a/arch/arm/mach-pxa/mioa701.c
> +++ b/arch/arm/mach-pxa/mioa701.c
> @@ -724,19 +724,21 @@ struct pxacamera_platform_data mioa701_pxacamera_platform_data = {
>        .mclk_10khz = 5000,
>  };
>
> -static struct soc_camera_link iclink = {
> -       .bus_id = 0, /* Must match id in pxa27x_device_camera in device.c */
> -};
> -
> -/* Board I2C devices. */
> +/*
> + * Board I2C devices
> + */
>  static struct i2c_board_info __initdata mioa701_i2c_devices[] = {
>        {
> -               /* Must initialize before the camera(s) */
>                I2C_BOARD_INFO("mt9m111", 0x5d),
> -               .platform_data = &iclink,
>        },
>  };
>
> +static struct soc_camera_link iclink = {
> +       .bus_id         = 0, /* Match id in pxa27x_device_camera in device.c */
> +       .board_info     = &mioa701_i2c_devices[0],
> +       .i2c_adapter_id = 0,
> +};
> +
>  struct i2c_pxa_platform_data i2c_pdata = {
>        .fast_mode = 1,
>  };
> @@ -754,20 +756,21 @@ static struct platform_device var = {                     \
>                .platform_data = pdata,                 \
>                .parent = tparent,                      \
>        },                                              \
> -};
> +}
>  #define MIO_SIMPLE_DEV(var, strname, pdata)    \
>        MIO_PARENT_DEV(var, strname, NULL, pdata)
>
> -MIO_SIMPLE_DEV(mioa701_gpio_keys, "gpio-keys",     &mioa701_gpio_keys_data)
> +MIO_SIMPLE_DEV(mioa701_gpio_keys, "gpio-keys",     &mioa701_gpio_keys_data);
>  MIO_PARENT_DEV(mioa701_backlight, "pwm-backlight",  &pxa27x_device_pwm0.dev,
>                &mioa701_backlight_data);
> -MIO_SIMPLE_DEV(mioa701_led,      "leds-gpio",      &gpio_led_info)
> -MIO_SIMPLE_DEV(pxa2xx_pcm,       "pxa2xx-pcm",     NULL)
> -MIO_SIMPLE_DEV(pxa2xx_ac97,      "pxa2xx-ac97",    NULL)
> -MIO_PARENT_DEV(mio_wm9713_codec,  "wm9713-codec",   &pxa2xx_ac97.dev, NULL)
> -MIO_SIMPLE_DEV(mioa701_sound,    "mioa701-wm9713", NULL)
> -MIO_SIMPLE_DEV(mioa701_board,    "mioa701-board",  NULL)
> +MIO_SIMPLE_DEV(mioa701_led,      "leds-gpio",      &gpio_led_info);
> +MIO_SIMPLE_DEV(pxa2xx_pcm,       "pxa2xx-pcm",     NULL);
> +MIO_SIMPLE_DEV(pxa2xx_ac97,      "pxa2xx-ac97",    NULL);
> +MIO_PARENT_DEV(mio_wm9713_codec,  "wm9713-codec",   &pxa2xx_ac97.dev, NULL);
> +MIO_SIMPLE_DEV(mioa701_sound,    "mioa701-wm9713", NULL);
> +MIO_SIMPLE_DEV(mioa701_board,    "mioa701-board",  NULL);
>  MIO_SIMPLE_DEV(gpio_vbus,        "gpio-vbus",      &gpio_vbus_data);
> +MIO_SIMPLE_DEV(mioa701_camera,   "soc-camera-pdrv",&iclink[0]);
>
>  static struct platform_device *devices[] __initdata = {
>        &mioa701_gpio_keys,
> @@ -780,6 +783,7 @@ static struct platform_device *devices[] __initdata = {
>        &power_dev,
>        &strataflash,
>        &gpio_vbus,
> +       &mioa701_camera,
>        &mioa701_board,
>  };
>
> @@ -825,7 +829,6 @@ static void __init mioa701_machine_init(void)
>
>        pxa_set_i2c_info(&i2c_pdata);
>        pxa_set_camera_info(&mioa701_pxacamera_platform_data);
> -       i2c_register_board_info(0, ARRAY_AND_SIZE(mioa701_i2c_devices));
>  }
>
>  static void mioa701_machine_exit(void)
> diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
> index 9ce1ef2..619b90e 100644
> --- a/arch/arm/mach-pxa/pcm990-baseboard.c
> +++ b/arch/arm/mach-pxa/pcm990-baseboard.c
> @@ -427,25 +427,54 @@ static void pcm990_camera_free_bus(struct soc_camera_link *link)
>        gpio_bus_switch = -EINVAL;
>  }
>
> -static struct soc_camera_link iclink = {
> -       .bus_id = 0, /* Must match with the camera ID above */
> -       .query_bus_param = pcm990_camera_query_bus_param,
> -       .set_bus_param = pcm990_camera_set_bus_param,
> -       .free_bus = pcm990_camera_free_bus,
> -};
> -
>  /* Board I2C devices. */
>  static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
>        {
>                /* Must initialize before the camera(s) */
>                I2C_BOARD_INFO("pca9536", 0x41),
>                .platform_data = &pca9536_data,
> -       }, {
> +       },
> +};
> +
> +static struct i2c_board_info __initdata pcm990_camera_i2c[] = {
> +       {
>                I2C_BOARD_INFO("mt9v022", 0x48),
> -               .platform_data = &iclink, /* With extender */
>        }, {
>                I2C_BOARD_INFO("mt9m001", 0x5d),
> -               .platform_data = &iclink, /* With extender */
> +       },
> +};
> +
> +static struct soc_camera_link iclink[] = {
> +       {
> +               .bus_id                 = 0, /* Must match with the camera ID */
> +               .board_info             = &pcm990_camera_i2c[0],
> +               .i2c_adapter_id         = 0,
> +               .query_bus_param        = pcm990_camera_query_bus_param,
> +               .set_bus_param          = pcm990_camera_set_bus_param,
> +               .free_bus               = pcm990_camera_free_bus,
> +       }, {
> +               .bus_id                 = 0, /* Must match with the camera ID */
> +               .board_info             = &pcm990_camera_i2c[1],
> +               .i2c_adapter_id         = 0,
> +               .query_bus_param        = pcm990_camera_query_bus_param,
> +               .set_bus_param          = pcm990_camera_set_bus_param,
> +               .free_bus               = pcm990_camera_free_bus,
> +       },
> +};
> +
> +static struct platform_device pcm990_camera[] = {
> +       {
> +               .name   = "soc-camera-pdrv",
> +               .id     = 0,
> +               .dev    = {
> +                       .platform_data = &iclink[0],
> +               },
> +       }, {
> +               .name   = "soc-camera-pdrv",
> +               .id     = 1,
> +               .dev    = {
> +                       .platform_data = &iclink[1],
> +               },
>        },
>  };
>  #endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
> @@ -501,6 +530,9 @@ void __init pcm990_baseboard_init(void)
>        pxa_set_camera_info(&pcm990_pxacamera_platform_data);
>
>        i2c_register_board_info(0, ARRAY_AND_SIZE(pcm990_i2c_devices));
> +
> +       platform_device_register(&pcm990_camera[0]);
> +       platform_device_register(&pcm990_camera[1]);
>  #endif
>
>        printk(KERN_INFO "PCM-990 Evaluation baseboard initialized\n");
> diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c
> index e27655b..37c9139 100644
> --- a/arch/sh/boards/board-ap325rxa.c
> +++ b/arch/sh/boards/board-ap325rxa.c
> @@ -228,12 +228,6 @@ static struct platform_device lcdc_device = {
>        },
>  };
>
> -static void camera_power(int val)
> -{
> -       gpio_set_value(GPIO_PTZ5, val); /* RST_CAM/RSTB */
> -       mdelay(10);
> -}
> -
>  #ifdef CONFIG_I2C
>  static unsigned char camera_ncm03j_magic[] =
>  {
> @@ -255,23 +249,28 @@ static unsigned char camera_ncm03j_magic[] =
>        0x63, 0xD4, 0x64, 0xEA, 0xD6, 0x0F,
>  };
>
> -static int camera_set_capture(struct soc_camera_platform_info *info,
> -                             int enable)
> +static int ap325rxa_camera_power(struct device *dev, int on)
>  {
> -       struct i2c_adapter *a = i2c_get_adapter(0);
> +       gpio_set_value(GPIO_PTZ5, on); /* RST_CAM/RSTB */
> +       mdelay(10);
> +       return 0;
> +}
> +
> +static int ap325rxa_camera_set_capture(struct soc_camera_platform_info *info,
> +                                      int enable)
> +{
> +       struct i2c_adapter *a = i2c_get_adapter(info->link.i2c_adapter_id);
>        struct i2c_msg msg;
>        int ret = 0;
>        int i;
>
> -       camera_power(0);
>        if (!enable)
> -               return 0; /* no disable for now */
> +               return ap325rxa_camera_power(NULL, 0); /* no disable for now */
>
> -       camera_power(1);
>        for (i = 0; i < ARRAY_SIZE(camera_ncm03j_magic); i += 2) {
>                u_int8_t buf[8];
>
> -               msg.addr = 0x6e;
> +               msg.addr = info->link.board_info->addr;
>                msg.buf = buf;
>                msg.len = 2;
>                msg.flags = 0;
> @@ -285,8 +284,11 @@ static int camera_set_capture(struct soc_camera_platform_info *info,
>        return ret;
>  }
>
> +static struct i2c_board_info __initdata ap325rxa_camera_i2c = {
> +       I2C_BOARD_INFO("soc_camera_platform", 0x6e),
> +};
> +
>  static struct soc_camera_platform_info camera_info = {
> -       .iface = 0,
>        .format_name = "UYVY",
>        .format_depth = 16,
>        .format = {
> @@ -296,22 +298,29 @@ static struct soc_camera_platform_info camera_info = {
>                .height = 480,
>        },
>        .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
> -       SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
> -       .set_capture = camera_set_capture,
> +               SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
> +       .set_capture = ap325rxa_camera_set_capture,
> +       .link = {
> +               .bus_id = 0,
> +               .board_info = &ap325rxa_camera_i2c,
> +               .i2c_adapter_id = 0,
> +               .power = ap325rxa_camera_power,
> +       },
>  };
>
> -static struct platform_device camera_device = {
> -       .name           = "soc_camera_platform",
> -       .dev            = {
> -               .platform_data  = &camera_info,
> +static struct platform_device ap325rxa_camera = {
> +       .name   = "soc-camera-pdrv",
> +       .id     = -1,
> +       .dev    = {
> +               .platform_data = &camera_info.link,
>        },
>  };
>  #endif /* CONFIG_I2C */
>
>  static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
>        .flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
> -       SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER |
> -       SOCAM_DATAWIDTH_8,
> +               SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH |
> +               SOCAM_MASTER | SOCAM_DATAWIDTH_8,
>  };
>
>  static struct resource ceu_resources[] = {
> @@ -360,7 +369,7 @@ static struct platform_device *ap325rxa_devices[] __initdata = {
>        &lcdc_device,
>        &ceu_device,
>  #ifdef CONFIG_I2C
> -       &camera_device,
> +       &ap325rxa_camera,
>  #endif
>        &nand_flash_device,
>        &sdcard_cn3_device,
> diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
> index 4fd6a72..b8cb246 100644
> --- a/arch/sh/boards/mach-migor/setup.c
> +++ b/arch/sh/boards/mach-migor/setup.c
> @@ -383,21 +383,6 @@ static struct platform_device migor_ceu_device = {
>        },
>  };
>
> -static struct ov772x_camera_info ov7725_info = {
> -       .buswidth  = SOCAM_DATAWIDTH_8,
> -       .link = {
> -               .power  = ov7725_power,
> -       },
> -};
> -
> -static struct tw9910_video_info tw9910_info = {
> -       .buswidth = SOCAM_DATAWIDTH_8,
> -       .mpout    = TW9910_MPO_FIELD,
> -       .link = {
> -               .power  = tw9910_power,
> -       }
> -};
> -
>  struct spi_gpio_platform_data sdcard_cn9_platform_data = {
>        .sck = GPIO_PTD0,
>        .mosi = GPIO_PTD1,
> @@ -412,16 +397,6 @@ static struct platform_device sdcard_cn9_device = {
>        },
>  };
>
> -static struct platform_device *migor_devices[] __initdata = {
> -       &smc91x_eth_device,
> -       &sh_keysc_device,
> -       &migor_lcdc_device,
> -       &migor_ceu_device,
> -       &migor_nor_flash_device,
> -       &migor_nand_flash_device,
> -       &sdcard_cn9_device,
> -};
> -
>  static struct i2c_board_info migor_i2c_devices[] = {
>        {
>                I2C_BOARD_INFO("rs5c372b", 0x32),
> @@ -430,16 +405,64 @@ static struct i2c_board_info migor_i2c_devices[] = {
>                I2C_BOARD_INFO("migor_ts", 0x51),
>                .irq = 38, /* IRQ6 */
>        },
> +};
> +
> +static struct i2c_board_info migor_camera_i2c[] = {
>        {
>                I2C_BOARD_INFO("ov772x", 0x21),
> -               .platform_data = &ov7725_info,
>        },
>        {
>                I2C_BOARD_INFO("tw9910", 0x45),
> -               .platform_data = &tw9910_info,
>        },
>  };
>
> +static struct ov772x_camera_info ov7725_info = {
> +       .buswidth  = SOCAM_DATAWIDTH_8,
> +       .link = {
> +               .power  = ov7725_power,
> +               .board_info             = &migor_camera_i2c[0],
> +               .i2c_adapter_id         = 0,
> +       },
> +};
> +
> +static struct tw9910_video_info tw9910_info = {
> +       .buswidth = SOCAM_DATAWIDTH_8,
> +       .mpout    = TW9910_MPO_FIELD,
> +       .link = {
> +               .power  = tw9910_power,
> +               .board_info             = &migor_camera_i2c[1],
> +               .i2c_adapter_id         = 0,
> +       }
> +};
> +
> +static struct platform_device migor_camera[] = {
> +       {
> +               .name   = "soc-camera-pdrv",
> +               .id     = 0,
> +               .dev    = {
> +                       .platform_data = &ov7725_info.link,
> +               },
> +       }, {
> +               .name   = "soc-camera-pdrv",
> +               .id     = 1,
> +               .dev    = {
> +                       .platform_data = &tw9910_info.link,
> +               },
> +       },
> +};
> +
> +static struct platform_device *migor_devices[] __initdata = {
> +       &smc91x_eth_device,
> +       &sh_keysc_device,
> +       &migor_lcdc_device,
> +       &migor_ceu_device,
> +       &migor_nor_flash_device,
> +       &migor_nand_flash_device,
> +       &sdcard_cn9_device,
> +       &migor_camera[0],
> +       &migor_camera[1],
> +};
> +
>  static struct spi_board_info migor_spi_devices[] = {
>        {
>                .modalias = "mmc_spi",
> diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
> index 459c04c..b0f4ad5 100644
> --- a/drivers/media/video/mt9m001.c
> +++ b/drivers/media/video/mt9m001.c
> @@ -69,8 +69,6 @@ static const struct soc_camera_data_format mt9m001_monochrome_formats[] = {
>  };
>
>  struct mt9m001 {
> -       struct i2c_client *client;
> -       struct soc_camera_device icd;
>        int model;      /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
>        unsigned char autoexposure;
>  };
> @@ -111,11 +109,11 @@ static int reg_clear(struct i2c_client *client, const u8 reg,
>
>  static int mt9m001_init(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        int ret;
>
> -       dev_dbg(icd->vdev->parent, "%s\n", __func__);
> +       dev_dbg(&icd->dev, "%s\n", __func__);
>
>        if (icl->power) {
>                ret = icl->power(&client->dev, 1);
> @@ -147,8 +145,8 @@ static int mt9m001_init(struct soc_camera_device *icd)
>
>  static int mt9m001_release(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>
>        /* Disable the chip */
>        reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
> @@ -161,7 +159,7 @@ static int mt9m001_release(struct soc_camera_device *icd)
>
>  static int mt9m001_start_capture(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        /* Switch to master "normal" mode */
>        if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0)
> @@ -171,7 +169,7 @@ static int mt9m001_start_capture(struct soc_camera_device *icd)
>
>  static int mt9m001_stop_capture(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        /* Stop sensor readout */
>        if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0)
> @@ -182,8 +180,7 @@ static int mt9m001_stop_capture(struct soc_camera_device *icd)
>  static int mt9m001_set_bus_param(struct soc_camera_device *icd,
>                                 unsigned long flags)
>  {
> -       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
> -       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
>
>        /* Only one width bit may be set */
> @@ -205,8 +202,7 @@ static int mt9m001_set_bus_param(struct soc_camera_device *icd,
>
>  static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
>  {
> -       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
> -       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        /* MT9M001 has all capture_format parameters fixed */
>        unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING |
>                SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
> @@ -223,8 +219,8 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
>  static int mt9m001_set_crop(struct soc_camera_device *icd,
>                            struct v4l2_rect *rect)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
>        int ret;
>        const u16 hblank = 9, vblank = 25;
>
> @@ -296,12 +292,13 @@ static int mt9m001_try_fmt(struct soc_camera_device *icd,
>  static int mt9m001_get_chip_id(struct soc_camera_device *icd,
>                               struct v4l2_dbg_chip_ident *id)
>  {
> -       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
>
>        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
>                return -EINVAL;
>
> -       if (id->match.addr != mt9m001->client->addr)
> +       if (id->match.addr != client->addr)
>                return -ENODEV;
>
>        id->ident       = mt9m001->model;
> @@ -314,7 +311,7 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd,
>  static int mt9m001_get_register(struct soc_camera_device *icd,
>                                struct v4l2_dbg_register *reg)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
>                return -EINVAL;
> @@ -334,7 +331,7 @@ static int mt9m001_get_register(struct soc_camera_device *icd,
>  static int mt9m001_set_register(struct soc_camera_device *icd,
>                                struct v4l2_dbg_register *reg)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
>                return -EINVAL;
> @@ -387,15 +384,11 @@ static const struct v4l2_queryctrl mt9m001_controls[] = {
>        }
>  };
>
> -static int mt9m001_video_probe(struct soc_camera_device *);
> -static void mt9m001_video_remove(struct soc_camera_device *);
>  static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *);
>  static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *);
>
>  static struct soc_camera_ops mt9m001_ops = {
>        .owner                  = THIS_MODULE,
> -       .probe                  = mt9m001_video_probe,
> -       .remove                 = mt9m001_video_remove,
>        .init                   = mt9m001_init,
>        .release                = mt9m001_release,
>        .start_capture          = mt9m001_start_capture,
> @@ -418,8 +411,8 @@ static struct soc_camera_ops mt9m001_ops = {
>
>  static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
>        int data;
>
>        switch (ctrl->id) {
> @@ -438,8 +431,8 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro
>
>  static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
>        const struct v4l2_queryctrl *qctrl;
>        int data;
>
> @@ -531,11 +524,11 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
>
>  /* Interface active, can use i2c. If it fails, it can indeed mean, that
>  * this wasn't our capture interface, so, we wait for the right one */
> -static int mt9m001_video_probe(struct soc_camera_device *icd)
> +static int mt9m001_video_probe(struct soc_camera_device *icd,
> +                              struct i2c_client *client)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        s32 data;
>        int ret;
>        unsigned long flags;
> @@ -546,6 +539,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
>            to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
>                return -ENODEV;
>
> +       /* Switch master clock on */
> +       ret = soc_camera_video_start(icd, &client->dev);
> +       if (ret)
> +               return ret;
> +
>        /* Enable the chip */
>        data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
>        dev_dbg(&icd->dev, "write: %d\n", data);
> @@ -553,6 +551,8 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
>        /* Read out the chip version register */
>        data = reg_read(client, MT9M001_CHIP_VERSION);
>
> +       soc_camera_video_stop(icd);
> +
>        /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
>        switch (data) {
>        case 0x8411:
> @@ -565,10 +565,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
>                icd->formats = mt9m001_monochrome_formats;
>                break;
>        default:
> -               ret = -ENODEV;
>                dev_err(&icd->dev,
>                        "No MT9M001 chip detected, register read %x\n", data);
> -               goto ei2c;
> +               return -ENODEV;
>        }
>
>        icd->num_formats = 0;
> @@ -594,26 +593,17 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
>        dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
>                 data == 0x8431 ? "C12STM" : "C12ST");
>
> -       /* Now that we know the model, we can start video */
> -       ret = soc_camera_video_start(icd);
> -       if (ret)
> -               goto eisis;
> -
>        return 0;
> -
> -eisis:
> -ei2c:
> -       return ret;
>  }
>
>  static void mt9m001_video_remove(struct soc_camera_device *icd)
>  {
> -       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
> -       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>
> -       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
> +       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr,
>                icd->dev.parent, icd->vdev);
> -       soc_camera_video_stop(icd);
> +       icd->ops = NULL;
>        if (icl->free_bus)
>                icl->free_bus(icl);
>  }
> @@ -622,11 +612,17 @@ static int mt9m001_probe(struct i2c_client *client,
>                         const struct i2c_device_id *did)
>  {
>        struct mt9m001 *mt9m001;
> -       struct soc_camera_device *icd;
> +       struct soc_camera_device *icd = client->dev.platform_data;
>        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct soc_camera_link *icl;
>        int ret;
>
> +       if (!icd) {
> +               dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
> +               return -EINVAL;
> +       }
> +
> +       icl = to_soc_camera_link(icd);
>        if (!icl) {
>                dev_err(&client->dev, "MT9M001 driver needs platform data\n");
>                return -EINVAL;
> @@ -642,13 +638,10 @@ static int mt9m001_probe(struct i2c_client *client,
>        if (!mt9m001)
>                return -ENOMEM;
>
> -       mt9m001->client = client;
>        i2c_set_clientdata(client, mt9m001);
>
>        /* Second stage probe - when a capture adapter is there */
> -       icd = &mt9m001->icd;
>        icd->ops        = &mt9m001_ops;
> -       icd->control    = &client->dev;
>        icd->x_min      = 20;
>        icd->y_min      = 12;
>        icd->x_current  = 20;
> @@ -658,27 +651,27 @@ static int mt9m001_probe(struct i2c_client *client,
>        icd->height_min = 32;
>        icd->height_max = 1024;
>        icd->y_skip_top = 1;
> -       icd->iface      = icl->bus_id;
>        /* Simulated autoexposure. If enabled, we calculate shutter width
>         * ourselves in the driver based on vertical blanking and frame width */
>        mt9m001->autoexposure = 1;
>
> -       ret = soc_camera_device_register(icd);
> -       if (ret)
> -               goto eisdr;
> -
> -       return 0;
> +       ret = mt9m001_video_probe(icd, client);
> +       if (ret) {
> +               i2c_set_clientdata(client, NULL);
> +               kfree(mt9m001);
> +       }
>
> -eisdr:
> -       kfree(mt9m001);
>        return ret;
>  }
>
>  static int mt9m001_remove(struct i2c_client *client)
>  {
>        struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
> +       struct soc_camera_device *icd = client->dev.platform_data;
>
> -       soc_camera_device_unregister(&mt9m001->icd);
> +       mt9m001_video_remove(icd);
> +       i2c_set_clientdata(client, NULL);
> +       client->driver = NULL;
>        kfree(mt9m001);
>
>        return 0;
> diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
> index fc5e2de..330753a 100644
> --- a/drivers/media/video/mt9m111.c
> +++ b/drivers/media/video/mt9m111.c
> @@ -148,8 +148,6 @@ enum mt9m111_context {
>  };
>
>  struct mt9m111 {
> -       struct i2c_client *client;
> -       struct soc_camera_device icd;
>        int model;      /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
>        enum mt9m111_context context;
>        struct v4l2_rect rect;
> @@ -203,7 +201,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
>
>        ret = reg_page_map_set(client, reg);
>        if (!ret)
> -               ret = i2c_smbus_write_word_data(client, (reg & 0xff),
> +               ret = i2c_smbus_write_word_data(client, reg & 0xff,
>                                                swab16(data));
>        dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
>        return ret;
> @@ -232,7 +230,7 @@ static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
>  static int mt9m111_set_context(struct soc_camera_device *icd,
>                               enum mt9m111_context ctxt)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>        int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
>                | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
>                | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
> @@ -249,8 +247,8 @@ static int mt9m111_set_context(struct soc_camera_device *icd,
>  static int mt9m111_setup_rect(struct soc_camera_device *icd,
>                              struct v4l2_rect *rect)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret, is_raw_format;
>        int width = rect->width;
>        int height = rect->height;
> @@ -294,7 +292,7 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd,
>
>  static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>        int ret;
>
>        ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
> @@ -315,7 +313,8 @@ static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd)
>
>  static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int val = 0;
>
>        if (mt9m111->swap_rgb_red_blue)
> @@ -329,7 +328,8 @@ static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
>
>  static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int val = 0;
>
>        if (mt9m111->swap_rgb_red_blue)
> @@ -343,7 +343,8 @@ static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
>
>  static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int val = 0;
>
>        if (mt9m111->swap_yuv_cb_cr)
> @@ -356,9 +357,9 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
>
>  static int mt9m111_enable(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret;
>
>        if (icl->power) {
> @@ -378,9 +379,9 @@ static int mt9m111_enable(struct soc_camera_device *icd)
>
>  static int mt9m111_disable(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret;
>
>        ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
> @@ -395,8 +396,8 @@ static int mt9m111_disable(struct soc_camera_device *icd)
>
>  static int mt9m111_reset(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        int ret;
>
>        ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
> @@ -424,8 +425,7 @@ static int mt9m111_stop_capture(struct soc_camera_device *icd)
>
>  static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> -       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
>                SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
>                SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
> @@ -441,7 +441,8 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
>  static int mt9m111_set_crop(struct soc_camera_device *icd,
>                            struct v4l2_rect *rect)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret;
>
>        dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
> @@ -456,7 +457,8 @@ static int mt9m111_set_crop(struct soc_camera_device *icd,
>
>  static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret;
>
>        switch (pixfmt) {
> @@ -506,7 +508,8 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
>  static int mt9m111_set_fmt(struct soc_camera_device *icd,
>                           struct v4l2_format *f)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        struct v4l2_pix_format *pix = &f->fmt.pix;
>        struct v4l2_rect rect = {
>                .left   = mt9m111->rect.left,
> @@ -544,12 +547,13 @@ static int mt9m111_try_fmt(struct soc_camera_device *icd,
>  static int mt9m111_get_chip_id(struct soc_camera_device *icd,
>                               struct v4l2_dbg_chip_ident *id)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>
>        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
>                return -EINVAL;
>
> -       if (id->match.addr != mt9m111->client->addr)
> +       if (id->match.addr != client->addr)
>                return -ENODEV;
>
>        id->ident       = mt9m111->model;
> @@ -562,8 +566,8 @@ static int mt9m111_get_chip_id(struct soc_camera_device *icd,
>  static int mt9m111_get_register(struct soc_camera_device *icd,
>                                struct v4l2_dbg_register *reg)
>  {
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>        int val;
> -       struct i2c_client *client = to_i2c_client(icd->control);
>
>        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
>                return -EINVAL;
> @@ -583,7 +587,7 @@ static int mt9m111_get_register(struct soc_camera_device *icd,
>  static int mt9m111_set_register(struct soc_camera_device *icd,
>                                struct v4l2_dbg_register *reg)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
>                return -EINVAL;
> @@ -635,8 +639,6 @@ static const struct v4l2_queryctrl mt9m111_controls[] = {
>        }
>  };
>
> -static int mt9m111_video_probe(struct soc_camera_device *);
> -static void mt9m111_video_remove(struct soc_camera_device *);
>  static int mt9m111_get_control(struct soc_camera_device *,
>                               struct v4l2_control *);
>  static int mt9m111_set_control(struct soc_camera_device *,
> @@ -647,8 +649,6 @@ static int mt9m111_release(struct soc_camera_device *icd);
>
>  static struct soc_camera_ops mt9m111_ops = {
>        .owner                  = THIS_MODULE,
> -       .probe                  = mt9m111_video_probe,
> -       .remove                 = mt9m111_video_remove,
>        .init                   = mt9m111_init,
>        .resume                 = mt9m111_resume,
>        .release                = mt9m111_release,
> @@ -672,8 +672,8 @@ static struct soc_camera_ops mt9m111_ops = {
>
>  static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret;
>
>        if (mt9m111->context == HIGHPOWER) {
> @@ -693,7 +693,7 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
>
>  static int mt9m111_get_global_gain(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>        int data;
>
>        data = reg_read(GLOBAL_GAIN);
> @@ -705,7 +705,7 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd)
>
>  static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>        u16 val;
>
>        if (gain > 63 * 2 * 2)
> @@ -724,8 +724,8 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
>
>  static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret;
>
>        if (on)
> @@ -741,8 +741,8 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
>
>  static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret;
>
>        if (on)
> @@ -759,8 +759,8 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
>  static int mt9m111_get_control(struct soc_camera_device *icd,
>                               struct v4l2_control *ctrl)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int data;
>
>        switch (ctrl->id) {
> @@ -803,7 +803,8 @@ static int mt9m111_get_control(struct soc_camera_device *icd,
>  static int mt9m111_set_control(struct soc_camera_device *icd,
>                               struct v4l2_control *ctrl)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        const struct v4l2_queryctrl *qctrl;
>        int ret;
>
> @@ -841,7 +842,8 @@ static int mt9m111_set_control(struct soc_camera_device *icd,
>
>  static int mt9m111_restore_state(struct soc_camera_device *icd)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>
>        mt9m111_set_context(icd, mt9m111->context);
>        mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
> @@ -856,7 +858,8 @@ static int mt9m111_restore_state(struct soc_camera_device *icd)
>
>  static int mt9m111_resume(struct soc_camera_device *icd)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret = 0;
>
>        if (mt9m111->powered) {
> @@ -871,7 +874,8 @@ static int mt9m111_resume(struct soc_camera_device *icd)
>
>  static int mt9m111_init(struct soc_camera_device *icd)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        int ret;
>
>        mt9m111->context = HIGHPOWER;
> @@ -902,10 +906,10 @@ static int mt9m111_release(struct soc_camera_device *icd)
>  * Interface active, can use i2c. If it fails, it can indeed mean, that
>  * this wasn't our capture interface, so, we wait for the right one
>  */
> -static int mt9m111_video_probe(struct soc_camera_device *icd)
> +static int mt9m111_video_probe(struct soc_camera_device *icd,
> +                              struct i2c_client *client)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
>        s32 data;
>        int ret;
>
> @@ -917,6 +921,11 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
>            to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
>                return -ENODEV;
>
> +       /* Switch master clock on */
> +       ret = soc_camera_video_start(icd, &client->dev);
> +       if (ret)
> +               return ret;
> +
>        ret = mt9m111_enable(icd);
>        if (ret)
>                goto ei2c;
> @@ -945,40 +954,42 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
>
>        dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data);
>
> -       ret = soc_camera_video_start(icd);
> -       if (ret)
> -               goto eisis;
> -
>        mt9m111->autoexposure = 1;
>        mt9m111->autowhitebalance = 1;
>
>        mt9m111->swap_rgb_even_odd = 1;
>        mt9m111->swap_rgb_red_blue = 1;
>
> -       return 0;
> -eisis:
>  ei2c:
> +       soc_camera_video_stop(icd);
> +
>        return ret;
>  }
>
>  static void mt9m111_video_remove(struct soc_camera_device *icd)
>  {
> -       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
> -       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr,
> -               mt9m111->icd.dev.parent, mt9m111->icd.vdev);
> -       soc_camera_video_stop(&mt9m111->icd);
> +       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr,
> +               icd->dev.parent, icd->vdev);
> +       icd->ops = NULL;
>  }
>
>  static int mt9m111_probe(struct i2c_client *client,
>                         const struct i2c_device_id *did)
>  {
>        struct mt9m111 *mt9m111;
> -       struct soc_camera_device *icd;
> +       struct soc_camera_device *icd = client->dev.platform_data;
>        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct soc_camera_link *icl;
>        int ret;
>
> +       if (!icd) {
> +               dev_err(&client->dev, "MT9M11x: missing soc-camera data!\n");
> +               return -EINVAL;
> +       }
> +
> +       icl = to_soc_camera_link(icd);
>        if (!icl) {
>                dev_err(&client->dev, "MT9M11x driver needs platform data\n");
>                return -EINVAL;
> @@ -994,13 +1005,10 @@ static int mt9m111_probe(struct i2c_client *client,
>        if (!mt9m111)
>                return -ENOMEM;
>
> -       mt9m111->client = client;
>        i2c_set_clientdata(client, mt9m111);
>
>        /* Second stage probe - when a capture adapter is there */
> -       icd             = &mt9m111->icd;
>        icd->ops        = &mt9m111_ops;
> -       icd->control    = &client->dev;
>        icd->x_min      = MT9M111_MIN_DARK_COLS;
>        icd->y_min      = MT9M111_MIN_DARK_ROWS;
>        icd->x_current  = icd->x_min;
> @@ -1010,22 +1018,24 @@ static int mt9m111_probe(struct i2c_client *client,
>        icd->height_min = MT9M111_MIN_DARK_COLS;
>        icd->height_max = MT9M111_MAX_HEIGHT;
>        icd->y_skip_top = 0;
> -       icd->iface      = icl->bus_id;
>
> -       ret = soc_camera_device_register(icd);
> -       if (ret)
> -               goto eisdr;
> -       return 0;
> +       ret = mt9m111_video_probe(icd, client);
> +       if (ret) {
> +               i2c_set_clientdata(client, NULL);
> +               kfree(mt9m111);
> +       }
>
> -eisdr:
> -       kfree(mt9m111);
>        return ret;
>  }
>
>  static int mt9m111_remove(struct i2c_client *client)
>  {
>        struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
> -       soc_camera_device_unregister(&mt9m111->icd);
> +       struct soc_camera_device *icd = client->dev.platform_data;
> +
> +       mt9m111_video_remove(icd);
> +       i2c_set_clientdata(client, NULL);
> +       client->driver = NULL;
>        kfree(mt9m111);
>
>        return 0;
> diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
> index f72aeb7..da09906 100644
> --- a/drivers/media/video/mt9t031.c
> +++ b/drivers/media/video/mt9t031.c
> @@ -68,8 +68,6 @@ static const struct soc_camera_data_format mt9t031_colour_formats[] = {
>  };
>
>  struct mt9t031 {
> -       struct i2c_client *client;
> -       struct soc_camera_device icd;
>        int model;      /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
>        unsigned char autoexposure;
>        u16 xskip;
> @@ -138,8 +136,8 @@ static int get_shutter(struct i2c_client *client, u32 *data)
>
>  static int mt9t031_init(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        int ret;
>
>        if (icl->power) {
> @@ -166,8 +164,8 @@ static int mt9t031_init(struct soc_camera_device *icd)
>
>  static int mt9t031_release(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>
>        /* Disable the chip */
>        reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
> @@ -180,7 +178,7 @@ static int mt9t031_release(struct soc_camera_device *icd)
>
>  static int mt9t031_start_capture(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        /* Switch to master "normal" mode */
>        if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
> @@ -190,7 +188,7 @@ static int mt9t031_start_capture(struct soc_camera_device *icd)
>
>  static int mt9t031_stop_capture(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        /* Stop sensor readout */
>        if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
> @@ -201,7 +199,7 @@ static int mt9t031_stop_capture(struct soc_camera_device *icd)
>  static int mt9t031_set_bus_param(struct soc_camera_device *icd,
>                                 unsigned long flags)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        /* The caller should have queried our parameters, check anyway */
>        if (flags & ~MT9T031_BUS_PARAM)
> @@ -217,8 +215,7 @@ static int mt9t031_set_bus_param(struct soc_camera_device *icd,
>
>  static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
>  {
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> -       struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>
>        return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
>  }
> @@ -238,8 +235,8 @@ static void recalculate_limits(struct soc_camera_device *icd,
>  static int mt9t031_set_params(struct soc_camera_device *icd,
>                              struct v4l2_rect *rect, u16 xskip, u16 yskip)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
>        int ret;
>        u16 xbin, ybin, width, height, left, top;
>        const u16 hblank = MT9T031_HORIZONTAL_BLANK,
> @@ -336,7 +333,8 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
>  static int mt9t031_set_crop(struct soc_camera_device *icd,
>                            struct v4l2_rect *rect)
>  {
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
>
>        /* CROP - no change in scaling, or in limits */
>        return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
> @@ -345,7 +343,8 @@ static int mt9t031_set_crop(struct soc_camera_device *icd,
>  static int mt9t031_set_fmt(struct soc_camera_device *icd,
>                           struct v4l2_format *f)
>  {
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
>        int ret;
>        u16 xskip, yskip;
>        struct v4l2_rect rect = {
> @@ -403,12 +402,13 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
>  static int mt9t031_get_chip_id(struct soc_camera_device *icd,
>                               struct v4l2_dbg_chip_ident *id)
>  {
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
>
>        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
>                return -EINVAL;
>
> -       if (id->match.addr != mt9t031->client->addr)
> +       if (id->match.addr != client->addr)
>                return -ENODEV;
>
>        id->ident       = mt9t031->model;
> @@ -421,7 +421,7 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd,
>  static int mt9t031_get_register(struct soc_camera_device *icd,
>                                struct v4l2_dbg_register *reg)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
>                return -EINVAL;
> @@ -440,7 +440,7 @@ static int mt9t031_get_register(struct soc_camera_device *icd,
>  static int mt9t031_set_register(struct soc_camera_device *icd,
>                                struct v4l2_dbg_register *reg)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
>                return -EINVAL;
> @@ -501,15 +501,11 @@ static const struct v4l2_queryctrl mt9t031_controls[] = {
>        }
>  };
>
> -static int mt9t031_video_probe(struct soc_camera_device *);
> -static void mt9t031_video_remove(struct soc_camera_device *);
>  static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *);
>  static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *);
>
>  static struct soc_camera_ops mt9t031_ops = {
>        .owner                  = THIS_MODULE,
> -       .probe                  = mt9t031_video_probe,
> -       .remove                 = mt9t031_video_remove,
>        .init                   = mt9t031_init,
>        .release                = mt9t031_release,
>        .start_capture          = mt9t031_start_capture,
> @@ -532,8 +528,8 @@ static struct soc_camera_ops mt9t031_ops = {
>
>  static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
>        int data;
>
>        switch (ctrl->id) {
> @@ -558,8 +554,8 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro
>
>  static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
>        const struct v4l2_queryctrl *qctrl;
>        int data;
>
> @@ -665,10 +661,10 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
>
>  /* Interface active, can use i2c. If it fails, it can indeed mean, that
>  * this wasn't our capture interface, so, we wait for the right one */
> -static int mt9t031_video_probe(struct soc_camera_device *icd)
> +static int mt9t031_video_probe(struct soc_camera_device *icd,
> +                              struct i2c_client *client)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> +       struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
>        s32 data;
>        int ret;
>
> @@ -678,6 +674,11 @@ static int mt9t031_video_probe(struct soc_camera_device *icd)
>            to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
>                return -ENODEV;
>
> +       /* Switch master clock on */
> +       ret = soc_camera_video_start(icd, &client->dev);
> +       if (ret)
> +               return ret;
> +
>        /* Enable the chip */
>        data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
>        dev_dbg(&icd->dev, "write: %d\n", data);
> @@ -685,6 +686,8 @@ static int mt9t031_video_probe(struct soc_camera_device *icd)
>        /* Read out the chip version register */
>        data = reg_read(client, MT9T031_CHIP_VERSION);
>
> +       soc_camera_video_stop(icd);
> +
>        switch (data) {
>        case 0x1621:
>                mt9t031->model = V4L2_IDENT_MT9T031;
> @@ -692,44 +695,40 @@ static int mt9t031_video_probe(struct soc_camera_device *icd)
>                icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
>                break;
>        default:
> -               ret = -ENODEV;
>                dev_err(&icd->dev,
>                        "No MT9T031 chip detected, register read %x\n", data);
> -               goto ei2c;
> +               return -ENODEV;
>        }
>
>        dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data);
>
> -       /* Now that we know the model, we can start video */
> -       ret = soc_camera_video_start(icd);
> -       if (ret)
> -               goto evstart;
> -
>        return 0;
> -
> -evstart:
> -ei2c:
> -       return ret;
>  }
>
>  static void mt9t031_video_remove(struct soc_camera_device *icd)
>  {
> -       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
> -       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr,
> +       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr,
>                icd->dev.parent, icd->vdev);
> -       soc_camera_video_stop(icd);
> +       icd->ops = NULL;
>  }
>
>  static int mt9t031_probe(struct i2c_client *client,
>                         const struct i2c_device_id *did)
>  {
>        struct mt9t031 *mt9t031;
> -       struct soc_camera_device *icd;
> +       struct soc_camera_device *icd = client->dev.platform_data;
>        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct soc_camera_link *icl;
>        int ret;
>
> +       if (!icd) {
> +               dev_err(&client->dev, "MT9T031: missing soc-camera data!\n");
> +               return -EINVAL;
> +       }
> +
> +       icl = to_soc_camera_link(icd);
>        if (!icl) {
>                dev_err(&client->dev, "MT9T031 driver needs platform data\n");
>                return -EINVAL;
> @@ -745,13 +744,10 @@ static int mt9t031_probe(struct i2c_client *client,
>        if (!mt9t031)
>                return -ENOMEM;
>
> -       mt9t031->client = client;
>        i2c_set_clientdata(client, mt9t031);
>
>        /* Second stage probe - when a capture adapter is there */
> -       icd = &mt9t031->icd;
>        icd->ops        = &mt9t031_ops;
> -       icd->control    = &client->dev;
>        icd->x_min      = MT9T031_COLUMN_SKIP;
>        icd->y_min      = MT9T031_ROW_SKIP;
>        icd->x_current  = icd->x_min;
> @@ -761,7 +757,6 @@ static int mt9t031_probe(struct i2c_client *client,
>        icd->height_min = MT9T031_MIN_HEIGHT;
>        icd->height_max = MT9T031_MAX_HEIGHT;
>        icd->y_skip_top = 0;
> -       icd->iface      = icl->bus_id;
>        /* Simulated autoexposure. If enabled, we calculate shutter width
>         * ourselves in the driver based on vertical blanking and frame width */
>        mt9t031->autoexposure = 1;
> @@ -769,24 +764,24 @@ static int mt9t031_probe(struct i2c_client *client,
>        mt9t031->xskip = 1;
>        mt9t031->yskip = 1;
>
> -       ret = soc_camera_device_register(icd);
> -       if (ret)
> -               goto eisdr;
> -
> -       return 0;
> +       ret = mt9t031_video_probe(icd, client);
> +       if (ret) {
> +               icd->ops = NULL;
> +               i2c_set_clientdata(client, NULL);
> +               kfree(mt9t031);
> +       }
>
> -eisdr:
> -       i2c_set_clientdata(client, NULL);
> -       kfree(mt9t031);
>        return ret;
>  }
>
>  static int mt9t031_remove(struct i2c_client *client)
>  {
>        struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
> +       struct soc_camera_device *icd = client->dev.platform_data;
>
> -       soc_camera_device_unregister(&mt9t031->icd);
> +       mt9t031_video_remove(icd);
>        i2c_set_clientdata(client, NULL);
> +       client->driver = NULL;
>        kfree(mt9t031);
>
>        return 0;
> diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
> index be20d31..1683af1 100644
> --- a/drivers/media/video/mt9v022.c
> +++ b/drivers/media/video/mt9v022.c
> @@ -85,8 +85,6 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
>  };
>
>  struct mt9v022 {
> -       struct i2c_client *client;
> -       struct soc_camera_device icd;
>        int model;      /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
>        u16 chip_control;
>  };
> @@ -127,9 +125,9 @@ static int reg_clear(struct i2c_client *client, const u8 reg,
>
>  static int mt9v022_init(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
> +       struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
>        int ret;
>
>        if (icl->power) {
> @@ -173,19 +171,19 @@ static int mt9v022_init(struct soc_camera_device *icd)
>
>  static int mt9v022_release(struct soc_camera_device *icd)
>  {
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> -       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>
>        if (icl->power)
> -               icl->power(&mt9v022->client->dev, 0);
> +               icl->power(&client->dev, 0);
>
>        return 0;
>  }
>
>  static int mt9v022_start_capture(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
>        /* Switch to master "normal" mode */
>        mt9v022->chip_control &= ~0x10;
>        if (reg_write(client, MT9V022_CHIP_CONTROL,
> @@ -196,8 +194,8 @@ static int mt9v022_start_capture(struct soc_camera_device *icd)
>
>  static int mt9v022_stop_capture(struct soc_camera_device *icd)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
>        /* Switch to snapshot mode */
>        mt9v022->chip_control |= 0x10;
>        if (reg_write(client, MT9V022_CHIP_CONTROL,
> @@ -209,9 +207,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd)
>  static int mt9v022_set_bus_param(struct soc_camera_device *icd,
>                                 unsigned long flags)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
>        int ret;
>        u16 pixclk = 0;
> @@ -263,8 +261,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
>
>  static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
>  {
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> -       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        unsigned int width_flag;
>
>        if (icl->query_bus_param)
> @@ -283,7 +280,7 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
>  static int mt9v022_set_crop(struct soc_camera_device *icd,
>                            struct v4l2_rect *rect)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>        int ret;
>
>        /* Like in example app. Contradicts the datasheet though */
> @@ -326,7 +323,8 @@ static int mt9v022_set_crop(struct soc_camera_device *icd,
>  static int mt9v022_set_fmt(struct soc_camera_device *icd,
>                           struct v4l2_format *f)
>  {
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
>        struct v4l2_pix_format *pix = &f->fmt.pix;
>        struct v4l2_rect rect = {
>                .left   = icd->x_current,
> @@ -380,12 +378,13 @@ static int mt9v022_try_fmt(struct soc_camera_device *icd,
>  static int mt9v022_get_chip_id(struct soc_camera_device *icd,
>                               struct v4l2_dbg_chip_ident *id)
>  {
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
>
>        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
>                return -EINVAL;
>
> -       if (id->match.addr != mt9v022->client->addr)
> +       if (id->match.addr != client->addr)
>                return -ENODEV;
>
>        id->ident       = mt9v022->model;
> @@ -398,7 +397,7 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd,
>  static int mt9v022_get_register(struct soc_camera_device *icd,
>                                struct v4l2_dbg_register *reg)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
>                return -EINVAL;
> @@ -418,7 +417,7 @@ static int mt9v022_get_register(struct soc_camera_device *icd,
>  static int mt9v022_set_register(struct soc_camera_device *icd,
>                                struct v4l2_dbg_register *reg)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
>                return -EINVAL;
> @@ -487,15 +486,11 @@ static const struct v4l2_queryctrl mt9v022_controls[] = {
>        }
>  };
>
> -static int mt9v022_video_probe(struct soc_camera_device *);
> -static void mt9v022_video_remove(struct soc_camera_device *);
>  static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *);
>  static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *);
>
>  static struct soc_camera_ops mt9v022_ops = {
>        .owner                  = THIS_MODULE,
> -       .probe                  = mt9v022_video_probe,
> -       .remove                 = mt9v022_video_remove,
>        .init                   = mt9v022_init,
>        .release                = mt9v022_release,
>        .start_capture          = mt9v022_start_capture,
> @@ -519,7 +514,7 @@ static struct soc_camera_ops mt9v022_ops = {
>  static int mt9v022_get_control(struct soc_camera_device *icd,
>                               struct v4l2_control *ctrl)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>        int data;
>
>        switch (ctrl->id) {
> @@ -555,7 +550,7 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
>                               struct v4l2_control *ctrl)
>  {
>        int data;
> -       struct i2c_client *client = to_i2c_client(icd->control);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>        const struct v4l2_queryctrl *qctrl;
>
>        qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
> @@ -652,11 +647,11 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
>
>  /* Interface active, can use i2c. If it fails, it can indeed mean, that
>  * this wasn't our capture interface, so, we wait for the right one */
> -static int mt9v022_video_probe(struct soc_camera_device *icd)
> +static int mt9v022_video_probe(struct soc_camera_device *icd,
> +                              struct i2c_client *client)
>  {
> -       struct i2c_client *client = to_i2c_client(icd->control);
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        s32 data;
>        int ret;
>        unsigned long flags;
> @@ -665,6 +660,11 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
>            to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
>                return -ENODEV;
>
> +       /* Switch master clock on */
> +       ret = soc_camera_video_start(icd, &client->dev);
> +       if (ret)
> +               return ret;
> +
>        /* Read out the chip version register */
>        data = reg_read(client, MT9V022_CHIP_VERSION);
>
> @@ -684,6 +684,8 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
>        udelay(200);
>        if (reg_read(client, MT9V022_RESET)) {
>                dev_err(&icd->dev, "Resetting MT9V022 failed!\n");
> +               if (ret > 0)
> +                       ret = -EIO;
>                goto ei2c;
>        }
>
> @@ -700,7 +702,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
>        }
>
>        if (ret < 0)
> -               goto eisis;
> +               goto ei2c;
>
>        icd->num_formats = 0;
>
> @@ -722,29 +724,24 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
>        if (flags & SOCAM_DATAWIDTH_8)
>                icd->num_formats++;
>
> -       ret = soc_camera_video_start(icd);
> -       if (ret < 0)
> -               goto eisis;
> -
>        dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
>                 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
>                 "monochrome" : "colour");
>
> -       return 0;
> -
> -eisis:
>  ei2c:
> +       soc_camera_video_stop(icd);
> +
>        return ret;
>  }
>
>  static void mt9v022_video_remove(struct soc_camera_device *icd)
>  {
> -       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
> -       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>
> -       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
> +       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr,
>                icd->dev.parent, icd->vdev);
> -       soc_camera_video_stop(icd);
> +       icd->ops = NULL;
>        if (icl->free_bus)
>                icl->free_bus(icl);
>  }
> @@ -753,11 +750,17 @@ static int mt9v022_probe(struct i2c_client *client,
>                         const struct i2c_device_id *did)
>  {
>        struct mt9v022 *mt9v022;
> -       struct soc_camera_device *icd;
> +       struct soc_camera_device *icd = client->dev.platform_data;
>        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> -       struct soc_camera_link *icl = client->dev.platform_data;
> +       struct soc_camera_link *icl;
>        int ret;
>
> +       if (!icd) {
> +               dev_err(&client->dev, "MT9V022: missing soc-camera data!\n");
> +               return -EINVAL;
> +       }
> +
> +       icl = to_soc_camera_link(icd);
>        if (!icl) {
>                dev_err(&client->dev, "MT9V022 driver needs platform data\n");
>                return -EINVAL;
> @@ -774,12 +777,9 @@ static int mt9v022_probe(struct i2c_client *client,
>                return -ENOMEM;
>
>        mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
> -       mt9v022->client = client;
>        i2c_set_clientdata(client, mt9v022);
>
> -       icd = &mt9v022->icd;
>        icd->ops        = &mt9v022_ops;
> -       icd->control    = &client->dev;
>        icd->x_min      = 1;
>        icd->y_min      = 4;
>        icd->x_current  = 1;
> @@ -789,24 +789,24 @@ static int mt9v022_probe(struct i2c_client *client,
>        icd->height_min = 32;
>        icd->height_max = 480;
>        icd->y_skip_top = 1;
> -       icd->iface      = icl->bus_id;
> -
> -       ret = soc_camera_device_register(icd);
> -       if (ret)
> -               goto eisdr;
>
> -       return 0;
> +       ret = mt9v022_video_probe(icd, client);
> +       if (ret) {
> +               i2c_set_clientdata(client, NULL);
> +               kfree(mt9v022);
> +       }
>
> -eisdr:
> -       kfree(mt9v022);
>        return ret;
>  }
>
>  static int mt9v022_remove(struct i2c_client *client)
>  {
>        struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
> +       struct soc_camera_device *icd = client->dev.platform_data;
>
> -       soc_camera_device_unregister(&mt9v022->icd);
> +       mt9v022_video_remove(icd);
> +       i2c_set_clientdata(client, NULL);
> +       client->driver = NULL;
>        kfree(mt9v022);
>
>        return 0;
> diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
> index cb13faa..ed752c5 100644
> --- a/drivers/media/video/mx3_camera.c
> +++ b/drivers/media/video/mx3_camera.c
> @@ -502,18 +502,19 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
>
>        mx3_camera_activate(mx3_cam, icd);
>        ret = icd->ops->init(icd);
> -       if (ret < 0) {
> -               clk_disable(mx3_cam->clk);
> +       if (ret < 0)
>                goto einit;
> -       }
>
>        mx3_cam->icd = icd;
>
> +       dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
> +                icd->devnum);
> +
> +       return 0;
> +
>  einit:
> +       clk_disable(mx3_cam->clk);
>  ebusy:
> -       if (!ret)
> -               dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
> -                        icd->devnum);
>
>        return ret;
>  }
> @@ -946,9 +947,10 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
>        camera_flags = icd->ops->query_bus_param(icd);
>
>        common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
> +       dev_dbg(ici->dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n",
> +               camera_flags, bus_flags, common_flags);
>        if (!common_flags) {
> -               dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n",
> -                       camera_flags, bus_flags);
> +               dev_dbg(ici->dev, "no common flags");
>                return -EINVAL;
>        }
>
> @@ -1001,8 +1003,11 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
>                        SOCAM_DATAWIDTH_4;
>
>        ret = icd->ops->set_bus_param(icd, common_flags);
> -       if (ret < 0)
> +       if (ret < 0) {
> +               dev_dbg(ici->dev, "camera set_bus_param(%lx) returned %d\n",
> +                       common_flags, ret);
>                return ret;
> +       }
>
>        /*
>         * So far only gated clock mode is supported. Add a line
> @@ -1130,8 +1135,9 @@ static int mx3_camera_probe(struct platform_device *pdev)
>        INIT_LIST_HEAD(&mx3_cam->capture);
>        spin_lock_init(&mx3_cam->lock);
>
> -       base = ioremap(res->start, res->end - res->start + 1);
> +       base = ioremap(res->start, resource_size(res));
>        if (!base) {
> +               pr_err("Couldn't map %x@%x\n", resource_size(res), res->start);
>                err = -ENOMEM;
>                goto eioremap;
>        }
> @@ -1218,3 +1224,4 @@ module_exit(mx3_camera_exit);
>  MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
>  MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
>  MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
> diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
> index c0d9112..48f4d64 100644
> --- a/drivers/media/video/ov772x.c
> +++ b/drivers/media/video/ov772x.c
> @@ -399,8 +399,6 @@ struct ov772x_win_size {
>
>  struct ov772x_priv {
>        struct ov772x_camera_info        *info;
> -       struct i2c_client                *client;
> -       struct soc_camera_device          icd;
>        const struct ov772x_color_format *fmt;
>        const struct ov772x_win_size     *win;
>        int                               model;
> @@ -619,53 +617,56 @@ static int ov772x_reset(struct i2c_client *client)
>
>  static int ov772x_init(struct soc_camera_device *icd)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = dev_get_drvdata(&icd->dev);
>        int ret = 0;
>
> -       if (priv->info->link.power) {
> -               ret = priv->info->link.power(&priv->client->dev, 1);
> +       if (icl->power) {
> +               ret = icl->power(&client->dev, 1);
>                if (ret < 0)
>                        return ret;
>        }
>
> -       if (priv->info->link.reset)
> -               ret = priv->info->link.reset(&priv->client->dev);
> +       if (icl->reset)
> +               ret = icl->reset(&client->dev);
>
>        return ret;
>  }
>
>  static int ov772x_release(struct soc_camera_device *icd)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct soc_camera_link *icl = dev_get_drvdata(&icd->dev);
>        int ret = 0;
>
> -       if (priv->info->link.power)
> -               ret = priv->info->link.power(&priv->client->dev, 0);
> +       if (icl->power)
> +               ret = icl->power(&client->dev, 0);
>
>        return ret;
>  }
>
>  static int ov772x_start_capture(struct soc_camera_device *icd)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct ov772x_priv *priv = i2c_get_clientdata(client);
>
>        if (!priv->win || !priv->fmt) {
>                dev_err(&icd->dev, "norm or win select error\n");
>                return -EPERM;
>        }
>
> -       ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0);
> +       ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
>
>        dev_dbg(&icd->dev,
> -                "format %s, win %s\n", priv->fmt->name, priv->win->name);
> +               "format %s, win %s\n", priv->fmt->name, priv->win->name);
>
>        return 0;
>  }
>
>  static int ov772x_stop_capture(struct soc_camera_device *icd)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> -       ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
>        return 0;
>  }
>
> @@ -677,8 +678,9 @@ static int ov772x_set_bus_param(struct soc_camera_device *icd,
>
>  static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> -       struct soc_camera_link *icl = &priv->info->link;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct ov772x_priv *priv = i2c_get_clientdata(client);
> +       struct soc_camera_link *icl = dev_get_drvdata(&icd->dev);
>        unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
>                SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
>                SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
> @@ -689,7 +691,8 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
>  static int ov772x_get_control(struct soc_camera_device *icd,
>                              struct v4l2_control *ctrl)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct ov772x_priv *priv = i2c_get_clientdata(client);
>
>        switch (ctrl->id) {
>        case V4L2_CID_VFLIP:
> @@ -705,7 +708,8 @@ static int ov772x_get_control(struct soc_camera_device *icd,
>  static int ov772x_set_control(struct soc_camera_device *icd,
>                              struct v4l2_control *ctrl)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct ov772x_priv *priv = i2c_get_clientdata(client);
>        int ret = 0;
>        u8 val;
>
> @@ -715,14 +719,14 @@ static int ov772x_set_control(struct soc_camera_device *icd,
>                priv->flag_vflip = ctrl->value;
>                if (priv->info->flags & OV772X_FLAG_VFLIP)
>                        val ^= VFLIP_IMG;
> -               ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val);
> +               ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val);
>                break;
>        case V4L2_CID_HFLIP:
>                val = ctrl->value ? HFLIP_IMG : 0x00;
>                priv->flag_hflip = ctrl->value;
>                if (priv->info->flags & OV772X_FLAG_HFLIP)
>                        val ^= HFLIP_IMG;
> -               ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val);
> +               ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val);
>                break;
>        }
>
> @@ -730,9 +734,10 @@ static int ov772x_set_control(struct soc_camera_device *icd,
>  }
>
>  static int ov772x_get_chip_id(struct soc_camera_device *icd,
> -                             struct v4l2_dbg_chip_ident   *id)
> +                             struct v4l2_dbg_chip_ident *id)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct ov772x_priv *priv = i2c_get_clientdata(client);
>
>        id->ident    = priv->model;
>        id->revision = 0;
> @@ -744,14 +749,14 @@ static int ov772x_get_chip_id(struct soc_camera_device *icd,
>  static int ov772x_get_register(struct soc_camera_device *icd,
>                               struct v4l2_dbg_register *reg)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> -       int                 ret;
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       int ret;
>
>        reg->size = 1;
>        if (reg->reg > 0xff)
>                return -EINVAL;
>
> -       ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
> +       ret = i2c_smbus_read_byte_data(client, reg->reg);
>        if (ret < 0)
>                return ret;
>
> @@ -763,13 +768,13 @@ static int ov772x_get_register(struct soc_camera_device *icd,
>  static int ov772x_set_register(struct soc_camera_device *icd,
>                               struct v4l2_dbg_register *reg)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
>
>        if (reg->reg > 0xff ||
>            reg->val > 0xff)
>                return -EINVAL;
>
> -       return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
> +       return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
>  }
>  #endif
>
> @@ -793,9 +798,11 @@ ov772x_select_win(u32 width, u32 height)
>        return win;
>  }
>
> -static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
> -                            u32 pixfmt)
> +static int ov772x_set_params(struct soc_camera_device *icd,
> +                            u32 width, u32 height, u32 pixfmt)
>  {
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct ov772x_priv *priv = i2c_get_clientdata(client);
>        int ret = -EINVAL;
>        u8  val;
>        int i;
> @@ -821,7 +828,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
>        /*
>         * reset hardware
>         */
> -       ov772x_reset(priv->client);
> +       ov772x_reset(client);
>
>        /*
>         * Edge Ctrl
> @@ -835,17 +842,17 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
>                 * Remove it when manual mode.
>                 */
>
> -               ret = ov772x_mask_set(priv->client, DSPAUTO, EDGE_ACTRL, 0x00);
> +               ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
>                if (ret < 0)
>                        goto ov772x_set_fmt_error;
>
> -               ret = ov772x_mask_set(priv->client,
> +               ret = ov772x_mask_set(client,
>                                      EDGE_TRSHLD, EDGE_THRESHOLD_MASK,
>                                      priv->info->edgectrl.threshold);
>                if (ret < 0)
>                        goto ov772x_set_fmt_error;
>
> -               ret = ov772x_mask_set(priv->client,
> +               ret = ov772x_mask_set(client,
>                                      EDGE_STRNGT, EDGE_STRENGTH_MASK,
>                                      priv->info->edgectrl.strength);
>                if (ret < 0)
> @@ -857,13 +864,13 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
>                 *
>                 * set upper and lower limit
>                 */
> -               ret = ov772x_mask_set(priv->client,
> +               ret = ov772x_mask_set(client,
>                                      EDGE_UPPER, EDGE_UPPER_MASK,
>                                      priv->info->edgectrl.upper);
>                if (ret < 0)
>                        goto ov772x_set_fmt_error;
>
> -               ret = ov772x_mask_set(priv->client,
> +               ret = ov772x_mask_set(client,
>                                      EDGE_LOWER, EDGE_LOWER_MASK,
>                                      priv->info->edgectrl.lower);
>                if (ret < 0)
> @@ -873,7 +880,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
>        /*
>         * set size format
>         */
> -       ret = ov772x_write_array(priv->client, priv->win->regs);
> +       ret = ov772x_write_array(client, priv->win->regs);
>        if (ret < 0)
>                goto ov772x_set_fmt_error;
>
> @@ -882,7 +889,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
>         */
>        val = priv->fmt->dsp3;
>        if (val) {
> -               ret = ov772x_mask_set(priv->client,
> +               ret = ov772x_mask_set(client,
>                                      DSP_CTRL3, UV_MASK, val);
>                if (ret < 0)
>                        goto ov772x_set_fmt_error;
> @@ -901,7 +908,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
>        if (priv->flag_hflip)
>                val ^= HFLIP_IMG;
>
> -       ret = ov772x_mask_set(priv->client,
> +       ret = ov772x_mask_set(client,
>                              COM3, SWAP_MASK | IMG_MASK, val);
>        if (ret < 0)
>                goto ov772x_set_fmt_error;
> @@ -910,7 +917,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
>         * set COM7
>         */
>        val = priv->win->com7_bit | priv->fmt->com7;
> -       ret = ov772x_mask_set(priv->client,
> +       ret = ov772x_mask_set(client,
>                              COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
>                              val);
>        if (ret < 0)
> @@ -920,7 +927,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
>
>  ov772x_set_fmt_error:
>
> -       ov772x_reset(priv->client);
> +       ov772x_reset(client);
>        priv->win = NULL;
>        priv->fmt = NULL;
>
> @@ -930,22 +937,22 @@ ov772x_set_fmt_error:
>  static int ov772x_set_crop(struct soc_camera_device *icd,
>                           struct v4l2_rect *rect)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
> +       struct ov772x_priv *priv = i2c_get_clientdata(client);
>
>        if (!priv->fmt)
>                return -EINVAL;
>
> -       return ov772x_set_params(priv, rect->width, rect->height,
> +       return ov772x_set_params(icd, rect->width, rect->height,
>                                 priv->fmt->fourcc);
>  }
>
>  static int ov772x_set_fmt(struct soc_camera_device *icd,
>                          struct v4l2_format *f)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
>        struct v4l2_pix_format *pix = &f->fmt.pix;
>
> -       return ov772x_set_params(priv, pix->width, pix->height,
> +       return ov772x_set_params(icd, pix->width, pix->height,
>                                 pix->pixelformat);
>  }
>
> @@ -967,11 +974,13 @@ static int ov772x_try_fmt(struct soc_camera_device *icd,
>        return 0;
>  }
>
> -static int ov772x_video_probe(struct soc_camera_device *icd)
> +static int ov772x_video_probe(struct soc_camera_device *icd,
> +                             struct i2c_client *client)
>  {
> -       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
> +       struct ov772x_priv *priv = i2c_get_clientdata(client);
>        u8                  pid, ver;
>        const char         *devname;
> +       int ret;
>
>        /*
>         * We must have a parent by now. And it cannot be a wrong one.
> @@ -993,11 +1002,18 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
>        icd->formats     = ov772x_fmt_lists;
>        icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists);
>
> +       /* Switch master clock on */
> +       ret = soc_camera_video_start(icd, &client->dev);
> +       if (ret)
> +               return ret;
> +
>        /*
>         * check and show product ID and manufacturer ID
>         */
> -       pid = i2c_smbus_read_byte_data(priv->client, PID);
> -       ver = i2c_smbus_read_byte_data(priv->client, VER);
> +       pid = i2c_smbus_read_byte_data(client, PID);
> +       ver = i2c_smbus_read_byte_data(client, VER);
> +
> +       soc_camera_video_stop(icd);
>
>        switch (VERSION(pid, ver)) {
>        case OV7720:
> @@ -1019,21 +1035,19 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
>                 devname,
>                 pid,
>                 ver,
> -                i2c_smbus_read_byte_data(priv->client, MIDH),
> -                i2c_smbus_read_byte_data(priv->client, MIDL));
> +                i2c_smbus_read_byte_data(client, MIDH),
> +                i2c_smbus_read_byte_data(client, MIDL));
>
> -       return soc_camera_video_start(icd);
> +       return 0;
>  }
>
>  static void ov772x_video_remove(struct soc_camera_device *icd)
>  {
> -       soc_camera_video_stop(icd);
> +       icd->ops = NULL;
>  }
>
>  static struct soc_camera_ops ov772x_ops = {
>        .owner                  = THIS_MODULE,
> -       .probe                  = ov772x_video_probe,
> -       .remove                 = ov772x_video_remove,
>        .init                   = ov772x_init,
>        .release                = ov772x_release,
>        .start_capture          = ov772x_start_capture,
> @@ -1063,13 +1077,21 @@ static int ov772x_probe(struct i2c_client *client,
>  {
>        struct ov772x_priv        *priv;
>        struct ov772x_camera_info *info;
> -       struct soc_camera_device  *icd;
> +       struct soc_camera_device  *icd = client->dev.platform_data;
>        struct i2c_adapter        *adapter = to_i2c_adapter(client->dev.parent);
> +       struct soc_camera_link    *icl;
>        int                        ret;
>
> -       info = client->dev.platform_data;
> -       if (!info)
> +       if (!icd) {
> +               dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
>                return -EINVAL;
> +       }
> +
> +       icl = dev_get_drvdata(&icd->dev);
> +       if (!icl)
> +               return -EINVAL;
> +
> +       info = container_of(icl, struct ov772x_camera_info, link);
>
>        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
>                dev_err(&adapter->dev,
> @@ -1083,18 +1105,13 @@ static int ov772x_probe(struct i2c_client *client,
>                return -ENOMEM;
>
>        priv->info   = info;
> -       priv->client = client;
>        i2c_set_clientdata(client, priv);
>
> -       icd             = &priv->icd;
>        icd->ops        = &ov772x_ops;
> -       icd->control    = &client->dev;
>        icd->width_max  = MAX_WIDTH;
>        icd->height_max = MAX_HEIGHT;
> -       icd->iface      = priv->info->link.bus_id;
> -
> -       ret = soc_camera_device_register(icd);
>
> +       ret = ov772x_video_probe(icd, client);
>        if (ret) {
>                i2c_set_clientdata(client, NULL);
>                kfree(priv);
> @@ -1106,8 +1123,9 @@ static int ov772x_probe(struct i2c_client *client,
>  static int ov772x_remove(struct i2c_client *client)
>  {
>        struct ov772x_priv *priv = i2c_get_clientdata(client);
> +       struct soc_camera_device *icd = client->dev.platform_data;
>
> -       soc_camera_device_unregister(&priv->icd);
> +       ov772x_video_remove(icd);
>        i2c_set_clientdata(client, NULL);
>        kfree(priv);
>        return 0;
> diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
> index 2da5eef..63964d0 100644
> --- a/drivers/media/video/pxa_camera.c
> +++ b/drivers/media/video/pxa_camera.c
> @@ -841,7 +841,8 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
>                                sizeof(struct pxa_buffer), icd);
>  }
>
> -static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
> +static u32 mclk_get_divisor(struct platform_device *pdev,
> +                           struct pxa_camera_dev *pcdev)
>  {
>        unsigned long mclk = pcdev->mclk;
>        u32 div;
> @@ -853,7 +854,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
>        /* mclk <= ciclk / 4 (27.4.2) */
>        if (mclk > lcdclk / 4) {
>                mclk = lcdclk / 4;
> -               dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk);
> +               dev_warn(&pdev->dev, "Limiting master clock to %lu\n", mclk);
>        }
>
>        /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
> @@ -863,8 +864,8 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
>        if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
>                pcdev->mclk = lcdclk / (2 * (div + 1));
>
> -       dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, "
> -               "divisor %u\n", lcdclk, mclk, div);
> +       dev_dbg(&pdev->dev, "LCD clock %luHz, target freq %luHz, divisor %u\n",
> +               lcdclk, mclk, div);
>
>        return div;
>  }
> @@ -969,15 +970,20 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
>                goto ebusy;
>        }
>
> -       dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
> -                icd->devnum);
> -
>        pxa_camera_activate(pcdev);
>        ret = icd->ops->init(icd);
> +       if (ret < 0)
> +               goto einit;
> +
> +       pcdev->icd = icd;
>
> -       if (!ret)
> -               pcdev->icd = icd;
> +       dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
> +                icd->devnum);
>
> +       return 0;
> +
> +einit:
> +       pxa_camera_deactivate(pcdev);
>  ebusy:
>        return ret;
>  }
> @@ -1599,7 +1605,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
>                pcdev->mclk = 20000000;
>        }
>
> -       pcdev->mclk_divisor = mclk_get_divisor(pcdev);
> +       pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev);
>
>        INIT_LIST_HEAD(&pcdev->capture);
>        spin_lock_init(&pcdev->lock);
> @@ -1746,3 +1752,4 @@ module_exit(pxa_camera_exit);
>  MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
>  MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
>  MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME);
> diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
> index d369e84..ac9b467 100644
> --- a/drivers/media/video/sh_mobile_ceu_camera.c
> +++ b/drivers/media/video/sh_mobile_ceu_camera.c
> @@ -360,11 +360,13 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
>                 "SuperH Mobile CEU driver attached to camera %d\n",
>                 icd->devnum);
>
> +       clk_enable(pcdev->clk);
> +
>        ret = icd->ops->init(icd);
> -       if (ret)
> +       if (ret) {
> +               clk_disable(pcdev->clk);
>                goto err;
> -
> -       clk_enable(pcdev->clk);
> +       }
>
>        ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
>        while (ceu_read(pcdev, CSTSR) & 1)
> @@ -398,10 +400,10 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
>        }
>        spin_unlock_irqrestore(&pcdev->lock, flags);
>
> -       clk_disable(pcdev->clk);
> -
>        icd->ops->release(icd);
>
> +       clk_disable(pcdev->clk);
> +
>        dev_info(&icd->dev,
>                 "SuperH Mobile CEU driver detached from camera %d\n",
>                 icd->devnum);
> @@ -948,3 +950,4 @@ module_exit(sh_mobile_ceu_exit);
>  MODULE_DESCRIPTION("SuperH Mobile CEU driver");
>  MODULE_AUTHOR("Magnus Damm");
>  MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:sh_mobile_ceu");
> diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
> index 03a6c29..d2b765d 100644
> --- a/drivers/media/video/soc_camera.c
> +++ b/drivers/media/video/soc_camera.c
> @@ -16,19 +16,21 @@
>  * published by the Free Software Foundation.
>  */
>
> -#include <linux/module.h>
> -#include <linux/init.h>
>  #include <linux/device.h>
> -#include <linux/list.h>
>  #include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/list.h>
>  #include <linux/mutex.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
>  #include <linux/vmalloc.h>
>
> +#include <media/soc_camera.h>
>  #include <media/v4l2-common.h>
>  #include <media/v4l2-ioctl.h>
>  #include <media/v4l2-dev.h>
>  #include <media/videobuf-core.h>
> -#include <media/soc_camera.h>
>
>  /* Default to VGA resolution */
>  #define DEFAULT_WIDTH  640
> @@ -36,7 +38,7 @@
>
>  static LIST_HEAD(hosts);
>  static LIST_HEAD(devices);
> -static DEFINE_MUTEX(list_lock);
> +static DEFINE_MUTEX(list_lock);                /* Protects the list of hosts */
>
>  const struct soc_camera_data_format *soc_camera_format_by_fourcc(
>        struct soc_camera_device *icd, unsigned int fourcc)
> @@ -207,6 +209,7 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
>        return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
>  }
>
> +/* Always entered with .video_lock held */
>  static int soc_camera_init_user_formats(struct soc_camera_device *icd)
>  {
>        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
> @@ -255,9 +258,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
>        return 0;
>  }
>
> +/* Always entered with .video_lock held */
>  static void soc_camera_free_user_formats(struct soc_camera_device *icd)
>  {
> +       icd->current_fmt = NULL;
>        vfree(icd->user_formats);
> +       icd->user_formats = NULL;
>  }
>
>  /* Called with .vb_lock held */
> @@ -308,10 +314,6 @@ static int soc_camera_open(struct file *file)
>        struct soc_camera_file *icf;
>        int ret;
>
> -       icf = vmalloc(sizeof(*icf));
> -       if (!icf)
> -               return -ENOMEM;
> -
>        /*
>         * It is safe to dereference these pointers now as long as a user has
>         * the video device open - we are protected by the held cdev reference.
> @@ -319,8 +321,17 @@ static int soc_camera_open(struct file *file)
>
>        vdev = video_devdata(file);
>        icd = container_of(vdev->parent, struct soc_camera_device, dev);
> +
> +       if (!icd->ops)
> +               /* No device driver attached */
> +               return -ENODEV;
> +
>        ici = to_soc_camera_host(icd->dev.parent);
>
> +       icf = vmalloc(sizeof(*icf));
> +       if (!icf)
> +               return -ENOMEM;
> +
>        if (!try_module_get(icd->ops->owner)) {
>                dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
>                ret = -EINVAL;
> @@ -333,7 +344,7 @@ static int soc_camera_open(struct file *file)
>                goto emgi;
>        }
>
> -       /* Protect against icd->remove() until we module_get() both drivers. */
> +       /* Protect against icd->ops->remove() until we module_get() both drivers. */
>        mutex_lock(&icd->video_lock);
>
>        icf->icd = icd;
> @@ -348,11 +359,16 @@ static int soc_camera_open(struct file *file)
>                                .width          = icd->width,
>                                .height         = icd->height,
>                                .field          = icd->field,
> -                               .pixelformat    = icd->current_fmt->fourcc,
> -                               .colorspace     = icd->current_fmt->colorspace,
>                        },
>                };
>
> +               ret = soc_camera_init_user_formats(icd);
> +               if (ret < 0)
> +                       goto eiufmt;
> +
> +               f.fmt.pix.pixelformat   = icd->current_fmt->fourcc;
> +               f.fmt.pix.colorspace    = icd->current_fmt->colorspace;
> +
>                ret = ici->ops->add(icd);
>                if (ret < 0) {
>                        dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
> @@ -381,6 +397,8 @@ static int soc_camera_open(struct file *file)
>  esfmt:
>        ici->ops->remove(icd);
>  eiciadd:
> +       soc_camera_free_user_formats(icd);
> +eiufmt:
>        icd->use_count--;
>        mutex_unlock(&icd->video_lock);
>        module_put(ici->ops->owner);
> @@ -400,8 +418,10 @@ static int soc_camera_close(struct file *file)
>
>        mutex_lock(&icd->video_lock);
>        icd->use_count--;
> -       if (!icd->use_count)
> +       if (!icd->use_count) {
>                ici->ops->remove(icd);
> +               soc_camera_free_user_formats(icd);
> +       }
>
>        mutex_unlock(&icd->video_lock);
>
> @@ -762,29 +782,6 @@ static int soc_camera_s_register(struct file *file, void *fh,
>  }
>  #endif
>
> -static int device_register_link(struct soc_camera_device *icd)
> -{
> -       int ret = dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
> -
> -       if (!ret)
> -               ret = device_register(&icd->dev);
> -
> -       if (ret < 0) {
> -               /* Prevent calling device_unregister() */
> -               icd->dev.parent = NULL;
> -               dev_err(&icd->dev, "Cannot register device: %d\n", ret);
> -       /* Even if probe() was unsuccessful for all registered drivers,
> -        * device_register() returns 0, and we add the link, just to
> -        * document this camera's control device */
> -       } else if (icd->control)
> -               /* Have to sysfs_remove_link() before device_unregister()? */
> -               if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
> -                                     "control"))
> -                       dev_warn(&icd->dev,
> -                                "Failed creating the control symlink\n");
> -       return ret;
> -}
> -
>  /* So far this function cannot fail */
>  static void scan_add_host(struct soc_camera_host *ici)
>  {
> @@ -794,103 +791,70 @@ static void scan_add_host(struct soc_camera_host *ici)
>
>        list_for_each_entry(icd, &devices, list) {
>                if (icd->iface == ici->nr) {
> +                       int ret;
>                        icd->dev.parent = ici->dev;
> -                       device_register_link(icd);
> -               }
> -       }
> -
> -       mutex_unlock(&list_lock);
> -}
> -
> -/* return: 0 if no match found or a match found and
> - * device_register() successful, error code otherwise */
> -static int scan_add_device(struct soc_camera_device *icd)
> -{
> -       struct soc_camera_host *ici;
> -       int ret = 0;
> -
> -       mutex_lock(&list_lock);
> -
> -       list_add_tail(&icd->list, &devices);
> -
> -       /* Watch out for class_for_each_device / class_find_device API by
> -        * Dave Young <hidave.darkstar@gmail.com> */
> -       list_for_each_entry(ici, &hosts, list) {
> -               if (icd->iface == ici->nr) {
> -                       ret = 1;
> -                       icd->dev.parent = ici->dev;
> -                       break;
> +                       dev_set_name(&icd->dev, "%u-%u", icd->iface,
> +                                    icd->devnum);
> +                       ret = device_register(&icd->dev);
> +                       if (ret < 0) {
> +                               icd->dev.parent = NULL;
> +                               dev_err(&icd->dev,
> +                                       "Cannot register device: %d\n", ret);
> +                       }
>                }
>        }
>
>        mutex_unlock(&list_lock);
> -
> -       if (ret)
> -               ret = device_register_link(icd);
> -
> -       return ret;
>  }
>
> +static int video_dev_create(struct soc_camera_device *icd);
> +/* Called during host-driver probe */
>  static int soc_camera_probe(struct device *dev)
>  {
>        struct soc_camera_device *icd = to_soc_camera_dev(dev);
> -       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
> +       struct soc_camera_link *icl = to_soc_camera_link(icd);
>        int ret;
> +       struct i2c_client *client;
> +       struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
>
> -       /*
> -        * Possible race scenario:
> -        * modprobe <camera-host-driver> triggers __func__
> -        * at this moment respective <camera-sensor-driver> gets rmmod'ed
> -        * to protect take module references.
> -        */
> -
> -       if (!try_module_get(icd->ops->owner)) {
> -               dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
> -               ret = -EINVAL;
> -               goto emgd;
> -       }
> -
> -       if (!try_module_get(ici->ops->owner)) {
> -               dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
> -               ret = -EINVAL;
> -               goto emgi;
> +       if (!adap) {
> +               ret = -ENODEV;
> +               dev_err(dev, "Cannot get I2C adapter %d\n", icl->i2c_adapter_id);
> +               goto ei2cga;
>        }
>
> -       mutex_lock(&icd->video_lock);
> +       dev_info(dev, "Probing %s\n", dev_name(dev));
>
> -       /* We only call ->add() here to activate and probe the camera.
> -        * We shall ->remove() and deactivate it immediately afterwards. */
> -       ret = ici->ops->add(icd);
> -       if (ret < 0)
> -               goto eiadd;
> +       client = i2c_new_device(adap, icl->board_info);
> +       if (!client) {
> +               ret = -ENOMEM;
> +               goto ei2cnd;
> +       }
>
> -       ret = icd->ops->probe(icd);
> -       if (ret >= 0) {
> -               const struct v4l2_queryctrl *qctrl;
> +       /*
> +        * We set icd drvdata at two locations - here and in
> +        * soc_camera_video_start(). Depending on the module loading /
> +        * initialisation order one of these locations will be entered first
> +        */
> +       /* Use to_i2c_client(dev) to recover the i2c client */
> +       dev_set_drvdata(&icd->dev, &client->dev);
>
> -               qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
> -               icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
> -               qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
> -               icd->exposure = qctrl ? qctrl->default_value :
> -                       (unsigned short)~0;
> +       /* Do we have to sysfs_remove_link() before device_unregister()? */
> +       if (sysfs_create_link(&dev->kobj, &to_soc_camera_control(icd)->kobj,
> +                             "control"))
> +               dev_warn(dev, "Failed creating the control symlink\n");
>
> -               ret = soc_camera_init_user_formats(icd);
> -               if (ret < 0)
> -                       goto eiufmt;
> +       ret = video_dev_create(icd);
> +       if (ret < 0)
> +               goto evdc;
>
> -               icd->height     = DEFAULT_HEIGHT;
> -               icd->width      = DEFAULT_WIDTH;
> -               icd->field      = V4L2_FIELD_ANY;
> -       }
> +       return 0;
>
> -eiufmt:
> -       ici->ops->remove(icd);
> -eiadd:
> -       mutex_unlock(&icd->video_lock);
> -       module_put(ici->ops->owner);
> -emgi:
> -       module_put(icd->ops->owner);
> -emgd:
> +evdc:
> +       i2c_unregister_device(client);
> +ei2cnd:
> +       i2c_put_adapter(adap);
> +ei2cga:
>        return ret;
>  }
>
> @@ -899,11 +863,23 @@ emgd:
>  static int soc_camera_remove(struct device *dev)
>  {
>        struct soc_camera_device *icd = to_soc_camera_dev(dev);
> +       struct video_device *vdev = icd->vdev;
>
> -       if (icd->ops->remove)
> -               icd->ops->remove(icd);
> +       BUG_ON(!dev->parent);
>
> -       soc_camera_free_user_formats(icd);
> +       if (vdev) {
> +               mutex_lock(&icd->video_lock);
> +               video_unregister_device(vdev);
> +               icd->vdev = NULL;
> +               mutex_unlock(&icd->video_lock);
> +       }
> +
> +       if (to_soc_camera_control(icd)) {
> +               struct i2c_client *client =
> +                       to_i2c_client(to_soc_camera_control(icd));
> +               i2c_unregister_device(client);
> +               i2c_put_adapter(client->adapter);
> +       }
>
>        return 0;
>  }
> @@ -998,10 +974,14 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
>
>        list_for_each_entry(icd, &devices, list) {
>                if (icd->dev.parent == ici->dev) {
> +                       /* The bus->remove will be called */
>                        device_unregister(&icd->dev);
>                        /* Not before device_unregister(), .remove
>                         * needs parent to call ici->ops->remove() */
>                        icd->dev.parent = NULL;
> +
> +                       /* If the host module is loaded again, device_register()
> +                        * would complain "already initialised" */
>                        memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
>                }
>        }
> @@ -1013,26 +993,14 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
>  EXPORT_SYMBOL(soc_camera_host_unregister);
>
>  /* Image capture device */
> -int soc_camera_device_register(struct soc_camera_device *icd)
> +static int soc_camera_device_register(struct soc_camera_device *icd)
>  {
>        struct soc_camera_device *ix;
>        int num = -1, i;
>
> -       if (!icd || !icd->ops ||
> -           !icd->ops->probe ||
> -           !icd->ops->init ||
> -           !icd->ops->release ||
> -           !icd->ops->start_capture ||
> -           !icd->ops->stop_capture ||
> -           !icd->ops->set_crop ||
> -           !icd->ops->set_fmt ||
> -           !icd->ops->try_fmt ||
> -           !icd->ops->query_bus_param ||
> -           !icd->ops->set_bus_param)
> -               return -EINVAL;
> -
>        for (i = 0; i < 256 && num < 0; i++) {
>                num = i;
> +               /* Check if this index is available on this interface */
>                list_for_each_entry(ix, &devices, list) {
>                        if (ix->iface == icd->iface && ix->devnum == i) {
>                                num = -1;
> @@ -1054,21 +1022,15 @@ int soc_camera_device_register(struct soc_camera_device *icd)
>        icd->host_priv          = NULL;
>        mutex_init(&icd->video_lock);
>
> -       return scan_add_device(icd);
> +       list_add_tail(&icd->list, &devices);
> +
> +       return 0;
>  }
> -EXPORT_SYMBOL(soc_camera_device_register);
>
> -void soc_camera_device_unregister(struct soc_camera_device *icd)
> +static void soc_camera_device_unregister(struct soc_camera_device *icd)
>  {
> -       mutex_lock(&list_lock);
>        list_del(&icd->list);
> -
> -       /* The bus->remove will be eventually called */
> -       if (icd->dev.parent)
> -               device_unregister(&icd->dev);
> -       mutex_unlock(&list_lock);
>  }
> -EXPORT_SYMBOL(soc_camera_device_unregister);
>
>  static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
>        .vidioc_querycap         = soc_camera_querycap,
> @@ -1099,22 +1061,14 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
>  #endif
>  };
>
> -/*
> - * Usually called from the struct soc_camera_ops .probe() method, i.e., from
> - * soc_camera_probe() above with .video_lock held
> - */
> -int soc_camera_video_start(struct soc_camera_device *icd)
> +static int video_dev_create(struct soc_camera_device *icd)
>  {
>        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
> -       int err = -ENOMEM;
> -       struct video_device *vdev;
> -
> -       if (!icd->dev.parent)
> -               return -ENODEV;
> +       int ret;
> +       struct video_device *vdev = video_device_alloc();
>
> -       vdev = video_device_alloc();
>        if (!vdev)
> -               goto evidallocd;
> +               return -ENOMEM;
>        dev_dbg(ici->dev, "Allocated video_device %p\n", vdev);
>
>        strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
> @@ -1125,10 +1079,10 @@ int soc_camera_video_start(struct soc_camera_device *icd)
>        vdev->ioctl_ops         = &soc_camera_ioctl_ops;
>        vdev->release           = video_device_release;
>        vdev->minor             = -1;
> -       vdev->tvnorms           = V4L2_STD_UNKNOWN,
> +       vdev->tvnorms           = V4L2_STD_UNKNOWN;
>
> -       err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
> -       if (err < 0) {
> +       ret = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
> +       if (ret < 0) {
>                dev_err(vdev->parent, "video_register_device failed\n");
>                goto evidregd;
>        }
> @@ -1138,27 +1092,99 @@ int soc_camera_video_start(struct soc_camera_device *icd)
>
>  evidregd:
>        video_device_release(vdev);
> -evidallocd:
> -       return err;
> +       return ret;
> +}
> +
> +/*
> + * Usually called from the struct soc_camera_ops .probe() method, i.e., from
> + * soc_camera_probe() above with .video_lock held
> + */
> +int soc_camera_video_start(struct soc_camera_device *icd, struct device *dev)
> +{
> +       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
> +       const struct v4l2_queryctrl *qctrl;
> +
> +       if (!icd->dev.parent)
> +               return -ENODEV;
> +
> +       if (!icd->ops ||
> +           !icd->ops->init ||
> +           !icd->ops->release ||
> +           !icd->ops->start_capture ||
> +           !icd->ops->stop_capture ||
> +           !icd->ops->set_fmt ||
> +           !icd->ops->try_fmt ||
> +           !icd->ops->query_bus_param ||
> +           !icd->ops->set_bus_param)
> +               return -EINVAL;
> +
> +       /* See comment in soc_camera_probe() */
> +       dev_set_drvdata(&icd->dev, dev);
> +
> +       qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
> +       icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
> +       qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
> +       icd->exposure = qctrl ? qctrl->default_value : (unsigned short)~0;
> +
> +       return ici->ops->add(icd);
>  }
>  EXPORT_SYMBOL(soc_camera_video_start);
>
>  void soc_camera_video_stop(struct soc_camera_device *icd)
>  {
> -       struct video_device *vdev = icd->vdev;
> +       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
>
>        dev_dbg(&icd->dev, "%s\n", __func__);
>
> -       if (!icd->dev.parent || !vdev)
> -               return;
> -
> -       mutex_lock(&icd->video_lock);
> -       video_unregister_device(vdev);
> -       icd->vdev = NULL;
> -       mutex_unlock(&icd->video_lock);
> +       ici->ops->remove(icd);
>  }
>  EXPORT_SYMBOL(soc_camera_video_stop);
>
> +static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
> +{
> +       struct soc_camera_link *icl = pdev->dev.platform_data;
> +       struct soc_camera_device *icd;
> +
> +       if (!icl)
> +               return -EINVAL;
> +
> +       icd = kzalloc(sizeof(*icd), GFP_KERNEL);
> +       if (!icd)
> +               return -ENOMEM;
> +
> +       icd->iface = icl->bus_id;
> +       icl->board_info->platform_data = icd;
> +       platform_set_drvdata(pdev, icd);
> +       icd->dev.platform_data = icl;
> +
> +       return soc_camera_device_register(icd);
> +}
> +
> +/* Only called on rmmod for each platform device, since they are not
> + * hot-plugg...
>
> [Message clipped]
Guennadi Liakhovetski April 16, 2009, 8:58 a.m. UTC | #3
On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:

> Hello Guennadi,
> 
> 
> Reviewing your patch, I've got curious about a thing.
> I think your soc camera subsystem is covering multiple camera
> devices(sensors) in one target board, but if that is true I'm afraid
> I'm confused how to handle them properly.
> Because according to your patch, video_dev_create() takes camera
> device as parameter and it seems to be creating device node for each
> camera devices.

This patch is a preparatory step for the v4l2-(sub)dev conversion. With it 
yes (I think) a video device will be created for every registered on the 
platform level camera, but only the one(s) that probed successfully will 
actually work, others will return -ENODEV on open().

> It means, if I have one camera host and several camera devices, there
> should be several device nodes for camera devices but cannot be used
> at the same time. Because typical camera host(camera interface) can
> handle only one camera device at a time. But multiple device nodes
> mean "we can open and handle them at the same time".
> 
> How about registering camera host device as v4l2 device and make
> camera device a input device which could be handled using
> VIDIOC_S_INPUT/G_INPUT api?

There are also cases, when you have several cameras simultaneously (think 
for example about stereo vision), even though we don't have any such cases 
just yet.

> Actually, I'm working on S3C64xx camera interface driver with soc
> camera subsystem,

Looking forward to it!:-)

> and I'm facing that issue right now because I've got
> dual camera on my target board.

Good, I think, there also has been a similar design based on a pxa270 SoC. 
How are cameras switched in your case? You probably have some additional 
hardware logic to switch between them, right? So, you need some code to 
control that. I think, you should even be able to do this automatically in 
your platform code using power hooks from the struct soc_camera_link. You 
could fail to power on a camera if another camera is currently active. In 
fact, I have to add a return code test to the call to icl->power(icl, 1) 
in soc_camera_open(), I'll do this for the final v4l2-dev version. Would 
this work for you or do you have another requirements? In which case, can 
you describe your use-case in more detail - should both cameras be open by 
applications simultaneously (looks like not), do you need a more explicit 
switching control, than just "first open switches," which shouldn't be the 
case, since you can even create a separate task, that does nothing but 
just keeps the required camera device open.

> I hope you to consider this concept, and also want to know your opinion.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
--
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
Dongsoo Kim April 16, 2009, 10 a.m. UTC | #4
Hello Guennadi,

On Thu, Apr 16, 2009 at 5:58 PM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:
>
>> Hello Guennadi,
>>
>>
>> Reviewing your patch, I've got curious about a thing.
>> I think your soc camera subsystem is covering multiple camera
>> devices(sensors) in one target board, but if that is true I'm afraid
>> I'm confused how to handle them properly.
>> Because according to your patch, video_dev_create() takes camera
>> device as parameter and it seems to be creating device node for each
>> camera devices.
>
> This patch is a preparatory step for the v4l2-(sub)dev conversion. With it
> yes (I think) a video device will be created for every registered on the
> platform level camera, but only the one(s) that probed successfully will
> actually work, others will return -ENODEV on open().
>
>> It means, if I have one camera host and several camera devices, there
>> should be several device nodes for camera devices but cannot be used
>> at the same time. Because typical camera host(camera interface) can
>> handle only one camera device at a time. But multiple device nodes
>> mean "we can open and handle them at the same time".
>>
>> How about registering camera host device as v4l2 device and make
>> camera device a input device which could be handled using
>> VIDIOC_S_INPUT/G_INPUT api?
>
> There are also cases, when you have several cameras simultaneously (think
> for example about stereo vision), even though we don't have any such cases
> just yet.

I think, there are some specific camera interfaces for stereo camera.
Like stereo camera controller chip from Epson.

But in case of camera interface which can handle only one single
camera at a time, I'm strongly believing that we should use only one
device node for camera.
I mean device node should be the camera interface not the sensor
device. If you are using stereo camera controller chip, you can make
that with a couple of device nodes, like /dev/video0 and /dev/video1.


>
>> Actually, I'm working on S3C64xx camera interface driver with soc
>> camera subsystem,
>
> Looking forward to it!:-)
>
>> and I'm facing that issue right now because I've got
>> dual camera on my target board.
>
> Good, I think, there also has been a similar design based on a pxa270 SoC.
> How are cameras switched in your case? You probably have some additional
> hardware logic to switch between them, right? So, you need some code to
> control that. I think, you should even be able to do this automatically in
> your platform code using power hooks from the struct soc_camera_link. You
> could fail to power on a camera if another camera is currently active. In
> fact, I have to add a return code test to the call to icl->power(icl, 1)
> in soc_camera_open(), I'll do this for the final v4l2-dev version. Would
> this work for you or do you have another requirements? In which case, can
> you describe your use-case in more detail - should both cameras be open by
> applications simultaneously (looks like not), do you need a more explicit
> switching control, than just "first open switches," which shouldn't be the
> case, since you can even create a separate task, that does nothing but
> just keeps the required camera device open.
>

Yes exactly right. My H/W is designed to share data pins and mclk,
pclk pins between both of cameras.
And they have to work mutually exclusive.
For now I'm working on s3c64xx with soc camera subsystem, so no way to
make dual camera control with VIDIOC_S_INPUT, VIDIOC_G_INPUT. But the
prior version of my driver was made to control dual camera with those
S_INPUT/G_INPUT api.
Actually with single device node and switching camera with S_INPUT and
G_INPUT, there is no way to mis-control dual camera.
Because both of cameras work mutually exclusive.

To make it easier, you can take a look at my presentation file which I
gave a talk at CELF ELC2009 in San Francisco.
Here it is the presentation file

http://tree.celinuxforum.org/CelfPubWiki/ELC2009Presentations?action=AttachFile&do=get&target=Framework_for_digital_camera_in_linux-in_detail.ppt

I think it is more decent way to control dual camera. No need to check
whether the sensor is available or not using this way. Just use
G_INPUT to check current active sensor and do S_INPUT to switch into
another one.
Cheers,

Nate


>> I hope you to consider this concept, and also want to know your opinion.
>
> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
>
Guennadi Liakhovetski April 16, 2009, 10:30 a.m. UTC | #5
On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:

> Hello Guennadi,
> 
> On Thu, Apr 16, 2009 at 5:58 PM, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
> > On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:
> >
> >> Hello Guennadi,
> >>
> >>
> >> Reviewing your patch, I've got curious about a thing.
> >> I think your soc camera subsystem is covering multiple camera
> >> devices(sensors) in one target board, but if that is true I'm afraid
> >> I'm confused how to handle them properly.
> >> Because according to your patch, video_dev_create() takes camera
> >> device as parameter and it seems to be creating device node for each
> >> camera devices.
> >
> > This patch is a preparatory step for the v4l2-(sub)dev conversion. With it
> > yes (I think) a video device will be created for every registered on the
> > platform level camera, but only the one(s) that probed successfully will
> > actually work, others will return -ENODEV on open().
> >
> >> It means, if I have one camera host and several camera devices, there
> >> should be several device nodes for camera devices but cannot be used
> >> at the same time. Because typical camera host(camera interface) can
> >> handle only one camera device at a time. But multiple device nodes
> >> mean "we can open and handle them at the same time".
> >>
> >> How about registering camera host device as v4l2 device and make
> >> camera device a input device which could be handled using
> >> VIDIOC_S_INPUT/G_INPUT api?
> >
> > There are also cases, when you have several cameras simultaneously (think
> > for example about stereo vision), even though we don't have any such cases
> > just yet.
> 
> I think, there are some specific camera interfaces for stereo camera.
> Like stereo camera controller chip from Epson.
> 
> But in case of camera interface which can handle only one single
> camera at a time, I'm strongly believing that we should use only one
> device node for camera.
> I mean device node should be the camera interface not the sensor
> device. If you are using stereo camera controller chip, you can make
> that with a couple of device nodes, like /dev/video0 and /dev/video1.

There are also some generic CMOS camera sensors, that support stereo mode, 
e.g., mt9v022. In this case you would do the actual stereo processing in 
host software, I think. The sensors just provide some synchronisation 
possibilities. And you would need both sensors in user-space over video0 
and video1. Also, i.MX31 datasheet says the (single) camera interface can 
handle up to two cameras (simultaneously), however, I haven't found any 
details how this could be supported in software, but I didn't look hard 
either, because I didn't need it until now.

> >> Actually, I'm working on S3C64xx camera interface driver with soc
> >> camera subsystem,
> >
> > Looking forward to it!:-)
> >
> >> and I'm facing that issue right now because I've got
> >> dual camera on my target board.
> >
> > Good, I think, there also has been a similar design based on a pxa270 SoC.
> > How are cameras switched in your case? You probably have some additional
> > hardware logic to switch between them, right? So, you need some code to
> > control that. I think, you should even be able to do this automatically in
> > your platform code using power hooks from the struct soc_camera_link. You
> > could fail to power on a camera if another camera is currently active. In
> > fact, I have to add a return code test to the call to icl->power(icl, 1)
> > in soc_camera_open(), I'll do this for the final v4l2-dev version. Would
> > this work for you or do you have another requirements? In which case, can
> > you describe your use-case in more detail - should both cameras be open by
> > applications simultaneously (looks like not), do you need a more explicit
> > switching control, than just "first open switches," which shouldn't be the
> > case, since you can even create a separate task, that does nothing but
> > just keeps the required camera device open.
> >
> 
> Yes exactly right. My H/W is designed to share data pins and mclk,
> pclk pins between both of cameras.
> And they have to work mutually exclusive.
> For now I'm working on s3c64xx with soc camera subsystem, so no way to
> make dual camera control with VIDIOC_S_INPUT, VIDIOC_G_INPUT. But the
> prior version of my driver was made to control dual camera with those
> S_INPUT/G_INPUT api.
> Actually with single device node and switching camera with S_INPUT and
> G_INPUT, there is no way to mis-control dual camera.
> Because both of cameras work mutually exclusive.
> 
> To make it easier, you can take a look at my presentation file which I
> gave a talk at CELF ELC2009 in San Francisco.
> Here it is the presentation file
> 
> http://tree.celinuxforum.org/CelfPubWiki/ELC2009Presentations?action=AttachFile&do=get&target=Framework_for_digital_camera_in_linux-in_detail.ppt
> 
> I think it is more decent way to control dual camera. No need to check
> whether the sensor is available or not using this way. Just use
> G_INPUT to check current active sensor and do S_INPUT to switch into
> another one.

I understand your idea, but I don't see any significant advantages with it 
or any problems with the current implementation. Notice, that this "one 
video device node per one camera client" concept has been there since the 
first version of soc-camera, it is not something new, that is coming now 
with the v4l2-subdev conversion. So, unless you provide some strong 
reasons I don't see a need to change this concept so far.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
--
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
Dongsoo Kim April 16, 2009, 11:09 a.m. UTC | #6
Hi Guennadi,

On Thu, Apr 16, 2009 at 7:30 PM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:
>
>> Hello Guennadi,
>>
>> On Thu, Apr 16, 2009 at 5:58 PM, Guennadi Liakhovetski
>> <g.liakhovetski@gmx.de> wrote:
>> > On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:
>> >
>> >> Hello Guennadi,
>> >>
>> >>
>> >> Reviewing your patch, I've got curious about a thing.
>> >> I think your soc camera subsystem is covering multiple camera
>> >> devices(sensors) in one target board, but if that is true I'm afraid
>> >> I'm confused how to handle them properly.
>> >> Because according to your patch, video_dev_create() takes camera
>> >> device as parameter and it seems to be creating device node for each
>> >> camera devices.
>> >
>> > This patch is a preparatory step for the v4l2-(sub)dev conversion. With it
>> > yes (I think) a video device will be created for every registered on the
>> > platform level camera, but only the one(s) that probed successfully will
>> > actually work, others will return -ENODEV on open().
>> >
>> >> It means, if I have one camera host and several camera devices, there
>> >> should be several device nodes for camera devices but cannot be used
>> >> at the same time. Because typical camera host(camera interface) can
>> >> handle only one camera device at a time. But multiple device nodes
>> >> mean "we can open and handle them at the same time".
>> >>
>> >> How about registering camera host device as v4l2 device and make
>> >> camera device a input device which could be handled using
>> >> VIDIOC_S_INPUT/G_INPUT api?
>> >
>> > There are also cases, when you have several cameras simultaneously (think
>> > for example about stereo vision), even though we don't have any such cases
>> > just yet.
>>
>> I think, there are some specific camera interfaces for stereo camera.
>> Like stereo camera controller chip from Epson.
>>
>> But in case of camera interface which can handle only one single
>> camera at a time, I'm strongly believing that we should use only one
>> device node for camera.
>> I mean device node should be the camera interface not the sensor
>> device. If you are using stereo camera controller chip, you can make
>> that with a couple of device nodes, like /dev/video0 and /dev/video1.
>
> There are also some generic CMOS camera sensors, that support stereo mode,
> e.g., mt9v022. In this case you would do the actual stereo processing in
> host software, I think. The sensors just provide some synchronisation
> possibilities. And you would need both sensors in user-space over video0
> and video1. Also, i.MX31 datasheet says the (single) camera interface can
> handle up to two cameras (simultaneously), however, I haven't found any
> details how this could be supported in software, but I didn't look hard
> either, because I didn't need it until now.

Oh, interesting. I should look for mt9v022 datasheet.
BTW, also on OMAP3 user manual you can see that two cameras could be
opened at once (with different clock and so on), but it says also that
only one camera's data could be handled by ISP in OMAP.
I think the  freescale CPU case could be the same condition.(sorry I'm not sure)

>
>> >> Actually, I'm working on S3C64xx camera interface driver with soc
>> >> camera subsystem,
>> >
>> > Looking forward to it!:-)
>> >
>> >> and I'm facing that issue right now because I've got
>> >> dual camera on my target board.
>> >
>> > Good, I think, there also has been a similar design based on a pxa270 SoC.
>> > How are cameras switched in your case? You probably have some additional
>> > hardware logic to switch between them, right? So, you need some code to
>> > control that. I think, you should even be able to do this automatically in
>> > your platform code using power hooks from the struct soc_camera_link. You
>> > could fail to power on a camera if another camera is currently active. In
>> > fact, I have to add a return code test to the call to icl->power(icl, 1)
>> > in soc_camera_open(), I'll do this for the final v4l2-dev version. Would
>> > this work for you or do you have another requirements? In which case, can
>> > you describe your use-case in more detail - should both cameras be open by
>> > applications simultaneously (looks like not), do you need a more explicit
>> > switching control, than just "first open switches," which shouldn't be the
>> > case, since you can even create a separate task, that does nothing but
>> > just keeps the required camera device open.
>> >
>>
>> Yes exactly right. My H/W is designed to share data pins and mclk,
>> pclk pins between both of cameras.
>> And they have to work mutually exclusive.
>> For now I'm working on s3c64xx with soc camera subsystem, so no way to
>> make dual camera control with VIDIOC_S_INPUT, VIDIOC_G_INPUT. But the
>> prior version of my driver was made to control dual camera with those
>> S_INPUT/G_INPUT api.
>> Actually with single device node and switching camera with S_INPUT and
>> G_INPUT, there is no way to mis-control dual camera.
>> Because both of cameras work mutually exclusive.
>>
>> To make it easier, you can take a look at my presentation file which I
>> gave a talk at CELF ELC2009 in San Francisco.
>> Here it is the presentation file
>>
>> http://tree.celinuxforum.org/CelfPubWiki/ELC2009Presentations?action=AttachFile&do=get&target=Framework_for_digital_camera_in_linux-in_detail.ppt
>>
>> I think it is more decent way to control dual camera. No need to check
>> whether the sensor is available or not using this way. Just use
>> G_INPUT to check current active sensor and do S_INPUT to switch into
>> another one.
>
> I understand your idea, but I don't see any significant advantages with it
> or any problems with the current implementation. Notice, that this "one
> video device node per one camera client" concept has been there since the
> first version of soc-camera, it is not something new, that is coming now
> with the v4l2-subdev conversion. So, unless you provide some strong
> reasons I don't see a need to change this concept so far.
>

My concern is all about the logical thing. "Why can't we open device
node even if it is not opened from any other process."
I have been working on dual camera with Linux for few years, and
everybody who I'm working with wants not to fail opening camera device
node in the first place. Actually I'm mobile phone developer and I've
been seeing so many exceptional cases in field with dual camera
applications. With all my experiences, I got my conclusion which is
"Don't make user get confused with device opening failure". I want you
to know that no offence but just want to make it better.

But the mt9v022 case, I should need some research.
Cheers,

Nate

> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
>
Guennadi Liakhovetski April 16, 2009, 12:06 p.m. UTC | #7
On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:

> My concern is all about the logical thing. "Why can't we open device
> node even if it is not opened from any other process."

The answer is of course "because the other node is currently active," but 
I can understand the sort of "confusion" that the user might have: we have 
two "independent" device nodes, but only one of them can be active at any 
given time. So, in a way you're right, this might not be very intuitive.

> I have been working on dual camera with Linux for few years, and
> everybody who I'm working with wants not to fail opening camera device
> node in the first place. Actually I'm mobile phone developer and I've
> been seeing so many exceptional cases in field with dual camera
> applications. With all my experiences, I got my conclusion which is
> "Don't make user get confused with device opening failure". I want you
> to know that no offence but just want to make it better.

Sure, I appreciate your opinion and respect your experience, but let's 
have a look at the current concept:

1. the platform has N cameras on camera interface X
2. soc_camera.c finds the matching interface X and creates M (<= N) nodes 
for all successfully probed devices.
3. in the beginning, as long as no device is open, all cameras are powered 
down / inactive.
4. you then open() one of them, it gets powered on / activated, the others 
become unaccessible as long as one is used.
5. this way switching is easy - you're sure, that when no device is open, 
all cameras are powered down, so, you can safely select any of them.
6. module reference-counting is easy too - every open() of a device-node 
increments the use-count

With your proposed approach:

1. the platform has N cameras on camera interface X.
2. as long as at least one camera probed successfully for interface X, you 
create a videoX device and count inputs for it - successfully probed 
cameras.
3. you open videoX, one "default" camera gets activated immediately - not 
all applications issue S_INPUT, so, there has to be a default.
4. if an S_INPUT is issued, you have to verify, whether any camera is 
currently active / capturing, if none - switch to the requested one, if 
one is active - return -EBUSY.
5. reference-counting and guaranteeing consistency is more difficult, as 
well as handling camera driver loading / unloading.

So, I would say, your approach adds complexity and asymmetry. Can it be 
that one camera client has several inputs itself? E.g., a decoder? In any 
case, I wouldn't do this now, if we do decide in favour of your approach, 
then only after the v4l2-device transition, please.

> But the mt9v022 case, I should need some research.

Ok.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
--
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
Dongsoo Kim April 16, 2009, 12:48 p.m. UTC | #8
Hello Guennadi,

On Thu, Apr 16, 2009 at 9:06 PM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:
>
>> My concern is all about the logical thing. "Why can't we open device
>> node even if it is not opened from any other process."
>
> The answer is of course "because the other node is currently active," but
> I can understand the sort of "confusion" that the user might have: we have
> two "independent" device nodes, but only one of them can be active at any
> given time. So, in a way you're right, this might not be very intuitive.
>
>> I have been working on dual camera with Linux for few years, and
>> everybody who I'm working with wants not to fail opening camera device
>> node in the first place. Actually I'm mobile phone developer and I've
>> been seeing so many exceptional cases in field with dual camera
>> applications. With all my experiences, I got my conclusion which is
>> "Don't make user get confused with device opening failure". I want you
>> to know that no offence but just want to make it better.
>
> Sure, I appreciate your opinion and respect your experience, but let's
> have a look at the current concept:
>
> 1. the platform has N cameras on camera interface X
> 2. soc_camera.c finds the matching interface X and creates M (<= N) nodes
> for all successfully probed devices.
> 3. in the beginning, as long as no device is open, all cameras are powered
> down / inactive.
> 4. you then open() one of them, it gets powered on / activated, the others
> become unaccessible as long as one is used.
> 5. this way switching is easy - you're sure, that when no device is open,
> all cameras are powered down, so, you can safely select any of them.
> 6. module reference-counting is easy too - every open() of a device-node
> increments the use-count
>

Honestly it is not that bad. but in situation of multiple processes
trying to access camera devices like process A already opened video0
and process B tries to open video1, process B should face an error
returns even though process B checked for video1 is already opened or
not and verified that it is not opened.


> With your proposed approach:
>
> 1. the platform has N cameras on camera interface X.
> 2. as long as at least one camera probed successfully for interface X, you
> create a videoX device and count inputs for it - successfully probed
> cameras.
> 3. you open videoX, one "default" camera gets activated immediately - not
> all applications issue S_INPUT, so, there has to be a default.
> 4. if an S_INPUT is issued, you have to verify, whether any camera is
> currently active / capturing, if none - switch to the requested one, if
> one is active - return -EBUSY.
> 5. reference-counting and guaranteeing consistency is more difficult, as
> well as handling camera driver loading / unloading.

Oops I forgot to say that we need to enforce legacy v4l2 applications
to use VIDIOC_S_INPUT  after opening device.
And every S_INPUT issuing should come after G_INPUT like every "set"
API in v4l2.


>
> So, I would say, your approach adds complexity and asymmetry. Can it be
> that one camera client has several inputs itself? E.g., a decoder? In any
> case, I wouldn't do this now, if we do decide in favour of your approach,
> then only after the v4l2-device transition, please.
>

Of course. I didn't mean to disturb your transition job. Please do
your priority job first.

And about camera client with several inputs question, I will say that
almost every 3G UMTS phone has dual camera on it. And we can consider
every 3G UMTS smart phones have dual camera on it with soc camera
solution.
BTW, thank you for this conversation. It was a pleasure to discuss
about this issue with you.
Cheers,

Nate

>> But the mt9v022 case, I should need some research.
>
> Ok.
>
> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
>
Guennadi Liakhovetski April 16, 2009, 12:59 p.m. UTC | #9
On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:

> Hello Guennadi,
> 
> On Thu, Apr 16, 2009 at 9:06 PM, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
> > 3. you open videoX, one "default" camera gets activated immediately - not
> > all applications issue S_INPUT, so, there has to be a default.
> > 4. if an S_INPUT is issued, you have to verify, whether any camera is
> > currently active / capturing, if none - switch to the requested one, if
> > one is active - return -EBUSY.
> > 5. reference-counting and guaranteeing consistency is more difficult, as
> > well as handling camera driver loading / unloading.
> 
> Oops I forgot to say that we need to enforce legacy v4l2 applications
> to use VIDIOC_S_INPUT  after opening device.
> And every S_INPUT issuing should come after G_INPUT like every "set"
> API in v4l2.

Hm? Does the API require it? If not, I don't think we should inforce it. 
And what do you mean "legacy v4l2 applications" - which applications are 
not "legacy"?

> > So, I would say, your approach adds complexity and asymmetry. Can it be
> > that one camera client has several inputs itself? E.g., a decoder? In any
> > case, I wouldn't do this now, if we do decide in favour of your approach,
> > then only after the v4l2-device transition, please.
> >
> 
> Of course. I didn't mean to disturb your transition job. Please do
> your priority job first.
> 
> And about camera client with several inputs question, I will say that
> almost every 3G UMTS phone has dual camera on it. And we can consider
> every 3G UMTS smart phones have dual camera on it with soc camera
> solution.

No, sorry, this wasn't my question. By "client" I meant one camera or 
decoder or whatever chip connects to a camera host. I.e., if we have a 
single chip with several inputs, that should logically be handled with 
S_INPUT ioctl, this would further add to the confusion of using different 
inputs on one video device to switch between chips or inputs / functions 
on one chip.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
--
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
Dongsoo Kim April 16, 2009, 2:44 p.m. UTC | #10
2009. 04. 16, 오후 9:59, Guennadi Liakhovetski 작성:

> On Thu, 16 Apr 2009, Dongsoo, Nathaniel Kim wrote:
>
>> Hello Guennadi,
>>
>> On Thu, Apr 16, 2009 at 9:06 PM, Guennadi Liakhovetski
>> <g.liakhovetski@gmx.de> wrote:
>>> 3. you open videoX, one "default" camera gets activated  
>>> immediately - not
>>> all applications issue S_INPUT, so, there has to be a default.
>>> 4. if an S_INPUT is issued, you have to verify, whether any camera  
>>> is
>>> currently active / capturing, if none - switch to the requested  
>>> one, if
>>> one is active - return -EBUSY.
>>> 5. reference-counting and guaranteeing consistency is more  
>>> difficult, as
>>> well as handling camera driver loading / unloading.
>>
>> Oops I forgot to say that we need to enforce legacy v4l2 applications
>> to use VIDIOC_S_INPUT  after opening device.
>> And every S_INPUT issuing should come after G_INPUT like every "set"
>> API in v4l2.
>
> Hm? Does the API require it? If not, I don't think we should inforce  
> it.

No I don't think so, but we can use that to be sure.
>
> And what do you mean "legacy v4l2 applications" - which applications  
> are
>
> not "legacy"?

I mean upcoming applications in the future, like LiMo based platform  
from several mobile phone vendors.
And we can also expect for 3rd party applications if the camera APIs  
are well made and standardized.

>
>
>>> So, I would say, your approach adds complexity and asymmetry. Can  
>>> it be
>>> that one camera client has several inputs itself? E.g., a decoder?  
>>> In any
>>> case, I wouldn't do this now, if we do decide in favour of your  
>>> approach,
>>> then only after the v4l2-device transition, please.
>>>
>>
>> Of course. I didn't mean to disturb your transition job. Please do
>> your priority job first.
>>
>> And about camera client with several inputs question, I will say that
>> almost every 3G UMTS phone has dual camera on it. And we can consider
>> every 3G UMTS smart phones have dual camera on it with soc camera
>> solution.
>
> No, sorry, this wasn't my question. By "client" I meant one camera or
> decoder or whatever chip connects to a camera host. I.e., if we have a
> single chip with several inputs, that should logically be handled with
> S_INPUT ioctl, this would further add to the confusion of using  
> different
> inputs on one video device to switch between chips or inputs /  
> functions
> on one chip.

Yes exactly. It was  "single chip with several inputs." that I  
intended to tell. but still don't get what the confusion you mean.  
Sorry ;-()
Cheers,

Nate

>
>
> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer

--
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 April 16, 2009, 2:56 p.m. UTC | #11
On Thu, 16 Apr 2009, Dongsoo Kim wrote:

> > > And about camera client with several inputs question, I will say that
> > > almost every 3G UMTS phone has dual camera on it. And we can consider
> > > every 3G UMTS smart phones have dual camera on it with soc camera
> > > solution.
> > 
> > No, sorry, this wasn't my question. By "client" I meant one camera or
> > decoder or whatever chip connects to a camera host. I.e., if we have a
> > single chip with several inputs, that should logically be handled with
> > S_INPUT ioctl, this would further add to the confusion of using different
> > inputs on one video device to switch between chips or inputs / functions
> > on one chip.
> 
> Yes exactly. It was  "single chip with several inputs." that I intended to
> tell. but still don't get what the confusion you mean. Sorry ;-()
> Cheers,

Wow, so, on those phone a "dual camera" is a single (CMOS) controller with 
two sensors / lenses / filters?... Cool, do you have an example of such a 
camera to look for on the net? Preferably with a datasheet available.

"Confusion" I meant that in this case switching between inputs sometimes 
switches you to another controller and sometimes to another function 
within the same controller...

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
--
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
Dongsoo Kim April 16, 2009, 3:15 p.m. UTC | #12
2009. 04. 16, 오후 11:56, Guennadi Liakhovetski 작성:

> On Thu, 16 Apr 2009, Dongsoo Kim wrote:
>
>>>> And about camera client with several inputs question, I will say  
>>>> that
>>>> almost every 3G UMTS phone has dual camera on it. And we can  
>>>> consider
>>>> every 3G UMTS smart phones have dual camera on it with soc camera
>>>> solution.
>>>
>>> No, sorry, this wasn't my question. By "client" I meant one camera  
>>> or
>>> decoder or whatever chip connects to a camera host. I.e., if we  
>>> have a
>>> single chip with several inputs, that should logically be handled  
>>> with
>>> S_INPUT ioctl, this would further add to the confusion of using  
>>> different
>>> inputs on one video device to switch between chips or inputs /  
>>> functions
>>> on one chip.
>>
>> Yes exactly. It was  "single chip with several inputs." that I  
>> intended to
>> tell. but still don't get what the confusion you mean. Sorry ;-()
>> Cheers,
>
> Wow, so, on those phone a "dual camera" is a single (CMOS)  
> controller with
> two sensors / lenses / filters?... Cool, do you have an example of  
> such a
> camera to look for on the net? Preferably with a datasheet available.
>

Oops sorry I didn't mean that.
I just meant one single camera interface on Application Processor and  
two camera modules (sensor, lens, isp) connected. Sorry I explained  
badly.
I considered this as single camera interface with several inputs.

> "Confusion" I meant that in this case switching between inputs  
> sometimes
> switches you to another controller and sometimes to another function
> within the same controller...

I think we don't need to worry about that if  we can query camera  
inputs clearly.
Cheers,

Nate
>
>
> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer

--
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/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c
index 6bfd29a..00ce1eb 100644
--- a/arch/arm/mach-mx3/pcm037.c
+++ b/arch/arm/mach-mx3/pcm037.c
@@ -241,9 +241,17 @@  static int pcm037_camera_power(struct device *dev, int on)
 	return 0;
 }
 
+static struct i2c_board_info pcm037_i2c_2_devices[] = {
+	{
+		I2C_BOARD_INFO("mt9t031", 0x5d),
+	},
+};
+
 static struct soc_camera_link iclink = {
-	.bus_id	= 0,			/* Must match with the camera ID */
-	.power = pcm037_camera_power,
+	.bus_id		= 0,		/* Must match with the camera ID */
+	.power		= pcm037_camera_power,
+	.board_info	= &pcm037_i2c_2_devices[0],
+	.i2c_adapter_id	= 2,
 };
 
 static struct i2c_board_info pcm037_i2c_devices[] = {
@@ -256,9 +264,10 @@  static struct i2c_board_info pcm037_i2c_devices[] = {
 	}
 };
 
-static struct i2c_board_info pcm037_i2c_2_devices[] = {
-	{
-		I2C_BOARD_INFO("mt9t031", 0x5d),
+static struct platform_device pcm037_camera = {
+	.name	= "soc-camera-pdrv",
+	.id	= 0,
+	.dev	= {
 		.platform_data = &iclink,
 	},
 };
@@ -338,6 +347,9 @@  static struct platform_device *devices[] __initdata = {
 	&pcm037_flash,
 	&pcm037_eth,
 	&pcm037_sram_device,
+#if defined(CONFIG_I2C_IMX) || defined(CONFIG_I2C_IMX_MODULE)
+	&pcm037_camera,
+#endif
 };
 
 static struct ipu_platform_data mx3_ipu_data = {
@@ -395,9 +407,6 @@  static void __init mxc_board_init(void)
 	i2c_register_board_info(1, pcm037_i2c_devices,
 			ARRAY_SIZE(pcm037_i2c_devices));
 
-	i2c_register_board_info(2, pcm037_i2c_2_devices,
-			ARRAY_SIZE(pcm037_i2c_2_devices));
-
 	mxc_register_device(&mxc_i2c_device1, &pcm037_i2c_1_data);
 	mxc_register_device(&mxc_i2c_device2, &pcm037_i2c_2_data);
 #endif
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 920dfb8..d4eb0c7 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -847,14 +847,23 @@  static int em_x270_sensor_power(struct device *dev, int on)
 	return 0;
 }
 
-static struct soc_camera_link iclink = {
-	.bus_id	= 0,
-	.power = em_x270_sensor_power,
-};
-
 static struct i2c_board_info em_x270_i2c_cam_info[] = {
 	{
 		I2C_BOARD_INFO("mt9m111", 0x48),
+	},
+};
+
+static struct soc_camera_link iclink = {
+	.bus_id		= 0,
+	.power		= em_x270_sensor_power,
+	.board_info	= &em_x270_i2c_cam_info[0],
+	.i2c_adapter_id	= 0,
+};
+
+static struct platform_device em_x270_camera = {
+	.name	= "soc-camera-pdrv",
+	.id	= -1,
+	.dev	= {
 		.platform_data = &iclink,
 	},
 };
@@ -866,8 +875,8 @@  static struct i2c_pxa_platform_data em_x270_i2c_info = {
 static void  __init em_x270_init_camera(void)
 {
 	pxa_set_i2c_info(&em_x270_i2c_info);
-	i2c_register_board_info(0, ARRAY_AND_SIZE(em_x270_i2c_cam_info));
 	pxa_set_camera_info(&em_x270_camera_platform_data);
+	platform_device_register(&em_x270_camera);
 }
 #else
 static inline void em_x270_init_camera(void) {}
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 97c93a7..444818b 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -724,19 +724,21 @@  struct pxacamera_platform_data mioa701_pxacamera_platform_data = {
 	.mclk_10khz = 5000,
 };
 
-static struct soc_camera_link iclink = {
-	.bus_id	= 0, /* Must match id in pxa27x_device_camera in device.c */
-};
-
-/* Board I2C devices. */
+/*
+ * Board I2C devices
+ */
 static struct i2c_board_info __initdata mioa701_i2c_devices[] = {
 	{
-		/* Must initialize before the camera(s) */
 		I2C_BOARD_INFO("mt9m111", 0x5d),
-		.platform_data = &iclink,
 	},
 };
 
+static struct soc_camera_link iclink = {
+	.bus_id		= 0, /* Match id in pxa27x_device_camera in device.c */
+	.board_info	= &mioa701_i2c_devices[0],
+	.i2c_adapter_id	= 0,
+};
+
 struct i2c_pxa_platform_data i2c_pdata = {
 	.fast_mode = 1,
 };
@@ -754,20 +756,21 @@  static struct platform_device var = {			\
 		.platform_data = pdata,			\
 		.parent	= tparent,			\
 	},						\
-};
+}
 #define MIO_SIMPLE_DEV(var, strname, pdata)	\
 	MIO_PARENT_DEV(var, strname, NULL, pdata)
 
-MIO_SIMPLE_DEV(mioa701_gpio_keys, "gpio-keys",	    &mioa701_gpio_keys_data)
+MIO_SIMPLE_DEV(mioa701_gpio_keys, "gpio-keys",	    &mioa701_gpio_keys_data);
 MIO_PARENT_DEV(mioa701_backlight, "pwm-backlight",  &pxa27x_device_pwm0.dev,
 		&mioa701_backlight_data);
-MIO_SIMPLE_DEV(mioa701_led,	  "leds-gpio",	    &gpio_led_info)
-MIO_SIMPLE_DEV(pxa2xx_pcm,	  "pxa2xx-pcm",	    NULL)
-MIO_SIMPLE_DEV(pxa2xx_ac97,	  "pxa2xx-ac97",    NULL)
-MIO_PARENT_DEV(mio_wm9713_codec,  "wm9713-codec",   &pxa2xx_ac97.dev, NULL)
-MIO_SIMPLE_DEV(mioa701_sound,	  "mioa701-wm9713", NULL)
-MIO_SIMPLE_DEV(mioa701_board,	  "mioa701-board",  NULL)
+MIO_SIMPLE_DEV(mioa701_led,	  "leds-gpio",	    &gpio_led_info);
+MIO_SIMPLE_DEV(pxa2xx_pcm,	  "pxa2xx-pcm",	    NULL);
+MIO_SIMPLE_DEV(pxa2xx_ac97,	  "pxa2xx-ac97",    NULL);
+MIO_PARENT_DEV(mio_wm9713_codec,  "wm9713-codec",   &pxa2xx_ac97.dev, NULL);
+MIO_SIMPLE_DEV(mioa701_sound,	  "mioa701-wm9713", NULL);
+MIO_SIMPLE_DEV(mioa701_board,	  "mioa701-board",  NULL);
 MIO_SIMPLE_DEV(gpio_vbus,	  "gpio-vbus",      &gpio_vbus_data);
+MIO_SIMPLE_DEV(mioa701_camera,	  "soc-camera-pdrv",&iclink[0]);
 
 static struct platform_device *devices[] __initdata = {
 	&mioa701_gpio_keys,
@@ -780,6 +783,7 @@  static struct platform_device *devices[] __initdata = {
 	&power_dev,
 	&strataflash,
 	&gpio_vbus,
+	&mioa701_camera,
 	&mioa701_board,
 };
 
@@ -825,7 +829,6 @@  static void __init mioa701_machine_init(void)
 
 	pxa_set_i2c_info(&i2c_pdata);
 	pxa_set_camera_info(&mioa701_pxacamera_platform_data);
-	i2c_register_board_info(0, ARRAY_AND_SIZE(mioa701_i2c_devices));
 }
 
 static void mioa701_machine_exit(void)
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index 9ce1ef2..619b90e 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -427,25 +427,54 @@  static void pcm990_camera_free_bus(struct soc_camera_link *link)
 	gpio_bus_switch = -EINVAL;
 }
 
-static struct soc_camera_link iclink = {
-	.bus_id	= 0, /* Must match with the camera ID above */
-	.query_bus_param = pcm990_camera_query_bus_param,
-	.set_bus_param = pcm990_camera_set_bus_param,
-	.free_bus = pcm990_camera_free_bus,
-};
-
 /* Board I2C devices. */
 static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
 	{
 		/* Must initialize before the camera(s) */
 		I2C_BOARD_INFO("pca9536", 0x41),
 		.platform_data = &pca9536_data,
-	}, {
+	},
+};
+
+static struct i2c_board_info __initdata pcm990_camera_i2c[] = {
+	{
 		I2C_BOARD_INFO("mt9v022", 0x48),
-		.platform_data = &iclink, /* With extender */
 	}, {
 		I2C_BOARD_INFO("mt9m001", 0x5d),
-		.platform_data = &iclink, /* With extender */
+	},
+};
+
+static struct soc_camera_link iclink[] = {
+	{
+		.bus_id			= 0, /* Must match with the camera ID */
+		.board_info		= &pcm990_camera_i2c[0],
+		.i2c_adapter_id		= 0,
+		.query_bus_param	= pcm990_camera_query_bus_param,
+		.set_bus_param		= pcm990_camera_set_bus_param,
+		.free_bus		= pcm990_camera_free_bus,
+	}, {
+		.bus_id			= 0, /* Must match with the camera ID */
+		.board_info		= &pcm990_camera_i2c[1],
+		.i2c_adapter_id		= 0,
+		.query_bus_param	= pcm990_camera_query_bus_param,
+		.set_bus_param		= pcm990_camera_set_bus_param,
+		.free_bus		= pcm990_camera_free_bus,
+	},
+};
+
+static struct platform_device pcm990_camera[] = {
+	{
+		.name	= "soc-camera-pdrv",
+		.id	= 0,
+		.dev	= {
+			.platform_data = &iclink[0],
+		},
+	}, {
+		.name	= "soc-camera-pdrv",
+		.id	= 1,
+		.dev	= {
+			.platform_data = &iclink[1],
+		},
 	},
 };
 #endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
@@ -501,6 +530,9 @@  void __init pcm990_baseboard_init(void)
 	pxa_set_camera_info(&pcm990_pxacamera_platform_data);
 
 	i2c_register_board_info(0, ARRAY_AND_SIZE(pcm990_i2c_devices));
+
+	platform_device_register(&pcm990_camera[0]);
+	platform_device_register(&pcm990_camera[1]);
 #endif
 
 	printk(KERN_INFO "PCM-990 Evaluation baseboard initialized\n");
diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c
index e27655b..37c9139 100644
--- a/arch/sh/boards/board-ap325rxa.c
+++ b/arch/sh/boards/board-ap325rxa.c
@@ -228,12 +228,6 @@  static struct platform_device lcdc_device = {
 	},
 };
 
-static void camera_power(int val)
-{
-	gpio_set_value(GPIO_PTZ5, val); /* RST_CAM/RSTB */
-	mdelay(10);
-}
-
 #ifdef CONFIG_I2C
 static unsigned char camera_ncm03j_magic[] =
 {
@@ -255,23 +249,28 @@  static unsigned char camera_ncm03j_magic[] =
 	0x63, 0xD4, 0x64, 0xEA, 0xD6, 0x0F,
 };
 
-static int camera_set_capture(struct soc_camera_platform_info *info,
-			      int enable)
+static int ap325rxa_camera_power(struct device *dev, int on)
 {
-	struct i2c_adapter *a = i2c_get_adapter(0);
+	gpio_set_value(GPIO_PTZ5, on); /* RST_CAM/RSTB */
+	mdelay(10);
+	return 0;
+}
+
+static int ap325rxa_camera_set_capture(struct soc_camera_platform_info *info,
+				       int enable)
+{
+	struct i2c_adapter *a = i2c_get_adapter(info->link.i2c_adapter_id);
 	struct i2c_msg msg;
 	int ret = 0;
 	int i;
 
-	camera_power(0);
 	if (!enable)
-		return 0; /* no disable for now */
+		return ap325rxa_camera_power(NULL, 0); /* no disable for now */
 
-	camera_power(1);
 	for (i = 0; i < ARRAY_SIZE(camera_ncm03j_magic); i += 2) {
 		u_int8_t buf[8];
 
-		msg.addr = 0x6e;
+		msg.addr = info->link.board_info->addr;
 		msg.buf = buf;
 		msg.len = 2;
 		msg.flags = 0;
@@ -285,8 +284,11 @@  static int camera_set_capture(struct soc_camera_platform_info *info,
 	return ret;
 }
 
+static struct i2c_board_info __initdata ap325rxa_camera_i2c = {
+	I2C_BOARD_INFO("soc_camera_platform", 0x6e),
+};
+
 static struct soc_camera_platform_info camera_info = {
-	.iface = 0,
 	.format_name = "UYVY",
 	.format_depth = 16,
 	.format = {
@@ -296,22 +298,29 @@  static struct soc_camera_platform_info camera_info = {
 		.height = 480,
 	},
 	.bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
-	SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
-	.set_capture = camera_set_capture,
+		SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
+	.set_capture = ap325rxa_camera_set_capture,
+	.link = {
+		.bus_id = 0,
+		.board_info = &ap325rxa_camera_i2c,
+		.i2c_adapter_id	= 0,
+		.power = ap325rxa_camera_power,
+	},
 };
 
-static struct platform_device camera_device = {
-	.name		= "soc_camera_platform",
-	.dev		= {
-		.platform_data	= &camera_info,
+static struct platform_device ap325rxa_camera = {
+	.name	= "soc-camera-pdrv",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &camera_info.link,
 	},
 };
 #endif /* CONFIG_I2C */
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
 	.flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
-	SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER |
-	SOCAM_DATAWIDTH_8,
+		SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH |
+		SOCAM_MASTER | SOCAM_DATAWIDTH_8,
 };
 
 static struct resource ceu_resources[] = {
@@ -360,7 +369,7 @@  static struct platform_device *ap325rxa_devices[] __initdata = {
 	&lcdc_device,
 	&ceu_device,
 #ifdef CONFIG_I2C
-	&camera_device,
+	&ap325rxa_camera,
 #endif
 	&nand_flash_device,
 	&sdcard_cn3_device,
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 4fd6a72..b8cb246 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -383,21 +383,6 @@  static struct platform_device migor_ceu_device = {
 	},
 };
 
-static struct ov772x_camera_info ov7725_info = {
-	.buswidth  = SOCAM_DATAWIDTH_8,
-	.link = {
-		.power  = ov7725_power,
-	},
-};
-
-static struct tw9910_video_info tw9910_info = {
-	.buswidth = SOCAM_DATAWIDTH_8,
-	.mpout    = TW9910_MPO_FIELD,
-	.link = {
-		.power  = tw9910_power,
-	}
-};
-
 struct spi_gpio_platform_data sdcard_cn9_platform_data = {
 	.sck = GPIO_PTD0,
 	.mosi = GPIO_PTD1,
@@ -412,16 +397,6 @@  static struct platform_device sdcard_cn9_device = {
 	},
 };
 
-static struct platform_device *migor_devices[] __initdata = {
-	&smc91x_eth_device,
-	&sh_keysc_device,
-	&migor_lcdc_device,
-	&migor_ceu_device,
-	&migor_nor_flash_device,
-	&migor_nand_flash_device,
-	&sdcard_cn9_device,
-};
-
 static struct i2c_board_info migor_i2c_devices[] = {
 	{
 		I2C_BOARD_INFO("rs5c372b", 0x32),
@@ -430,16 +405,64 @@  static struct i2c_board_info migor_i2c_devices[] = {
 		I2C_BOARD_INFO("migor_ts", 0x51),
 		.irq = 38, /* IRQ6 */
 	},
+};
+
+static struct i2c_board_info migor_camera_i2c[] = {
 	{
 		I2C_BOARD_INFO("ov772x", 0x21),
-		.platform_data = &ov7725_info,
 	},
 	{
 		I2C_BOARD_INFO("tw9910", 0x45),
-		.platform_data = &tw9910_info,
 	},
 };
 
+static struct ov772x_camera_info ov7725_info = {
+	.buswidth  = SOCAM_DATAWIDTH_8,
+	.link = {
+		.power  = ov7725_power,
+		.board_info		= &migor_camera_i2c[0],
+		.i2c_adapter_id		= 0,
+	},
+};
+
+static struct tw9910_video_info tw9910_info = {
+	.buswidth = SOCAM_DATAWIDTH_8,
+	.mpout    = TW9910_MPO_FIELD,
+	.link = {
+		.power  = tw9910_power,
+		.board_info		= &migor_camera_i2c[1],
+		.i2c_adapter_id		= 0,
+	}
+};
+
+static struct platform_device migor_camera[] = {
+	{
+		.name	= "soc-camera-pdrv",
+		.id	= 0,
+		.dev	= {
+			.platform_data = &ov7725_info.link,
+		},
+	}, {
+		.name	= "soc-camera-pdrv",
+		.id	= 1,
+		.dev	= {
+			.platform_data = &tw9910_info.link,
+		},
+	},
+};
+
+static struct platform_device *migor_devices[] __initdata = {
+	&smc91x_eth_device,
+	&sh_keysc_device,
+	&migor_lcdc_device,
+	&migor_ceu_device,
+	&migor_nor_flash_device,
+	&migor_nand_flash_device,
+	&sdcard_cn9_device,
+	&migor_camera[0],
+	&migor_camera[1],
+};
+
 static struct spi_board_info migor_spi_devices[] = {
 	{
 		.modalias = "mmc_spi",
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 459c04c..b0f4ad5 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -69,8 +69,6 @@  static const struct soc_camera_data_format mt9m001_monochrome_formats[] = {
 };
 
 struct mt9m001 {
-	struct i2c_client *client;
-	struct soc_camera_device icd;
 	int model;	/* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
 	unsigned char autoexposure;
 };
@@ -111,11 +109,11 @@  static int reg_clear(struct i2c_client *client, const u8 reg,
 
 static int mt9m001_init(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	int ret;
 
-	dev_dbg(icd->vdev->parent, "%s\n", __func__);
+	dev_dbg(&icd->dev, "%s\n", __func__);
 
 	if (icl->power) {
 		ret = icl->power(&client->dev, 1);
@@ -147,8 +145,8 @@  static int mt9m001_init(struct soc_camera_device *icd)
 
 static int mt9m001_release(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 
 	/* Disable the chip */
 	reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
@@ -161,7 +159,7 @@  static int mt9m001_release(struct soc_camera_device *icd)
 
 static int mt9m001_start_capture(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	/* Switch to master "normal" mode */
 	if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0)
@@ -171,7 +169,7 @@  static int mt9m001_start_capture(struct soc_camera_device *icd)
 
 static int mt9m001_stop_capture(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	/* Stop sensor readout */
 	if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0)
@@ -182,8 +180,7 @@  static int mt9m001_stop_capture(struct soc_camera_device *icd)
 static int mt9m001_set_bus_param(struct soc_camera_device *icd,
 				 unsigned long flags)
 {
-	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-	struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
 
 	/* Only one width bit may be set */
@@ -205,8 +202,7 @@  static int mt9m001_set_bus_param(struct soc_camera_device *icd,
 
 static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
 {
-	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-	struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	/* MT9M001 has all capture_format parameters fixed */
 	unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING |
 		SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
@@ -223,8 +219,8 @@  static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
 static int mt9m001_set_crop(struct soc_camera_device *icd,
 			    struct v4l2_rect *rect)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
 	int ret;
 	const u16 hblank = 9, vblank = 25;
 
@@ -296,12 +292,13 @@  static int mt9m001_try_fmt(struct soc_camera_device *icd,
 static int mt9m001_get_chip_id(struct soc_camera_device *icd,
 			       struct v4l2_dbg_chip_ident *id)
 {
-	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
 
 	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
 		return -EINVAL;
 
-	if (id->match.addr != mt9m001->client->addr)
+	if (id->match.addr != client->addr)
 		return -ENODEV;
 
 	id->ident	= mt9m001->model;
@@ -314,7 +311,7 @@  static int mt9m001_get_chip_id(struct soc_camera_device *icd,
 static int mt9m001_get_register(struct soc_camera_device *icd,
 				struct v4l2_dbg_register *reg)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
 		return -EINVAL;
@@ -334,7 +331,7 @@  static int mt9m001_get_register(struct soc_camera_device *icd,
 static int mt9m001_set_register(struct soc_camera_device *icd,
 				struct v4l2_dbg_register *reg)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
 		return -EINVAL;
@@ -387,15 +384,11 @@  static const struct v4l2_queryctrl mt9m001_controls[] = {
 	}
 };
 
-static int mt9m001_video_probe(struct soc_camera_device *);
-static void mt9m001_video_remove(struct soc_camera_device *);
 static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *);
 static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *);
 
 static struct soc_camera_ops mt9m001_ops = {
 	.owner			= THIS_MODULE,
-	.probe			= mt9m001_video_probe,
-	.remove			= mt9m001_video_remove,
 	.init			= mt9m001_init,
 	.release		= mt9m001_release,
 	.start_capture		= mt9m001_start_capture,
@@ -418,8 +411,8 @@  static struct soc_camera_ops mt9m001_ops = {
 
 static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
 	int data;
 
 	switch (ctrl->id) {
@@ -438,8 +431,8 @@  static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro
 
 static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
 	const struct v4l2_queryctrl *qctrl;
 	int data;
 
@@ -531,11 +524,11 @@  static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
 
 /* Interface active, can use i2c. If it fails, it can indeed mean, that
  * this wasn't our capture interface, so, we wait for the right one */
-static int mt9m001_video_probe(struct soc_camera_device *icd)
+static int mt9m001_video_probe(struct soc_camera_device *icd,
+			       struct i2c_client *client)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	s32 data;
 	int ret;
 	unsigned long flags;
@@ -546,6 +539,11 @@  static int mt9m001_video_probe(struct soc_camera_device *icd)
 	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
 		return -ENODEV;
 
+	/* Switch master clock on */
+	ret = soc_camera_video_start(icd, &client->dev);
+	if (ret)
+		return ret;
+
 	/* Enable the chip */
 	data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
 	dev_dbg(&icd->dev, "write: %d\n", data);
@@ -553,6 +551,8 @@  static int mt9m001_video_probe(struct soc_camera_device *icd)
 	/* Read out the chip version register */
 	data = reg_read(client, MT9M001_CHIP_VERSION);
 
+	soc_camera_video_stop(icd);
+
 	/* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
 	switch (data) {
 	case 0x8411:
@@ -565,10 +565,9 @@  static int mt9m001_video_probe(struct soc_camera_device *icd)
 		icd->formats = mt9m001_monochrome_formats;
 		break;
 	default:
-		ret = -ENODEV;
 		dev_err(&icd->dev,
 			"No MT9M001 chip detected, register read %x\n", data);
-		goto ei2c;
+		return -ENODEV;
 	}
 
 	icd->num_formats = 0;
@@ -594,26 +593,17 @@  static int mt9m001_video_probe(struct soc_camera_device *icd)
 	dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
 		 data == 0x8431 ? "C12STM" : "C12ST");
 
-	/* Now that we know the model, we can start video */
-	ret = soc_camera_video_start(icd);
-	if (ret)
-		goto eisis;
-
 	return 0;
-
-eisis:
-ei2c:
-	return ret;
 }
 
 static void mt9m001_video_remove(struct soc_camera_device *icd)
 {
-	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-	struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 
-	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
+	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr,
 		icd->dev.parent, icd->vdev);
-	soc_camera_video_stop(icd);
+	icd->ops = NULL;
 	if (icl->free_bus)
 		icl->free_bus(icl);
 }
@@ -622,11 +612,17 @@  static int mt9m001_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
 	struct mt9m001 *mt9m001;
-	struct soc_camera_device *icd;
+	struct soc_camera_device *icd = client->dev.platform_data;
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct soc_camera_link *icl;
 	int ret;
 
+	if (!icd) {
+		dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
+		return -EINVAL;
+	}
+
+	icl = to_soc_camera_link(icd);
 	if (!icl) {
 		dev_err(&client->dev, "MT9M001 driver needs platform data\n");
 		return -EINVAL;
@@ -642,13 +638,10 @@  static int mt9m001_probe(struct i2c_client *client,
 	if (!mt9m001)
 		return -ENOMEM;
 
-	mt9m001->client = client;
 	i2c_set_clientdata(client, mt9m001);
 
 	/* Second stage probe - when a capture adapter is there */
-	icd = &mt9m001->icd;
 	icd->ops	= &mt9m001_ops;
-	icd->control	= &client->dev;
 	icd->x_min	= 20;
 	icd->y_min	= 12;
 	icd->x_current	= 20;
@@ -658,27 +651,27 @@  static int mt9m001_probe(struct i2c_client *client,
 	icd->height_min	= 32;
 	icd->height_max	= 1024;
 	icd->y_skip_top	= 1;
-	icd->iface	= icl->bus_id;
 	/* Simulated autoexposure. If enabled, we calculate shutter width
 	 * ourselves in the driver based on vertical blanking and frame width */
 	mt9m001->autoexposure = 1;
 
-	ret = soc_camera_device_register(icd);
-	if (ret)
-		goto eisdr;
-
-	return 0;
+	ret = mt9m001_video_probe(icd, client);
+	if (ret) {
+		i2c_set_clientdata(client, NULL);
+		kfree(mt9m001);
+	}
 
-eisdr:
-	kfree(mt9m001);
 	return ret;
 }
 
 static int mt9m001_remove(struct i2c_client *client)
 {
 	struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 
-	soc_camera_device_unregister(&mt9m001->icd);
+	mt9m001_video_remove(icd);
+	i2c_set_clientdata(client, NULL);
+	client->driver = NULL;
 	kfree(mt9m001);
 
 	return 0;
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index fc5e2de..330753a 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -148,8 +148,6 @@  enum mt9m111_context {
 };
 
 struct mt9m111 {
-	struct i2c_client *client;
-	struct soc_camera_device icd;
 	int model;	/* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
 	enum mt9m111_context context;
 	struct v4l2_rect rect;
@@ -203,7 +201,7 @@  static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
 
 	ret = reg_page_map_set(client, reg);
 	if (!ret)
-		ret = i2c_smbus_write_word_data(client, (reg & 0xff),
+		ret = i2c_smbus_write_word_data(client, reg & 0xff,
 						swab16(data));
 	dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
 	return ret;
@@ -232,7 +230,7 @@  static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
 static int mt9m111_set_context(struct soc_camera_device *icd,
 			       enum mt9m111_context ctxt)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
 		| MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
 		| MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
@@ -249,8 +247,8 @@  static int mt9m111_set_context(struct soc_camera_device *icd,
 static int mt9m111_setup_rect(struct soc_camera_device *icd,
 			      struct v4l2_rect *rect)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret, is_raw_format;
 	int width = rect->width;
 	int height = rect->height;
@@ -294,7 +292,7 @@  static int mt9m111_setup_rect(struct soc_camera_device *icd,
 
 static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	int ret;
 
 	ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
@@ -315,7 +313,8 @@  static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd)
 
 static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int val = 0;
 
 	if (mt9m111->swap_rgb_red_blue)
@@ -329,7 +328,8 @@  static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
 
 static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int val = 0;
 
 	if (mt9m111->swap_rgb_red_blue)
@@ -343,7 +343,8 @@  static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
 
 static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int val = 0;
 
 	if (mt9m111->swap_yuv_cb_cr)
@@ -356,9 +357,9 @@  static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
 
 static int mt9m111_enable(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret;
 
 	if (icl->power) {
@@ -378,9 +379,9 @@  static int mt9m111_enable(struct soc_camera_device *icd)
 
 static int mt9m111_disable(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret;
 
 	ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
@@ -395,8 +396,8 @@  static int mt9m111_disable(struct soc_camera_device *icd)
 
 static int mt9m111_reset(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	int ret;
 
 	ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -424,8 +425,7 @@  static int mt9m111_stop_capture(struct soc_camera_device *icd)
 
 static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-	struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
 		SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
 		SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
@@ -441,7 +441,8 @@  static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
 static int mt9m111_set_crop(struct soc_camera_device *icd,
 			    struct v4l2_rect *rect)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret;
 
 	dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
@@ -456,7 +457,8 @@  static int mt9m111_set_crop(struct soc_camera_device *icd,
 
 static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret;
 
 	switch (pixfmt) {
@@ -506,7 +508,8 @@  static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
 static int mt9m111_set_fmt(struct soc_camera_device *icd,
 			   struct v4l2_format *f)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_rect rect = {
 		.left	= mt9m111->rect.left,
@@ -544,12 +547,13 @@  static int mt9m111_try_fmt(struct soc_camera_device *icd,
 static int mt9m111_get_chip_id(struct soc_camera_device *icd,
 			       struct v4l2_dbg_chip_ident *id)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 
 	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
 		return -EINVAL;
 
-	if (id->match.addr != mt9m111->client->addr)
+	if (id->match.addr != client->addr)
 		return -ENODEV;
 
 	id->ident	= mt9m111->model;
@@ -562,8 +566,8 @@  static int mt9m111_get_chip_id(struct soc_camera_device *icd,
 static int mt9m111_get_register(struct soc_camera_device *icd,
 				struct v4l2_dbg_register *reg)
 {
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	int val;
-	struct i2c_client *client = to_i2c_client(icd->control);
 
 	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
 		return -EINVAL;
@@ -583,7 +587,7 @@  static int mt9m111_get_register(struct soc_camera_device *icd,
 static int mt9m111_set_register(struct soc_camera_device *icd,
 				struct v4l2_dbg_register *reg)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
 		return -EINVAL;
@@ -635,8 +639,6 @@  static const struct v4l2_queryctrl mt9m111_controls[] = {
 	}
 };
 
-static int mt9m111_video_probe(struct soc_camera_device *);
-static void mt9m111_video_remove(struct soc_camera_device *);
 static int mt9m111_get_control(struct soc_camera_device *,
 			       struct v4l2_control *);
 static int mt9m111_set_control(struct soc_camera_device *,
@@ -647,8 +649,6 @@  static int mt9m111_release(struct soc_camera_device *icd);
 
 static struct soc_camera_ops mt9m111_ops = {
 	.owner			= THIS_MODULE,
-	.probe			= mt9m111_video_probe,
-	.remove			= mt9m111_video_remove,
 	.init			= mt9m111_init,
 	.resume			= mt9m111_resume,
 	.release		= mt9m111_release,
@@ -672,8 +672,8 @@  static struct soc_camera_ops mt9m111_ops = {
 
 static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret;
 
 	if (mt9m111->context == HIGHPOWER) {
@@ -693,7 +693,7 @@  static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
 
 static int mt9m111_get_global_gain(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	int data;
 
 	data = reg_read(GLOBAL_GAIN);
@@ -705,7 +705,7 @@  static int mt9m111_get_global_gain(struct soc_camera_device *icd)
 
 static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	u16 val;
 
 	if (gain > 63 * 2 * 2)
@@ -724,8 +724,8 @@  static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
 
 static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret;
 
 	if (on)
@@ -741,8 +741,8 @@  static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
 
 static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret;
 
 	if (on)
@@ -759,8 +759,8 @@  static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
 static int mt9m111_get_control(struct soc_camera_device *icd,
 			       struct v4l2_control *ctrl)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int data;
 
 	switch (ctrl->id) {
@@ -803,7 +803,8 @@  static int mt9m111_get_control(struct soc_camera_device *icd,
 static int mt9m111_set_control(struct soc_camera_device *icd,
 			       struct v4l2_control *ctrl)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	const struct v4l2_queryctrl *qctrl;
 	int ret;
 
@@ -841,7 +842,8 @@  static int mt9m111_set_control(struct soc_camera_device *icd,
 
 static int mt9m111_restore_state(struct soc_camera_device *icd)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 
 	mt9m111_set_context(icd, mt9m111->context);
 	mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
@@ -856,7 +858,8 @@  static int mt9m111_restore_state(struct soc_camera_device *icd)
 
 static int mt9m111_resume(struct soc_camera_device *icd)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret = 0;
 
 	if (mt9m111->powered) {
@@ -871,7 +874,8 @@  static int mt9m111_resume(struct soc_camera_device *icd)
 
 static int mt9m111_init(struct soc_camera_device *icd)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	int ret;
 
 	mt9m111->context = HIGHPOWER;
@@ -902,10 +906,10 @@  static int mt9m111_release(struct soc_camera_device *icd)
  * Interface active, can use i2c. If it fails, it can indeed mean, that
  * this wasn't our capture interface, so, we wait for the right one
  */
-static int mt9m111_video_probe(struct soc_camera_device *icd)
+static int mt9m111_video_probe(struct soc_camera_device *icd,
+			       struct i2c_client *client)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
 	s32 data;
 	int ret;
 
@@ -917,6 +921,11 @@  static int mt9m111_video_probe(struct soc_camera_device *icd)
 	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
 		return -ENODEV;
 
+	/* Switch master clock on */
+	ret = soc_camera_video_start(icd, &client->dev);
+	if (ret)
+		return ret;
+
 	ret = mt9m111_enable(icd);
 	if (ret)
 		goto ei2c;
@@ -945,40 +954,42 @@  static int mt9m111_video_probe(struct soc_camera_device *icd)
 
 	dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data);
 
-	ret = soc_camera_video_start(icd);
-	if (ret)
-		goto eisis;
-
 	mt9m111->autoexposure = 1;
 	mt9m111->autowhitebalance = 1;
 
 	mt9m111->swap_rgb_even_odd = 1;
 	mt9m111->swap_rgb_red_blue = 1;
 
-	return 0;
-eisis:
 ei2c:
+	soc_camera_video_stop(icd);
+
 	return ret;
 }
 
 static void mt9m111_video_remove(struct soc_camera_device *icd)
 {
-	struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
-	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr,
-		mt9m111->icd.dev.parent, mt9m111->icd.vdev);
-	soc_camera_video_stop(&mt9m111->icd);
+	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr,
+		icd->dev.parent, icd->vdev);
+	icd->ops = NULL;
 }
 
 static int mt9m111_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
 	struct mt9m111 *mt9m111;
-	struct soc_camera_device *icd;
+	struct soc_camera_device *icd = client->dev.platform_data;
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct soc_camera_link *icl;
 	int ret;
 
+	if (!icd) {
+		dev_err(&client->dev, "MT9M11x: missing soc-camera data!\n");
+		return -EINVAL;
+	}
+
+	icl = to_soc_camera_link(icd);
 	if (!icl) {
 		dev_err(&client->dev, "MT9M11x driver needs platform data\n");
 		return -EINVAL;
@@ -994,13 +1005,10 @@  static int mt9m111_probe(struct i2c_client *client,
 	if (!mt9m111)
 		return -ENOMEM;
 
-	mt9m111->client = client;
 	i2c_set_clientdata(client, mt9m111);
 
 	/* Second stage probe - when a capture adapter is there */
-	icd 		= &mt9m111->icd;
 	icd->ops	= &mt9m111_ops;
-	icd->control	= &client->dev;
 	icd->x_min	= MT9M111_MIN_DARK_COLS;
 	icd->y_min	= MT9M111_MIN_DARK_ROWS;
 	icd->x_current	= icd->x_min;
@@ -1010,22 +1018,24 @@  static int mt9m111_probe(struct i2c_client *client,
 	icd->height_min	= MT9M111_MIN_DARK_COLS;
 	icd->height_max	= MT9M111_MAX_HEIGHT;
 	icd->y_skip_top	= 0;
-	icd->iface	= icl->bus_id;
 
-	ret = soc_camera_device_register(icd);
-	if (ret)
-		goto eisdr;
-	return 0;
+	ret = mt9m111_video_probe(icd, client);
+	if (ret) {
+		i2c_set_clientdata(client, NULL);
+		kfree(mt9m111);
+	}
 
-eisdr:
-	kfree(mt9m111);
 	return ret;
 }
 
 static int mt9m111_remove(struct i2c_client *client)
 {
 	struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
-	soc_camera_device_unregister(&mt9m111->icd);
+	struct soc_camera_device *icd = client->dev.platform_data;
+
+	mt9m111_video_remove(icd);
+	i2c_set_clientdata(client, NULL);
+	client->driver = NULL;
 	kfree(mt9m111);
 
 	return 0;
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index f72aeb7..da09906 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -68,8 +68,6 @@  static const struct soc_camera_data_format mt9t031_colour_formats[] = {
 };
 
 struct mt9t031 {
-	struct i2c_client *client;
-	struct soc_camera_device icd;
 	int model;	/* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
 	unsigned char autoexposure;
 	u16 xskip;
@@ -138,8 +136,8 @@  static int get_shutter(struct i2c_client *client, u32 *data)
 
 static int mt9t031_init(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	int ret;
 
 	if (icl->power) {
@@ -166,8 +164,8 @@  static int mt9t031_init(struct soc_camera_device *icd)
 
 static int mt9t031_release(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 
 	/* Disable the chip */
 	reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
@@ -180,7 +178,7 @@  static int mt9t031_release(struct soc_camera_device *icd)
 
 static int mt9t031_start_capture(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	/* Switch to master "normal" mode */
 	if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
@@ -190,7 +188,7 @@  static int mt9t031_start_capture(struct soc_camera_device *icd)
 
 static int mt9t031_stop_capture(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	/* Stop sensor readout */
 	if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
@@ -201,7 +199,7 @@  static int mt9t031_stop_capture(struct soc_camera_device *icd)
 static int mt9t031_set_bus_param(struct soc_camera_device *icd,
 				 unsigned long flags)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	/* The caller should have queried our parameters, check anyway */
 	if (flags & ~MT9T031_BUS_PARAM)
@@ -217,8 +215,7 @@  static int mt9t031_set_bus_param(struct soc_camera_device *icd,
 
 static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
 {
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-	struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 
 	return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
 }
@@ -238,8 +235,8 @@  static void recalculate_limits(struct soc_camera_device *icd,
 static int mt9t031_set_params(struct soc_camera_device *icd,
 			      struct v4l2_rect *rect, u16 xskip, u16 yskip)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
 	int ret;
 	u16 xbin, ybin, width, height, left, top;
 	const u16 hblank = MT9T031_HORIZONTAL_BLANK,
@@ -336,7 +333,8 @@  static int mt9t031_set_params(struct soc_camera_device *icd,
 static int mt9t031_set_crop(struct soc_camera_device *icd,
 			    struct v4l2_rect *rect)
 {
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
 
 	/* CROP - no change in scaling, or in limits */
 	return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
@@ -345,7 +343,8 @@  static int mt9t031_set_crop(struct soc_camera_device *icd,
 static int mt9t031_set_fmt(struct soc_camera_device *icd,
 			   struct v4l2_format *f)
 {
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
 	int ret;
 	u16 xskip, yskip;
 	struct v4l2_rect rect = {
@@ -403,12 +402,13 @@  static int mt9t031_try_fmt(struct soc_camera_device *icd,
 static int mt9t031_get_chip_id(struct soc_camera_device *icd,
 			       struct v4l2_dbg_chip_ident *id)
 {
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
 
 	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
 		return -EINVAL;
 
-	if (id->match.addr != mt9t031->client->addr)
+	if (id->match.addr != client->addr)
 		return -ENODEV;
 
 	id->ident	= mt9t031->model;
@@ -421,7 +421,7 @@  static int mt9t031_get_chip_id(struct soc_camera_device *icd,
 static int mt9t031_get_register(struct soc_camera_device *icd,
 				struct v4l2_dbg_register *reg)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
 		return -EINVAL;
@@ -440,7 +440,7 @@  static int mt9t031_get_register(struct soc_camera_device *icd,
 static int mt9t031_set_register(struct soc_camera_device *icd,
 				struct v4l2_dbg_register *reg)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
 		return -EINVAL;
@@ -501,15 +501,11 @@  static const struct v4l2_queryctrl mt9t031_controls[] = {
 	}
 };
 
-static int mt9t031_video_probe(struct soc_camera_device *);
-static void mt9t031_video_remove(struct soc_camera_device *);
 static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *);
 static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *);
 
 static struct soc_camera_ops mt9t031_ops = {
 	.owner			= THIS_MODULE,
-	.probe			= mt9t031_video_probe,
-	.remove			= mt9t031_video_remove,
 	.init			= mt9t031_init,
 	.release		= mt9t031_release,
 	.start_capture		= mt9t031_start_capture,
@@ -532,8 +528,8 @@  static struct soc_camera_ops mt9t031_ops = {
 
 static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
 	int data;
 
 	switch (ctrl->id) {
@@ -558,8 +554,8 @@  static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro
 
 static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
 	const struct v4l2_queryctrl *qctrl;
 	int data;
 
@@ -665,10 +661,10 @@  static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
 
 /* Interface active, can use i2c. If it fails, it can indeed mean, that
  * this wasn't our capture interface, so, we wait for the right one */
-static int mt9t031_video_probe(struct soc_camera_device *icd)
+static int mt9t031_video_probe(struct soc_camera_device *icd,
+			       struct i2c_client *client)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+	struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
 	s32 data;
 	int ret;
 
@@ -678,6 +674,11 @@  static int mt9t031_video_probe(struct soc_camera_device *icd)
 	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
 		return -ENODEV;
 
+	/* Switch master clock on */
+	ret = soc_camera_video_start(icd, &client->dev);
+	if (ret)
+		return ret;
+
 	/* Enable the chip */
 	data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
 	dev_dbg(&icd->dev, "write: %d\n", data);
@@ -685,6 +686,8 @@  static int mt9t031_video_probe(struct soc_camera_device *icd)
 	/* Read out the chip version register */
 	data = reg_read(client, MT9T031_CHIP_VERSION);
 
+	soc_camera_video_stop(icd);
+
 	switch (data) {
 	case 0x1621:
 		mt9t031->model = V4L2_IDENT_MT9T031;
@@ -692,44 +695,40 @@  static int mt9t031_video_probe(struct soc_camera_device *icd)
 		icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
 		break;
 	default:
-		ret = -ENODEV;
 		dev_err(&icd->dev,
 			"No MT9T031 chip detected, register read %x\n", data);
-		goto ei2c;
+		return -ENODEV;
 	}
 
 	dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data);
 
-	/* Now that we know the model, we can start video */
-	ret = soc_camera_video_start(icd);
-	if (ret)
-		goto evstart;
-
 	return 0;
-
-evstart:
-ei2c:
-	return ret;
 }
 
 static void mt9t031_video_remove(struct soc_camera_device *icd)
 {
-	struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
-	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr,
+	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr,
 		icd->dev.parent, icd->vdev);
-	soc_camera_video_stop(icd);
+	icd->ops = NULL;
 }
 
 static int mt9t031_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
 	struct mt9t031 *mt9t031;
-	struct soc_camera_device *icd;
+	struct soc_camera_device *icd = client->dev.platform_data;
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct soc_camera_link *icl;
 	int ret;
 
+	if (!icd) {
+		dev_err(&client->dev, "MT9T031: missing soc-camera data!\n");
+		return -EINVAL;
+	}
+
+	icl = to_soc_camera_link(icd);
 	if (!icl) {
 		dev_err(&client->dev, "MT9T031 driver needs platform data\n");
 		return -EINVAL;
@@ -745,13 +744,10 @@  static int mt9t031_probe(struct i2c_client *client,
 	if (!mt9t031)
 		return -ENOMEM;
 
-	mt9t031->client = client;
 	i2c_set_clientdata(client, mt9t031);
 
 	/* Second stage probe - when a capture adapter is there */
-	icd = &mt9t031->icd;
 	icd->ops	= &mt9t031_ops;
-	icd->control	= &client->dev;
 	icd->x_min	= MT9T031_COLUMN_SKIP;
 	icd->y_min	= MT9T031_ROW_SKIP;
 	icd->x_current	= icd->x_min;
@@ -761,7 +757,6 @@  static int mt9t031_probe(struct i2c_client *client,
 	icd->height_min	= MT9T031_MIN_HEIGHT;
 	icd->height_max	= MT9T031_MAX_HEIGHT;
 	icd->y_skip_top	= 0;
-	icd->iface	= icl->bus_id;
 	/* Simulated autoexposure. If enabled, we calculate shutter width
 	 * ourselves in the driver based on vertical blanking and frame width */
 	mt9t031->autoexposure = 1;
@@ -769,24 +764,24 @@  static int mt9t031_probe(struct i2c_client *client,
 	mt9t031->xskip = 1;
 	mt9t031->yskip = 1;
 
-	ret = soc_camera_device_register(icd);
-	if (ret)
-		goto eisdr;
-
-	return 0;
+	ret = mt9t031_video_probe(icd, client);
+	if (ret) {
+		icd->ops = NULL;
+		i2c_set_clientdata(client, NULL);
+		kfree(mt9t031);
+	}
 
-eisdr:
-	i2c_set_clientdata(client, NULL);
-	kfree(mt9t031);
 	return ret;
 }
 
 static int mt9t031_remove(struct i2c_client *client)
 {
 	struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 
-	soc_camera_device_unregister(&mt9t031->icd);
+	mt9t031_video_remove(icd);
 	i2c_set_clientdata(client, NULL);
+	client->driver = NULL;
 	kfree(mt9t031);
 
 	return 0;
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index be20d31..1683af1 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -85,8 +85,6 @@  static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
 };
 
 struct mt9v022 {
-	struct i2c_client *client;
-	struct soc_camera_device icd;
 	int model;	/* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
 	u16 chip_control;
 };
@@ -127,9 +125,9 @@  static int reg_clear(struct i2c_client *client, const u8 reg,
 
 static int mt9v022_init(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
 	int ret;
 
 	if (icl->power) {
@@ -173,19 +171,19 @@  static int mt9v022_init(struct soc_camera_device *icd)
 
 static int mt9v022_release(struct soc_camera_device *icd)
 {
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-	struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 
 	if (icl->power)
-		icl->power(&mt9v022->client->dev, 0);
+		icl->power(&client->dev, 0);
 
 	return 0;
 }
 
 static int mt9v022_start_capture(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
 	/* Switch to master "normal" mode */
 	mt9v022->chip_control &= ~0x10;
 	if (reg_write(client, MT9V022_CHIP_CONTROL,
@@ -196,8 +194,8 @@  static int mt9v022_start_capture(struct soc_camera_device *icd)
 
 static int mt9v022_stop_capture(struct soc_camera_device *icd)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
 	/* Switch to snapshot mode */
 	mt9v022->chip_control |= 0x10;
 	if (reg_write(client, MT9V022_CHIP_CONTROL,
@@ -209,9 +207,9 @@  static int mt9v022_stop_capture(struct soc_camera_device *icd)
 static int mt9v022_set_bus_param(struct soc_camera_device *icd,
 				 unsigned long flags)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
 	int ret;
 	u16 pixclk = 0;
@@ -263,8 +261,7 @@  static int mt9v022_set_bus_param(struct soc_camera_device *icd,
 
 static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
 {
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-	struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	unsigned int width_flag;
 
 	if (icl->query_bus_param)
@@ -283,7 +280,7 @@  static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
 static int mt9v022_set_crop(struct soc_camera_device *icd,
 			    struct v4l2_rect *rect)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	int ret;
 
 	/* Like in example app. Contradicts the datasheet though */
@@ -326,7 +323,8 @@  static int mt9v022_set_crop(struct soc_camera_device *icd,
 static int mt9v022_set_fmt(struct soc_camera_device *icd,
 			   struct v4l2_format *f)
 {
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_rect rect = {
 		.left	= icd->x_current,
@@ -380,12 +378,13 @@  static int mt9v022_try_fmt(struct soc_camera_device *icd,
 static int mt9v022_get_chip_id(struct soc_camera_device *icd,
 			       struct v4l2_dbg_chip_ident *id)
 {
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
 
 	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
 		return -EINVAL;
 
-	if (id->match.addr != mt9v022->client->addr)
+	if (id->match.addr != client->addr)
 		return -ENODEV;
 
 	id->ident	= mt9v022->model;
@@ -398,7 +397,7 @@  static int mt9v022_get_chip_id(struct soc_camera_device *icd,
 static int mt9v022_get_register(struct soc_camera_device *icd,
 				struct v4l2_dbg_register *reg)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
 		return -EINVAL;
@@ -418,7 +417,7 @@  static int mt9v022_get_register(struct soc_camera_device *icd,
 static int mt9v022_set_register(struct soc_camera_device *icd,
 				struct v4l2_dbg_register *reg)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
 		return -EINVAL;
@@ -487,15 +486,11 @@  static const struct v4l2_queryctrl mt9v022_controls[] = {
 	}
 };
 
-static int mt9v022_video_probe(struct soc_camera_device *);
-static void mt9v022_video_remove(struct soc_camera_device *);
 static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *);
 static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *);
 
 static struct soc_camera_ops mt9v022_ops = {
 	.owner			= THIS_MODULE,
-	.probe			= mt9v022_video_probe,
-	.remove			= mt9v022_video_remove,
 	.init			= mt9v022_init,
 	.release		= mt9v022_release,
 	.start_capture		= mt9v022_start_capture,
@@ -519,7 +514,7 @@  static struct soc_camera_ops mt9v022_ops = {
 static int mt9v022_get_control(struct soc_camera_device *icd,
 			       struct v4l2_control *ctrl)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	int data;
 
 	switch (ctrl->id) {
@@ -555,7 +550,7 @@  static int mt9v022_set_control(struct soc_camera_device *icd,
 			       struct v4l2_control *ctrl)
 {
 	int data;
-	struct i2c_client *client = to_i2c_client(icd->control);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	const struct v4l2_queryctrl *qctrl;
 
 	qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
@@ -652,11 +647,11 @@  static int mt9v022_set_control(struct soc_camera_device *icd,
 
 /* Interface active, can use i2c. If it fails, it can indeed mean, that
  * this wasn't our capture interface, so, we wait for the right one */
-static int mt9v022_video_probe(struct soc_camera_device *icd)
+static int mt9v022_video_probe(struct soc_camera_device *icd,
+			       struct i2c_client *client)
 {
-	struct i2c_client *client = to_i2c_client(icd->control);
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	s32 data;
 	int ret;
 	unsigned long flags;
@@ -665,6 +660,11 @@  static int mt9v022_video_probe(struct soc_camera_device *icd)
 	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
 		return -ENODEV;
 
+	/* Switch master clock on */
+	ret = soc_camera_video_start(icd, &client->dev);
+	if (ret)
+		return ret;
+
 	/* Read out the chip version register */
 	data = reg_read(client, MT9V022_CHIP_VERSION);
 
@@ -684,6 +684,8 @@  static int mt9v022_video_probe(struct soc_camera_device *icd)
 	udelay(200);
 	if (reg_read(client, MT9V022_RESET)) {
 		dev_err(&icd->dev, "Resetting MT9V022 failed!\n");
+		if (ret > 0)
+			ret = -EIO;
 		goto ei2c;
 	}
 
@@ -700,7 +702,7 @@  static int mt9v022_video_probe(struct soc_camera_device *icd)
 	}
 
 	if (ret < 0)
-		goto eisis;
+		goto ei2c;
 
 	icd->num_formats = 0;
 
@@ -722,29 +724,24 @@  static int mt9v022_video_probe(struct soc_camera_device *icd)
 	if (flags & SOCAM_DATAWIDTH_8)
 		icd->num_formats++;
 
-	ret = soc_camera_video_start(icd);
-	if (ret < 0)
-		goto eisis;
-
 	dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
 		 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
 		 "monochrome" : "colour");
 
-	return 0;
-
-eisis:
 ei2c:
+	soc_camera_video_stop(icd);
+
 	return ret;
 }
 
 static void mt9v022_video_remove(struct soc_camera_device *icd)
 {
-	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-	struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 
-	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
+	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr,
 		icd->dev.parent, icd->vdev);
-	soc_camera_video_stop(icd);
+	icd->ops = NULL;
 	if (icl->free_bus)
 		icl->free_bus(icl);
 }
@@ -753,11 +750,17 @@  static int mt9v022_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
 	struct mt9v022 *mt9v022;
-	struct soc_camera_device *icd;
+	struct soc_camera_device *icd = client->dev.platform_data;
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-	struct soc_camera_link *icl = client->dev.platform_data;
+	struct soc_camera_link *icl;
 	int ret;
 
+	if (!icd) {
+		dev_err(&client->dev, "MT9V022: missing soc-camera data!\n");
+		return -EINVAL;
+	}
+
+	icl = to_soc_camera_link(icd);
 	if (!icl) {
 		dev_err(&client->dev, "MT9V022 driver needs platform data\n");
 		return -EINVAL;
@@ -774,12 +777,9 @@  static int mt9v022_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
-	mt9v022->client = client;
 	i2c_set_clientdata(client, mt9v022);
 
-	icd = &mt9v022->icd;
 	icd->ops	= &mt9v022_ops;
-	icd->control	= &client->dev;
 	icd->x_min	= 1;
 	icd->y_min	= 4;
 	icd->x_current	= 1;
@@ -789,24 +789,24 @@  static int mt9v022_probe(struct i2c_client *client,
 	icd->height_min	= 32;
 	icd->height_max	= 480;
 	icd->y_skip_top	= 1;
-	icd->iface	= icl->bus_id;
-
-	ret = soc_camera_device_register(icd);
-	if (ret)
-		goto eisdr;
 
-	return 0;
+	ret = mt9v022_video_probe(icd, client);
+	if (ret) {
+		i2c_set_clientdata(client, NULL);
+		kfree(mt9v022);
+	}
 
-eisdr:
-	kfree(mt9v022);
 	return ret;
 }
 
 static int mt9v022_remove(struct i2c_client *client)
 {
 	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 
-	soc_camera_device_unregister(&mt9v022->icd);
+	mt9v022_video_remove(icd);
+	i2c_set_clientdata(client, NULL);
+	client->driver = NULL;
 	kfree(mt9v022);
 
 	return 0;
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index cb13faa..ed752c5 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -502,18 +502,19 @@  static int mx3_camera_add_device(struct soc_camera_device *icd)
 
 	mx3_camera_activate(mx3_cam, icd);
 	ret = icd->ops->init(icd);
-	if (ret < 0) {
-		clk_disable(mx3_cam->clk);
+	if (ret < 0)
 		goto einit;
-	}
 
 	mx3_cam->icd = icd;
 
+	dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
+		 icd->devnum);
+
+	return 0;
+
 einit:
+	clk_disable(mx3_cam->clk);
 ebusy:
-	if (!ret)
-		dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
-			 icd->devnum);
 
 	return ret;
 }
@@ -946,9 +947,10 @@  static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 	camera_flags = icd->ops->query_bus_param(icd);
 
 	common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+	dev_dbg(ici->dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n",
+		camera_flags, bus_flags, common_flags);
 	if (!common_flags) {
-		dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n",
-			camera_flags, bus_flags);
+		dev_dbg(ici->dev, "no common flags");
 		return -EINVAL;
 	}
 
@@ -1001,8 +1003,11 @@  static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 			SOCAM_DATAWIDTH_4;
 
 	ret = icd->ops->set_bus_param(icd, common_flags);
-	if (ret < 0)
+	if (ret < 0) {
+		dev_dbg(ici->dev, "camera set_bus_param(%lx) returned %d\n",
+			common_flags, ret);
 		return ret;
+	}
 
 	/*
 	 * So far only gated clock mode is supported. Add a line
@@ -1130,8 +1135,9 @@  static int mx3_camera_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&mx3_cam->capture);
 	spin_lock_init(&mx3_cam->lock);
 
-	base = ioremap(res->start, res->end - res->start + 1);
+	base = ioremap(res->start, resource_size(res));
 	if (!base) {
+		pr_err("Couldn't map %x@%x\n", resource_size(res), res->start);
 		err = -ENOMEM;
 		goto eioremap;
 	}
@@ -1218,3 +1224,4 @@  module_exit(mx3_camera_exit);
 MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index c0d9112..48f4d64 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -399,8 +399,6 @@  struct ov772x_win_size {
 
 struct ov772x_priv {
 	struct ov772x_camera_info        *info;
-	struct i2c_client                *client;
-	struct soc_camera_device          icd;
 	const struct ov772x_color_format *fmt;
 	const struct ov772x_win_size     *win;
 	int                               model;
@@ -619,53 +617,56 @@  static int ov772x_reset(struct i2c_client *client)
 
 static int ov772x_init(struct soc_camera_device *icd)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = dev_get_drvdata(&icd->dev);
 	int ret = 0;
 
-	if (priv->info->link.power) {
-		ret = priv->info->link.power(&priv->client->dev, 1);
+	if (icl->power) {
+		ret = icl->power(&client->dev, 1);
 		if (ret < 0)
 			return ret;
 	}
 
-	if (priv->info->link.reset)
-		ret = priv->info->link.reset(&priv->client->dev);
+	if (icl->reset)
+		ret = icl->reset(&client->dev);
 
 	return ret;
 }
 
 static int ov772x_release(struct soc_camera_device *icd)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = dev_get_drvdata(&icd->dev);
 	int ret = 0;
 
-	if (priv->info->link.power)
-		ret = priv->info->link.power(&priv->client->dev, 0);
+	if (icl->power)
+		ret = icl->power(&client->dev, 0);
 
 	return ret;
 }
 
 static int ov772x_start_capture(struct soc_camera_device *icd)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct ov772x_priv *priv = i2c_get_clientdata(client);
 
 	if (!priv->win || !priv->fmt) {
 		dev_err(&icd->dev, "norm or win select error\n");
 		return -EPERM;
 	}
 
-	ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0);
+	ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
 
 	dev_dbg(&icd->dev,
-		 "format %s, win %s\n", priv->fmt->name, priv->win->name);
+		"format %s, win %s\n", priv->fmt->name, priv->win->name);
 
 	return 0;
 }
 
 static int ov772x_stop_capture(struct soc_camera_device *icd)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-	ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
 	return 0;
 }
 
@@ -677,8 +678,9 @@  static int ov772x_set_bus_param(struct soc_camera_device *icd,
 
 static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-	struct soc_camera_link *icl = &priv->info->link;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct ov772x_priv *priv = i2c_get_clientdata(client);
+	struct soc_camera_link *icl = dev_get_drvdata(&icd->dev);
 	unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
 		SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
 		SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
@@ -689,7 +691,8 @@  static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
 static int ov772x_get_control(struct soc_camera_device *icd,
 			      struct v4l2_control *ctrl)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct ov772x_priv *priv = i2c_get_clientdata(client);
 
 	switch (ctrl->id) {
 	case V4L2_CID_VFLIP:
@@ -705,7 +708,8 @@  static int ov772x_get_control(struct soc_camera_device *icd,
 static int ov772x_set_control(struct soc_camera_device *icd,
 			      struct v4l2_control *ctrl)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct ov772x_priv *priv = i2c_get_clientdata(client);
 	int ret = 0;
 	u8 val;
 
@@ -715,14 +719,14 @@  static int ov772x_set_control(struct soc_camera_device *icd,
 		priv->flag_vflip = ctrl->value;
 		if (priv->info->flags & OV772X_FLAG_VFLIP)
 			val ^= VFLIP_IMG;
-		ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val);
+		ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val);
 		break;
 	case V4L2_CID_HFLIP:
 		val = ctrl->value ? HFLIP_IMG : 0x00;
 		priv->flag_hflip = ctrl->value;
 		if (priv->info->flags & OV772X_FLAG_HFLIP)
 			val ^= HFLIP_IMG;
-		ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val);
+		ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val);
 		break;
 	}
 
@@ -730,9 +734,10 @@  static int ov772x_set_control(struct soc_camera_device *icd,
 }
 
 static int ov772x_get_chip_id(struct soc_camera_device *icd,
-			      struct v4l2_dbg_chip_ident   *id)
+			      struct v4l2_dbg_chip_ident *id)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct ov772x_priv *priv = i2c_get_clientdata(client);
 
 	id->ident    = priv->model;
 	id->revision = 0;
@@ -744,14 +749,14 @@  static int ov772x_get_chip_id(struct soc_camera_device *icd,
 static int ov772x_get_register(struct soc_camera_device *icd,
 			       struct v4l2_dbg_register *reg)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-	int                 ret;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	int ret;
 
 	reg->size = 1;
 	if (reg->reg > 0xff)
 		return -EINVAL;
 
-	ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+	ret = i2c_smbus_read_byte_data(client, reg->reg);
 	if (ret < 0)
 		return ret;
 
@@ -763,13 +768,13 @@  static int ov772x_get_register(struct soc_camera_device *icd,
 static int ov772x_set_register(struct soc_camera_device *icd,
 			       struct v4l2_dbg_register *reg)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->reg > 0xff ||
 	    reg->val > 0xff)
 		return -EINVAL;
 
-	return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+	return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
 }
 #endif
 
@@ -793,9 +798,11 @@  ov772x_select_win(u32 width, u32 height)
 	return win;
 }
 
-static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
-			     u32 pixfmt)
+static int ov772x_set_params(struct soc_camera_device *icd,
+			     u32 width, u32 height, u32 pixfmt)
 {
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct ov772x_priv *priv = i2c_get_clientdata(client);
 	int ret = -EINVAL;
 	u8  val;
 	int i;
@@ -821,7 +828,7 @@  static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
 	/*
 	 * reset hardware
 	 */
-	ov772x_reset(priv->client);
+	ov772x_reset(client);
 
 	/*
 	 * Edge Ctrl
@@ -835,17 +842,17 @@  static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
 		 * Remove it when manual mode.
 		 */
 
-		ret = ov772x_mask_set(priv->client, DSPAUTO, EDGE_ACTRL, 0x00);
+		ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
 		if (ret < 0)
 			goto ov772x_set_fmt_error;
 
-		ret = ov772x_mask_set(priv->client,
+		ret = ov772x_mask_set(client,
 				      EDGE_TRSHLD, EDGE_THRESHOLD_MASK,
 				      priv->info->edgectrl.threshold);
 		if (ret < 0)
 			goto ov772x_set_fmt_error;
 
-		ret = ov772x_mask_set(priv->client,
+		ret = ov772x_mask_set(client,
 				      EDGE_STRNGT, EDGE_STRENGTH_MASK,
 				      priv->info->edgectrl.strength);
 		if (ret < 0)
@@ -857,13 +864,13 @@  static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
 		 *
 		 * set upper and lower limit
 		 */
-		ret = ov772x_mask_set(priv->client,
+		ret = ov772x_mask_set(client,
 				      EDGE_UPPER, EDGE_UPPER_MASK,
 				      priv->info->edgectrl.upper);
 		if (ret < 0)
 			goto ov772x_set_fmt_error;
 
-		ret = ov772x_mask_set(priv->client,
+		ret = ov772x_mask_set(client,
 				      EDGE_LOWER, EDGE_LOWER_MASK,
 				      priv->info->edgectrl.lower);
 		if (ret < 0)
@@ -873,7 +880,7 @@  static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
 	/*
 	 * set size format
 	 */
-	ret = ov772x_write_array(priv->client, priv->win->regs);
+	ret = ov772x_write_array(client, priv->win->regs);
 	if (ret < 0)
 		goto ov772x_set_fmt_error;
 
@@ -882,7 +889,7 @@  static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
 	 */
 	val = priv->fmt->dsp3;
 	if (val) {
-		ret = ov772x_mask_set(priv->client,
+		ret = ov772x_mask_set(client,
 				      DSP_CTRL3, UV_MASK, val);
 		if (ret < 0)
 			goto ov772x_set_fmt_error;
@@ -901,7 +908,7 @@  static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
 	if (priv->flag_hflip)
 		val ^= HFLIP_IMG;
 
-	ret = ov772x_mask_set(priv->client,
+	ret = ov772x_mask_set(client,
 			      COM3, SWAP_MASK | IMG_MASK, val);
 	if (ret < 0)
 		goto ov772x_set_fmt_error;
@@ -910,7 +917,7 @@  static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
 	 * set COM7
 	 */
 	val = priv->win->com7_bit | priv->fmt->com7;
-	ret = ov772x_mask_set(priv->client,
+	ret = ov772x_mask_set(client,
 			      COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
 			      val);
 	if (ret < 0)
@@ -920,7 +927,7 @@  static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
 
 ov772x_set_fmt_error:
 
-	ov772x_reset(priv->client);
+	ov772x_reset(client);
 	priv->win = NULL;
 	priv->fmt = NULL;
 
@@ -930,22 +937,22 @@  ov772x_set_fmt_error:
 static int ov772x_set_crop(struct soc_camera_device *icd,
 			   struct v4l2_rect *rect)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct ov772x_priv *priv = i2c_get_clientdata(client);
 
 	if (!priv->fmt)
 		return -EINVAL;
 
-	return ov772x_set_params(priv, rect->width, rect->height,
+	return ov772x_set_params(icd, rect->width, rect->height,
 				 priv->fmt->fourcc);
 }
 
 static int ov772x_set_fmt(struct soc_camera_device *icd,
 			  struct v4l2_format *f)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 
-	return ov772x_set_params(priv, pix->width, pix->height,
+	return ov772x_set_params(icd, pix->width, pix->height,
 				 pix->pixelformat);
 }
 
@@ -967,11 +974,13 @@  static int ov772x_try_fmt(struct soc_camera_device *icd,
 	return 0;
 }
 
-static int ov772x_video_probe(struct soc_camera_device *icd)
+static int ov772x_video_probe(struct soc_camera_device *icd,
+			      struct i2c_client *client)
 {
-	struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+	struct ov772x_priv *priv = i2c_get_clientdata(client);
 	u8                  pid, ver;
 	const char         *devname;
+	int ret;
 
 	/*
 	 * We must have a parent by now. And it cannot be a wrong one.
@@ -993,11 +1002,18 @@  static int ov772x_video_probe(struct soc_camera_device *icd)
 	icd->formats     = ov772x_fmt_lists;
 	icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists);
 
+	/* Switch master clock on */
+	ret = soc_camera_video_start(icd, &client->dev);
+	if (ret)
+		return ret;
+
 	/*
 	 * check and show product ID and manufacturer ID
 	 */
-	pid = i2c_smbus_read_byte_data(priv->client, PID);
-	ver = i2c_smbus_read_byte_data(priv->client, VER);
+	pid = i2c_smbus_read_byte_data(client, PID);
+	ver = i2c_smbus_read_byte_data(client, VER);
+
+	soc_camera_video_stop(icd);
 
 	switch (VERSION(pid, ver)) {
 	case OV7720:
@@ -1019,21 +1035,19 @@  static int ov772x_video_probe(struct soc_camera_device *icd)
 		 devname,
 		 pid,
 		 ver,
-		 i2c_smbus_read_byte_data(priv->client, MIDH),
-		 i2c_smbus_read_byte_data(priv->client, MIDL));
+		 i2c_smbus_read_byte_data(client, MIDH),
+		 i2c_smbus_read_byte_data(client, MIDL));
 
-	return soc_camera_video_start(icd);
+	return 0;
 }
 
 static void ov772x_video_remove(struct soc_camera_device *icd)
 {
-	soc_camera_video_stop(icd);
+	icd->ops = NULL;
 }
 
 static struct soc_camera_ops ov772x_ops = {
 	.owner			= THIS_MODULE,
-	.probe			= ov772x_video_probe,
-	.remove			= ov772x_video_remove,
 	.init			= ov772x_init,
 	.release		= ov772x_release,
 	.start_capture		= ov772x_start_capture,
@@ -1063,13 +1077,21 @@  static int ov772x_probe(struct i2c_client *client,
 {
 	struct ov772x_priv        *priv;
 	struct ov772x_camera_info *info;
-	struct soc_camera_device  *icd;
+	struct soc_camera_device  *icd = client->dev.platform_data;
 	struct i2c_adapter        *adapter = to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link    *icl;
 	int                        ret;
 
-	info = client->dev.platform_data;
-	if (!info)
+	if (!icd) {
+		dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
 		return -EINVAL;
+	}
+
+	icl = dev_get_drvdata(&icd->dev);
+	if (!icl)
+		return -EINVAL;
+
+	info = container_of(icl, struct ov772x_camera_info, link);
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 		dev_err(&adapter->dev,
@@ -1083,18 +1105,13 @@  static int ov772x_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	priv->info   = info;
-	priv->client = client;
 	i2c_set_clientdata(client, priv);
 
-	icd             = &priv->icd;
 	icd->ops        = &ov772x_ops;
-	icd->control    = &client->dev;
 	icd->width_max  = MAX_WIDTH;
 	icd->height_max = MAX_HEIGHT;
-	icd->iface      = priv->info->link.bus_id;
-
-	ret = soc_camera_device_register(icd);
 
+	ret = ov772x_video_probe(icd, client);
 	if (ret) {
 		i2c_set_clientdata(client, NULL);
 		kfree(priv);
@@ -1106,8 +1123,9 @@  static int ov772x_probe(struct i2c_client *client,
 static int ov772x_remove(struct i2c_client *client)
 {
 	struct ov772x_priv *priv = i2c_get_clientdata(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 
-	soc_camera_device_unregister(&priv->icd);
+	ov772x_video_remove(icd);
 	i2c_set_clientdata(client, NULL);
 	kfree(priv);
 	return 0;
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 2da5eef..63964d0 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -841,7 +841,8 @@  static void pxa_camera_init_videobuf(struct videobuf_queue *q,
 				sizeof(struct pxa_buffer), icd);
 }
 
-static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
+static u32 mclk_get_divisor(struct platform_device *pdev,
+			    struct pxa_camera_dev *pcdev)
 {
 	unsigned long mclk = pcdev->mclk;
 	u32 div;
@@ -853,7 +854,7 @@  static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
 	/* mclk <= ciclk / 4 (27.4.2) */
 	if (mclk > lcdclk / 4) {
 		mclk = lcdclk / 4;
-		dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk);
+		dev_warn(&pdev->dev, "Limiting master clock to %lu\n", mclk);
 	}
 
 	/* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
@@ -863,8 +864,8 @@  static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
 	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
 		pcdev->mclk = lcdclk / (2 * (div + 1));
 
-	dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, "
-		"divisor %u\n", lcdclk, mclk, div);
+	dev_dbg(&pdev->dev, "LCD clock %luHz, target freq %luHz, divisor %u\n",
+		lcdclk, mclk, div);
 
 	return div;
 }
@@ -969,15 +970,20 @@  static int pxa_camera_add_device(struct soc_camera_device *icd)
 		goto ebusy;
 	}
 
-	dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
-		 icd->devnum);
-
 	pxa_camera_activate(pcdev);
 	ret = icd->ops->init(icd);
+	if (ret < 0)
+		goto einit;
+
+	pcdev->icd = icd;
 
-	if (!ret)
-		pcdev->icd = icd;
+	dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
+		 icd->devnum);
 
+	return 0;
+
+einit:
+	pxa_camera_deactivate(pcdev);
 ebusy:
 	return ret;
 }
@@ -1599,7 +1605,7 @@  static int pxa_camera_probe(struct platform_device *pdev)
 		pcdev->mclk = 20000000;
 	}
 
-	pcdev->mclk_divisor = mclk_get_divisor(pcdev);
+	pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev);
 
 	INIT_LIST_HEAD(&pcdev->capture);
 	spin_lock_init(&pcdev->lock);
@@ -1746,3 +1752,4 @@  module_exit(pxa_camera_exit);
 MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME);
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index d369e84..ac9b467 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -360,11 +360,13 @@  static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 		 "SuperH Mobile CEU driver attached to camera %d\n",
 		 icd->devnum);
 
+	clk_enable(pcdev->clk);
+
 	ret = icd->ops->init(icd);
-	if (ret)
+	if (ret) {
+		clk_disable(pcdev->clk);
 		goto err;
-
-	clk_enable(pcdev->clk);
+	}
 
 	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
 	while (ceu_read(pcdev, CSTSR) & 1)
@@ -398,10 +400,10 @@  static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 	}
 	spin_unlock_irqrestore(&pcdev->lock, flags);
 
-	clk_disable(pcdev->clk);
-
 	icd->ops->release(icd);
 
+	clk_disable(pcdev->clk);
+
 	dev_info(&icd->dev,
 		 "SuperH Mobile CEU driver detached from camera %d\n",
 		 icd->devnum);
@@ -948,3 +950,4 @@  module_exit(sh_mobile_ceu_exit);
 MODULE_DESCRIPTION("SuperH Mobile CEU driver");
 MODULE_AUTHOR("Magnus Damm");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh_mobile_ceu");
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 03a6c29..d2b765d 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -16,19 +16,21 @@ 
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/device.h>
-#include <linux/list.h>
 #include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/vmalloc.h>
 
+#include <media/soc_camera.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-dev.h>
 #include <media/videobuf-core.h>
-#include <media/soc_camera.h>
 
 /* Default to VGA resolution */
 #define DEFAULT_WIDTH	640
@@ -36,7 +38,7 @@ 
 
 static LIST_HEAD(hosts);
 static LIST_HEAD(devices);
-static DEFINE_MUTEX(list_lock);
+static DEFINE_MUTEX(list_lock);		/* Protects the list of hosts */
 
 const struct soc_camera_data_format *soc_camera_format_by_fourcc(
 	struct soc_camera_device *icd, unsigned int fourcc)
@@ -207,6 +209,7 @@  static int soc_camera_dqbuf(struct file *file, void *priv,
 	return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
 }
 
+/* Always entered with .video_lock held */
 static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 {
 	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
@@ -255,9 +258,12 @@  static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 	return 0;
 }
 
+/* Always entered with .video_lock held */
 static void soc_camera_free_user_formats(struct soc_camera_device *icd)
 {
+	icd->current_fmt = NULL;
 	vfree(icd->user_formats);
+	icd->user_formats = NULL;
 }
 
 /* Called with .vb_lock held */
@@ -308,10 +314,6 @@  static int soc_camera_open(struct file *file)
 	struct soc_camera_file *icf;
 	int ret;
 
-	icf = vmalloc(sizeof(*icf));
-	if (!icf)
-		return -ENOMEM;
-
 	/*
 	 * It is safe to dereference these pointers now as long as a user has
 	 * the video device open - we are protected by the held cdev reference.
@@ -319,8 +321,17 @@  static int soc_camera_open(struct file *file)
 
 	vdev = video_devdata(file);
 	icd = container_of(vdev->parent, struct soc_camera_device, dev);
+
+	if (!icd->ops)
+		/* No device driver attached */
+		return -ENODEV;
+
 	ici = to_soc_camera_host(icd->dev.parent);
 
+	icf = vmalloc(sizeof(*icf));
+	if (!icf)
+		return -ENOMEM;
+
 	if (!try_module_get(icd->ops->owner)) {
 		dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
 		ret = -EINVAL;
@@ -333,7 +344,7 @@  static int soc_camera_open(struct file *file)
 		goto emgi;
 	}
 
-	/* Protect against icd->remove() until we module_get() both drivers. */
+	/* Protect against icd->ops->remove() until we module_get() both drivers. */
 	mutex_lock(&icd->video_lock);
 
 	icf->icd = icd;
@@ -348,11 +359,16 @@  static int soc_camera_open(struct file *file)
 				.width		= icd->width,
 				.height		= icd->height,
 				.field		= icd->field,
-				.pixelformat	= icd->current_fmt->fourcc,
-				.colorspace	= icd->current_fmt->colorspace,
 			},
 		};
 
+		ret = soc_camera_init_user_formats(icd);
+		if (ret < 0)
+			goto eiufmt;
+
+		f.fmt.pix.pixelformat	= icd->current_fmt->fourcc;
+		f.fmt.pix.colorspace	= icd->current_fmt->colorspace;
+
 		ret = ici->ops->add(icd);
 		if (ret < 0) {
 			dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
@@ -381,6 +397,8 @@  static int soc_camera_open(struct file *file)
 esfmt:
 	ici->ops->remove(icd);
 eiciadd:
+	soc_camera_free_user_formats(icd);
+eiufmt:
 	icd->use_count--;
 	mutex_unlock(&icd->video_lock);
 	module_put(ici->ops->owner);
@@ -400,8 +418,10 @@  static int soc_camera_close(struct file *file)
 
 	mutex_lock(&icd->video_lock);
 	icd->use_count--;
-	if (!icd->use_count)
+	if (!icd->use_count) {
 		ici->ops->remove(icd);
+		soc_camera_free_user_formats(icd);
+	}
 
 	mutex_unlock(&icd->video_lock);
 
@@ -762,29 +782,6 @@  static int soc_camera_s_register(struct file *file, void *fh,
 }
 #endif
 
-static int device_register_link(struct soc_camera_device *icd)
-{
-	int ret = dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
-
-	if (!ret)
-		ret = device_register(&icd->dev);
-
-	if (ret < 0) {
-		/* Prevent calling device_unregister() */
-		icd->dev.parent = NULL;
-		dev_err(&icd->dev, "Cannot register device: %d\n", ret);
-	/* Even if probe() was unsuccessful for all registered drivers,
-	 * device_register() returns 0, and we add the link, just to
-	 * document this camera's control device */
-	} else if (icd->control)
-		/* Have to sysfs_remove_link() before device_unregister()? */
-		if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
-				      "control"))
-			dev_warn(&icd->dev,
-				 "Failed creating the control symlink\n");
-	return ret;
-}
-
 /* So far this function cannot fail */
 static void scan_add_host(struct soc_camera_host *ici)
 {
@@ -794,103 +791,70 @@  static void scan_add_host(struct soc_camera_host *ici)
 
 	list_for_each_entry(icd, &devices, list) {
 		if (icd->iface == ici->nr) {
+			int ret;
 			icd->dev.parent = ici->dev;
-			device_register_link(icd);
-		}
-	}
-
-	mutex_unlock(&list_lock);
-}
-
-/* return: 0 if no match found or a match found and
- * device_register() successful, error code otherwise */
-static int scan_add_device(struct soc_camera_device *icd)
-{
-	struct soc_camera_host *ici;
-	int ret = 0;
-
-	mutex_lock(&list_lock);
-
-	list_add_tail(&icd->list, &devices);
-
-	/* Watch out for class_for_each_device / class_find_device API by
-	 * Dave Young <hidave.darkstar@gmail.com> */
-	list_for_each_entry(ici, &hosts, list) {
-		if (icd->iface == ici->nr) {
-			ret = 1;
-			icd->dev.parent = ici->dev;
-			break;
+			dev_set_name(&icd->dev, "%u-%u", icd->iface,
+				     icd->devnum);
+			ret = device_register(&icd->dev);
+			if (ret < 0) {
+				icd->dev.parent = NULL;
+				dev_err(&icd->dev,
+					"Cannot register device: %d\n", ret);
+			}
 		}
 	}
 
 	mutex_unlock(&list_lock);
-
-	if (ret)
-		ret = device_register_link(icd);
-
-	return ret;
 }
 
+static int video_dev_create(struct soc_camera_device *icd);
+/* Called during host-driver probe */
 static int soc_camera_probe(struct device *dev)
 {
 	struct soc_camera_device *icd = to_soc_camera_dev(dev);
-	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	int ret;
+	struct i2c_client *client;
+	struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
 
-	/*
-	 * Possible race scenario:
-	 * modprobe <camera-host-driver> triggers __func__
-	 * at this moment respective <camera-sensor-driver> gets rmmod'ed
-	 * to protect take module references.
-	 */
-
-	if (!try_module_get(icd->ops->owner)) {
-		dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
-		ret = -EINVAL;
-		goto emgd;
-	}
-
-	if (!try_module_get(ici->ops->owner)) {
-		dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
-		ret = -EINVAL;
-		goto emgi;
+	if (!adap) {
+		ret = -ENODEV;
+		dev_err(dev, "Cannot get I2C adapter %d\n", icl->i2c_adapter_id);
+		goto ei2cga;
 	}
 
-	mutex_lock(&icd->video_lock);
+	dev_info(dev, "Probing %s\n", dev_name(dev));
 
-	/* We only call ->add() here to activate and probe the camera.
-	 * We shall ->remove() and deactivate it immediately afterwards. */
-	ret = ici->ops->add(icd);
-	if (ret < 0)
-		goto eiadd;
+	client = i2c_new_device(adap, icl->board_info);
+	if (!client) {
+		ret = -ENOMEM;
+		goto ei2cnd;
+	}
 
-	ret = icd->ops->probe(icd);
-	if (ret >= 0) {
-		const struct v4l2_queryctrl *qctrl;
+	/*
+	 * We set icd drvdata at two locations - here and in
+	 * soc_camera_video_start(). Depending on the module loading /
+	 * initialisation order one of these locations will be entered first
+	 */
+	/* Use to_i2c_client(dev) to recover the i2c client */
+	dev_set_drvdata(&icd->dev, &client->dev);
 
-		qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
-		icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
-		qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
-		icd->exposure = qctrl ? qctrl->default_value :
-			(unsigned short)~0;
+	/* Do we have to sysfs_remove_link() before device_unregister()? */
+	if (sysfs_create_link(&dev->kobj, &to_soc_camera_control(icd)->kobj,
+			      "control"))
+		dev_warn(dev, "Failed creating the control symlink\n");
 
-		ret = soc_camera_init_user_formats(icd);
-		if (ret < 0)
-			goto eiufmt;
+	ret = video_dev_create(icd);
+	if (ret < 0)
+		goto evdc;
 
-		icd->height	= DEFAULT_HEIGHT;
-		icd->width	= DEFAULT_WIDTH;
-		icd->field	= V4L2_FIELD_ANY;
-	}
+	return 0;
 
-eiufmt:
-	ici->ops->remove(icd);
-eiadd:
-	mutex_unlock(&icd->video_lock);
-	module_put(ici->ops->owner);
-emgi:
-	module_put(icd->ops->owner);
-emgd:
+evdc:
+	i2c_unregister_device(client);
+ei2cnd:
+	i2c_put_adapter(adap);
+ei2cga:
 	return ret;
 }
 
@@ -899,11 +863,23 @@  emgd:
 static int soc_camera_remove(struct device *dev)
 {
 	struct soc_camera_device *icd = to_soc_camera_dev(dev);
+	struct video_device *vdev = icd->vdev;
 
-	if (icd->ops->remove)
-		icd->ops->remove(icd);
+	BUG_ON(!dev->parent);
 
-	soc_camera_free_user_formats(icd);
+	if (vdev) {
+		mutex_lock(&icd->video_lock);
+		video_unregister_device(vdev);
+		icd->vdev = NULL;
+		mutex_unlock(&icd->video_lock);
+	}
+
+	if (to_soc_camera_control(icd)) {
+		struct i2c_client *client =
+			to_i2c_client(to_soc_camera_control(icd));
+		i2c_unregister_device(client);
+		i2c_put_adapter(client->adapter);
+	}
 
 	return 0;
 }
@@ -998,10 +974,14 @@  void soc_camera_host_unregister(struct soc_camera_host *ici)
 
 	list_for_each_entry(icd, &devices, list) {
 		if (icd->dev.parent == ici->dev) {
+			/* The bus->remove will be called */
 			device_unregister(&icd->dev);
 			/* Not before device_unregister(), .remove
 			 * needs parent to call ici->ops->remove() */
 			icd->dev.parent = NULL;
+
+			/* If the host module is loaded again, device_register()
+			 * would complain "already initialised" */
 			memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
 		}
 	}
@@ -1013,26 +993,14 @@  void soc_camera_host_unregister(struct soc_camera_host *ici)
 EXPORT_SYMBOL(soc_camera_host_unregister);
 
 /* Image capture device */
-int soc_camera_device_register(struct soc_camera_device *icd)
+static int soc_camera_device_register(struct soc_camera_device *icd)
 {
 	struct soc_camera_device *ix;
 	int num = -1, i;
 
-	if (!icd || !icd->ops ||
-	    !icd->ops->probe ||
-	    !icd->ops->init ||
-	    !icd->ops->release ||
-	    !icd->ops->start_capture ||
-	    !icd->ops->stop_capture ||
-	    !icd->ops->set_crop ||
-	    !icd->ops->set_fmt ||
-	    !icd->ops->try_fmt ||
-	    !icd->ops->query_bus_param ||
-	    !icd->ops->set_bus_param)
-		return -EINVAL;
-
 	for (i = 0; i < 256 && num < 0; i++) {
 		num = i;
+		/* Check if this index is available on this interface */
 		list_for_each_entry(ix, &devices, list) {
 			if (ix->iface == icd->iface && ix->devnum == i) {
 				num = -1;
@@ -1054,21 +1022,15 @@  int soc_camera_device_register(struct soc_camera_device *icd)
 	icd->host_priv		= NULL;
 	mutex_init(&icd->video_lock);
 
-	return scan_add_device(icd);
+	list_add_tail(&icd->list, &devices);
+
+	return 0;
 }
-EXPORT_SYMBOL(soc_camera_device_register);
 
-void soc_camera_device_unregister(struct soc_camera_device *icd)
+static void soc_camera_device_unregister(struct soc_camera_device *icd)
 {
-	mutex_lock(&list_lock);
 	list_del(&icd->list);
-
-	/* The bus->remove will be eventually called */
-	if (icd->dev.parent)
-		device_unregister(&icd->dev);
-	mutex_unlock(&list_lock);
 }
-EXPORT_SYMBOL(soc_camera_device_unregister);
 
 static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
 	.vidioc_querycap	 = soc_camera_querycap,
@@ -1099,22 +1061,14 @@  static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
 #endif
 };
 
-/*
- * Usually called from the struct soc_camera_ops .probe() method, i.e., from
- * soc_camera_probe() above with .video_lock held
- */
-int soc_camera_video_start(struct soc_camera_device *icd)
+static int video_dev_create(struct soc_camera_device *icd)
 {
 	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-	int err = -ENOMEM;
-	struct video_device *vdev;
-
-	if (!icd->dev.parent)
-		return -ENODEV;
+	int ret;
+	struct video_device *vdev = video_device_alloc();
 
-	vdev = video_device_alloc();
 	if (!vdev)
-		goto evidallocd;
+		return -ENOMEM;
 	dev_dbg(ici->dev, "Allocated video_device %p\n", vdev);
 
 	strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
@@ -1125,10 +1079,10 @@  int soc_camera_video_start(struct soc_camera_device *icd)
 	vdev->ioctl_ops		= &soc_camera_ioctl_ops;
 	vdev->release		= video_device_release;
 	vdev->minor		= -1;
-	vdev->tvnorms		= V4L2_STD_UNKNOWN,
+	vdev->tvnorms		= V4L2_STD_UNKNOWN;
 
-	err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
-	if (err < 0) {
+	ret = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
+	if (ret < 0) {
 		dev_err(vdev->parent, "video_register_device failed\n");
 		goto evidregd;
 	}
@@ -1138,27 +1092,99 @@  int soc_camera_video_start(struct soc_camera_device *icd)
 
 evidregd:
 	video_device_release(vdev);
-evidallocd:
-	return err;
+	return ret;
+}
+
+/*
+ * Usually called from the struct soc_camera_ops .probe() method, i.e., from
+ * soc_camera_probe() above with .video_lock held
+ */
+int soc_camera_video_start(struct soc_camera_device *icd, struct device *dev)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	const struct v4l2_queryctrl *qctrl;
+
+	if (!icd->dev.parent)
+		return -ENODEV;
+
+	if (!icd->ops ||
+	    !icd->ops->init ||
+	    !icd->ops->release ||
+	    !icd->ops->start_capture ||
+	    !icd->ops->stop_capture ||
+	    !icd->ops->set_fmt ||
+	    !icd->ops->try_fmt ||
+	    !icd->ops->query_bus_param ||
+	    !icd->ops->set_bus_param)
+		return -EINVAL;
+
+	/* See comment in soc_camera_probe() */
+	dev_set_drvdata(&icd->dev, dev);
+
+	qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
+	icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
+	qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
+	icd->exposure = qctrl ? qctrl->default_value : (unsigned short)~0;
+
+	return ici->ops->add(icd);
 }
 EXPORT_SYMBOL(soc_camera_video_start);
 
 void soc_camera_video_stop(struct soc_camera_device *icd)
 {
-	struct video_device *vdev = icd->vdev;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
 	dev_dbg(&icd->dev, "%s\n", __func__);
 
-	if (!icd->dev.parent || !vdev)
-		return;
-
-	mutex_lock(&icd->video_lock);
-	video_unregister_device(vdev);
-	icd->vdev = NULL;
-	mutex_unlock(&icd->video_lock);
+	ici->ops->remove(icd);
 }
 EXPORT_SYMBOL(soc_camera_video_stop);
 
+static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
+{
+	struct soc_camera_link *icl = pdev->dev.platform_data;
+	struct soc_camera_device *icd;
+
+	if (!icl)
+		return -EINVAL;
+
+	icd = kzalloc(sizeof(*icd), GFP_KERNEL);
+	if (!icd)
+		return -ENOMEM;
+
+	icd->iface = icl->bus_id;
+	icl->board_info->platform_data = icd;
+	platform_set_drvdata(pdev, icd);
+	icd->dev.platform_data = icl;
+
+	return soc_camera_device_register(icd);
+}
+
+/* Only called on rmmod for each platform device, since they are not
+ * hot-pluggable. Now we know, that all our users - hosts and devices have
+ * been unloaded already */
+static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
+{
+	struct soc_camera_device *icd = platform_get_drvdata(pdev);
+
+	if (!icd)
+		return -EINVAL;
+
+	soc_camera_device_unregister(icd);
+
+	kfree(icd);
+
+	return 0;
+}
+
+static struct platform_driver soc_camera_pdrv = {
+	.remove  = __exit_p(soc_camera_pdrv_remove),
+	.driver  = {
+		.name = "soc-camera-pdrv",
+		.owner = THIS_MODULE,
+	},
+};
+
 static int __init soc_camera_init(void)
 {
 	int ret = bus_register(&soc_camera_bus_type);
@@ -1168,8 +1194,14 @@  static int __init soc_camera_init(void)
 	if (ret)
 		goto edrvr;
 
+	ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
+	if (ret)
+		goto epdr;
+
 	return 0;
 
+epdr:
+	driver_unregister(&ic_drv);
 edrvr:
 	bus_unregister(&soc_camera_bus_type);
 	return ret;
@@ -1177,6 +1209,7 @@  edrvr:
 
 static void __exit soc_camera_exit(void)
 {
+	platform_driver_unregister(&soc_camera_pdrv);
 	driver_unregister(&ic_drv);
 	bus_unregister(&soc_camera_bus_type);
 }
@@ -1187,3 +1220,4 @@  module_exit(soc_camera_exit);
 MODULE_DESCRIPTION("Image capture bus driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-camera-pdrv");
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index c486763..021f9f1 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -20,49 +20,52 @@ 
 #include <media/soc_camera.h>
 #include <media/soc_camera_platform.h>
 
+static const char drv_name[] = "soc_camera_platform";
+
 struct soc_camera_platform_priv {
 	struct soc_camera_platform_info *info;
-	struct soc_camera_device icd;
 	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_info *i2c_to_info(struct i2c_client *client)
 {
-	struct soc_camera_platform_priv *priv;
-	priv = container_of(icd, struct soc_camera_platform_priv, icd);
+	struct soc_camera_platform_priv *priv = i2c_get_clientdata(client);
 	return priv->info;
 }
 
 static int soc_camera_platform_init(struct soc_camera_device *icd)
 {
-	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_platform_info *p = i2c_to_info(client);
 
-	if (p->power)
-		p->power(1);
+	if (p->link.power)
+		p->link.power(&client->dev, 1);
 
 	return 0;
 }
 
 static int soc_camera_platform_release(struct soc_camera_device *icd)
 {
-	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_platform_info *p = i2c_to_info(client);
 
-	if (p->power)
-		p->power(0);
+	if (p->link.power)
+		p->link.power(&client->dev, 0);
 
 	return 0;
 }
 
 static int soc_camera_platform_start_capture(struct soc_camera_device *icd)
 {
-	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_platform_info *p = i2c_to_info(client);
 	return p->set_capture(p, 1);
 }
 
 static int soc_camera_platform_stop_capture(struct soc_camera_device *icd)
 {
-	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_platform_info *p = i2c_to_info(client);
 	return p->set_capture(p, 0);
 }
 
@@ -75,7 +78,8 @@  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 i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_platform_info *p = i2c_to_info(client);
 	return p->bus_param;
 }
 
@@ -94,7 +98,8 @@  static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
 static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
 				       struct v4l2_format *f)
 {
-	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_platform_info *p = i2c_to_info(client);
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 
 	pix->width = p->format.width;
@@ -102,31 +107,30 @@  static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
 	return 0;
 }
 
-static int soc_camera_platform_video_probe(struct soc_camera_device *icd)
+static int soc_camera_platform_video_probe(struct soc_camera_device *icd,
+					   struct i2c_client *client)
 {
-	struct soc_camera_platform_priv *priv;
-	priv = container_of(icd, struct soc_camera_platform_priv, icd);
+	struct soc_camera_platform_priv *priv = i2c_get_clientdata(client);
+	struct soc_camera_platform_info *p = priv->info;
 
-	priv->format.name = priv->info->format_name;
-	priv->format.depth = priv->info->format_depth;
-	priv->format.fourcc = priv->info->format.pixelformat;
-	priv->format.colorspace = priv->info->format.colorspace;
+	priv->format.name = p->format_name;
+	priv->format.depth = p->format_depth;
+	priv->format.fourcc = p->format.pixelformat;
+	priv->format.colorspace = p->format.colorspace;
 
 	icd->formats = &priv->format;
 	icd->num_formats = 1;
 
-	return soc_camera_video_start(icd);
+	return 0;
 }
 
 static void soc_camera_platform_video_remove(struct soc_camera_device *icd)
 {
-	soc_camera_video_stop(icd);
+	icd->ops = NULL;
 }
 
 static struct soc_camera_ops soc_camera_platform_ops = {
 	.owner			= THIS_MODULE,
-	.probe			= soc_camera_platform_video_probe,
-	.remove			= soc_camera_platform_video_remove,
 	.init			= soc_camera_platform_init,
 	.release		= soc_camera_platform_release,
 	.start_capture		= soc_camera_platform_start_capture,
@@ -138,66 +142,85 @@  static struct soc_camera_ops soc_camera_platform_ops = {
 	.query_bus_param	= soc_camera_platform_query_bus_param,
 };
 
-static int soc_camera_platform_probe(struct platform_device *pdev)
+static int soc_camera_platform_probe(struct i2c_client *client,
+				     const struct i2c_device_id *did)
 {
 	struct soc_camera_platform_priv *priv;
 	struct soc_camera_platform_info *p;
-	struct soc_camera_device *icd;
+	struct soc_camera_device *icd = client->dev.platform_data;
+	struct soc_camera_link *icl;
 	int ret;
 
-	p = pdev->dev.platform_data;
-	if (!p)
+	if (!icd) {
+		dev_err(&client->dev, "%s: missing soc-camera data!\n", drv_name);
 		return -EINVAL;
+	}
+
+	icl = dev_get_drvdata(&icd->dev);
+	if (!icl) {
+		dev_err(&client->dev, "%s driver needs platform data\n", drv_name);
+		return -EINVAL;
+	}
+
+	p = container_of(icl, struct soc_camera_platform_info, link);
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
 	priv->info = p;
-	platform_set_drvdata(pdev, priv);
+	i2c_set_clientdata(client, priv);
 
-	icd = &priv->icd;
 	icd->ops	= &soc_camera_platform_ops;
-	icd->control	= &pdev->dev;
 	icd->width_min	= 0;
-	icd->width_max	= priv->info->format.width;
+	icd->width_max	= p->format.width;
 	icd->height_min	= 0;
-	icd->height_max	= priv->info->format.height;
+	icd->height_max	= p->format.height;
 	icd->y_skip_top	= 0;
-	icd->iface	= priv->info->iface;
 
-	ret = soc_camera_device_register(icd);
-	if (ret)
+	ret = soc_camera_platform_video_probe(icd, client);
+	if (ret) {
+		i2c_set_clientdata(client, NULL);
 		kfree(priv);
+	}
 
 	return ret;
 }
 
-static int soc_camera_platform_remove(struct platform_device *pdev)
+static int soc_camera_platform_remove(struct i2c_client *client)
 {
-	struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev);
+	struct soc_camera_platform_priv *priv = i2c_get_clientdata(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 
-	soc_camera_device_unregister(&priv->icd);
+	soc_camera_platform_video_remove(icd);
+	i2c_set_clientdata(client, NULL);
 	kfree(priv);
 	return 0;
 }
 
-static struct platform_driver soc_camera_platform_driver = {
+static const struct i2c_device_id soc_camera_platform_id[] = {
+	{ "soc_camera_platform", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, soc_camera_platform_id);
+
+static struct i2c_driver soc_camera_platform_driver = {
 	.driver 	= {
 		.name	= "soc_camera_platform",
 	},
 	.probe		= soc_camera_platform_probe,
 	.remove		= soc_camera_platform_remove,
+	.id_table	= soc_camera_platform_id,
 };
 
 static int __init soc_camera_platform_module_init(void)
 {
-	return platform_driver_register(&soc_camera_platform_driver);
+	return i2c_add_driver(&soc_camera_platform_driver);
 }
 
 static void __exit soc_camera_platform_module_exit(void)
 {
-	platform_driver_unregister(&soc_camera_platform_driver);
+	i2c_del_driver(&soc_camera_platform_driver);
 }
 
 module_init(soc_camera_platform_module_init);
@@ -206,3 +229,4 @@  module_exit(soc_camera_platform_module_exit);
 MODULE_DESCRIPTION("SoC Camera Platform driver");
 MODULE_AUTHOR("Magnus Damm");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:soc_camera_platform");
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index a399476..419e596 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -224,8 +224,6 @@  struct tw9910_hsync_ctrl {
 
 struct tw9910_priv {
 	struct tw9910_video_info       *info;
-	struct i2c_client              *client;
-	struct soc_camera_device        icd;
 	const struct tw9910_scale_ctrl *scale;
 };
 
@@ -511,35 +509,38 @@  tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
  */
 static int tw9910_init(struct soc_camera_device *icd)
 {
-	struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	int ret = 0;
 
-	if (priv->info->link.power) {
-		ret = priv->info->link.power(&priv->client->dev, 1);
+	if (icl->power) {
+		ret = icl->power(&client->dev, 1);
 		if (ret < 0)
 			return ret;
 	}
 
-	if (priv->info->link.reset)
-		ret = priv->info->link.reset(&priv->client->dev);
+	if (icl->reset)
+		ret = icl->reset(&client->dev);
 
 	return ret;
 }
 
 static int tw9910_release(struct soc_camera_device *icd)
 {
-	struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	int ret = 0;
 
-	if (priv->info->link.power)
-		ret = priv->info->link.power(&priv->client->dev, 0);
+	if (icl->power)
+		ret = icl->power(&client->dev, 0);
 
 	return ret;
 }
 
 static int tw9910_start_capture(struct soc_camera_device *icd)
 {
-	struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct tw9910_priv *priv = i2c_get_clientdata(client);
 
 	if (!priv->scale) {
 		dev_err(&icd->dev, "norm select error\n");
@@ -567,8 +568,9 @@  static int tw9910_set_bus_param(struct soc_camera_device *icd,
 
 static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd)
 {
-	struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
-	struct soc_camera_link *icl = priv->client->dev.platform_data;
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct tw9910_priv *priv = i2c_get_clientdata(client);
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
 	unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
 		SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
 		SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
@@ -610,13 +612,13 @@  static int tw9910_enum_input(struct soc_camera_device *icd,
 static int tw9910_get_register(struct soc_camera_device *icd,
 			       struct v4l2_dbg_register *reg)
 {
-	struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 	int ret;
 
 	if (reg->reg > 0xff)
 		return -EINVAL;
 
-	ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+	ret = i2c_smbus_read_byte_data(client, reg->reg);
 	if (ret < 0)
 		return ret;
 
@@ -631,20 +633,21 @@  static int tw9910_get_register(struct soc_camera_device *icd,
 static int tw9910_set_register(struct soc_camera_device *icd,
 			       struct v4l2_dbg_register *reg)
 {
-	struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
 
 	if (reg->reg > 0xff ||
 	    reg->val > 0xff)
 		return -EINVAL;
 
-	return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+	return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
 }
 #endif
 
 static int tw9910_set_crop(struct soc_camera_device *icd,
 			   struct v4l2_rect *rect)
 {
-	struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+	struct tw9910_priv *priv = i2c_get_clientdata(client);
 	int                 ret  = -EINVAL;
 	u8                  val;
 
@@ -658,8 +661,8 @@  static int tw9910_set_crop(struct soc_camera_device *icd,
 	/*
 	 * reset hardware
 	 */
-	tw9910_reset(priv->client);
-	ret = tw9910_write_array(priv->client, tw9910_default_regs);
+	tw9910_reset(client);
+	ret = tw9910_write_array(client, tw9910_default_regs);
 	if (ret < 0)
 		goto tw9910_set_fmt_error;
 
@@ -670,7 +673,7 @@  static int tw9910_set_crop(struct soc_camera_device *icd,
 	if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
 		val = LEN;
 
-	ret = tw9910_mask_set(priv->client, OPFORM, LEN, val);
+	ret = tw9910_mask_set(client, OPFORM, LEN, val);
 	if (ret < 0)
 		goto tw9910_set_fmt_error;
 
@@ -698,28 +701,28 @@  static int tw9910_set_crop(struct soc_camera_device *icd,
 		val = 0;
 	}
 
-	ret = tw9910_mask_set(priv->client, VBICNTL, RTSEL_MASK, val);
+	ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
 	if (ret < 0)
 		goto tw9910_set_fmt_error;
 
 	/*
 	 * set scale
 	 */
-	ret = tw9910_set_scale(priv->client, priv->scale);
+	ret = tw9910_set_scale(client, priv->scale);
 	if (ret < 0)
 		goto tw9910_set_fmt_error;
 
 	/*
 	 * set cropping
 	 */
-	ret = tw9910_set_cropping(priv->client, &tw9910_cropping_ctrl);
+	ret = tw9910_set_cropping(client, &tw9910_cropping_ctrl);
 	if (ret < 0)
 		goto tw9910_set_fmt_error;
 
 	/*
 	 * set hsync
 	 */
-	ret = tw9910_set_hsync(priv->client, &tw9910_hsync_ctrl);
+	ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl);
 	if (ret < 0)
 		goto tw9910_set_fmt_error;
 
@@ -727,7 +730,7 @@  static int tw9910_set_crop(struct soc_camera_device *icd,
 
 tw9910_set_fmt_error:
 
-	tw9910_reset(priv->client);
+	tw9910_reset(client);
 	priv->scale = NULL;
 
 	return ret;
@@ -784,9 +787,10 @@  static int tw9910_try_fmt(struct soc_camera_device *icd,
 	return 0;
 }
 
-static int tw9910_video_probe(struct soc_camera_device *icd)
+static int tw9910_video_probe(struct soc_camera_device *icd,
+			      struct i2c_client *client)
 {
-	struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+	struct tw9910_priv *priv = i2c_get_clientdata(client);
 	s32 val;
 	int ret;
 
@@ -810,10 +814,18 @@  static int tw9910_video_probe(struct soc_camera_device *icd)
 	icd->formats     = tw9910_color_fmt;
 	icd->num_formats = ARRAY_SIZE(tw9910_color_fmt);
 
+	/* Switch master clock on */
+	ret = soc_camera_video_start(icd, &client->dev);
+	if (ret)
+		return ret;
+
 	/*
 	 * check and show Product ID
 	 */
-	val = i2c_smbus_read_byte_data(priv->client, ID);
+	val = i2c_smbus_read_byte_data(client, ID);
+
+	soc_camera_video_stop(icd);
+
 	if (0x0B != GET_ID(val) ||
 	    0x00 != GET_ReV(val)) {
 		dev_err(&icd->dev,
@@ -824,10 +836,6 @@  static int tw9910_video_probe(struct soc_camera_device *icd)
 	dev_info(&icd->dev,
 		 "tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val));
 
-	ret = soc_camera_video_start(icd);
-	if (ret < 0)
-		return ret;
-
 	icd->vdev->tvnorms      = V4L2_STD_NTSC | V4L2_STD_PAL;
 	icd->vdev->current_norm = V4L2_STD_NTSC;
 
@@ -836,13 +844,11 @@  static int tw9910_video_probe(struct soc_camera_device *icd)
 
 static void tw9910_video_remove(struct soc_camera_device *icd)
 {
-	soc_camera_video_stop(icd);
+	icd->ops = NULL;
 }
 
 static struct soc_camera_ops tw9910_ops = {
 	.owner			= THIS_MODULE,
-	.probe			= tw9910_video_probe,
-	.remove			= tw9910_video_remove,
 	.init			= tw9910_init,
 	.release		= tw9910_release,
 	.start_capture		= tw9910_start_capture,
@@ -871,16 +877,25 @@  static int tw9910_probe(struct i2c_client *client,
 {
 	struct tw9910_priv             *priv;
 	struct tw9910_video_info       *info;
-	struct soc_camera_device       *icd;
+	struct soc_camera_device       *icd = client->dev.platform_data;
+	struct i2c_adapter             *adapter =
+		to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link         *icl;
 	const struct tw9910_scale_ctrl *scale;
 	int                             i, ret;
 
-	info = client->dev.platform_data;
-	if (!info)
+	if (!icd) {
+		dev_err(&client->dev, "TW9910: missing soc-camera data!\n");
 		return -EINVAL;
+	}
 
-	if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent),
-				     I2C_FUNC_SMBUS_BYTE_DATA)) {
+	icl = to_soc_camera_link(icd);
+	if (!icl)
+		return -EINVAL;
+
+	info = container_of(icl, struct tw9910_video_info, link);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 		dev_err(&client->dev,
 			"I2C-Adapter doesn't support "
 			"I2C_FUNC_SMBUS_BYTE_DATA\n");
@@ -892,12 +907,9 @@  static int tw9910_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	priv->info   = info;
-	priv->client = client;
 	i2c_set_clientdata(client, priv);
 
-	icd          = &priv->icd;
 	icd->ops     = &tw9910_ops;
-	icd->control = &client->dev;
 	icd->iface   = info->link.bus_id;
 
 	/*
@@ -923,8 +935,7 @@  static int tw9910_probe(struct i2c_client *client,
 		icd->height_min = min(scale[i].height, icd->height_min);
 	}
 
-	ret = soc_camera_device_register(icd);
-
+	ret = tw9910_video_probe(icd, client);
 	if (ret) {
 		i2c_set_clientdata(client, NULL);
 		kfree(priv);
@@ -936,8 +947,9 @@  static int tw9910_probe(struct i2c_client *client,
 static int tw9910_remove(struct i2c_client *client)
 {
 	struct tw9910_priv *priv = i2c_get_clientdata(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
 
-	soc_camera_device_unregister(&priv->icd);
+	tw9910_video_remove(icd);
 	i2c_set_clientdata(client, NULL);
 	kfree(priv);
 	return 0;
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index bef5e81..977326e 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -12,6 +12,7 @@ 
 #ifndef SOC_CAMERA_H
 #define SOC_CAMERA_H
 
+#include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/videodev2.h>
@@ -20,7 +21,6 @@ 
 struct soc_camera_device {
 	struct list_head list;
 	struct device dev;
-	struct device *control;
 	unsigned short width;		/* Current window */
 	unsigned short height;		/* sizes */
 	unsigned short x_min;		/* Camera capabilities */
@@ -97,6 +97,8 @@  struct soc_camera_link {
 	int bus_id;
 	/* Per camera SOCAM_SENSOR_* bus flags */
 	unsigned long flags;
+	int i2c_adapter_id;
+	struct i2c_board_info *board_info;
 	/* Optional callbacks to power on or off and reset the sensor */
 	int (*power)(struct device *, int);
 	int (*reset)(struct device *);
@@ -120,17 +122,25 @@  static inline struct soc_camera_host *to_soc_camera_host(struct device *dev)
 	return dev_get_drvdata(dev);
 }
 
-extern int soc_camera_host_register(struct soc_camera_host *ici);
-extern void soc_camera_host_unregister(struct soc_camera_host *ici);
-extern int soc_camera_device_register(struct soc_camera_device *icd);
-extern void soc_camera_device_unregister(struct soc_camera_device *icd);
+static inline struct soc_camera_link *to_soc_camera_link(struct soc_camera_device *icd)
+{
+	return icd->dev.platform_data;
+}
 
-extern int soc_camera_video_start(struct soc_camera_device *icd);
-extern void soc_camera_video_stop(struct soc_camera_device *icd);
+static inline struct device *to_soc_camera_control(struct soc_camera_device *icd)
+{
+	return dev_get_drvdata(&icd->dev);
+}
 
-extern const struct soc_camera_data_format *soc_camera_format_by_fourcc(
+int soc_camera_host_register(struct soc_camera_host *ici);
+void soc_camera_host_unregister(struct soc_camera_host *ici);
+
+int soc_camera_video_start(struct soc_camera_device *icd, struct device *dev);
+void soc_camera_video_stop(struct soc_camera_device *icd);
+
+const struct soc_camera_data_format *soc_camera_format_by_fourcc(
 	struct soc_camera_device *icd, unsigned int fourcc);
-extern const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
 	struct soc_camera_device *icd, unsigned int fourcc);
 
 struct soc_camera_data_format {
@@ -159,8 +169,6 @@  struct soc_camera_format_xlate {
 
 struct soc_camera_ops {
 	struct module *owner;
-	int (*probe)(struct soc_camera_device *);
-	void (*remove)(struct soc_camera_device *);
 	int (*suspend)(struct soc_camera_device *, pm_message_t state);
 	int (*resume)(struct soc_camera_device *);
 	int (*init)(struct soc_camera_device *);
diff --git a/include/media/soc_camera_platform.h b/include/media/soc_camera_platform.h
index 1d092b4..db7ff89 100644
--- a/include/media/soc_camera_platform.h
+++ b/include/media/soc_camera_platform.h
@@ -14,13 +14,12 @@ 
 #include <linux/videodev2.h>
 
 struct soc_camera_platform_info {
-	int iface;
-	char *format_name;
+	const char *format_name;
 	unsigned long format_depth;
 	struct v4l2_pix_format format;
 	unsigned long bus_param;
-	void (*power)(int);
 	int (*set_capture)(struct soc_camera_platform_info *info, int enable);
+	struct soc_camera_link link;
 };
 
 #endif /* __SOC_CAMERA_H__ */