diff options
Diffstat (limited to 'drivers/net/wireless/wl1251')
-rw-r--r-- | drivers/net/wireless/wl1251/sdio.c | 64 |
1 files changed, 61 insertions, 3 deletions
diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index 02851901677e..f3e185efe124 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/wl12xx.h> | 27 | #include <linux/wl12xx.h> |
28 | #include <linux/irq.h> | 28 | #include <linux/irq.h> |
29 | #include <linux/pm_runtime.h> | ||
29 | 30 | ||
30 | #include "wl1251.h" | 31 | #include "wl1251.h" |
31 | 32 | ||
@@ -173,10 +174,40 @@ static void wl1251_disable_line_irq(struct wl1251 *wl) | |||
173 | 174 | ||
174 | static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) | 175 | static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) |
175 | { | 176 | { |
176 | if (wl->set_power) | 177 | struct sdio_func *func = wl_to_func(wl); |
177 | wl->set_power(enable); | 178 | int ret; |
178 | 179 | ||
179 | return 0; | 180 | if (enable) { |
181 | /* | ||
182 | * Power is controlled by runtime PM, but we still call board | ||
183 | * callback in case it wants to do any additional setup, | ||
184 | * for example enabling clock buffer for the module. | ||
185 | */ | ||
186 | if (wl->set_power) | ||
187 | wl->set_power(true); | ||
188 | |||
189 | ret = pm_runtime_get_sync(&func->dev); | ||
190 | if (ret < 0) | ||
191 | goto out; | ||
192 | |||
193 | sdio_claim_host(func); | ||
194 | sdio_enable_func(func); | ||
195 | sdio_release_host(func); | ||
196 | } else { | ||
197 | sdio_claim_host(func); | ||
198 | sdio_disable_func(func); | ||
199 | sdio_release_host(func); | ||
200 | |||
201 | ret = pm_runtime_put_sync(&func->dev); | ||
202 | if (ret < 0) | ||
203 | goto out; | ||
204 | |||
205 | if (wl->set_power) | ||
206 | wl->set_power(false); | ||
207 | } | ||
208 | |||
209 | out: | ||
210 | return ret; | ||
180 | } | 211 | } |
181 | 212 | ||
182 | static struct wl1251_if_operations wl1251_sdio_ops = { | 213 | static struct wl1251_if_operations wl1251_sdio_ops = { |
@@ -277,6 +308,10 @@ static int wl1251_sdio_probe(struct sdio_func *func, | |||
277 | goto out_free_irq; | 308 | goto out_free_irq; |
278 | 309 | ||
279 | sdio_set_drvdata(func, wl); | 310 | sdio_set_drvdata(func, wl); |
311 | |||
312 | /* Tell PM core that we don't need the card to be powered now */ | ||
313 | pm_runtime_put_noidle(&func->dev); | ||
314 | |||
280 | return ret; | 315 | return ret; |
281 | 316 | ||
282 | out_free_irq: | 317 | out_free_irq: |
@@ -298,6 +333,9 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func) | |||
298 | struct wl1251 *wl = sdio_get_drvdata(func); | 333 | struct wl1251 *wl = sdio_get_drvdata(func); |
299 | struct wl1251_sdio *wl_sdio = wl->if_priv; | 334 | struct wl1251_sdio *wl_sdio = wl->if_priv; |
300 | 335 | ||
336 | /* Undo decrement done above in wl1251_probe */ | ||
337 | pm_runtime_get_noresume(&func->dev); | ||
338 | |||
301 | if (wl->irq) | 339 | if (wl->irq) |
302 | free_irq(wl->irq, wl); | 340 | free_irq(wl->irq, wl); |
303 | kfree(wl_sdio); | 341 | kfree(wl_sdio); |
@@ -309,11 +347,31 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func) | |||
309 | sdio_release_host(func); | 347 | sdio_release_host(func); |
310 | } | 348 | } |
311 | 349 | ||
350 | static int wl1251_suspend(struct device *dev) | ||
351 | { | ||
352 | /* | ||
353 | * Tell MMC/SDIO core it's OK to power down the card | ||
354 | * (if it isn't already), but not to remove it completely. | ||
355 | */ | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int wl1251_resume(struct device *dev) | ||
360 | { | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static const struct dev_pm_ops wl1251_sdio_pm_ops = { | ||
365 | .suspend = wl1251_suspend, | ||
366 | .resume = wl1251_resume, | ||
367 | }; | ||
368 | |||
312 | static struct sdio_driver wl1251_sdio_driver = { | 369 | static struct sdio_driver wl1251_sdio_driver = { |
313 | .name = "wl1251_sdio", | 370 | .name = "wl1251_sdio", |
314 | .id_table = wl1251_devices, | 371 | .id_table = wl1251_devices, |
315 | .probe = wl1251_sdio_probe, | 372 | .probe = wl1251_sdio_probe, |
316 | .remove = __devexit_p(wl1251_sdio_remove), | 373 | .remove = __devexit_p(wl1251_sdio_remove), |
374 | .drv.pm = &wl1251_sdio_pm_ops, | ||
317 | }; | 375 | }; |
318 | 376 | ||
319 | static int __init wl1251_sdio_init(void) | 377 | static int __init wl1251_sdio_init(void) |