[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