diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-15 16:08:50 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-15 16:08:50 -0700 |
commit | 65a6ec0d72a07f16719e9b7a96e1c4bae044b591 (patch) | |
tree | 344e03a5039a44982c1b78d6113633b21b434820 /arch/arm/mach-ns9xxx | |
parent | 541010e4b8921cd781ff02ae68028501457045b6 (diff) | |
parent | 0181b61a988424b5cc44fe09e6968142359c815e (diff) | |
download | linux-65a6ec0d72a07f16719e9b7a96e1c4bae044b591.tar.bz2 |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (95 commits)
[ARM] 4578/1: CM-x270: PCMCIA support
[ARM] 4577/1: ITE 8152 PCI bridge support
[ARM] 4576/1: CM-X270 machine support
[ARM] pxa: Avoid pxa_gpio_mode() in gpio_direction_{in,out}put()
[ARM] pxa: move pxa_set_mode() from pxa2xx_mainstone.c to mainstone.c
[ARM] pxa: move pxa_set_mode() from pxa2xx_lubbock.c to lubbock.c
[ARM] pxa: Make cpu_is_pxaXXX dependent on configuration symbols
[ARM] pxa: PXA3xx base support
[NET] smc91x: fix PXA DMA support code
[SERIAL] Fix console initialisation ordering
[ARM] pxa: tidy up arch/arm/mach-pxa/Makefile
[ARM] Update arch/arm/Kconfig for drivers/Kconfig changes
[ARM] 4600/1: fix kernel build failure with build-id-supporting binutils
[ARM] 4599/1: Preserve ATAG list for use with kexec (2.6.23)
[ARM] Rename consistent_sync() as dma_cache_maint()
[ARM] 4572/1: ep93xx: add cirrus logic edb9307 support
[ARM] 4596/1: S3C2412: Correct IRQs for SDI+CF and add decoding support
[ARM] 4595/1: ns9xxx: define registers as void __iomem * instead of volatile u32
[ARM] 4594/1: ns9xxx: use the new gpio functions
[ARM] 4593/1: ns9xxx: implement generic clockevents
...
Diffstat (limited to 'arch/arm/mach-ns9xxx')
-rw-r--r-- | arch/arm/mach-ns9xxx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/board-a9m9750dev.c | 70 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/gpio.c | 190 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/irq.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/time.c | 172 |
5 files changed, 380 insertions, 104 deletions
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile index 4476411b8140..6fb82b855a55 100644 --- a/arch/arm/mach-ns9xxx/Makefile +++ b/arch/arm/mach-ns9xxx/Makefile @@ -1,4 +1,4 @@ -obj-y := irq.o time.o generic.o +obj-y := irq.o time.o generic.o gpio.o obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c index 925048e7adfe..0f65177f9e5f 100644 --- a/arch/arm/mach-ns9xxx/board-a9m9750dev.c +++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c @@ -13,6 +13,7 @@ #include <linux/irq.h> #include <asm/mach/map.h> +#include <asm/gpio.h> #include <asm/arch-ns9xxx/board.h> #include <asm/arch-ns9xxx/regs-sys.h> @@ -44,7 +45,13 @@ static void a9m9750dev_fpga_ack_irq(unsigned int irq) static void a9m9750dev_fpga_mask_irq(unsigned int irq) { - FPGA_IER &= ~(1 << (irq - FPGA_IRQ(0))); + u8 ier; + + ier = __raw_readb(FPGA_IER); + + ier &= ~(1 << (irq - FPGA_IRQ(0))); + + __raw_writeb(ier, FPGA_IER); } static void a9m9750dev_fpga_maskack_irq(unsigned int irq) @@ -55,7 +62,13 @@ static void a9m9750dev_fpga_maskack_irq(unsigned int irq) static void a9m9750dev_fpga_unmask_irq(unsigned int irq) { - FPGA_IER |= 1 << (irq - FPGA_IRQ(0)); + u8 ier; + + ier = __raw_readb(FPGA_IER); + + ier |= 1 << (irq - FPGA_IRQ(0)); + + __raw_writeb(ier, FPGA_IER); } static struct irq_chip a9m9750dev_fpga_chip = { @@ -68,30 +81,34 @@ static struct irq_chip a9m9750dev_fpga_chip = { static void a9m9750dev_fpga_demux_handler(unsigned int irq, struct irq_desc *desc) { - int stat = FPGA_ISR; + u8 stat = __raw_readb(FPGA_ISR); + + desc->chip->mask_ack(irq); while (stat != 0) { int irqno = fls(stat) - 1; + struct irq_desc *fpgadesc; stat &= ~(1 << irqno); - desc = irq_desc + FPGA_IRQ(irqno); + fpgadesc = irq_desc + FPGA_IRQ(irqno); - desc_handle_irq(FPGA_IRQ(irqno), desc); + desc_handle_irq(FPGA_IRQ(irqno), fpgadesc); } + + desc->chip->unmask(irq); } void __init board_a9m9750dev_init_irq(void) { - u32 reg; + u32 eic; int i; - /* - * configure gpio for IRQ_EXT2 - * use GPIO 11, because GPIO 32 is used for the LCD - */ - /* XXX: proper GPIO handling */ - BBU_GCONFb1(1) &= ~0x2000; + if (gpio_request(11, "board a9m9750dev extirq2") == 0) + ns9xxx_gpio_configure(11, 0, 1); + else + printk(KERN_ERR "%s: cannot get gpio 11 for IRQ_EXT2\n", + __func__); for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) { set_irq_chip(i, &a9m9750dev_fpga_chip); @@ -100,10 +117,10 @@ void __init board_a9m9750dev_init_irq(void) } /* IRQ_EXT2: level sensitive + active low */ - reg = SYS_EIC(2); - REGSET(reg, SYS_EIC, PLTY, AL); - REGSET(reg, SYS_EIC, LVEDG, LEVEL); - SYS_EIC(2) = reg; + eic = __raw_readl(SYS_EIC(2)); + REGSET(eic, SYS_EIC, PLTY, AL); + REGSET(eic, SYS_EIC, LVEDG, LEVEL); + __raw_writel(eic, SYS_EIC(2)); set_irq_chained_handler(IRQ_EXT2, a9m9750dev_fpga_demux_handler); @@ -167,17 +184,18 @@ void __init board_a9m9750dev_init_machine(void) u32 reg; /* setup static CS0: memory base ... */ - REGSETIM(SYS_SMCSSMB(0), SYS_SMCSSMB, CSxB, - NS9XXX_CSxSTAT_PHYS(0) >> 12); + reg = __raw_readl(SYS_SMCSSMB(0)); + REGSETIM(reg, SYS_SMCSSMB, CSxB, NS9XXX_CSxSTAT_PHYS(0) >> 12); + __raw_writel(reg, SYS_SMCSSMB(0)); /* ... and mask */ - reg = SYS_SMCSSMM(0); + reg = __raw_readl(SYS_SMCSSMM(0)); REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff); REGSET(reg, SYS_SMCSSMM, CSEx, EN); - SYS_SMCSSMM(0) = reg; + __raw_writel(reg, SYS_SMCSSMM(0)); /* setup static CS0: memory configuration */ - reg = MEM_SMC(0); + reg = __raw_readl(MEM_SMC(0)); REGSET(reg, MEM_SMC, PSMC, OFF); REGSET(reg, MEM_SMC, BSMC, OFF); REGSET(reg, MEM_SMC, EW, OFF); @@ -185,13 +203,13 @@ void __init board_a9m9750dev_init_machine(void) REGSET(reg, MEM_SMC, PC, AL); REGSET(reg, MEM_SMC, PM, DIS); REGSET(reg, MEM_SMC, MW, 8); - MEM_SMC(0) = reg; + __raw_writel(reg, MEM_SMC(0)); /* setup static CS0: timing */ - MEM_SMWED(0) = 0x2; - MEM_SMOED(0) = 0x2; - MEM_SMRD(0) = 0x6; - MEM_SMWD(0) = 0x6; + __raw_writel(0x2, MEM_SMWED(0)); + __raw_writel(0x2, MEM_SMOED(0)); + __raw_writel(0x6, MEM_SMRD(0)); + __raw_writel(0x6, MEM_SMWD(0)); platform_add_devices(board_a9m9750dev_devices, ARRAY_SIZE(board_a9m9750dev_devices)); diff --git a/arch/arm/mach-ns9xxx/gpio.c b/arch/arm/mach-ns9xxx/gpio.c new file mode 100644 index 000000000000..b2230213b983 --- /dev/null +++ b/arch/arm/mach-ns9xxx/gpio.c @@ -0,0 +1,190 @@ +/* + * arch/arm/mach-ns9xxx/gpio.c + * + * Copyright (C) 2006 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/compiler.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/module.h> + +#include <asm/arch-ns9xxx/gpio.h> +#include <asm/arch-ns9xxx/processor.h> +#include <asm/arch-ns9xxx/regs-bbu.h> +#include <asm/io.h> +#include <asm/bug.h> +#include <asm/types.h> +#include <asm/bitops.h> + +#if defined(CONFIG_PROCESSOR_NS9360) +#define GPIO_MAX 72 +#elif defined(CONFIG_PROCESSOR_NS9750) +#define GPIO_MAX 49 +#endif + +/* protects BBU_GCONFx and BBU_GCTRLx */ +static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock); + +/* only access gpiores with atomic ops */ +static DECLARE_BITMAP(gpiores, GPIO_MAX); + +static inline int ns9xxx_valid_gpio(unsigned gpio) +{ +#if defined(CONFIG_PROCESSOR_NS9360) + if (processor_is_ns9360()) + return gpio <= 72; + else +#endif +#if defined(CONFIG_PROCESSOR_NS9750) + if (processor_is_ns9750()) + return gpio <= 49; + else +#endif + BUG(); +} + +static inline void __iomem *ns9xxx_gpio_get_gconfaddr(unsigned gpio) +{ + if (gpio < 56) + return BBU_GCONFb1(gpio / 8); + else + /* + * this could be optimised away on + * ns9750 only builds, but it isn't ... + */ + return BBU_GCONFb2((gpio - 56) / 8); +} + +static inline void __iomem *ns9xxx_gpio_get_gctrladdr(unsigned gpio) +{ + if (gpio < 32) + return BBU_GCTRL1; + else if (gpio < 64) + return BBU_GCTRL2; + else + /* this could be optimised away on ns9750 only builds */ + return BBU_GCTRL3; +} + +static inline void __iomem *ns9xxx_gpio_get_gstataddr(unsigned gpio) +{ + if (gpio < 32) + return BBU_GSTAT1; + else if (gpio < 64) + return BBU_GSTAT2; + else + /* this could be optimised away on ns9750 only builds */ + return BBU_GSTAT3; +} + +int gpio_request(unsigned gpio, const char *label) +{ + if (likely(ns9xxx_valid_gpio(gpio))) + return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0; + else + return -EINVAL; +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned gpio) +{ + clear_bit(gpio, gpiores); + return; +} +EXPORT_SYMBOL(gpio_free); + +/* + * each gpio can serve for 4 different purposes [0..3]. These are called + * "functions" and passed in the parameter func. Functions 0-2 are always some + * special things, function 3 is GPIO. If func == 3 dir specifies input or + * output, and with inv you can enable an inverter (independent of func). + */ +static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func) +{ + void __iomem *conf = ns9xxx_gpio_get_gconfaddr(gpio); + u32 confval; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + + confval = __raw_readl(conf); + REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir); + REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv); + REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func); + __raw_writel(confval, conf); + + spin_unlock_irqrestore(&gpio_lock, flags); + + return 0; +} + +int ns9xxx_gpio_configure(unsigned gpio, int inv, int func) +{ + if (likely(ns9xxx_valid_gpio(gpio))) { + if (func == 3) { + printk(KERN_WARNING "use gpio_direction_input " + "or gpio_direction_output\n"); + return -EINVAL; + } else + return __ns9xxx_gpio_configure(gpio, 0, inv, func); + } else + return -EINVAL; +} +EXPORT_SYMBOL(ns9xxx_gpio_configure); + +int gpio_direction_input(unsigned gpio) +{ + if (likely(ns9xxx_valid_gpio(gpio))) { + return __ns9xxx_gpio_configure(gpio, 0, 0, 3); + } else + return -EINVAL; +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned gpio, int value) +{ + if (likely(ns9xxx_valid_gpio(gpio))) { + gpio_set_value(gpio, value); + + return __ns9xxx_gpio_configure(gpio, 1, 0, 3); + } else + return -EINVAL; +} +EXPORT_SYMBOL(gpio_direction_output); + +int gpio_get_value(unsigned gpio) +{ + void __iomem *stat = ns9xxx_gpio_get_gstataddr(gpio); + int ret; + + ret = 1 & (__raw_readl(stat) >> (gpio & 31)); + + return ret; +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned gpio, int value) +{ + void __iomem *ctrl = ns9xxx_gpio_get_gctrladdr(gpio); + u32 ctrlval; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + + ctrlval = __raw_readl(ctrl); + + if (value) + ctrlval |= 1 << (gpio & 31); + else + ctrlval &= ~(1 << (gpio & 31)); + + __raw_writel(ctrlval, ctrl); + + spin_unlock_irqrestore(&gpio_lock, flags); +} +EXPORT_SYMBOL(gpio_set_value); diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c index b8c7b00522e6..00001b874e97 100644 --- a/arch/arm/mach-ns9xxx/irq.c +++ b/arch/arm/mach-ns9xxx/irq.c @@ -9,6 +9,7 @@ * the Free Software Foundation. */ #include <linux/interrupt.h> +#include <asm/io.h> #include <asm/mach/irq.h> #include <asm/mach-types.h> #include <asm/arch-ns9xxx/regs-sys.h> @@ -17,48 +18,17 @@ #include "generic.h" -static void ns9xxx_ack_irq_timer(unsigned int irq) -{ - u32 tc = SYS_TC(irq - IRQ_TIMER0); - - /* - * If the timer is programmed to halt on terminal count, the - * timer must be disabled before clearing the interrupt. - */ - if (REGGET(tc, SYS_TCx, REN) == 0) { - REGSET(tc, SYS_TCx, TEN, DIS); - SYS_TC(irq - IRQ_TIMER0) = tc; - } - - REGSET(tc, SYS_TCx, INTC, SET); - SYS_TC(irq - IRQ_TIMER0) = tc; - - REGSET(tc, SYS_TCx, INTC, UNSET); - SYS_TC(irq - IRQ_TIMER0) = tc; -} - -static void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = { - [IRQ_TIMER0] = ns9xxx_ack_irq_timer, - [IRQ_TIMER1] = ns9xxx_ack_irq_timer, - [IRQ_TIMER2] = ns9xxx_ack_irq_timer, - [IRQ_TIMER3] = ns9xxx_ack_irq_timer, -}; - static void ns9xxx_mask_irq(unsigned int irq) { /* XXX: better use cpp symbols */ - SYS_IC(irq / 4) &= ~(1 << (7 + 8 * (3 - (irq & 3)))); + u32 ic = __raw_readl(SYS_IC(irq / 4)); + ic &= ~(1 << (7 + 8 * (3 - (irq & 3)))); + __raw_writel(ic, SYS_IC(irq / 4)); } static void ns9xxx_ack_irq(unsigned int irq) { - if (!ns9xxx_ack_irq_functions[irq]) { - printk(KERN_ERR "no ack function for irq %u\n", irq); - BUG(); - } - - ns9xxx_ack_irq_functions[irq](irq); - SYS_ISRADDR = 0; + __raw_writel(0, SYS_ISRADDR); } static void ns9xxx_maskack_irq(unsigned int irq) @@ -70,7 +40,9 @@ static void ns9xxx_maskack_irq(unsigned int irq) static void ns9xxx_unmask_irq(unsigned int irq) { /* XXX: better use cpp symbols */ - SYS_IC(irq / 4) |= 1 << (7 + 8 * (3 - (irq & 3))); + u32 ic = __raw_readl(SYS_IC(irq / 4)); + ic |= 1 << (7 + 8 * (3 - (irq & 3))); + __raw_writel(ic, SYS_IC(irq / 4)); } static struct irq_chip ns9xxx_chip = { @@ -86,14 +58,14 @@ void __init ns9xxx_init_irq(void) /* disable all IRQs */ for (i = 0; i < 8; ++i) - SYS_IC(i) = (4 * i) << 24 | (4 * i + 1) << 16 | - (4 * i + 2) << 8 | (4 * i + 3); + __raw_writel((4 * i) << 24 | (4 * i + 1) << 16 | + (4 * i + 2) << 8 | (4 * i + 3), SYS_IC(i)); /* simple interrupt prio table: * prio(x) < prio(y) <=> x < y */ for (i = 0; i < 32; ++i) - SYS_IVA(i) = i; + __raw_writel(i, SYS_IVA(i)); for (i = IRQ_WATCHDOG; i <= IRQ_EXT3; ++i) { set_irq_chip(i, &ns9xxx_chip); diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c index b97d0c54a388..c3dd1f4acb99 100644 --- a/arch/arm/mach-ns9xxx/time.c +++ b/arch/arm/mach-ns9xxx/time.c @@ -11,78 +11,174 @@ #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/regs-sys.h> #include <asm/arch-ns9xxx/clock.h> #include <asm/arch-ns9xxx/irqs.h> #include <asm/arch/system.h> #include "generic.h" -#define TIMERCLOCKSELECT 64 +#define TIMER_CLOCKSOURCE 0 +#define TIMER_CLOCKEVENT 1 +static u32 latch; + +static cycle_t ns9xxx_clocksource_read(void) +{ + return __raw_readl(SYS_TR(TIMER_CLOCKSOURCE)); +} -static u32 usecs_per_tick; +static struct clocksource ns9xxx_clocksource = { + .name = "ns9xxx-timer" __stringify(TIMER_CLOCKSOURCE), + .rating = 300, + .read = ns9xxx_clocksource_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; -static irqreturn_t -ns9xxx_timer_interrupt(int irq, void *dev_id) +static void ns9xxx_clockevent_setmode(enum clock_event_mode mode, + struct clock_event_device *clk) { - write_seqlock(&xtime_lock); - timer_tick(); - write_sequnlock(&xtime_lock); + 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)); +} - return IRQ_HANDLED; +static int ns9xxx_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 unsigned long ns9xxx_timer_gettimeoffset(void) +static struct clock_event_device ns9xxx_clockevent_device = { + .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT), + .shift = 20, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = ns9xxx_clockevent_setmode, + .set_next_event = ns9xxx_clockevent_setnextevent, +}; + +static irqreturn_t ns9xxx_clockevent_handler(int irq, void *dev_id) { - /* return the microseconds which have passed since the last interrupt - * was _serviced_. That is, if an interrupt is pending or the counter - * reloads, return one period more. */ + int timerno = irq - IRQ_TIMER0; + u32 tc; - u32 counter1 = SYS_TR(0); - int pending = SYS_ISR & (1 << IRQ_TIMER0); - u32 counter2 = SYS_TR(0); - u32 elapsed; + struct clock_event_device *evt = &ns9xxx_clockevent_device; - if (pending || counter2 > counter1) - elapsed = 2 * SYS_TRC(0) - counter2; - else - elapsed = SYS_TRC(0) - counter1; + /* 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)); - return (elapsed * usecs_per_tick) >> 16; + evt->event_handler(evt); + return IRQ_HANDLED; } -static struct irqaction ns9xxx_timer_irq = { - .name = "NS9xxx Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = ns9xxx_timer_interrupt, +static struct irqaction ns9xxx_clockevent_action = { + .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT), + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = ns9xxx_clockevent_handler, }; static void __init ns9xxx_timer_init(void) { int tc; - usecs_per_tick = - SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16); + 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)); + } - /* disable timer */ - if ((tc = SYS_TC(0)) & SYS_TCx_TEN) - SYS_TC(0) = tc & ~SYS_TCx_TEN; - - SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0); + __raw_writel(0, SYS_TRC(TIMER_CLOCKSOURCE)); REGSET(tc, SYS_TCx, TEN, EN); - REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */ - REGSET(tc, SYS_TCx, INTS, EN); - REGSET(tc, SYS_TCx, UDS, DOWN); 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); - SYS_TC(0) = tc; - setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); + __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE)); + + ns9xxx_clocksource.mult = clocksource_hz2mult(ns9xxx_cpuclock(), + ns9xxx_clocksource.shift); + + clocksource_register(&ns9xxx_clocksource); + + latch = SH_DIV(ns9xxx_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)); + + ns9xxx_clockevent_device.mult = div_sc(ns9xxx_cpuclock(), + NSEC_PER_SEC, ns9xxx_clockevent_device.shift); + ns9xxx_clockevent_device.max_delta_ns = + clockevent_delta2ns(-1, &ns9xxx_clockevent_device); + ns9xxx_clockevent_device.min_delta_ns = + clockevent_delta2ns(1, &ns9xxx_clockevent_device); + + ns9xxx_clockevent_device.cpumask = cpumask_of_cpu(0); + clockevents_register_device(&ns9xxx_clockevent_device); + + setup_irq(IRQ_TIMER0 + TIMER_CLOCKEVENT, &ns9xxx_clockevent_action); } struct sys_timer ns9xxx_timer = { .init = ns9xxx_timer_init, - .offset = ns9xxx_timer_gettimeoffset, }; |