]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - arch/arm/plat-omap/dmtimer.c
Merge branch 'for_3.6/fixes/pm' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-hirsute-kernel.git] / arch / arm / plat-omap / dmtimer.c
CommitLineData
92105bb7
TL
1/*
2 * linux/arch/arm/plat-omap/dmtimer.c
3 *
4 * OMAP Dual-Mode Timers
5 *
97933d6c
TKD
6 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
7 * Tarun Kanti DebBarma <tarun.kanti@ti.com>
8 * Thara Gopinath <thara@ti.com>
9 *
10 * dmtimer adaptation to platform_driver.
11 *
92105bb7 12 * Copyright (C) 2005 Nokia Corporation
77900a2f
TT
13 * OMAP2 support by Juha Yrjola
14 * API improvements and OMAP2 clock framework support by Timo Teras
92105bb7 15 *
44169075
SS
16 * Copyright (C) 2009 Texas Instruments
17 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
18 *
92105bb7
TL
19 * This program is free software; you can redistribute it and/or modify it
20 * under the terms of the GNU General Public License as published by the
21 * Free Software Foundation; either version 2 of the License, or (at your
22 * option) any later version.
23 *
24 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
27 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * You should have received a copy of the GNU General Public License along
34 * with this program; if not, write to the Free Software Foundation, Inc.,
35 * 675 Mass Ave, Cambridge, MA 02139, USA.
36 */
37
869dec15 38#include <linux/module.h>
fced80c7 39#include <linux/io.h>
74dd9ec6 40#include <linux/device.h>
3392cdd3 41#include <linux/err.h>
ffe07cea 42#include <linux/pm_runtime.h>
44169075 43
3392cdd3 44#include <plat/dmtimer.h>
0b30ec1c 45#include <plat/omap-pm.h>
471b3aa7 46
2c799cef
TL
47#include <mach/hardware.h>
48
b7b4ff76 49static u32 omap_reserved_systimers;
df28472a 50static LIST_HEAD(omap_timer_list);
3392cdd3 51static DEFINE_SPINLOCK(dm_timer_lock);
92105bb7 52
3392cdd3
TKD
53/**
54 * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
55 * @timer: timer pointer over which read operation to perform
56 * @reg: lowest byte holds the register offset
57 *
58 * The posted mode bit is encoded in reg. Note that in posted mode write
59 * pending bit must be checked. Otherwise a read of a non completed write
60 * will produce an error.
0f0d0807
RW
61 */
62static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
77900a2f 63{
ee17f114
TL
64 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
65 return __omap_dm_timer_read(timer, reg, timer->posted);
77900a2f 66}
92105bb7 67
3392cdd3
TKD
68/**
69 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
70 * @timer: timer pointer over which write operation is to perform
71 * @reg: lowest byte holds the register offset
72 * @value: data to write into the register
73 *
74 * The posted mode bit is encoded in reg. Note that in posted mode the write
75 * pending bit must be checked. Otherwise a write on a register which has a
76 * pending write will be lost.
0f0d0807
RW
77 */
78static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
79 u32 value)
92105bb7 80{
ee17f114
TL
81 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
82 __omap_dm_timer_write(timer, reg, value, timer->posted);
92105bb7
TL
83}
84
b481113a
TKD
85static void omap_timer_restore_context(struct omap_dm_timer *timer)
86{
dffc9dae 87 if (timer->revision == 1)
b481113a
TKD
88 __raw_writel(timer->context.tistat, timer->sys_stat);
89
90 __raw_writel(timer->context.tisr, timer->irq_stat);
91 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
92 timer->context.twer);
93 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
94 timer->context.tcrr);
95 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
96 timer->context.tldr);
97 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
98 timer->context.tmar);
99 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
100 timer->context.tsicr);
101 __raw_writel(timer->context.tier, timer->irq_ena);
102 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
103 timer->context.tclr);
104}
105
77900a2f 106static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
92105bb7 107{
77900a2f
TT
108 int c;
109
ee17f114
TL
110 if (!timer->sys_stat)
111 return;
112
77900a2f 113 c = 0;
ee17f114 114 while (!(__raw_readl(timer->sys_stat) & 1)) {
77900a2f
TT
115 c++;
116 if (c > 100000) {
117 printk(KERN_ERR "Timer failed to reset\n");
118 return;
119 }
120 }
92105bb7
TL
121}
122
77900a2f
TT
123static void omap_dm_timer_reset(struct omap_dm_timer *timer)
124{
b481113a 125 omap_dm_timer_enable(timer);
3392cdd3 126 if (timer->pdev->id != 1) {
e32f7ec2
TT
127 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
128 omap_dm_timer_wait_for_reset(timer);
129 }
0f0d0807 130
3392cdd3 131 __omap_dm_timer_reset(timer, 0, 0);
b481113a 132 omap_dm_timer_disable(timer);
0f0d0807 133 timer->posted = 1;
77900a2f
TT
134}
135
3392cdd3 136int omap_dm_timer_prepare(struct omap_dm_timer *timer)
77900a2f 137{
3392cdd3
TKD
138 int ret;
139
bca45808
JH
140 /*
141 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
142 * do not call clk_get() for these devices.
143 */
144 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
145 timer->fclk = clk_get(&timer->pdev->dev, "fck");
146 if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
147 timer->fclk = NULL;
148 dev_err(&timer->pdev->dev, ": No fclk handle.\n");
149 return -EINVAL;
150 }
3392cdd3
TKD
151 }
152
6615975b 153 if (timer->capability & OMAP_TIMER_NEEDS_RESET)
3392cdd3
TKD
154 omap_dm_timer_reset(timer);
155
156 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
157
158 timer->posted = 1;
159 return ret;
77900a2f
TT
160}
161
b7b4ff76
JH
162static inline u32 omap_dm_timer_reserved_systimer(int id)
163{
164 return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
165}
166
167int omap_dm_timer_reserve_systimer(int id)
168{
169 if (omap_dm_timer_reserved_systimer(id))
170 return -ENODEV;
171
172 omap_reserved_systimers |= (1 << (id - 1));
173
174 return 0;
175}
176
77900a2f
TT
177struct omap_dm_timer *omap_dm_timer_request(void)
178{
3392cdd3 179 struct omap_dm_timer *timer = NULL, *t;
77900a2f 180 unsigned long flags;
3392cdd3 181 int ret = 0;
77900a2f
TT
182
183 spin_lock_irqsave(&dm_timer_lock, flags);
3392cdd3
TKD
184 list_for_each_entry(t, &omap_timer_list, node) {
185 if (t->reserved)
77900a2f
TT
186 continue;
187
3392cdd3 188 timer = t;
83379c81 189 timer->reserved = 1;
77900a2f
TT
190 break;
191 }
3392cdd3
TKD
192
193 if (timer) {
194 ret = omap_dm_timer_prepare(timer);
195 if (ret) {
196 timer->reserved = 0;
197 timer = NULL;
198 }
199 }
77900a2f
TT
200 spin_unlock_irqrestore(&dm_timer_lock, flags);
201
3392cdd3
TKD
202 if (!timer)
203 pr_debug("%s: timer request failed!\n", __func__);
83379c81 204
77900a2f
TT
205 return timer;
206}
6c366e32 207EXPORT_SYMBOL_GPL(omap_dm_timer_request);
77900a2f
TT
208
209struct omap_dm_timer *omap_dm_timer_request_specific(int id)
92105bb7 210{
3392cdd3 211 struct omap_dm_timer *timer = NULL, *t;
77900a2f 212 unsigned long flags;
3392cdd3 213 int ret = 0;
92105bb7 214
77900a2f 215 spin_lock_irqsave(&dm_timer_lock, flags);
3392cdd3
TKD
216 list_for_each_entry(t, &omap_timer_list, node) {
217 if (t->pdev->id == id && !t->reserved) {
218 timer = t;
219 timer->reserved = 1;
220 break;
221 }
77900a2f 222 }
92105bb7 223
3392cdd3
TKD
224 if (timer) {
225 ret = omap_dm_timer_prepare(timer);
226 if (ret) {
227 timer->reserved = 0;
228 timer = NULL;
229 }
230 }
77900a2f
TT
231 spin_unlock_irqrestore(&dm_timer_lock, flags);
232
3392cdd3
TKD
233 if (!timer)
234 pr_debug("%s: timer%d request failed!\n", __func__, id);
83379c81 235
77900a2f 236 return timer;
92105bb7 237}
6c366e32 238EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
92105bb7 239
ab4eb8b0 240int omap_dm_timer_free(struct omap_dm_timer *timer)
77900a2f 241{
ab4eb8b0
TKD
242 if (unlikely(!timer))
243 return -EINVAL;
244
3392cdd3 245 clk_put(timer->fclk);
fa4bb626 246
77900a2f
TT
247 WARN_ON(!timer->reserved);
248 timer->reserved = 0;
ab4eb8b0 249 return 0;
77900a2f 250}
6c366e32 251EXPORT_SYMBOL_GPL(omap_dm_timer_free);
77900a2f 252
12583a70
TT
253void omap_dm_timer_enable(struct omap_dm_timer *timer)
254{
ffe07cea 255 pm_runtime_get_sync(&timer->pdev->dev);
12583a70 256}
6c366e32 257EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
12583a70
TT
258
259void omap_dm_timer_disable(struct omap_dm_timer *timer)
260{
54f32a35 261 pm_runtime_put_sync(&timer->pdev->dev);
12583a70 262}
6c366e32 263EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
12583a70 264
77900a2f
TT
265int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
266{
ab4eb8b0
TKD
267 if (timer)
268 return timer->irq;
269 return -EINVAL;
77900a2f 270}
6c366e32 271EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
77900a2f
TT
272
273#if defined(CONFIG_ARCH_OMAP1)
274
a569c6ec
TL
275/**
276 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
277 * @inputmask: current value of idlect mask
278 */
279__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
280{
3392cdd3
TKD
281 int i = 0;
282 struct omap_dm_timer *timer = NULL;
283 unsigned long flags;
a569c6ec
TL
284
285 /* If ARMXOR cannot be idled this function call is unnecessary */
286 if (!(inputmask & (1 << 1)))
287 return inputmask;
288
289 /* If any active timer is using ARMXOR return modified mask */
3392cdd3
TKD
290 spin_lock_irqsave(&dm_timer_lock, flags);
291 list_for_each_entry(timer, &omap_timer_list, node) {
77900a2f
TT
292 u32 l;
293
3392cdd3 294 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
295 if (l & OMAP_TIMER_CTRL_ST) {
296 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
a569c6ec
TL
297 inputmask &= ~(1 << 1);
298 else
299 inputmask &= ~(1 << 2);
300 }
3392cdd3 301 i++;
77900a2f 302 }
3392cdd3 303 spin_unlock_irqrestore(&dm_timer_lock, flags);
a569c6ec
TL
304
305 return inputmask;
306}
6c366e32 307EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
a569c6ec 308
140455fa 309#else
a569c6ec 310
77900a2f 311struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
92105bb7 312{
ab4eb8b0
TKD
313 if (timer)
314 return timer->fclk;
315 return NULL;
77900a2f 316}
6c366e32 317EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
92105bb7 318
77900a2f
TT
319__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
320{
321 BUG();
2121880e
DB
322
323 return 0;
92105bb7 324}
6c366e32 325EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
92105bb7 326
77900a2f 327#endif
92105bb7 328
ab4eb8b0 329int omap_dm_timer_trigger(struct omap_dm_timer *timer)
92105bb7 330{
ab4eb8b0
TKD
331 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
332 pr_err("%s: timer not available or enabled.\n", __func__);
333 return -EINVAL;
b481113a
TKD
334 }
335
77900a2f 336 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
ab4eb8b0 337 return 0;
92105bb7 338}
6c366e32 339EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
92105bb7 340
ab4eb8b0 341int omap_dm_timer_start(struct omap_dm_timer *timer)
77900a2f
TT
342{
343 u32 l;
92105bb7 344
ab4eb8b0
TKD
345 if (unlikely(!timer))
346 return -EINVAL;
347
b481113a
TKD
348 omap_dm_timer_enable(timer);
349
1c2d076b 350 if (!(timer->capability & OMAP_TIMER_ALWON)) {
0b30ec1c
JH
351 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
352 timer->ctx_loss_count)
b481113a
TKD
353 omap_timer_restore_context(timer);
354 }
355
77900a2f
TT
356 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
357 if (!(l & OMAP_TIMER_CTRL_ST)) {
358 l |= OMAP_TIMER_CTRL_ST;
359 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
360 }
b481113a
TKD
361
362 /* Save the context */
363 timer->context.tclr = l;
ab4eb8b0 364 return 0;
77900a2f 365}
6c366e32 366EXPORT_SYMBOL_GPL(omap_dm_timer_start);
92105bb7 367
ab4eb8b0 368int omap_dm_timer_stop(struct omap_dm_timer *timer)
92105bb7 369{
caf64f2f 370 unsigned long rate = 0;
92105bb7 371
ab4eb8b0
TKD
372 if (unlikely(!timer))
373 return -EINVAL;
374
6615975b 375 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
3392cdd3 376 rate = clk_get_rate(timer->fclk);
caf64f2f 377
ee17f114 378 __omap_dm_timer_stop(timer, timer->posted, rate);
ab4eb8b0 379
0b30ec1c 380 if (!(timer->capability & OMAP_TIMER_ALWON))
dffc9dae 381 timer->ctx_loss_count =
0b30ec1c 382 omap_pm_get_dev_context_loss_count(&timer->pdev->dev);
dffc9dae
TKD
383
384 /*
385 * Since the register values are computed and written within
386 * __omap_dm_timer_stop, we need to use read to retrieve the
387 * context.
388 */
389 timer->context.tclr =
390 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
391 timer->context.tisr = __raw_readl(timer->irq_stat);
392 omap_dm_timer_disable(timer);
ab4eb8b0 393 return 0;
92105bb7 394}
6c366e32 395EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
92105bb7 396
f248076c 397int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
92105bb7 398{
3392cdd3 399 int ret;
2b2d3523
JH
400 char *parent_name = NULL;
401 struct clk *fclk, *parent;
ab4eb8b0
TKD
402 struct dmtimer_platform_data *pdata;
403
404 if (unlikely(!timer))
405 return -EINVAL;
406
407 pdata = timer->pdev->dev.platform_data;
3392cdd3 408
77900a2f 409 if (source < 0 || source >= 3)
f248076c 410 return -EINVAL;
77900a2f 411
2b2d3523
JH
412 /*
413 * FIXME: Used for OMAP1 devices only because they do not currently
414 * use the clock framework to set the parent clock. To be removed
415 * once OMAP1 migrated to using clock framework for dmtimers
416 */
417 if (pdata->set_timer_src)
418 return pdata->set_timer_src(timer->pdev, source);
419
420 fclk = clk_get(&timer->pdev->dev, "fck");
421 if (IS_ERR_OR_NULL(fclk)) {
422 pr_err("%s: fck not found\n", __func__);
423 return -EINVAL;
424 }
425
426 switch (source) {
427 case OMAP_TIMER_SRC_SYS_CLK:
c59b537d 428 parent_name = "timer_sys_ck";
2b2d3523
JH
429 break;
430
431 case OMAP_TIMER_SRC_32_KHZ:
c59b537d 432 parent_name = "timer_32k_ck";
2b2d3523
JH
433 break;
434
435 case OMAP_TIMER_SRC_EXT_CLK:
c59b537d 436 parent_name = "timer_ext_ck";
2b2d3523
JH
437 break;
438 }
439
440 parent = clk_get(&timer->pdev->dev, parent_name);
441 if (IS_ERR_OR_NULL(parent)) {
442 pr_err("%s: %s not found\n", __func__, parent_name);
443 ret = -EINVAL;
444 goto out;
445 }
446
447 ret = clk_set_parent(fclk, parent);
448 if (IS_ERR_VALUE(ret))
449 pr_err("%s: failed to set %s as parent\n", __func__,
450 parent_name);
451
452 clk_put(parent);
453out:
454 clk_put(fclk);
3392cdd3
TKD
455
456 return ret;
92105bb7 457}
6c366e32 458EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
92105bb7 459
ab4eb8b0 460int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
77900a2f 461 unsigned int load)
92105bb7
TL
462{
463 u32 l;
77900a2f 464
ab4eb8b0
TKD
465 if (unlikely(!timer))
466 return -EINVAL;
467
b481113a 468 omap_dm_timer_enable(timer);
92105bb7 469 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
470 if (autoreload)
471 l |= OMAP_TIMER_CTRL_AR;
472 else
473 l &= ~OMAP_TIMER_CTRL_AR;
92105bb7 474 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
77900a2f 475 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
0f0d0807 476
77900a2f 477 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
b481113a
TKD
478 /* Save the context */
479 timer->context.tclr = l;
480 timer->context.tldr = load;
481 omap_dm_timer_disable(timer);
ab4eb8b0 482 return 0;
92105bb7 483}
6c366e32 484EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
92105bb7 485
3fddd09e 486/* Optimized set_load which removes costly spin wait in timer_start */
ab4eb8b0 487int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
3fddd09e
RW
488 unsigned int load)
489{
490 u32 l;
491
ab4eb8b0
TKD
492 if (unlikely(!timer))
493 return -EINVAL;
494
b481113a
TKD
495 omap_dm_timer_enable(timer);
496
1c2d076b 497 if (!(timer->capability & OMAP_TIMER_ALWON)) {
0b30ec1c
JH
498 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
499 timer->ctx_loss_count)
b481113a
TKD
500 omap_timer_restore_context(timer);
501 }
502
3fddd09e 503 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
64ce2907 504 if (autoreload) {
3fddd09e 505 l |= OMAP_TIMER_CTRL_AR;
64ce2907
PW
506 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
507 } else {
3fddd09e 508 l &= ~OMAP_TIMER_CTRL_AR;
64ce2907 509 }
3fddd09e
RW
510 l |= OMAP_TIMER_CTRL_ST;
511
ee17f114 512 __omap_dm_timer_load_start(timer, l, load, timer->posted);
b481113a
TKD
513
514 /* Save the context */
515 timer->context.tclr = l;
516 timer->context.tldr = load;
517 timer->context.tcrr = load;
ab4eb8b0 518 return 0;
3fddd09e 519}
6c366e32 520EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
3fddd09e 521
ab4eb8b0 522int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
77900a2f 523 unsigned int match)
92105bb7
TL
524{
525 u32 l;
526
ab4eb8b0
TKD
527 if (unlikely(!timer))
528 return -EINVAL;
529
b481113a 530 omap_dm_timer_enable(timer);
92105bb7 531 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
83379c81 532 if (enable)
77900a2f
TT
533 l |= OMAP_TIMER_CTRL_CE;
534 else
535 l &= ~OMAP_TIMER_CTRL_CE;
92105bb7 536 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
77900a2f 537 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
b481113a
TKD
538
539 /* Save the context */
540 timer->context.tclr = l;
541 timer->context.tmar = match;
542 omap_dm_timer_disable(timer);
ab4eb8b0 543 return 0;
92105bb7 544}
6c366e32 545EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
92105bb7 546
ab4eb8b0 547int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
77900a2f 548 int toggle, int trigger)
92105bb7
TL
549{
550 u32 l;
551
ab4eb8b0
TKD
552 if (unlikely(!timer))
553 return -EINVAL;
554
b481113a 555 omap_dm_timer_enable(timer);
92105bb7 556 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
557 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
558 OMAP_TIMER_CTRL_PT | (0x03 << 10));
559 if (def_on)
560 l |= OMAP_TIMER_CTRL_SCPWM;
561 if (toggle)
562 l |= OMAP_TIMER_CTRL_PT;
563 l |= trigger << 10;
92105bb7 564 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
b481113a
TKD
565
566 /* Save the context */
567 timer->context.tclr = l;
568 omap_dm_timer_disable(timer);
ab4eb8b0 569 return 0;
92105bb7 570}
6c366e32 571EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
92105bb7 572
ab4eb8b0 573int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
92105bb7
TL
574{
575 u32 l;
576
ab4eb8b0
TKD
577 if (unlikely(!timer))
578 return -EINVAL;
579
b481113a 580 omap_dm_timer_enable(timer);
92105bb7 581 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
582 l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
583 if (prescaler >= 0x00 && prescaler <= 0x07) {
584 l |= OMAP_TIMER_CTRL_PRE;
585 l |= prescaler << 2;
586 }
92105bb7 587 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
b481113a
TKD
588
589 /* Save the context */
590 timer->context.tclr = l;
591 omap_dm_timer_disable(timer);
ab4eb8b0 592 return 0;
92105bb7 593}
6c366e32 594EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
92105bb7 595
ab4eb8b0 596int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
77900a2f 597 unsigned int value)
92105bb7 598{
ab4eb8b0
TKD
599 if (unlikely(!timer))
600 return -EINVAL;
601
b481113a 602 omap_dm_timer_enable(timer);
ee17f114 603 __omap_dm_timer_int_enable(timer, value);
b481113a
TKD
604
605 /* Save the context */
606 timer->context.tier = value;
607 timer->context.twer = value;
608 omap_dm_timer_disable(timer);
ab4eb8b0 609 return 0;
92105bb7 610}
6c366e32 611EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
92105bb7 612
77900a2f 613unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
92105bb7 614{
fa4bb626
TT
615 unsigned int l;
616
ab4eb8b0
TKD
617 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
618 pr_err("%s: timer not available or enabled.\n", __func__);
b481113a
TKD
619 return 0;
620 }
621
ee17f114 622 l = __raw_readl(timer->irq_stat);
fa4bb626
TT
623
624 return l;
92105bb7 625}
6c366e32 626EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
92105bb7 627
ab4eb8b0 628int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
92105bb7 629{
ab4eb8b0
TKD
630 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
631 return -EINVAL;
632
ee17f114 633 __omap_dm_timer_write_status(timer, value);
b481113a
TKD
634 /* Save the context */
635 timer->context.tisr = value;
ab4eb8b0 636 return 0;
92105bb7 637}
6c366e32 638EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
92105bb7 639
77900a2f 640unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
92105bb7 641{
ab4eb8b0
TKD
642 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
643 pr_err("%s: timer not iavailable or enabled.\n", __func__);
b481113a
TKD
644 return 0;
645 }
646
ee17f114 647 return __omap_dm_timer_read_counter(timer, timer->posted);
92105bb7 648}
6c366e32 649EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
92105bb7 650
ab4eb8b0 651int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
83379c81 652{
ab4eb8b0
TKD
653 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
654 pr_err("%s: timer not available or enabled.\n", __func__);
655 return -EINVAL;
b481113a
TKD
656 }
657
fa4bb626 658 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
b481113a
TKD
659
660 /* Save the context */
661 timer->context.tcrr = value;
ab4eb8b0 662 return 0;
83379c81 663}
6c366e32 664EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
83379c81 665
77900a2f 666int omap_dm_timers_active(void)
92105bb7 667{
3392cdd3 668 struct omap_dm_timer *timer;
12583a70 669
3392cdd3 670 list_for_each_entry(timer, &omap_timer_list, node) {
ffe07cea 671 if (!timer->reserved)
12583a70
TT
672 continue;
673
77900a2f 674 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
fa4bb626 675 OMAP_TIMER_CTRL_ST) {
77900a2f 676 return 1;
fa4bb626 677 }
77900a2f
TT
678 }
679 return 0;
680}
6c366e32 681EXPORT_SYMBOL_GPL(omap_dm_timers_active);
92105bb7 682
df28472a
TKD
683/**
684 * omap_dm_timer_probe - probe function called for every registered device
685 * @pdev: pointer to current timer platform device
686 *
687 * Called by driver framework at the end of device registration for all
688 * timer devices.
689 */
690static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
691{
df28472a
TKD
692 unsigned long flags;
693 struct omap_dm_timer *timer;
74dd9ec6
TKD
694 struct resource *mem, *irq;
695 struct device *dev = &pdev->dev;
df28472a
TKD
696 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
697
698 if (!pdata) {
74dd9ec6 699 dev_err(dev, "%s: no platform data.\n", __func__);
df28472a
TKD
700 return -ENODEV;
701 }
702
703 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
704 if (unlikely(!irq)) {
74dd9ec6 705 dev_err(dev, "%s: no IRQ resource.\n", __func__);
df28472a
TKD
706 return -ENODEV;
707 }
708
709 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
710 if (unlikely(!mem)) {
74dd9ec6 711 dev_err(dev, "%s: no memory resource.\n", __func__);
df28472a
TKD
712 return -ENODEV;
713 }
714
74dd9ec6 715 timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
df28472a 716 if (!timer) {
74dd9ec6
TKD
717 dev_err(dev, "%s: memory alloc failed!\n", __func__);
718 return -ENOMEM;
df28472a
TKD
719 }
720
74dd9ec6 721 timer->io_base = devm_request_and_ioremap(dev, mem);
df28472a 722 if (!timer->io_base) {
74dd9ec6
TKD
723 dev_err(dev, "%s: region already claimed.\n", __func__);
724 return -ENOMEM;
df28472a
TKD
725 }
726
727 timer->id = pdev->id;
728 timer->irq = irq->start;
b7b4ff76 729 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
df28472a 730 timer->pdev = pdev;
d1c1691b 731 timer->capability = pdata->timer_capability;
df28472a 732
ffe07cea 733 /* Skip pm_runtime_enable for OMAP1 */
6615975b 734 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
74dd9ec6
TKD
735 pm_runtime_enable(dev);
736 pm_runtime_irq_safe(dev);
ffe07cea
TKD
737 }
738
0dad9fae 739 if (!timer->reserved) {
74dd9ec6 740 pm_runtime_get_sync(dev);
0dad9fae 741 __omap_dm_timer_init_regs(timer);
74dd9ec6 742 pm_runtime_put(dev);
0dad9fae
TL
743 }
744
df28472a
TKD
745 /* add the timer element to the list */
746 spin_lock_irqsave(&dm_timer_lock, flags);
747 list_add_tail(&timer->node, &omap_timer_list);
748 spin_unlock_irqrestore(&dm_timer_lock, flags);
749
74dd9ec6 750 dev_dbg(dev, "Device Probed.\n");
df28472a
TKD
751
752 return 0;
df28472a
TKD
753}
754
755/**
756 * omap_dm_timer_remove - cleanup a registered timer device
757 * @pdev: pointer to current timer platform device
758 *
759 * Called by driver framework whenever a timer device is unregistered.
760 * In addition to freeing platform resources it also deletes the timer
761 * entry from the local list.
762 */
763static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
764{
765 struct omap_dm_timer *timer;
766 unsigned long flags;
767 int ret = -EINVAL;
768
769 spin_lock_irqsave(&dm_timer_lock, flags);
770 list_for_each_entry(timer, &omap_timer_list, node)
771 if (timer->pdev->id == pdev->id) {
772 list_del(&timer->node);
df28472a
TKD
773 ret = 0;
774 break;
775 }
776 spin_unlock_irqrestore(&dm_timer_lock, flags);
777
778 return ret;
779}
780
781static struct platform_driver omap_dm_timer_driver = {
782 .probe = omap_dm_timer_probe,
4c23c8da 783 .remove = __devexit_p(omap_dm_timer_remove),
df28472a
TKD
784 .driver = {
785 .name = "omap_timer",
786 },
787};
788
789static int __init omap_dm_timer_driver_init(void)
790{
791 return platform_driver_register(&omap_dm_timer_driver);
792}
793
794static void __exit omap_dm_timer_driver_exit(void)
795{
796 platform_driver_unregister(&omap_dm_timer_driver);
797}
798
799early_platform_init("earlytimer", &omap_dm_timer_driver);
800module_init(omap_dm_timer_driver_init);
801module_exit(omap_dm_timer_driver_exit);
802
803MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
804MODULE_LICENSE("GPL");
805MODULE_ALIAS("platform:" DRIVER_NAME);
806MODULE_AUTHOR("Texas Instruments Inc");