/* * linux/arch/arm/mach-ebsa110/time.c * * Copyright (C) 2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #define PIT_CTRL (PIT_BASE + 0x0d) #define PIT_T2 (PIT_BASE + 0x09) #define PIT_T1 (PIT_BASE + 0x05) #define PIT_T0 (PIT_BASE + 0x01) /* * This is the rate at which your MCLK signal toggles (in Hz) * This was measured on a 10 digit frequency counter sampling * over 1 second. */ #define MCLK 47894000 /* * This is the rate at which the PIT timers get clocked */ #define CLKBY7 (MCLK / 7) /* * If CLKBY7 is larger than this, then we must do software * division of the timer interrupt. */ #if CLKBY7 > 6553500 #define DIVISOR 2 #else #define DIVISOR 1 #endif /* * This is the counter value */ #define COUNT ((CLKBY7 + (DIVISOR * HZ / 2)) / (DIVISOR * HZ)) extern unsigned long (*gettimeoffset)(void); static unsigned long divisor; /* * Get the time offset from the system PIT. Note that if we have missed an * interrupt, then the PIT counter will roll over (ie, be negative). * This actually works out to be convenient. */ static unsigned long ebsa110_gettimeoffset(void) { unsigned long offset, count; __raw_writeb(0x40, PIT_CTRL); count = __raw_readb(PIT_T1); count |= __raw_readb(PIT_T1) << 8; /* * If count > COUNT, make the number negative. */ if (count > COUNT) count |= 0xffff0000; offset = COUNT * (DIVISOR - divisor); offset -= count; /* * `offset' is in units of timer counts. Convert * offset to units of microseconds. */ offset = offset * (1000000 / HZ) / (COUNT * DIVISOR); return offset; } int ebsa110_reset_timer(void) { u32 count; /* latch and read timer 1 */ __raw_writeb(0x40, PIT_CTRL); count = __raw_readb(PIT_T1); count |= __raw_readb(PIT_T1) << 8; count += COUNT; __raw_writeb(count & 0xff, PIT_T1); __raw_writeb(count >> 8, PIT_T1); if (divisor == 0) divisor = DIVISOR; divisor -= 1; return divisor; } void __init ebsa110_setup_timer(void) { /* * Timer 1, mode 2, LSB/MSB */ __raw_writeb(0x70, PIT_CTRL); __raw_writeb(COUNT & 0xff, PIT_T1); __raw_writeb(COUNT >> 8, PIT_T1); divisor = DIVISOR - 1; gettimeoffset = ebsa110_gettimeoffset; }