Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
[linux-2.6-block.git] / drivers / bluetooth / btmrvl_sdio.c
index 08e01f002bad215c7dc5929ea1a2cf7e42f4a820..eb794f08b2385bfcb2162531cee4fbaa62c818fd 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/suspend.h>
 
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio_func.h>
@@ -60,13 +61,15 @@ static const struct of_device_id btmrvl_sdio_of_match_table[] = {
 
 static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
 {
-       struct btmrvl_plt_wake_cfg *cfg = priv;
+       struct btmrvl_sdio_card *card = priv;
+       struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg;
 
-       if (cfg->irq_bt >= 0) {
-               pr_info("%s: wake by bt", __func__);
-               cfg->wake_by_bt = true;
-               disable_irq_nosync(irq);
-       }
+       pr_info("%s: wake by bt", __func__);
+       cfg->wake_by_bt = true;
+       disable_irq_nosync(irq);
+
+       pm_wakeup_event(&card->func->dev, 0);
+       pm_system_wakeup();
 
        return IRQ_HANDLED;
 }
@@ -101,7 +104,7 @@ static int btmrvl_sdio_probe_of(struct device *dev,
                } else {
                        ret = devm_request_irq(dev, cfg->irq_bt,
                                               btmrvl_wake_irq_bt,
-                                              0, "bt_wake", cfg);
+                                              0, "bt_wake", card);
                        if (ret) {
                                dev_err(dev,
                                        "Failed to request irq_bt %d (%d)\n",
@@ -1574,7 +1577,7 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
                                                        MODULE_SHUTDOWN_REQ);
                                btmrvl_sdio_disable_host_int(card);
                        }
-                       BT_DBG("unregester dev");
+                       BT_DBG("unregister dev");
                        card->priv->surprise_removed = true;
                        btmrvl_sdio_unregister_dev(card);
                        btmrvl_remove_card(card->priv);
@@ -1625,6 +1628,13 @@ static int btmrvl_sdio_suspend(struct device *dev)
        if (priv->adapter->hs_state != HS_ACTIVATED) {
                if (btmrvl_enable_hs(priv)) {
                        BT_ERR("HS not activated, suspend failed!");
+                       /* Disable platform specific wakeup interrupt */
+                       if (card->plt_wake_cfg &&
+                           card->plt_wake_cfg->irq_bt >= 0) {
+                               disable_irq_wake(card->plt_wake_cfg->irq_bt);
+                               disable_irq(card->plt_wake_cfg->irq_bt);
+                       }
+
                        priv->adapter->is_suspending = false;
                        return -EBUSY;
                }
@@ -1637,10 +1647,10 @@ static int btmrvl_sdio_suspend(struct device *dev)
        if (priv->adapter->hs_state == HS_ACTIVATED) {
                BT_DBG("suspend with MMC_PM_KEEP_POWER");
                return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
-       } else {
-               BT_DBG("suspend without MMC_PM_KEEP_POWER");
-               return 0;
        }
+
+       BT_DBG("suspend without MMC_PM_KEEP_POWER");
+       return 0;
 }
 
 static int btmrvl_sdio_resume(struct device *dev)