Commit | Line | Data |
---|---|---|
bb6d8c88 SH |
1 | /* |
2 | * arch/arm/mach-netx/time.c | |
3 | * | |
4 | * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | */ | |
19 | ||
20 | #include <linux/init.h> | |
21 | #include <linux/interrupt.h> | |
1a815aed SH |
22 | #include <linux/irq.h> |
23 | #include <linux/clocksource.h> | |
2fcfe6b8 | 24 | #include <linux/clockchips.h> |
fced80c7 | 25 | #include <linux/io.h> |
bb6d8c88 | 26 | |
a09e64fb | 27 | #include <mach/hardware.h> |
bb6d8c88 | 28 | #include <asm/mach/time.h> |
a09e64fb | 29 | #include <mach/netx-regs.h> |
bb6d8c88 | 30 | |
5e3e2763 UKK |
31 | #define NETX_CLOCK_FREQ 100000000 |
32 | #define NETX_LATCH DIV_ROUND_CLOSEST(NETX_CLOCK_FREQ, HZ) | |
33 | ||
2fcfe6b8 | 34 | #define TIMER_CLOCKEVENT 0 |
24e78576 UKK |
35 | #define TIMER_CLOCKSOURCE 1 |
36 | ||
c22437b7 | 37 | static inline void timer_shutdown(struct clock_event_device *evt) |
2fcfe6b8 | 38 | { |
2fcfe6b8 UKK |
39 | /* disable timer */ |
40 | writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); | |
c22437b7 VK |
41 | } |
42 | ||
43 | static int netx_shutdown(struct clock_event_device *evt) | |
44 | { | |
45 | timer_shutdown(evt); | |
46 | ||
47 | return 0; | |
48 | } | |
49 | ||
50 | static int netx_set_oneshot(struct clock_event_device *evt) | |
51 | { | |
52 | u32 tmode = NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN; | |
53 | ||
54 | timer_shutdown(evt); | |
55 | writel(0, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); | |
56 | writel(tmode, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); | |
2fcfe6b8 | 57 | |
c22437b7 VK |
58 | return 0; |
59 | } | |
2fcfe6b8 | 60 | |
c22437b7 VK |
61 | static int netx_set_periodic(struct clock_event_device *evt) |
62 | { | |
63 | u32 tmode = NETX_GPIO_COUNTER_CTRL_RST_EN | | |
64 | NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN; | |
65 | ||
66 | timer_shutdown(evt); | |
67 | writel(NETX_LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); | |
2fcfe6b8 | 68 | writel(tmode, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); |
c22437b7 VK |
69 | |
70 | return 0; | |
2fcfe6b8 UKK |
71 | } |
72 | ||
73 | static int netx_set_next_event(unsigned long evt, | |
74 | struct clock_event_device *clk) | |
75 | { | |
76 | writel(0 - evt, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKEVENT)); | |
77 | return 0; | |
78 | } | |
79 | ||
80 | static struct clock_event_device netx_clockevent = { | |
81 | .name = "netx-timer" __stringify(TIMER_CLOCKEVENT), | |
2fcfe6b8 UKK |
82 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
83 | .set_next_event = netx_set_next_event, | |
c22437b7 VK |
84 | .set_state_shutdown = netx_shutdown, |
85 | .set_state_periodic = netx_set_periodic, | |
86 | .set_state_oneshot = netx_set_oneshot, | |
87 | .tick_resume = netx_shutdown, | |
2fcfe6b8 UKK |
88 | }; |
89 | ||
bb6d8c88 SH |
90 | /* |
91 | * IRQ handler for the timer | |
92 | */ | |
93 | static irqreturn_t | |
0cd61b68 | 94 | netx_timer_interrupt(int irq, void *dev_id) |
bb6d8c88 | 95 | { |
2fcfe6b8 | 96 | struct clock_event_device *evt = &netx_clockevent; |
1a815aed | 97 | |
bb6d8c88 SH |
98 | /* acknowledge interrupt */ |
99 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ); | |
100 | ||
2fcfe6b8 UKK |
101 | evt->event_handler(evt); |
102 | ||
bb6d8c88 SH |
103 | return IRQ_HANDLED; |
104 | } | |
105 | ||
bb6d8c88 | 106 | static struct irqaction netx_timer_irq = { |
98538488 | 107 | .name = "NetX Timer Tick", |
78f6db99 | 108 | .flags = IRQF_TIMER | IRQF_IRQPOLL, |
98538488 | 109 | .handler = netx_timer_interrupt, |
bb6d8c88 SH |
110 | }; |
111 | ||
112 | /* | |
113 | * Set up timer interrupt | |
114 | */ | |
6bb27d73 | 115 | void __init netx_timer_init(void) |
bb6d8c88 SH |
116 | { |
117 | /* disable timer initially */ | |
118 | writel(0, NETX_GPIO_COUNTER_CTRL(0)); | |
119 | ||
120 | /* Reset the timer value to zero */ | |
121 | writel(0, NETX_GPIO_COUNTER_CURRENT(0)); | |
122 | ||
5e3e2763 | 123 | writel(NETX_LATCH, NETX_GPIO_COUNTER_MAX(0)); |
bb6d8c88 SH |
124 | |
125 | /* acknowledge interrupt */ | |
126 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ); | |
127 | ||
98538488 UKK |
128 | /* Enable the interrupt in the specific timer |
129 | * register and start timer | |
130 | */ | |
bb6d8c88 SH |
131 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ_ENABLE); |
132 | writel(NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN, | |
98538488 | 133 | NETX_GPIO_COUNTER_CTRL(0)); |
bb6d8c88 SH |
134 | |
135 | setup_irq(NETX_IRQ_TIMER0, &netx_timer_irq); | |
1a815aed SH |
136 | |
137 | /* Setup timer one for clocksource */ | |
24e78576 UKK |
138 | writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE)); |
139 | writel(0, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE)); | |
140 | writel(0xffffffff, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKSOURCE)); | |
1a815aed | 141 | |
98538488 | 142 | writel(NETX_GPIO_COUNTER_CTRL_RUN, |
24e78576 | 143 | NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE)); |
1a815aed | 144 | |
234b6ced | 145 | clocksource_mmio_init(NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE), |
5e3e2763 | 146 | "netx_timer", NETX_CLOCK_FREQ, 200, 32, clocksource_mmio_readl_up); |
2fcfe6b8 | 147 | |
2fcfe6b8 UKK |
148 | /* with max_delta_ns >= delta2ns(0x800) the system currently runs fine. |
149 | * Adding some safety ... */ | |
29279267 | 150 | netx_clockevent.cpumask = cpumask_of(0); |
5e3e2763 | 151 | clockevents_config_and_register(&netx_clockevent, NETX_CLOCK_FREQ, |
838a2ae8 | 152 | 0xa00, 0xfffffffe); |
bb6d8c88 | 153 | } |