#include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 
+/*
+ * ATTENTION: this driver still cannot be used outside of the soc-camera
+ * framework because of its PM implementation, using the video_device node.
+ * If hardware becomes available for testing, alternative PM approaches shall
+ * be considered and tested.
+ */
+
 /*
  * mt9t031 i2c address 0x5d
  * The platform has to define i2c_board_info and link to it from
        .pm     = &mt9t031_dev_pm_ops,
 };
 
+static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct video_device *vdev = soc_camera_i2c_to_vdev(client);
+
+       if (on)
+               vdev->dev.type = &mt9t031_dev_type;
+       else
+               vdev->dev.type = NULL;
+
+       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
 static int mt9t031_video_probe(struct i2c_client *client)
 {
        struct mt9t031 *mt9t031 = to_mt9t031(client);
-       struct video_device *vdev = soc_camera_i2c_to_vdev(client);
        s32 data;
        int ret;
 
        dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
 
        ret = mt9t031_idle(client);
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(&client->dev, "Failed to initialise the camera\n");
-       } else {
-               vdev->dev.type = &mt9t031_dev_type;
+       else
                v4l2_ctrl_handler_setup(&mt9t031->hdl);
-       }
+
        return ret;
 }
 
 
 static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
        .g_chip_ident   = mt9t031_g_chip_ident,
+       .s_power        = mt9t031_s_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9t031_g_register,
        .s_register     = mt9t031_s_register,
 
        return v4l2_subdev_call(sd, core, s_std, *a);
 }
 
+static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+       struct soc_camera_device *icd = file->private_data;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+       return v4l2_subdev_call(sd, core, g_std, a);
+}
+
 static int soc_camera_enum_fsizes(struct file *file, void *fh,
                                         struct v4l2_frmsizeenum *fsize)
 {
                goto ei2cga;
        }
 
-       icl->board_info->platform_data = icd;
+       icl->board_info->platform_data = icl;
 
        subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
                                icl->board_info, NULL);
        .vidioc_g_input          = soc_camera_g_input,
        .vidioc_s_input          = soc_camera_s_input,
        .vidioc_s_std            = soc_camera_s_std,
+       .vidioc_g_std            = soc_camera_g_std,
        .vidioc_enum_framesizes  = soc_camera_enum_fsizes,
        .vidioc_reqbufs          = soc_camera_reqbufs,
        .vidioc_querybuf         = soc_camera_querybuf,
 
        struct v4l2_subdev              subdev;
        struct tw9910_video_info        *info;
        const struct tw9910_scale_ctrl  *scale;
+       v4l2_std_id                     norm;
        u32                             revision;
 };
 
        return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2);
 }
 
-static const struct tw9910_scale_ctrl *tw9910_select_norm(struct soc_camera_device *icd,
+static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm,
                                                          u32 width, u32 height)
 {
        const struct tw9910_scale_ctrl *scale;
        const struct tw9910_scale_ctrl *ret = NULL;
-       v4l2_std_id norm = icd->vdev->current_norm;
        __u32 diff = 0xffffffff, tmp;
        int size, i;
 
        return tw9910_power(client, enable);
 }
 
+static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
+
+       *norm = priv->norm;
+
+       return 0;
+}
+
 static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
 {
-       int ret = -EINVAL;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
 
-       if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL))
-               ret = 0;
+       if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
+               return -EINVAL;
 
-       return ret;
+       priv->norm = norm;
+
+       return 0;
 }
 
 static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct tw9910_priv *priv = to_tw9910(client);
-       struct soc_camera_device *icd = client->dev.platform_data;
        int ret = -EINVAL;
        u8 val;
 
        /*
         * select suitable norm
         */
-       priv->scale = tw9910_select_norm(icd, *width, *height);
+       priv->scale = tw9910_select_norm(priv->norm, *width, *height);
        if (!priv->scale)
                goto tw9910_set_fmt_error;
 
 static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_device *icd = client->dev.platform_data;
+       struct tw9910_priv *priv = to_tw9910(client);
 
        a->c.left       = 0;
        a->c.top        = 0;
-       if (icd->vdev->current_norm & V4L2_STD_NTSC) {
+       if (priv->norm & V4L2_STD_NTSC) {
                a->c.width      = 640;
                a->c.height     = 480;
        } else {
 static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_device *icd = client->dev.platform_data;
+       struct tw9910_priv *priv = to_tw9910(client);
 
        a->bounds.left                  = 0;
        a->bounds.top                   = 0;
-       if (icd->vdev->current_norm & V4L2_STD_NTSC) {
+       if (priv->norm & V4L2_STD_NTSC) {
                a->bounds.width         = 640;
                a->bounds.height        = 480;
        } else {
                          struct v4l2_mbus_framefmt *mf)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_device *icd = client->dev.platform_data;
+       struct tw9910_priv *priv = to_tw9910(client);
        const struct tw9910_scale_ctrl *scale;
 
        if (V4L2_FIELD_ANY == mf->field) {
        /*
         * select suitable norm
         */
-       scale = tw9910_select_norm(icd, mf->width, mf->height);
+       scale = tw9910_select_norm(priv->norm, mf->width, mf->height);
        if (!scale)
                return -EINVAL;
 
        return 0;
 }
 
-static int tw9910_video_probe(struct soc_camera_device *icd,
-                             struct i2c_client *client)
+static int tw9910_video_probe(struct i2c_client *client)
 {
        struct tw9910_priv *priv = to_tw9910(client);
        s32 id;
        dev_info(&client->dev,
                 "tw9910 Product ID %0x:%0x\n", id, priv->revision);
 
-       icd->vdev->tvnorms      = V4L2_STD_NTSC | V4L2_STD_PAL;
-       icd->vdev->current_norm = V4L2_STD_NTSC;
+       priv->norm = V4L2_STD_NTSC;
 
        return 0;
 }
 static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
        .g_chip_ident   = tw9910_g_chip_ident,
        .s_std          = tw9910_s_std,
+       .g_std          = tw9910_g_std,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = tw9910_g_register,
        .s_register     = tw9910_s_register,
 {
        struct tw9910_priv              *priv;
        struct tw9910_video_info        *info;
-       struct soc_camera_device        *icd = client->dev.platform_data;
        struct i2c_adapter              *adapter =
                to_i2c_adapter(client->dev.parent);
        struct soc_camera_link          *icl = soc_camera_i2c_to_link(client);
 
        v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
 
-       ret = tw9910_video_probe(icd, client);
+       ret = tw9910_video_probe(client);
        if (ret)
                kfree(priv);