[PATCH 4/7 v2] Add TCC8xxx system timer
Hans J. Koch
hjk at linutronix.de
Sat Mar 27 12:49:20 EDT 2010
On Thu, Mar 25, 2010 at 08:35:15PM +0000, Russell King - ARM Linux wrote:
> On Thu, Mar 25, 2010 at 09:12:48PM +0100, Hans J. Koch wrote:
> > diff --git a/arch/arm/mach-tcc8k/time.c b/arch/arm/mach-tcc8k/time.c
> > new file mode 100644
> > index 0000000..db0a6da
> > --- /dev/null
> > +++ b/arch/arm/mach-tcc8k/time.c
> > @@ -0,0 +1,150 @@
> > +/*
> > + * TCC8000 system timer setup
> > + *
> > + * (C) 2009 Hans J. Koch <hjk at linutronix.de>
> > + *
> > + * Licensed under the terms of the GPL version 2.
> > + *
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/init.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/irq.h>
> > +#include <linux/clk.h>
> > +#include <linux/clockchips.h>
> > +
> > +#include <asm/io.h>
>
> linux/io.h
OK.
>
> > +#include <asm/mach/time.h>
> > +
> > +#include <mach/tcc8k-regs.h>
> > +#include <mach/irqs.h>
> > +
> > +static void __iomem *timer_base;
> > +static struct clock_event_device clockevent_tcc;
>
> You don't need this.
OK.
>
> > +static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
>
> Do you need to keep this state around?
Not really. Removed.
>
> > +
> > +static cycle_t tcc_get_cycles(struct clocksource *cs)
> > +{
> > + return __raw_readl(timer_base + TC32MCNT_OFFS);
> > +}
> > +
> > +static struct clocksource clocksource_tcc = {
> > + .name = "tcc_tc32",
> > + .rating = 200,
> > + .read = tcc_get_cycles,
> > + .mask = CLOCKSOURCE_MASK(32),
> > + .shift = 28,
> > + .flags = CLOCK_SOURCE_IS_CONTINUOUS,
> > +};
> > +
> > +static int tcc_set_next_event(unsigned long evt,
> > + struct clock_event_device *unused)
> > +{
> > + unsigned long reg = __raw_readl(timer_base + TC32MCNT_OFFS);
> > +
> > + __raw_writel(reg + evt, timer_base + TC32CMP0_OFFS);
> > + return 0;
> > +}
> > +
> > +static void tcc_set_mode(enum clock_event_mode mode,
> > + struct clock_event_device *evt)
> > +{
> > + unsigned long tc32irq;
> > +
> > + clockevent_mode = mode;
> > +
> > + switch (mode) {
> > + case CLOCK_EVT_MODE_ONESHOT:
> > + tc32irq = __raw_readl(timer_base + TC32IRQ_OFFS);
> > + tc32irq |= TC32IRQ_IRQEN0;
> > + __raw_writel(tc32irq, timer_base + TC32IRQ_OFFS);
> > + break;
> > + case CLOCK_EVT_MODE_SHUTDOWN:
> > + case CLOCK_EVT_MODE_UNUSED:
> > + tc32irq = __raw_readl(timer_base + TC32IRQ_OFFS);
> > + tc32irq &= ~TC32IRQ_IRQEN0;
> > + __raw_writel(tc32irq, timer_base + TC32IRQ_OFFS);
> > + break;
> > + case CLOCK_EVT_MODE_PERIODIC:
> > + case CLOCK_EVT_MODE_RESUME:
> > + break;
> > + }
> > +}
> > +
> > +static irqreturn_t tcc8k_timer_interrupt(int irq, void *dev_id)
> > +{
> > + struct clock_event_device *evt = &clockevent_tcc;
>
> Change this to:
> struct clock_event_device *evt = dev_id;
Done.
>
> > +
> > + /* Acknowledge TC32 interrupt by reading TC32IRQ */
> > + __raw_readl(timer_base + TC32IRQ_OFFS);
> > +
> > + evt->event_handler(evt);
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static struct irqaction tcc8k_timer_irq = {
> > + .name = "TC32_timer",
> > + .flags = IRQF_DISABLED | IRQF_TIMER,
> > + .handler = tcc8k_timer_interrupt,
> > +};
> > +
> > +static struct clock_event_device clockevent_tcc = {
> > + .name = "tcc_timer1",
> > + .features = CLOCK_EVT_FEAT_ONESHOT,
> > + .shift = 32,
> > + .set_mode = tcc_set_mode,
> > + .set_next_event = tcc_set_next_event,
> > + .rating = 200,
> > +};
>
> And add:
> static struct irqaction tcc8k_timer_irq = {
> .name = "TC32_timer",
> .flags = IRQF_DISABLED | IRQF_TIMER,
> .handler = tcc8k_timer_interrupt,
> + .dev_id = &clockevent_tcc,
> };
OK, done.
Thanks,
Hans
More information about the linux-arm-kernel
mailing list