Merge tag 'v3.10.56' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / time / alarmtimer.c
index aa27d391bfc8b408ced23985bc4946067b5eba87..1303df8ab3bd2de8e5adf1c5637d55dc2f0ca4bb 100644 (file)
 #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
@@ -37,7 +55,6 @@
 static struct alarm_base {
        spinlock_t              lock;
        struct timerqueue_head  timerqueue;
-       struct hrtimer          timer;
        ktime_t                 (*gettime)(void);
        clockid_t               base_clockid;
 } alarm_bases[ALARM_NUMTYPE];
@@ -46,6 +63,8 @@ static struct alarm_base {
 static ktime_t freezer_delta;
 static DEFINE_SPINLOCK(freezer_delta_lock);
 
+static struct wakeup_source *ws;
+
 #ifdef CONFIG_RTC_CLASS
 /* rtc timer and device for setting alarm wakeups at suspend */
 static struct rtc_timer                rtctimer;
@@ -83,8 +102,8 @@ static int alarmtimer_rtc_add_device(struct device *dev,
 
        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) {
@@ -125,55 +144,86 @@ static inline void alarmtimer_rtc_interface_remove(void) { }
 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
  * @alarm: pointer to alarm being enqueued.
  *
- * Adds alarm to a alarm_base timerqueue and if necessary sets
- * an hrtimer to run.
+ * Adds alarm to a alarm_base timerqueue
  *
  * Must hold base->lock when calling.
  */
 static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
 {
+       if (alarm->state & ALARMTIMER_STATE_ENQUEUED)
+               timerqueue_del(&base->timerqueue, &alarm->node);
+
        timerqueue_add(&base->timerqueue, &alarm->node);
        alarm->state |= ALARMTIMER_STATE_ENQUEUED;
-
-       if (&alarm->node == timerqueue_getnext(&base->timerqueue)) {
-               hrtimer_try_to_cancel(&base->timer);
-               hrtimer_start(&base->timer, alarm->node.expires,
-                               HRTIMER_MODE_ABS);
-       }
 }
 
 /**
- * alarmtimer_remove - Removes an alarm timer from an alarm_base timerqueue
+ * alarmtimer_dequeue - Removes an alarm timer from an alarm_base timerqueue
  * @base: pointer to the base where the timer is running
  * @alarm: pointer to alarm being removed
  *
- * Removes alarm to a alarm_base timerqueue and if necessary sets
- * a new timer to run.
+ * Removes alarm to a alarm_base timerqueue
  *
  * Must hold base->lock when calling.
  */
-static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
+static void alarmtimer_dequeue(struct alarm_base *base, struct alarm *alarm)
 {
-       struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue);
-
        if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED))
                return;
 
        timerqueue_del(&base->timerqueue, &alarm->node);
        alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
-
-       if (next == &alarm->node) {
-               hrtimer_try_to_cancel(&base->timer);
-               next = timerqueue_getnext(&base->timerqueue);
-               if (!next)
-                       return;
-               hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS);
-       }
 }
 
 
@@ -188,42 +238,25 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
  */
 static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
 {
-       struct alarm_base *base = container_of(timer, struct alarm_base, timer);
-       struct timerqueue_node *next;
+       struct alarm *alarm = container_of(timer, struct alarm, timer);
+       struct alarm_base *base = &alarm_bases[alarm->type];
        unsigned long flags;
-       ktime_t now;
        int ret = HRTIMER_NORESTART;
        int restart = ALARMTIMER_NORESTART;
 
+       alarm_dbg(INT, "alarmtimer_fired \n");
+       
        spin_lock_irqsave(&base->lock, flags);
-       now = base->gettime();
-       while ((next = timerqueue_getnext(&base->timerqueue))) {
-               struct alarm *alarm;
-               ktime_t expired = next->expires;
-
-               if (expired.tv64 > now.tv64)
-                       break;
-
-               alarm = container_of(next, struct alarm, node);
-
-               timerqueue_del(&base->timerqueue, &alarm->node);
-               alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
-
-               alarm->state |= ALARMTIMER_STATE_CALLBACK;
-               spin_unlock_irqrestore(&base->lock, flags);
-               if (alarm->function)
-                       restart = alarm->function(alarm, now);
-               spin_lock_irqsave(&base->lock, flags);
-               alarm->state &= ~ALARMTIMER_STATE_CALLBACK;
+       alarmtimer_dequeue(base, alarm);
+       spin_unlock_irqrestore(&base->lock, flags);
 
-               if (restart != ALARMTIMER_NORESTART) {
-                       timerqueue_add(&base->timerqueue, &alarm->node);
-                       alarm->state |= ALARMTIMER_STATE_ENQUEUED;
-               }
-       }
+       if (alarm->function)
+               restart = alarm->function(alarm, base->gettime());
 
-       if (next) {
-               hrtimer_set_expires(&base->timer, next->expires);
+       spin_lock_irqsave(&base->lock, flags);
+       if (restart != ALARMTIMER_NORESTART) {
+               hrtimer_set_expires(&alarm->timer, alarm->node.expires);
+               alarmtimer_enqueue(base, alarm);
                ret = HRTIMER_RESTART;
        }
        spin_unlock_irqrestore(&base->lock, flags);
@@ -232,6 +265,12 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
 
 }
 
+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
@@ -250,6 +289,7 @@ static int alarmtimer_suspend(struct device *dev)
        unsigned long flags;
        struct rtc_device *rtc;
        int i;
+       int ret;
 
        spin_lock_irqsave(&freezer_delta_lock, flags);
        min = freezer_delta;
@@ -276,11 +316,15 @@ static int alarmtimer_suspend(struct device *dev)
                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;
-
-       /* XXX - Should we enforce a minimum sleep time? */
-       WARN_ON(min.tv64 < NSEC_PER_SEC);
+       }
+       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;
+       }
 
        /* Setup an rtc timer to fire that far in the future */
        rtc_timer_cancel(rtc, &rtctimer);
@@ -288,9 +332,16 @@ static int alarmtimer_suspend(struct device *dev)
        now = rtc_tm_to_ktime(tm);
        now = ktime_add(now, min);
 
-       rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
-
-       return 0;
+       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)
+               __pm_wakeup_event(ws, MSEC_PER_SEC);
+       return ret;
 }
 #else
 static int alarmtimer_suspend(struct device *dev)
@@ -324,26 +375,56 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
                enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
 {
        timerqueue_init(&alarm->node);
+       hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid,
+                       HRTIMER_MODE_ABS);
+       alarm->timer.function = alarmtimer_fired;
        alarm->function = function;
        alarm->type = type;
        alarm->state = ALARMTIMER_STATE_INACTIVE;
 }
 
 /**
- * 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
  */
-void alarm_start(struct alarm *alarm, ktime_t start)
+int alarm_start(struct alarm *alarm, ktime_t start)
 {
        struct alarm_base *base = &alarm_bases[alarm->type];
        unsigned long flags;
+       int ret;
 
        spin_lock_irqsave(&base->lock, flags);
-       if (alarmtimer_active(alarm))
-               alarmtimer_remove(base, alarm);
        alarm->node.expires = start;
        alarmtimer_enqueue(base, alarm);
+       ret = hrtimer_start(&alarm->timer, alarm->node.expires,
+                               HRTIMER_MODE_ABS);
+       spin_unlock_irqrestore(&base->lock, flags);
+       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);
 }
 
@@ -358,18 +439,12 @@ int alarm_try_to_cancel(struct alarm *alarm)
 {
        struct alarm_base *base = &alarm_bases[alarm->type];
        unsigned long flags;
-       int ret = -1;
-       spin_lock_irqsave(&base->lock, flags);
-
-       if (alarmtimer_callback_running(alarm))
-               goto out;
+       int ret;
 
-       if (alarmtimer_is_queued(alarm)) {
-               alarmtimer_remove(base, alarm);
-               ret = 1;
-       } else
-               ret = 0;
-out:
+       spin_lock_irqsave(&base->lock, flags);
+       ret = hrtimer_try_to_cancel(&alarm->timer);
+       if (ret >= 0)
+               alarmtimer_dequeue(base, alarm);
        spin_unlock_irqrestore(&base->lock, flags);
        return ret;
 }
@@ -423,6 +498,12 @@ u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval)
        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);
+}
 
 
 
@@ -448,18 +529,26 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid)
 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;
 }
 
 /**
@@ -474,7 +563,7 @@ static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp)
        clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid;
 
        if (!alarmtimer_get_rtcdev())
-               return -ENOTSUPP;
+               return -EINVAL;
 
        return hrtimer_get_res(baseid, tp);
 }
@@ -491,7 +580,7 @@ static int alarm_clock_get(clockid_t which_clock, struct timespec *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;
@@ -569,9 +658,14 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
                                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);
 
@@ -581,8 +675,16 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
 
        /* 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;
 }
 
@@ -714,6 +816,9 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
        if (!alarmtimer_get_rtcdev())
                return -ENOTSUPP;
 
+       if (flags & ~TIMER_ABSTIME)
+               return -EINVAL;
+
        if (!capable(CAP_WAKE_ALARM))
                return -EPERM;
 
@@ -802,10 +907,6 @@ static int __init alarmtimer_init(void)
        for (i = 0; i < ALARM_NUMTYPE; i++) {
                timerqueue_init_head(&alarm_bases[i].timerqueue);
                spin_lock_init(&alarm_bases[i].lock);
-               hrtimer_init(&alarm_bases[i].timer,
-                               alarm_bases[i].base_clockid,
-                               HRTIMER_MODE_ABS);
-               alarm_bases[i].timer.function = alarmtimer_fired;
        }
 
        error = alarmtimer_rtc_interface_setup();
@@ -821,6 +922,7 @@ static int __init alarmtimer_init(void)
                error = PTR_ERR(pdev);
                goto out_drv;
        }
+       ws = wakeup_source_register("alarmtimer");
        return 0;
 
 out_drv: