void hpet_init(void) { uint64_t reg; uint64_t s1, s2; int same = 0; /* Disable the counter. */ reg = hpet_read(HPET_REG_CONFIG); reg &= ~(HPET_LEG_RT_CNF|HPET_ENABLE_CNF); hpet_write(HPET_REG_CONFIG, reg); /* Reset the counter value. */ hpet_write(HPET_REG_COUNTER, 0); /* Re-enable the counter. */ reg |= HPET_ENABLE_CNF; hpet_write(HPET_REG_CONFIG, reg); /* See whether the hardware actually works. */ s1 = hpet_read(HPET_REG_COUNTER); for (;;) { s2 = hpet_read(HPET_REG_COUNTER); if (s1 != s2) break; if (++same == 1000) panic("HPET timer missing"); } }
static int hpet_set_state_periodic(struct clock_event_device *evt) { int cfg; spin_lock(&hpet_lock); pr_info("set clock event to periodic mode!\n"); /* stop counter */ hpet_stop_counter(); /* enables the timer0 to generate a periodic interrupt */ cfg = hpet_read(HPET_T0_CFG); cfg &= ~HPET_TN_LEVEL; cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | HPET_TN_32BIT; hpet_write(HPET_T0_CFG, cfg); /* set the comparator */ hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); udelay(1); hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); /* start counter */ hpet_start_counter(); spin_unlock(&hpet_lock); return 0; }
static void hpet_stop_counter(void) { unsigned int cfg = hpet_read(HPET_CFG); cfg &= ~HPET_CFG_ENABLE; hpet_write(HPET_CFG, cfg); }
static int hpet_set_state_shutdown(struct clock_event_device *evt) { int cfg; spin_lock(&hpet_lock); cfg = hpet_read(HPET_T0_CFG); cfg &= ~HPET_TN_ENABLE; hpet_write(HPET_T0_CFG, cfg); spin_unlock(&hpet_lock); return 0; }
static int hpet_next_event(unsigned long delta, struct clock_event_device *evt) { u32 cnt; s32 res; cnt = hpet_read(HPET_COUNTER); cnt += (u32) delta; hpet_write(HPET_T0_CMP, cnt); res = (s32)(cnt - hpet_read(HPET_COUNTER)); return res < HPET_MIN_CYCLES ? -ETIME : 0; }
static irqreturn_t hpet_irq_handler(int irq, void *data) { int is_irq; struct clock_event_device *cd; unsigned int cpu = smp_processor_id(); is_irq = hpet_read(HPET_STATUS); if (is_irq & HPET_T0_IRS) { /* clear the TIMER0 irq status register */ hpet_write(HPET_STATUS, HPET_T0_IRS); cd = &per_cpu(hpet_clockevent_device, cpu); cd->event_handler(cd); return IRQ_HANDLED; } return IRQ_NONE; }
static int hpet_set_state_oneshot(struct clock_event_device *evt) { int cfg; spin_lock(&hpet_lock); pr_info("set clock event to one shot mode!\n"); cfg = hpet_read(HPET_T0_CFG); /* * set timer0 type * 1 : periodic interrupt * 0 : non-periodic(oneshot) interrupt */ cfg &= ~HPET_TN_PERIODIC; cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; hpet_write(HPET_T0_CFG, cfg); spin_unlock(&hpet_lock); return 0; }
static void hpet_reset_counter(void) { hpet_write(HPET_COUNTER, 0); hpet_write(HPET_COUNTER + 4, 0); }