diff options
author | ludovic.desroches@atmel.com <ludovic.desroches@atmel.com> | 2015-11-11 13:11:48 -0500 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2015-12-22 05:32:06 -0500 |
commit | f5f17813ae9b80fc8458281014c308e5121e0a4e (patch) | |
tree | cca7c0fb8b78d0ffd3823b83c9bc725bf4bf3ef1 /drivers/mmc | |
parent | 28ff4fda9e5b4917375a49a3c6f76aed0cdd55ae (diff) |
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>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/sdhci-of-at91.c | 75 |
1 files changed, 73 insertions, 2 deletions
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 06d0b50dfe71..7e7d8f0c9438 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/of.h> | 22 | #include <linux/of.h> |
23 | #include <linux/of_device.h> | 23 | #include <linux/of_device.h> |
24 | #include <linux/pm.h> | ||
25 | #include <linux/pm_runtime.h> | ||
24 | 26 | ||
25 | #include "sdhci-pltfm.h" | 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 | static int sdhci_at91_probe(struct platform_device *pdev) | 110 | static int sdhci_at91_probe(struct platform_device *pdev) |
55 | { | 111 | { |
56 | const struct of_device_id *match; | 112 | const struct of_device_id *match; |
@@ -144,12 +200,23 @@ static int sdhci_at91_probe(struct platform_device *pdev) | |||
144 | 200 | ||
145 | sdhci_get_of_property(pdev); | 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 | ret = sdhci_add_host(host); | 209 | ret = sdhci_add_host(host); |
148 | if (ret) | 210 | if (ret) |
149 | goto clocks_disable_unprepare; | 211 | goto pm_runtime_disable; |
212 | |||
213 | pm_runtime_put_autosuspend(&pdev->dev); | ||
150 | 214 | ||
151 | return 0; | 215 | return 0; |
152 | 216 | ||
217 | pm_runtime_disable: | ||
218 | pm_runtime_disable(&pdev->dev); | ||
219 | pm_runtime_set_suspended(&pdev->dev); | ||
153 | clocks_disable_unprepare: | 220 | clocks_disable_unprepare: |
154 | clk_disable_unprepare(priv->gck); | 221 | clk_disable_unprepare(priv->gck); |
155 | clk_disable_unprepare(priv->mainck); | 222 | clk_disable_unprepare(priv->mainck); |
@@ -165,6 +232,10 @@ static int sdhci_at91_remove(struct platform_device *pdev) | |||
165 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 232 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
166 | struct sdhci_at91_priv *priv = pltfm_host->priv; | 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 | sdhci_pltfm_unregister(pdev); | 239 | sdhci_pltfm_unregister(pdev); |
169 | 240 | ||
170 | clk_disable_unprepare(priv->gck); | 241 | clk_disable_unprepare(priv->gck); |
@@ -178,7 +249,7 @@ static struct platform_driver sdhci_at91_driver = { | |||
178 | .driver = { | 249 | .driver = { |
179 | .name = "sdhci-at91", | 250 | .name = "sdhci-at91", |
180 | .of_match_table = sdhci_at91_dt_match, | 251 | .of_match_table = sdhci_at91_dt_match, |
181 | .pm = SDHCI_PLTFM_PMOPS, | 252 | .pm = &sdhci_at91_dev_pm_ops, |
182 | }, | 253 | }, |
183 | .probe = sdhci_at91_probe, | 254 | .probe = sdhci_at91_probe, |
184 | .remove = sdhci_at91_remove, | 255 | .remove = sdhci_at91_remove, |