Skip to content

Commit f5f1781

Browse files
ldesrochesstorulf
authored andcommitted
mmc: sdhci-of-at91: add PM support
Add runtime PM support and use runtime_force_suspend|resume() for system PM. Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent 28ff4fd commit f5f1781

File tree

1 file changed

+73
-2
lines changed

1 file changed

+73
-2
lines changed

drivers/mmc/host/sdhci-of-at91.c

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <linux/module.h>
2222
#include <linux/of.h>
2323
#include <linux/of_device.h>
24+
#include <linux/pm.h>
25+
#include <linux/pm_runtime.h>
2426

2527
#include "sdhci-pltfm.h"
2628

@@ -51,6 +53,60 @@ static const struct of_device_id sdhci_at91_dt_match[] = {
5153
{}
5254
};
5355

56+
#ifdef CONFIG_PM
57+
static int sdhci_at91_runtime_suspend(struct device *dev)
58+
{
59+
struct sdhci_host *host = dev_get_drvdata(dev);
60+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
61+
struct sdhci_at91_priv *priv = pltfm_host->priv;
62+
int ret;
63+
64+
ret = sdhci_runtime_suspend_host(host);
65+
66+
clk_disable_unprepare(priv->gck);
67+
clk_disable_unprepare(priv->hclock);
68+
clk_disable_unprepare(priv->mainck);
69+
70+
return ret;
71+
}
72+
73+
static int sdhci_at91_runtime_resume(struct device *dev)
74+
{
75+
struct sdhci_host *host = dev_get_drvdata(dev);
76+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
77+
struct sdhci_at91_priv *priv = pltfm_host->priv;
78+
int ret;
79+
80+
ret = clk_prepare_enable(priv->mainck);
81+
if (ret) {
82+
dev_err(dev, "can't enable mainck\n");
83+
return ret;
84+
}
85+
86+
ret = clk_prepare_enable(priv->hclock);
87+
if (ret) {
88+
dev_err(dev, "can't enable hclock\n");
89+
return ret;
90+
}
91+
92+
ret = clk_prepare_enable(priv->gck);
93+
if (ret) {
94+
dev_err(dev, "can't enable gck\n");
95+
return ret;
96+
}
97+
98+
return sdhci_runtime_resume_host(host);
99+
}
100+
#endif /* CONFIG_PM */
101+
102+
static const struct dev_pm_ops sdhci_at91_dev_pm_ops = {
103+
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
104+
pm_runtime_force_resume)
105+
SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend,
106+
sdhci_at91_runtime_resume,
107+
NULL)
108+
};
109+
54110
static int sdhci_at91_probe(struct platform_device *pdev)
55111
{
56112
const struct of_device_id *match;
@@ -144,12 +200,23 @@ static int sdhci_at91_probe(struct platform_device *pdev)
144200

145201
sdhci_get_of_property(pdev);
146202

203+
pm_runtime_get_noresume(&pdev->dev);
204+
pm_runtime_set_active(&pdev->dev);
205+
pm_runtime_enable(&pdev->dev);
206+
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
207+
pm_runtime_use_autosuspend(&pdev->dev);
208+
147209
ret = sdhci_add_host(host);
148210
if (ret)
149-
goto clocks_disable_unprepare;
211+
goto pm_runtime_disable;
212+
213+
pm_runtime_put_autosuspend(&pdev->dev);
150214

151215
return 0;
152216

217+
pm_runtime_disable:
218+
pm_runtime_disable(&pdev->dev);
219+
pm_runtime_set_suspended(&pdev->dev);
153220
clocks_disable_unprepare:
154221
clk_disable_unprepare(priv->gck);
155222
clk_disable_unprepare(priv->mainck);
@@ -165,6 +232,10 @@ static int sdhci_at91_remove(struct platform_device *pdev)
165232
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
166233
struct sdhci_at91_priv *priv = pltfm_host->priv;
167234

235+
pm_runtime_get_sync(&pdev->dev);
236+
pm_runtime_disable(&pdev->dev);
237+
pm_runtime_put_noidle(&pdev->dev);
238+
168239
sdhci_pltfm_unregister(pdev);
169240

170241
clk_disable_unprepare(priv->gck);
@@ -178,7 +249,7 @@ static struct platform_driver sdhci_at91_driver = {
178249
.driver = {
179250
.name = "sdhci-at91",
180251
.of_match_table = sdhci_at91_dt_match,
181-
.pm = SDHCI_PLTFM_PMOPS,
252+
.pm = &sdhci_at91_dev_pm_ops,
182253
},
183254
.probe = sdhci_at91_probe,
184255
.remove = sdhci_at91_remove,

0 commit comments

Comments
 (0)