Commit 55cd3452 authored by Lubomir Rintel's avatar Lubomir Rintel Committed by Mauro Carvalho Chehab

media: marvell-ccic: add support for runtime PM

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: default avatarLubomir Rintel <lkundrak@v3.sk>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 9ac7400f
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/pm_runtime.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
...@@ -893,30 +894,6 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam) ...@@ -893,30 +894,6 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam)
spin_unlock_irqrestore(&cam->dev_lock, flags); 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. * Master sensor clock.
...@@ -1633,7 +1610,7 @@ static int mcam_v4l_open(struct file *filp) ...@@ -1633,7 +1610,7 @@ static int mcam_v4l_open(struct file *filp)
ret = sensor_call(cam, core, s_power, 1); ret = sensor_call(cam, core, s_power, 1);
if (ret) if (ret)
goto out; goto out;
mcam_clk_enable(cam); pm_runtime_get_sync(cam->dev);
__mcam_cam_reset(cam); __mcam_cam_reset(cam);
mcam_set_config_needed(cam, 1); mcam_set_config_needed(cam, 1);
} }
...@@ -1656,7 +1633,7 @@ static int mcam_v4l_release(struct file *filp) ...@@ -1656,7 +1633,7 @@ static int mcam_v4l_release(struct file *filp)
if (last_open) { if (last_open) {
mcam_disable_mipi(cam); mcam_disable_mipi(cam);
sensor_call(cam, core, s_power, 0); 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) if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
mcam_free_dma_bufs(cam); mcam_free_dma_bufs(cam);
} }
...@@ -1977,7 +1954,6 @@ void mccic_suspend(struct mcam_camera *cam) ...@@ -1977,7 +1954,6 @@ void mccic_suspend(struct mcam_camera *cam)
mcam_ctlr_stop_dma(cam); mcam_ctlr_stop_dma(cam);
sensor_call(cam, core, s_power, 0); sensor_call(cam, core, s_power, 0);
mcam_clk_disable(cam);
cam->state = cstate; cam->state = cstate;
} }
mutex_unlock(&cam->s_mutex); mutex_unlock(&cam->s_mutex);
...@@ -1990,7 +1966,6 @@ int mccic_resume(struct mcam_camera *cam) ...@@ -1990,7 +1966,6 @@ int mccic_resume(struct mcam_camera *cam)
mutex_lock(&cam->s_mutex); mutex_lock(&cam->s_mutex);
if (!list_empty(&cam->vdev.fh_list)) { if (!list_empty(&cam->vdev.fh_list)) {
mcam_clk_enable(cam);
ret = sensor_call(cam, core, s_power, 1); ret = sensor_call(cam, core, s_power, 1);
if (ret) { if (ret) {
mutex_unlock(&cam->s_mutex); mutex_unlock(&cam->s_mutex);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/pm.h> #include <linux/pm.h>
...@@ -274,6 +275,7 @@ static int mmpcam_probe(struct platform_device *pdev) ...@@ -274,6 +275,7 @@ static int mmpcam_probe(struct platform_device *pdev)
if (ret) if (ret)
goto out; goto out;
pm_runtime_enable(&pdev->dev);
return 0; return 0;
out: out:
fwnode_handle_put(mcam->asd.match.fwnode); fwnode_handle_put(mcam->asd.match.fwnode);
...@@ -288,6 +290,7 @@ static int mmpcam_remove(struct mmp_camera *cam) ...@@ -288,6 +290,7 @@ static int mmpcam_remove(struct mmp_camera *cam)
struct mcam_camera *mcam = &cam->mcam; struct mcam_camera *mcam = &cam->mcam;
mccic_shutdown(mcam); mccic_shutdown(mcam);
pm_runtime_force_suspend(mcam->dev);
return 0; return 0;
} }
...@@ -304,10 +307,39 @@ static int mmpcam_platform_remove(struct platform_device *pdev) ...@@ -304,10 +307,39 @@ static int mmpcam_platform_remove(struct platform_device *pdev)
* Suspend/resume support. * 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) static int mmpcam_suspend(struct device *dev)
{ {
struct mmp_camera *cam = dev_get_drvdata(dev); struct mmp_camera *cam = dev_get_drvdata(dev);
if (!pm_runtime_suspended(dev))
mccic_suspend(&cam->mcam); mccic_suspend(&cam->mcam);
return 0; return 0;
} }
...@@ -316,10 +348,15 @@ static int mmpcam_resume(struct device *dev) ...@@ -316,10 +348,15 @@ static int mmpcam_resume(struct device *dev)
{ {
struct mmp_camera *cam = dev_get_drvdata(dev); struct mmp_camera *cam = dev_get_drvdata(dev);
if (!pm_runtime_suspended(dev))
return mccic_resume(&cam->mcam); 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[] = { static const struct of_device_id mmpcam_of_match[] = {
{ .compatible = "marvell,mmp2-ccic", }, { .compatible = "marvell,mmp2-ccic", },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment