From c1b2e47058c86bea9680eadc01b65e8c3bb2415d Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Fri, 17 May 2013 15:15:02 +0530 Subject: [PATCH] rtc: alarm: Add power-on alarm feature Android does not support powering up of phone through alarm. Adding shutdown hook in alarm driver which will set alarm while phone is going down so as to power-up the phone after alarm expiration. CRs-Fixed: 432312 Change-Id: I21786d264b93f7c0c660823a0a1a221c1b4df7b2 Signed-off-by: Ashay Jaiswal --- drivers/rtc/alarm-dev.c | 6 +++++ drivers/rtc/alarm.c | 47 +++++++++++++++++++++++++++++++++++ include/linux/android_alarm.h | 1 + 3 files changed, 54 insertions(+) diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c index bfcaebc9ce4..1d60e9784a5 100644 --- a/drivers/rtc/alarm-dev.c +++ b/drivers/rtc/alarm-dev.c @@ -98,6 +98,8 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) wake_unlock(&alarm_wake_lock); } alarm_enabled &= ~alarm_type_mask; + if (alarm_type == ANDROID_ALARM_RTC_WAKEUP) + set_power_on_alarm(0); spin_unlock_irqrestore(&alarm_slock, flags); break; @@ -125,6 +127,10 @@ from_old_alarm_set: alarm_start_range(&alarms[alarm_type], timespec_to_ktime(new_alarm_time), timespec_to_ktime(new_alarm_time)); + if ((alarm_type == ANDROID_ALARM_RTC_WAKEUP) && + (ANDROID_ALARM_BASE_CMD(cmd) == + ANDROID_ALARM_SET(0))) + set_power_on_alarm(new_alarm_time.tv_sec); spin_unlock_irqrestore(&alarm_slock, flags); if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0) && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD) diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c index 9340af7dc86..e318ecf7f0f 100644 --- a/drivers/rtc/alarm.c +++ b/drivers/rtc/alarm.c @@ -68,6 +68,13 @@ static struct wake_lock alarm_rtc_wake_lock; static struct platform_device *alarm_platform_dev; struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT]; static bool suspended; +static long power_on_alarm; + +void set_power_on_alarm(long secs) +{ + power_on_alarm = secs; +} + static void update_timer_locked(struct alarm_queue *base, bool head_removed) { @@ -486,6 +493,45 @@ static int alarm_resume(struct platform_device *pdev) return 0; } +static void alarm_shutdown(struct platform_device *dev) +{ + struct timespec wall_time; + struct rtc_time rtc_time; + struct rtc_wkalrm alarm; + unsigned long flags; + long rtc_secs, alarm_delta, alarm_time; + int rc; + + spin_lock_irqsave(&alarm_slock, flags); + + if (!power_on_alarm) + goto disable_alarm; + + rtc_read_time(alarm_rtc_dev, &rtc_time); + getnstimeofday(&wall_time); + rtc_tm_to_time(&rtc_time, &rtc_secs); + alarm_delta = wall_time.tv_sec - rtc_secs; + alarm_time = power_on_alarm - alarm_delta; + if (alarm_time <= rtc_secs) + goto disable_alarm; + + rtc_time_to_tm(alarm_time, &alarm.time); + alarm.enabled = 1; + rc = rtc_set_alarm(alarm_rtc_dev, &alarm); + if (rc) + pr_alarm(ERROR, "Unable to set power-on alarm\n"); + else + pr_alarm(FLOW, "Power-on alarm set to %lu\n", + alarm_time); + + spin_unlock_irqrestore(&alarm_slock, flags); + return; + +disable_alarm: + rtc_alarm_irq_enable(alarm_rtc_dev, 0); + spin_unlock_irqrestore(&alarm_slock, flags); +} + static struct rtc_task alarm_rtc_task = { .func = alarm_triggered_func }; @@ -545,6 +591,7 @@ static struct class_interface rtc_alarm_interface = { static struct platform_driver alarm_driver = { .suspend = alarm_suspend, .resume = alarm_resume, + .shutdown = alarm_shutdown, .driver = { .name = "alarm" } diff --git a/include/linux/android_alarm.h b/include/linux/android_alarm.h index cbfeafce329..096f77711b1 100644 --- a/include/linux/android_alarm.h +++ b/include/linux/android_alarm.h @@ -70,6 +70,7 @@ void alarm_init(struct alarm *alarm, void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end); int alarm_try_to_cancel(struct alarm *alarm); int alarm_cancel(struct alarm *alarm); +void set_power_on_alarm(long secs); ktime_t alarm_get_elapsed_realtime(void); /* set rtc while preserving elapsed realtime */