summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorTodd Poynor <toddpoynor@google.com>2012-08-07 17:14:52 -0700
committerVarun Wadekar <vwadekar@nvidia.com>2012-08-13 14:13:20 +0530
commit564e6b431e9696d6b7186d120d563a74ae290092 (patch)
tree4ed05fbc23e72e57575dcc53ca551f5b4f94098a /kernel
parent559be66522421d65e323a2fae1016d968c1b9d12 (diff)
alarmtimer: implement minimum alarm interval for allowing suspend
alarmtimer suspend return -EBUSY if the next alarm will fire in less than 2 seconds. This allows one RTC seconds tick to occur subsequent to this check before the alarm wakeup time is set, ensuring the wakeup time is still in the future (assuming the RTC does not tick one more second prior to setting the alarm). If suspend is rejected, hold a wakeup source for 2 seconds to process the alarm prior to reattempting suspend. Change-Id: If38e2568da0ea01dfee6e00323ce7e2c00f2f110 Signed-off-by: Todd Poynor <toddpoynor@google.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/alarmtimer.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 01a0f5ff1990..0c079010527f 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -46,6 +46,8 @@ static struct alarm_base {
static ktime_t freezer_delta;
static DEFINE_SPINLOCK(freezer_delta_lock);
+static struct wakeup_source *ws;
+
#ifdef CONFIG_RTC_CLASS
/* rtc timer and device for setting alarm wakeups at suspend */
static struct rtc_timer rtctimer;
@@ -246,6 +248,7 @@ static int alarmtimer_suspend(struct device *dev)
unsigned long flags;
struct rtc_device *rtc;
int i;
+ int ret;
spin_lock_irqsave(&freezer_delta_lock, flags);
min = freezer_delta;
@@ -275,8 +278,10 @@ static int alarmtimer_suspend(struct device *dev)
if (min.tv64 == 0)
return 0;
- /* XXX - Should we enforce a minimum sleep time? */
- WARN_ON(min.tv64 < NSEC_PER_SEC);
+ if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
+ __pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
+ return -EBUSY;
+ }
/* Setup an rtc timer to fire that far in the future */
rtc_timer_cancel(rtc, &rtctimer);
@@ -284,9 +289,11 @@ static int alarmtimer_suspend(struct device *dev)
now = rtc_tm_to_ktime(tm);
now = ktime_add(now, min);
- rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
-
- return 0;
+ /* Set alarm, if in the past reject suspend briefly to handle */
+ ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
+ if (ret < 0)
+ __pm_wakeup_event(ws, 1 * MSEC_PER_SEC);
+ return ret;
}
#else
static int alarmtimer_suspend(struct device *dev)
@@ -817,6 +824,7 @@ static int __init alarmtimer_init(void)
error = PTR_ERR(pdev);
goto out_drv;
}
+ ws = wakeup_source_register("alarmtimer");
return 0;
out_drv: