diff mbox

mmc: Enable wakeup_sources for mmc core

Message ID 1340411570-63361-1-git-send-email-john.stultz@linaro.org
State Superseded
Headers show

Commit Message

John Stultz June 23, 2012, 12:32 a.m. UTC
Hey San, Colin, 
	I just wanted to send this your way for comment
before possibly sending it to the mmc maintainer & lkml.

Let me know if you have any objections.

thanks
-john


This is a reworked implementation using wakeup_sources
of two patches by San Mehat and Colin Cross that enabled
wakelocks for the mmc core.

CC: San Mehat <san@google.com>
CC: Colin Cross <ccross@android.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
---
 drivers/mmc/core/core.c  |   26 +++++++++++++++++++++-----
 drivers/mmc/core/host.c  |    4 ++++
 include/linux/mmc/host.h |    2 ++
 3 files changed, 27 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 0b6141d..6e86f3d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -26,6 +26,7 @@ 
 #include <linux/suspend.h>
 #include <linux/fault-inject.h>
 #include <linux/random.h>
+#include <linux/pm_wakeup.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -1358,6 +1359,8 @@  void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 	spin_unlock_irqrestore(&host->lock, flags);
 #endif
 	host->detect_change = 1;
+
+	__pm_stay_awake(&host->detect_wakeup_source);
 	mmc_schedule_delayed_work(&host->detect, delay);
 }
 
@@ -2016,6 +2019,7 @@  void mmc_rescan(struct work_struct *work)
 	struct mmc_host *host =
 		container_of(work, struct mmc_host, detect.work);
 	int i;
+	bool extend_wakeup = false;
 
 	if (host->rescan_disable)
 		return;
@@ -2060,16 +2064,25 @@  void mmc_rescan(struct work_struct *work)
 
 	mmc_claim_host(host);
 	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
-		if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
+		if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
+			extend_wakeup = true;
 			break;
+		}
 		if (freqs[i] <= host->f_min)
 			break;
 	}
 	mmc_release_host(host);
 
  out:
-	if (host->caps & MMC_CAP_NEEDS_POLL)
+	if (extend_wakeup)
+		__pm_wakeup_event(&host->detect_wakeup_source, 500);
+	else
+		__pm_relax(&host->detect_wakeup_source);
+
+	if (host->caps & MMC_CAP_NEEDS_POLL) {
+		__pm_stay_awake(&host->detect_wakeup_source);
 		mmc_schedule_delayed_work(&host->detect, HZ);
+	}
 }
 
 void mmc_start_host(struct mmc_host *host)
@@ -2088,7 +2101,8 @@  void mmc_stop_host(struct mmc_host *host)
 	spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
-	cancel_delayed_work_sync(&host->detect);
+	if (cancel_delayed_work_sync(&host->detect))
+		__pm_relax(&host->detect_wakeup_source);
 	mmc_flush_scheduled_work();
 
 	/* clear pm flags now and let card drivers set them as needed */
@@ -2284,7 +2298,8 @@  int mmc_suspend_host(struct mmc_host *host)
 {
 	int err = 0;
 
-	cancel_delayed_work(&host->detect);
+	if (cancel_delayed_work(&host->detect))
+		__pm_relax(&host->detect_wakeup_source);
 	mmc_flush_scheduled_work();
 
 	err = mmc_cache_ctrl(host, 0);
@@ -2387,7 +2402,8 @@  int mmc_pm_notify(struct notifier_block *notify_block,
 		host->rescan_disable = 1;
 		host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
 		spin_unlock_irqrestore(&host->lock, flags);
-		cancel_delayed_work_sync(&host->detect);
+		if (cancel_delayed_work_sync(&host->detect))
+			__pm_relax(&host->detect_wakeup_source);
 
 		if (!host->bus_ops || host->bus_ops->suspend)
 			break;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 91c84c7..3117d35 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -329,6 +329,9 @@  struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 
 	spin_lock_init(&host->lock);
 	init_waitqueue_head(&host->wq);
+	wakeup_source_init(&host->detect_wakeup_source,
+				kasprintf(GFP_KERNEL, "%s_detect",
+						mmc_hostname(host)));
 	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
 #ifdef CONFIG_PM
 	host->pm_notify.notifier_call = mmc_pm_notify;
@@ -425,6 +428,7 @@  void mmc_free_host(struct mmc_host *host)
 	spin_lock(&mmc_host_lock);
 	idr_remove(&mmc_host_idr, host->index);
 	spin_unlock(&mmc_host_lock);
+	wakeup_source_trash(&host->detect_wakeup_source);
 
 	put_device(&host->class_dev);
 }
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 0707d22..a3c75d8 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -14,6 +14,7 @@ 
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/fault-inject.h>
+#include <linux/pm_wakeup.h>
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/pm.h>
@@ -289,6 +290,7 @@  struct mmc_host {
 	int			claim_cnt;	/* "claim" nesting count */
 
 	struct delayed_work	detect;
+	struct wakeup_source	detect_wakeup_source;
 	int			detect_change;	/* card detect flag */
 	struct mmc_hotplug	hotplug;