Merge branches 'amba', 'fixes', 'kees', 'misc' and 'unstable/sa11x0' into for-next
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / arm / mach-footbridge / dc21285-timer.c
index 9ee78f7..3971104 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/sched_clock.h>
 
 #include <asm/irq.h>
 
@@ -46,6 +47,16 @@ static struct clocksource cksrc_dc21285 = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+static int ckevt_dc21285_set_next_event(unsigned long delta,
+       struct clock_event_device *c)
+{
+       *CSR_TIMER1_CLR = 0;
+       *CSR_TIMER1_LOAD = delta;
+       *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16;
+
+       return 0;
+}
+
 static void ckevt_dc21285_set_mode(enum clock_event_mode mode,
        struct clock_event_device *c)
 {
@@ -58,7 +69,9 @@ static void ckevt_dc21285_set_mode(enum clock_event_mode mode,
                                   TIMER_CNTL_DIV16;
                break;
 
-       default:
+       case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
                *CSR_TIMER1_CNTL = 0;
                break;
        }
@@ -66,9 +79,11 @@ static void ckevt_dc21285_set_mode(enum clock_event_mode mode,
 
 static struct clock_event_device ckevt_dc21285 = {
        .name           = "dc21285_timer1",
-       .features       = CLOCK_EVT_FEAT_PERIODIC,
+       .features       = CLOCK_EVT_FEAT_PERIODIC |
+                         CLOCK_EVT_FEAT_ONESHOT,
        .rating         = 200,
        .irq            = IRQ_TIMER1,
+       .set_next_event = ckevt_dc21285_set_next_event,
        .set_mode       = ckevt_dc21285_set_mode,
 };
 
@@ -78,6 +93,10 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id)
 
        *CSR_TIMER1_CLR = 0;
 
+       /* Stop the timer if in one-shot mode */
+       if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
+               *CSR_TIMER1_CNTL = 0;
+
        ce->event_handler(ce);
 
        return IRQ_HANDLED;
@@ -96,11 +115,28 @@ static struct irqaction footbridge_timer_irq = {
 void __init footbridge_timer_init(void)
 {
        struct clock_event_device *ce = &ckevt_dc21285;
+       unsigned rate = DIV_ROUND_CLOSEST(mem_fclk_21285, 16);
 
-       clocksource_register_hz(&cksrc_dc21285, (mem_fclk_21285 + 8) / 16);
+       clocksource_register_hz(&cksrc_dc21285, rate);
 
        setup_irq(ce->irq, &footbridge_timer_irq);
 
        ce->cpumask = cpumask_of(smp_processor_id());
-       clockevents_config_and_register(ce, mem_fclk_21285, 0x4, 0xffffff);
+       clockevents_config_and_register(ce, rate, 0x4, 0xffffff);
+}
+
+static u32 notrace footbridge_read_sched_clock(void)
+{
+       return ~*CSR_TIMER3_VALUE;
+}
+
+void __init footbridge_sched_clock(void)
+{
+       unsigned rate = DIV_ROUND_CLOSEST(mem_fclk_21285, 16);
+
+       *CSR_TIMER3_LOAD = 0;
+       *CSR_TIMER3_CLR = 0;
+       *CSR_TIMER3_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16;
+
+       setup_sched_clock(footbridge_read_sched_clock, 24, rate);
 }