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>
This commit is contained in:
Mohit Aggarwal 2015-01-06 13:03:49 +05:30
parent 0874ae25b6
commit 992eea2fae
4 changed files with 73 additions and 2 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -46,9 +46,10 @@
(arr[3] << 24))
/* Module parameter to control power-on-alarm */
static bool poweron_alarm;
bool poweron_alarm;
module_param(poweron_alarm, bool, 0644);
MODULE_PARM_DESC(poweron_alarm, "Enable/Disable power-on alarm");
EXPORT_SYMBOL(poweron_alarm);
/* rtc driver internal structure */
struct qpnp_rtc {

View File

@ -57,5 +57,8 @@ ktime_t alarm_expires_remaining(const struct alarm *alarm);
/* Provide way to access the rtc device being used by alarmtimers */
struct rtc_device *alarmtimer_get_rtcdev(void);
#ifdef CONFIG_RTC_DRV_QPNP
extern bool poweron_alarm;
#endif
#endif

View File

@ -8,3 +8,5 @@ obj-$(CONFIG_GENERIC_SCHED_CLOCK) += sched_clock.o
obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o
obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o
obj-$(CONFIG_TIMER_STATS) += timer_stats.o
ccflags-y += -Idrivers/cpuidle

View File

@ -25,6 +25,7 @@
#include <linux/posix-timers.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include "lpm-levels.h"
#define ALARM_DELTA 120
@ -320,6 +321,69 @@ ktime_t alarm_expires_remaining(const struct alarm *alarm)
* 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;
@ -374,6 +438,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;