[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