/* * The ST_CRTR is updated asynchronously to the master clock ... but * the updates as seen by the CPU don't seem to be strictly monotonic. * Waiting until we read the same value twice avoids glitching.
*/ staticinlineunsignedlong read_CRTR(void)
{ unsignedint x1, x2;
regmap_read(regmap_st, AT91_ST_CRTR, &x1); do {
regmap_read(regmap_st, AT91_ST_CRTR, &x2); if (x1 == x2) break;
x1 = x2;
} while (1); return x1;
}
/* * IRQ handler for the timer.
*/ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
{
u32 sr;
regmap_read(regmap_st, AT91_ST_SR, &sr);
sr &= irqmask;
/* * 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());
/* simulate "oneshot" timer with alarm */ if (sr & AT91_ST_ALMS) {
clkevt.event_handler(&clkevt); return IRQ_HANDLED;
}
/* periodic mode should handle delayed ticks */ if (sr & AT91_ST_PITS) {
u32 crtr = read_CRTR();
/* The alarm IRQ uses absolute time (now+delta), not the relative * time (delta) in our calling convention. Like all clockevents * using such "match" hardware, we have a race to defend against. * * Our defense here is to have set up the clockevent device so the * delta is at least two. That way we never end up writing RTAR * with the value then held in CRTR ... which would mean the match * wouldn't trigger until 32 seconds later, after CRTR wraps.
*/
alm = read_CRTR();
/* Cancel any pending alarm; flush any pending IRQ */
regmap_write(regmap_st, AT91_ST_RTAR, alm);
regmap_read(regmap_st, AT91_ST_SR, &val);
/* * ST (system timer) module supports both clockevents and clocksource.
*/ staticint __init atmel_st_timer_init(struct device_node *node)
{ struct clk *sclk; unsignedint sclk_rate, val; int irq, ret;
regmap_st = syscon_node_to_regmap(node); if (IS_ERR(regmap_st)) {
pr_err("Unable to get regmap\n"); return PTR_ERR(regmap_st);
}
/* Disable all timer interrupts, and clear any pending ones */
regmap_write(regmap_st, AT91_ST_IDR,
AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
regmap_read(regmap_st, AT91_ST_SR, &val);
/* Get the interrupts property */
irq = irq_of_parse_and_map(node, 0); if (!irq) {
pr_err("Unable to get IRQ from DT\n"); return -EINVAL;
}
/* Make IRQs happen for the system timer */
ret = request_irq(irq, at91rm9200_timer_interrupt,
IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, "at91_tick", regmap_st); if (ret) {
pr_err("Unable to setup IRQ\n"); return ret;
}
sclk = of_clk_get(node, 0); if (IS_ERR(sclk)) {
pr_err("Unable to get slow clock\n"); return PTR_ERR(sclk);
}
ret = clk_prepare_enable(sclk); if (ret) {
pr_err("Could not enable slow clock\n"); return ret;
}
/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used * directly for the clocksource and all clockevents, after adjusting * its prescaler from the 1 Hz default.
*/
regmap_write(regmap_st, AT91_ST_RTMR, 1);
/* Setup timer clockevent, with minimum of two ticks (important!!) */
clkevt.cpumask = cpumask_of(0);
clockevents_config_and_register(&clkevt, sclk_rate,
2, AT91_ST_ALMV);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.