[RFC/RFT 2/3] iop: clockevent support
Russell King - ARM Linux
linux at arm.linux.org.uk
Tue Sep 1 08:25:11 EDT 2009
On Sat, Aug 22, 2009 at 02:05:29PM +0200, Mikael Pettersson wrote:
> +/*
> + * IOP clockevents (interrupting timer 0).
> + */
> +static int iop_set_next_event(unsigned long delta,
> + struct clock_event_device *unused)
> +{
> + u32 tmr = IOP_TMR_EN | IOP_TMR_PRIVILEGED
> + | IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
> +
> + BUG_ON(delta == 0);
> + write_tmr0(tmr & ~(IOP_TMR_EN | IOP_TMR_RELOAD));
> + write_tcr0(delta);
> + write_tmr0((tmr & ~IOP_TMR_RELOAD) | IOP_TMR_EN);
Hmm, not sure you should be clearing TMR_RELOAD here. I thought
periodic clock events were initialized by a call to set_mode followed
by a call to set_next_event.
> +static void iop_set_mode(enum clock_event_mode mode,
> + struct clock_event_device *unused)
> +{
> + u32 tmr = IOP_TMR_EN | IOP_TMR_PRIVILEGED
> + | IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
> +
> + switch (mode) {
> + case CLOCK_EVT_MODE_PERIODIC:
> + write_tmr0(tmr & ~IOP_TMR_EN);
> + write_tcr0(ticks_per_jiffy - 1);
> + tmr |= (IOP_TMR_RELOAD | IOP_TMR_EN);
> + break;
> + case CLOCK_EVT_MODE_ONESHOT:
> + /* ->set_next_event sets period and enables timer */
> + tmr &= ~(IOP_TMR_RELOAD | IOP_TMR_EN);
> + break;
> + case CLOCK_EVT_MODE_RESUME:
> + tmr |= IOP_TMR_EN;
> + break;
> + case CLOCK_EVT_MODE_SHUTDOWN:
> + case CLOCK_EVT_MODE_UNUSED:
> + default:
> + tmr &= ~IOP_TMR_EN;
Doesn't this result in the clock mode being overwritten upon
resume/shutdown? tmr, being a local variable, will always be
initialized with IOP_TMR_RELOAD etc.
> + break;
> + }
> +
> + write_tmr0(tmr);
> +}
> +
> +static struct clock_event_device iop_clockevent = {
> + .name = "iop_timer0",
> + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> + .rating = 300,
> + .shift = 20, /* ??? crude guesstimate */
> + .set_next_event = iop_set_next_event,
> + .set_mode = iop_set_mode,
> +};
> +
> static unsigned long ticks_per_usec;
> static unsigned long next_jiffy_time;
>
> @@ -75,13 +132,12 @@ unsigned long iop_gettimeoffset(void)
> static irqreturn_t
> iop_timer_interrupt(int irq, void *dev_id)
> {
> + struct clock_event_device *evt;
> +
> write_tisr(1);
>
> - while ((signed long)(next_jiffy_time - read_tcr1())
> - >= ticks_per_jiffy) {
> - timer_tick();
> - next_jiffy_time -= ticks_per_jiffy;
> - }
> + evt = &iop_clockevent;
You can use 'dev_id' here, and when registering the interrupt, pass
iop_clockevent via the dev_id field in iop_timer_irq.
More information about the linux-arm-kernel
mailing list