Loading arch/arm/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading arch/arm/mach-netx/time.c +67 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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 = { Loading Loading
arch/arm/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
arch/arm/mach-netx/time.c +67 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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 = { Loading