diff options
Diffstat (limited to 'arch/arm/plat-orion/time.c')
| -rw-r--r-- | arch/arm/plat-orion/time.c | 121 |
1 files changed, 67 insertions, 54 deletions
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c index 9d2b2ac74938..509d4824dc1c 100644 --- a/arch/arm/plat-orion/time.c +++ b/arch/arm/plat-orion/time.c @@ -17,6 +17,8 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/sched_clock.h> +#include <plat/time.h> +#include <asm/delay.h> /* * MBus bridge block registers. @@ -60,7 +62,7 @@ static u32 ticks_per_jiffy; * at least 7.5ns (133MHz TCLK). */ -static u32 notrace orion_read_sched_clock(void) +static u64 notrace orion_read_sched_clock(void) { return ~readl(timer_base + TIMER0_VAL_OFF); } @@ -105,60 +107,63 @@ orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev) return 0; } -static void -orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) +static int orion_clkevt_shutdown(struct clock_event_device *evt) { unsigned long flags; u32 u; local_irq_save(flags); - if (mode == CLOCK_EVT_MODE_PERIODIC) { - /* - * Setup timer to fire at 1/HZ intervals. - */ - writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF); - writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF); - - /* - * Enable timer interrupt. - */ - u = readl(bridge_base + BRIDGE_MASK_OFF); - writel(u | BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); - - /* - * Enable timer. - */ - u = readl(timer_base + TIMER_CTRL_OFF); - writel(u | TIMER1_EN | TIMER1_RELOAD_EN, - timer_base + TIMER_CTRL_OFF); - } else { - /* - * Disable timer. - */ - u = readl(timer_base + TIMER_CTRL_OFF); - writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF); - - /* - * Disable timer interrupt. - */ - u = readl(bridge_base + BRIDGE_MASK_OFF); - writel(u & ~BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); - - /* - * ACK pending timer interrupt. - */ - writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); - - } + + /* Disable timer */ + u = readl(timer_base + TIMER_CTRL_OFF); + writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF); + + /* Disable timer interrupt */ + u = readl(bridge_base + BRIDGE_MASK_OFF); + writel(u & ~BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); + + /* ACK pending timer interrupt */ + writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); + + local_irq_restore(flags); + + return 0; +} + +static int orion_clkevt_set_periodic(struct clock_event_device *evt) +{ + unsigned long flags; + u32 u; + + local_irq_save(flags); + + /* Setup timer to fire at 1/HZ intervals */ + writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF); + writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF); + + /* Enable timer interrupt */ + u = readl(bridge_base + BRIDGE_MASK_OFF); + writel(u | BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); + + /* Enable timer */ + u = readl(timer_base + TIMER_CTRL_OFF); + writel(u | TIMER1_EN | TIMER1_RELOAD_EN, timer_base + TIMER_CTRL_OFF); + local_irq_restore(flags); + + return 0; } static struct clock_event_device orion_clkevt = { - .name = "orion_tick", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .rating = 300, - .set_next_event = orion_clkevt_next_event, - .set_mode = orion_clkevt_mode, + .name = "orion_tick", + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC, + .rating = 300, + .set_next_event = orion_clkevt_next_event, + .set_state_shutdown = orion_clkevt_shutdown, + .set_state_periodic = orion_clkevt_set_periodic, + .set_state_oneshot = orion_clkevt_shutdown, + .tick_resume = orion_clkevt_shutdown, }; static irqreturn_t orion_timer_interrupt(int irq, void *dev_id) @@ -172,18 +177,21 @@ static irqreturn_t orion_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction orion_timer_irq = { - .name = "orion_tick", - .flags = IRQF_DISABLED | IRQF_TIMER, - .handler = orion_timer_interrupt -}; - void __init orion_time_set_base(void __iomem *_timer_base) { timer_base = _timer_base; } +static unsigned long orion_delay_timer_read(void) +{ + return ~readl(timer_base + TIMER0_VAL_OFF); +} + +static struct delay_timer orion_delay_timer = { + .read_current_timer = orion_delay_timer_read, +}; + void __init orion_time_init(void __iomem *_bridge_base, u32 _bridge_timer1_clr_mask, unsigned int irq, unsigned int tclk) @@ -198,10 +206,13 @@ orion_time_init(void __iomem *_bridge_base, u32 _bridge_timer1_clr_mask, ticks_per_jiffy = (tclk + HZ/2) / HZ; + orion_delay_timer.freq = tclk; + register_current_timer_delay(&orion_delay_timer); + /* * Set scale and timer for sched_clock. */ - setup_sched_clock(orion_read_sched_clock, 32, tclk); + sched_clock_register(orion_read_sched_clock, 32, tclk); /* * Setup free-running clocksource timer (interrupts @@ -219,7 +230,9 @@ orion_time_init(void __iomem *_bridge_base, u32 _bridge_timer1_clr_mask, /* * Setup clockevent timer (interrupt-driven). */ - setup_irq(irq, &orion_timer_irq); + if (request_irq(irq, orion_timer_interrupt, IRQF_TIMER, "orion_tick", + NULL)) + pr_err("Failed to request irq %u (orion_tick)\n", irq); orion_clkevt.cpumask = cpumask_of(0); clockevents_config_and_register(&orion_clkevt, tclk, 1, 0xfffffffe); } |
