V4L/DVB (12510): soc-camera: (partially) convert to v4l2-(sub)dev API
[profile/ivi/kernel-adaptation-intel-automotive.git] / drivers / media / video / sh_mobile_ceu_camera.c
index e86878d..5101fa7 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/videodev2.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
@@ -86,7 +86,6 @@ struct sh_mobile_ceu_dev {
 
        unsigned int irq;
        void __iomem *base;
-       struct clk *clk;
        unsigned long video_limit;
 
        /* lock used to protect videobuf */
@@ -348,19 +347,14 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
-       int ret = -EBUSY;
 
        if (pcdev->icd)
-               goto err;
+               return -EBUSY;
 
        dev_info(&icd->dev,
                 "SuperH Mobile CEU driver attached to camera %d\n",
                 icd->devnum);
 
-       ret = icd->ops->init(icd);
-       if (ret)
-               goto err;
-
        clk_enable(pcdev->clk);
 
        ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
@@ -368,8 +362,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
                msleep(1);
 
        pcdev->icd = icd;
-err:
-       return ret;
+
+       return 0;
 }
 
 /* Called with .video_lock held */
@@ -397,8 +391,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 
        clk_disable(pcdev->clk);
 
-       icd->ops->release(icd);
-
        dev_info(&icd->dev,
                 "SuperH Mobile CEU driver detached from camera %d\n",
                 icd->devnum);
@@ -613,7 +605,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->v4l2_dev.dev, "Providing format %s using %s\n",
                                sh_mobile_ceu_formats[k].name,
                                icd->formats[idx].name);
                }
@@ -626,7 +618,7 @@ add_single_format:
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(ici->dev,
+                       dev_dbg(ici->v4l2_dev.dev,
                                "Providing format %s in pass-through mode\n",
                                icd->formats[idx].name);
                }
@@ -648,18 +640,17 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        __u32 pixfmt = f->fmt.pix.pixelformat;
        const struct soc_camera_format_xlate *xlate;
-       struct v4l2_format cam_f = *f;
        int ret;
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
-       cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
-       ret = icd->ops->set_fmt(icd, &cam_f);
-
+       f->fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
+       ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, s_fmt, f);
+       f->fmt.pix.pixelformat = pixfmt;
        if (!ret) {
                icd->buswidth = xlate->buswidth;
                icd->current_fmt = xlate->host_fmt;
@@ -680,7 +671,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -693,8 +684,11 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                DIV_ROUND_UP(xlate->host_fmt->depth, 8);
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
 
+       f->fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
+
        /* limit to sensor capabilities */
-       ret = icd->ops->try_fmt(icd, f);
+       ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, try_fmt, f);
+       f->fmt.pix.pixelformat = pixfmt;
        if (ret < 0)
                return ret;
 
@@ -770,7 +764,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
 
        videobuf_queue_dma_contig_init(q,
                                       &sh_mobile_ceu_videobuf_ops,
-                                      ici->dev, &pcdev->lock,
+                                      ici->v4l2_dev.dev, &pcdev->lock,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                       pcdev->is_interlaced ?
                                       V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE,
@@ -793,12 +787,11 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
        .init_videobuf  = sh_mobile_ceu_init_videobuf,
 };
 
-static int sh_mobile_ceu_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
 {
        struct sh_mobile_ceu_dev *pcdev;
        struct resource *res;
        void __iomem *base;
-       char clk_name[8];
        unsigned int irq;
        int err = 0;
 
@@ -862,28 +855,22 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                goto exit_release_mem;
        }
 
-       snprintf(clk_name, sizeof(clk_name), "ceu%d", pdev->id);
-       pcdev->clk = clk_get(&pdev->dev, clk_name);
-       if (IS_ERR(pcdev->clk)) {
-               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
-               err = PTR_ERR(pcdev->clk);
-               goto exit_free_irq;
-       }
+       pm_suspend_ignore_children(&pdev->dev, true);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_resume(&pdev->dev);
 
        pcdev->ici.priv = pcdev;
-       pcdev->ici.dev = &pdev->dev;
+       pcdev->ici.v4l2_dev.dev = &pdev->dev;
        pcdev->ici.nr = pdev->id;
        pcdev->ici.drv_name = dev_name(&pdev->dev);
        pcdev->ici.ops = &sh_mobile_ceu_host_ops;
 
        err = soc_camera_host_register(&pcdev->ici);
        if (err)
-               goto exit_free_clk;
+               goto exit_free_irq;
 
        return 0;
 
-exit_free_clk:
-       clk_put(pcdev->clk);
 exit_free_irq:
        free_irq(pcdev->irq, pcdev);
 exit_release_mem:
@@ -897,14 +884,13 @@ exit:
        return err;
 }
 
-static int sh_mobile_ceu_remove(struct platform_device *pdev)
+static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
 {
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
                                        struct sh_mobile_ceu_dev, ici);
 
        soc_camera_host_unregister(soc_host);
-       clk_put(pcdev->clk);
        free_irq(pcdev->irq, pcdev);
        if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
                dma_release_declared_memory(&pdev->dev);
@@ -913,12 +899,30 @@ static int sh_mobile_ceu_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int sh_mobile_ceu_runtime_nop(struct device *dev)
+{
+       /* Runtime PM callback shared between ->runtime_suspend()
+        * and ->runtime_resume(). Simply returns success.
+        *
+        * This driver re-initializes all registers after
+        * pm_runtime_get_sync() anyway so there is no need
+        * to save and restore registers here.
+        */
+       return 0;
+}
+
+static struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = {
+       .runtime_suspend = sh_mobile_ceu_runtime_nop,
+       .runtime_resume = sh_mobile_ceu_runtime_nop,
+};
+
 static struct platform_driver sh_mobile_ceu_driver = {
        .driver         = {
                .name   = "sh_mobile_ceu",
+               .pm     = &sh_mobile_ceu_dev_pm_ops,
        },
        .probe          = sh_mobile_ceu_probe,
-       .remove         = sh_mobile_ceu_remove,
+       .remove         = __exit_p(sh_mobile_ceu_remove),
 };
 
 static int __init sh_mobile_ceu_init(void)
@@ -937,3 +941,4 @@ module_exit(sh_mobile_ceu_exit);
 MODULE_DESCRIPTION("SuperH Mobile CEU driver");
 MODULE_AUTHOR("Magnus Damm");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh_mobile_ceu");