/** * gtm_get_timer16 - request GTM timer to use it with the rest of GTM API * Context: non-IRQ * * This function reserves GTM timer for later use. It returns gtm_timer * structure to use with the rest of GTM API, you should use timer->irq * to manage timer interrupt.
*/ struct gtm_timer *gtm_get_timer16(void)
{ struct gtm *gtm; int i;
for (i = 0; i < ARRAY_SIZE(gtm->timers); i++) { if (!gtm->timers[i].requested) {
gtm->timers[i].requested = true;
spin_unlock_irq(>m->lock); return >m->timers[i];
}
}
spin_unlock_irq(>m->lock);
}
if (!list_empty(>ms)) return ERR_PTR(-EBUSY); return ERR_PTR(-ENODEV);
}
EXPORT_SYMBOL(gtm_get_timer16);
/** * gtm_get_specific_timer16 - request specific GTM timer * @gtm: specific GTM, pass here GTM's device_node->data * @timer: specific timer number, Timer1 is 0. * Context: non-IRQ * * This function reserves GTM timer for later use. It returns gtm_timer * structure to use with the rest of GTM API, you should use timer->irq * to manage timer interrupt.
*/ struct gtm_timer *gtm_get_specific_timer16(struct gtm *gtm, unsignedint timer)
{ struct gtm_timer *ret = ERR_PTR(-EBUSY);
/** * gtm_put_timer16 - release 16 bits GTM timer * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer * Context: any * * This function releases GTM timer so others may request it.
*/ void gtm_put_timer16(struct gtm_timer *tmr)
{
gtm_stop_timer16(tmr);
/* * This is back-end for the exported functions, it's used to reset single * timer in reference mode.
*/ staticint gtm_set_ref_timer16(struct gtm_timer *tmr, int frequency, int reference_value, bool free_run)
{ struct gtm *gtm = tmr->gtm; int num = tmr - >m->timers[0]; unsignedint prescaler;
u8 iclk = GTMDR_ICLK_ICLK;
u8 psr;
u8 sps; unsignedlong flags; int max_prescaler = 256 * 256 * 16;
/* CPM2 doesn't have primary prescaler */ if (!tmr->gtpsr)
max_prescaler /= 256;
prescaler = gtm->clock / frequency; /* * We have two 8 bit prescalers -- primary and secondary (psr, sps), * plus "slow go" mode (clk / 16). So, total prescale value is * 16 * (psr + 1) * (sps + 1). Though, for CPM2 GTMs we losing psr.
*/ if (prescaler > max_prescaler) return -EINVAL;
/* Let it be. */
clrbits8(tmr->gtcfr, GTCFR_STP(num));
spin_unlock_irqrestore(>m->lock, flags);
return 0;
}
/** * gtm_set_timer16 - (re)set 16 bit timer with arbitrary precision * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer * @usec: timer interval in microseconds * @reload: if set, the timer will reset upon expiry rather than * continue running free. * Context: any * * This function (re)sets the GTM timer so that it counts up to the requested * interval value, and fires the interrupt when the value is reached. This * function will reduce the precision of the timer as needed in order for the * requested timeout to fit in a 16-bit register.
*/ int gtm_set_timer16(struct gtm_timer *tmr, unsignedlong usec, bool reload)
{ /* quite obvious, frequency which is enough for µSec precision */ int freq = 1000000; unsignedint bit;
bit = fls_long(usec); if (bit > 15) {
freq >>= bit - 15;
usec >>= bit - 15;
}
/** * gtm_set_exact_timer16 - (re)set 16 bits timer * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer * @usec: timer interval in microseconds * @reload: if set, the timer will reset upon expiry rather than * continue running free. * Context: any * * This function (re)sets GTM timer so that it counts up to the requested * interval value, and fires the interrupt when the value is reached. If reload * flag was set, timer will also reset itself upon reference value, otherwise * it continues to increment. * * The _exact_ bit in the function name states that this function will not * crop precision of the "usec" argument, thus usec is limited to 16 bits * (single timer width).
*/ int gtm_set_exact_timer16(struct gtm_timer *tmr, u16 usec, bool reload)
{ /* quite obvious, frequency which is enough for µSec precision */ constint freq = 1000000;
/* * We can lower the frequency (and probably power consumption) by * dividing both frequency and usec by 2 until there is no remainder. * But we won't bother with this unless savings are measured, so just * run the timer as is.
*/
/** * gtm_stop_timer16 - stop single timer * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer * Context: any * * This function simply stops the GTM timer.
*/ void gtm_stop_timer16(struct gtm_timer *tmr)
{ struct gtm *gtm = tmr->gtm; int num = tmr - >m->timers[0]; unsignedlong flags;
/** * gtm_ack_timer16 - acknowledge timer event (free-run timers only) * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer * @events: events mask to ack * Context: any * * Thus function used to acknowledge timer interrupt event, use it inside the * interrupt handler.
*/ void gtm_ack_timer16(struct gtm_timer *tmr, u16 events)
{
out_be16(tmr->gtevr, events);
}
EXPORT_SYMBOL(gtm_ack_timer16);
staticvoid __init gtm_set_shortcuts(struct device_node *np, struct gtm_timer *timers, struct gtm_timers_regs __iomem *regs)
{ /* * Yeah, I don't like this either, but timers' registers a bit messed, * so we have to provide shortcuts to write timer independent code. * Alternative option is to create gt*() accessors, but that will be * even uglier and cryptic.
*/
timers[0].gtcfr = ®s->gtcfr1;
timers[0].gtmdr = ®s->gtmdr1;
timers[0].gtcnr = ®s->gtcnr1;
timers[0].gtrfr = ®s->gtrfr1;
timers[0].gtevr = ®s->gtevr1;
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.