#include <linux/posix-timers.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
+#include <linux/xlog.h>
+#include <linux/module.h>
+#include <mach/mtk_rtc.h>
+
+#define XLOG_MYTAG "Power/Alarm"
+
+#define ANDROID_ALARM_PRINT_INFO (1U << 0)
+#define ANDROID_ALARM_PRINT_IO (1U << 1)
+#define ANDROID_ALARM_PRINT_INT (1U << 2)
+
+static int debug_mask = ANDROID_ALARM_PRINT_INFO;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define alarm_dbg(debug_level_mask, fmt, args...) \
+do { \
+ if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) \
+ xlog_printk(ANDROID_LOG_INFO, XLOG_MYTAG, fmt, ##args); \
+} while (0)
/**
* struct alarm_base - Alarm timer bases
if (!rtc->ops->set_alarm)
return -1;
- if (!device_may_wakeup(rtc->dev.parent))
- return -1;
+ //if (!device_may_wakeup(rtc->dev.parent))
+ // return -1;
spin_lock_irqsave(&rtcdev_lock, flags);
if (!rtcdev) {
static inline void alarmtimer_rtc_timer_init(void) { }
#endif
+void alarm_set_power_on(struct timespec new_pwron_time, bool logo)
+{
+ unsigned long pwron_time;
+ struct rtc_wkalrm alm;
+ struct rtc_device *alarm_rtc_dev;
+// ktime_t now;
+
+ printk("alarm set power on\n");
+
+#ifdef RTC_PWRON_SEC
+ /* round down the second */
+ new_pwron_time.tv_sec = (new_pwron_time.tv_sec / 60) * 60;
+#endif
+ if (new_pwron_time.tv_sec > 0) {
+ pwron_time = new_pwron_time.tv_sec;
+#ifdef RTC_PWRON_SEC
+ pwron_time += RTC_PWRON_SEC;
+#endif
+ alm.enabled = (logo ? 3 : 2);
+ } else {
+ pwron_time = 0;
+ alm.enabled = 4;
+ }
+ alarm_rtc_dev = alarmtimer_get_rtcdev();
+ rtc_time_to_tm(pwron_time, &alm.time);
+/*
+ rtc_timer_cancel(alarm_rtc_dev, &rtctimer);
+ now = rtc_tm_to_ktime(alm.time);
+ rtc_timer_start(alarm_rtc_dev, &rtctimer, now, ktime_set(0, 0));
+*/
+ rtc_timer_cancel(alarm_rtc_dev, &rtctimer);
+ rtc_set_alarm(alarm_rtc_dev, &alm);
+ rtc_set_alarm_poweron(alarm_rtc_dev, &alm);
+}
+
+void alarm_get_power_on(struct rtc_wkalrm *alm)
+{
+ if (!alm)
+ return;
+
+ memset(alm, 0, sizeof(struct rtc_wkalrm));
+#ifndef CONFIG_MTK_FPGA
+ rtc_read_pwron_alarm(alm);
+#endif
+}
+
/**
* alarmtimer_enqueue - Adds an alarm timer to an alarm_base timerqueue
* @base: pointer to the base where the timer is being run
int ret = HRTIMER_NORESTART;
int restart = ALARMTIMER_NORESTART;
+ alarm_dbg(INT, "alarmtimer_fired \n");
+
spin_lock_irqsave(&base->lock, flags);
alarmtimer_dequeue(base, alarm);
spin_unlock_irqrestore(&base->lock, flags);
}
+ktime_t alarm_expires_remaining(const struct alarm *alarm)
+{
+ struct alarm_base *base = &alarm_bases[alarm->type];
+ return ktime_sub(alarm->node.expires, base->gettime());
+}
+
#ifdef CONFIG_RTC_CLASS
/**
* alarmtimer_suspend - Suspend time callback
if (!min.tv64 || (delta.tv64 < min.tv64))
min = delta;
}
- if (min.tv64 == 0)
+ if (min.tv64 == 0) {
+ alarm_dbg(INT, "min.tv64 == 0\n");
return 0;
-
+ }
if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
+ alarm_dbg(INT, "min.tv64 < 2S, give up suspend\n");
__pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
return -EBUSY;
}
now = rtc_tm_to_ktime(tm);
now = ktime_add(now, min);
+ alarm_dbg(INFO, "now:%02d=%02d:%02d %02d/%02d/%04d. min.tv64=%lld\n",
+ tm.tm_hour, tm.tm_min,
+ tm.tm_sec, tm.tm_mon + 1,
+ tm.tm_mday,
+ tm.tm_year + 1900, min.tv64);
/* 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)
}
/**
- * alarm_start - Sets an alarm to fire
+ * alarm_start - Sets an absolute alarm to fire
* @alarm: ptr to alarm to set
* @start: time to run the alarm
*/
return ret;
}
+/**
+ * alarm_start_relative - Sets a relative alarm to fire
+ * @alarm: ptr to alarm to set
+ * @start: time relative to now to run the alarm
+ */
+int alarm_start_relative(struct alarm *alarm, ktime_t start)
+{
+ struct alarm_base *base = &alarm_bases[alarm->type];
+
+ start = ktime_add(start, base->gettime());
+ return alarm_start(alarm, start);
+}
+
+void alarm_restart(struct alarm *alarm)
+{
+ struct alarm_base *base = &alarm_bases[alarm->type];
+ unsigned long flags;
+
+ spin_lock_irqsave(&base->lock, flags);
+ hrtimer_set_expires(&alarm->timer, alarm->node.expires);
+ hrtimer_restart(&alarm->timer);
+ alarmtimer_enqueue(base, alarm);
+ spin_unlock_irqrestore(&base->lock, flags);
+}
+
/**
* alarm_try_to_cancel - Tries to cancel an alarm timer
* @alarm: ptr to alarm to be canceled
return overrun;
}
+u64 alarm_forward_now(struct alarm *alarm, ktime_t interval)
+{
+ struct alarm_base *base = &alarm_bases[alarm->type];
+
+ return alarm_forward(alarm, base->gettime(), interval);
+}
static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
ktime_t now)
{
+ unsigned long flags;
struct k_itimer *ptr = container_of(alarm, struct k_itimer,
it.alarm.alarmtimer);
- if (posix_timer_event(ptr, 0) != 0)
- ptr->it_overrun++;
+ enum alarmtimer_restart result = ALARMTIMER_NORESTART;
+
+ spin_lock_irqsave(&ptr->it_lock, flags);
+ if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) {
+ if (posix_timer_event(ptr, 0) != 0)
+ ptr->it_overrun++;
+ }
/* Re-add periodic timers */
if (ptr->it.alarm.interval.tv64) {
ptr->it_overrun += alarm_forward(alarm, now,
ptr->it.alarm.interval);
- return ALARMTIMER_RESTART;
+ result = ALARMTIMER_RESTART;
}
- return ALARMTIMER_NORESTART;
+ spin_unlock_irqrestore(&ptr->it_lock, flags);
+
+ return result;
}
/**
clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid;
if (!alarmtimer_get_rtcdev())
- return -ENOTSUPP;
+ return -EINVAL;
return hrtimer_get_res(baseid, tp);
}
struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)];
if (!alarmtimer_get_rtcdev())
- return -ENOTSUPP;
+ return -EINVAL;
*tp = ktime_to_timespec(base->gettime());
return 0;
struct itimerspec *new_setting,
struct itimerspec *old_setting)
{
+ ktime_t exp;
+
if (!rtcdev)
return -ENOTSUPP;
+ if (flags & ~TIMER_ABSTIME)
+ return -EINVAL;
+
if (old_setting)
alarm_timer_get(timr, old_setting);
/* start the timer */
timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval);
- alarm_start(&timr->it.alarm.alarmtimer,
- timespec_to_ktime(new_setting->it_value));
+ exp = timespec_to_ktime(new_setting->it_value);
+ /* Convert (if necessary) to absolute time */
+ if (flags != TIMER_ABSTIME) {
+ ktime_t now;
+
+ now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime();
+ exp = ktime_add(now, exp);
+ }
+
+ alarm_start(&timr->it.alarm.alarmtimer, exp);
return 0;
}
if (!alarmtimer_get_rtcdev())
return -ENOTSUPP;
+ if (flags & ~TIMER_ABSTIME)
+ return -EINVAL;
+
if (!capable(CAP_WAKE_ALARM))
return -EPERM;