diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2008-12-09 23:57:24 +0300 |
---|---|---|
committer | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2008-12-09 23:57:59 +0300 |
commit | 2fcfe6b872b21639dcffbaf3ca2a84ec01d104e0 (patch) | |
tree | c96ef9521311b25740b77c5a815e441c43778f82 | |
parent | 21edecd35580faebbd31be284df662fcc6088c50 (diff) | |
download | linux-2fcfe6b872b21639dcffbaf3ca2a84ec01d104e0.tar.xz |
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 config ARCH_NETX bool "Hilscher NetX based" select ARM_VIC + select GENERIC_CLOCKEVENTS select GENERIC_TIME help 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 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/clocksource.h> +#include <linux/clockchips.h> #include <linux/io.h> #include <mach/hardware.h> #include <asm/mach/time.h> #include <mach/netx-regs.h> +#define TIMER_CLOCKEVENT 0 #define TIMER_CLOCKSOURCE 1 +static void netx_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + u32 tmode; + + /* disable timer */ + writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); + tmode = NETX_GPIO_COUNTER_CTRL_RST_EN | + NETX_GPIO_COUNTER_CTRL_IRQ_EN | + NETX_GPIO_COUNTER_CTRL_RUN; + break; + + case CLOCK_EVT_MODE_ONESHOT: + writel(0, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); + tmode = NETX_GPIO_COUNTER_CTRL_IRQ_EN | + NETX_GPIO_COUNTER_CTRL_RUN; + break; + + default: + WARN(1, "%s: unhandled mode %d\n", __func__, mode); + /* fall through */ + + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_RESUME: + tmode = 0; + break; + } + + writel(tmode, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); +} + +static int netx_set_next_event(unsigned long evt, + struct clock_event_device *clk) +{ + writel(0 - evt, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKEVENT)); + return 0; +} + +static struct clock_event_device netx_clockevent = { + .name = "netx-timer" __stringify(TIMER_CLOCKEVENT), + .shift = 32, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = netx_set_next_event, + .set_mode = netx_set_mode, +}; + /* * IRQ handler for the timer */ static irqreturn_t netx_timer_interrupt(int irq, void *dev_id) { - timer_tick(); + struct clock_event_device *evt = &netx_clockevent; /* acknowledge interrupt */ writel(COUNTER_BIT(0), NETX_GPIO_IRQ); + evt->event_handler(evt); + return IRQ_HANDLED; } @@ -99,6 +154,17 @@ static void __init netx_timer_init(void) clocksource_netx.mult = clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift); clocksource_register(&clocksource_netx); + + netx_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, + netx_clockevent.shift); + netx_clockevent.max_delta_ns = + clockevent_delta2ns(0xfffffffe, &netx_clockevent); + /* with max_delta_ns >= delta2ns(0x800) the system currently runs fine. + * Adding some safety ... */ + netx_clockevent.min_delta_ns = + clockevent_delta2ns(0xa00, &netx_clockevent); + netx_clockevent.cpumask = cpumask_of_cpu(0); + clockevents_register_device(&netx_clockevent); } struct sys_timer netx_timer = { |