Commit 1e6af546 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

[media] v4l: vsp1: Implement runtime PM support

Replace the manual refcount and clock management code by runtime PM.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 7b49235e
...@@ -64,9 +64,6 @@ struct vsp1_device { ...@@ -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 @@ ...@@ -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) ...@@ -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);
if (vsp1->ref_count > 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); ret = pm_runtime_get_sync(vsp1->dev);
return ret; return ret < 0 ? ret : 0;
} }
/* /*
...@@ -501,12 +483,7 @@ int vsp1_device_get(struct vsp1_device *vsp1) ...@@ -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,37 +495,55 @@ static int vsp1_pm_suspend(struct device *dev) ...@@ -518,37 +495,55 @@ 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)); vsp1_pipelines_suspend(vsp1);
pm_runtime_force_suspend(vsp1->dev);
if (vsp1->ref_count == 0) return 0;
return 0; }
vsp1_pipelines_suspend(vsp1); static int vsp1_pm_resume(struct device *dev)
{
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
clk_disable_unprepare(vsp1->clock); pm_runtime_force_resume(vsp1->dev);
vsp1_pipelines_resume(vsp1);
return 0; return 0;
} }
#endif
static int vsp1_pm_resume(struct device *dev) static int vsp1_pm_runtime_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)); clk_disable_unprepare(vsp1->clock);
if (vsp1->ref_count == 0) return 0;
return 0; }
clk_prepare_enable(vsp1->clock); static int vsp1_pm_runtime_resume(struct device *dev)
{
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
int ret;
vsp1_pipelines_resume(vsp1); 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; return 0;
} }
#endif
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
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