1 /* 2 * linux/arch/arm/mach-footbridge/isa-timer.c 3 * 4 * Copyright (C) 1998 Russell King. 5 * Copyright (C) 1998 Phil Blundell 6 */ 7 #include <linux/init.h> 8 #include <linux/interrupt.h> 9 10 #include <asm/io.h> 11 #include <asm/irq.h> 12 13 #include <asm/mach/time.h> 14 15 #include "common.h" 16 17 /* 18 * ISA timer tick support 19 */ 20 #define mSEC_10_from_14 ((14318180 + 100) / 200) 21 22 static unsigned long isa_gettimeoffset(void) 23 { 24 int count; 25 26 static int count_p = (mSEC_10_from_14/6); /* for the first call after boot */ 27 static unsigned long jiffies_p = 0; 28 29 /* 30 * cache volatile jiffies temporarily; we have IRQs turned off. 31 */ 32 unsigned long jiffies_t; 33 34 /* timer count may underflow right here */ 35 outb_p(0x00, 0x43); /* latch the count ASAP */ 36 37 count = inb_p(0x40); /* read the latched count */ 38 39 /* 40 * We do this guaranteed double memory access instead of a _p 41 * postfix in the previous port access. Wheee, hackady hack 42 */ 43 jiffies_t = jiffies; 44 45 count |= inb_p(0x40) << 8; 46 47 /* Detect timer underflows. If we haven't had a timer tick since 48 the last time we were called, and time is apparently going 49 backwards, the counter must have wrapped during this routine. */ 50 if ((jiffies_t == jiffies_p) && (count > count_p)) 51 count -= (mSEC_10_from_14/6); 52 else 53 jiffies_p = jiffies_t; 54 55 count_p = count; 56 57 count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000); 58 count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); 59 60 return count; 61 } 62 63 static irqreturn_t 64 isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 65 { 66 write_seqlock(&xtime_lock); 67 timer_tick(regs); 68 write_sequnlock(&xtime_lock); 69 return IRQ_HANDLED; 70 } 71 72 static struct irqaction isa_timer_irq = { 73 .name = "ISA timer tick", 74 .handler = isa_timer_interrupt, 75 .flags = SA_INTERRUPT | SA_TIMER, 76 }; 77 78 static void __init isa_timer_init(void) 79 { 80 isa_rtc_init(); 81 82 /* enable PIT timer */ 83 /* set for periodic (4) and LSB/MSB write (0x30) */ 84 outb(0x34, 0x43); 85 outb((mSEC_10_from_14/6) & 0xFF, 0x40); 86 outb((mSEC_10_from_14/6) >> 8, 0x40); 87 88 setup_irq(IRQ_ISA_TIMER, &isa_timer_irq); 89 } 90 91 struct sys_timer isa_timer = { 92 .init = isa_timer_init, 93 .offset = isa_gettimeoffset, 94 }; 95