2006-06-26 15:25:12 +08: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 15:25:15 +08:00
|
|
|
#define HPET_MASK CLOCKSOURCE_MASK(32)
|
2006-06-26 15:25:12 +08:00
|
|
|
#define HPET_SHIFT 22
|
|
|
|
|
|
|
|
/* FSEC = 10^-15 NSEC = 10^-9 */
|
|
|
|
#define FSEC_PER_NSEC 1000000
|
|
|
|
|
2007-02-10 00:39:15 +08:00
|
|
|
static void __iomem *hpet_ptr;
|
2006-06-26 15:25:12 +08:00
|
|
|
|
|
|
|
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 15:25:15 +08:00
|
|
|
.mask = HPET_MASK,
|
2006-06-26 15:25:12 +08: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 09:14:02 +08:00
|
|
|
int err;
|
2006-06-26 15:25:12 +08:00
|
|
|
|
2006-09-01 12:27:37 +08:00
|
|
|
if (!is_hpet_enabled())
|
2006-06-26 15:25:12 +08:00
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
/* calculate the hpet address: */
|
2007-02-10 00:39:15 +08:00
|
|
|
hpet_base = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
|
2006-06-26 15:25:12 +08:00
|
|
|
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 * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
|
|
|
|
* fsec/cyc * 1ns/1000000fsec * 2^shift = mult
|
|
|
|
* fsec/cyc * 2^shift * 1nsec/1000000fsec = 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 09:14:02 +08:00
|
|
|
err = clocksource_register(&clocksource_hpet);
|
|
|
|
if (err)
|
|
|
|
iounmap(hpet_base);
|
|
|
|
|
|
|
|
return err;
|
2006-06-26 15:25:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(init_hpet_clocksource);
|