|  | /* | 
|  | * linux/arch/arm/mach-nuc93x/time.c | 
|  | * | 
|  | * Copyright (c) 2009 Nuvoton technology corporation. | 
|  | * | 
|  | * Wan ZongShun <mcuos.com@gmail.com> | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or modify | 
|  | * it under the terms of the GNU General Public License as published by | 
|  | * the Free Software Foundation; either version 2 of the License, or | 
|  | * (at your option) any later version. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/sched.h> | 
|  | #include <linux/init.h> | 
|  | #include <linux/interrupt.h> | 
|  | #include <linux/err.h> | 
|  | #include <linux/clk.h> | 
|  | #include <linux/io.h> | 
|  | #include <linux/leds.h> | 
|  |  | 
|  | #include <asm/mach-types.h> | 
|  | #include <asm/mach/irq.h> | 
|  | #include <asm/mach/time.h> | 
|  |  | 
|  | #include <mach/system.h> | 
|  | #include <mach/map.h> | 
|  | #include <mach/regs-timer.h> | 
|  |  | 
|  | #define RESETINT	0x01 | 
|  | #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 unsigned long nuc93x_gettimeoffset(void) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*IRQ handler for the timer*/ | 
|  |  | 
|  | static irqreturn_t nuc93x_timer_interrupt(int irq, void *dev_id) | 
|  | { | 
|  | timer_tick(); | 
|  | __raw_writel(0x01, REG_TISR); /* clear TIF0 */ | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  |  | 
|  | static struct irqaction nuc93x_timer_irq = { | 
|  | .name		= "nuc93x Timer Tick", | 
|  | .flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 
|  | .handler	= nuc93x_timer_interrupt, | 
|  | }; | 
|  |  | 
|  | /*Set up timer reg.*/ | 
|  |  | 
|  | static void nuc93x_timer_setup(void) | 
|  | { | 
|  | struct clk *ck_ext = clk_get(NULL, "ext"); | 
|  | struct clk *ck_timer = clk_get(NULL, "timer"); | 
|  | unsigned int rate, val = 0; | 
|  |  | 
|  | BUG_ON(IS_ERR(ck_ext) || IS_ERR(ck_timer)); | 
|  |  | 
|  | clk_enable(ck_timer); | 
|  | 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(RESETINT, REG_TISR); | 
|  |  | 
|  | timer0_load = (rate / TICKS_PER_SEC); | 
|  | __raw_writel(timer0_load, REG_TICR0); | 
|  |  | 
|  | val |= (PERIOD | COUNTEN | INTEN | PRESCALE);; | 
|  | __raw_writel(val, REG_TCSR0); | 
|  |  | 
|  | } | 
|  |  | 
|  | static void __init nuc93x_timer_init(void) | 
|  | { | 
|  | nuc93x_timer_setup(); | 
|  | setup_irq(IRQ_TIMER0, &nuc93x_timer_irq); | 
|  | } | 
|  |  | 
|  | struct sys_timer nuc93x_timer = { | 
|  | .init		= nuc93x_timer_init, | 
|  | .offset		= nuc93x_gettimeoffset, | 
|  | .resume		= nuc93x_timer_setup | 
|  | }; |