aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@solidboot.com>2006-06-26 19:16:12 -0400
committerTony Lindgren <tony@atomide.com>2006-06-26 19:16:12 -0400
commit77900a2fc3bfb1eb6eaa6d43eef4591e1f7c600d (patch)
tree6d6278f833a6057b1b951e4e9bded234aa6459e2 /arch
parent6e711ec6d249c0d3f8bc225066738d064ed90032 (diff)
ARM: OMAP: Port dmtimers to OMAP2 and implement PWM support
Port dmtimer framework to OMAP2. Modify the dmtimers API to support setting of PWM configuration and prescaler. Convert 32 kHz timer and GP timer to use the dmtimer framework. Signed-off-by: Timo Teras <timo.teras@solidboot.com> Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/timer-gp.c86
-rw-r--r--arch/arm/plat-omap/Kconfig2
-rw-r--r--arch/arm/plat-omap/dmtimer.c413
-rw-r--r--arch/arm/plat-omap/timer32k.c121
5 files changed, 367 insertions, 256 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 537dd2e6d380..aab97ccf1e63 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -8,6 +8,7 @@ config ARCH_OMAP24XX
8config ARCH_OMAP2420 8config ARCH_OMAP2420
9 bool "OMAP2420 support" 9 bool "OMAP2420 support"
10 depends on ARCH_OMAP24XX 10 depends on ARCH_OMAP24XX
11 select OMAP_DM_TIMER
11 12
12comment "OMAP Board Type" 13comment "OMAP Board Type"
13 depends on ARCH_OMAP2 14 depends on ARCH_OMAP2
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 1d2f5ac2f69b..3358c0d47b1a 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -6,6 +6,7 @@
6 * Copyright (C) 2005 Nokia Corporation 6 * Copyright (C) 2005 Nokia Corporation
7 * Author: Paul Mundt <paul.mundt@nokia.com> 7 * Author: Paul Mundt <paul.mundt@nokia.com>
8 * Juha Yrjölä <juha.yrjola@nokia.com> 8 * Juha Yrjölä <juha.yrjola@nokia.com>
9 * OMAP Dual-mode timer framework support by Timo Teras
9 * 10 *
10 * Some parts based off of TI's 24xx code: 11 * Some parts based off of TI's 24xx code:
11 * 12 *
@@ -22,54 +23,18 @@
22#include <linux/interrupt.h> 23#include <linux/interrupt.h>
23#include <linux/err.h> 24#include <linux/err.h>
24#include <linux/clk.h> 25#include <linux/clk.h>
26#include <linux/delay.h>
25 27
26#include <asm/mach/time.h> 28#include <asm/mach/time.h>
27#include <asm/delay.h> 29#include <asm/arch/dmtimer.h>
28#include <asm/io.h>
29 30
30#define OMAP2_GP_TIMER1_BASE 0x48028000 31static struct omap_dm_timer *gptimer;
31#define OMAP2_GP_TIMER2_BASE 0x4802a000
32#define OMAP2_GP_TIMER3_BASE 0x48078000
33#define OMAP2_GP_TIMER4_BASE 0x4807a000
34 32
35#define GP_TIMER_TIDR 0x00 33static inline void omap2_gp_timer_start(unsigned long load_val)
36#define GP_TIMER_TISR 0x18
37#define GP_TIMER_TIER 0x1c
38#define GP_TIMER_TCLR 0x24
39#define GP_TIMER_TCRR 0x28
40#define GP_TIMER_TLDR 0x2c
41#define GP_TIMER_TSICR 0x40
42
43#define OS_TIMER_NR 1 /* GP timer 2 */
44
45static unsigned long timer_base[] = {
46 IO_ADDRESS(OMAP2_GP_TIMER1_BASE),
47 IO_ADDRESS(OMAP2_GP_TIMER2_BASE),
48 IO_ADDRESS(OMAP2_GP_TIMER3_BASE),
49 IO_ADDRESS(OMAP2_GP_TIMER4_BASE),
50};
51
52static inline unsigned int timer_read_reg(int nr, unsigned int reg)
53{
54 return __raw_readl(timer_base[nr] + reg);
55}
56
57static inline void timer_write_reg(int nr, unsigned int reg, unsigned int val)
58{
59 __raw_writel(val, timer_base[nr] + reg);
60}
61
62/* Note that we always enable the clock prescale divider bit */
63static inline void omap2_gp_timer_start(int nr, unsigned long load_val)
64{ 34{
65 unsigned int tmp; 35 omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val);
66 36 omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
67 tmp = 0xffffffff - load_val; 37 omap_dm_timer_start(gptimer);
68
69 timer_write_reg(nr, GP_TIMER_TLDR, tmp);
70 timer_write_reg(nr, GP_TIMER_TCRR, tmp);
71 timer_write_reg(nr, GP_TIMER_TIER, 1 << 1);
72 timer_write_reg(nr, GP_TIMER_TCLR, (1 << 5) | (1 << 1) | 1);
73} 38}
74 39
75static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, 40static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
@@ -77,7 +42,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
77{ 42{
78 write_seqlock(&xtime_lock); 43 write_seqlock(&xtime_lock);
79 44
80 timer_write_reg(OS_TIMER_NR, GP_TIMER_TISR, 1 << 1); 45 omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW);
81 timer_tick(regs); 46 timer_tick(regs);
82 47
83 write_sequnlock(&xtime_lock); 48 write_sequnlock(&xtime_lock);
@@ -87,41 +52,26 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
87 52
88static struct irqaction omap2_gp_timer_irq = { 53static struct irqaction omap2_gp_timer_irq = {
89 .name = "gp timer", 54 .name = "gp timer",
90 .flags = SA_INTERRUPT, 55 .flags = SA_INTERRUPT | SA_TIMER,
91 .handler = omap2_gp_timer_interrupt, 56 .handler = omap2_gp_timer_interrupt,
92}; 57};
93 58
94static void __init omap2_gp_timer_init(void) 59static void __init omap2_gp_timer_init(void)
95{ 60{
96 struct clk * sys_ck; 61 u32 tick_period;
97 u32 tick_period = 120000;
98 u32 l;
99 62
100 /* Reset clock and prescale value */ 63 omap_dm_timer_init();
101 timer_write_reg(OS_TIMER_NR, GP_TIMER_TCLR, 0); 64 gptimer = omap_dm_timer_request_specific(2);
65 BUG_ON(gptimer == NULL);
102 66
103 sys_ck = clk_get(NULL, "sys_ck"); 67 omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK);
104 if (IS_ERR(sys_ck)) 68 tick_period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / 100;
105 printk(KERN_ERR "Could not get sys_ck\n");
106 else {
107 clk_enable(sys_ck);
108 tick_period = clk_get_rate(sys_ck) / 100;
109 clk_put(sys_ck);
110 }
111
112 tick_period /= 2; /* Minimum prescale divider is 2 */
113 tick_period -= 1; 69 tick_period -= 1;
114 70
115 l = timer_read_reg(OS_TIMER_NR, GP_TIMER_TIDR); 71 setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
116 printk(KERN_INFO "OMAP2 GP timer (HW version %d.%d)\n", 72 omap2_gp_timer_start(tick_period);
117 (l >> 4) & 0x0f, l & 0x0f);
118
119 setup_irq(38, &omap2_gp_timer_irq);
120
121 omap2_gp_timer_start(OS_TIMER_NR, tick_period);
122} 73}
123 74
124struct sys_timer omap_timer = { 75struct sys_timer omap_timer = {
125 .init = omap2_gp_timer_init, 76 .init = omap2_gp_timer_init,
126}; 77};
127
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index ec49495e651e..ec752e16d618 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -91,7 +91,7 @@ config OMAP_32K_TIMER_HZ
91 91
92config OMAP_DM_TIMER 92config OMAP_DM_TIMER
93 bool "Use dual-mode timer" 93 bool "Use dual-mode timer"
94 depends on ARCH_OMAP16XX 94 depends on ARCH_OMAP16XX || ARCH_OMAP24XX
95 help 95 help
96 Select this option if you want to use OMAP Dual-Mode timers. 96 Select this option if you want to use OMAP Dual-Mode timers.
97 97
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index eba3cb52ad87..c25a1a6d2b03 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -4,7 +4,8 @@
4 * OMAP Dual-Mode Timers 4 * OMAP Dual-Mode Timers
5 * 5 *
6 * Copyright (C) 2005 Nokia Corporation 6 * Copyright (C) 2005 Nokia Corporation
7 * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> 7 * OMAP2 support by Juha Yrjola
8 * API improvements and OMAP2 clock framework support by Timo Teras
8 * 9 *
9 * This program is free software; you can redistribute it and/or modify it 10 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the 11 * under the terms of the GNU General Public License as published by the
@@ -26,15 +27,17 @@
26 */ 27 */
27 28
28#include <linux/init.h> 29#include <linux/init.h>
30#include <linux/spinlock.h>
31#include <linux/errno.h>
32#include <linux/list.h>
33#include <linux/clk.h>
34#include <linux/delay.h>
29#include <asm/hardware.h> 35#include <asm/hardware.h>
30#include <asm/arch/dmtimer.h> 36#include <asm/arch/dmtimer.h>
31#include <asm/io.h> 37#include <asm/io.h>
32#include <asm/arch/irqs.h> 38#include <asm/arch/irqs.h>
33#include <linux/spinlock.h>
34#include <linux/list.h>
35
36#define OMAP_TIMER_COUNT 8
37 39
40/* register offsets */
38#define OMAP_TIMER_ID_REG 0x00 41#define OMAP_TIMER_ID_REG 0x00
39#define OMAP_TIMER_OCP_CFG_REG 0x10 42#define OMAP_TIMER_OCP_CFG_REG 0x10
40#define OMAP_TIMER_SYS_STAT_REG 0x14 43#define OMAP_TIMER_SYS_STAT_REG 0x14
@@ -50,52 +53,184 @@
50#define OMAP_TIMER_CAPTURE_REG 0x3c 53#define OMAP_TIMER_CAPTURE_REG 0x3c
51#define OMAP_TIMER_IF_CTRL_REG 0x40 54#define OMAP_TIMER_IF_CTRL_REG 0x40
52 55
56/* timer control reg bits */
57#define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
58#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
59#define OMAP_TIMER_CTRL_PT (1 << 12)
60#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8)
61#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8)
62#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8)
63#define OMAP_TIMER_CTRL_SCPWM (1 << 7)
64#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */
65#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */
66#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */
67#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */
68#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */
69
70struct omap_dm_timer {
71 unsigned long phys_base;
72 int irq;
73#ifdef CONFIG_ARCH_OMAP2
74 struct clk *iclk, *fclk;
75#endif
76 void __iomem *io_base;
77 unsigned reserved:1;
78};
79
80#ifdef CONFIG_ARCH_OMAP1
81
82static struct omap_dm_timer dm_timers[] = {
83 { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
84 { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
85 { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 },
86 { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 },
87 { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 },
88 { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 },
89 { .phys_base = 0xfffb4400, .irq = INT_1610_GPTIMER7 },
90 { .phys_base = 0xfffb4c00, .irq = INT_1610_GPTIMER8 },
91};
53 92
54static struct dmtimer_info_struct { 93#elif defined(CONFIG_ARCH_OMAP2)
55 struct list_head unused_timers;
56 struct list_head reserved_timers;
57} dm_timer_info;
58 94
59static struct omap_dm_timer dm_timers[] = { 95static struct omap_dm_timer dm_timers[] = {
60 { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 }, 96 { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
61 { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 }, 97 { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
62 { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 }, 98 { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
63 { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 }, 99 { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
64 { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 }, 100 { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
65 { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 }, 101 { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
66 { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 }, 102 { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
67 { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 }, 103 { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
68 { .base=0x0 }, 104 { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
105 { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
106 { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
107 { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
69}; 108};
70 109
110#else
111
112#error OMAP architecture not supported!
113
114#endif
115
116static const int dm_timer_count = ARRAY_SIZE(dm_timers);
71 117
72static spinlock_t dm_timer_lock; 118static spinlock_t dm_timer_lock;
73 119
120static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
121{
122 return readl(timer->io_base + reg);
123}
74 124
75inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) 125static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
76{ 126{
77 omap_writel(value, timer->base + reg); 127 writel(value, timer->io_base + reg);
78 while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) 128 while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
79 ; 129 ;
80} 130}
81 131
82u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) 132static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
83{ 133{
84 return omap_readl(timer->base + reg); 134 int c;
135
136 c = 0;
137 while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
138 c++;
139 if (c > 100000) {
140 printk(KERN_ERR "Timer failed to reset\n");
141 return;
142 }
143 }
85} 144}
86 145
87int omap_dm_timers_active(void) 146static void omap_dm_timer_reset(struct omap_dm_timer *timer)
147{
148 u32 l;
149
150 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
151 omap_dm_timer_wait_for_reset(timer);
152
153 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK);
154
155 /* Set to smart-idle mode */
156 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
157 l |= 0x02 << 3;
158 omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
159}
160
161static void omap_dm_timer_reserve(struct omap_dm_timer *timer)
162{
163 timer->reserved = 1;
164#ifdef CONFIG_ARCH_OMAP2
165 clk_enable(timer->iclk);
166 clk_enable(timer->fclk);
167#endif
168 omap_dm_timer_reset(timer);
169}
170
171struct omap_dm_timer *omap_dm_timer_request(void)
172{
173 struct omap_dm_timer *timer = NULL;
174 unsigned long flags;
175 int i;
176
177 spin_lock_irqsave(&dm_timer_lock, flags);
178 for (i = 0; i < dm_timer_count; i++) {
179 if (dm_timers[i].reserved)
180 continue;
181
182 timer = &dm_timers[i];
183 omap_dm_timer_reserve(timer);
184 break;
185 }
186 spin_unlock_irqrestore(&dm_timer_lock, flags);
187
188 return timer;
189}
190
191struct omap_dm_timer *omap_dm_timer_request_specific(int id)
88{ 192{
89 struct omap_dm_timer *timer; 193 struct omap_dm_timer *timer;
194 unsigned long flags;
90 195
91 for (timer = &dm_timers[0]; timer->base; ++timer) 196 spin_lock_irqsave(&dm_timer_lock, flags);
92 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & 197 if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
93 OMAP_TIMER_CTRL_ST) 198 spin_unlock_irqrestore(&dm_timer_lock, flags);
94 return 1; 199 printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
200 __FILE__, __LINE__, __FUNCTION__, id);
201 dump_stack();
202 return NULL;
203 }
95 204
96 return 0; 205 timer = &dm_timers[id-1];
206 omap_dm_timer_reserve(timer);
207 spin_unlock_irqrestore(&dm_timer_lock, flags);
208
209 return timer;
97} 210}
98 211
212void omap_dm_timer_free(struct omap_dm_timer *timer)
213{
214 omap_dm_timer_reset(timer);
215#ifdef CONFIG_ARCH_OMAP2
216 clk_disable(timer->iclk);
217 clk_disable(timer->fclk);
218#endif
219 WARN_ON(!timer->reserved);
220 timer->reserved = 0;
221}
222
223int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
224{
225 return timer->irq;
226}
227
228#if defined(CONFIG_ARCH_OMAP1)
229
230struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
231{
232 BUG();
233}
99 234
100/** 235/**
101 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR 236 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
@@ -103,184 +238,226 @@ int omap_dm_timers_active(void)
103 */ 238 */
104__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) 239__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
105{ 240{
106 int n; 241 int i;
107 242
108 /* If ARMXOR cannot be idled this function call is unnecessary */ 243 /* If ARMXOR cannot be idled this function call is unnecessary */
109 if (!(inputmask & (1 << 1))) 244 if (!(inputmask & (1 << 1)))
110 return inputmask; 245 return inputmask;
111 246
112 /* If any active timer is using ARMXOR return modified mask */ 247 /* If any active timer is using ARMXOR return modified mask */
113 for (n = 0; dm_timers[n].base; ++n) 248 for (i = 0; i < dm_timer_count; i++) {
114 if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)& 249 u32 l;
115 OMAP_TIMER_CTRL_ST) { 250
116 if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0) 251 l = omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG);
252 if (l & OMAP_TIMER_CTRL_ST) {
253 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
117 inputmask &= ~(1 << 1); 254 inputmask &= ~(1 << 1);
118 else 255 else
119 inputmask &= ~(1 << 2); 256 inputmask &= ~(1 << 2);
120 } 257 }
258 }
121 259
122 return inputmask; 260 return inputmask;
123} 261}
124 262
263#elif defined(CONFIG_ARCH_OMAP2)
125 264
126void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) 265struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
127{ 266{
128 int n = (timer - dm_timers) << 1; 267 return timer->fclk;
129 u32 l; 268}
130 269
131 l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); 270__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
132 l |= source << n; 271{
133 omap_writel(l, MOD_CONF_CTRL_1); 272 BUG();
134} 273}
135 274
275#endif
136 276
137static void omap_dm_timer_reset(struct omap_dm_timer *timer) 277void omap_dm_timer_trigger(struct omap_dm_timer *timer)
138{ 278{
139 /* Reset and set posted mode */ 279 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
140 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
141 omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02);
142
143 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
144} 280}
145 281
282void omap_dm_timer_start(struct omap_dm_timer *timer)
283{
284 u32 l;
146 285
286 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
287 if (!(l & OMAP_TIMER_CTRL_ST)) {
288 l |= OMAP_TIMER_CTRL_ST;
289 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
290 }
291}
147 292
148struct omap_dm_timer * omap_dm_timer_request(void) 293void omap_dm_timer_stop(struct omap_dm_timer *timer)
149{ 294{
150 struct omap_dm_timer *timer = NULL; 295 u32 l;
151 unsigned long flags;
152 296
153 spin_lock_irqsave(&dm_timer_lock, flags); 297 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
154 if (!list_empty(&dm_timer_info.unused_timers)) { 298 if (l & OMAP_TIMER_CTRL_ST) {
155 timer = (struct omap_dm_timer *) 299 l &= ~0x1;
156 dm_timer_info.unused_timers.next; 300 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
157 list_move_tail((struct list_head *)timer,
158 &dm_timer_info.reserved_timers);
159 } 301 }
160 spin_unlock_irqrestore(&dm_timer_lock, flags);
161
162 return timer;
163} 302}
164 303
304#ifdef CONFIG_ARCH_OMAP1
165 305
166void omap_dm_timer_free(struct omap_dm_timer *timer) 306void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
167{ 307{
168 unsigned long flags; 308 int n = (timer - dm_timers) << 1;
169 309 u32 l;
170 omap_dm_timer_reset(timer);
171 310
172 spin_lock_irqsave(&dm_timer_lock, flags); 311 l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
173 list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers); 312 l |= source << n;
174 spin_unlock_irqrestore(&dm_timer_lock, flags); 313 omap_writel(l, MOD_CONF_CTRL_1);
175} 314}
176 315
177void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, 316#else
178 unsigned int value)
179{
180 omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
181}
182 317
183unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) 318void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
184{ 319{
185 return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); 320 static const char *source_timers[] = {
321 "sys_ck",
322 "func_32k_ck",
323 "alt_ck"
324 };
325 struct clk *parent;
326
327 if (source < 0 || source >= 3)
328 return;
329
330 parent = clk_get(NULL, source_timers[source]);
331 clk_disable(timer->fclk);
332 clk_set_parent(timer->fclk, parent);
333 clk_enable(timer->fclk);
334 clk_put(parent);
335
336 /* When the functional clock disappears, too quick writes seem to
337 * cause an abort. */
338 udelay(50);
186} 339}
187 340
188void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) 341#endif
189{
190 omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
191}
192 342
193void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer) 343void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
344 unsigned int load)
194{ 345{
195 u32 l; 346 u32 l;
347
196 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 348 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
197 l |= OMAP_TIMER_CTRL_AR; 349 if (autoreload)
350 l |= OMAP_TIMER_CTRL_AR;
351 else
352 l &= ~OMAP_TIMER_CTRL_AR;
198 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 353 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
354 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
355 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
199} 356}
200 357
201void omap_dm_timer_trigger(struct omap_dm_timer *timer) 358void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
202{ 359 unsigned int match)
203 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
204}
205
206void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
207{ 360{
208 u32 l; 361 u32 l;
209 362
210 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 363 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
211 l |= value & 0x3; 364 if (enable)
365 l |= OMAP_TIMER_CTRL_CE;
366 else
367 l &= ~OMAP_TIMER_CTRL_CE;
212 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 368 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
369 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
213} 370}
214 371
215void omap_dm_timer_start(struct omap_dm_timer *timer) 372
373void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
374 int toggle, int trigger)
216{ 375{
217 u32 l; 376 u32 l;
218 377
219 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 378 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
220 l |= OMAP_TIMER_CTRL_ST; 379 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
380 OMAP_TIMER_CTRL_PT | (0x03 << 10));
381 if (def_on)
382 l |= OMAP_TIMER_CTRL_SCPWM;
383 if (toggle)
384 l |= OMAP_TIMER_CTRL_PT;
385 l |= trigger << 10;
221 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 386 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
222} 387}
223 388
224void omap_dm_timer_stop(struct omap_dm_timer *timer) 389void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
225{ 390{
226 u32 l; 391 u32 l;
227 392
228 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 393 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
229 l &= ~0x1; 394 l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
395 if (prescaler >= 0x00 && prescaler <= 0x07) {
396 l |= OMAP_TIMER_CTRL_PRE;
397 l |= prescaler << 2;
398 }
230 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 399 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
231} 400}
232 401
233unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) 402void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
403 unsigned int value)
234{ 404{
235 return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); 405 omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
236} 406}
237 407
238void omap_dm_timer_reset_counter(struct omap_dm_timer *timer) 408unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
239{ 409{
240 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0); 410 return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
241} 411}
242 412
243void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) 413void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
244{ 414{
245 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); 415 omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
246} 416}
247 417
248void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match) 418unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
249{ 419{
250 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); 420 return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
251} 421}
252 422
253void omap_dm_timer_enable_compare(struct omap_dm_timer *timer) 423int omap_dm_timers_active(void)
254{ 424{
255 u32 l; 425 int i;
256 426
257 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 427 for (i = 0; i < dm_timer_count; i++) {
258 l |= OMAP_TIMER_CTRL_CE; 428 struct omap_dm_timer *timer;
259 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
260}
261 429
430 timer = &dm_timers[i];
431 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
432 OMAP_TIMER_CTRL_ST)
433 return 1;
434 }
435 return 0;
436}
262 437
263static inline void __dm_timer_init(void) 438int omap_dm_timer_init(void)
264{ 439{
265 struct omap_dm_timer *timer; 440 struct omap_dm_timer *timer;
441 int i;
442
443 if (!(cpu_is_omap16xx() || cpu_is_omap24xx()))
444 return -ENODEV;
266 445
267 spin_lock_init(&dm_timer_lock); 446 spin_lock_init(&dm_timer_lock);
268 INIT_LIST_HEAD(&dm_timer_info.unused_timers); 447 for (i = 0; i < dm_timer_count; i++) {
269 INIT_LIST_HEAD(&dm_timer_info.reserved_timers); 448#ifdef CONFIG_ARCH_OMAP2
270 449 char clk_name[16];
271 timer = &dm_timers[0]; 450#endif
272 while (timer->base) { 451
273 list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers); 452 timer = &dm_timers[i];
274 omap_dm_timer_reset(timer); 453 timer->io_base = (void __iomem *) io_p2v(timer->phys_base);
275 timer++; 454#ifdef CONFIG_ARCH_OMAP2
455 sprintf(clk_name, "gpt%d_ick", i + 1);
456 timer->iclk = clk_get(NULL, clk_name);
457 sprintf(clk_name, "gpt%d_fck", i + 1);
458 timer->fclk = clk_get(NULL, clk_name);
459#endif
276 } 460 }
277}
278 461
279static int __init omap_dm_timer_init(void)
280{
281 if (cpu_is_omap16xx())
282 __dm_timer_init();
283 return 0; 462 return 0;
284} 463}
285
286arch_initcall(omap_dm_timer_init);
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
index 3461a6c9665c..f028e182215a 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.
@@ -79,18 +80,6 @@ struct sys_timer omap_timer;
79#define OMAP1_32K_TIMER_TVR 0x00 80#define OMAP1_32K_TIMER_TVR 0x00
80#define OMAP1_32K_TIMER_TCR 0x04 81#define OMAP1_32K_TIMER_TCR 0x04
81 82
82/* 24xx specific defines */
83#define OMAP2_GP_TIMER_BASE 0x48028000
84#define CM_CLKSEL_WKUP 0x48008440
85#define GP_TIMER_TIDR 0x00
86#define GP_TIMER_TISR 0x18
87#define GP_TIMER_TIER 0x1c
88#define GP_TIMER_TCLR 0x24
89#define GP_TIMER_TCRR 0x28
90#define GP_TIMER_TLDR 0x2c
91#define GP_TIMER_TTGR 0x30
92#define GP_TIMER_TSICR 0x40
93
94#define OMAP_32K_TICKS_PER_HZ (32768 / HZ) 83#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
95 84
96/* 85/*
@@ -102,54 +91,64 @@ struct sys_timer omap_timer;
102#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ 91#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
103 (((nr_jiffies) * (clock_rate)) / HZ) 92 (((nr_jiffies) * (clock_rate)) / HZ)
104 93
94#if defined(CONFIG_ARCH_OMAP1)
95
105static inline void omap_32k_timer_write(int val, int reg) 96static inline void omap_32k_timer_write(int val, int reg)
106{ 97{
107 if (cpu_class_is_omap1()) 98 omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
108 omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
109
110 if (cpu_is_omap24xx())
111 omap_writel(val, OMAP2_GP_TIMER_BASE + reg);
112} 99}
113 100
114static inline unsigned long omap_32k_timer_read(int reg) 101static inline unsigned long omap_32k_timer_read(int reg)
115{ 102{
116 if (cpu_class_is_omap1()) 103 return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff;
117 return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; 104}
118 105
119 if (cpu_is_omap24xx()) 106static inline void omap_32k_timer_start(unsigned long load_val)
120 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);
121} 110}
122 111
123/* 112static inline void omap_32k_timer_stop(void)
124 * The 32KHz synchronized timer is an additional timer on 16xx.
125 * It is always running.
126 */
127static inline unsigned long omap_32k_sync_timer_read(void)
128{ 113{
129 return omap_readl(TIMER_32K_SYNCHRONIZED); 114 omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR);
130} 115}
131 116
117#define omap_32k_timer_ack_irq()
118
119#elif defined(CONFIG_ARCH_OMAP2)
120
121#include <asm/arch/dmtimer.h>
122
123static struct omap_dm_timer *gptimer;
124
132static inline void omap_32k_timer_start(unsigned long load_val) 125static inline void omap_32k_timer_start(unsigned long load_val)
133{ 126{
134 if (cpu_class_is_omap1()) { 127 omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val);
135 omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); 128 omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
136 omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); 129 omap_dm_timer_start(gptimer);
137 }
138
139 if (cpu_is_omap24xx()) {
140 omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR);
141 omap_32k_timer_write((1 << 1), GP_TIMER_TIER);
142 omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR);
143 }
144} 130}
145 131
146static inline void omap_32k_timer_stop(void) 132static inline void omap_32k_timer_stop(void)
147{ 133{
148 if (cpu_class_is_omap1()) 134 omap_dm_timer_stop(gptimer);
149 omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); 135}
150 136
151 if (cpu_is_omap24xx()) 137static inline void omap_32k_timer_ack_irq(void)
152 omap_32k_timer_write(0x0, GP_TIMER_TCLR); 138{
139 u32 status = omap_dm_timer_read_status(gptimer);
140 omap_dm_timer_write_status(gptimer, status);
141}
142
143#endif
144
145/*
146 * The 32KHz synchronized timer is an additional timer on 16xx.
147 * It is always running.
148 */
149static inline unsigned long omap_32k_sync_timer_read(void)
150{
151 return omap_readl(TIMER_32K_SYNCHRONIZED);
153} 152}
154 153
155/* 154/*
@@ -203,11 +202,7 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
203 202
204 write_seqlock_irqsave(&xtime_lock, flags); 203 write_seqlock_irqsave(&xtime_lock, flags);
205 204
206 if (cpu_is_omap24xx()) { 205 omap_32k_timer_ack_irq();
207 u32 status = omap_32k_timer_read(GP_TIMER_TISR);
208 omap_32k_timer_write(status, GP_TIMER_TISR);
209 }
210
211 now = omap_32k_sync_timer_read(); 206 now = omap_32k_sync_timer_read();
212 207
213 while ((signed long)(now - omap_32k_last_tick) 208 while ((signed long)(now - omap_32k_last_tick)
@@ -269,9 +264,6 @@ static struct irqaction omap_32k_timer_irq = {
269 .handler = omap_32k_timer_interrupt, 264 .handler = omap_32k_timer_interrupt,
270}; 265};
271 266
272static struct clk * gpt1_ick;
273static struct clk * gpt1_fck;
274
275static __init void omap_init_32k_timer(void) 267static __init void omap_init_32k_timer(void)
276{ 268{
277#ifdef CONFIG_NO_IDLE_HZ 269#ifdef CONFIG_NO_IDLE_HZ
@@ -280,31 +272,19 @@ static __init void omap_init_32k_timer(void)
280 272
281 if (cpu_class_is_omap1()) 273 if (cpu_class_is_omap1())
282 setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); 274 setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
283 if (cpu_is_omap24xx())
284 setup_irq(37, &omap_32k_timer_irq);
285 omap_timer.offset = omap_32k_timer_gettimeoffset; 275 omap_timer.offset = omap_32k_timer_gettimeoffset;
286 omap_32k_last_tick = omap_32k_sync_timer_read(); 276 omap_32k_last_tick = omap_32k_sync_timer_read();
287 277
288 /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ 278 /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */
289 if (cpu_is_omap24xx()) { 279 if (cpu_is_omap24xx()) {
290 omap_32k_timer_write(0, GP_TIMER_TCLR); 280 gptimer = omap_dm_timer_request_specific(1);
291 omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */ 281 BUG_ON(gptimer == NULL);
292 282
293 gpt1_ick = clk_get(NULL, "gpt1_ick"); 283 omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ);
294 if (IS_ERR(gpt1_ick)) 284 setup_irq(omap_dm_timer_get_irq(gptimer), &omap_32k_timer_irq);
295 printk(KERN_ERR "Could not get gpt1_ick\n"); 285 omap_dm_timer_set_int_enable(gptimer,
296 else 286 OMAP_TIMER_INT_CAPTURE | OMAP_TIMER_INT_OVERFLOW |
297 clk_enable(gpt1_ick); 287 OMAP_TIMER_INT_MATCH);
298
299 gpt1_fck = clk_get(NULL, "gpt1_fck");
300 if (IS_ERR(gpt1_fck))
301 printk(KERN_ERR "Could not get gpt1_fck\n");
302 else
303 clk_enable(gpt1_fck);
304
305 mdelay(100); /* Wait for clocks to stabilize */
306
307 omap_32k_timer_write(0x7, GP_TIMER_TISR);
308 } 288 }
309 289
310 omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); 290 omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
@@ -317,6 +297,9 @@ static __init void omap_init_32k_timer(void)
317 */ 297 */
318static void __init omap_timer_init(void) 298static void __init omap_timer_init(void)
319{ 299{
300#ifdef CONFIG_OMAP_DM_TIMER
301 omap_dm_timer_init();
302#endif
320 omap_init_32k_timer(); 303 omap_init_32k_timer();
321} 304}
322 305