From 2fcfe6b872b21639dcffbaf3ca2a84ec01d104e0 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 9 Dec 2008 21:57:24 +0100 Subject: netx: add support for clockevents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is based on a patch by Luotao Fu Signed-off-by: Uwe Kleine-König Acked-by: Luotao Fu Acked-by: Sascha Hauer --- arch/arm/Kconfig | 1 + arch/arm/mach-netx/time.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 444ebd3aa26..1bce9caea27 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 34a6a157f35..d51d627ce7c 100644 --- a/arch/arm/mach-netx/time.c +++ b/arch/arm/mach-netx/time.c @@ -21,25 +21,80 @@ #include #include #include +#include #include #include #include #include +#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 = { -- cgit v1.2.3-18-g5258