[media] V4L: soc-camera: call soc_camera_power_on() after adding the client to the...
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Wed, 14 Mar 2012 10:22:07 +0000 (07:22 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 20 Mar 2012 01:11:05 +0000 (22:11 -0300)
soc_camera_power_on() calls client's .s_power(1) method, which can try to
access the client hardware. This, however, is typically only possible,
after calling host's .add() method, because that's where the host driver
usually turns the master clock on.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/soc_camera.c

index b82710745ba8b40fdd3b3f7f1326050541eacad8..eb25756a07af3fdbc26b9993f153716cea0edc85 100644 (file)
@@ -526,10 +526,6 @@ static int soc_camera_open(struct file *file)
                        },
                };
 
-               ret = soc_camera_power_on(icd, icl);
-               if (ret < 0)
-                       goto epower;
-
                /* The camera could have been already on, try to reset */
                if (icl->reset)
                        icl->reset(icd->pdev);
@@ -540,6 +536,10 @@ static int soc_camera_open(struct file *file)
                        goto eiciadd;
                }
 
+               ret = soc_camera_power_on(icd, icl);
+               if (ret < 0)
+                       goto epower;
+
                pm_runtime_enable(&icd->vdev->dev);
                ret = pm_runtime_resume(&icd->vdev->dev);
                if (ret < 0 && ret != -ENOSYS)
@@ -578,10 +578,10 @@ einitvb:
 esfmt:
        pm_runtime_disable(&icd->vdev->dev);
 eresume:
-       ici->ops->remove(icd);
-eiciadd:
        soc_camera_power_off(icd, icl);
 epower:
+       ici->ops->remove(icd);
+eiciadd:
        icd->use_count--;
        module_put(ici->ops->owner);
 
@@ -1050,6 +1050,14 @@ static int soc_camera_probe(struct soc_camera_device *icd)
        if (ret < 0)
                goto ereg;
 
+       /* The camera could have been already on, try to reset */
+       if (icl->reset)
+               icl->reset(icd->pdev);
+
+       ret = ici->ops->add(icd);
+       if (ret < 0)
+               goto eadd;
+
        /*
         * This will not yet call v4l2_subdev_core_ops::s_power(1), because the
         * subdevice has not been initialised yet. We'll have to call it once
@@ -1060,14 +1068,6 @@ static int soc_camera_probe(struct soc_camera_device *icd)
        if (ret < 0)
                goto epower;
 
-       /* The camera could have been already on, try to reset */
-       if (icl->reset)
-               icl->reset(icd->pdev);
-
-       ret = ici->ops->add(icd);
-       if (ret < 0)
-               goto eadd;
-
        /* Must have icd->vdev before registering the device */
        ret = video_dev_create(icd);
        if (ret < 0)
@@ -1165,10 +1165,10 @@ eadddev:
        video_device_release(icd->vdev);
        icd->vdev = NULL;
 evdc:
-       ici->ops->remove(icd);
-eadd:
        soc_camera_power_off(icd, icl);
 epower:
+       ici->ops->remove(icd);
+eadd:
        regulator_bulk_free(icl->num_regulators, icl->regulators);
 ereg:
        v4l2_ctrl_handler_free(&icd->ctrl_handler);