Merge branch 'patchwork' into v4l_for_linus
[cascardo/linux.git] / drivers / media / platform / soc_camera / soc_camera.c
index cee7b56..55370d7 100644 (file)
@@ -177,6 +177,30 @@ static int __soc_camera_power_off(struct soc_camera_device *icd)
        return 0;
 }
 
+static int soc_camera_clock_start(struct soc_camera_host *ici)
+{
+       int ret;
+
+       if (!ici->ops->clock_start)
+               return 0;
+
+       mutex_lock(&ici->clk_lock);
+       ret = ici->ops->clock_start(ici);
+       mutex_unlock(&ici->clk_lock);
+
+       return ret;
+}
+
+static void soc_camera_clock_stop(struct soc_camera_host *ici)
+{
+       if (!ici->ops->clock_stop)
+               return;
+
+       mutex_lock(&ici->clk_lock);
+       ici->ops->clock_stop(ici);
+       mutex_unlock(&ici->clk_lock);
+}
+
 const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
        struct soc_camera_device *icd, unsigned int fourcc)
 {
@@ -584,9 +608,7 @@ static int soc_camera_add_device(struct soc_camera_device *icd)
                return -EBUSY;
 
        if (!icd->clk) {
-               mutex_lock(&ici->clk_lock);
-               ret = ici->ops->clock_start(ici);
-               mutex_unlock(&ici->clk_lock);
+               ret = soc_camera_clock_start(ici);
                if (ret < 0)
                        return ret;
        }
@@ -602,11 +624,8 @@ static int soc_camera_add_device(struct soc_camera_device *icd)
        return 0;
 
 eadd:
-       if (!icd->clk) {
-               mutex_lock(&ici->clk_lock);
-               ici->ops->clock_stop(ici);
-               mutex_unlock(&ici->clk_lock);
-       }
+       if (!icd->clk)
+               soc_camera_clock_stop(ici);
        return ret;
 }
 
@@ -619,11 +638,8 @@ static void soc_camera_remove_device(struct soc_camera_device *icd)
 
        if (ici->ops->remove)
                ici->ops->remove(icd);
-       if (!icd->clk) {
-               mutex_lock(&ici->clk_lock);
-               ici->ops->clock_stop(ici);
-               mutex_unlock(&ici->clk_lock);
-       }
+       if (!icd->clk)
+               soc_camera_clock_stop(ici);
        ici->icd = NULL;
 }
 
@@ -688,7 +704,8 @@ static int soc_camera_open(struct file *file)
 
                /* The camera could have been already on, try to reset */
                if (sdesc->subdev_desc.reset)
-                       sdesc->subdev_desc.reset(icd->pdev);
+                       if (icd->control)
+                               sdesc->subdev_desc.reset(icd->control);
 
                ret = soc_camera_add_device(icd);
                if (ret < 0) {
@@ -1159,7 +1176,8 @@ static void scan_add_host(struct soc_camera_host *ici)
 
                        /* The camera could have been already on, try to reset */
                        if (ssdd->reset)
-                               ssdd->reset(icd->pdev);
+                               if (icd->control)
+                                       ssdd->reset(icd->control);
 
                        icd->parent = ici->v4l2_dev.dev;
 
@@ -1178,7 +1196,6 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk)
 {
        struct soc_camera_device *icd = clk->priv;
        struct soc_camera_host *ici;
-       int ret;
 
        if (!icd || !icd->parent)
                return -ENODEV;
@@ -1192,10 +1209,7 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk)
         * If a different client is currently being probed, the host will tell
         * you to go
         */
-       mutex_lock(&ici->clk_lock);
-       ret = ici->ops->clock_start(ici);
-       mutex_unlock(&ici->clk_lock);
-       return ret;
+       return soc_camera_clock_start(ici);
 }
 
 static void soc_camera_clk_disable(struct v4l2_clk *clk)
@@ -1208,9 +1222,7 @@ static void soc_camera_clk_disable(struct v4l2_clk *clk)
 
        ici = to_soc_camera_host(icd->parent);
 
-       mutex_lock(&ici->clk_lock);
-       ici->ops->clock_stop(ici);
-       mutex_unlock(&ici->clk_lock);
+       soc_camera_clock_stop(ici);
 
        module_put(ici->ops->owner);
 }
@@ -1364,7 +1376,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
        snprintf(clk_name, sizeof(clk_name), "%d-%04x",
                 shd->i2c_adapter_id, shd->board_info->addr);
 
-       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
        if (IS_ERR(icd->clk)) {
                ret = PTR_ERR(icd->clk);
                goto eclkreg;
@@ -1445,7 +1457,7 @@ static int soc_camera_async_bound(struct v4l2_async_notifier *notifier,
                                memcpy(&sdesc->subdev_desc, ssdd,
                                       sizeof(sdesc->subdev_desc));
                                if (ssdd->reset)
-                                       ssdd->reset(icd->pdev);
+                                       ssdd->reset(&client->dev);
                        }
 
                        icd->control = &client->dev;
@@ -1545,7 +1557,7 @@ static int scan_async_group(struct soc_camera_host *ici,
        snprintf(clk_name, sizeof(clk_name), "%d-%04x",
                 sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address);
 
-       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
        if (IS_ERR(icd->clk)) {
                ret = PTR_ERR(icd->clk);
                goto eclkreg;
@@ -1650,7 +1662,7 @@ static int soc_of_bind(struct soc_camera_host *ici,
                snprintf(clk_name, sizeof(clk_name), "of-%s",
                         of_node_full_name(remote));
 
-       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
        if (IS_ERR(icd->clk)) {
                ret = PTR_ERR(icd->clk);
                goto eclkreg;
@@ -1659,13 +1671,15 @@ static int soc_of_bind(struct soc_camera_host *ici,
        ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier);
        if (!ret)
                return 0;
+
+       v4l2_clk_unregister(icd->clk);
 eclkreg:
        icd->clk = NULL;
        platform_device_del(sasc->pdev);
 eaddpdev:
        platform_device_put(sasc->pdev);
 eallocpdev:
-       devm_kfree(ici->v4l2_dev.dev, sasc);
+       devm_kfree(ici->v4l2_dev.dev, info);
        dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret);
 
        return ret;
@@ -1750,9 +1764,7 @@ static int soc_camera_probe(struct soc_camera_host *ici,
                ret = -EINVAL;
                goto eadd;
        } else {
-               mutex_lock(&ici->clk_lock);
-               ret = ici->ops->clock_start(ici);
-               mutex_unlock(&ici->clk_lock);
+               ret = soc_camera_clock_start(ici);
                if (ret < 0)
                        goto eadd;
 
@@ -1792,9 +1804,7 @@ efinish:
                module_put(control->driver->owner);
 enodrv:
 eadddev:
-               mutex_lock(&ici->clk_lock);
-               ici->ops->clock_stop(ici);
-               mutex_unlock(&ici->clk_lock);
+               soc_camera_clock_stop(ici);
        }
 eadd:
        if (icd->vdev) {
@@ -1888,22 +1898,34 @@ static int default_enum_framesizes(struct soc_camera_device *icd,
        int ret;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
-       __u32 pixfmt = fsize->pixel_format;
-       struct v4l2_frmsizeenum fsize_mbus = *fsize;
+       struct v4l2_subdev_frame_size_enum fse = {
+               .index = fsize->index,
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+       };
 
-       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       xlate = soc_camera_xlate_by_fourcc(icd, fsize->pixel_format);
        if (!xlate)
                return -EINVAL;
-       /* map xlate-code to pixel_format, sensor only handle xlate-code*/
-       fsize_mbus.pixel_format = xlate->code;
+       fse.code = xlate->code;
 
-       ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus);
+       ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse);
        if (ret < 0)
                return ret;
 
-       *fsize = fsize_mbus;
-       fsize->pixel_format = pixfmt;
-
+       if (fse.min_width == fse.max_width &&
+           fse.min_height == fse.max_height) {
+               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+               fsize->discrete.width = fse.min_width;
+               fsize->discrete.height = fse.min_height;
+               return 0;
+       }
+       fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+       fsize->stepwise.min_width = fse.min_width;
+       fsize->stepwise.max_width = fse.max_width;
+       fsize->stepwise.min_height = fse.min_height;
+       fsize->stepwise.max_height = fse.max_height;
+       fsize->stepwise.step_width = 1;
+       fsize->stepwise.step_height = 1;
        return 0;
 }
 
@@ -1920,8 +1942,6 @@ int soc_camera_host_register(struct soc_camera_host *ici)
            ((!ici->ops->init_videobuf ||
              !ici->ops->reqbufs) &&
             !ici->ops->init_videobuf2) ||
-           !ici->ops->clock_start ||
-           !ici->ops->clock_stop ||
            !ici->ops->poll ||
            !ici->v4l2_dev.dev)
                return -EINVAL;