[PATCH 4/7 v2] Add TCC8xxx system timer

Russell King - ARM Linux linux at arm.linux.org.uk
Thu Mar 25 16:35:15 EDT 2010


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

> +#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.

> +static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;

Do you need to keep this state around?

> +
> +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;

> +
> +	/* 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,
 };



More information about the linux-arm-kernel mailing list