11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/arch/arm/mach-footbridge/isa-timer.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1998 Russell King. 51da177e4SLinus Torvalds * Copyright (C) 1998 Phil Blundell 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds #include <linux/init.h> 81da177e4SLinus Torvalds #include <linux/interrupt.h> 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include <asm/io.h> 111da177e4SLinus Torvalds #include <asm/irq.h> 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds #include <asm/mach/time.h> 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include "common.h" 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds /* 181da177e4SLinus Torvalds * ISA timer tick support 191da177e4SLinus Torvalds */ 201da177e4SLinus Torvalds #define mSEC_10_from_14 ((14318180 + 100) / 200) 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds static unsigned long isa_gettimeoffset(void) 231da177e4SLinus Torvalds { 241da177e4SLinus Torvalds int count; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds static int count_p = (mSEC_10_from_14/6); /* for the first call after boot */ 271da177e4SLinus Torvalds static unsigned long jiffies_p = 0; 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds /* 301da177e4SLinus Torvalds * cache volatile jiffies temporarily; we have IRQs turned off. 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds unsigned long jiffies_t; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* timer count may underflow right here */ 351da177e4SLinus Torvalds outb_p(0x00, 0x43); /* latch the count ASAP */ 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds count = inb_p(0x40); /* read the latched count */ 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* 401da177e4SLinus Torvalds * We do this guaranteed double memory access instead of a _p 411da177e4SLinus Torvalds * postfix in the previous port access. Wheee, hackady hack 421da177e4SLinus Torvalds */ 431da177e4SLinus Torvalds jiffies_t = jiffies; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds count |= inb_p(0x40) << 8; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds /* Detect timer underflows. If we haven't had a timer tick since 481da177e4SLinus Torvalds the last time we were called, and time is apparently going 491da177e4SLinus Torvalds backwards, the counter must have wrapped during this routine. */ 501da177e4SLinus Torvalds if ((jiffies_t == jiffies_p) && (count > count_p)) 511da177e4SLinus Torvalds count -= (mSEC_10_from_14/6); 521da177e4SLinus Torvalds else 531da177e4SLinus Torvalds jiffies_p = jiffies_t; 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds count_p = count; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000); 581da177e4SLinus Torvalds count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds return count; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds static irqreturn_t 641da177e4SLinus Torvalds isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 651da177e4SLinus Torvalds { 661da177e4SLinus Torvalds write_seqlock(&xtime_lock); 671da177e4SLinus Torvalds timer_tick(regs); 681da177e4SLinus Torvalds write_sequnlock(&xtime_lock); 691da177e4SLinus Torvalds return IRQ_HANDLED; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds static struct irqaction isa_timer_irq = { 731da177e4SLinus Torvalds .name = "ISA timer tick", 741da177e4SLinus Torvalds .handler = isa_timer_interrupt, 751da177e4SLinus Torvalds .flags = SA_INTERRUPT, 761da177e4SLinus Torvalds }; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds static void __init isa_timer_init(void) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds isa_rtc_init(); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* enable PIT timer */ 831da177e4SLinus Torvalds /* set for periodic (4) and LSB/MSB write (0x30) */ 841da177e4SLinus Torvalds outb(0x34, 0x43); 851da177e4SLinus Torvalds outb((mSEC_10_from_14/6) & 0xFF, 0x40); 861da177e4SLinus Torvalds outb((mSEC_10_from_14/6) >> 8, 0x40); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds setup_irq(IRQ_ISA_TIMER, &isa_timer_irq); 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds struct sys_timer isa_timer = { 921da177e4SLinus Torvalds .init = isa_timer_init, 931da177e4SLinus Torvalds .offset = isa_gettimeoffset, 941da177e4SLinus Torvalds }; 95