Also provides an interface to set the wall time which must be used
for elapsed realtime to work.
+config ALARM_PM_THRESHOLD
+ int "Wakeup Alarm Threshold for deep sleep (Experimental)"
+ range 0 3600
+ depends on RTC_INTF_ALARM_DEV && ANDROID && PM_SLEEP && PM_RUNTIME
+ default 0
+ help
+ For Mobile Internet Devices, saving power is one of the main requirement.
+ In general, such devices supports already some power management machanism
+ that allows to to optimize the power consumption (such as suspend to
+ ram and hibernation). But using such mechanisms could be very penalizing
+ in term of power consumption in the case where the wakeup from deep sleep
+ is triggered periodically.
+
+ Actually the suspend process starts by waken up all the devices in order
+ to well prepare them for a deep sleep. Experimental results shows that,
+ depending on the devices presents on the system, the suspend increases
+ significantly the power if the wakeup capable alarms are configured to be
+ triggered before a certain threshold.
+
+ Be careful while setting this parameter: a wrong value may increase the
+ power consumption. So, if no full study was performed on the target
+ platform, please leave it at its default value.
+
config RTC_INTF_ALARM_DEV
bool "Android alarm device"
depends on RTC_INTF_ALARM
#include <linux/reboot.h>
#include <linux/notifier.h>
-
#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
#define ANDROID_ALARM_PRINT_TSET (1U << 2)
static struct platform_device *alarm_platform_dev;
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
static bool suspended;
+static u32 config_pm_threshold = (u32)CONFIG_ALARM_PM_THRESHOLD;
static int alarm_reboot_callback(struct notifier_block *nfb,
unsigned long event, void *data);
wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
}
+static struct alarm_queue *alarm_find_next_wakeup_hrtimer(void)
+{
+ struct alarm_queue *wakeup_queue = NULL;
+ struct alarm_queue *tmp_queue = NULL;
+
+ tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
+ if (tmp_queue->first)
+ wakeup_queue = tmp_queue;
+ tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
+ if (tmp_queue->first && (!wakeup_queue ||
+ hrtimer_get_expires(&tmp_queue->timer).tv64 <
+ hrtimer_get_expires(&wakeup_queue->timer).tv64))
+ wakeup_queue = tmp_queue;
+ tmp_queue = &alarms[ANDROID_ALARM_POWER_OFF_WAKEUP];
+ if (tmp_queue->first && (!wakeup_queue ||
+ hrtimer_get_expires(&tmp_queue->timer).tv64 <
+ hrtimer_get_expires(&wakeup_queue->timer).tv64))
+ wakeup_queue = tmp_queue;
+
+ return wakeup_queue;
+}
+
static int alarm_suspend(struct device *dev)
{
int err = 0;
struct timespec rtc_delta;
struct timespec wall_time;
struct alarm_queue *wakeup_queue = NULL;
- struct alarm_queue *tmp_queue = NULL;
spin_lock_irqsave(&alarm_slock, flags);
suspended = true;
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
hrtimer_cancel(&alarms[ANDROID_ALARM_POWER_OFF_WAKEUP].timer);
- tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
- if (tmp_queue->first)
- wakeup_queue = tmp_queue;
- tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
- if (tmp_queue->first && (!wakeup_queue ||
- hrtimer_get_expires(&tmp_queue->timer).tv64 <
- hrtimer_get_expires(&wakeup_queue->timer).tv64))
- wakeup_queue = tmp_queue;
- tmp_queue = &alarms[ANDROID_ALARM_POWER_OFF_WAKEUP];
- if (tmp_queue->first && (!wakeup_queue ||
- hrtimer_get_expires(&tmp_queue->timer).tv64 <
- hrtimer_get_expires(&wakeup_queue->timer).tv64))
- wakeup_queue = tmp_queue;
+ wakeup_queue = alarm_find_next_wakeup_hrtimer();
if (wakeup_queue) {
rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
getnstimeofday(&wall_time);
return 0;
}
+int alarm_pm_wake_check(void)
+{
+ struct alarm_queue *wk_queue = alarm_find_next_wakeup_hrtimer();
+
+ if (wk_queue && config_pm_threshold) {
+ /*
+ * Compute the timestamp of the next wakeup alarm in
+ * second.
+ */
+ ktime_t expire = hrtimer_get_remaining(
+ &wk_queue->timer);
+ struct timespec x = ktime_to_timespec(expire);
+ unsigned long timeout = timespec_to_jiffies(&x);
+ unsigned long next_alarm_secs = timeout / HZ;
+
+ if (next_alarm_secs < config_pm_threshold) {
+ wake_lock_timeout(&alarm_rtc_wake_lock,
+ timeout + HZ);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
static struct rtc_task alarm_rtc_task = {
.func = alarm_triggered_func
};
goto err2;
register_reboot_notifier(&alarm_reboot_notifier_block);
-
return 0;
err2: