Merge branch 'v4l_for_2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/mcheha...
[safe/jmp/linux-2.6] / drivers / media / video / mt9t031.c
index f234ba6..a9a28b2 100644 (file)
@@ -8,18 +8,22 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/videodev2.h>
-#include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/i2c.h>
 #include <linux/log2.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
 
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
 
-/* mt9t031 i2c address 0x5d
+/*
+ * mt9t031 i2c address 0x5d
  * The platform has to define i2c_board_info and link to it from
- * struct soc_camera_link */
+ * struct soc_camera_link
+ */
 
 /* mt9t031 selected register addresses */
 #define MT9T031_CHIP_VERSION           0x00
        SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH |      \
        SOCAM_MASTER | SOCAM_DATAWIDTH_10)
 
-static const struct soc_camera_data_format mt9t031_colour_formats[] = {
-       {
-               .name           = "Bayer (sRGB) 10 bit",
-               .depth          = 10,
-               .fourcc         = V4L2_PIX_FMT_SGRBG10,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-       }
-};
-
 struct mt9t031 {
        struct v4l2_subdev subdev;
        struct v4l2_rect rect;  /* Sensor window */
        int model;      /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
        u16 xskip;
        u16 yskip;
+       unsigned int gain;
+       unsigned short y_skip_top;      /* Lines to skip at the top */
+       unsigned int exposure;
        unsigned char autoexposure;
 };
 
@@ -163,20 +161,6 @@ static int mt9t031_disable(struct i2c_client *client)
        return 0;
 }
 
-static int mt9t031_init(struct soc_camera_device *icd)
-{
-       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-
-       return mt9t031_idle(client);
-}
-
-static int mt9t031_release(struct soc_camera_device *icd)
-{
-       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-
-       return mt9t031_disable(client);
-}
-
 static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct i2c_client *client = sd->priv;
@@ -219,6 +203,71 @@ static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
        return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
 }
 
+enum {
+       MT9T031_CTRL_VFLIP,
+       MT9T031_CTRL_HFLIP,
+       MT9T031_CTRL_GAIN,
+       MT9T031_CTRL_EXPOSURE,
+       MT9T031_CTRL_EXPOSURE_AUTO,
+};
+
+static const struct v4l2_queryctrl mt9t031_controls[] = {
+       [MT9T031_CTRL_VFLIP] = {
+               .id             = V4L2_CID_VFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Vertically",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       },
+       [MT9T031_CTRL_HFLIP] = {
+               .id             = V4L2_CID_HFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Horizontally",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       },
+       [MT9T031_CTRL_GAIN] = {
+               .id             = V4L2_CID_GAIN,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gain",
+               .minimum        = 0,
+               .maximum        = 127,
+               .step           = 1,
+               .default_value  = 64,
+               .flags          = V4L2_CTRL_FLAG_SLIDER,
+       },
+       [MT9T031_CTRL_EXPOSURE] = {
+               .id             = V4L2_CID_EXPOSURE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Exposure",
+               .minimum        = 1,
+               .maximum        = 255,
+               .step           = 1,
+               .default_value  = 255,
+               .flags          = V4L2_CTRL_FLAG_SLIDER,
+       },
+       [MT9T031_CTRL_EXPOSURE_AUTO] = {
+               .id             = V4L2_CID_EXPOSURE_AUTO,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Automatic Exposure",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       }
+};
+
+static struct soc_camera_ops mt9t031_ops = {
+       .set_bus_param          = mt9t031_set_bus_param,
+       .query_bus_param        = mt9t031_query_bus_param,
+       .controls               = mt9t031_controls,
+       .num_controls           = ARRAY_SIZE(mt9t031_controls),
+};
+
 /* target must be _even_ */
 static u16 mt9t031_skip(s32 *source, s32 target, s32 max)
 {
@@ -238,10 +287,9 @@ static u16 mt9t031_skip(s32 *source, s32 target, s32 max)
 }
 
 /* rect is the sensor rectangle, the caller guarantees parameter validity */
-static int mt9t031_set_params(struct soc_camera_device *icd,
+static int mt9t031_set_params(struct i2c_client *client,
                              struct v4l2_rect *rect, u16 xskip, u16 yskip)
 {
-       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
        struct mt9t031 *mt9t031 = to_mt9t031(client);
        int ret;
        u16 xbin, ybin;
@@ -303,8 +351,10 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
        dev_dbg(&client->dev, "new physical left %u, top %u\n",
                rect->left, rect->top);
 
-       /* The caller provides a supported format, as guaranteed by
-        * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
+       /*
+        * The caller provides a supported format, as guaranteed by
+        * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap()
+        */
        if (ret >= 0)
                ret = reg_write(client, MT9T031_COLUMN_START, rect->left);
        if (ret >= 0)
@@ -313,18 +363,16 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
                ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1);
        if (ret >= 0)
                ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
-                               rect->height + icd->y_skip_top - 1);
+                               rect->height + mt9t031->y_skip_top - 1);
        if (ret >= 0 && mt9t031->autoexposure) {
-               ret = set_shutter(client,
-                                 rect->height + icd->y_skip_top + vblank);
+               unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank;
+               ret = set_shutter(client, total_h);
                if (ret >= 0) {
                        const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
                        const struct v4l2_queryctrl *qctrl =
-                               soc_camera_find_qctrl(icd->ops,
-                                                     V4L2_CID_EXPOSURE);
-                       icd->exposure = (shutter_max / 2 + (rect->height +
-                                        icd->y_skip_top + vblank - 1) *
-                                        (qctrl->maximum - qctrl->minimum)) /
+                               &mt9t031_controls[MT9T031_CTRL_EXPOSURE];
+                       mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
+                                (qctrl->maximum - qctrl->minimum)) /
                                shutter_max + qctrl->minimum;
                }
        }
@@ -347,7 +395,6 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
        struct v4l2_rect rect = a->c;
        struct i2c_client *client = sd->priv;
        struct mt9t031 *mt9t031 = to_mt9t031(client);
-       struct soc_camera_device *icd = client->dev.platform_data;
 
        rect.width = ALIGN(rect.width, 2);
        rect.height = ALIGN(rect.height, 2);
@@ -358,7 +405,7 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
        soc_camera_limit_side(&rect.top, &rect.height,
                     MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT);
 
-       return mt9t031_set_params(icd, &rect, mt9t031->xskip, mt9t031->yskip);
+       return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip);
 }
 
 static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
@@ -386,27 +433,26 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
        return 0;
 }
 
-static int mt9t031_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int mt9t031_g_fmt(struct v4l2_subdev *sd,
+                        struct v4l2_mbus_framefmt *mf)
 {
        struct i2c_client *client = sd->priv;
        struct mt9t031 *mt9t031 = to_mt9t031(client);
-       struct v4l2_pix_format *pix = &f->fmt.pix;
 
-       pix->width              = mt9t031->rect.width / mt9t031->xskip;
-       pix->height             = mt9t031->rect.height / mt9t031->yskip;
-       pix->pixelformat        = V4L2_PIX_FMT_SGRBG10;
-       pix->field              = V4L2_FIELD_NONE;
-       pix->colorspace         = V4L2_COLORSPACE_SRGB;
+       mf->width       = mt9t031->rect.width / mt9t031->xskip;
+       mf->height      = mt9t031->rect.height / mt9t031->yskip;
+       mf->code        = V4L2_MBUS_FMT_SBGGR10_1X10;
+       mf->colorspace  = V4L2_COLORSPACE_SRGB;
+       mf->field       = V4L2_FIELD_NONE;
 
        return 0;
 }
 
-static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int mt9t031_s_fmt(struct v4l2_subdev *sd,
+                        struct v4l2_mbus_framefmt *mf)
 {
        struct i2c_client *client = sd->priv;
        struct mt9t031 *mt9t031 = to_mt9t031(client);
-       struct soc_camera_device *icd = client->dev.platform_data;
-       struct v4l2_pix_format *pix = &f->fmt.pix;
        u16 xskip, yskip;
        struct v4l2_rect rect = mt9t031->rect;
 
@@ -414,24 +460,29 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
         * try_fmt has put width and height within limits.
         * S_FMT: use binning and skipping for scaling
         */
-       xskip = mt9t031_skip(&rect.width, pix->width, MT9T031_MAX_WIDTH);
-       yskip = mt9t031_skip(&rect.height, pix->height, MT9T031_MAX_HEIGHT);
+       xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH);
+       yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT);
+
+       mf->code        = V4L2_MBUS_FMT_SBGGR10_1X10;
+       mf->colorspace  = V4L2_COLORSPACE_SRGB;
 
        /* mt9t031_set_params() doesn't change width and height */
-       return mt9t031_set_params(icd, &rect, xskip, yskip);
+       return mt9t031_set_params(client, &rect, xskip, yskip);
 }
 
 /*
  * If a user window larger than sensor window is requested, we'll increase the
  * sensor window.
  */
-static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int mt9t031_try_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_mbus_framefmt *mf)
 {
-       struct v4l2_pix_format *pix = &f->fmt.pix;
-
        v4l_bound_align_image(
-               &pix->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
-               &pix->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
+               &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
+               &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
+
+       mf->code        = V4L2_MBUS_FMT_SBGGR10_1X10;
+       mf->colorspace  = V4L2_COLORSPACE_SRGB;
 
        return 0;
 }
@@ -492,61 +543,6 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,
 }
 #endif
 
-static const struct v4l2_queryctrl mt9t031_controls[] = {
-       {
-               .id             = V4L2_CID_VFLIP,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Flip Vertically",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 0,
-       }, {
-               .id             = V4L2_CID_HFLIP,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Flip Horizontally",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 0,
-       }, {
-               .id             = V4L2_CID_GAIN,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Gain",
-               .minimum        = 0,
-               .maximum        = 127,
-               .step           = 1,
-               .default_value  = 64,
-               .flags          = V4L2_CTRL_FLAG_SLIDER,
-       }, {
-               .id             = V4L2_CID_EXPOSURE,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Exposure",
-               .minimum        = 1,
-               .maximum        = 255,
-               .step           = 1,
-               .default_value  = 255,
-               .flags          = V4L2_CTRL_FLAG_SLIDER,
-       }, {
-               .id             = V4L2_CID_EXPOSURE_AUTO,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Automatic Exposure",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 1,
-       }
-};
-
-static struct soc_camera_ops mt9t031_ops = {
-       .init                   = mt9t031_init,
-       .release                = mt9t031_release,
-       .set_bus_param          = mt9t031_set_bus_param,
-       .query_bus_param        = mt9t031_query_bus_param,
-       .controls               = mt9t031_controls,
-       .num_controls           = ARRAY_SIZE(mt9t031_controls),
-};
-
 static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        struct i2c_client *client = sd->priv;
@@ -569,6 +565,12 @@ static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        case V4L2_CID_EXPOSURE_AUTO:
                ctrl->value = mt9t031->autoexposure;
                break;
+       case V4L2_CID_GAIN:
+               ctrl->value = mt9t031->gain;
+               break;
+       case V4L2_CID_EXPOSURE:
+               ctrl->value = mt9t031->exposure;
+               break;
        }
        return 0;
 }
@@ -577,15 +579,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        struct i2c_client *client = sd->priv;
        struct mt9t031 *mt9t031 = to_mt9t031(client);
-       struct soc_camera_device *icd = client->dev.platform_data;
        const struct v4l2_queryctrl *qctrl;
        int data;
 
-       qctrl = soc_camera_find_qctrl(&mt9t031_ops, ctrl->id);
-
-       if (!qctrl)
-               return -EINVAL;
-
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                if (ctrl->value)
@@ -604,6 +600,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                        return -EIO;
                break;
        case V4L2_CID_GAIN:
+               qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN];
                if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
                        return -EINVAL;
                /* See Datasheet Table 7, Gain settings. */
@@ -640,9 +637,10 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                }
 
                /* Success */
-               icd->gain = ctrl->value;
+               mt9t031->gain = ctrl->value;
                break;
        case V4L2_CID_EXPOSURE:
+               qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE];
                /* mt9t031 has maximum == default */
                if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
                        return -EINVAL;
@@ -657,7 +655,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                                old, shutter);
                        if (set_shutter(client, shutter) < 0)
                                return -EIO;
-                       icd->exposure = ctrl->value;
+                       mt9t031->exposure = ctrl->value;
                        mt9t031->autoexposure = 0;
                }
                break;
@@ -665,30 +663,88 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                if (ctrl->value) {
                        const u16 vblank = MT9T031_VERTICAL_BLANK;
                        const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
-                       if (set_shutter(client, mt9t031->rect.height +
-                                       icd->y_skip_top + vblank) < 0)
+                       unsigned int total_h = mt9t031->rect.height +
+                               mt9t031->y_skip_top + vblank;
+
+                       if (set_shutter(client, total_h) < 0)
                                return -EIO;
-                       qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
-                       icd->exposure = (shutter_max / 2 +
-                                        (mt9t031->rect.height +
-                                         icd->y_skip_top + vblank - 1) *
-                                        (qctrl->maximum - qctrl->minimum)) /
+                       qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE];
+                       mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
+                                (qctrl->maximum - qctrl->minimum)) /
                                shutter_max + qctrl->minimum;
                        mt9t031->autoexposure = 1;
                } else
                        mt9t031->autoexposure = 0;
                break;
+       default:
+               return -EINVAL;
        }
        return 0;
 }
 
-/* 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 */
+/*
+ * Power Management:
+ * This function does nothing for now but must be present for pm to work
+ */
+static int mt9t031_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+/*
+ * Power Management:
+ * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged
+ * they are however changed at reset if the platform hook is present
+ * thus we rewrite them with the values stored by the driver
+ */
+static int mt9t031_runtime_resume(struct device *dev)
+{
+       struct video_device *vdev = to_video_device(dev);
+       struct soc_camera_device *icd = container_of(vdev->parent,
+               struct soc_camera_device, dev);
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct i2c_client *client = sd->priv;
+       struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+       int ret;
+       u16 xbin, ybin;
+
+       xbin = min(mt9t031->xskip, (u16)3);
+       ybin = min(mt9t031->yskip, (u16)3);
+
+       ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
+               ((xbin - 1) << 4) | (mt9t031->xskip - 1));
+       if (ret < 0)
+               return ret;
+
+       ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
+               ((ybin - 1) << 4) | (mt9t031->yskip - 1));
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct dev_pm_ops mt9t031_dev_pm_ops = {
+       .runtime_suspend        = mt9t031_runtime_suspend,
+       .runtime_resume         = mt9t031_runtime_resume,
+};
+
+static struct device_type mt9t031_dev_type = {
+       .name   = "MT9T031",
+       .pm     = &mt9t031_dev_pm_ops,
+};
+
+/*
+ * 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 i2c_client *client)
 {
-       struct soc_camera_device *icd = client->dev.platform_data;
        struct mt9t031 *mt9t031 = to_mt9t031(client);
+       struct video_device *vdev = soc_camera_i2c_to_vdev(client);
        s32 data;
+       int ret;
 
        /* Enable the chip */
        data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
@@ -700,8 +756,6 @@ static int mt9t031_video_probe(struct i2c_client *client)
        switch (data) {
        case 0x1621:
                mt9t031->model = V4L2_IDENT_MT9T031;
-               icd->formats = mt9t031_colour_formats;
-               icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
                break;
        default:
                dev_err(&client->dev,
@@ -711,6 +765,26 @@ static int mt9t031_video_probe(struct i2c_client *client)
 
        dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
 
+       ret = mt9t031_idle(client);
+       if (ret < 0)
+               dev_err(&client->dev, "Failed to initialise the camera\n");
+       else
+               vdev->dev.type = &mt9t031_dev_type;
+
+       /* mt9t031_idle() has reset the chip to default. */
+       mt9t031->exposure = 255;
+       mt9t031->gain = 64;
+
+       return ret;
+}
+
+static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+       struct i2c_client *client = sd->priv;
+       struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+       *lines = mt9t031->y_skip_top;
+
        return 0;
 }
 
@@ -724,19 +798,35 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
 #endif
 };
 
+static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                           enum v4l2_mbus_pixelcode *code)
+{
+       if (index)
+               return -EINVAL;
+
+       *code = V4L2_MBUS_FMT_SBGGR10_1X10;
+       return 0;
+}
+
 static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
        .s_stream       = mt9t031_s_stream,
-       .s_fmt          = mt9t031_s_fmt,
-       .g_fmt          = mt9t031_g_fmt,
-       .try_fmt        = mt9t031_try_fmt,
+       .s_mbus_fmt     = mt9t031_s_fmt,
+       .g_mbus_fmt     = mt9t031_g_fmt,
+       .try_mbus_fmt   = mt9t031_try_fmt,
        .s_crop         = mt9t031_s_crop,
        .g_crop         = mt9t031_g_crop,
        .cropcap        = mt9t031_cropcap,
+       .enum_mbus_fmt  = mt9t031_enum_fmt,
+};
+
+static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = {
+       .g_skip_top_lines       = mt9t031_g_skip_top_lines,
 };
 
 static struct v4l2_subdev_ops mt9t031_subdev_ops = {
        .core   = &mt9t031_subdev_core_ops,
        .video  = &mt9t031_subdev_video_ops,
+       .sensor = &mt9t031_subdev_sensor_ops,
 };
 
 static int mt9t031_probe(struct i2c_client *client,
@@ -745,18 +835,16 @@ static int mt9t031_probe(struct i2c_client *client,
        struct mt9t031 *mt9t031;
        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 (!icd) {
-               dev_err(&client->dev, "MT9T031: missing soc-camera data!\n");
-               return -EINVAL;
-       }
+       if (icd) {
+               struct soc_camera_link *icl = to_soc_camera_link(icd);
+               if (!icl) {
+                       dev_err(&client->dev, "MT9T031 driver needs platform data\n");
+                       return -EINVAL;
+               }
 
-       icl = to_soc_camera_link(icd);
-       if (!icl) {
-               dev_err(&client->dev, "MT9T031 driver needs platform data\n");
-               return -EINVAL;
+               icd->ops = &mt9t031_ops;
        }
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
@@ -771,17 +859,16 @@ static int mt9t031_probe(struct i2c_client *client,
 
        v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
 
-       /* Second stage probe - when a capture adapter is there */
-       icd->ops                = &mt9t031_ops;
-       icd->y_skip_top         = 0;
-
+       mt9t031->y_skip_top     = 0;
        mt9t031->rect.left      = MT9T031_COLUMN_SKIP;
        mt9t031->rect.top       = MT9T031_ROW_SKIP;
        mt9t031->rect.width     = MT9T031_MAX_WIDTH;
        mt9t031->rect.height    = MT9T031_MAX_HEIGHT;
 
-       /* Simulated autoexposure. If enabled, we calculate shutter width
-        * ourselves in the driver based on vertical blanking and frame width */
+       /*
+        * Simulated autoexposure. If enabled, we calculate shutter width
+        * ourselves in the driver based on vertical blanking and frame width
+        */
        mt9t031->autoexposure = 1;
 
        mt9t031->xskip = 1;
@@ -794,8 +881,8 @@ static int mt9t031_probe(struct i2c_client *client,
        mt9t031_disable(client);
 
        if (ret) {
-               icd->ops = NULL;
-               i2c_set_clientdata(client, NULL);
+               if (icd)
+                       icd->ops = NULL;
                kfree(mt9t031);
        }
 
@@ -807,8 +894,8 @@ static int mt9t031_remove(struct i2c_client *client)
        struct mt9t031 *mt9t031 = to_mt9t031(client);
        struct soc_camera_device *icd = client->dev.platform_data;
 
-       icd->ops = NULL;
-       i2c_set_clientdata(client, NULL);
+       if (icd)
+               icd->ops = NULL;
        client->driver = NULL;
        kfree(mt9t031);