[PATCH v2] drm/exynos: mic: Add runtime PM support
Inki Dae
inki.dae at samsung.com
Mon Jan 16 09:19:42 UTC 2017
Applied.
Thanks.
2017년 01월 13일 17:30에 Marek Szyprowski 이(가) 쓴 글:
> This patch adds runtime support calls to notify device core when MIC
> device is really in use. Runtime PM is implemented by enabling and
> disabling clocks like in other Exynos DRM subdrivers. Adding runtime
> PM support is needed to let power domain with this device to be turned
> off when display is not used.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> ---
> Changelog:
> v2:
> - moved clock control to runtime PM callbacks as requested by Inki Dae
>
> v1: http://www.spinics.net/lists/dri-devel/msg129095.html
> - initial version
> ---
> drivers/gpu/drm/exynos/exynos_drm_mic.c | 82 ++++++++++++++++++++++++---------
> 1 file changed, 59 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
> index a0def0be6d65..430f67c63707 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
> @@ -19,6 +19,7 @@
> #include <linux/of_graph.h>
> #include <linux/clk.h>
> #include <linux/component.h>
> +#include <linux/pm_runtime.h>
> #include <drm/drmP.h>
> #include <linux/mfd/syscon.h>
> #include <linux/regmap.h>
> @@ -312,7 +313,6 @@ static void mic_disable(struct drm_bridge *bridge) { }
> static void mic_post_disable(struct drm_bridge *bridge)
> {
> struct exynos_mic *mic = bridge->driver_private;
> - int i;
>
> mutex_lock(&mic_mutex);
> if (!mic->enabled)
> @@ -320,9 +320,7 @@ static void mic_post_disable(struct drm_bridge *bridge)
>
> mic_set_path(mic, 0);
>
> - for (i = NUM_CLKS - 1; i > -1; i--)
> - clk_disable_unprepare(mic->clks[i]);
> -
> + pm_runtime_put(mic->dev);
> mic->enabled = 0;
>
> already_disabled:
> @@ -332,27 +330,22 @@ static void mic_post_disable(struct drm_bridge *bridge)
> static void mic_pre_enable(struct drm_bridge *bridge)
> {
> struct exynos_mic *mic = bridge->driver_private;
> - int ret, i;
> + int ret;
>
> mutex_lock(&mic_mutex);
> if (mic->enabled)
> - goto already_enabled;
> + goto unlock;
>
> - for (i = 0; i < NUM_CLKS; i++) {
> - ret = clk_prepare_enable(mic->clks[i]);
> - if (ret < 0) {
> - DRM_ERROR("Failed to enable clock (%s)\n",
> - clk_names[i]);
> - goto turn_off_clks;
> - }
> - }
> + ret = pm_runtime_get_sync(mic->dev);
> + if (ret < 0)
> + goto unlock;
>
> mic_set_path(mic, 1);
>
> ret = mic_sw_reset(mic);
> if (ret) {
> DRM_ERROR("Failed to reset\n");
> - goto turn_off_clks;
> + goto turn_off;
> }
>
> if (!mic->i80_mode)
> @@ -365,10 +358,9 @@ static void mic_pre_enable(struct drm_bridge *bridge)
>
> return;
>
> -turn_off_clks:
> - while (--i > -1)
> - clk_disable_unprepare(mic->clks[i]);
> -already_enabled:
> +turn_off:
> + pm_runtime_put(mic->dev);
> +unlock:
> mutex_unlock(&mic_mutex);
> }
>
> @@ -401,14 +393,12 @@ static void exynos_mic_unbind(struct device *dev, struct device *master,
> void *data)
> {
> struct exynos_mic *mic = dev_get_drvdata(dev);
> - int i;
>
> mutex_lock(&mic_mutex);
> if (!mic->enabled)
> goto already_disabled;
>
> - for (i = NUM_CLKS - 1; i > -1; i--)
> - clk_disable_unprepare(mic->clks[i]);
> + pm_runtime_put(mic->dev);
>
> already_disabled:
> mutex_unlock(&mic_mutex);
> @@ -421,6 +411,41 @@ static void exynos_mic_unbind(struct device *dev, struct device *master,
> .unbind = exynos_mic_unbind,
> };
>
> +#ifdef CONFIG_PM
> +static int exynos_mic_suspend(struct device *dev)
> +{
> + struct exynos_mic *mic = dev_get_drvdata(dev);
> + int i;
> +
> + for (i = NUM_CLKS - 1; i > -1; i--)
> + clk_disable_unprepare(mic->clks[i]);
> +
> + return 0;
> +}
> +
> +static int exynos_mic_resume(struct device *dev)
> +{
> + struct exynos_mic *mic = dev_get_drvdata(dev);
> + int ret, i;
> +
> + for (i = 0; i < NUM_CLKS; i++) {
> + ret = clk_prepare_enable(mic->clks[i]);
> + if (ret < 0) {
> + DRM_ERROR("Failed to enable clock (%s)\n",
> + clk_names[i]);
> + while (--i > -1)
> + clk_disable_unprepare(mic->clks[i]);
> + return ret;
> + }
> + }
> + return 0;
> +}
> +#endif
> +
> +static const struct dev_pm_ops exynos_mic_pm_ops = {
> + SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
> +};
> +
> static int exynos_mic_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -473,9 +498,18 @@ static int exynos_mic_probe(struct platform_device *pdev)
>
> platform_set_drvdata(pdev, mic);
>
> + pm_runtime_enable(dev);
> +
> + ret = component_add(dev, &exynos_mic_component_ops);
> + if (ret)
> + goto err_pm;
> +
> DRM_DEBUG_KMS("MIC has been probed\n");
> - return component_add(dev, &exynos_mic_component_ops);
>
> + return 0;
> +
> +err_pm:
> + pm_runtime_disable(dev);
> err:
> return ret;
> }
> @@ -483,6 +517,7 @@ static int exynos_mic_probe(struct platform_device *pdev)
> static int exynos_mic_remove(struct platform_device *pdev)
> {
> component_del(&pdev->dev, &exynos_mic_component_ops);
> + pm_runtime_disable(&pdev->dev);
> return 0;
> }
>
> @@ -497,6 +532,7 @@ struct platform_driver mic_driver = {
> .remove = exynos_mic_remove,
> .driver = {
> .name = "exynos-mic",
> + .pm = &exynos_mic_pm_ops,
> .owner = THIS_MODULE,
> .of_match_table = exynos_mic_of_match,
> },
>
More information about the dri-devel
mailing list