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> 10fced80c7SRussell King #include <linux/io.h> 111da177e4SLinus Torvalds 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 { 670cd61b68SLinus Torvalds timer_tick(); 681da177e4SLinus Torvalds return IRQ_HANDLED; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds static struct irqaction isa_timer_irq = { 721da177e4SLinus Torvalds .name = "ISA timer tick", 731da177e4SLinus Torvalds .handler = isa_timer_interrupt, 74b30fabadSBernhard Walle .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 751da177e4SLinus Torvalds }; 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds static void __init isa_timer_init(void) 781da177e4SLinus Torvalds { 791da177e4SLinus Torvalds isa_rtc_init(); 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds /* enable PIT timer */ 821da177e4SLinus Torvalds /* set for periodic (4) and LSB/MSB write (0x30) */ 831da177e4SLinus Torvalds outb(0x34, 0x43); 841da177e4SLinus Torvalds outb((mSEC_10_from_14/6) & 0xFF, 0x40); 851da177e4SLinus Torvalds outb((mSEC_10_from_14/6) >> 8, 0x40); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds setup_irq(IRQ_ISA_TIMER, &isa_timer_irq); 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds struct sys_timer isa_timer = { 911da177e4SLinus Torvalds .init = isa_timer_init, 921da177e4SLinus Torvalds .offset = isa_gettimeoffset, 931da177e4SLinus Torvalds }; 94