Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / arch / arm / mach-orion / time.c
blobbd4262da4f405ed0ad1f65f2cddf4e411fc32765
1 /*
2 * arch/arm/mach-orion/time.c
4 * Core time functions for Marvell Orion System On Chip
6 * Maintainer: Tzachi Perelstein <tzachi@marvell.com>
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
13 #include <linux/kernel.h>
14 #include <linux/clockchips.h>
15 #include <linux/interrupt.h>
16 #include <linux/irq.h>
17 #include <asm/mach/time.h>
18 #include <asm/arch/orion.h>
19 #include "common.h"
22 * Timer0: clock_event_device, Tick.
23 * Timer1: clocksource, Free running.
24 * WatchDog: Not used.
26 * Timers are counting down.
28 #define CLOCKEVENT 0
29 #define CLOCKSOURCE 1
32 * Timers bits
34 #define BRIDGE_INT_TIMER(x) (1 << ((x) + 1))
35 #define TIMER_EN(x) (1 << ((x) * 2))
36 #define TIMER_RELOAD_EN(x) (1 << (((x) * 2) + 1))
37 #define BRIDGE_INT_TIMER_WD (1 << 3)
38 #define TIMER_WD_EN (1 << 4)
39 #define TIMER_WD_RELOAD_EN (1 << 5)
41 static cycle_t orion_clksrc_read(void)
43 return (0xffffffff - orion_read(TIMER_VAL(CLOCKSOURCE)));
46 static struct clocksource orion_clksrc = {
47 .name = "orion_clocksource",
48 .shift = 20,
49 .rating = 300,
50 .read = orion_clksrc_read,
51 .mask = CLOCKSOURCE_MASK(32),
52 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
55 static int
56 orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev)
58 unsigned long flags;
60 if (delta == 0)
61 return -ETIME;
63 local_irq_save(flags);
66 * Clear and enable timer interrupt bit
68 orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
69 orion_setbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
72 * Setup new timer value
74 orion_write(TIMER_VAL(CLOCKEVENT), delta);
77 * Disable auto reload and kickoff the timer
79 orion_clrbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT));
80 orion_setbits(TIMER_CTRL, TIMER_EN(CLOCKEVENT));
82 local_irq_restore(flags);
84 return 0;
87 static void
88 orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
90 unsigned long flags;
92 local_irq_save(flags);
94 if (mode == CLOCK_EVT_MODE_PERIODIC) {
96 * Setup latch cycles in timer and enable reload interrupt.
98 orion_write(TIMER_VAL_RELOAD(CLOCKEVENT), LATCH);
99 orion_write(TIMER_VAL(CLOCKEVENT), LATCH);
100 orion_setbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
101 orion_setbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT) |
102 TIMER_EN(CLOCKEVENT));
103 } else {
105 * Disable timer and interrupt
107 orion_clrbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
108 orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
109 orion_clrbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT) |
110 TIMER_EN(CLOCKEVENT));
113 local_irq_restore(flags);
116 static struct clock_event_device orion_clkevt = {
117 .name = "orion_tick",
118 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
119 .shift = 32,
120 .rating = 300,
121 .cpumask = CPU_MASK_CPU0,
122 .set_next_event = orion_clkevt_next_event,
123 .set_mode = orion_clkevt_mode,
126 static irqreturn_t orion_timer_interrupt(int irq, void *dev_id)
129 * Clear cause bit and do event
131 orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
132 orion_clkevt.event_handler(&orion_clkevt);
133 return IRQ_HANDLED;
136 static struct irqaction orion_timer_irq = {
137 .name = "orion_tick",
138 .flags = IRQF_DISABLED | IRQF_TIMER,
139 .handler = orion_timer_interrupt
142 static void orion_timer_init(void)
145 * Setup clocksource free running timer (no interrupt on reload)
147 orion_write(TIMER_VAL(CLOCKSOURCE), 0xffffffff);
148 orion_write(TIMER_VAL_RELOAD(CLOCKSOURCE), 0xffffffff);
149 orion_clrbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKSOURCE));
150 orion_setbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKSOURCE) |
151 TIMER_EN(CLOCKSOURCE));
154 * Register clocksource
156 orion_clksrc.mult =
157 clocksource_hz2mult(CLOCK_TICK_RATE, orion_clksrc.shift);
159 clocksource_register(&orion_clksrc);
162 * Connect and enable tick handler
164 setup_irq(IRQ_ORION_BRIDGE, &orion_timer_irq);
167 * Register clockevent
169 orion_clkevt.mult =
170 div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, orion_clkevt.shift);
171 orion_clkevt.max_delta_ns =
172 clockevent_delta2ns(0xfffffffe, &orion_clkevt);
173 orion_clkevt.min_delta_ns =
174 clockevent_delta2ns(1, &orion_clkevt);
176 clockevents_register_device(&orion_clkevt);
179 struct sys_timer orion_timer = {
180 .init = orion_timer_init,