]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/clocksource/timer-marco.c
gpio: Fix build breakage
[karo-tx-linux.git] / drivers / clocksource / timer-marco.c
index 62876baa3ab9c2f69c680e316a4801b11e89777f..09a17d9a6594c80e38c64bd18d6827db427df18b 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/clockchips.h>
 #include <linux/clocksource.h>
+#include <linux/cpu.h>
 #include <linux/bitops.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
@@ -18,7 +19,6 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/sched_clock.h>
-#include <asm/localtimer.h>
 #include <asm/mach/time.h>
 
 #define SIRFSOC_TIMER_32COUNTER_0_CTRL                 0x0000
@@ -151,13 +151,7 @@ static void sirfsoc_clocksource_resume(struct clocksource *cs)
                BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
 }
 
-static struct clock_event_device sirfsoc_clockevent = {
-       .name = "sirfsoc_clockevent",
-       .rating = 200,
-       .features = CLOCK_EVT_FEAT_ONESHOT,
-       .set_mode = sirfsoc_timer_set_mode,
-       .set_next_event = sirfsoc_timer_set_next_event,
-};
+static struct clock_event_device __percpu *sirfsoc_clockevent;
 
 static struct clocksource sirfsoc_clocksource = {
        .name = "sirfsoc_clocksource",
@@ -173,11 +167,8 @@ static struct irqaction sirfsoc_timer_irq = {
        .name = "sirfsoc_timer0",
        .flags = IRQF_TIMER | IRQF_NOBALANCING,
        .handler = sirfsoc_timer_interrupt,
-       .dev_id = &sirfsoc_clockevent,
 };
 
-#ifdef CONFIG_LOCAL_TIMERS
-
 static struct irqaction sirfsoc_timer1_irq = {
        .name = "sirfsoc_timer1",
        .flags = IRQF_TIMER | IRQF_NOBALANCING,
@@ -186,24 +177,28 @@ static struct irqaction sirfsoc_timer1_irq = {
 
 static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
 {
-       /* Use existing clock_event for cpu 0 */
-       if (!smp_processor_id())
-               return 0;
+       int cpu = smp_processor_id();
+       struct irqaction *action;
+
+       if (cpu == 0)
+               action = &sirfsoc_timer_irq;
+       else
+               action = &sirfsoc_timer1_irq;
 
-       ce->irq = sirfsoc_timer1_irq.irq;
+       ce->irq = action->irq;
        ce->name = "local_timer";
-       ce->features = sirfsoc_clockevent.features;
-       ce->rating = sirfsoc_clockevent.rating;
+       ce->features = CLOCK_EVT_FEAT_ONESHOT;
+       ce->rating = 200;
        ce->set_mode = sirfsoc_timer_set_mode;
        ce->set_next_event = sirfsoc_timer_set_next_event;
-       ce->shift = sirfsoc_clockevent.shift;
-       ce->mult = sirfsoc_clockevent.mult;
-       ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns;
-       ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns;
+       clockevents_calc_mult_shift(ce, CLOCK_TICK_RATE, 60);
+       ce->max_delta_ns = clockevent_delta2ns(-2, ce);
+       ce->min_delta_ns = clockevent_delta2ns(2, ce);
+       ce->cpumask = cpumask_of(cpu);
 
-       sirfsoc_timer1_irq.dev_id = ce;
-       BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq));
-       irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1));
+       action->dev_id = ce;
+       BUG_ON(setup_irq(ce->irq, action));
+       irq_set_affinity(action->irq, cpumask_of(cpu));
 
        clockevents_register_device(ce);
        return 0;
@@ -211,31 +206,48 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
 
 static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
 {
+       int cpu = smp_processor_id();
+
        sirfsoc_timer_count_disable(1);
 
-       remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+       if (cpu == 0)
+               remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
+       else
+               remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
 }
 
-static struct local_timer_ops sirfsoc_local_timer_ops = {
-       .setup  = sirfsoc_local_timer_setup,
-       .stop   = sirfsoc_local_timer_stop,
+static int sirfsoc_cpu_notify(struct notifier_block *self,
+                             unsigned long action, void *hcpu)
+{
+       /*
+        * Grab cpu pointer in each case to avoid spurious
+        * preemptible warnings
+        */
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_STARTING:
+               sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
+               break;
+       case CPU_DYING:
+               sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent));
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block sirfsoc_cpu_nb = {
+       .notifier_call = sirfsoc_cpu_notify,
 };
-#endif /* CONFIG_LOCAL_TIMERS */
 
 static void __init sirfsoc_clockevent_init(void)
 {
-       clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
-
-       sirfsoc_clockevent.max_delta_ns =
-               clockevent_delta2ns(-2, &sirfsoc_clockevent);
-       sirfsoc_clockevent.min_delta_ns =
-               clockevent_delta2ns(2, &sirfsoc_clockevent);
-
-       sirfsoc_clockevent.cpumask = cpumask_of(0);
-       clockevents_register_device(&sirfsoc_clockevent);
-#ifdef CONFIG_LOCAL_TIMERS
-       local_timer_register(&sirfsoc_local_timer_ops);
-#endif
+       sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
+       BUG_ON(!sirfsoc_clockevent);
+
+       BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb));
+
+       /* Immediately configure the timer on the boot CPU */
+       sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
 }
 
 /* initialize the kernel jiffy timer source */
@@ -273,8 +285,6 @@ static void __init sirfsoc_marco_timer_init(void)
 
        BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
 
-       BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
-
        sirfsoc_clockevent_init();
 }
 
@@ -288,11 +298,9 @@ static void __init sirfsoc_of_timer_init(struct device_node *np)
        if (!sirfsoc_timer_irq.irq)
                panic("No irq passed for timer0 via DT\n");
 
-#ifdef CONFIG_LOCAL_TIMERS
        sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
        if (!sirfsoc_timer1_irq.irq)
                panic("No irq passed for timer1 via DT\n");
-#endif
 
        sirfsoc_marco_timer_init();
 }