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: Lubomir Rintel <lkundrak@v3.sk> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
parent
9ac7400f49
commit
55cd34524a
drivers/media/platform/marvell-ccic
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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,11 +307,40 @@ 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);
|
||||||
|
|
||||||
mccic_suspend(&cam->mcam);
|
if (!pm_runtime_suspended(dev))
|
||||||
|
mccic_suspend(&cam->mcam);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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);
|
||||||
|
|
||||||
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[] = {
|
static const struct of_device_id mmpcam_of_match[] = {
|
||||||
{ .compatible = "marvell,mmp2-ccic", },
|
{ .compatible = "marvell,mmp2-ccic", },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user