diff mbox

mmc: sdio: add wakeup event for suspend/resume

Message ID 1359113606-3011-1-git-send-email-kliu5@marvell.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kevin Liu Jan. 25, 2013, 11:33 a.m. UTC
If sdio host can wakeup system, interrupts will _NOT_ be disabled
and sdio card interrupt may happen during whole suspend/resume process.
Then 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 <kliu5@marvell.com>
---
 drivers/mmc/core/sdio.c       |    4 ++++
 drivers/mmc/core/sdio_irq.c   |   19 +++++++++++++++++++
 include/linux/mmc/sdio_func.h |    6 ++++++
 3 files changed, 29 insertions(+)
diff mbox

Patch

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..0f204dd 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -28,6 +28,15 @@ 
 
 #include "sdio_ops.h"
 
+static void mmc_sdio_irq_wakeup(struct mmc_host *host)
+{
+	int sec = 3;
+
+	pr_info("%s: hold %d seconds to prevent suspend\n",
+			mmc_hostname(host), sec);
+	pm_wakeup_event(mmc_dev(host), 1000 * sec);
+}
+
 static int process_sdio_pending_irqs(struct mmc_host *host)
 {
 	struct mmc_card *card = host->card;
@@ -42,6 +51,11 @@  static int process_sdio_pending_irqs(struct mmc_host *host)
 	 */
 	func = card->sdio_single_irq;
 	if (func && host->sdio_irq_pending) {
+		if (mmc_card_keep_power(host) &&
+			mmc_card_wake_sdio_irq(host) &&
+			(func->func_status == FUNC_SUSPENDED)) {
+			mmc_sdio_irq_wakeup(host);
+		}
 		func->irq_handler(func);
 		return 1;
 	}
@@ -63,6 +77,11 @@  static int process_sdio_pending_irqs(struct mmc_host *host)
 					mmc_card_id(card));
 				ret = -EINVAL;
 			} else if (func->irq_handler) {
+				if (mmc_card_keep_power(host) &&
+					mmc_card_wake_sdio_irq(host) &&
+					(func->func_status == FUNC_SUSPENDED)) {
+					mmc_sdio_irq_wakeup(host);
+				}
 				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)