Commit | Line | Data |
---|---|---|
92105bb7 TL |
1 | /* |
2 | * linux/arch/arm/plat-omap/dmtimer.c | |
3 | * | |
4 | * OMAP Dual-Mode Timers | |
5 | * | |
6 | * Copyright (C) 2005 Nokia Corporation | |
77900a2f TT |
7 | * OMAP2 support by Juha Yrjola |
8 | * API improvements and OMAP2 clock framework support by Timo Teras | |
92105bb7 TL |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | |
11 | * under the terms of the GNU General Public License as published by the | |
12 | * Free Software Foundation; either version 2 of the License, or (at your | |
13 | * option) any later version. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
18 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
23 | * | |
24 | * You should have received a copy of the GNU General Public License along | |
25 | * with this program; if not, write to the Free Software Foundation, Inc., | |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
27 | */ | |
28 | ||
29 | #include <linux/init.h> | |
77900a2f TT |
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> | |
0a5709b2 | 35 | #include <asm/hardware.h> |
92105bb7 TL |
36 | #include <asm/arch/dmtimer.h> |
37 | #include <asm/io.h> | |
38 | #include <asm/arch/irqs.h> | |
92105bb7 | 39 | |
77900a2f | 40 | /* register offsets */ |
92105bb7 TL |
41 | #define OMAP_TIMER_ID_REG 0x00 |
42 | #define OMAP_TIMER_OCP_CFG_REG 0x10 | |
43 | #define OMAP_TIMER_SYS_STAT_REG 0x14 | |
44 | #define OMAP_TIMER_STAT_REG 0x18 | |
45 | #define OMAP_TIMER_INT_EN_REG 0x1c | |
46 | #define OMAP_TIMER_WAKEUP_EN_REG 0x20 | |
47 | #define OMAP_TIMER_CTRL_REG 0x24 | |
48 | #define OMAP_TIMER_COUNTER_REG 0x28 | |
49 | #define OMAP_TIMER_LOAD_REG 0x2c | |
50 | #define OMAP_TIMER_TRIGGER_REG 0x30 | |
471b3aa7 | 51 | #define OMAP_TIMER_WRITE_PEND_REG 0x34 |
92105bb7 TL |
52 | #define OMAP_TIMER_MATCH_REG 0x38 |
53 | #define OMAP_TIMER_CAPTURE_REG 0x3c | |
54 | #define OMAP_TIMER_IF_CTRL_REG 0x40 | |
55 | ||
77900a2f TT |
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; | |
ce2df9ca | 73 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) |
77900a2f TT |
74 | struct clk *iclk, *fclk; |
75 | #endif | |
76 | void __iomem *io_base; | |
77 | unsigned reserved:1; | |
12583a70 | 78 | unsigned enabled:1; |
77900a2f TT |
79 | }; |
80 | ||
81 | #ifdef CONFIG_ARCH_OMAP1 | |
82 | ||
fa4bb626 TT |
83 | #define omap_dm_clk_enable(x) |
84 | #define omap_dm_clk_disable(x) | |
471b3aa7 SMK |
85 | #define omap2_dm_timers NULL |
86 | #define omap2_dm_source_names NULL | |
87 | #define omap2_dm_source_clocks NULL | |
ce2df9ca SMK |
88 | #define omap3_dm_timers NULL |
89 | #define omap3_dm_source_names NULL | |
90 | #define omap3_dm_source_clocks NULL | |
fa4bb626 | 91 | |
471b3aa7 | 92 | static struct omap_dm_timer omap1_dm_timers[] = { |
77900a2f TT |
93 | { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, |
94 | { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, | |
95 | { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 }, | |
96 | { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 }, | |
97 | { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 }, | |
98 | { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 }, | |
53037f4c MP |
99 | { .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 }, |
100 | { .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 }, | |
77900a2f | 101 | }; |
92105bb7 | 102 | |
471b3aa7 SMK |
103 | static const int dm_timer_count = ARRAY_SIZE(omap1_dm_timers); |
104 | ||
77900a2f | 105 | #elif defined(CONFIG_ARCH_OMAP2) |
92105bb7 | 106 | |
471b3aa7 SMK |
107 | #define omap_dm_clk_enable(x) clk_enable(x) |
108 | #define omap_dm_clk_disable(x) clk_disable(x) | |
109 | #define omap1_dm_timers NULL | |
ce2df9ca SMK |
110 | #define omap3_dm_timers NULL |
111 | #define omap3_dm_source_names NULL | |
112 | #define omap3_dm_source_clocks NULL | |
fa4bb626 | 113 | |
471b3aa7 | 114 | static struct omap_dm_timer omap2_dm_timers[] = { |
77900a2f TT |
115 | { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 }, |
116 | { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 }, | |
117 | { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 }, | |
118 | { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 }, | |
119 | { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 }, | |
120 | { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 }, | |
121 | { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 }, | |
122 | { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 }, | |
123 | { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 }, | |
124 | { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 }, | |
125 | { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 }, | |
126 | { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 }, | |
92105bb7 TL |
127 | }; |
128 | ||
471b3aa7 | 129 | static const char *omap2_dm_source_names[] __initdata = { |
83379c81 TT |
130 | "sys_ck", |
131 | "func_32k_ck", | |
471b3aa7 SMK |
132 | "alt_ck", |
133 | NULL | |
83379c81 TT |
134 | }; |
135 | ||
471b3aa7 SMK |
136 | static struct clk **omap2_dm_source_clocks[3]; |
137 | static const int dm_timer_count = ARRAY_SIZE(omap2_dm_timers); | |
83379c81 | 138 | |
ce2df9ca SMK |
139 | #elif defined(CONFIG_ARCH_OMAP3) |
140 | ||
141 | #define omap_dm_clk_enable(x) clk_enable(x) | |
142 | #define omap_dm_clk_disable(x) clk_disable(x) | |
143 | #define omap1_dm_timers NULL | |
144 | #define omap2_dm_timers NULL | |
145 | #define omap2_dm_source_names NULL | |
146 | #define omap2_dm_source_clocks NULL | |
147 | ||
148 | static struct omap_dm_timer omap3_dm_timers[] = { | |
149 | { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 }, | |
150 | { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 }, | |
151 | { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 }, | |
152 | { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 }, | |
153 | { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 }, | |
154 | { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 }, | |
155 | { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 }, | |
156 | { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 }, | |
157 | { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 }, | |
158 | { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 }, | |
159 | { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 }, | |
160 | { .phys_base = 0x48304000, .irq = INT_24XX_GPTIMER12 }, | |
161 | }; | |
162 | ||
163 | static const char *omap3_dm_source_names[] __initdata = { | |
164 | "sys_ck", | |
165 | "omap_32k_fck", | |
166 | NULL | |
167 | }; | |
168 | ||
169 | static struct clk **omap3_dm_source_clocks[2]; | |
170 | static const int dm_timer_count = ARRAY_SIZE(omap3_dm_timers); | |
171 | ||
77900a2f TT |
172 | #else |
173 | ||
174 | #error OMAP architecture not supported! | |
175 | ||
176 | #endif | |
177 | ||
471b3aa7 SMK |
178 | static struct omap_dm_timer *dm_timers; |
179 | static char **dm_source_names; | |
180 | static struct clk **dm_source_clocks; | |
181 | ||
92105bb7 TL |
182 | static spinlock_t dm_timer_lock; |
183 | ||
77900a2f TT |
184 | static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) |
185 | { | |
186 | return readl(timer->io_base + reg); | |
187 | } | |
92105bb7 | 188 | |
77900a2f | 189 | static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) |
92105bb7 | 190 | { |
77900a2f | 191 | writel(value, timer->io_base + reg); |
92105bb7 TL |
192 | while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) |
193 | ; | |
194 | } | |
195 | ||
77900a2f | 196 | static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) |
92105bb7 | 197 | { |
77900a2f TT |
198 | int c; |
199 | ||
200 | c = 0; | |
201 | while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { | |
202 | c++; | |
203 | if (c > 100000) { | |
204 | printk(KERN_ERR "Timer failed to reset\n"); | |
205 | return; | |
206 | } | |
207 | } | |
92105bb7 TL |
208 | } |
209 | ||
77900a2f TT |
210 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) |
211 | { | |
212 | u32 l; | |
213 | ||
39020842 | 214 | if (!cpu_class_is_omap2() || timer != &dm_timers[0]) { |
e32f7ec2 TT |
215 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); |
216 | omap_dm_timer_wait_for_reset(timer); | |
217 | } | |
12583a70 | 218 | omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); |
77900a2f TT |
219 | |
220 | /* Set to smart-idle mode */ | |
221 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); | |
222 | l |= 0x02 << 3; | |
39020842 JY |
223 | |
224 | if (cpu_class_is_omap2() && timer == &dm_timers[0]) { | |
225 | /* Enable wake-up only for GPT1 on OMAP2 CPUs*/ | |
226 | l |= 1 << 2; | |
227 | /* Non-posted mode */ | |
228 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0); | |
229 | } | |
77900a2f TT |
230 | omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); |
231 | } | |
232 | ||
83379c81 | 233 | static void omap_dm_timer_prepare(struct omap_dm_timer *timer) |
77900a2f | 234 | { |
12583a70 | 235 | omap_dm_timer_enable(timer); |
77900a2f TT |
236 | omap_dm_timer_reset(timer); |
237 | } | |
238 | ||
239 | struct omap_dm_timer *omap_dm_timer_request(void) | |
240 | { | |
241 | struct omap_dm_timer *timer = NULL; | |
242 | unsigned long flags; | |
243 | int i; | |
244 | ||
245 | spin_lock_irqsave(&dm_timer_lock, flags); | |
246 | for (i = 0; i < dm_timer_count; i++) { | |
247 | if (dm_timers[i].reserved) | |
248 | continue; | |
249 | ||
250 | timer = &dm_timers[i]; | |
83379c81 | 251 | timer->reserved = 1; |
77900a2f TT |
252 | break; |
253 | } | |
254 | spin_unlock_irqrestore(&dm_timer_lock, flags); | |
255 | ||
83379c81 TT |
256 | if (timer != NULL) |
257 | omap_dm_timer_prepare(timer); | |
258 | ||
77900a2f TT |
259 | return timer; |
260 | } | |
261 | ||
262 | struct omap_dm_timer *omap_dm_timer_request_specific(int id) | |
92105bb7 TL |
263 | { |
264 | struct omap_dm_timer *timer; | |
77900a2f | 265 | unsigned long flags; |
92105bb7 | 266 | |
77900a2f TT |
267 | spin_lock_irqsave(&dm_timer_lock, flags); |
268 | if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) { | |
269 | spin_unlock_irqrestore(&dm_timer_lock, flags); | |
270 | printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n", | |
8e86f427 | 271 | __FILE__, __LINE__, __func__, id); |
77900a2f TT |
272 | dump_stack(); |
273 | return NULL; | |
274 | } | |
92105bb7 | 275 | |
77900a2f | 276 | timer = &dm_timers[id-1]; |
83379c81 | 277 | timer->reserved = 1; |
77900a2f TT |
278 | spin_unlock_irqrestore(&dm_timer_lock, flags); |
279 | ||
83379c81 TT |
280 | omap_dm_timer_prepare(timer); |
281 | ||
77900a2f | 282 | return timer; |
92105bb7 TL |
283 | } |
284 | ||
77900a2f TT |
285 | void omap_dm_timer_free(struct omap_dm_timer *timer) |
286 | { | |
12583a70 | 287 | omap_dm_timer_enable(timer); |
77900a2f | 288 | omap_dm_timer_reset(timer); |
12583a70 | 289 | omap_dm_timer_disable(timer); |
fa4bb626 | 290 | |
77900a2f TT |
291 | WARN_ON(!timer->reserved); |
292 | timer->reserved = 0; | |
293 | } | |
294 | ||
12583a70 TT |
295 | void omap_dm_timer_enable(struct omap_dm_timer *timer) |
296 | { | |
297 | if (timer->enabled) | |
298 | return; | |
299 | ||
300 | omap_dm_clk_enable(timer->fclk); | |
301 | omap_dm_clk_enable(timer->iclk); | |
302 | ||
303 | timer->enabled = 1; | |
304 | } | |
305 | ||
306 | void omap_dm_timer_disable(struct omap_dm_timer *timer) | |
307 | { | |
308 | if (!timer->enabled) | |
309 | return; | |
310 | ||
311 | omap_dm_clk_disable(timer->iclk); | |
312 | omap_dm_clk_disable(timer->fclk); | |
313 | ||
314 | timer->enabled = 0; | |
315 | } | |
316 | ||
77900a2f TT |
317 | int omap_dm_timer_get_irq(struct omap_dm_timer *timer) |
318 | { | |
319 | return timer->irq; | |
320 | } | |
321 | ||
322 | #if defined(CONFIG_ARCH_OMAP1) | |
323 | ||
a569c6ec TL |
324 | /** |
325 | * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR | |
326 | * @inputmask: current value of idlect mask | |
327 | */ | |
328 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) | |
329 | { | |
77900a2f | 330 | int i; |
a569c6ec TL |
331 | |
332 | /* If ARMXOR cannot be idled this function call is unnecessary */ | |
333 | if (!(inputmask & (1 << 1))) | |
334 | return inputmask; | |
335 | ||
336 | /* If any active timer is using ARMXOR return modified mask */ | |
77900a2f TT |
337 | for (i = 0; i < dm_timer_count; i++) { |
338 | u32 l; | |
339 | ||
35912c79 | 340 | l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG); |
77900a2f TT |
341 | if (l & OMAP_TIMER_CTRL_ST) { |
342 | if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) | |
a569c6ec TL |
343 | inputmask &= ~(1 << 1); |
344 | else | |
345 | inputmask &= ~(1 << 2); | |
346 | } | |
77900a2f | 347 | } |
a569c6ec TL |
348 | |
349 | return inputmask; | |
350 | } | |
351 | ||
ce2df9ca | 352 | #elif defined(CONFIG_ARCH_OMAP2) || defined (CONFIG_ARCH_OMAP3) |
a569c6ec | 353 | |
77900a2f | 354 | struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) |
92105bb7 | 355 | { |
fa4bb626 | 356 | return timer->fclk; |
77900a2f | 357 | } |
92105bb7 | 358 | |
77900a2f TT |
359 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) |
360 | { | |
361 | BUG(); | |
2121880e DB |
362 | |
363 | return 0; | |
92105bb7 TL |
364 | } |
365 | ||
77900a2f | 366 | #endif |
92105bb7 | 367 | |
77900a2f | 368 | void omap_dm_timer_trigger(struct omap_dm_timer *timer) |
92105bb7 | 369 | { |
77900a2f | 370 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); |
92105bb7 TL |
371 | } |
372 | ||
77900a2f TT |
373 | void omap_dm_timer_start(struct omap_dm_timer *timer) |
374 | { | |
375 | u32 l; | |
92105bb7 | 376 | |
77900a2f TT |
377 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
378 | if (!(l & OMAP_TIMER_CTRL_ST)) { | |
379 | l |= OMAP_TIMER_CTRL_ST; | |
380 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | |
381 | } | |
382 | } | |
92105bb7 | 383 | |
77900a2f | 384 | void omap_dm_timer_stop(struct omap_dm_timer *timer) |
92105bb7 | 385 | { |
77900a2f | 386 | u32 l; |
92105bb7 | 387 | |
77900a2f TT |
388 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
389 | if (l & OMAP_TIMER_CTRL_ST) { | |
390 | l &= ~0x1; | |
391 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | |
92105bb7 | 392 | } |
92105bb7 TL |
393 | } |
394 | ||
77900a2f | 395 | #ifdef CONFIG_ARCH_OMAP1 |
92105bb7 | 396 | |
77900a2f | 397 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
92105bb7 | 398 | { |
77900a2f TT |
399 | int n = (timer - dm_timers) << 1; |
400 | u32 l; | |
92105bb7 | 401 | |
77900a2f TT |
402 | l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); |
403 | l |= source << n; | |
404 | omap_writel(l, MOD_CONF_CTRL_1); | |
92105bb7 TL |
405 | } |
406 | ||
77900a2f | 407 | #else |
92105bb7 | 408 | |
77900a2f | 409 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
92105bb7 | 410 | { |
77900a2f TT |
411 | if (source < 0 || source >= 3) |
412 | return; | |
413 | ||
77900a2f | 414 | clk_disable(timer->fclk); |
83379c81 | 415 | clk_set_parent(timer->fclk, dm_source_clocks[source]); |
77900a2f | 416 | clk_enable(timer->fclk); |
77900a2f TT |
417 | |
418 | /* When the functional clock disappears, too quick writes seem to | |
419 | * cause an abort. */ | |
c40fae95 | 420 | __delay(150000); |
92105bb7 TL |
421 | } |
422 | ||
77900a2f | 423 | #endif |
92105bb7 | 424 | |
77900a2f TT |
425 | void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, |
426 | unsigned int load) | |
92105bb7 TL |
427 | { |
428 | u32 l; | |
77900a2f | 429 | |
92105bb7 | 430 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
77900a2f TT |
431 | if (autoreload) |
432 | l |= OMAP_TIMER_CTRL_AR; | |
433 | else | |
434 | l &= ~OMAP_TIMER_CTRL_AR; | |
92105bb7 | 435 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
77900a2f TT |
436 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); |
437 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); | |
92105bb7 TL |
438 | } |
439 | ||
77900a2f TT |
440 | void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, |
441 | unsigned int match) | |
92105bb7 TL |
442 | { |
443 | u32 l; | |
444 | ||
445 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | |
83379c81 | 446 | if (enable) |
77900a2f TT |
447 | l |= OMAP_TIMER_CTRL_CE; |
448 | else | |
449 | l &= ~OMAP_TIMER_CTRL_CE; | |
92105bb7 | 450 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
77900a2f | 451 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); |
92105bb7 TL |
452 | } |
453 | ||
77900a2f TT |
454 | |
455 | void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, | |
456 | int toggle, int trigger) | |
92105bb7 TL |
457 | { |
458 | u32 l; | |
459 | ||
460 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | |
77900a2f TT |
461 | l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | |
462 | OMAP_TIMER_CTRL_PT | (0x03 << 10)); | |
463 | if (def_on) | |
464 | l |= OMAP_TIMER_CTRL_SCPWM; | |
465 | if (toggle) | |
466 | l |= OMAP_TIMER_CTRL_PT; | |
467 | l |= trigger << 10; | |
92105bb7 TL |
468 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
469 | } | |
470 | ||
77900a2f | 471 | void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) |
92105bb7 TL |
472 | { |
473 | u32 l; | |
474 | ||
475 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | |
77900a2f TT |
476 | l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); |
477 | if (prescaler >= 0x00 && prescaler <= 0x07) { | |
478 | l |= OMAP_TIMER_CTRL_PRE; | |
479 | l |= prescaler << 2; | |
480 | } | |
92105bb7 TL |
481 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
482 | } | |
483 | ||
77900a2f TT |
484 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, |
485 | unsigned int value) | |
92105bb7 | 486 | { |
77900a2f | 487 | omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); |
39020842 | 488 | omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value); |
92105bb7 TL |
489 | } |
490 | ||
77900a2f | 491 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) |
92105bb7 | 492 | { |
fa4bb626 TT |
493 | unsigned int l; |
494 | ||
fa4bb626 | 495 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); |
fa4bb626 TT |
496 | |
497 | return l; | |
92105bb7 TL |
498 | } |
499 | ||
77900a2f | 500 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) |
92105bb7 | 501 | { |
77900a2f | 502 | omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); |
92105bb7 TL |
503 | } |
504 | ||
77900a2f | 505 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) |
92105bb7 | 506 | { |
fa4bb626 TT |
507 | unsigned int l; |
508 | ||
fa4bb626 | 509 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); |
fa4bb626 TT |
510 | |
511 | return l; | |
92105bb7 TL |
512 | } |
513 | ||
83379c81 TT |
514 | void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) |
515 | { | |
fa4bb626 | 516 | omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); |
83379c81 TT |
517 | } |
518 | ||
77900a2f | 519 | int omap_dm_timers_active(void) |
92105bb7 | 520 | { |
77900a2f | 521 | int i; |
92105bb7 | 522 | |
77900a2f TT |
523 | for (i = 0; i < dm_timer_count; i++) { |
524 | struct omap_dm_timer *timer; | |
92105bb7 | 525 | |
77900a2f | 526 | timer = &dm_timers[i]; |
12583a70 TT |
527 | |
528 | if (!timer->enabled) | |
529 | continue; | |
530 | ||
77900a2f | 531 | if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & |
fa4bb626 | 532 | OMAP_TIMER_CTRL_ST) { |
77900a2f | 533 | return 1; |
fa4bb626 | 534 | } |
77900a2f TT |
535 | } |
536 | return 0; | |
537 | } | |
92105bb7 | 538 | |
471b3aa7 | 539 | int __init omap_dm_timer_init(void) |
92105bb7 TL |
540 | { |
541 | struct omap_dm_timer *timer; | |
77900a2f TT |
542 | int i; |
543 | ||
ce2df9ca | 544 | if (!(cpu_is_omap16xx() || cpu_class_is_omap2())) |
77900a2f | 545 | return -ENODEV; |
92105bb7 TL |
546 | |
547 | spin_lock_init(&dm_timer_lock); | |
471b3aa7 SMK |
548 | |
549 | if (cpu_class_is_omap1()) | |
550 | dm_timers = omap1_dm_timers; | |
551 | else if (cpu_is_omap24xx()) { | |
552 | dm_timers = omap2_dm_timers; | |
553 | dm_source_names = (char **)omap2_dm_source_names; | |
554 | dm_source_clocks = (struct clk **)omap2_dm_source_clocks; | |
ce2df9ca SMK |
555 | } else if (cpu_is_omap34xx()) { |
556 | dm_timers = omap3_dm_timers; | |
557 | dm_source_names = (char **)omap3_dm_source_names; | |
558 | dm_source_clocks = (struct clk **)omap3_dm_source_clocks; | |
83379c81 | 559 | } |
471b3aa7 SMK |
560 | |
561 | if (cpu_class_is_omap2()) | |
562 | for (i = 0; dm_source_names[i] != NULL; i++) | |
563 | dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]); | |
564 | ||
56a25641 SMK |
565 | if (cpu_is_omap243x()) |
566 | dm_timers[0].phys_base = 0x49018000; | |
83379c81 | 567 | |
77900a2f | 568 | for (i = 0; i < dm_timer_count; i++) { |
77900a2f | 569 | timer = &dm_timers[i]; |
471b3aa7 | 570 | timer->io_base = (void __iomem *)io_p2v(timer->phys_base); |
ce2df9ca | 571 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) |
471b3aa7 SMK |
572 | if (cpu_class_is_omap2()) { |
573 | char clk_name[16]; | |
574 | sprintf(clk_name, "gpt%d_ick", i + 1); | |
575 | timer->iclk = clk_get(NULL, clk_name); | |
576 | sprintf(clk_name, "gpt%d_fck", i + 1); | |
577 | timer->fclk = clk_get(NULL, clk_name); | |
578 | } | |
77900a2f | 579 | #endif |
92105bb7 | 580 | } |
92105bb7 | 581 | |
92105bb7 TL |
582 | return 0; |
583 | } |