aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2013-09-20 05:02:35 -0400
committerChris Ball <cjb@laptop.org>2013-10-30 20:26:32 -0400
commitbbd43682eb12dab2ff4addfca04c32043dfde026 (patch)
treecace4f8790b8b2d007ab6ceaab1e74f83a2cb0d0
parent726d6f2374410d980341bfeb49399614e689e702 (diff)
mmc: core: Signal wakeup event at card insert/removal
We want to give user space provision to fully consume a card insert/remove event, when the event was caused by a wakeup irq. By signaling the wakeup event for a time of 5 s for devices configured as wakeup capable, we likely will be prevent a sleep long enough to let user space consume the event. To enable this feature, host drivers must thus configure their devices as wakeup capable. This is a reworked implementation of the old wakelocks for the mmc subsystem, originally authored by Colin Cross and San Mehat for the Android kernel. Zoran Markovic shall also be given cred for recently re-trying to upstream this feature. Cc: San Mehat <san@google.com> Cc: Colin Cross <ccross@android.com> Cc: John Stultz <john.stultz@linaro.org> Cc: Zoran Markovic <zoran.markovic@linaro.org> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Zoran Markovic <zoran.markovic@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/core/core.c39
1 files changed, 27 insertions, 12 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index bcb507771eeb..49dfafa99cc1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -23,6 +23,7 @@
23#include <linux/log2.h> 23#include <linux/log2.h>
24#include <linux/regulator/consumer.h> 24#include <linux/regulator/consumer.h>
25#include <linux/pm_runtime.h> 25#include <linux/pm_runtime.h>
26#include <linux/pm_wakeup.h>
26#include <linux/suspend.h> 27#include <linux/suspend.h>
27#include <linux/fault-inject.h> 28#include <linux/fault-inject.h>
28#include <linux/random.h> 29#include <linux/random.h>
@@ -1692,6 +1693,28 @@ void mmc_detach_bus(struct mmc_host *host)
1692 mmc_bus_put(host); 1693 mmc_bus_put(host);
1693} 1694}
1694 1695
1696static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
1697 bool cd_irq)
1698{
1699#ifdef CONFIG_MMC_DEBUG
1700 unsigned long flags;
1701 spin_lock_irqsave(&host->lock, flags);
1702 WARN_ON(host->removed);
1703 spin_unlock_irqrestore(&host->lock, flags);
1704#endif
1705
1706 /*
1707 * If the device is configured as wakeup, we prevent a new sleep for
1708 * 5 s to give provision for user space to consume the event.
1709 */
1710 if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
1711 device_can_wakeup(mmc_dev(host)))
1712 pm_wakeup_event(mmc_dev(host), 5000);
1713
1714 host->detect_change = 1;
1715 mmc_schedule_delayed_work(&host->detect, delay);
1716}
1717
1695/** 1718/**
1696 * mmc_detect_change - process change of state on a MMC socket 1719 * mmc_detect_change - process change of state on a MMC socket
1697 * @host: host which changed state. 1720 * @host: host which changed state.
@@ -1704,16 +1727,8 @@ void mmc_detach_bus(struct mmc_host *host)
1704 */ 1727 */
1705void mmc_detect_change(struct mmc_host *host, unsigned long delay) 1728void mmc_detect_change(struct mmc_host *host, unsigned long delay)
1706{ 1729{
1707#ifdef CONFIG_MMC_DEBUG 1730 _mmc_detect_change(host, delay, true);
1708 unsigned long flags;
1709 spin_lock_irqsave(&host->lock, flags);
1710 WARN_ON(host->removed);
1711 spin_unlock_irqrestore(&host->lock, flags);
1712#endif
1713 host->detect_change = 1;
1714 mmc_schedule_delayed_work(&host->detect, delay);
1715} 1731}
1716
1717EXPORT_SYMBOL(mmc_detect_change); 1732EXPORT_SYMBOL(mmc_detect_change);
1718 1733
1719void mmc_init_erase(struct mmc_card *card) 1734void mmc_init_erase(struct mmc_card *card)
@@ -2392,7 +2407,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
2392 * rescan handle the card removal. 2407 * rescan handle the card removal.
2393 */ 2408 */
2394 cancel_delayed_work(&host->detect); 2409 cancel_delayed_work(&host->detect);
2395 mmc_detect_change(host, 0); 2410 _mmc_detect_change(host, 0, false);
2396 } 2411 }
2397 } 2412 }
2398 2413
@@ -2474,7 +2489,7 @@ void mmc_start_host(struct mmc_host *host)
2474 mmc_power_off(host); 2489 mmc_power_off(host);
2475 else 2490 else
2476 mmc_power_up(host, host->ocr_avail); 2491 mmc_power_up(host, host->ocr_avail);
2477 mmc_detect_change(host, 0); 2492 _mmc_detect_change(host, 0, false);
2478} 2493}
2479 2494
2480void mmc_stop_host(struct mmc_host *host) 2495void mmc_stop_host(struct mmc_host *host)
@@ -2693,7 +2708,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
2693 spin_lock_irqsave(&host->lock, flags); 2708 spin_lock_irqsave(&host->lock, flags);
2694 host->rescan_disable = 0; 2709 host->rescan_disable = 0;
2695 spin_unlock_irqrestore(&host->lock, flags); 2710 spin_unlock_irqrestore(&host->lock, flags);
2696 mmc_detect_change(host, 0); 2711 _mmc_detect_change(host, 0, false);
2697 2712
2698 } 2713 }
2699 2714