If sdio can wakeup host, the card interrupts received after suspend
while before resume back should be regard as wakeup event. So set
a wakeup event at that point. All sdio functions should set the
wakeup event individually according to its suspending status.

Signed-off-by: Kevin Liu <kl...@marvell.com>
---
 drivers/mmc/core/sdio.c       |    4 ++++
 drivers/mmc/core/sdio_irq.c   |   12 ++++++++++++
 include/linux/mmc/sdio_func.h |    6 ++++++
 3 files changed, 22 insertions(+)

diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 3a64933..06675cb 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -904,6 +904,8 @@ static int mmc_sdio_suspend(struct mmc_host *host)
                                err = pmops->suspend(&func->dev);
                        if (err)
                                break;
+                       else
+                               func->func_status = FUNC_SUSPENDED;
                }
        }
        while (err && --i >= 0) {
@@ -911,6 +913,7 @@ static int mmc_sdio_suspend(struct mmc_host *host)
                if (func && sdio_func_present(func) && func->dev.driver) {
                        const struct dev_pm_ops *pmops = func->dev.driver->pm;
                        pmops->resume(&func->dev);
+                       func->func_status = FUNC_RESUMED;
                }
        }
 
@@ -967,6 +970,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
                if (func && sdio_func_present(func) && func->dev.driver) {
                        const struct dev_pm_ops *pmops = func->dev.driver->pm;
                        err = pmops->resume(&func->dev);
+                       func->func_status = FUNC_RESUMED;
                }
        }
 
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 3d8ceb4..3bae8aa 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -28,6 +28,14 @@
 
 #include "sdio_ops.h"
 
+static inline bool sdio_irq_wakeup(struct sdio_func *func)
+{
+       struct mmc_host *host = func->card->host;
+
+       return mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)
+               && func->func_status == FUNC_SUSPENDED;
+}
+
 static int process_sdio_pending_irqs(struct mmc_host *host)
 {
        struct mmc_card *card = host->card;
@@ -42,6 +50,8 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
         */
        func = card->sdio_single_irq;
        if (func && host->sdio_irq_pending) {
+               if (sdio_irq_wakeup(func))
+                       pm_wakeup_event(mmc_dev(host), 0);
                func->irq_handler(func);
                return 1;
        }
@@ -63,6 +73,8 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
                                        mmc_card_id(card));
                                ret = -EINVAL;
                        } else if (func->irq_handler) {
+                               if (sdio_irq_wakeup(func))
+                                       pm_wakeup_event(mmc_dev(host), 0);
                                func->irq_handler(func);
                                count++;
                        } else {
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
index 50f0bc9..59f4c23 100644
--- a/include/linux/mmc/sdio_func.h
+++ b/include/linux/mmc/sdio_func.h
@@ -32,6 +32,11 @@ struct sdio_func_tuple {
        unsigned char data[0];
 };
 
+enum sdio_func_status {
+       FUNC_RESUMED = 0,       /* default value */
+       FUNC_SUSPENDED,
+};
+
 /*
  * SDIO function devices
  */
@@ -59,6 +64,7 @@ struct sdio_func {
        const char              **info;         /* info strings */
 
        struct sdio_func_tuple *tuples;
+       enum sdio_func_status   func_status;    /* SDIO function driver state */
 };
 
 #define sdio_func_present(f)   ((f)->state & SDIO_STATE_PRESENT)
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to