diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2008-12-09 15:57:24 -0500 |
---|---|---|
committer | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2008-12-09 15:57:59 -0500 |
commit | 2fcfe6b872b21639dcffbaf3ca2a84ec01d104e0 (patch) | |
tree | c96ef9521311b25740b77c5a815e441c43778f82 /arch/arm/mach-netx | |
parent | 21edecd35580faebbd31be284df662fcc6088c50 (diff) |
netx: add support for clockevents
This is based on a patch by Luotao Fu <lfu@pengutronix.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Luotao Fu <lfu@pengutronix.de>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-netx')
-rw-r--r-- | arch/arm/mach-netx/time.c | 68 |
1 files changed, 67 insertions, 1 deletions
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c index 34a6a157f355..d51d627ce7cf 100644 --- a/arch/arm/mach-netx/time.c +++ b/arch/arm/mach-netx/time.c | |||
@@ -21,25 +21,80 @@ | |||
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
23 | #include <linux/clocksource.h> | 23 | #include <linux/clocksource.h> |
24 | #include <linux/clockchips.h> | ||
24 | #include <linux/io.h> | 25 | #include <linux/io.h> |
25 | 26 | ||
26 | #include <mach/hardware.h> | 27 | #include <mach/hardware.h> |
27 | #include <asm/mach/time.h> | 28 | #include <asm/mach/time.h> |
28 | #include <mach/netx-regs.h> | 29 | #include <mach/netx-regs.h> |
29 | 30 | ||
31 | #define TIMER_CLOCKEVENT 0 | ||
30 | #define TIMER_CLOCKSOURCE 1 | 32 | #define TIMER_CLOCKSOURCE 1 |
31 | 33 | ||
34 | static void netx_set_mode(enum clock_event_mode mode, | ||
35 | struct clock_event_device *clk) | ||
36 | { | ||
37 | u32 tmode; | ||
38 | |||
39 | /* disable timer */ | ||
40 | writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); | ||
41 | |||
42 | switch (mode) { | ||
43 | case CLOCK_EVT_MODE_PERIODIC: | ||
44 | writel(LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); | ||
45 | tmode = NETX_GPIO_COUNTER_CTRL_RST_EN | | ||
46 | NETX_GPIO_COUNTER_CTRL_IRQ_EN | | ||
47 | NETX_GPIO_COUNTER_CTRL_RUN; | ||
48 | break; | ||
49 | |||
50 | case CLOCK_EVT_MODE_ONESHOT: | ||
51 | writel(0, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); | ||
52 | tmode = NETX_GPIO_COUNTER_CTRL_IRQ_EN | | ||
53 | NETX_GPIO_COUNTER_CTRL_RUN; | ||
54 | break; | ||
55 | |||
56 | default: | ||
57 | WARN(1, "%s: unhandled mode %d\n", __func__, mode); | ||
58 | /* fall through */ | ||
59 | |||
60 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
61 | case CLOCK_EVT_MODE_UNUSED: | ||
62 | case CLOCK_EVT_MODE_RESUME: | ||
63 | tmode = 0; | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | writel(tmode, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); | ||
68 | } | ||
69 | |||
70 | static int netx_set_next_event(unsigned long evt, | ||
71 | struct clock_event_device *clk) | ||
72 | { | ||
73 | writel(0 - evt, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKEVENT)); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static struct clock_event_device netx_clockevent = { | ||
78 | .name = "netx-timer" __stringify(TIMER_CLOCKEVENT), | ||
79 | .shift = 32, | ||
80 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
81 | .set_next_event = netx_set_next_event, | ||
82 | .set_mode = netx_set_mode, | ||
83 | }; | ||
84 | |||
32 | /* | 85 | /* |
33 | * IRQ handler for the timer | 86 | * IRQ handler for the timer |
34 | */ | 87 | */ |
35 | static irqreturn_t | 88 | static irqreturn_t |
36 | netx_timer_interrupt(int irq, void *dev_id) | 89 | netx_timer_interrupt(int irq, void *dev_id) |
37 | { | 90 | { |
38 | timer_tick(); | 91 | struct clock_event_device *evt = &netx_clockevent; |
39 | 92 | ||
40 | /* acknowledge interrupt */ | 93 | /* acknowledge interrupt */ |
41 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ); | 94 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ); |
42 | 95 | ||
96 | evt->event_handler(evt); | ||
97 | |||
43 | return IRQ_HANDLED; | 98 | return IRQ_HANDLED; |
44 | } | 99 | } |
45 | 100 | ||
@@ -99,6 +154,17 @@ static void __init netx_timer_init(void) | |||
99 | clocksource_netx.mult = | 154 | clocksource_netx.mult = |
100 | clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift); | 155 | clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift); |
101 | clocksource_register(&clocksource_netx); | 156 | clocksource_register(&clocksource_netx); |
157 | |||
158 | netx_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, | ||
159 | netx_clockevent.shift); | ||
160 | netx_clockevent.max_delta_ns = | ||
161 | clockevent_delta2ns(0xfffffffe, &netx_clockevent); | ||
162 | /* with max_delta_ns >= delta2ns(0x800) the system currently runs fine. | ||
163 | * Adding some safety ... */ | ||
164 | netx_clockevent.min_delta_ns = | ||
165 | clockevent_delta2ns(0xa00, &netx_clockevent); | ||
166 | netx_clockevent.cpumask = cpumask_of_cpu(0); | ||
167 | clockevents_register_device(&netx_clockevent); | ||
102 | } | 168 | } |
103 | 169 | ||
104 | struct sys_timer netx_timer = { | 170 | struct sys_timer netx_timer = { |