Loading drivers/rtc/qpnp-rtc.c +3 −2 Original line number Diff line number Diff line /* 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 Loading Loading @@ -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 { Loading include/linux/alarmtimer.h +3 −0 Original line number Diff line number Diff line Loading @@ -55,5 +55,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 kernel/time/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -31,3 +31,4 @@ targets += timeconst.h $(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE $(call if_changed,bc) ccflags-y += -Idrivers/cpuidle kernel/time/alarmtimer.c +66 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <linux/posix-timers.h> #include <linux/workqueue.h> #include <linux/freezer.h> #include "lpm-levels.h" /** * struct alarm_base - Alarm timer bases Loading Loading @@ -242,6 +243,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; Loading Loading @@ -296,7 +361,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; Loading Loading
drivers/rtc/qpnp-rtc.c +3 −2 Original line number Diff line number Diff line /* 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 Loading Loading @@ -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 { Loading
include/linux/alarmtimer.h +3 −0 Original line number Diff line number Diff line Loading @@ -55,5 +55,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
kernel/time/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -31,3 +31,4 @@ targets += timeconst.h $(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE $(call if_changed,bc) ccflags-y += -Idrivers/cpuidle
kernel/time/alarmtimer.c +66 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <linux/posix-timers.h> #include <linux/workqueue.h> #include <linux/freezer.h> #include "lpm-levels.h" /** * struct alarm_base - Alarm timer bases Loading Loading @@ -242,6 +243,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; Loading Loading @@ -296,7 +361,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; Loading