[media] V4L2: mt9t031: don't Oops if asynchronous probing is attempted
[firefly-linux-kernel-4.4.55.git] / drivers / media / i2c / soc_camera / mt9t031.c
index 26a15b87a9a25be5b9ab1283da80c5dbec22c5f6..ee7bb0ffcecbe79c7d8b076ba5428a965a06ecfb 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 
@@ -76,7 +76,7 @@ struct mt9t031 {
                struct v4l2_ctrl *exposure;
        };
        struct v4l2_rect rect;  /* Sensor window */
-       int model;      /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
+       struct v4l2_clk *clk;
        u16 xskip;
        u16 yskip;
        unsigned int total_h;
@@ -391,36 +391,16 @@ static int mt9t031_try_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t031 *mt9t031 = to_mt9t031(client);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = mt9t031->model;
-       id->revision    = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9t031_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
+       reg->size = 1;
        reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
@@ -434,12 +414,9 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
@@ -595,7 +572,7 @@ static int mt9t031_runtime_resume(struct device *dev)
        return 0;
 }
 
-static struct dev_pm_ops mt9t031_dev_pm_ops = {
+static const struct dev_pm_ops mt9t031_dev_pm_ops = {
        .runtime_suspend        = mt9t031_runtime_suspend,
        .runtime_resume         = mt9t031_runtime_resume,
 };
@@ -610,16 +587,20 @@ static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
        struct video_device *vdev = soc_camera_i2c_to_vdev(client);
+       struct mt9t031 *mt9t031 = to_mt9t031(client);
        int ret;
 
        if (on) {
-               ret = soc_camera_power_on(&client->dev, ssdd);
+               ret = soc_camera_power_on(&client->dev, ssdd, mt9t031->clk);
                if (ret < 0)
                        return ret;
-               vdev->dev.type = &mt9t031_dev_type;
+               if (vdev)
+                       /* Not needed during probing, when vdev isn't available yet */
+                       vdev->dev.type = &mt9t031_dev_type;
        } else {
-               vdev->dev.type = NULL;
-               soc_camera_power_off(&client->dev, ssdd);
+               if (vdev)
+                       vdev->dev.type = NULL;
+               soc_camera_power_off(&client->dev, ssdd, mt9t031->clk);
        }
 
        return 0;
@@ -650,7 +631,6 @@ static int mt9t031_video_probe(struct i2c_client *client)
 
        switch (data) {
        case 0x1621:
-               mt9t031->model = V4L2_IDENT_MT9T031;
                break;
        default:
                dev_err(&client->dev,
@@ -685,7 +665,6 @@ static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
 };
 
 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,
@@ -812,9 +791,18 @@ static int mt9t031_probe(struct i2c_client *client,
        mt9t031->xskip = 1;
        mt9t031->yskip = 1;
 
+       mt9t031->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9t031->clk)) {
+               ret = PTR_ERR(mt9t031->clk);
+               goto eclkget;
+       }
+
        ret = mt9t031_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9t031->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9t031->hdl);
+       }
 
        return ret;
 }
@@ -823,6 +811,7 @@ static int mt9t031_remove(struct i2c_client *client)
 {
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
+       v4l2_clk_put(mt9t031->clk);
        v4l2_device_unregister_subdev(&mt9t031->subdev);
        v4l2_ctrl_handler_free(&mt9t031->hdl);