diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-14 17:48:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-14 17:48:14 -0700 |
commit | 2ca7d674d7ab2220707b2ada0b690c0e7c95e7ac (patch) | |
tree | 9c0927ed1d540e5fd704c1f82689870786514655 /arch/arm/mach-w90x900/time.c | |
parent | 2195d2818c37bdf263865f1e9effccdd9fc5f9d4 (diff) | |
parent | 87d721ad7a37b7650dd710c88dd5c6a5bf9fe996 (diff) |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (257 commits)
[ARM] Update mach-types
ARM: 5636/1: Move vendor enum to AMBA include
ARM: Fix pfn_valid() for sparse memory
[ARM] orion5x: Add LaCie NAS 2Big Network support
[ARM] pxa/sharpsl_pm: zaurus c3000 aka spitz: fix resume
ARM: 5686/1: at91: Correct AC97 reset line in at91sam9263ek board
ARM: 5640/1: This patch modifies the support of AC97 on the at91sam9263 ek board
ARM: 5689/1: Update default config of HP Jornada 700-series machines
ARM: 5691/1: fix cache aliasing issues between kmap() and kmap_atomic() with highmem
ARM: 5688/1: ks8695_serial: disable_irq() lockup
ARM: 5687/1: fix an oops with highmem
ARM: 5684/1: Add nuc960 platform to w90x900
ARM: 5683/1: Add nuc950 platform to w90x900
ARM: 5682/1: Add cpu.c and dev.c and modify some files of w90p910 platform
ARM: 5626/1: add suspend/resume functions to amba-pl011 serial driver
ARM: 5625/1: fix hard coded 4K resource size in amba bus detection
MMC: MMCI: convert realview MMC to use gpiolib
ARM: 5685/1: Make MMCI driver compile without gpiolib
ARM: implement highpte
ARM: Show FIQ in /proc/interrupts on CONFIG_FIQ
...
Fix up trivial conflict in arch/arm/kernel/signal.c.
It was due to the TIF_NOTIFY_RESUME addition in commit d0420c83f ("KEYS:
Extend TIF_NOTIFY_RESUME to (almost) all architectures") and follow-ups.
Diffstat (limited to 'arch/arm/mach-w90x900/time.c')
-rw-r--r-- | arch/arm/mach-w90x900/time.c | 153 |
1 files changed, 128 insertions, 25 deletions
diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c index bcc838f6b39..4128af870b4 100644 --- a/arch/arm/mach-w90x900/time.c +++ b/arch/arm/mach-w90x900/time.c @@ -3,7 +3,7 @@ * * Based on linux/arch/arm/plat-s3c24xx/time.c by Ben Dooks * - * Copyright (c) 2008 Nuvoton technology corporation + * Copyright (c) 2009 Nuvoton technology corporation * All rights reserved. * * Wan ZongShun <mcuos.com@gmail.com> @@ -23,6 +23,8 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/leds.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/mach-types.h> #include <asm/mach/irq.h> @@ -31,49 +33,150 @@ #include <mach/map.h> #include <mach/regs-timer.h> -static unsigned long w90x900_gettimeoffset(void) +#define RESETINT 0x1f +#define PERIOD (0x01 << 27) +#define ONESHOT (0x00 << 27) +#define COUNTEN (0x01 << 30) +#define INTEN (0x01 << 29) + +#define TICKS_PER_SEC 100 +#define PRESCALE 0x63 /* Divider = prescale + 1 */ + +unsigned int timer0_load; + +static void nuc900_clockevent_setmode(enum clock_event_mode mode, + struct clock_event_device *clk) { + unsigned int val; + + val = __raw_readl(REG_TCSR0); + val &= ~(0x03 << 27); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + __raw_writel(timer0_load, REG_TICR0); + val |= (PERIOD | COUNTEN | INTEN | PRESCALE); + break; + + case CLOCK_EVT_MODE_ONESHOT: + val |= (ONESHOT | COUNTEN | INTEN | PRESCALE); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_RESUME: + break; + } + + __raw_writel(val, REG_TCSR0); +} + +static int nuc900_clockevent_setnextevent(unsigned long evt, + struct clock_event_device *clk) +{ + unsigned int val; + + __raw_writel(evt, REG_TICR0); + + val = __raw_readl(REG_TCSR0); + val |= (COUNTEN | INTEN | PRESCALE); + __raw_writel(val, REG_TCSR0); + return 0; } +static struct clock_event_device nuc900_clockevent_device = { + .name = "nuc900-timer0", + .shift = 32, + .features = CLOCK_EVT_MODE_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = nuc900_clockevent_setmode, + .set_next_event = nuc900_clockevent_setnextevent, + .rating = 300, +}; + /*IRQ handler for the timer*/ -static irqreturn_t -w90x900_timer_interrupt(int irq, void *dev_id) +static irqreturn_t nuc900_timer0_interrupt(int irq, void *dev_id) { - timer_tick(); + struct clock_event_device *evt = &nuc900_clockevent_device; + __raw_writel(0x01, REG_TISR); /* clear TIF0 */ + + evt->event_handler(evt); return IRQ_HANDLED; } -static struct irqaction w90x900_timer_irq = { - .name = "w90x900 Timer Tick", +static struct irqaction nuc900_timer0_irq = { + .name = "nuc900-timer0", .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = w90x900_timer_interrupt, + .handler = nuc900_timer0_interrupt, }; -/*Set up timer reg.*/ +static void __init nuc900_clockevents_init(unsigned int rate) +{ + nuc900_clockevent_device.mult = div_sc(rate, NSEC_PER_SEC, + nuc900_clockevent_device.shift); + nuc900_clockevent_device.max_delta_ns = clockevent_delta2ns(0xffffffff, + &nuc900_clockevent_device); + nuc900_clockevent_device.min_delta_ns = clockevent_delta2ns(0xf, + &nuc900_clockevent_device); + nuc900_clockevent_device.cpumask = cpumask_of(0); -static void w90x900_timer_setup(void) + clockevents_register_device(&nuc900_clockevent_device); +} + +static cycle_t nuc900_get_cycles(struct clocksource *cs) { - __raw_writel(0, REG_TCSR0); - __raw_writel(0, REG_TCSR1); - __raw_writel(0, REG_TCSR2); - __raw_writel(0, REG_TCSR3); - __raw_writel(0, REG_TCSR4); - __raw_writel(0x1F, REG_TISR); - __raw_writel(15000000/(100 * 100), REG_TICR0); - __raw_writel(0x68000063, REG_TCSR0); + return ~__raw_readl(REG_TDR1); } -static void __init w90x900_timer_init(void) +static struct clocksource clocksource_nuc900 = { + .name = "nuc900-timer1", + .rating = 200, + .read = nuc900_get_cycles, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init nuc900_clocksource_init(unsigned int rate) { - w90x900_timer_setup(); - setup_irq(IRQ_TIMER0, &w90x900_timer_irq); + unsigned int val; + + __raw_writel(0xffffffff, REG_TICR1); + + val = __raw_readl(REG_TCSR1); + val |= (COUNTEN | PERIOD); + __raw_writel(val, REG_TCSR1); + + clocksource_nuc900.mult = + clocksource_khz2mult((rate / 1000), clocksource_nuc900.shift); + clocksource_register(&clocksource_nuc900); +} + +static void __init nuc900_timer_init(void) +{ + struct clk *ck_ext = clk_get(NULL, "ext"); + unsigned int rate; + + BUG_ON(IS_ERR(ck_ext)); + + rate = clk_get_rate(ck_ext); + clk_put(ck_ext); + rate = rate / (PRESCALE + 0x01); + + /* set a known state */ + __raw_writel(0x00, REG_TCSR0); + __raw_writel(0x00, REG_TCSR1); + __raw_writel(RESETINT, REG_TISR); + timer0_load = (rate / TICKS_PER_SEC); + + setup_irq(IRQ_TIMER0, &nuc900_timer0_irq); + + nuc900_clocksource_init(rate); + nuc900_clockevents_init(rate); } -struct sys_timer w90x900_timer = { - .init = w90x900_timer_init, - .offset = w90x900_gettimeoffset, - .resume = w90x900_timer_setup +struct sys_timer nuc900_timer = { + .init = nuc900_timer_init, }; |