[media] exynos-gsc: Simplify system PM
[linux-2.6-microblaze.git] / drivers / media / platform / exynos-gsc / gsc-core.c
index fac0c02..5aeb8b4 100644 (file)
@@ -39,8 +39,8 @@ static const struct gsc_fmt gsc_formats[] = {
                .num_planes     = 1,
                .num_comp       = 1,
        }, {
-               .name           = "XRGB-8-8-8-8, 32 bpp",
-               .pixelformat    = V4L2_PIX_FMT_RGB32,
+               .name           = "BGRX-8-8-8-8, 32 bpp",
+               .pixelformat    = V4L2_PIX_FMT_BGR32,
                .depth          = { 32 },
                .color          = GSC_RGB,
                .num_planes     = 1,
@@ -451,12 +451,25 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
        else /* SD */
                pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-
        for (i = 0; i < pix_mp->num_planes; ++i) {
-               int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
-               pix_mp->plane_fmt[i].bytesperline = bpl;
-               pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
+               struct v4l2_plane_pix_format *plane_fmt = &pix_mp->plane_fmt[i];
+               u32 bpl = plane_fmt->bytesperline;
+
+               if (fmt->num_comp == 1 && /* Packed */
+                   (bpl == 0 || (bpl * 8 / fmt->depth[i]) < pix_mp->width))
+                       bpl = pix_mp->width * fmt->depth[i] / 8;
+
+               if (fmt->num_comp > 1 && /* Planar */
+                   (bpl == 0 || bpl < pix_mp->width))
+                       bpl = pix_mp->width;
 
+               if (i != 0 && fmt->num_comp == 3)
+                       bpl /= 2;
+
+               plane_fmt->bytesperline = bpl;
+               plane_fmt->sizeimage = max(pix_mp->width * pix_mp->height *
+                                          fmt->depth[i] / 8,
+                                          plane_fmt->sizeimage);
                pr_debug("[%d]: bpl: %d, sizeimage: %d",
                                i, bpl, pix_mp->plane_fmt[i].sizeimage);
        }
@@ -988,75 +1001,6 @@ static void *gsc_get_drv_data(struct platform_device *pdev)
        return driver_data;
 }
 
-static void gsc_clk_put(struct gsc_dev *gsc)
-{
-       if (!IS_ERR(gsc->clock))
-               clk_unprepare(gsc->clock);
-}
-
-static int gsc_clk_get(struct gsc_dev *gsc)
-{
-       int ret;
-
-       dev_dbg(&gsc->pdev->dev, "gsc_clk_get Called\n");
-
-       gsc->clock = devm_clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
-       if (IS_ERR(gsc->clock)) {
-               dev_err(&gsc->pdev->dev, "failed to get clock~~~: %s\n",
-                       GSC_CLOCK_GATE_NAME);
-               return PTR_ERR(gsc->clock);
-       }
-
-       ret = clk_prepare(gsc->clock);
-       if (ret < 0) {
-               dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
-                       GSC_CLOCK_GATE_NAME);
-               gsc->clock = ERR_PTR(-EINVAL);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int gsc_m2m_suspend(struct gsc_dev *gsc)
-{
-       unsigned long flags;
-       int timeout;
-
-       spin_lock_irqsave(&gsc->slock, flags);
-       if (!gsc_m2m_pending(gsc)) {
-               spin_unlock_irqrestore(&gsc->slock, flags);
-               return 0;
-       }
-       clear_bit(ST_M2M_SUSPENDED, &gsc->state);
-       set_bit(ST_M2M_SUSPENDING, &gsc->state);
-       spin_unlock_irqrestore(&gsc->slock, flags);
-
-       timeout = wait_event_timeout(gsc->irq_queue,
-                            test_bit(ST_M2M_SUSPENDED, &gsc->state),
-                            GSC_SHUTDOWN_TIMEOUT);
-
-       clear_bit(ST_M2M_SUSPENDING, &gsc->state);
-       return timeout == 0 ? -EAGAIN : 0;
-}
-
-static int gsc_m2m_resume(struct gsc_dev *gsc)
-{
-       struct gsc_ctx *ctx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&gsc->slock, flags);
-       /* Clear for full H/W setup in first run after resume */
-       ctx = gsc->m2m.ctx;
-       gsc->m2m.ctx = NULL;
-       spin_unlock_irqrestore(&gsc->slock, flags);
-
-       if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
-               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
-
-       return 0;
-}
-
 static int gsc_probe(struct platform_device *pdev)
 {
        struct gsc_dev *gsc;
@@ -1085,7 +1029,6 @@ static int gsc_probe(struct platform_device *pdev)
        init_waitqueue_head(&gsc->irq_queue);
        spin_lock_init(&gsc->slock);
        mutex_init(&gsc->lock);
-       gsc->clock = ERR_PTR(-EINVAL);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        gsc->regs = devm_ioremap_resource(dev, res);
@@ -1098,9 +1041,19 @@ static int gsc_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       ret = gsc_clk_get(gsc);
-       if (ret)
+       gsc->clock = devm_clk_get(dev, GSC_CLOCK_GATE_NAME);
+       if (IS_ERR(gsc->clock)) {
+               dev_err(dev, "failed to get clock~~~: %s\n",
+                       GSC_CLOCK_GATE_NAME);
+               return PTR_ERR(gsc->clock);
+       }
+
+       ret = clk_prepare_enable(gsc->clock);
+       if (ret) {
+               dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
+                       GSC_CLOCK_GATE_NAME);
                return ret;
+       }
 
        ret = devm_request_irq(dev, res->start, gsc_irq_handler,
                                0, pdev->name, gsc);
@@ -1118,24 +1071,23 @@ static int gsc_probe(struct platform_device *pdev)
                goto err_v4l2;
 
        platform_set_drvdata(pdev, gsc);
-       pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(&pdev->dev);
-       if (ret < 0)
-               goto err_m2m;
+
+       gsc_hw_set_sw_reset(gsc);
+       gsc_wait_reset(gsc);
 
        vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
 
        dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
 
-       pm_runtime_put(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
        return 0;
 
-err_m2m:
-       gsc_unregister_m2m_device(gsc);
 err_v4l2:
        v4l2_device_unregister(&gsc->v4l2_dev);
 err_clk:
-       gsc_clk_put(gsc);
+       clk_disable_unprepare(gsc->clock);
        return ret;
 }
 
@@ -1143,17 +1095,58 @@ static int gsc_remove(struct platform_device *pdev)
 {
        struct gsc_dev *gsc = platform_get_drvdata(pdev);
 
+       pm_runtime_get_sync(&pdev->dev);
+
        gsc_unregister_m2m_device(gsc);
        v4l2_device_unregister(&gsc->v4l2_dev);
 
        vb2_dma_contig_clear_max_seg_size(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
-       gsc_clk_put(gsc);
+       clk_disable_unprepare(gsc->clock);
+
+       pm_runtime_put_noidle(&pdev->dev);
 
        dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int gsc_m2m_suspend(struct gsc_dev *gsc)
+{
+       unsigned long flags;
+       int timeout;
+
+       spin_lock_irqsave(&gsc->slock, flags);
+       if (!gsc_m2m_pending(gsc)) {
+               spin_unlock_irqrestore(&gsc->slock, flags);
+               return 0;
+       }
+       clear_bit(ST_M2M_SUSPENDED, &gsc->state);
+       set_bit(ST_M2M_SUSPENDING, &gsc->state);
+       spin_unlock_irqrestore(&gsc->slock, flags);
+
+       timeout = wait_event_timeout(gsc->irq_queue,
+                            test_bit(ST_M2M_SUSPENDED, &gsc->state),
+                            GSC_SHUTDOWN_TIMEOUT);
+
+       clear_bit(ST_M2M_SUSPENDING, &gsc->state);
+       return timeout == 0 ? -EAGAIN : 0;
+}
+
+static void gsc_m2m_resume(struct gsc_dev *gsc)
+{
+       struct gsc_ctx *ctx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gsc->slock, flags);
+       /* Clear for full H/W setup in first run after resume */
+       ctx = gsc->m2m.ctx;
+       gsc->m2m.ctx = NULL;
+       spin_unlock_irqrestore(&gsc->slock, flags);
+
+       if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
+               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+}
+
 static int gsc_runtime_resume(struct device *dev)
 {
        struct gsc_dev *gsc = dev_get_drvdata(dev);
@@ -1161,14 +1154,15 @@ static int gsc_runtime_resume(struct device *dev)
 
        pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
 
-       ret = clk_enable(gsc->clock);
+       ret = clk_prepare_enable(gsc->clock);
        if (ret)
                return ret;
 
        gsc_hw_set_sw_reset(gsc);
        gsc_wait_reset(gsc);
+       gsc_m2m_resume(gsc);
 
-       return gsc_m2m_resume(gsc);
+       return 0;
 }
 
 static int gsc_runtime_suspend(struct device *dev)
@@ -1178,28 +1172,16 @@ static int gsc_runtime_suspend(struct device *dev)
 
        ret = gsc_m2m_suspend(gsc);
        if (!ret)
-               clk_disable(gsc->clock);
+               clk_disable_unprepare(gsc->clock);
 
        pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
        return ret;
 }
+#endif
 
+#ifdef CONFIG_PM_SLEEP
 static int gsc_resume(struct device *dev)
 {
-       struct gsc_dev *gsc = dev_get_drvdata(dev);
-       unsigned long flags;
-
-       pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
-
-       /* Do not resume if the device was idle before system suspend */
-       spin_lock_irqsave(&gsc->slock, flags);
-       if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) ||
-           !gsc_m2m_opened(gsc)) {
-               spin_unlock_irqrestore(&gsc->slock, flags);
-               return 0;
-       }
-       spin_unlock_irqrestore(&gsc->slock, flags);
-
        if (!pm_runtime_suspended(dev))
                return gsc_runtime_resume(dev);
 
@@ -1208,24 +1190,16 @@ static int gsc_resume(struct device *dev)
 
 static int gsc_suspend(struct device *dev)
 {
-       struct gsc_dev *gsc = dev_get_drvdata(dev);
-
-       pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
-
-       if (test_and_set_bit(ST_SUSPEND, &gsc->state))
-               return 0;
-
        if (!pm_runtime_suspended(dev))
                return gsc_runtime_suspend(dev);
 
        return 0;
 }
+#endif
 
 static const struct dev_pm_ops gsc_pm_ops = {
-       .suspend                = gsc_suspend,
-       .resume                 = gsc_resume,
-       .runtime_suspend        = gsc_runtime_suspend,
-       .runtime_resume         = gsc_runtime_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(gsc_suspend, gsc_resume)
+       SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
 };
 
 static struct platform_driver gsc_driver = {