media: marvell-ccic: add support for runtime PM
authorLubomir Rintel <lkundrak@v3.sk>
Mon, 17 Aug 2020 22:08:50 +0000 (00:08 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Sat, 29 Aug 2020 06:10:02 +0000 (08:10 +0200)
On MMP3, the camera block lives on a separate power island. We want to
turn it off if the CCIC is not in use to conserve power.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/marvell-ccic/mmp-driver.c

index 3d4242b8182ba701308710f81c05dce6e0699cd0..a967f010341fa35bec28bfccfb51d786d5d4e647 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/videodev2.h>
+#include <linux/pm_runtime.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
@@ -893,30 +894,6 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam)
        spin_unlock_irqrestore(&cam->dev_lock, flags);
 }
 
-/* ---------------------------------------------------------------------- */
-/*
- * Controller clocks.
- */
-static void mcam_clk_enable(struct mcam_camera *mcam)
-{
-       unsigned int i;
-
-       for (i = 0; i < NR_MCAM_CLK; i++) {
-               if (!IS_ERR(mcam->clk[i]))
-                       clk_prepare_enable(mcam->clk[i]);
-       }
-}
-
-static void mcam_clk_disable(struct mcam_camera *mcam)
-{
-       int i;
-
-       for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
-               if (!IS_ERR(mcam->clk[i]))
-                       clk_disable_unprepare(mcam->clk[i]);
-       }
-}
-
 /* ---------------------------------------------------------------------- */
 /*
  * Master sensor clock.
@@ -1633,7 +1610,7 @@ static int mcam_v4l_open(struct file *filp)
                ret = sensor_call(cam, core, s_power, 1);
                if (ret)
                        goto out;
-               mcam_clk_enable(cam);
+               pm_runtime_get_sync(cam->dev);
                __mcam_cam_reset(cam);
                mcam_set_config_needed(cam, 1);
        }
@@ -1656,7 +1633,7 @@ static int mcam_v4l_release(struct file *filp)
        if (last_open) {
                mcam_disable_mipi(cam);
                sensor_call(cam, core, s_power, 0);
-               mcam_clk_disable(cam);
+               pm_runtime_put(cam->dev);
                if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
                        mcam_free_dma_bufs(cam);
        }
@@ -1977,7 +1954,6 @@ void mccic_suspend(struct mcam_camera *cam)
 
                mcam_ctlr_stop_dma(cam);
                sensor_call(cam, core, s_power, 0);
-               mcam_clk_disable(cam);
                cam->state = cstate;
        }
        mutex_unlock(&cam->s_mutex);
@@ -1990,7 +1966,6 @@ int mccic_resume(struct mcam_camera *cam)
 
        mutex_lock(&cam->s_mutex);
        if (!list_empty(&cam->vdev.fh_list)) {
-               mcam_clk_enable(cam);
                ret = sensor_call(cam, core, s_power, 1);
                if (ret) {
                        mutex_unlock(&cam->s_mutex);
index 78263e746cad207d96875af6fcce96253bffa26e..c4b28a00a3a24d0b7789db26244f9e28c86e45db 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/io.h>
 #include <linux/list.h>
 #include <linux/pm.h>
@@ -274,6 +275,7 @@ static int mmpcam_probe(struct platform_device *pdev)
        if (ret)
                goto out;
 
+       pm_runtime_enable(&pdev->dev);
        return 0;
 out:
        fwnode_handle_put(mcam->asd.match.fwnode);
@@ -288,6 +290,7 @@ static int mmpcam_remove(struct mmp_camera *cam)
        struct mcam_camera *mcam = &cam->mcam;
 
        mccic_shutdown(mcam);
+       pm_runtime_force_suspend(mcam->dev);
        return 0;
 }
 
@@ -304,11 +307,40 @@ static int mmpcam_platform_remove(struct platform_device *pdev)
  * Suspend/resume support.
  */
 
+static int mmpcam_runtime_resume(struct device *dev)
+{
+       struct mmp_camera *cam = dev_get_drvdata(dev);
+       struct mcam_camera *mcam = &cam->mcam;
+       unsigned int i;
+
+       for (i = 0; i < NR_MCAM_CLK; i++) {
+               if (!IS_ERR(mcam->clk[i]))
+                       clk_prepare_enable(mcam->clk[i]);
+       }
+
+       return 0;
+}
+
+static int mmpcam_runtime_suspend(struct device *dev)
+{
+       struct mmp_camera *cam = dev_get_drvdata(dev);
+       struct mcam_camera *mcam = &cam->mcam;
+       int i;
+
+       for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
+               if (!IS_ERR(mcam->clk[i]))
+                       clk_disable_unprepare(mcam->clk[i]);
+       }
+
+       return 0;
+}
+
 static int mmpcam_suspend(struct device *dev)
 {
        struct mmp_camera *cam = dev_get_drvdata(dev);
 
-       mccic_suspend(&cam->mcam);
+       if (!pm_runtime_suspended(dev))
+               mccic_suspend(&cam->mcam);
        return 0;
 }
 
@@ -316,10 +348,15 @@ static int mmpcam_resume(struct device *dev)
 {
        struct mmp_camera *cam = dev_get_drvdata(dev);
 
-       return mccic_resume(&cam->mcam);
+       if (!pm_runtime_suspended(dev))
+               return mccic_resume(&cam->mcam);
+       return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(mmpcam_pm_ops, mmpcam_suspend, mmpcam_resume);
+static const struct dev_pm_ops mmpcam_pm_ops = {
+       SET_RUNTIME_PM_OPS(mmpcam_runtime_suspend, mmpcam_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(mmpcam_suspend, mmpcam_resume)
+};
 
 static const struct of_device_id mmpcam_of_match[] = {
        { .compatible = "marvell,mmp2-ccic", },