diff options
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 428 |
1 files changed, 310 insertions, 118 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index eba3cb52ad87..50524436de63 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,196 @@ | |||
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 | |||
70 | struct 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 | }; | ||
53 | 79 | ||
54 | static struct dmtimer_info_struct { | 80 | #ifdef CONFIG_ARCH_OMAP1 |
55 | struct list_head unused_timers; | ||
56 | struct list_head reserved_timers; | ||
57 | } dm_timer_info; | ||
58 | 81 | ||
59 | static struct omap_dm_timer dm_timers[] = { | 82 | static struct omap_dm_timer dm_timers[] = { |
60 | { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 }, | 83 | { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, |
61 | { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 }, | 84 | { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, |
62 | { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 }, | 85 | { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 }, |
63 | { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 }, | 86 | { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 }, |
64 | { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 }, | 87 | { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 }, |
65 | { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 }, | 88 | { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 }, |
66 | { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 }, | 89 | { .phys_base = 0xfffb4400, .irq = INT_1610_GPTIMER7 }, |
67 | { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 }, | 90 | { .phys_base = 0xfffb4c00, .irq = INT_1610_GPTIMER8 }, |
68 | { .base=0x0 }, | ||
69 | }; | 91 | }; |
70 | 92 | ||
93 | #elif defined(CONFIG_ARCH_OMAP2) | ||
94 | |||
95 | static struct omap_dm_timer dm_timers[] = { | ||
96 | { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 }, | ||
97 | { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 }, | ||
98 | { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 }, | ||
99 | { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 }, | ||
100 | { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 }, | ||
101 | { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 }, | ||
102 | { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 }, | ||
103 | { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 }, | ||
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 }, | ||
108 | }; | ||
109 | |||
110 | static const char *dm_source_names[] = { | ||
111 | "sys_ck", | ||
112 | "func_32k_ck", | ||
113 | "alt_ck" | ||
114 | }; | ||
71 | 115 | ||
116 | static struct clk *dm_source_clocks[3]; | ||
117 | |||
118 | #else | ||
119 | |||
120 | #error OMAP architecture not supported! | ||
121 | |||
122 | #endif | ||
123 | |||
124 | static const int dm_timer_count = ARRAY_SIZE(dm_timers); | ||
72 | static spinlock_t dm_timer_lock; | 125 | static spinlock_t dm_timer_lock; |
73 | 126 | ||
127 | static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) | ||
128 | { | ||
129 | return readl(timer->io_base + reg); | ||
130 | } | ||
74 | 131 | ||
75 | inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) | 132 | static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) |
76 | { | 133 | { |
77 | omap_writel(value, timer->base + reg); | 134 | writel(value, timer->io_base + reg); |
78 | while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) | 135 | while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) |
79 | ; | 136 | ; |
80 | } | 137 | } |
81 | 138 | ||
82 | u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) | 139 | static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) |
83 | { | 140 | { |
84 | return omap_readl(timer->base + reg); | 141 | int c; |
142 | |||
143 | c = 0; | ||
144 | while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { | ||
145 | c++; | ||
146 | if (c > 100000) { | ||
147 | printk(KERN_ERR "Timer failed to reset\n"); | ||
148 | return; | ||
149 | } | ||
150 | } | ||
85 | } | 151 | } |
86 | 152 | ||
87 | int omap_dm_timers_active(void) | 153 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) |
154 | { | ||
155 | u32 l; | ||
156 | |||
157 | if (timer != &dm_timers[0]) { | ||
158 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); | ||
159 | omap_dm_timer_wait_for_reset(timer); | ||
160 | } | ||
161 | omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK); | ||
162 | |||
163 | /* Set to smart-idle mode */ | ||
164 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); | ||
165 | l |= 0x02 << 3; | ||
166 | omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); | ||
167 | } | ||
168 | |||
169 | static void omap_dm_timer_prepare(struct omap_dm_timer *timer) | ||
170 | { | ||
171 | #ifdef CONFIG_ARCH_OMAP2 | ||
172 | clk_enable(timer->iclk); | ||
173 | clk_enable(timer->fclk); | ||
174 | #endif | ||
175 | omap_dm_timer_reset(timer); | ||
176 | } | ||
177 | |||
178 | struct omap_dm_timer *omap_dm_timer_request(void) | ||
179 | { | ||
180 | struct omap_dm_timer *timer = NULL; | ||
181 | unsigned long flags; | ||
182 | int i; | ||
183 | |||
184 | spin_lock_irqsave(&dm_timer_lock, flags); | ||
185 | for (i = 0; i < dm_timer_count; i++) { | ||
186 | if (dm_timers[i].reserved) | ||
187 | continue; | ||
188 | |||
189 | timer = &dm_timers[i]; | ||
190 | timer->reserved = 1; | ||
191 | break; | ||
192 | } | ||
193 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
194 | |||
195 | if (timer != NULL) | ||
196 | omap_dm_timer_prepare(timer); | ||
197 | |||
198 | return timer; | ||
199 | } | ||
200 | |||
201 | struct omap_dm_timer *omap_dm_timer_request_specific(int id) | ||
88 | { | 202 | { |
89 | struct omap_dm_timer *timer; | 203 | struct omap_dm_timer *timer; |
204 | unsigned long flags; | ||
90 | 205 | ||
91 | for (timer = &dm_timers[0]; timer->base; ++timer) | 206 | spin_lock_irqsave(&dm_timer_lock, flags); |
92 | if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & | 207 | if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) { |
93 | OMAP_TIMER_CTRL_ST) | 208 | spin_unlock_irqrestore(&dm_timer_lock, flags); |
94 | return 1; | 209 | printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n", |
210 | __FILE__, __LINE__, __FUNCTION__, id); | ||
211 | dump_stack(); | ||
212 | return NULL; | ||
213 | } | ||
95 | 214 | ||
96 | return 0; | 215 | timer = &dm_timers[id-1]; |
216 | timer->reserved = 1; | ||
217 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
218 | |||
219 | omap_dm_timer_prepare(timer); | ||
220 | |||
221 | return timer; | ||
97 | } | 222 | } |
98 | 223 | ||
224 | void omap_dm_timer_free(struct omap_dm_timer *timer) | ||
225 | { | ||
226 | omap_dm_timer_reset(timer); | ||
227 | #ifdef CONFIG_ARCH_OMAP2 | ||
228 | clk_disable(timer->iclk); | ||
229 | clk_disable(timer->fclk); | ||
230 | #endif | ||
231 | WARN_ON(!timer->reserved); | ||
232 | timer->reserved = 0; | ||
233 | } | ||
234 | |||
235 | int omap_dm_timer_get_irq(struct omap_dm_timer *timer) | ||
236 | { | ||
237 | return timer->irq; | ||
238 | } | ||
239 | |||
240 | #if defined(CONFIG_ARCH_OMAP1) | ||
241 | |||
242 | struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) | ||
243 | { | ||
244 | BUG(); | ||
245 | } | ||
99 | 246 | ||
100 | /** | 247 | /** |
101 | * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR | 248 | * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR |
@@ -103,184 +250,229 @@ int omap_dm_timers_active(void) | |||
103 | */ | 250 | */ |
104 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) | 251 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) |
105 | { | 252 | { |
106 | int n; | 253 | int i; |
107 | 254 | ||
108 | /* If ARMXOR cannot be idled this function call is unnecessary */ | 255 | /* If ARMXOR cannot be idled this function call is unnecessary */ |
109 | if (!(inputmask & (1 << 1))) | 256 | if (!(inputmask & (1 << 1))) |
110 | return inputmask; | 257 | return inputmask; |
111 | 258 | ||
112 | /* If any active timer is using ARMXOR return modified mask */ | 259 | /* If any active timer is using ARMXOR return modified mask */ |
113 | for (n = 0; dm_timers[n].base; ++n) | 260 | for (i = 0; i < dm_timer_count; i++) { |
114 | if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)& | 261 | u32 l; |
115 | OMAP_TIMER_CTRL_ST) { | 262 | |
116 | if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0) | 263 | l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG); |
264 | if (l & OMAP_TIMER_CTRL_ST) { | ||
265 | if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) | ||
117 | inputmask &= ~(1 << 1); | 266 | inputmask &= ~(1 << 1); |
118 | else | 267 | else |
119 | inputmask &= ~(1 << 2); | 268 | inputmask &= ~(1 << 2); |
120 | } | 269 | } |
270 | } | ||
121 | 271 | ||
122 | return inputmask; | 272 | return inputmask; |
123 | } | 273 | } |
124 | 274 | ||
275 | #elif defined(CONFIG_ARCH_OMAP2) | ||
125 | 276 | ||
126 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) | 277 | struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) |
127 | { | 278 | { |
128 | int n = (timer - dm_timers) << 1; | 279 | return timer->fclk; |
129 | u32 l; | 280 | } |
130 | 281 | ||
131 | l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); | 282 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) |
132 | l |= source << n; | 283 | { |
133 | omap_writel(l, MOD_CONF_CTRL_1); | 284 | BUG(); |
134 | } | 285 | } |
135 | 286 | ||
287 | #endif | ||
136 | 288 | ||
137 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) | 289 | void omap_dm_timer_trigger(struct omap_dm_timer *timer) |
138 | { | 290 | { |
139 | /* Reset and set posted mode */ | 291 | 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 | } | 292 | } |
145 | 293 | ||
294 | void omap_dm_timer_start(struct omap_dm_timer *timer) | ||
295 | { | ||
296 | u32 l; | ||
146 | 297 | ||
298 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | ||
299 | if (!(l & OMAP_TIMER_CTRL_ST)) { | ||
300 | l |= OMAP_TIMER_CTRL_ST; | ||
301 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | ||
302 | } | ||
303 | } | ||
147 | 304 | ||
148 | struct omap_dm_timer * omap_dm_timer_request(void) | 305 | void omap_dm_timer_stop(struct omap_dm_timer *timer) |
149 | { | 306 | { |
150 | struct omap_dm_timer *timer = NULL; | 307 | u32 l; |
151 | unsigned long flags; | ||
152 | 308 | ||
153 | spin_lock_irqsave(&dm_timer_lock, flags); | 309 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
154 | if (!list_empty(&dm_timer_info.unused_timers)) { | 310 | if (l & OMAP_TIMER_CTRL_ST) { |
155 | timer = (struct omap_dm_timer *) | 311 | l &= ~0x1; |
156 | dm_timer_info.unused_timers.next; | 312 | 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 | } | 313 | } |
160 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
161 | |||
162 | return timer; | ||
163 | } | 314 | } |
164 | 315 | ||
316 | #ifdef CONFIG_ARCH_OMAP1 | ||
165 | 317 | ||
166 | void omap_dm_timer_free(struct omap_dm_timer *timer) | 318 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
167 | { | 319 | { |
168 | unsigned long flags; | 320 | int n = (timer - dm_timers) << 1; |
169 | 321 | u32 l; | |
170 | omap_dm_timer_reset(timer); | ||
171 | 322 | ||
172 | spin_lock_irqsave(&dm_timer_lock, flags); | 323 | l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); |
173 | list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers); | 324 | l |= source << n; |
174 | spin_unlock_irqrestore(&dm_timer_lock, flags); | 325 | omap_writel(l, MOD_CONF_CTRL_1); |
175 | } | 326 | } |
176 | 327 | ||
177 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, | 328 | #else |
178 | unsigned int value) | ||
179 | { | ||
180 | omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); | ||
181 | } | ||
182 | 329 | ||
183 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) | 330 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
184 | { | 331 | { |
185 | return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); | 332 | if (source < 0 || source >= 3) |
186 | } | 333 | return; |
187 | 334 | ||
188 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) | 335 | clk_disable(timer->fclk); |
189 | { | 336 | clk_set_parent(timer->fclk, dm_source_clocks[source]); |
190 | omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); | 337 | clk_enable(timer->fclk); |
338 | |||
339 | /* When the functional clock disappears, too quick writes seem to | ||
340 | * cause an abort. */ | ||
341 | __delay(15000); | ||
191 | } | 342 | } |
192 | 343 | ||
193 | void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer) | 344 | #endif |
345 | |||
346 | void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, | ||
347 | unsigned int load) | ||
194 | { | 348 | { |
195 | u32 l; | 349 | u32 l; |
350 | |||
196 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 351 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
197 | l |= OMAP_TIMER_CTRL_AR; | 352 | if (autoreload) |
353 | l |= OMAP_TIMER_CTRL_AR; | ||
354 | else | ||
355 | l &= ~OMAP_TIMER_CTRL_AR; | ||
198 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 356 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
357 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); | ||
358 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); | ||
199 | } | 359 | } |
200 | 360 | ||
201 | void omap_dm_timer_trigger(struct omap_dm_timer *timer) | 361 | void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, |
202 | { | 362 | unsigned int match) |
203 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1); | ||
204 | } | ||
205 | |||
206 | void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value) | ||
207 | { | 363 | { |
208 | u32 l; | 364 | u32 l; |
209 | 365 | ||
210 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 366 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
211 | l |= value & 0x3; | 367 | if (enable) |
368 | l |= OMAP_TIMER_CTRL_CE; | ||
369 | else | ||
370 | l &= ~OMAP_TIMER_CTRL_CE; | ||
212 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 371 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
372 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); | ||
213 | } | 373 | } |
214 | 374 | ||
215 | void omap_dm_timer_start(struct omap_dm_timer *timer) | 375 | |
376 | void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, | ||
377 | int toggle, int trigger) | ||
216 | { | 378 | { |
217 | u32 l; | 379 | u32 l; |
218 | 380 | ||
219 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 381 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
220 | l |= OMAP_TIMER_CTRL_ST; | 382 | l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | |
383 | OMAP_TIMER_CTRL_PT | (0x03 << 10)); | ||
384 | if (def_on) | ||
385 | l |= OMAP_TIMER_CTRL_SCPWM; | ||
386 | if (toggle) | ||
387 | l |= OMAP_TIMER_CTRL_PT; | ||
388 | l |= trigger << 10; | ||
221 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 389 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
222 | } | 390 | } |
223 | 391 | ||
224 | void omap_dm_timer_stop(struct omap_dm_timer *timer) | 392 | void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) |
225 | { | 393 | { |
226 | u32 l; | 394 | u32 l; |
227 | 395 | ||
228 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 396 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
229 | l &= ~0x1; | 397 | l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); |
398 | if (prescaler >= 0x00 && prescaler <= 0x07) { | ||
399 | l |= OMAP_TIMER_CTRL_PRE; | ||
400 | l |= prescaler << 2; | ||
401 | } | ||
230 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 402 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
231 | } | 403 | } |
232 | 404 | ||
233 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) | 405 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, |
406 | unsigned int value) | ||
234 | { | 407 | { |
235 | return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); | 408 | omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); |
236 | } | 409 | } |
237 | 410 | ||
238 | void omap_dm_timer_reset_counter(struct omap_dm_timer *timer) | 411 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) |
239 | { | 412 | { |
240 | omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0); | 413 | return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); |
241 | } | 414 | } |
242 | 415 | ||
243 | void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) | 416 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) |
244 | { | 417 | { |
245 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); | 418 | omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); |
246 | } | 419 | } |
247 | 420 | ||
248 | void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match) | 421 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) |
249 | { | 422 | { |
250 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); | 423 | return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); |
251 | } | 424 | } |
252 | 425 | ||
253 | void omap_dm_timer_enable_compare(struct omap_dm_timer *timer) | 426 | void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) |
254 | { | 427 | { |
255 | u32 l; | 428 | return omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); |
256 | |||
257 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | ||
258 | l |= OMAP_TIMER_CTRL_CE; | ||
259 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | ||
260 | } | 429 | } |
261 | 430 | ||
431 | int omap_dm_timers_active(void) | ||
432 | { | ||
433 | int i; | ||
434 | |||
435 | for (i = 0; i < dm_timer_count; i++) { | ||
436 | struct omap_dm_timer *timer; | ||
437 | |||
438 | timer = &dm_timers[i]; | ||
439 | if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & | ||
440 | OMAP_TIMER_CTRL_ST) | ||
441 | return 1; | ||
442 | } | ||
443 | return 0; | ||
444 | } | ||
262 | 445 | ||
263 | static inline void __dm_timer_init(void) | 446 | int omap_dm_timer_init(void) |
264 | { | 447 | { |
265 | struct omap_dm_timer *timer; | 448 | struct omap_dm_timer *timer; |
449 | int i; | ||
450 | |||
451 | if (!(cpu_is_omap16xx() || cpu_is_omap24xx())) | ||
452 | return -ENODEV; | ||
266 | 453 | ||
267 | spin_lock_init(&dm_timer_lock); | 454 | spin_lock_init(&dm_timer_lock); |
268 | INIT_LIST_HEAD(&dm_timer_info.unused_timers); | 455 | #ifdef CONFIG_ARCH_OMAP2 |
269 | INIT_LIST_HEAD(&dm_timer_info.reserved_timers); | 456 | for (i = 0; i < ARRAY_SIZE(dm_source_names); i++) { |
270 | 457 | dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]); | |
271 | timer = &dm_timers[0]; | 458 | BUG_ON(dm_source_clocks[i] == NULL); |
272 | while (timer->base) { | 459 | } |
273 | list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers); | 460 | #endif |
274 | omap_dm_timer_reset(timer); | 461 | |
275 | timer++; | 462 | for (i = 0; i < dm_timer_count; i++) { |
463 | #ifdef CONFIG_ARCH_OMAP2 | ||
464 | char clk_name[16]; | ||
465 | #endif | ||
466 | |||
467 | timer = &dm_timers[i]; | ||
468 | timer->io_base = (void __iomem *) io_p2v(timer->phys_base); | ||
469 | #ifdef CONFIG_ARCH_OMAP2 | ||
470 | sprintf(clk_name, "gpt%d_ick", i + 1); | ||
471 | timer->iclk = clk_get(NULL, clk_name); | ||
472 | sprintf(clk_name, "gpt%d_fck", i + 1); | ||
473 | timer->fclk = clk_get(NULL, clk_name); | ||
474 | #endif | ||
276 | } | 475 | } |
277 | } | ||
278 | 476 | ||
279 | static int __init omap_dm_timer_init(void) | ||
280 | { | ||
281 | if (cpu_is_omap16xx()) | ||
282 | __dm_timer_init(); | ||
283 | return 0; | 477 | return 0; |
284 | } | 478 | } |
285 | |||
286 | arch_initcall(omap_dm_timer_init); | ||