2006-06-26 00:25:12 -07:00
# include <linux/clocksource.h>
# include <linux/errno.h>
# include <linux/hpet.h>
# include <linux/init.h>
# include <asm/hpet.h>
# include <asm/io.h>
2006-06-26 00:25:15 -07:00
# define HPET_MASK CLOCKSOURCE_MASK(32)
2006-06-26 00:25:12 -07:00
# define HPET_SHIFT 22
/* FSEC = 10^-15 NSEC = 10^-9 */
# define FSEC_PER_NSEC 1000000
static void * hpet_ptr ;
static cycle_t read_hpet ( void )
{
return ( cycle_t ) readl ( hpet_ptr ) ;
}
static struct clocksource clocksource_hpet = {
. name = " hpet " ,
. rating = 250 ,
. read = read_hpet ,
2006-06-26 00:25:15 -07:00
. mask = HPET_MASK ,
2006-06-26 00:25:12 -07:00
. mult = 0 , /* set below */
. shift = HPET_SHIFT ,
. is_continuous = 1 ,
} ;
static int __init init_hpet_clocksource ( void )
{
unsigned long hpet_period ;
void __iomem * hpet_base ;
u64 tmp ;
2006-12-07 02:14:02 +01:00
int err ;
2006-06-26 00:25:12 -07:00
2006-08-31 21:27:37 -07:00
if ( ! is_hpet_enabled ( ) )
2006-06-26 00:25:12 -07:00
return - ENODEV ;
/* calculate the hpet address: */
hpet_base =
( void __iomem * ) ioremap_nocache ( hpet_address , HPET_MMAP_SIZE ) ;
hpet_ptr = hpet_base + HPET_COUNTER ;
/* calculate the frequency: */
hpet_period = readl ( hpet_base + HPET_PERIOD ) ;
/*
* hpet period is in femto seconds per cycle
* so we need to convert this to ns / cyc units
* aproximated by mult / 2 ^ shift
*
* fsec / cyc * 1 nsec / 1000000f sec = nsec / cyc = mult / 2 ^ shift
* fsec / cyc * 1 ns / 1000000f sec * 2 ^ shift = mult
* fsec / cyc * 2 ^ shift * 1 nsec / 1000000f sec = mult
* ( fsec / cyc < < shift ) / 1000000 = mult
* ( hpet_period < < shift ) / FSEC_PER_NSEC = mult
*/
tmp = ( u64 ) hpet_period < < HPET_SHIFT ;
do_div ( tmp , FSEC_PER_NSEC ) ;
clocksource_hpet . mult = ( u32 ) tmp ;
2006-12-07 02:14:02 +01:00
err = clocksource_register ( & clocksource_hpet ) ;
if ( err )
iounmap ( hpet_base ) ;
return err ;
2006-06-26 00:25:12 -07:00
}
module_init ( init_hpet_clocksource ) ;