diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-12-19 14:46:52 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-12-19 14:46:52 -0500 |
commit | 828aac2ee239dca9c1856c4856a57912e6a487c4 (patch) | |
tree | 44de8a7d318bbcef29da00992ebfa7356f470af7 /arch/arm/mach-netx/time.c | |
parent | 6fd7c7fe72a46dfd227fe8db0c7b6863af90a982 (diff) | |
parent | 7971db5a4b4176ad5df590fce07a962c643a2740 (diff) |
Merge branch 'for-rmk' of git://git.pengutronix.de/git/ukl/linux-2.6 into devel
Diffstat (limited to 'arch/arm/mach-netx/time.c')
-rw-r--r-- | arch/arm/mach-netx/time.c | 98 |
1 files changed, 84 insertions, 14 deletions
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c index 7c540c1f01fa..d51d627ce7cf 100644 --- a/arch/arm/mach-netx/time.c +++ b/arch/arm/mach-netx/time.c | |||
@@ -21,43 +21,100 @@ | |||
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 | ||
32 | #define TIMER_CLOCKSOURCE 1 | ||
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 | |||
30 | /* | 85 | /* |
31 | * IRQ handler for the timer | 86 | * IRQ handler for the timer |
32 | */ | 87 | */ |
33 | static irqreturn_t | 88 | static irqreturn_t |
34 | netx_timer_interrupt(int irq, void *dev_id) | 89 | netx_timer_interrupt(int irq, void *dev_id) |
35 | { | 90 | { |
36 | timer_tick(); | 91 | struct clock_event_device *evt = &netx_clockevent; |
37 | 92 | ||
38 | /* acknowledge interrupt */ | 93 | /* acknowledge interrupt */ |
39 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ); | 94 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ); |
40 | 95 | ||
96 | evt->event_handler(evt); | ||
97 | |||
41 | return IRQ_HANDLED; | 98 | return IRQ_HANDLED; |
42 | } | 99 | } |
43 | 100 | ||
44 | static struct irqaction netx_timer_irq = { | 101 | static struct irqaction netx_timer_irq = { |
45 | .name = "NetX Timer Tick", | 102 | .name = "NetX Timer Tick", |
46 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 103 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, |
47 | .handler = netx_timer_interrupt, | 104 | .handler = netx_timer_interrupt, |
48 | }; | 105 | }; |
49 | 106 | ||
50 | cycle_t netx_get_cycles(void) | 107 | cycle_t netx_get_cycles(void) |
51 | { | 108 | { |
52 | return readl(NETX_GPIO_COUNTER_CURRENT(1)); | 109 | return readl(NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE)); |
53 | } | 110 | } |
54 | 111 | ||
55 | static struct clocksource clocksource_netx = { | 112 | static struct clocksource clocksource_netx = { |
56 | .name = "netx_timer", | 113 | .name = "netx_timer", |
57 | .rating = 200, | 114 | .rating = 200, |
58 | .read = netx_get_cycles, | 115 | .read = netx_get_cycles, |
59 | .mask = CLOCKSOURCE_MASK(32), | 116 | .mask = CLOCKSOURCE_MASK(32), |
60 | .shift = 20, | 117 | .shift = 20, |
61 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 118 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
62 | }; | 119 | }; |
63 | 120 | ||
@@ -77,24 +134,37 @@ static void __init netx_timer_init(void) | |||
77 | /* acknowledge interrupt */ | 134 | /* acknowledge interrupt */ |
78 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ); | 135 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ); |
79 | 136 | ||
80 | /* Enable the interrupt in the specific timer register and start timer */ | 137 | /* Enable the interrupt in the specific timer |
138 | * register and start timer | ||
139 | */ | ||
81 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ_ENABLE); | 140 | writel(COUNTER_BIT(0), NETX_GPIO_IRQ_ENABLE); |
82 | writel(NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN, | 141 | writel(NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN, |
83 | NETX_GPIO_COUNTER_CTRL(0)); | 142 | NETX_GPIO_COUNTER_CTRL(0)); |
84 | 143 | ||
85 | setup_irq(NETX_IRQ_TIMER0, &netx_timer_irq); | 144 | setup_irq(NETX_IRQ_TIMER0, &netx_timer_irq); |
86 | 145 | ||
87 | /* Setup timer one for clocksource */ | 146 | /* Setup timer one for clocksource */ |
88 | writel(0, NETX_GPIO_COUNTER_CTRL(1)); | 147 | writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE)); |
89 | writel(0, NETX_GPIO_COUNTER_CURRENT(1)); | 148 | writel(0, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE)); |
90 | writel(0xFFFFFFFF, NETX_GPIO_COUNTER_MAX(1)); | 149 | writel(0xffffffff, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKSOURCE)); |
91 | 150 | ||
92 | writel(NETX_GPIO_COUNTER_CTRL_RUN, | 151 | writel(NETX_GPIO_COUNTER_CTRL_RUN, |
93 | NETX_GPIO_COUNTER_CTRL(1)); | 152 | NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE)); |
94 | 153 | ||
95 | clocksource_netx.mult = | 154 | clocksource_netx.mult = |
96 | clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift); | 155 | clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift); |
97 | 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); | ||
98 | } | 168 | } |
99 | 169 | ||
100 | struct sys_timer netx_timer = { | 170 | struct sys_timer netx_timer = { |