diff options
Diffstat (limited to 'arch/arm/plat-omap/timer32k.c')
| -rw-r--r-- | arch/arm/plat-omap/timer32k.c | 122 | 
1 files changed, 53 insertions, 69 deletions
| diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c index 053c18132ef4..ddf4360dea72 100644 --- a/arch/arm/plat-omap/timer32k.c +++ b/arch/arm/plat-omap/timer32k.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | * Partial timer rewrite and additional dynamic tick timer support by | 7 | * Partial timer rewrite and additional dynamic tick timer support by | 
| 8 | * Tony Lindgen <tony@atomide.com> and | 8 | * Tony Lindgen <tony@atomide.com> and | 
| 9 | * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | 9 | * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | 
| 10 | * OMAP Dual-mode timer framework support by Timo Teras | ||
| 10 | * | 11 | * | 
| 11 | * MPU timer code based on the older MPU timer code for OMAP | 12 | * MPU timer code based on the older MPU timer code for OMAP | 
| 12 | * Copyright (C) 2000 RidgeRun, Inc. | 13 | * Copyright (C) 2000 RidgeRun, Inc. | 
| @@ -49,6 +50,7 @@ | |||
| 49 | #include <asm/irq.h> | 50 | #include <asm/irq.h> | 
| 50 | #include <asm/mach/irq.h> | 51 | #include <asm/mach/irq.h> | 
| 51 | #include <asm/mach/time.h> | 52 | #include <asm/mach/time.h> | 
| 53 | #include <asm/arch/dmtimer.h> | ||
| 52 | 54 | ||
| 53 | struct sys_timer omap_timer; | 55 | struct sys_timer omap_timer; | 
| 54 | 56 | ||
| @@ -78,18 +80,6 @@ struct sys_timer omap_timer; | |||
| 78 | #define OMAP1_32K_TIMER_TVR 0x00 | 80 | #define OMAP1_32K_TIMER_TVR 0x00 | 
| 79 | #define OMAP1_32K_TIMER_TCR 0x04 | 81 | #define OMAP1_32K_TIMER_TCR 0x04 | 
| 80 | 82 | ||
| 81 | /* 24xx specific defines */ | ||
| 82 | #define OMAP2_GP_TIMER_BASE 0x48028000 | ||
| 83 | #define CM_CLKSEL_WKUP 0x48008440 | ||
| 84 | #define GP_TIMER_TIDR 0x00 | ||
| 85 | #define GP_TIMER_TISR 0x18 | ||
| 86 | #define GP_TIMER_TIER 0x1c | ||
| 87 | #define GP_TIMER_TCLR 0x24 | ||
| 88 | #define GP_TIMER_TCRR 0x28 | ||
| 89 | #define GP_TIMER_TLDR 0x2c | ||
| 90 | #define GP_TIMER_TTGR 0x30 | ||
| 91 | #define GP_TIMER_TSICR 0x40 | ||
| 92 | |||
| 93 | #define OMAP_32K_TICKS_PER_HZ (32768 / HZ) | 83 | #define OMAP_32K_TICKS_PER_HZ (32768 / HZ) | 
| 94 | 84 | ||
| 95 | /* | 85 | /* | 
| @@ -101,54 +91,62 @@ struct sys_timer omap_timer; | |||
| 101 | #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ | 91 | #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ | 
| 102 | (((nr_jiffies) * (clock_rate)) / HZ) | 92 | (((nr_jiffies) * (clock_rate)) / HZ) | 
| 103 | 93 | ||
| 94 | #if defined(CONFIG_ARCH_OMAP1) | ||
| 95 | |||
| 104 | static inline void omap_32k_timer_write(int val, int reg) | 96 | static inline void omap_32k_timer_write(int val, int reg) | 
| 105 | { | 97 | { | 
| 106 | if (cpu_class_is_omap1()) | 98 | omap_writew(val, OMAP1_32K_TIMER_BASE + reg); | 
| 107 | omap_writew(val, OMAP1_32K_TIMER_BASE + reg); | ||
| 108 | |||
| 109 | if (cpu_is_omap24xx()) | ||
| 110 | omap_writel(val, OMAP2_GP_TIMER_BASE + reg); | ||
| 111 | } | 99 | } | 
| 112 | 100 | ||
| 113 | static inline unsigned long omap_32k_timer_read(int reg) | 101 | static inline unsigned long omap_32k_timer_read(int reg) | 
| 114 | { | 102 | { | 
| 115 | if (cpu_class_is_omap1()) | 103 | return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; | 
| 116 | return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; | 104 | } | 
| 117 | 105 | ||
| 118 | if (cpu_is_omap24xx()) | 106 | static inline void omap_32k_timer_start(unsigned long load_val) | 
| 119 | return omap_readl(OMAP2_GP_TIMER_BASE + reg); | 107 | { | 
| 108 | omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); | ||
| 109 | omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); | ||
| 120 | } | 110 | } | 
| 121 | 111 | ||
| 122 | /* | 112 | static inline void omap_32k_timer_stop(void) | 
| 123 | * The 32KHz synchronized timer is an additional timer on 16xx. | ||
| 124 | * It is always running. | ||
| 125 | */ | ||
| 126 | static inline unsigned long omap_32k_sync_timer_read(void) | ||
| 127 | { | 113 | { | 
| 128 | return omap_readl(TIMER_32K_SYNCHRONIZED); | 114 | omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); | 
| 129 | } | 115 | } | 
| 130 | 116 | ||
| 117 | #define omap_32k_timer_ack_irq() | ||
| 118 | |||
| 119 | #elif defined(CONFIG_ARCH_OMAP2) | ||
| 120 | |||
| 121 | static struct omap_dm_timer *gptimer; | ||
| 122 | |||
| 131 | static inline void omap_32k_timer_start(unsigned long load_val) | 123 | static inline void omap_32k_timer_start(unsigned long load_val) | 
| 132 | { | 124 | { | 
| 133 | if (cpu_class_is_omap1()) { | 125 | omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val); | 
| 134 | omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); | 126 | omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); | 
| 135 | omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); | 127 | omap_dm_timer_start(gptimer); | 
| 136 | } | ||
| 137 | |||
| 138 | if (cpu_is_omap24xx()) { | ||
| 139 | omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR); | ||
| 140 | omap_32k_timer_write((1 << 1), GP_TIMER_TIER); | ||
| 141 | omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR); | ||
| 142 | } | ||
| 143 | } | 128 | } | 
| 144 | 129 | ||
| 145 | static inline void omap_32k_timer_stop(void) | 130 | static inline void omap_32k_timer_stop(void) | 
| 146 | { | 131 | { | 
| 147 | if (cpu_class_is_omap1()) | 132 | omap_dm_timer_stop(gptimer); | 
| 148 | omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); | 133 | } | 
| 149 | 134 | ||
| 150 | if (cpu_is_omap24xx()) | 135 | static inline void omap_32k_timer_ack_irq(void) | 
| 151 | omap_32k_timer_write(0x0, GP_TIMER_TCLR); | 136 | { | 
| 137 | u32 status = omap_dm_timer_read_status(gptimer); | ||
| 138 | omap_dm_timer_write_status(gptimer, status); | ||
| 139 | } | ||
| 140 | |||
| 141 | #endif | ||
| 142 | |||
| 143 | /* | ||
| 144 | * The 32KHz synchronized timer is an additional timer on 16xx. | ||
| 145 | * It is always running. | ||
| 146 | */ | ||
| 147 | static inline unsigned long omap_32k_sync_timer_read(void) | ||
| 148 | { | ||
| 149 | return omap_readl(TIMER_32K_SYNCHRONIZED); | ||
| 152 | } | 150 | } | 
| 153 | 151 | ||
| 154 | /* | 152 | /* | 
| @@ -202,11 +200,7 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, | |||
| 202 | 200 | ||
| 203 | write_seqlock_irqsave(&xtime_lock, flags); | 201 | write_seqlock_irqsave(&xtime_lock, flags); | 
| 204 | 202 | ||
| 205 | if (cpu_is_omap24xx()) { | 203 | omap_32k_timer_ack_irq(); | 
| 206 | u32 status = omap_32k_timer_read(GP_TIMER_TISR); | ||
| 207 | omap_32k_timer_write(status, GP_TIMER_TISR); | ||
| 208 | } | ||
| 209 | |||
| 210 | now = omap_32k_sync_timer_read(); | 204 | now = omap_32k_sync_timer_read(); | 
| 211 | 205 | ||
| 212 | while ((signed long)(now - omap_32k_last_tick) | 206 | while ((signed long)(now - omap_32k_last_tick) | 
| @@ -268,9 +262,6 @@ static struct irqaction omap_32k_timer_irq = { | |||
| 268 | .handler = omap_32k_timer_interrupt, | 262 | .handler = omap_32k_timer_interrupt, | 
| 269 | }; | 263 | }; | 
| 270 | 264 | ||
| 271 | static struct clk * gpt1_ick; | ||
| 272 | static struct clk * gpt1_fck; | ||
| 273 | |||
| 274 | static __init void omap_init_32k_timer(void) | 265 | static __init void omap_init_32k_timer(void) | 
| 275 | { | 266 | { | 
| 276 | #ifdef CONFIG_NO_IDLE_HZ | 267 | #ifdef CONFIG_NO_IDLE_HZ | 
| @@ -279,32 +270,22 @@ static __init void omap_init_32k_timer(void) | |||
| 279 | 270 | ||
| 280 | if (cpu_class_is_omap1()) | 271 | if (cpu_class_is_omap1()) | 
| 281 | setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); | 272 | setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); | 
| 282 | if (cpu_is_omap24xx()) | ||
| 283 | setup_irq(37, &omap_32k_timer_irq); | ||
| 284 | omap_timer.offset = omap_32k_timer_gettimeoffset; | 273 | omap_timer.offset = omap_32k_timer_gettimeoffset; | 
| 285 | omap_32k_last_tick = omap_32k_sync_timer_read(); | 274 | omap_32k_last_tick = omap_32k_sync_timer_read(); | 
| 286 | 275 | ||
| 276 | #ifdef CONFIG_ARCH_OMAP2 | ||
| 287 | /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ | 277 | /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ | 
| 288 | if (cpu_is_omap24xx()) { | 278 | if (cpu_is_omap24xx()) { | 
| 289 | omap_32k_timer_write(0, GP_TIMER_TCLR); | 279 | gptimer = omap_dm_timer_request_specific(1); | 
| 290 | omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */ | 280 | BUG_ON(gptimer == NULL); | 
| 291 | 281 | ||
| 292 | gpt1_ick = clk_get(NULL, "gpt1_ick"); | 282 | omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ); | 
| 293 | if (IS_ERR(gpt1_ick)) | 283 | setup_irq(omap_dm_timer_get_irq(gptimer), &omap_32k_timer_irq); | 
| 294 | printk(KERN_ERR "Could not get gpt1_ick\n"); | 284 | omap_dm_timer_set_int_enable(gptimer, | 
| 295 | else | 285 | OMAP_TIMER_INT_CAPTURE | OMAP_TIMER_INT_OVERFLOW | | 
| 296 | clk_enable(gpt1_ick); | 286 | OMAP_TIMER_INT_MATCH); | 
| 297 | |||
| 298 | gpt1_fck = clk_get(NULL, "gpt1_fck"); | ||
| 299 | if (IS_ERR(gpt1_fck)) | ||
| 300 | printk(KERN_ERR "Could not get gpt1_fck\n"); | ||
| 301 | else | ||
| 302 | clk_enable(gpt1_fck); | ||
| 303 | |||
| 304 | mdelay(100); /* Wait for clocks to stabilize */ | ||
| 305 | |||
| 306 | omap_32k_timer_write(0x7, GP_TIMER_TISR); | ||
| 307 | } | 287 | } | 
| 288 | #endif | ||
| 308 | 289 | ||
| 309 | omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); | 290 | omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); | 
| 310 | } | 291 | } | 
| @@ -316,6 +297,9 @@ static __init void omap_init_32k_timer(void) | |||
| 316 | */ | 297 | */ | 
| 317 | static void __init omap_timer_init(void) | 298 | static void __init omap_timer_init(void) | 
| 318 | { | 299 | { | 
| 300 | #ifdef CONFIG_OMAP_DM_TIMER | ||
| 301 | omap_dm_timer_init(); | ||
| 302 | #endif | ||
| 319 | omap_init_32k_timer(); | 303 | omap_init_32k_timer(); | 
| 320 | } | 304 | } | 
| 321 | 305 | ||
