aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl1251
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/wl1251')
-rw-r--r--drivers/net/wireless/wl1251/sdio.c64
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
174static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) 175static 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
209out:
210 return ret;
180} 211}
181 212
182static struct wl1251_if_operations wl1251_sdio_ops = { 213static 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
282out_free_irq: 317out_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
350static 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
359static int wl1251_resume(struct device *dev)
360{
361 return 0;
362}
363
364static const struct dev_pm_ops wl1251_sdio_pm_ops = {
365 .suspend = wl1251_suspend,
366 .resume = wl1251_resume,
367};
368
312static struct sdio_driver wl1251_sdio_driver = { 369static 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
319static int __init wl1251_sdio_init(void) 377static int __init wl1251_sdio_init(void)