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@xxxxxxxxxxx> > --- > 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, > }, > _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel