summaryrefslogtreecommitdiff
path: root/kernel/time/alarmtimer.c
diff options
context:
space:
mode:
authorMohit Aggarwal <maggarwa@codeaurora.org>2015-01-06 13:03:49 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 21:23:46 -0700
commit4b81b05c57d2501abbb5a07599ec6fabe011994a (patch)
tree9cb557e629f5e747d8a25213bd40e3171fdfc865 /kernel/time/alarmtimer.c
parentb01a9ad44f5e560948b611b7c9705a8bd34edc71 (diff)
rtc: alarm: Change wake-up source
Currently, RTC_ALARM is used to wake-up target from suspend state and is also used for power-off alarm feature. This patch uses qtimer to wake-up from suspend state. Change-Id: Ia42cfecd573309be2f03c18b4f1c321be8202d7d Signed-off-by: Mohit Aggarwal <maggarwa@codeaurora.org>
Diffstat (limited to 'kernel/time/alarmtimer.c')
-rw-r--r--kernel/time/alarmtimer.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index babb8b28f66f..fde72e7d6e67 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -25,6 +25,7 @@
#include <linux/posix-timers.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
+#include "lpm-levels.h"
#include <linux/workqueue.h>
/**
@@ -359,6 +360,70 @@ EXPORT_SYMBOL_GPL(alarm_expires_remaining);
* set an rtc timer to fire that far into the future, which
* will wake us from suspend.
*/
+#if defined(CONFIG_RTC_DRV_QPNP) && defined(CONFIG_MSM_PM)
+static int alarmtimer_suspend(struct device *dev)
+{
+ struct rtc_time tm;
+ ktime_t min, now;
+ unsigned long flags;
+ struct rtc_device *rtc;
+ int i;
+ int ret = 0;
+
+ spin_lock_irqsave(&freezer_delta_lock, flags);
+ min = freezer_delta;
+ freezer_delta = ktime_set(0, 0);
+ spin_unlock_irqrestore(&freezer_delta_lock, flags);
+
+ rtc = alarmtimer_get_rtcdev();
+ /* If we have no rtcdev, just return */
+ if (!rtc)
+ return 0;
+
+ /* Find the soonest timer to expire*/
+ for (i = 0; i < ALARM_NUMTYPE; i++) {
+ struct alarm_base *base = &alarm_bases[i];
+ struct timerqueue_node *next;
+ ktime_t delta;
+
+ spin_lock_irqsave(&base->lock, flags);
+ next = timerqueue_getnext(&base->timerqueue);
+ spin_unlock_irqrestore(&base->lock, flags);
+ if (!next)
+ continue;
+ delta = ktime_sub(next->expires, base->gettime());
+ if (!min.tv64 || (delta.tv64 < min.tv64))
+ min = delta;
+ }
+ if (min.tv64 == 0)
+ return 0;
+
+ if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
+ __pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
+ return -EBUSY;
+ }
+
+ /* Setup a timer to fire that far in the future */
+ rtc_timer_cancel(rtc, &rtctimer);
+ rtc_read_time(rtc, &tm);
+ now = rtc_tm_to_ktime(tm);
+ now = ktime_add(now, min);
+ if (poweron_alarm) {
+ struct rtc_time tm_val;
+ unsigned long secs;
+
+ tm_val = rtc_ktime_to_tm(min);
+ rtc_tm_to_time(&tm_val, &secs);
+ lpm_suspend_wake_time(secs);
+ } else {
+ /* 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, MSEC_PER_SEC);
+ }
+ return ret;
+}
+#else
static int alarmtimer_suspend(struct device *dev)
{
struct rtc_time tm;
@@ -415,7 +480,7 @@ static int alarmtimer_suspend(struct device *dev)
__pm_wakeup_event(ws, MSEC_PER_SEC);
return ret;
}
-
+#endif
static int alarmtimer_resume(struct device *dev)
{
struct rtc_device *rtc;