[media] v4l: vsp1: Implement runtime PM support
Replace the manual refcount and clock management code by runtime PM. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
parent
7b49235e83
commit
1e6af546ee
drivers/media/platform/vsp1
|
@ -64,9 +64,6 @@ struct vsp1_device {
|
||||||
void __iomem *mmio;
|
void __iomem *mmio;
|
||||||
struct clk *clock;
|
struct clk *clock;
|
||||||
|
|
||||||
struct mutex lock;
|
|
||||||
int ref_count;
|
|
||||||
|
|
||||||
struct vsp1_bru *bru;
|
struct vsp1_bru *bru;
|
||||||
struct vsp1_hsit *hsi;
|
struct vsp1_hsit *hsi;
|
||||||
struct vsp1_hsit *hst;
|
struct vsp1_hsit *hst;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
#include <media/v4l2-subdev.h>
|
#include <media/v4l2-subdev.h>
|
||||||
|
@ -462,35 +463,16 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
|
||||||
/*
|
/*
|
||||||
* vsp1_device_get - Acquire the VSP1 device
|
* vsp1_device_get - Acquire the VSP1 device
|
||||||
*
|
*
|
||||||
* Increment the VSP1 reference count and initialize the device if the first
|
* Make sure the device is not suspended and initialize it if needed.
|
||||||
* reference is taken.
|
|
||||||
*
|
*
|
||||||
* Return 0 on success or a negative error code otherwise.
|
* Return 0 on success or a negative error code otherwise.
|
||||||
*/
|
*/
|
||||||
int vsp1_device_get(struct vsp1_device *vsp1)
|
int vsp1_device_get(struct vsp1_device *vsp1)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&vsp1->lock);
|
ret = pm_runtime_get_sync(vsp1->dev);
|
||||||
if (vsp1->ref_count > 0)
|
return ret < 0 ? ret : 0;
|
||||||
goto done;
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(vsp1->clock);
|
|
||||||
if (ret < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
ret = vsp1_device_init(vsp1);
|
|
||||||
if (ret < 0) {
|
|
||||||
clk_disable_unprepare(vsp1->clock);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (!ret)
|
|
||||||
vsp1->ref_count++;
|
|
||||||
|
|
||||||
mutex_unlock(&vsp1->lock);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -501,12 +483,7 @@ int vsp1_device_get(struct vsp1_device *vsp1)
|
||||||
*/
|
*/
|
||||||
void vsp1_device_put(struct vsp1_device *vsp1)
|
void vsp1_device_put(struct vsp1_device *vsp1)
|
||||||
{
|
{
|
||||||
mutex_lock(&vsp1->lock);
|
pm_runtime_put_sync(vsp1->dev);
|
||||||
|
|
||||||
if (--vsp1->ref_count == 0)
|
|
||||||
clk_disable_unprepare(vsp1->clock);
|
|
||||||
|
|
||||||
mutex_unlock(&vsp1->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
|
@ -518,14 +495,8 @@ static int vsp1_pm_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||||
|
|
||||||
WARN_ON(mutex_is_locked(&vsp1->lock));
|
|
||||||
|
|
||||||
if (vsp1->ref_count == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
vsp1_pipelines_suspend(vsp1);
|
vsp1_pipelines_suspend(vsp1);
|
||||||
|
pm_runtime_force_suspend(vsp1->dev);
|
||||||
clk_disable_unprepare(vsp1->clock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -534,21 +505,45 @@ static int vsp1_pm_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||||
|
|
||||||
WARN_ON(mutex_is_locked(&vsp1->lock));
|
pm_runtime_force_resume(vsp1->dev);
|
||||||
|
|
||||||
if (vsp1->ref_count == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
clk_prepare_enable(vsp1->clock);
|
|
||||||
|
|
||||||
vsp1_pipelines_resume(vsp1);
|
vsp1_pipelines_resume(vsp1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int vsp1_pm_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
clk_disable_unprepare(vsp1->clock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vsp1_pm_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(vsp1->clock);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (vsp1->info) {
|
||||||
|
ret = vsp1_device_init(vsp1);
|
||||||
|
if (ret < 0) {
|
||||||
|
clk_disable_unprepare(vsp1->clock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops vsp1_pm_ops = {
|
static const struct dev_pm_ops vsp1_pm_ops = {
|
||||||
SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
|
SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
|
||||||
|
SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL)
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
|
@ -640,10 +635,11 @@ static int vsp1_probe(struct platform_device *pdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
vsp1->dev = &pdev->dev;
|
vsp1->dev = &pdev->dev;
|
||||||
mutex_init(&vsp1->lock);
|
|
||||||
INIT_LIST_HEAD(&vsp1->entities);
|
INIT_LIST_HEAD(&vsp1->entities);
|
||||||
INIT_LIST_HEAD(&vsp1->videos);
|
INIT_LIST_HEAD(&vsp1->videos);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, vsp1);
|
||||||
|
|
||||||
/* I/O, IRQ and clock resources */
|
/* I/O, IRQ and clock resources */
|
||||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
|
vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
|
||||||
|
@ -670,12 +666,14 @@ static int vsp1_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure device parameters based on the version register. */
|
/* Configure device parameters based on the version register. */
|
||||||
ret = clk_prepare_enable(vsp1->clock);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(&pdev->dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto done;
|
||||||
|
|
||||||
version = vsp1_read(vsp1, VI6_IP_VERSION);
|
version = vsp1_read(vsp1, VI6_IP_VERSION);
|
||||||
clk_disable_unprepare(vsp1->clock);
|
pm_runtime_put_sync(&pdev->dev);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
|
for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
|
||||||
if ((version & VI6_IP_VERSION_MODEL_MASK) ==
|
if ((version & VI6_IP_VERSION_MODEL_MASK) ==
|
||||||
|
@ -687,7 +685,8 @@ static int vsp1_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
if (!vsp1->info) {
|
if (!vsp1->info) {
|
||||||
dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version);
|
dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version);
|
||||||
return -ENXIO;
|
ret = -ENXIO;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "IP version 0x%08x\n", version);
|
dev_dbg(&pdev->dev, "IP version 0x%08x\n", version);
|
||||||
|
@ -696,12 +695,14 @@ static int vsp1_probe(struct platform_device *pdev)
|
||||||
ret = vsp1_create_entities(vsp1);
|
ret = vsp1_create_entities(vsp1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "failed to create entities\n");
|
dev_err(&pdev->dev, "failed to create entities\n");
|
||||||
return ret;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, vsp1);
|
done:
|
||||||
|
if (ret)
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vsp1_remove(struct platform_device *pdev)
|
static int vsp1_remove(struct platform_device *pdev)
|
||||||
|
@ -710,6 +711,8 @@ static int vsp1_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
vsp1_destroy_entities(vsp1);
|
vsp1_destroy_entities(vsp1);
|
||||||
|
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -383,7 +383,7 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* Resume pipeline all running pipelines. */
|
/* Resume all running pipelines. */
|
||||||
for (i = 0; i < vsp1->info->wpf_count; ++i) {
|
for (i = 0; i < vsp1->info->wpf_count; ++i) {
|
||||||
struct vsp1_rwpf *wpf = vsp1->wpf[i];
|
struct vsp1_rwpf *wpf = vsp1->wpf[i];
|
||||||
struct vsp1_pipeline *pipe;
|
struct vsp1_pipeline *pipe;
|
||||||
|
|
Loading…
Reference in New Issue