2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / mach - footbridge / isa - timer . c
*
* Copyright ( C ) 1998 Russell King .
* Copyright ( C ) 1998 Phil Blundell
*/
# include <linux/init.h>
# include <linux/interrupt.h>
2006-07-02 01:32:17 +04:00
# include <linux/irq.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
# include <asm/irq.h>
# include <asm/mach/time.h>
# include "common.h"
/*
* ISA timer tick support
*/
# define mSEC_10_from_14 ((14318180 + 100) / 200)
static unsigned long isa_gettimeoffset ( void )
{
int count ;
static int count_p = ( mSEC_10_from_14 / 6 ) ; /* for the first call after boot */
static unsigned long jiffies_p = 0 ;
/*
* cache volatile jiffies temporarily ; we have IRQs turned off .
*/
unsigned long jiffies_t ;
/* timer count may underflow right here */
outb_p ( 0x00 , 0x43 ) ; /* latch the count ASAP */
count = inb_p ( 0x40 ) ; /* read the latched count */
/*
* We do this guaranteed double memory access instead of a _p
* postfix in the previous port access . Wheee , hackady hack
*/
jiffies_t = jiffies ;
count | = inb_p ( 0x40 ) < < 8 ;
/* Detect timer underflows. If we haven't had a timer tick since
the last time we were called , and time is apparently going
backwards , the counter must have wrapped during this routine . */
if ( ( jiffies_t = = jiffies_p ) & & ( count > count_p ) )
count - = ( mSEC_10_from_14 / 6 ) ;
else
jiffies_p = jiffies_t ;
count_p = count ;
count = ( ( ( mSEC_10_from_14 / 6 ) - 1 ) - count ) * ( tick_nsec / 1000 ) ;
count = ( count + ( mSEC_10_from_14 / 6 ) / 2 ) / ( mSEC_10_from_14 / 6 ) ;
return count ;
}
static irqreturn_t
2006-10-06 21:53:39 +04:00
isa_timer_interrupt ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
2006-10-06 21:53:39 +04:00
timer_tick ( ) ;
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
static struct irqaction isa_timer_irq = {
. name = " ISA timer tick " ,
. handler = isa_timer_interrupt ,
2007-05-08 11:35:39 +04:00
. flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
2005-04-17 02:20:36 +04:00
} ;
static void __init isa_timer_init ( void )
{
/* enable PIT timer */
/* set for periodic (4) and LSB/MSB write (0x30) */
outb ( 0x34 , 0x43 ) ;
outb ( ( mSEC_10_from_14 / 6 ) & 0xFF , 0x40 ) ;
outb ( ( mSEC_10_from_14 / 6 ) > > 8 , 0x40 ) ;
setup_irq ( IRQ_ISA_TIMER , & isa_timer_irq ) ;
}
struct sys_timer isa_timer = {
. init = isa_timer_init ,
. offset = isa_gettimeoffset ,
} ;