21
21
#include <linux/module.h>
22
22
#include <linux/of.h>
23
23
#include <linux/of_device.h>
24
+ #include <linux/pm.h>
25
+ #include <linux/pm_runtime.h>
24
26
25
27
#include "sdhci-pltfm.h"
26
28
@@ -51,6 +53,60 @@ static const struct of_device_id sdhci_at91_dt_match[] = {
51
53
{}
52
54
};
53
55
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
+
54
110
static int sdhci_at91_probe (struct platform_device * pdev )
55
111
{
56
112
const struct of_device_id * match ;
@@ -144,12 +200,23 @@ static int sdhci_at91_probe(struct platform_device *pdev)
144
200
145
201
sdhci_get_of_property (pdev );
146
202
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
+
147
209
ret = sdhci_add_host (host );
148
210
if (ret )
149
- goto clocks_disable_unprepare ;
211
+ goto pm_runtime_disable ;
212
+
213
+ pm_runtime_put_autosuspend (& pdev -> dev );
150
214
151
215
return 0 ;
152
216
217
+ pm_runtime_disable :
218
+ pm_runtime_disable (& pdev -> dev );
219
+ pm_runtime_set_suspended (& pdev -> dev );
153
220
clocks_disable_unprepare :
154
221
clk_disable_unprepare (priv -> gck );
155
222
clk_disable_unprepare (priv -> mainck );
@@ -165,6 +232,10 @@ static int sdhci_at91_remove(struct platform_device *pdev)
165
232
struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
166
233
struct sdhci_at91_priv * priv = pltfm_host -> priv ;
167
234
235
+ pm_runtime_get_sync (& pdev -> dev );
236
+ pm_runtime_disable (& pdev -> dev );
237
+ pm_runtime_put_noidle (& pdev -> dev );
238
+
168
239
sdhci_pltfm_unregister (pdev );
169
240
170
241
clk_disable_unprepare (priv -> gck );
@@ -178,7 +249,7 @@ static struct platform_driver sdhci_at91_driver = {
178
249
.driver = {
179
250
.name = "sdhci-at91" ,
180
251
.of_match_table = sdhci_at91_dt_match ,
181
- .pm = SDHCI_PLTFM_PMOPS ,
252
+ .pm = & sdhci_at91_dev_pm_ops ,
182
253
},
183
254
.probe = sdhci_at91_probe ,
184
255
.remove = sdhci_at91_remove ,
0 commit comments