V4L/DVB (12506): soc-camera: convert to platform device
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Tue, 25 Aug 2009 14:28:22 +0000 (11:28 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Sat, 19 Sep 2009 03:18:27 +0000 (00:18 -0300)
Convert soc-camera core and all drivers to platform device API. We already
converted platforms to register a platform device for each soc-camera client,
now we remove the compatibility code and switch completely to the new scheme.
This is a preparatory step for the v4l2-subdev conversion.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
13 files changed:
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9v022.c
drivers/media/video/mx3_camera.c
drivers/media/video/ov772x.c
drivers/media/video/pxa_camera.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/soc_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/tw9910.c
include/media/soc_camera.h
include/media/soc_camera_platform.h

index 4d794b4..1e4f269 100644 (file)
@@ -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;
 
@@ -290,12 +286,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;
@@ -308,7 +305,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;
@@ -328,7 +325,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;
@@ -381,15 +378,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,
@@ -412,8 +405,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) {
@@ -432,8 +425,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;
 
@@ -525,11 +518,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;
@@ -540,6 +533,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);
@@ -547,6 +545,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:
@@ -559,10 +559,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;
@@ -588,26 +587,16 @@ 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);
        if (icl->free_bus)
                icl->free_bus(icl);
 }
@@ -616,11 +605,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;
@@ -636,13 +631,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;
@@ -652,27 +644,29 @@ 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) {
+               icd->ops = NULL;
+               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);
+       icd->ops = NULL;
+       mt9m001_video_remove(icd);
+       i2c_set_clientdata(client, NULL);
+       client->driver = NULL;
        kfree(mt9m001);
 
        return 0;
index fc5e2de..95c2f08 100644 (file)
@@ -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)
+               goto evstart;
+
        ret = mt9m111_enable(icd);
        if (ret)
                goto ei2c;
@@ -945,40 +954,33 @@ 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);
+evstart:
        return ret;
 }
 
-static void mt9m111_video_remove(struct soc_camera_device *icd)
-{
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, 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);
-}
-
 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 +996,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 +1009,25 @@ 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) {
+               icd->ops = NULL;
+               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;
+
+       icd->ops = NULL;
+       i2c_set_clientdata(client, NULL);
+       client->driver = NULL;
        kfree(mt9m111);
 
        return 0;
index 4207fb3..d9c7c2f 100644 (file)
@@ -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 = {
@@ -395,12 +394,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;
@@ -413,7 +413,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;
@@ -432,7 +432,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;
@@ -493,15 +493,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,
@@ -524,8 +520,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) {
@@ -550,8 +546,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;
 
@@ -657,10 +653,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;
 
@@ -670,6 +666,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);
@@ -677,6 +678,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;
@@ -684,44 +687,31 @@ 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);
-
-       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr,
-               icd->dev.parent, icd->vdev);
-       soc_camera_video_stop(icd);
 }
 
 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;
@@ -737,13 +727,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;
@@ -753,7 +740,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;
@@ -761,24 +747,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);
+       icd->ops = NULL;
        i2c_set_clientdata(client, NULL);
+       client->driver = NULL;
        kfree(mt9t031);
 
        return 0;
index dbdcc86..959cc29 100644 (file)
@@ -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,
@@ -374,12 +372,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;
@@ -392,7 +391,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;
@@ -412,7 +411,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;
@@ -481,15 +480,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,
@@ -513,7 +508,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) {
@@ -549,7 +544,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);
@@ -646,11 +641,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;
@@ -659,6 +654,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);
 
@@ -678,6 +678,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;
        }
 
@@ -694,7 +696,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
        }
 
        if (ret < 0)
-               goto eisis;
+               goto ei2c;
 
        icd->num_formats = 0;
 
@@ -716,29 +718,23 @@ 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);
        if (icl->free_bus)
                icl->free_bus(icl);
 }
@@ -747,11 +743,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;
@@ -768,12 +770,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;
@@ -783,24 +782,26 @@ 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) {
+               icd->ops = NULL;
+               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);
+       icd->ops = NULL;
+       mt9v022_video_remove(icd);
+       i2c_set_clientdata(client, NULL);
+       client->driver = NULL;
        kfree(mt9v022);
 
        return 0;
index 9770cb7..2edf77a 100644 (file)
@@ -503,18 +503,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;
 }
@@ -947,9 +948,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;
        }
 
@@ -1002,8 +1004,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
@@ -1127,8 +1132,9 @@ static int __devinit 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;
        }
@@ -1215,3 +1221,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);
index 0bce255..3ea650d 100644 (file)
@@ -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 = 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 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 = 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 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 = 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;
@@ -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;
@@ -810,6 +817,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
                        break;
                }
        }
+       dev_dbg(&icd->dev, "Using fmt %x #%d\n", pixfmt, i);
        if (!priv->fmt)
                goto ov772x_set_fmt_error;
 
@@ -821,7 +829,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 +843,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 +865,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 +881,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 +890,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 +909,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 +918,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 +928,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 +938,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 +975,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 +1003,16 @@ 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);
 
        switch (VERSION(pid, ver)) {
        case OV7720:
@@ -1011,7 +1026,8 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
        default:
                dev_err(&icd->dev,
                        "Product ID error %x:%x\n", pid, ver);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto ever;
        }
 
        dev_info(&icd->dev,
@@ -1019,21 +1035,17 @@ 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));
-
-       return soc_camera_video_start(icd);
-}
+                i2c_smbus_read_byte_data(client, MIDH),
+                i2c_smbus_read_byte_data(client, MIDL));
 
-static void ov772x_video_remove(struct soc_camera_device *icd)
-{
        soc_camera_video_stop(icd);
+
+ever:
+       return ret;
 }
 
 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,
@@ -1059,19 +1071,25 @@ static struct soc_camera_ops ov772x_ops = {
  */
 
 static int ov772x_probe(struct i2c_client *client,
-                        const struct i2c_device_id *did)
+                       const struct i2c_device_id *did)
 {
        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;
 
-       if (!client->dev.platform_data)
+       if (!icd) {
+               dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
                return -EINVAL;
+       }
 
-       info = container_of(client->dev.platform_data,
-                           struct ov772x_camera_info, link);
+       icl = to_soc_camera_link(icd);
+       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,
@@ -1085,19 +1103,15 @@ 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) {
+               icd->ops = NULL;
                i2c_set_clientdata(client, NULL);
                kfree(priv);
        }
@@ -1108,8 +1122,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);
+       icd->ops = NULL;
        i2c_set_clientdata(client, NULL);
        kfree(priv);
        return 0;
index 016bb45..8b9b44d 100644 (file)
@@ -830,7 +830,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;
@@ -842,7 +843,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 */
@@ -852,8 +853,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;
 }
@@ -958,15 +959,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;
 }
@@ -1575,8 +1581,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev)
                pcdev->mclk = 20000000;
        }
 
-       pcdev->soc_host.dev = &pdev->dev;
-       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);
@@ -1641,6 +1646,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev)
        pcdev->soc_host.drv_name        = PXA_CAM_DRV_NAME;
        pcdev->soc_host.ops             = &pxa_soc_camera_host_ops;
        pcdev->soc_host.priv            = pcdev;
+       pcdev->soc_host.dev             = &pdev->dev;
        pcdev->soc_host.nr              = pdev->id;
 
        err = soc_camera_host_register(&pcdev->soc_host);
@@ -1722,3 +1728,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);
index 61c47b8..e7ac84d 100644 (file)
@@ -356,11 +356,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;
-
-       pm_runtime_get_sync(ici->dev);
+       }
 
        ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
        while (ceu_read(pcdev, CSTSR) & 1)
@@ -394,10 +396,10 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
        }
        spin_unlock_irqrestore(&pcdev->lock, flags);
 
-       pm_runtime_put_sync(ici->dev);
-
        icd->ops->release(icd);
 
+       clk_disable(pcdev->clk);
+
        dev_info(&icd->dev,
                 "SuperH Mobile CEU driver detached from camera %d\n",
                 icd->devnum);
@@ -946,3 +948,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");
index 0340754..20ef5c7 100644 (file)
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/module.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-dev.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-dev.h>
 #include <media/videobuf-core.h>
 
 /* Default to VGA resolution */
@@ -38,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)
@@ -209,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);
@@ -257,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 */
@@ -310,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.
@@ -321,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;
@@ -335,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;
@@ -350,11 +359,18 @@ 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;
+
+               dev_dbg(&icd->dev, "Using fmt %x\n", icd->current_fmt->fourcc);
+
+               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);
@@ -383,6 +399,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);
@@ -402,8 +420,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);
 
@@ -764,29 +784,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)
 {
@@ -796,106 +793,124 @@ 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);
+                       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);
 }
 
-/* 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)
+#ifdef CONFIG_I2C_BOARDINFO
+static int soc_camera_init_i2c(struct soc_camera_device *icd,
+                              struct soc_camera_link *icl)
 {
-       struct soc_camera_host *ici;
-       int ret = 0;
+       struct i2c_client *client;
+       struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
+       int ret;
 
-       mutex_lock(&list_lock);
+       if (!adap) {
+               ret = -ENODEV;
+               dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n",
+                       icl->i2c_adapter_id);
+               goto ei2cga;
+       }
 
-       list_add_tail(&icd->list, &devices);
+       icl->board_info->platform_data = icd;
 
-       /* 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;
-               }
+       client = i2c_new_device(adap, icl->board_info);
+       if (!client) {
+               ret = -ENOMEM;
+               goto ei2cnd;
        }
 
-       mutex_unlock(&list_lock);
-
-       if (ret)
-               ret = device_register_link(icd);
+       /*
+        * 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);
 
+       return 0;
+ei2cnd:
+       i2c_put_adapter(adap);
+ei2cga:
        return ret;
 }
 
+static void soc_camera_free_i2c(struct soc_camera_device *icd)
+{
+       struct i2c_client *client =
+               to_i2c_client(to_soc_camera_control(icd));
+       dev_set_drvdata(&icd->dev, NULL);
+       i2c_unregister_device(client);
+       i2c_put_adapter(client->adapter);
+}
+#else
+#define soc_camera_init_i2c(icd, icl)  (-ENODEV)
+#define soc_camera_free_i2c(icd)       do {} while (0)
+#endif
+
+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;
 
-       /*
-        * Possible race scenario:
-        * modprobe <camera-host-driver> triggers __func__
-        * at this moment respective <camera-sensor-driver> gets rmmod'ed
-        * to protect take module references.
-        */
+       dev_info(dev, "Probing %s\n", dev_name(dev));
 
-       if (!try_module_get(icd->ops->owner)) {
-               dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
-               ret = -EINVAL;
-               goto emgd;
-       }
+       ret = video_dev_create(icd);
+       if (ret < 0)
+               goto evdc;
 
-       if (!try_module_get(ici->ops->owner)) {
-               dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+       /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
+       if (icl->board_info) {
+               ret = soc_camera_init_i2c(icd, icl);
+               if (ret < 0)
+                       goto eadddev;
+       } else if (!icl->add_device || !icl->del_device) {
                ret = -EINVAL;
-               goto emgi;
+               goto eadddev;
+       } else {
+               ret = icl->add_device(icl, &icd->dev);
+               if (ret < 0)
+                       goto eadddev;
        }
 
-       mutex_lock(&icd->video_lock);
-
-       /* 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;
-
-       ret = icd->ops->probe(icd);
-       if (ret >= 0) {
-               const struct v4l2_queryctrl *qctrl;
+       ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, icd->vdev->minor);
+       if (ret < 0) {
+               dev_err(&icd->dev, "video_register_device failed: %d\n", ret);
+               goto evidregd;
+       }
 
-               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 (to_soc_camera_control(icd) &&
+           sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
+                             "control"))
+               dev_warn(&icd->dev, "Failed creating the control symlink\n");
 
-               ret = soc_camera_init_user_formats(icd);
-               if (ret < 0) {
-                       if (icd->ops->remove)
-                               icd->ops->remove(icd);
-                       goto eiufmt;
-               }
 
-               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:
+evidregd:
+       if (icl->board_info)
+               soc_camera_free_i2c(icd);
+       else
+               icl->del_device(icl);
+eadddev:
+       video_device_release(icd->vdev);
+evdc:
        return ret;
 }
 
@@ -904,13 +919,22 @@ emgd:
 static int soc_camera_remove(struct device *dev)
 {
        struct soc_camera_device *icd = to_soc_camera_dev(dev);
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+       struct video_device *vdev = icd->vdev;
 
-       mutex_lock(&icd->video_lock);
-       if (icd->ops->remove)
-               icd->ops->remove(icd);
-       mutex_unlock(&icd->video_lock);
+       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 (icl->board_info)
+               soc_camera_free_i2c(icd);
+       else
+               icl->del_device(icl);
 
        return 0;
 }
@@ -1005,10 +1029,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));
                }
        }
@@ -1020,26 +1048,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;
@@ -1061,21 +1077,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,
@@ -1106,22 +1116,13 @@ 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;
+       struct video_device *vdev = video_device_alloc();
 
-       if (!icd->dev.parent)
-               return -ENODEV;
-
-       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));
@@ -1132,118 +1133,110 @@ 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) {
-               dev_err(vdev->parent, "video_register_device failed\n");
-               goto evidregd;
-       }
        icd->vdev = vdev;
 
        return 0;
+}
 
-evidregd:
-       video_device_release(vdev);
-evidallocd:
-       return err;
+/*
+ * 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);
 
 /* Called from client .remove() methods with .video_lock held */
 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;
-
-       video_unregister_device(vdev);
-       icd->vdev = NULL;
+       ici->ops->remove(icd);
 }
 EXPORT_SYMBOL(soc_camera_video_stop);
 
-#ifdef CONFIG_I2C_BOARDINFO
-static int soc_camera_init_i2c(struct platform_device *pdev,
-                              struct soc_camera_link *icl)
+static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
 {
-       struct i2c_client *client;
-       struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
+       struct soc_camera_link *icl = pdev->dev.platform_data;
+       struct soc_camera_device *icd;
        int ret;
 
-       if (!adap) {
-               ret = -ENODEV;
-               dev_err(&pdev->dev, "Cannot get adapter #%d. No driver?\n",
-                       icl->i2c_adapter_id);
-               goto ei2cga;
-       }
+       if (!icl)
+               return -EINVAL;
 
-       icl->board_info->platform_data = icl;
-       client = i2c_new_device(adap, icl->board_info);
-       if (!client) {
-               ret = -ENOMEM;
-               goto ei2cnd;
-       }
+       icd = kzalloc(sizeof(*icd), GFP_KERNEL);
+       if (!icd)
+               return -ENOMEM;
 
-       platform_set_drvdata(pdev, client);
+       icd->iface = icl->bus_id;
+       platform_set_drvdata(pdev, icd);
+       icd->dev.platform_data = icl;
 
-       return 0;
-ei2cnd:
-       i2c_put_adapter(adap);
-ei2cga:
-       return ret;
-}
+       ret = soc_camera_device_register(icd);
+       if (ret < 0)
+               goto escdevreg;
 
-static void soc_camera_free_i2c(struct platform_device *pdev)
-{
-       struct i2c_client *client = platform_get_drvdata(pdev);
+       return 0;
 
-       if (!client)
-               return;
+escdevreg:
+       kfree(icd);
 
-       i2c_unregister_device(client);
-       i2c_put_adapter(client->adapter);
+       return ret;
 }
-#else
-#define soc_camera_init_i2c(d, icl)    (-ENODEV)
-#define soc_camera_free_i2c(d)         do {} while (0)
-#endif
 
-static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
+/* 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_link *icl = pdev->dev.platform_data;
+       struct soc_camera_device *icd = platform_get_drvdata(pdev);
 
-       if (!icl)
+       if (!icd)
                return -EINVAL;
 
-       if (icl->board_info)
-               return soc_camera_init_i2c(pdev, icl);
-       else if (!icl->add_device || !icl->del_device)
-               return -EINVAL;
+       soc_camera_device_unregister(icd);
 
-       /* &pdev->dev will become &icd->dev */
-       return icl->add_device(icl, &pdev->dev);
-}
+       kfree(icd);
 
-static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
-{
-       struct soc_camera_link *icl = pdev->dev.platform_data;
-
-       if (icl->board_info)
-               soc_camera_free_i2c(pdev);
-       else
-               icl->del_device(icl);
        return 0;
 }
 
 static struct platform_driver __refdata soc_camera_pdrv = {
-       .probe  = soc_camera_pdrv_probe,
-       .remove = __devexit_p(soc_camera_pdrv_remove),
-       .driver = {
-               .name = "soc-camera-pdrv",
-               .owner = THIS_MODULE,
+       .remove  = __devexit_p(soc_camera_pdrv_remove),
+       .driver  = {
+               .name   = "soc-camera-pdrv",
+               .owner  = THIS_MODULE,
        },
 };
 
@@ -1256,7 +1249,7 @@ static int __init soc_camera_init(void)
        if (ret)
                goto edrvr;
 
-       ret = platform_driver_register(&soc_camera_pdrv);
+       ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
        if (ret)
                goto epdr;
 
index c486763..d84c134 100644 (file)
 #include <media/soc_camera_platform.h>
 
 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)
 {
-       struct soc_camera_platform_priv *priv;
-       priv = container_of(icd, struct soc_camera_platform_priv, icd);
-       return priv->info;
+       struct platform_device *pdev = to_platform_device(dev_get_drvdata(&icd->dev));
+       return pdev->dev.platform_data;
 }
 
 static int soc_camera_platform_init(struct soc_camera_device *icd)
 {
-       struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
 
-       if (p->power)
-               p->power(1);
+       if (icl->power)
+               icl->power(dev_get_drvdata(&icd->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 soc_camera_link *icl = to_soc_camera_link(icd);
 
-       if (p->power)
-               p->power(0);
+       if (icl->power)
+               icl->power(dev_get_drvdata(&icd->dev), 0);
 
        return 0;
 }
@@ -102,31 +99,29 @@ 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 platform_device *pdev)
 {
-       struct soc_camera_platform_priv *priv;
-       priv = container_of(icd, struct soc_camera_platform_priv, icd);
+       struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev);
+       struct soc_camera_platform_info *p = pdev->dev.platform_data;
+       int ret;
 
-       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);
-}
-
-static void soc_camera_platform_video_remove(struct soc_camera_device *icd)
-{
+       /* ..._video_start() does dev_set_drvdata(&icd->dev, &pdev->dev) */
+       ret = soc_camera_video_start(icd, &pdev->dev);
        soc_camera_video_stop(icd);
+       return ret;
 }
 
 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,
@@ -141,11 +136,10 @@ static struct soc_camera_ops soc_camera_platform_ops = {
 static int soc_camera_platform_probe(struct platform_device *pdev)
 {
        struct soc_camera_platform_priv *priv;
-       struct soc_camera_platform_info *p;
+       struct soc_camera_platform_info *p = pdev->dev.platform_data;
        struct soc_camera_device *icd;
        int ret;
 
-       p = pdev->dev.platform_data;
        if (!p)
                return -EINVAL;
 
@@ -153,31 +147,40 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       priv->info = p;
        platform_set_drvdata(pdev, priv);
 
-       icd = &priv->icd;
+       icd = to_soc_camera_dev(p->dev);
+       if (!icd)
+               goto enoicd;
+
        icd->ops        = &soc_camera_platform_ops;
-       icd->control    = &pdev->dev;
+       dev_set_drvdata(&icd->dev, &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, pdev);
+       if (ret) {
+               icd->ops = NULL;
                kfree(priv);
+       }
 
        return ret;
+
+enoicd:
+       kfree(priv);
+       return -EINVAL;
 }
 
 static int soc_camera_platform_remove(struct platform_device *pdev)
 {
        struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev);
+       struct soc_camera_platform_info *p = pdev->dev.platform_data;
+       struct soc_camera_device *icd = to_soc_camera_dev(p->dev);
 
-       soc_camera_device_unregister(&priv->icd);
+       icd->ops = NULL;
        kfree(priv);
        return 0;
 }
@@ -206,3 +209,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");
index aa5065e..d780a50 100644 (file)
@@ -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,25 +836,14 @@ 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;
 
        return ret;
 }
 
-static void tw9910_video_remove(struct soc_camera_device *icd)
-{
-       soc_camera_video_stop(icd);
-}
-
 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,18 +872,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;
 
-       if (!client->dev.platform_data)
+       if (!icd) {
+               dev_err(&client->dev, "TW9910: missing soc-camera data!\n");
                return -EINVAL;
+       }
 
-       info = container_of(client->dev.platform_data,
-                           struct tw9910_video_info, link);
+       icl = to_soc_camera_link(icd);
+       if (!icl)
+               return -EINVAL;
 
-       if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent),
-                                    I2C_FUNC_SMBUS_BYTE_DATA)) {
+       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");
@@ -894,12 +902,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;
 
        /*
@@ -925,9 +930,9 @@ 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) {
+               icd->ops = NULL;
                i2c_set_clientdata(client, NULL);
                kfree(priv);
        }
@@ -938,8 +943,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);
+       icd->ops = NULL;
        i2c_set_clientdata(client, NULL);
        kfree(priv);
        return 0;
index 813e120..d8b4256 100644 (file)
@@ -20,7 +20,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 */
@@ -131,17 +130,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 {
@@ -170,8 +177,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 *);
index 3e8f020..b144f94 100644 (file)
@@ -18,11 +18,10 @@ struct device;
 
 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);
        struct device *dev;
        int (*set_capture)(struct soc_camera_platform_info *info, int enable);
        struct soc_camera_link link;