aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time
diff options
context:
space:
mode:
authorTodd Poynor <toddpoynor@google.com>2012-08-09 03:37:27 -0400
committerJohn Stultz <john.stultz@linaro.org>2012-09-24 12:38:01 -0400
commit59a93c27c4892f04dfd8f91f8b64d0d6eae43e6e (patch)
treefcdf1189ed72a2ffaafb4a36b8224edea0ea0f56 /kernel/time
parentec145babe754f9ea1079034a108104b6001e001c (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 due to an imminent alarm, hold a wakeup source for 2 seconds to process the alarm prior to reattempting suspend. If setting the alarm incurs an -ETIME for an alarm set in the past, or any other problem setting the alarm, abort suspend and hold a wakelock for 1 second while the alarm is allowed to be serviced or other hopefully transient conditions preventing the alarm clear up. Signed-off-by: Todd Poynor <toddpoynor@google.com> Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'kernel/time')
-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 aa27d391bfc8..54e7145c5414 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -46,6 +46,8 @@ static struct alarm_base {
46static ktime_t freezer_delta; 46static ktime_t freezer_delta;
47static DEFINE_SPINLOCK(freezer_delta_lock); 47static DEFINE_SPINLOCK(freezer_delta_lock);
48 48
49static struct wakeup_source *ws;
50
49#ifdef CONFIG_RTC_CLASS 51#ifdef CONFIG_RTC_CLASS
50/* rtc timer and device for setting alarm wakeups at suspend */ 52/* rtc timer and device for setting alarm wakeups at suspend */
51static struct rtc_timer rtctimer; 53static struct rtc_timer rtctimer;
@@ -250,6 +252,7 @@ static int alarmtimer_suspend(struct device *dev)
250 unsigned long flags; 252 unsigned long flags;
251 struct rtc_device *rtc; 253 struct rtc_device *rtc;
252 int i; 254 int i;
255 int ret;
253 256
254 spin_lock_irqsave(&freezer_delta_lock, flags); 257 spin_lock_irqsave(&freezer_delta_lock, flags);
255 min = freezer_delta; 258 min = freezer_delta;
@@ -279,8 +282,10 @@ static int alarmtimer_suspend(struct device *dev)
279 if (min.tv64 == 0) 282 if (min.tv64 == 0)
280 return 0; 283 return 0;
281 284
282 /* XXX - Should we enforce a minimum sleep time? */ 285 if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
283 WARN_ON(min.tv64 < NSEC_PER_SEC); 286 __pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
287 return -EBUSY;
288 }
284 289
285 /* Setup an rtc timer to fire that far in the future */ 290 /* Setup an rtc timer to fire that far in the future */
286 rtc_timer_cancel(rtc, &rtctimer); 291 rtc_timer_cancel(rtc, &rtctimer);
@@ -288,9 +293,11 @@ static int alarmtimer_suspend(struct device *dev)
288 now = rtc_tm_to_ktime(tm); 293 now = rtc_tm_to_ktime(tm);
289 now = ktime_add(now, min); 294 now = ktime_add(now, min);
290 295
291 rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); 296 /* Set alarm, if in the past reject suspend briefly to handle */
292 297 ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
293 return 0; 298 if (ret < 0)
299 __pm_wakeup_event(ws, MSEC_PER_SEC);
300 return ret;
294} 301}
295#else 302#else
296static int alarmtimer_suspend(struct device *dev) 303static int alarmtimer_suspend(struct device *dev)
@@ -821,6 +828,7 @@ static int __init alarmtimer_init(void)
821 error = PTR_ERR(pdev); 828 error = PTR_ERR(pdev);
822 goto out_drv; 829 goto out_drv;
823 } 830 }
831 ws = wakeup_source_register("alarmtimer");
824 return 0; 832 return 0;
825 833
826out_drv: 834out_drv: