Commit 4e8ba5cc authored by Marek Szyprowski's avatar Marek Szyprowski Committed by Inki Dae

drm/exynos: mic: Add runtime PM support

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: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
parent 328c057c
......@@ -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>
......@@ -286,7 +287,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)
......@@ -294,9 +294,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:
......@@ -317,27 +315,22 @@ static void mic_mode_set(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)
......@@ -350,10 +343,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);
}
......@@ -387,14 +379,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);
......@@ -407,6 +397,41 @@ static const struct component_ops exynos_mic_component_ops = {
.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;
......@@ -459,9 +484,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;
}
......@@ -469,6 +503,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;
}
......@@ -483,6 +518,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,
},
......
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