| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 1 | /* | 
|  | 2 | * arch/sh/kernel/timers/timer-mtu2.c - MTU2 Timer Support | 
|  | 3 | * | 
|  | 4 | *  Copyright (C) 2005  Paul Mundt | 
|  | 5 | * | 
|  | 6 | * Based off of arch/sh/kernel/timers/timer-tmu.c | 
|  | 7 | * | 
|  | 8 | * This file is subject to the terms and conditions of the GNU General Public | 
|  | 9 | * License.  See the file "COPYING" in the main directory of this archive | 
|  | 10 | * for more details. | 
|  | 11 | */ | 
|  | 12 | #include <linux/init.h> | 
|  | 13 | #include <linux/kernel.h> | 
|  | 14 | #include <linux/interrupt.h> | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 15 | #include <linux/seqlock.h> | 
|  | 16 | #include <asm/timer.h> | 
|  | 17 | #include <asm/io.h> | 
|  | 18 | #include <asm/irq.h> | 
|  | 19 | #include <asm/clock.h> | 
|  | 20 |  | 
|  | 21 | /* | 
|  | 22 | * We use channel 1 for our lowly system timer. Channel 2 would be the other | 
|  | 23 | * likely candidate, but we leave it alone as it has higher divisors that | 
|  | 24 | * would be of more use to other more interesting applications. | 
|  | 25 | * | 
|  | 26 | * TODO: Presently we only implement a 16-bit single-channel system timer. | 
|  | 27 | * However, we can implement channel cascade if we go the overflow route and | 
|  | 28 | * get away with using 2 MTU2 channels as a 32-bit timer. | 
|  | 29 | */ | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 30 | #define MTU2_TSTR	0xfffe4280 | 
|  | 31 | #define MTU2_TCR_1	0xfffe4380 | 
|  | 32 | #define MTU2_TMDR_1	0xfffe4381 | 
|  | 33 | #define MTU2_TIOR_1	0xfffe4382 | 
|  | 34 | #define MTU2_TIER_1	0xfffe4384 | 
|  | 35 | #define MTU2_TSR_1	0xfffe4385 | 
|  | 36 | #define MTU2_TCNT_1	0xfffe4386	/* 16-bit counter */ | 
|  | 37 | #define MTU2_TGRA_1	0xfffe438a | 
|  | 38 |  | 
|  | 39 | #define STBCR3		0xfffe0408 | 
|  | 40 |  | 
|  | 41 | #define MTU2_TSTR_CST1	(1 << 1)	/* Counter Start 1 */ | 
|  | 42 |  | 
|  | 43 | #define MTU2_TSR_TGFA	(1 << 0)	/* GRA compare match */ | 
|  | 44 |  | 
|  | 45 | #define MTU2_TIER_TGIEA	(1 << 0)	/* GRA compare match  interrupt enable */ | 
|  | 46 |  | 
|  | 47 | #define MTU2_TCR_INIT	0x22 | 
|  | 48 |  | 
|  | 49 | #define MTU2_TCR_CALIB  0x00 | 
|  | 50 |  | 
|  | 51 | static unsigned long mtu2_timer_get_offset(void) | 
|  | 52 | { | 
|  | 53 | int count; | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 54 | static int count_p = 0x7fff;	/* for the first call after boot */ | 
|  | 55 | static unsigned long jiffies_p = 0; | 
|  | 56 |  | 
|  | 57 | /* | 
|  | 58 | * cache volatile jiffies temporarily; we have IRQs turned off. | 
|  | 59 | */ | 
|  | 60 | unsigned long jiffies_t; | 
|  | 61 |  | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 62 | /* timer count may underflow right here */ | 
|  | 63 | count = ctrl_inw(MTU2_TCNT_1);	/* read the latched count */ | 
|  | 64 |  | 
|  | 65 | jiffies_t = jiffies; | 
|  | 66 |  | 
|  | 67 | /* | 
|  | 68 | * avoiding timer inconsistencies (they are rare, but they happen)... | 
|  | 69 | * there is one kind of problem that must be avoided here: | 
|  | 70 | *  1. the timer counter underflows | 
|  | 71 | */ | 
|  | 72 |  | 
|  | 73 | if (jiffies_t == jiffies_p) { | 
|  | 74 | if (count > count_p) { | 
|  | 75 | if (ctrl_inb(MTU2_TSR_1) & MTU2_TSR_TGFA) { | 
|  | 76 | count -= LATCH; | 
|  | 77 | } else { | 
|  | 78 | printk("%s (): hardware timer problem?\n", | 
|  | 79 | __FUNCTION__); | 
|  | 80 | } | 
|  | 81 | } | 
|  | 82 | } else | 
|  | 83 | jiffies_p = jiffies_t; | 
|  | 84 |  | 
|  | 85 | count_p = count; | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 86 |  | 
|  | 87 | count = ((LATCH-1) - count) * TICK_SIZE; | 
|  | 88 | count = (count + LATCH/2) / LATCH; | 
|  | 89 |  | 
|  | 90 | return count; | 
|  | 91 | } | 
|  | 92 |  | 
| Paul Mundt | 710ee0c | 2006-11-05 16:48:42 +0900 | [diff] [blame] | 93 | static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id) | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 94 | { | 
|  | 95 | unsigned long timer_status; | 
|  | 96 |  | 
|  | 97 | /* Clear TGFA bit */ | 
|  | 98 | timer_status = ctrl_inb(MTU2_TSR_1); | 
|  | 99 | timer_status &= ~MTU2_TSR_TGFA; | 
|  | 100 | ctrl_outb(timer_status, MTU2_TSR_1); | 
|  | 101 |  | 
|  | 102 | /* Do timer tick */ | 
|  | 103 | write_seqlock(&xtime_lock); | 
| Paul Mundt | 710ee0c | 2006-11-05 16:48:42 +0900 | [diff] [blame] | 104 | handle_timer_tick(); | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 105 | write_sequnlock(&xtime_lock); | 
|  | 106 |  | 
|  | 107 | return IRQ_HANDLED; | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | static struct irqaction mtu2_irq = { | 
|  | 111 | .name		= "timer", | 
|  | 112 | .handler	= mtu2_timer_interrupt, | 
| Bernhard Walle | e9485ba | 2007-05-08 00:35:34 -0700 | [diff] [blame] | 113 | .flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 114 | .mask		= CPU_MASK_NONE, | 
|  | 115 | }; | 
|  | 116 |  | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 117 | static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 }; | 
|  | 118 |  | 
|  | 119 | static void mtu2_clk_init(struct clk *clk) | 
|  | 120 | { | 
|  | 121 | u8 idx = MTU2_TCR_INIT & 0x7; | 
|  | 122 |  | 
|  | 123 | clk->rate = clk->parent->rate / divisors[idx]; | 
|  | 124 | /* Start TCNT counting */ | 
|  | 125 | ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR); | 
|  | 126 |  | 
|  | 127 | } | 
|  | 128 |  | 
|  | 129 | static void mtu2_clk_recalc(struct clk *clk) | 
|  | 130 | { | 
|  | 131 | u8 idx = ctrl_inb(MTU2_TCR_1) & 0x7; | 
|  | 132 | clk->rate = clk->parent->rate / divisors[idx]; | 
|  | 133 | } | 
|  | 134 |  | 
|  | 135 | static struct clk_ops mtu2_clk_ops = { | 
|  | 136 | .init		= mtu2_clk_init, | 
|  | 137 | .recalc		= mtu2_clk_recalc, | 
|  | 138 | }; | 
|  | 139 |  | 
|  | 140 | static struct clk mtu2_clk1 = { | 
|  | 141 | .name		= "mtu2_clk1", | 
|  | 142 | .ops		= &mtu2_clk_ops, | 
|  | 143 | }; | 
|  | 144 |  | 
|  | 145 | static int mtu2_timer_start(void) | 
|  | 146 | { | 
|  | 147 | ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR); | 
|  | 148 | return 0; | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | static int mtu2_timer_stop(void) | 
|  | 152 | { | 
|  | 153 | ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR); | 
|  | 154 | return 0; | 
|  | 155 | } | 
|  | 156 |  | 
|  | 157 | static int mtu2_timer_init(void) | 
|  | 158 | { | 
|  | 159 | u8 tmp; | 
|  | 160 | unsigned long interval; | 
|  | 161 |  | 
| Paul Mundt | 417528a | 2006-11-20 11:18:30 +0900 | [diff] [blame] | 162 | setup_irq(CONFIG_SH_TIMER_IRQ, &mtu2_irq); | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 163 |  | 
| Paul Mundt | 1d11856 | 2006-12-01 13:15:14 +0900 | [diff] [blame] | 164 | mtu2_clk1.parent = clk_get(NULL, "module_clk"); | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 165 |  | 
|  | 166 | ctrl_outb(ctrl_inb(STBCR3) & (~0x20), STBCR3); | 
|  | 167 |  | 
|  | 168 | /* Normal operation */ | 
|  | 169 | ctrl_outb(0, MTU2_TMDR_1); | 
|  | 170 | ctrl_outb(MTU2_TCR_INIT, MTU2_TCR_1); | 
|  | 171 | ctrl_outb(0x01, MTU2_TIOR_1); | 
|  | 172 |  | 
|  | 173 | /* Enable underflow interrupt */ | 
|  | 174 | ctrl_outb(ctrl_inb(MTU2_TIER_1) | MTU2_TIER_TGIEA, MTU2_TIER_1); | 
|  | 175 |  | 
|  | 176 | interval = CONFIG_SH_PCLK_FREQ / 16 / HZ; | 
|  | 177 | printk(KERN_INFO "Interval = %ld\n", interval); | 
|  | 178 |  | 
|  | 179 | ctrl_outw(interval, MTU2_TGRA_1); | 
|  | 180 | ctrl_outw(0, MTU2_TCNT_1); | 
|  | 181 |  | 
|  | 182 | clk_register(&mtu2_clk1); | 
|  | 183 | clk_enable(&mtu2_clk1); | 
|  | 184 |  | 
|  | 185 | return 0; | 
|  | 186 | } | 
|  | 187 |  | 
|  | 188 | struct sys_timer_ops mtu2_timer_ops = { | 
|  | 189 | .init		= mtu2_timer_init, | 
|  | 190 | .start		= mtu2_timer_start, | 
|  | 191 | .stop		= mtu2_timer_stop, | 
| Paul Mundt | 710ee0c | 2006-11-05 16:48:42 +0900 | [diff] [blame] | 192 | #ifndef CONFIG_GENERIC_TIME | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 193 | .get_offset	= mtu2_timer_get_offset, | 
| Paul Mundt | 710ee0c | 2006-11-05 16:48:42 +0900 | [diff] [blame] | 194 | #endif | 
| Yoshinori Sato | 9d4436a | 2006-11-05 15:40:13 +0900 | [diff] [blame] | 195 | }; | 
|  | 196 |  | 
|  | 197 | struct sys_timer mtu2_timer = { | 
|  | 198 | .name	= "mtu2", | 
|  | 199 | .ops	= &mtu2_timer_ops, | 
|  | 200 | }; |