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 | |
| 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>
| -rw-r--r-- | arch/arm/Kconfig | 1 | ||||
| -rw-r--r-- | arch/arm/mach-netx/time.c | 68 |
2 files changed, 68 insertions, 1 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 444ebd3aa263..1bce9caea27c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -287,6 +287,7 @@ config ARCH_FOOTBRIDGE | |||
| 287 | config ARCH_NETX | 287 | config ARCH_NETX |
| 288 | bool "Hilscher NetX based" | 288 | bool "Hilscher NetX based" |
| 289 | select ARM_VIC | 289 | select ARM_VIC |
| 290 | select GENERIC_CLOCKEVENTS | ||
| 290 | select GENERIC_TIME | 291 | select GENERIC_TIME |
| 291 | help | 292 | help |
| 292 | This enables support for systems based on the Hilscher NetX Soc | 293 | This enables support for systems based on the Hilscher NetX Soc |
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 = { |
