| Paulius Zaleckas | 59d3a19 | 2009-03-26 10:06:08 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  *  Copyright (C) 2001-2006 Storlink, Corp. | 
 | 3 |  *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | 
 | 4 |  * | 
 | 5 |  * This program is free software; you can redistribute it and/or modify | 
 | 6 |  * it under the terms of the GNU General Public License as published by | 
 | 7 |  * the Free Software Foundation; either version 2 of the License, or | 
 | 8 |  * (at your option) any later version. | 
 | 9 |  */ | 
 | 10 | #include <linux/interrupt.h> | 
 | 11 | #include <linux/irq.h> | 
 | 12 | #include <linux/io.h> | 
 | 13 | #include <mach/hardware.h> | 
 | 14 | #include <mach/global_reg.h> | 
 | 15 | #include <asm/mach/time.h> | 
 | 16 |  | 
 | 17 | /* | 
 | 18 |  * Register definitions for the timers | 
 | 19 |  */ | 
 | 20 | #define TIMER_COUNT(BASE_ADDR)		(BASE_ADDR  + 0x00) | 
 | 21 | #define TIMER_LOAD(BASE_ADDR)		(BASE_ADDR  + 0x04) | 
 | 22 | #define TIMER_MATCH1(BASE_ADDR)		(BASE_ADDR  + 0x08) | 
 | 23 | #define TIMER_MATCH2(BASE_ADDR)		(BASE_ADDR  + 0x0C) | 
 | 24 | #define TIMER_CR(BASE_ADDR)		(BASE_ADDR  + 0x30) | 
 | 25 |  | 
 | 26 | #define TIMER_1_CR_ENABLE		(1 << 0) | 
 | 27 | #define TIMER_1_CR_CLOCK		(1 << 1) | 
 | 28 | #define TIMER_1_CR_INT			(1 << 2) | 
 | 29 | #define TIMER_2_CR_ENABLE		(1 << 3) | 
 | 30 | #define TIMER_2_CR_CLOCK		(1 << 4) | 
 | 31 | #define TIMER_2_CR_INT			(1 << 5) | 
 | 32 | #define TIMER_3_CR_ENABLE		(1 << 6) | 
 | 33 | #define TIMER_3_CR_CLOCK		(1 << 7) | 
 | 34 | #define TIMER_3_CR_INT			(1 << 8) | 
 | 35 |  | 
 | 36 | /* | 
 | 37 |  * IRQ handler for the timer | 
 | 38 |  */ | 
 | 39 | static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id) | 
 | 40 | { | 
 | 41 | 	timer_tick(); | 
 | 42 |  | 
 | 43 | 	return IRQ_HANDLED; | 
 | 44 | } | 
 | 45 |  | 
 | 46 | static struct irqaction gemini_timer_irq = { | 
 | 47 | 	.name		= "Gemini Timer Tick", | 
 | 48 | 	.flags		= IRQF_DISABLED | IRQF_TIMER, | 
 | 49 | 	.handler	= gemini_timer_interrupt, | 
 | 50 | }; | 
 | 51 |  | 
 | 52 | /* | 
 | 53 |  * Set up timer interrupt, and return the current time in seconds. | 
 | 54 |  */ | 
 | 55 | void __init gemini_timer_init(void) | 
 | 56 | { | 
 | 57 | 	unsigned int tick_rate, reg_v; | 
 | 58 |  | 
 | 59 | 	reg_v = __raw_readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS)); | 
 | 60 | 	tick_rate = REG_TO_AHB_SPEED(reg_v) * 1000000; | 
 | 61 |  | 
 | 62 | 	printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000); | 
 | 63 |  | 
 | 64 | 	tick_rate /= 6;		/* APB bus run AHB*(1/6) */ | 
 | 65 |  | 
 | 66 | 	switch(reg_v & CPU_AHB_RATIO_MASK) { | 
 | 67 | 	case CPU_AHB_1_1: | 
 | 68 | 		printk(KERN_CONT "(1/1)\n"); | 
 | 69 | 		break; | 
 | 70 | 	case CPU_AHB_3_2: | 
 | 71 | 		printk(KERN_CONT "(3/2)\n"); | 
 | 72 | 		break; | 
 | 73 | 	case CPU_AHB_24_13: | 
 | 74 | 		printk(KERN_CONT "(24/13)\n"); | 
 | 75 | 		break; | 
 | 76 | 	case CPU_AHB_2_1: | 
 | 77 | 		printk(KERN_CONT "(2/1)\n"); | 
 | 78 | 		break; | 
 | 79 | 	} | 
 | 80 |  | 
 | 81 | 	/* | 
 | 82 | 	 * Make irqs happen for the system timer | 
 | 83 | 	 */ | 
 | 84 | 	setup_irq(IRQ_TIMER2, &gemini_timer_irq); | 
 | 85 | 	/* Start the timer */ | 
 | 86 | 	__raw_writel(tick_rate / HZ, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE))); | 
 | 87 | 	__raw_writel(tick_rate / HZ, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE))); | 
 | 88 | 	__raw_writel(TIMER_2_CR_ENABLE | TIMER_2_CR_INT, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); | 
 | 89 | } |