|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/wl12xx.h>
|
|
|
#include <linux/irq.h>
|
|
|
+#include <linux/pm_runtime.h>
|
|
|
|
|
|
#include "wl1251.h"
|
|
|
|
|
@@ -173,10 +174,40 @@ static void wl1251_disable_line_irq(struct wl1251 *wl)
|
|
|
|
|
|
static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
|
|
|
{
|
|
|
- if (wl->set_power)
|
|
|
- wl->set_power(enable);
|
|
|
+ struct sdio_func *func = wl_to_func(wl);
|
|
|
+ int ret;
|
|
|
|
|
|
- return 0;
|
|
|
+ if (enable) {
|
|
|
+ /*
|
|
|
+ * Power is controlled by runtime PM, but we still call board
|
|
|
+ * callback in case it wants to do any additional setup,
|
|
|
+ * for example enabling clock buffer for the module.
|
|
|
+ */
|
|
|
+ if (wl->set_power)
|
|
|
+ wl->set_power(true);
|
|
|
+
|
|
|
+ ret = pm_runtime_get_sync(&func->dev);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ sdio_claim_host(func);
|
|
|
+ sdio_enable_func(func);
|
|
|
+ sdio_release_host(func);
|
|
|
+ } else {
|
|
|
+ sdio_claim_host(func);
|
|
|
+ sdio_disable_func(func);
|
|
|
+ sdio_release_host(func);
|
|
|
+
|
|
|
+ ret = pm_runtime_put_sync(&func->dev);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (wl->set_power)
|
|
|
+ wl->set_power(false);
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static struct wl1251_if_operations wl1251_sdio_ops = {
|
|
@@ -277,6 +308,10 @@ static int wl1251_sdio_probe(struct sdio_func *func,
|
|
|
goto out_free_irq;
|
|
|
|
|
|
sdio_set_drvdata(func, wl);
|
|
|
+
|
|
|
+ /* Tell PM core that we don't need the card to be powered now */
|
|
|
+ pm_runtime_put_noidle(&func->dev);
|
|
|
+
|
|
|
return ret;
|
|
|
|
|
|
out_free_irq:
|
|
@@ -298,6 +333,9 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
|
|
|
struct wl1251 *wl = sdio_get_drvdata(func);
|
|
|
struct wl1251_sdio *wl_sdio = wl->if_priv;
|
|
|
|
|
|
+ /* Undo decrement done above in wl1251_probe */
|
|
|
+ pm_runtime_get_noresume(&func->dev);
|
|
|
+
|
|
|
if (wl->irq)
|
|
|
free_irq(wl->irq, wl);
|
|
|
kfree(wl_sdio);
|
|
@@ -309,11 +347,31 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
|
|
|
sdio_release_host(func);
|
|
|
}
|
|
|
|
|
|
+static int wl1251_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Tell MMC/SDIO core it's OK to power down the card
|
|
|
+ * (if it isn't already), but not to remove it completely.
|
|
|
+ */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int wl1251_resume(struct device *dev)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct dev_pm_ops wl1251_sdio_pm_ops = {
|
|
|
+ .suspend = wl1251_suspend,
|
|
|
+ .resume = wl1251_resume,
|
|
|
+};
|
|
|
+
|
|
|
static struct sdio_driver wl1251_sdio_driver = {
|
|
|
.name = "wl1251_sdio",
|
|
|
.id_table = wl1251_devices,
|
|
|
.probe = wl1251_sdio_probe,
|
|
|
.remove = __devexit_p(wl1251_sdio_remove),
|
|
|
+ .drv.pm = &wl1251_sdio_pm_ops,
|
|
|
};
|
|
|
|
|
|
static int __init wl1251_sdio_init(void)
|