* [PATCH 1/7] [media] exynos-gsc: Simplify clock management
2014-10-14 7:15 [PATCH 0/7] [media] exynos-gsc: Fixup PM support Ulf Hansson
@ 2014-10-14 7:15 ` Ulf Hansson
2014-10-14 7:15 ` [PATCH 2/7] [media] exynos-gsc: Convert gsc_m2m_resume() from int to void Ulf Hansson
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Ulf Hansson @ 2014-10-14 7:15 UTC (permalink / raw)
To: linux-arm-kernel
Instead of having separate functions that fecthes, prepares and
unprepares the clock, let's encapsulate this code into ->probe().
This makes error handling easier and decreases the lines of code.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 49 ++++++++--------------------
1 file changed, 14 insertions(+), 35 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index b4c9f1d..3fca4fd 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1000,36 +1000,6 @@ static void *gsc_get_drv_data(struct platform_device *pdev)
return driver_data;
}
-static void gsc_clk_put(struct gsc_dev *gsc)
-{
- if (!IS_ERR(gsc->clock))
- clk_unprepare(gsc->clock);
-}
-
-static int gsc_clk_get(struct gsc_dev *gsc)
-{
- int ret;
-
- dev_dbg(&gsc->pdev->dev, "gsc_clk_get Called\n");
-
- gsc->clock = devm_clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
- if (IS_ERR(gsc->clock)) {
- dev_err(&gsc->pdev->dev, "failed to get clock~~~: %s\n",
- GSC_CLOCK_GATE_NAME);
- return PTR_ERR(gsc->clock);
- }
-
- ret = clk_prepare(gsc->clock);
- if (ret < 0) {
- dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
- GSC_CLOCK_GATE_NAME);
- gsc->clock = ERR_PTR(-EINVAL);
- return ret;
- }
-
- return 0;
-}
-
static int gsc_m2m_suspend(struct gsc_dev *gsc)
{
unsigned long flags;
@@ -1098,7 +1068,6 @@ static int gsc_probe(struct platform_device *pdev)
init_waitqueue_head(&gsc->irq_queue);
spin_lock_init(&gsc->slock);
mutex_init(&gsc->lock);
- gsc->clock = ERR_PTR(-EINVAL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gsc->regs = devm_ioremap_resource(dev, res);
@@ -1111,9 +1080,19 @@ static int gsc_probe(struct platform_device *pdev)
return -ENXIO;
}
- ret = gsc_clk_get(gsc);
- if (ret)
+ gsc->clock = devm_clk_get(dev, GSC_CLOCK_GATE_NAME);
+ if (IS_ERR(gsc->clock)) {
+ dev_err(dev, "failed to get clock~~~: %s\n",
+ GSC_CLOCK_GATE_NAME);
+ return PTR_ERR(gsc->clock);
+ }
+
+ ret = clk_prepare(gsc->clock);
+ if (ret) {
+ dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
+ GSC_CLOCK_GATE_NAME);
return ret;
+ }
ret = devm_request_irq(dev, res->start, gsc_irq_handler,
0, pdev->name, gsc);
@@ -1154,7 +1133,7 @@ err_m2m:
err_v4l2:
v4l2_device_unregister(&gsc->v4l2_dev);
err_clk:
- gsc_clk_put(gsc);
+ clk_unprepare(gsc->clock);
return ret;
}
@@ -1167,7 +1146,7 @@ static int gsc_remove(struct platform_device *pdev)
vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx);
pm_runtime_disable(&pdev->dev);
- gsc_clk_put(gsc);
+ clk_unprepare(gsc->clock);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 2/7] [media] exynos-gsc: Convert gsc_m2m_resume() from int to void
2014-10-14 7:15 [PATCH 0/7] [media] exynos-gsc: Fixup PM support Ulf Hansson
2014-10-14 7:15 ` [PATCH 1/7] [media] exynos-gsc: Simplify clock management Ulf Hansson
@ 2014-10-14 7:15 ` Ulf Hansson
2014-10-14 7:15 ` [PATCH 3/7] [media] exynos-gsc: Make driver functional without CONFIG_PM_RUNTIME Ulf Hansson
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Ulf Hansson @ 2014-10-14 7:15 UTC (permalink / raw)
To: linux-arm-kernel
Since gsc_m2m_resume() always returns 0, convert it into void instead.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 3fca4fd..13d0226 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1022,7 +1022,7 @@ static int gsc_m2m_suspend(struct gsc_dev *gsc)
return timeout == 0 ? -EAGAIN : 0;
}
-static int gsc_m2m_resume(struct gsc_dev *gsc)
+static void gsc_m2m_resume(struct gsc_dev *gsc)
{
struct gsc_ctx *ctx;
unsigned long flags;
@@ -1035,8 +1035,6 @@ static int gsc_m2m_resume(struct gsc_dev *gsc)
if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
-
- return 0;
}
static int gsc_probe(struct platform_device *pdev)
@@ -1165,8 +1163,9 @@ static int gsc_runtime_resume(struct device *dev)
gsc_hw_set_sw_reset(gsc);
gsc_wait_reset(gsc);
+ gsc_m2m_resume(gsc);
- return gsc_m2m_resume(gsc);
+ return 0;
}
static int gsc_runtime_suspend(struct device *dev)
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 3/7] [media] exynos-gsc: Make driver functional without CONFIG_PM_RUNTIME
2014-10-14 7:15 [PATCH 0/7] [media] exynos-gsc: Fixup PM support Ulf Hansson
2014-10-14 7:15 ` [PATCH 1/7] [media] exynos-gsc: Simplify clock management Ulf Hansson
2014-10-14 7:15 ` [PATCH 2/7] [media] exynos-gsc: Convert gsc_m2m_resume() from int to void Ulf Hansson
@ 2014-10-14 7:15 ` Ulf Hansson
2014-10-14 7:15 ` [PATCH 4/7] [media] exynos-gsc: Make runtime PM callbacks available for CONFIG_PM Ulf Hansson
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Ulf Hansson @ 2014-10-14 7:15 UTC (permalink / raw)
To: linux-arm-kernel
The driver depended on CONFIG_PM_RUNTIME to be functional, which isn't
necessary.
The solution to the above is to enable all runtime PM resourses during
probe and update the device's runtime PM status to active.
Since driver core invokes pm_request_idle() after ->probe(), unused gsc
devices will be runtime PM suspended and thus we will still benefit
from using CONFIG_PM_RUNTIME.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 13d0226..c3a050e 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1085,7 +1085,7 @@ static int gsc_probe(struct platform_device *pdev)
return PTR_ERR(gsc->clock);
}
- ret = clk_prepare(gsc->clock);
+ ret = clk_prepare_enable(gsc->clock);
if (ret) {
dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
GSC_CLOCK_GATE_NAME);
@@ -1108,30 +1108,30 @@ static int gsc_probe(struct platform_device *pdev)
goto err_v4l2;
platform_set_drvdata(pdev, gsc);
- pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0)
- goto err_m2m;
+
+ gsc_hw_set_sw_reset(gsc);
+ gsc_wait_reset(gsc);
+ gsc_m2m_resume(gsc);
/* Initialize continious memory allocator */
gsc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(gsc->alloc_ctx)) {
ret = PTR_ERR(gsc->alloc_ctx);
- goto err_pm;
+ goto err_m2m;
}
dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
- pm_runtime_put(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
return 0;
-err_pm:
- pm_runtime_put(dev);
err_m2m:
gsc_unregister_m2m_device(gsc);
err_v4l2:
v4l2_device_unregister(&gsc->v4l2_dev);
err_clk:
- clk_unprepare(gsc->clock);
+ clk_disable_unprepare(gsc->clock);
return ret;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 4/7] [media] exynos-gsc: Make runtime PM callbacks available for CONFIG_PM
2014-10-14 7:15 [PATCH 0/7] [media] exynos-gsc: Fixup PM support Ulf Hansson
` (2 preceding siblings ...)
2014-10-14 7:15 ` [PATCH 3/7] [media] exynos-gsc: Make driver functional without CONFIG_PM_RUNTIME Ulf Hansson
@ 2014-10-14 7:15 ` Ulf Hansson
2014-10-14 7:15 ` [PATCH 5/7] [media] exynos-gsc: Fixup system PM Ulf Hansson
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Ulf Hansson @ 2014-10-14 7:15 UTC (permalink / raw)
To: linux-arm-kernel
There are no need to set up the runtime PM callbacks unless they are
being used. Let's make them available for CONFIG_PM.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index c3a050e..361a807 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1150,6 +1150,7 @@ static int gsc_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
static int gsc_runtime_resume(struct device *dev)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
@@ -1180,6 +1181,7 @@ static int gsc_runtime_suspend(struct device *dev)
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
return ret;
}
+#endif
static int gsc_resume(struct device *dev)
{
@@ -1221,8 +1223,7 @@ static int gsc_suspend(struct device *dev)
static const struct dev_pm_ops gsc_pm_ops = {
.suspend = gsc_suspend,
.resume = gsc_resume,
- .runtime_suspend = gsc_runtime_suspend,
- .runtime_resume = gsc_runtime_resume,
+ SET_PM_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
};
static struct platform_driver gsc_driver = {
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 5/7] [media] exynos-gsc: Fixup system PM
2014-10-14 7:15 [PATCH 0/7] [media] exynos-gsc: Fixup PM support Ulf Hansson
` (3 preceding siblings ...)
2014-10-14 7:15 ` [PATCH 4/7] [media] exynos-gsc: Make runtime PM callbacks available for CONFIG_PM Ulf Hansson
@ 2014-10-14 7:15 ` Ulf Hansson
2014-10-14 7:15 ` [PATCH 6/7] [media] exynos-gsc: Fixup clock management at ->remove() Ulf Hansson
2014-10-14 7:15 ` [PATCH 7/7] [media] exynos-gsc: Do full clock gating at runtime PM suspend Ulf Hansson
6 siblings, 0 replies; 8+ messages in thread
From: Ulf Hansson @ 2014-10-14 7:15 UTC (permalink / raw)
To: linux-arm-kernel
We had several issues with the system PM support.
1) It were depending on CONFIG_PM_RUNTIME.
2) It unnecessarily tracked the suspend state in a flag.
3) If userspace through sysfs prevents runtime PM operations, could
cause the device to stay in low power after a system PM resume, which
is not reflected properly.
Solve all the above issues by using pm_runtime_force_suspend|resume() as
the system PM callbacks.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 41 ++--------------------------
drivers/media/platform/exynos-gsc/gsc-core.h | 3 --
2 files changed, 2 insertions(+), 42 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 361a807..1b9f3d7 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1183,46 +1183,9 @@ static int gsc_runtime_suspend(struct device *dev)
}
#endif
-static int gsc_resume(struct device *dev)
-{
- struct gsc_dev *gsc = dev_get_drvdata(dev);
- unsigned long flags;
-
- pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
-
- /* Do not resume if the device was idle before system suspend */
- spin_lock_irqsave(&gsc->slock, flags);
- if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) ||
- !gsc_m2m_opened(gsc)) {
- spin_unlock_irqrestore(&gsc->slock, flags);
- return 0;
- }
- spin_unlock_irqrestore(&gsc->slock, flags);
-
- if (!pm_runtime_suspended(dev))
- return gsc_runtime_resume(dev);
-
- return 0;
-}
-
-static int gsc_suspend(struct device *dev)
-{
- struct gsc_dev *gsc = dev_get_drvdata(dev);
-
- pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
-
- if (test_and_set_bit(ST_SUSPEND, &gsc->state))
- return 0;
-
- if (!pm_runtime_suspended(dev))
- return gsc_runtime_suspend(dev);
-
- return 0;
-}
-
static const struct dev_pm_ops gsc_pm_ops = {
- .suspend = gsc_suspend,
- .resume = gsc_resume,
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
SET_PM_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
};
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
index ef0a656..2dbaa20 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/exynos-gsc/gsc-core.h
@@ -48,9 +48,6 @@
#define GSC_CTX_ABORT (1 << 7)
enum gsc_dev_flags {
- /* for global */
- ST_SUSPEND,
-
/* for m2m node */
ST_M2M_OPEN,
ST_M2M_RUN,
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 6/7] [media] exynos-gsc: Fixup clock management at ->remove()
2014-10-14 7:15 [PATCH 0/7] [media] exynos-gsc: Fixup PM support Ulf Hansson
` (4 preceding siblings ...)
2014-10-14 7:15 ` [PATCH 5/7] [media] exynos-gsc: Fixup system PM Ulf Hansson
@ 2014-10-14 7:15 ` Ulf Hansson
2014-10-14 7:15 ` [PATCH 7/7] [media] exynos-gsc: Do full clock gating at runtime PM suspend Ulf Hansson
6 siblings, 0 replies; 8+ messages in thread
From: Ulf Hansson @ 2014-10-14 7:15 UTC (permalink / raw)
To: linux-arm-kernel
We want to make sure that the clock is fully gated after ->remove(). To
do this, we need to bring the device into full power and not only
unprepare the clock, but also disable it.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 1b9f3d7..e48aefa 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1139,12 +1139,15 @@ static int gsc_remove(struct platform_device *pdev)
{
struct gsc_dev *gsc = platform_get_drvdata(pdev);
+ pm_runtime_get_sync(&pdev->dev);
+
gsc_unregister_m2m_device(gsc);
v4l2_device_unregister(&gsc->v4l2_dev);
-
vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx);
+ clk_disable_unprepare(gsc->clock);
+
pm_runtime_disable(&pdev->dev);
- clk_unprepare(gsc->clock);
+ pm_runtime_put_noidle(&pdev->dev);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 7/7] [media] exynos-gsc: Do full clock gating at runtime PM suspend
2014-10-14 7:15 [PATCH 0/7] [media] exynos-gsc: Fixup PM support Ulf Hansson
` (5 preceding siblings ...)
2014-10-14 7:15 ` [PATCH 6/7] [media] exynos-gsc: Fixup clock management at ->remove() Ulf Hansson
@ 2014-10-14 7:15 ` Ulf Hansson
6 siblings, 0 replies; 8+ messages in thread
From: Ulf Hansson @ 2014-10-14 7:15 UTC (permalink / raw)
To: linux-arm-kernel
To potentially save more power in runtime PM suspend state, let's also
prepare/unprepare the clock from the runtime PM callbacks.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
drivers/media/platform/exynos-gsc/gsc-core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index e48aefa..e90ba09 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1161,7 +1161,7 @@ static int gsc_runtime_resume(struct device *dev)
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
- ret = clk_enable(gsc->clock);
+ ret = clk_prepare_enable(gsc->clock);
if (ret)
return ret;
@@ -1179,7 +1179,7 @@ static int gsc_runtime_suspend(struct device *dev)
ret = gsc_m2m_suspend(gsc);
if (!ret)
- clk_disable(gsc->clock);
+ clk_disable_unprepare(gsc->clock);
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
return ret;
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread