X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fplat-omap%2Ftimer32k.c;h=2653106011618b2a2279eb894298b8390ff2c1ed;hb=refs%2Fheads%2Fvserver;hp=b2a943bf11ef98f4a8eb5789102a9f968244de90;hpb=16cf0ec7408f389279d413869e94c1a351392f97;p=linux-2.6.git diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c index b2a943bf1..265310601 100644 --- a/arch/arm/plat-omap/timer32k.c +++ b/arch/arm/plat-omap/timer32k.c @@ -7,6 +7,7 @@ * Partial timer rewrite and additional dynamic tick timer support by * Tony Lindgen and * Tuukka Tikkanen + * OMAP Dual-mode timer framework support by Timo Teras * * MPU timer code based on the older MPU timer code for OMAP * Copyright (C) 2000 RidgeRun, Inc. @@ -33,7 +34,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include @@ -50,6 +50,7 @@ #include #include #include +#include struct sys_timer omap_timer; @@ -79,18 +80,6 @@ struct sys_timer omap_timer; #define OMAP1_32K_TIMER_TVR 0x00 #define OMAP1_32K_TIMER_TCR 0x04 -/* 24xx specific defines */ -#define OMAP2_GP_TIMER_BASE 0x48028000 -#define CM_CLKSEL_WKUP 0x48008440 -#define GP_TIMER_TIDR 0x00 -#define GP_TIMER_TISR 0x18 -#define GP_TIMER_TIER 0x1c -#define GP_TIMER_TCLR 0x24 -#define GP_TIMER_TCRR 0x28 -#define GP_TIMER_TLDR 0x2c -#define GP_TIMER_TTGR 0x30 -#define GP_TIMER_TSICR 0x40 - #define OMAP_32K_TICKS_PER_HZ (32768 / HZ) /* @@ -102,54 +91,64 @@ struct sys_timer omap_timer; #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ (((nr_jiffies) * (clock_rate)) / HZ) +#if defined(CONFIG_ARCH_OMAP1) + static inline void omap_32k_timer_write(int val, int reg) { - if (cpu_class_is_omap1()) - omap_writew(val, OMAP1_32K_TIMER_BASE + reg); - - if (cpu_is_omap24xx()) - omap_writel(val, OMAP2_GP_TIMER_BASE + reg); + omap_writew(val, OMAP1_32K_TIMER_BASE + reg); } static inline unsigned long omap_32k_timer_read(int reg) { - if (cpu_class_is_omap1()) - return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; + return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; +} - if (cpu_is_omap24xx()) - return omap_readl(OMAP2_GP_TIMER_BASE + reg); +static inline void omap_32k_timer_start(unsigned long load_val) +{ + if (!load_val) + load_val = 1; + omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); + omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); } -/* - * The 32KHz synchronized timer is an additional timer on 16xx. - * It is always running. - */ -static inline unsigned long omap_32k_sync_timer_read(void) +static inline void omap_32k_timer_stop(void) { - return omap_readl(TIMER_32K_SYNCHRONIZED); + omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); } +#define omap_32k_timer_ack_irq() + +#elif defined(CONFIG_ARCH_OMAP2) + +static struct omap_dm_timer *gptimer; + static inline void omap_32k_timer_start(unsigned long load_val) { - if (cpu_class_is_omap1()) { - omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); - omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); - } - - if (cpu_is_omap24xx()) { - omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR); - omap_32k_timer_write((1 << 1), GP_TIMER_TIER); - omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR); - } + omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val); + omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); + omap_dm_timer_start(gptimer); } static inline void omap_32k_timer_stop(void) { - if (cpu_class_is_omap1()) - omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); + omap_dm_timer_stop(gptimer); +} - if (cpu_is_omap24xx()) - omap_32k_timer_write(0x0, GP_TIMER_TCLR); +static inline void omap_32k_timer_ack_irq(void) +{ + u32 status = omap_dm_timer_read_status(gptimer); + omap_dm_timer_write_status(gptimer, status); +} + +#endif + +/* + * The 32KHz synchronized timer is an additional timer on 16xx. + * It is always running. + */ +static inline unsigned long omap_32k_sync_timer_read(void) +{ + return omap_readl(TIMER_32K_SYNCHRONIZED); } /* @@ -195,24 +194,17 @@ unsigned long long sched_clock(void) * issues with dynamic tick. In the dynamic tick case, we need to lock * with irqsave. */ -static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id) { - unsigned long flags; unsigned long now; - write_seqlock_irqsave(&xtime_lock, flags); - - if (cpu_is_omap24xx()) { - u32 status = omap_32k_timer_read(GP_TIMER_TISR); - omap_32k_timer_write(status, GP_TIMER_TISR); - } - + omap_32k_timer_ack_irq(); now = omap_32k_sync_timer_read(); - while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { + while ((signed long)(now - omap_32k_last_tick) + >= OMAP_32K_TICKS_PER_HZ) { omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; - timer_tick(regs); + timer_tick(); } /* Restart timer so we don't drift off due to modulo or dynamic tick. @@ -221,6 +213,21 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, * continuous timer can be overridden from pm_idle to be longer. */ omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); + + return IRQ_HANDLED; +} + +static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id) +{ + return _omap_32k_timer_interrupt(irq, dev_id); +} + +static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id) +{ + unsigned long flags; + + write_seqlock_irqsave(&xtime_lock, flags); + _omap_32k_timer_interrupt(irq, dev_id); write_sequnlock_irqrestore(&xtime_lock, flags); return IRQ_HANDLED; @@ -236,7 +243,15 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, */ void omap_32k_timer_reprogram(unsigned long next_tick) { - omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1); + unsigned long ticks = JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1; + unsigned long now = omap_32k_sync_timer_read(); + unsigned long idled = now - omap_32k_last_tick; + + if (idled + 1 < ticks) + ticks -= idled; + else + ticks = 1; + omap_32k_timer_start(ticks); } static struct irqaction omap_32k_timer_irq; @@ -258,19 +273,16 @@ static struct dyn_tick_timer omap_dyn_tick_timer = { .enable = omap_32k_timer_enable_dyn_tick, .disable = omap_32k_timer_disable_dyn_tick, .reprogram = omap_32k_timer_reprogram, - .handler = omap_32k_timer_interrupt, + .handler = omap_32k_timer_handler, }; #endif /* CONFIG_NO_IDLE_HZ */ static struct irqaction omap_32k_timer_irq = { .name = "32KHz timer", - .flags = SA_INTERRUPT | SA_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER, .handler = omap_32k_timer_interrupt, }; -static struct clk * gpt1_ick; -static struct clk * gpt1_fck; - static __init void omap_init_32k_timer(void) { #ifdef CONFIG_NO_IDLE_HZ @@ -279,32 +291,22 @@ static __init void omap_init_32k_timer(void) if (cpu_class_is_omap1()) setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); - if (cpu_is_omap24xx()) - setup_irq(37, &omap_32k_timer_irq); omap_timer.offset = omap_32k_timer_gettimeoffset; omap_32k_last_tick = omap_32k_sync_timer_read(); +#ifdef CONFIG_ARCH_OMAP2 /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ if (cpu_is_omap24xx()) { - omap_32k_timer_write(0, GP_TIMER_TCLR); - omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */ - - gpt1_ick = clk_get(NULL, "gpt1_ick"); - if (IS_ERR(gpt1_ick)) - printk(KERN_ERR "Could not get gpt1_ick\n"); - else - clk_enable(gpt1_ick); - - gpt1_fck = clk_get(NULL, "gpt1_fck"); - if (IS_ERR(gpt1_fck)) - printk(KERN_ERR "Could not get gpt1_fck\n"); - else - clk_enable(gpt1_fck); - - mdelay(100); /* Wait for clocks to stabilize */ - - omap_32k_timer_write(0x7, GP_TIMER_TISR); + gptimer = omap_dm_timer_request_specific(1); + BUG_ON(gptimer == NULL); + + omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ); + setup_irq(omap_dm_timer_get_irq(gptimer), &omap_32k_timer_irq); + omap_dm_timer_set_int_enable(gptimer, + OMAP_TIMER_INT_CAPTURE | OMAP_TIMER_INT_OVERFLOW | + OMAP_TIMER_INT_MATCH); } +#endif omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); } @@ -316,6 +318,9 @@ static __init void omap_init_32k_timer(void) */ static void __init omap_timer_init(void) { +#ifdef CONFIG_OMAP_DM_TIMER + omap_dm_timer_init(); +#endif omap_init_32k_timer(); }