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>
22 * Timer0: clock_event_device, Tick.
23 * Timer1: clocksource, Free running.
26 * Timers are counting down.
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",
50 .read
= orion_clksrc_read
,
51 .mask
= CLOCKSOURCE_MASK(32),
52 .flags
= CLOCK_SOURCE_IS_CONTINUOUS
,
56 orion_clkevt_next_event(unsigned long delta
, struct clock_event_device
*dev
)
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
);
88 orion_clkevt_mode(enum clock_event_mode mode
, struct clock_event_device
*dev
)
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
));
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
,
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
);
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
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
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
,