diff options
author | Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> | 2008-02-15 07:41:06 (GMT) |
---|---|---|
committer | Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> | 2008-03-31 06:17:01 (GMT) |
commit | 724ce5ee15ff4c4f3035110b683b990a3b33c832 (patch) | |
tree | 7b07d25bf64d2e6dad4495c847d1b24d9d5dca43 /arch/arm/mach-ns9xxx/time-ns9360.c | |
parent | 3a581349b961f225893103a0fbbd065a831c5184 (diff) | |
download | linux-724ce5ee15ff4c4f3035110b683b990a3b33c832.tar.xz |
ns9xxx: prepare for adding support for Digi ns921x processors
The hardware team changed some things that were taken as being common to
all ns9xxx processors up to now.
This patch addresses:
- irqs: s/IRQ_/IRQ_NS9360_/
- system module registers: some registers are still general, their
definition lives now in include/asm-arm/arch-ns9xxx/regs-sys-common.h.
The ns9360 specific ones are in .../regs-sys-ns9360.h
As a result ns9360_systemclock cannot be static inline any more as its
definition needs regs-sys-ns9360.h. This becomes a real problem when
adding support for ns9215 as this will need regs-sys-ns9215.h and
including both files will not work. For the same reason
ns9360_reset() is now non-inline and gpio functions live in their own
file.
- register mapping: s/ns9xxx_map_io/ns9360_map_io/
- timer registers: move time.c to time-ns9360.c;
s/ns9xxx_timer/ns9360_timer/
Signed-off-by: Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
Diffstat (limited to 'arch/arm/mach-ns9xxx/time-ns9360.c')
-rw-r--r-- | arch/arm/mach-ns9xxx/time-ns9360.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/arch/arm/mach-ns9xxx/time-ns9360.c b/arch/arm/mach-ns9xxx/time-ns9360.c new file mode 100644 index 0000000..4d573c9 --- /dev/null +++ b/arch/arm/mach-ns9xxx/time-ns9360.c @@ -0,0 +1,185 @@ +/* + * arch/arm/mach-ns9xxx/time-ns9360.c + * + * Copyright (C) 2006,2007 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/jiffies.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/stringify.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> + +#include <asm/arch-ns9xxx/processor-ns9360.h> +#include <asm/arch-ns9xxx/regs-sys-ns9360.h> +#include <asm/arch-ns9xxx/irqs.h> +#include <asm/arch/system.h> +#include "generic.h" + +#define TIMER_CLOCKSOURCE 0 +#define TIMER_CLOCKEVENT 1 +static u32 latch; + +static cycle_t ns9360_clocksource_read(void) +{ + return __raw_readl(SYS_TR(TIMER_CLOCKSOURCE)); +} + +static struct clocksource ns9360_clocksource = { + .name = "ns9360-timer" __stringify(TIMER_CLOCKSOURCE), + .rating = 300, + .read = ns9360_clocksource_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void ns9360_clockevent_setmode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + __raw_writel(latch, SYS_TRC(TIMER_CLOCKEVENT)); + REGSET(tc, SYS_TCx, REN, EN); + REGSET(tc, SYS_TCx, INTS, EN); + REGSET(tc, SYS_TCx, TEN, EN); + break; + + case CLOCK_EVT_MODE_ONESHOT: + REGSET(tc, SYS_TCx, REN, DIS); + REGSET(tc, SYS_TCx, INTS, EN); + + /* fall through */ + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_RESUME: + default: + REGSET(tc, SYS_TCx, TEN, DIS); + break; + } + + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); +} + +static int ns9360_clockevent_setnextevent(unsigned long evt, + struct clock_event_device *clk) +{ + u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); + + if (REGGET(tc, SYS_TCx, TEN)) { + REGSET(tc, SYS_TCx, TEN, DIS); + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); + } + + REGSET(tc, SYS_TCx, TEN, EN); + + __raw_writel(evt, SYS_TRC(TIMER_CLOCKEVENT)); + + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); + + return 0; +} + +static struct clock_event_device ns9360_clockevent_device = { + .name = "ns9360-timer" __stringify(TIMER_CLOCKEVENT), + .shift = 20, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = ns9360_clockevent_setmode, + .set_next_event = ns9360_clockevent_setnextevent, +}; + +static irqreturn_t ns9360_clockevent_handler(int irq, void *dev_id) +{ + int timerno = irq - IRQ_NS9360_TIMER0; + u32 tc; + + struct clock_event_device *evt = &ns9360_clockevent_device; + + /* clear irq */ + tc = __raw_readl(SYS_TC(timerno)); + if (REGGET(tc, SYS_TCx, REN) == SYS_TCx_REN_DIS) { + REGSET(tc, SYS_TCx, TEN, DIS); + __raw_writel(tc, SYS_TC(timerno)); + } + REGSET(tc, SYS_TCx, INTC, SET); + __raw_writel(tc, SYS_TC(timerno)); + REGSET(tc, SYS_TCx, INTC, UNSET); + __raw_writel(tc, SYS_TC(timerno)); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct irqaction ns9360_clockevent_action = { + .name = "ns9360-timer" __stringify(TIMER_CLOCKEVENT), + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = ns9360_clockevent_handler, +}; + +static void __init ns9360_timer_init(void) +{ + int tc; + + tc = __raw_readl(SYS_TC(TIMER_CLOCKSOURCE)); + if (REGGET(tc, SYS_TCx, TEN)) { + REGSET(tc, SYS_TCx, TEN, DIS); + __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE)); + } + + __raw_writel(0, SYS_TRC(TIMER_CLOCKSOURCE)); + + REGSET(tc, SYS_TCx, TEN, EN); + REGSET(tc, SYS_TCx, TDBG, STOP); + REGSET(tc, SYS_TCx, TLCS, CPU); + REGSET(tc, SYS_TCx, TM, IEE); + REGSET(tc, SYS_TCx, INTS, DIS); + REGSET(tc, SYS_TCx, UDS, UP); + REGSET(tc, SYS_TCx, TSZ, 32); + REGSET(tc, SYS_TCx, REN, EN); + + __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE)); + + ns9360_clocksource.mult = clocksource_hz2mult(ns9360_cpuclock(), + ns9360_clocksource.shift); + + clocksource_register(&ns9360_clocksource); + + latch = SH_DIV(ns9360_cpuclock(), HZ, 0); + + tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); + REGSET(tc, SYS_TCx, TEN, DIS); + REGSET(tc, SYS_TCx, TDBG, STOP); + REGSET(tc, SYS_TCx, TLCS, CPU); + REGSET(tc, SYS_TCx, TM, IEE); + REGSET(tc, SYS_TCx, INTS, DIS); + REGSET(tc, SYS_TCx, UDS, DOWN); + REGSET(tc, SYS_TCx, TSZ, 32); + REGSET(tc, SYS_TCx, REN, EN); + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); + + ns9360_clockevent_device.mult = div_sc(ns9360_cpuclock(), + NSEC_PER_SEC, ns9360_clockevent_device.shift); + ns9360_clockevent_device.max_delta_ns = + clockevent_delta2ns(-1, &ns9360_clockevent_device); + ns9360_clockevent_device.min_delta_ns = + clockevent_delta2ns(1, &ns9360_clockevent_device); + + ns9360_clockevent_device.cpumask = cpumask_of_cpu(0); + clockevents_register_device(&ns9360_clockevent_device); + + setup_irq(IRQ_NS9360_TIMER0 + TIMER_CLOCKEVENT, + &ns9360_clockevent_action); +} + +struct sys_timer ns9360_timer = { + .init = ns9360_timer_init, +}; |