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