/* * IRQ handler for the timer. */ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) { /* * irqs should be disabled here, but as the irq is shared they are only * guaranteed to be off if the timer irq is registered first. */ WARN_ON_ONCE(!irqs_disabled()); /* The PIT interrupt may be disabled, and is shared */ if ((pit_clkevt.mode == CLOCK_EVT_MODE_PERIODIC) && (pit_read(AT91_PIT_SR) & AT91_PIT_PITS)) { unsigned nr_ticks; /* Get number of ticks performed before irq, and ack it */ nr_ticks = PIT_PICNT(pit_read(AT91_PIT_PIVR)); do { pit_cnt += pit_cycle; pit_clkevt.event_handler(&pit_clkevt); nr_ticks--; } while (nr_ticks); return IRQ_HANDLED; } return IRQ_NONE; }
static void at91sam926x_pit_reset(void) { /* Disable timer and irqs */ pit_write(AT91_PIT_MR, 0); /* Clear any pending interrupts, wait for PIT to stop counting */ while (PIT_CPIV(pit_read(AT91_PIT_PIVR)) != 0) cpu_relax(); /* Start PIT but don't enable IRQ */ pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN); }
int osenv_timer_pit_read() { int enb; int value; enb = osenv_intr_save_disable(); value = pit_read(0); if (enb) osenv_intr_enable(); return value; }
/* * Clocksource: just a monotonic counter of MCK/16 cycles. * We don't care whether or not PIT irqs are enabled. */ static cycle_t read_pit_clk(struct clocksource *cs) { unsigned long flags; u32 elapsed; u32 t; raw_local_irq_save(flags); elapsed = pit_cnt; t = pit_read(AT91_PIT_PIIR); raw_local_irq_restore(flags); elapsed += PIT_PICNT(t) * pit_cycle; elapsed += PIT_CPIV(t); return elapsed; }
unsigned int timer_read(tim_t dev) { if ((unsigned int)dev >= TIMER_NUMOF) { /* invalid timer */ return 0; } /* demultiplex to handle two types of hardware timers */ switch (_timer_variant(dev)) { case TIMER_PIT: return pit_read(_pit_index(dev)); case TIMER_LPTMR: return lptmr_read(_lptmr_index(dev)); default: return 0; } }
/* * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16) */ static void pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) { switch (mode) { case CLOCK_EVT_MODE_PERIODIC: /* update clocksource counter */ pit_cnt += pit_cycle * PIT_PICNT(pit_read(AT91_PIT_PIVR)); pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN); break; case CLOCK_EVT_MODE_ONESHOT: BUG(); /* FALLTHROUGH */ case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_UNUSED: /* disable irq, leaving the clocksource active */ pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN); break; case CLOCK_EVT_MODE_RESUME: break; } }
TIME ll_gettime(int mode, struct timespec *tsres) { DWORD res, tc; BYTE isr; struct timespec tmp; #if 1 if (activeEvent) { if (tsres != NULL) { PITSPEC2TIMESPEC(&globalCounter, tsres); } else { struct timespec tmp; PITSPEC2TIMESPEC(&globalCounter, &tmp); return TIMESPEC2USEC(&tmp); } return TIMESPEC2USEC(tsres); } #endif if (mode == TIME_PTICK) { if (timermode != LL_PERIODIC) { return 0; } res = TIMESPEC2USEC(&actTime); if (tsres != NULL) { memcpy(tsres, &actTime, sizeof(struct timespec)); } return res; } if (mode == TIME_NEW) { WORD tmp; tmp = pit_read(frc); ADDPITSPEC((WORD)(lastTime - tmp), &globalCounter); lastTime = tmp; if (tsres != NULL) { PITSPEC2TIMESPEC(&globalCounter, tsres); } return (PITSPEC2USEC(&globalCounter)); } if (mode == TIME_EXACT) { if (timermode == LL_PERIODIC) { memcpy(&tmp, &actTime, sizeof(struct timespec)); /* How much time has elapsed * from the last Tick Boundary? */ tc = pit_read(0); if (tc > pit_time_const) { error("LL Time Panic!!!\n"); ll_abort(1); } res = pit_time_const - tc; res *= ticksize; res /= pit_time_const; /* Detect tick boundary and adjust the time... */ outp(0x20, 0x0A); isr = inp(0x20); if ((isr & 1) && res < ((8*ticksize)/10)){ /* res += ticksize; ADDNANO2TIMESPEC(ticksize * 1000, &tmp); */ res = ticksize; } /* Sum the Tick time... */ ADDNANO2TIMESPEC(res * 1000, &tmp); res += TIMESPEC2USEC(&actTime); if (tsres != NULL) { memcpy(tsres, &tmp, sizeof(struct timespec)); } return res; } else { return 0; } } return 0; }