]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - arch/arm/plat-omap/dmtimer.c
ARM: OMAP3+: Implement timer workaround for errata i103 and i767
[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>
9725f445
JH
43#include <linux/of.h>
44#include <linux/of_device.h>
44169075 45
3392cdd3 46#include <plat/dmtimer.h>
2c799cef 47
b7b4ff76 48static u32 omap_reserved_systimers;
df28472a 49static LIST_HEAD(omap_timer_list);
3392cdd3 50static DEFINE_SPINLOCK(dm_timer_lock);
92105bb7 51
3392cdd3
TKD
52/**
53 * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
54 * @timer: timer pointer over which read operation to perform
55 * @reg: lowest byte holds the register offset
56 *
57 * The posted mode bit is encoded in reg. Note that in posted mode write
58 * pending bit must be checked. Otherwise a read of a non completed write
59 * will produce an error.
0f0d0807
RW
60 */
61static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
77900a2f 62{
ee17f114
TL
63 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
64 return __omap_dm_timer_read(timer, reg, timer->posted);
77900a2f 65}
92105bb7 66
3392cdd3
TKD
67/**
68 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
69 * @timer: timer pointer over which write operation is to perform
70 * @reg: lowest byte holds the register offset
71 * @value: data to write into the register
72 *
73 * The posted mode bit is encoded in reg. Note that in posted mode the write
74 * pending bit must be checked. Otherwise a write on a register which has a
75 * pending write will be lost.
0f0d0807
RW
76 */
77static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
78 u32 value)
92105bb7 79{
ee17f114
TL
80 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
81 __omap_dm_timer_write(timer, reg, value, timer->posted);
92105bb7
TL
82}
83
b481113a
TKD
84static void omap_timer_restore_context(struct omap_dm_timer *timer)
85{
dffc9dae 86 if (timer->revision == 1)
b481113a
TKD
87 __raw_writel(timer->context.tistat, timer->sys_stat);
88
89 __raw_writel(timer->context.tisr, timer->irq_stat);
90 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
91 timer->context.twer);
92 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
93 timer->context.tcrr);
94 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
95 timer->context.tldr);
96 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
97 timer->context.tmar);
98 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
99 timer->context.tsicr);
100 __raw_writel(timer->context.tier, timer->irq_ena);
101 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
102 timer->context.tclr);
103}
104
77900a2f 105static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
92105bb7 106{
77900a2f
TT
107 int c;
108
ee17f114
TL
109 if (!timer->sys_stat)
110 return;
111
77900a2f 112 c = 0;
ee17f114 113 while (!(__raw_readl(timer->sys_stat) & 1)) {
77900a2f
TT
114 c++;
115 if (c > 100000) {
116 printk(KERN_ERR "Timer failed to reset\n");
117 return;
118 }
119 }
92105bb7
TL
120}
121
77900a2f
TT
122static void omap_dm_timer_reset(struct omap_dm_timer *timer)
123{
b481113a 124 omap_dm_timer_enable(timer);
3392cdd3 125 if (timer->pdev->id != 1) {
e32f7ec2
TT
126 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
127 omap_dm_timer_wait_for_reset(timer);
128 }
0f0d0807 129
3392cdd3 130 __omap_dm_timer_reset(timer, 0, 0);
bfd6d021 131 __omap_dm_timer_enable_posted(timer);
b481113a 132 omap_dm_timer_disable(timer);
77900a2f
TT
133}
134
3392cdd3 135int omap_dm_timer_prepare(struct omap_dm_timer *timer)
77900a2f 136{
3392cdd3
TKD
137 int ret;
138
bca45808
JH
139 /*
140 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
141 * do not call clk_get() for these devices.
142 */
143 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
144 timer->fclk = clk_get(&timer->pdev->dev, "fck");
145 if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
146 timer->fclk = NULL;
147 dev_err(&timer->pdev->dev, ": No fclk handle.\n");
148 return -EINVAL;
149 }
3392cdd3
TKD
150 }
151
6615975b 152 if (timer->capability & OMAP_TIMER_NEEDS_RESET)
3392cdd3
TKD
153 omap_dm_timer_reset(timer);
154
155 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
156
157 timer->posted = 1;
158 return ret;
77900a2f
TT
159}
160
b7b4ff76
JH
161static inline u32 omap_dm_timer_reserved_systimer(int id)
162{
163 return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
164}
165
166int omap_dm_timer_reserve_systimer(int id)
167{
168 if (omap_dm_timer_reserved_systimer(id))
169 return -ENODEV;
170
171 omap_reserved_systimers |= (1 << (id - 1));
172
173 return 0;
174}
175
77900a2f
TT
176struct omap_dm_timer *omap_dm_timer_request(void)
177{
3392cdd3 178 struct omap_dm_timer *timer = NULL, *t;
77900a2f 179 unsigned long flags;
3392cdd3 180 int ret = 0;
77900a2f
TT
181
182 spin_lock_irqsave(&dm_timer_lock, flags);
3392cdd3
TKD
183 list_for_each_entry(t, &omap_timer_list, node) {
184 if (t->reserved)
77900a2f
TT
185 continue;
186
3392cdd3 187 timer = t;
83379c81 188 timer->reserved = 1;
77900a2f
TT
189 break;
190 }
c5491d1a 191 spin_unlock_irqrestore(&dm_timer_lock, flags);
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 200
3392cdd3
TKD
201 if (!timer)
202 pr_debug("%s: timer request failed!\n", __func__);
83379c81 203
77900a2f
TT
204 return timer;
205}
6c366e32 206EXPORT_SYMBOL_GPL(omap_dm_timer_request);
77900a2f
TT
207
208struct omap_dm_timer *omap_dm_timer_request_specific(int id)
92105bb7 209{
3392cdd3 210 struct omap_dm_timer *timer = NULL, *t;
77900a2f 211 unsigned long flags;
3392cdd3 212 int ret = 0;
92105bb7 213
9725f445
JH
214 /* Requesting timer by ID is not supported when device tree is used */
215 if (of_have_populated_dt()) {
216 pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n",
217 __func__);
218 return NULL;
219 }
220
77900a2f 221 spin_lock_irqsave(&dm_timer_lock, flags);
3392cdd3
TKD
222 list_for_each_entry(t, &omap_timer_list, node) {
223 if (t->pdev->id == id && !t->reserved) {
224 timer = t;
225 timer->reserved = 1;
226 break;
227 }
77900a2f 228 }
c5491d1a 229 spin_unlock_irqrestore(&dm_timer_lock, flags);
92105bb7 230
3392cdd3
TKD
231 if (timer) {
232 ret = omap_dm_timer_prepare(timer);
233 if (ret) {
234 timer->reserved = 0;
235 timer = NULL;
236 }
237 }
77900a2f 238
3392cdd3
TKD
239 if (!timer)
240 pr_debug("%s: timer%d request failed!\n", __func__, id);
83379c81 241
77900a2f 242 return timer;
92105bb7 243}
6c366e32 244EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
92105bb7 245
373fe0bd
JH
246/**
247 * omap_dm_timer_request_by_cap - Request a timer by capability
248 * @cap: Bit mask of capabilities to match
249 *
250 * Find a timer based upon capabilities bit mask. Callers of this function
251 * should use the definitions found in the plat/dmtimer.h file under the
252 * comment "timer capabilities used in hwmod database". Returns pointer to
253 * timer handle on success and a NULL pointer on failure.
254 */
255struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
256{
257 struct omap_dm_timer *timer = NULL, *t;
258 unsigned long flags;
259
260 if (!cap)
261 return NULL;
262
263 spin_lock_irqsave(&dm_timer_lock, flags);
264 list_for_each_entry(t, &omap_timer_list, node) {
265 if ((!t->reserved) && ((t->capability & cap) == cap)) {
266 /*
267 * If timer is not NULL, we have already found one timer
268 * but it was not an exact match because it had more
269 * capabilites that what was required. Therefore,
270 * unreserve the last timer found and see if this one
271 * is a better match.
272 */
273 if (timer)
274 timer->reserved = 0;
275
276 timer = t;
277 timer->reserved = 1;
278
279 /* Exit loop early if we find an exact match */
280 if (t->capability == cap)
281 break;
282 }
283 }
284 spin_unlock_irqrestore(&dm_timer_lock, flags);
285
286 if (timer && omap_dm_timer_prepare(timer)) {
287 timer->reserved = 0;
288 timer = NULL;
289 }
290
291 if (!timer)
292 pr_debug("%s: timer request failed!\n", __func__);
293
294 return timer;
295}
296EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
297
ab4eb8b0 298int omap_dm_timer_free(struct omap_dm_timer *timer)
77900a2f 299{
ab4eb8b0
TKD
300 if (unlikely(!timer))
301 return -EINVAL;
302
3392cdd3 303 clk_put(timer->fclk);
fa4bb626 304
77900a2f
TT
305 WARN_ON(!timer->reserved);
306 timer->reserved = 0;
ab4eb8b0 307 return 0;
77900a2f 308}
6c366e32 309EXPORT_SYMBOL_GPL(omap_dm_timer_free);
77900a2f 310
12583a70
TT
311void omap_dm_timer_enable(struct omap_dm_timer *timer)
312{
ffe07cea 313 pm_runtime_get_sync(&timer->pdev->dev);
12583a70 314}
6c366e32 315EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
12583a70
TT
316
317void omap_dm_timer_disable(struct omap_dm_timer *timer)
318{
54f32a35 319 pm_runtime_put_sync(&timer->pdev->dev);
12583a70 320}
6c366e32 321EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
12583a70 322
77900a2f
TT
323int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
324{
ab4eb8b0
TKD
325 if (timer)
326 return timer->irq;
327 return -EINVAL;
77900a2f 328}
6c366e32 329EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
77900a2f
TT
330
331#if defined(CONFIG_ARCH_OMAP1)
7136f8d8 332#include <mach/hardware.h>
a569c6ec
TL
333/**
334 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
335 * @inputmask: current value of idlect mask
336 */
337__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
338{
3392cdd3
TKD
339 int i = 0;
340 struct omap_dm_timer *timer = NULL;
341 unsigned long flags;
a569c6ec
TL
342
343 /* If ARMXOR cannot be idled this function call is unnecessary */
344 if (!(inputmask & (1 << 1)))
345 return inputmask;
346
347 /* If any active timer is using ARMXOR return modified mask */
3392cdd3
TKD
348 spin_lock_irqsave(&dm_timer_lock, flags);
349 list_for_each_entry(timer, &omap_timer_list, node) {
77900a2f
TT
350 u32 l;
351
3392cdd3 352 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
353 if (l & OMAP_TIMER_CTRL_ST) {
354 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
a569c6ec
TL
355 inputmask &= ~(1 << 1);
356 else
357 inputmask &= ~(1 << 2);
358 }
3392cdd3 359 i++;
77900a2f 360 }
3392cdd3 361 spin_unlock_irqrestore(&dm_timer_lock, flags);
a569c6ec
TL
362
363 return inputmask;
364}
6c366e32 365EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
a569c6ec 366
140455fa 367#else
a569c6ec 368
77900a2f 369struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
92105bb7 370{
ab4eb8b0
TKD
371 if (timer)
372 return timer->fclk;
373 return NULL;
77900a2f 374}
6c366e32 375EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
92105bb7 376
77900a2f
TT
377__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
378{
379 BUG();
2121880e
DB
380
381 return 0;
92105bb7 382}
6c366e32 383EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
92105bb7 384
77900a2f 385#endif
92105bb7 386
ab4eb8b0 387int omap_dm_timer_trigger(struct omap_dm_timer *timer)
92105bb7 388{
ab4eb8b0
TKD
389 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
390 pr_err("%s: timer not available or enabled.\n", __func__);
391 return -EINVAL;
b481113a
TKD
392 }
393
77900a2f 394 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
ab4eb8b0 395 return 0;
92105bb7 396}
6c366e32 397EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
92105bb7 398
ab4eb8b0 399int omap_dm_timer_start(struct omap_dm_timer *timer)
77900a2f
TT
400{
401 u32 l;
92105bb7 402
ab4eb8b0
TKD
403 if (unlikely(!timer))
404 return -EINVAL;
405
b481113a
TKD
406 omap_dm_timer_enable(timer);
407
1c2d076b 408 if (!(timer->capability & OMAP_TIMER_ALWON)) {
6e740f9a
TL
409 if (timer->get_context_loss_count &&
410 timer->get_context_loss_count(&timer->pdev->dev) !=
0b30ec1c 411 timer->ctx_loss_count)
b481113a
TKD
412 omap_timer_restore_context(timer);
413 }
414
77900a2f
TT
415 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
416 if (!(l & OMAP_TIMER_CTRL_ST)) {
417 l |= OMAP_TIMER_CTRL_ST;
418 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
419 }
b481113a
TKD
420
421 /* Save the context */
422 timer->context.tclr = l;
ab4eb8b0 423 return 0;
77900a2f 424}
6c366e32 425EXPORT_SYMBOL_GPL(omap_dm_timer_start);
92105bb7 426
ab4eb8b0 427int omap_dm_timer_stop(struct omap_dm_timer *timer)
92105bb7 428{
caf64f2f 429 unsigned long rate = 0;
92105bb7 430
ab4eb8b0
TKD
431 if (unlikely(!timer))
432 return -EINVAL;
433
6615975b 434 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
3392cdd3 435 rate = clk_get_rate(timer->fclk);
caf64f2f 436
ee17f114 437 __omap_dm_timer_stop(timer, timer->posted, rate);
ab4eb8b0 438
6e740f9a
TL
439 if (!(timer->capability & OMAP_TIMER_ALWON)) {
440 if (timer->get_context_loss_count)
441 timer->ctx_loss_count =
442 timer->get_context_loss_count(&timer->pdev->dev);
443 }
dffc9dae
TKD
444
445 /*
446 * Since the register values are computed and written within
447 * __omap_dm_timer_stop, we need to use read to retrieve the
448 * context.
449 */
450 timer->context.tclr =
451 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
452 timer->context.tisr = __raw_readl(timer->irq_stat);
453 omap_dm_timer_disable(timer);
ab4eb8b0 454 return 0;
92105bb7 455}
6c366e32 456EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
92105bb7 457
f248076c 458int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
92105bb7 459{
3392cdd3 460 int ret;
2b2d3523
JH
461 char *parent_name = NULL;
462 struct clk *fclk, *parent;
ab4eb8b0
TKD
463 struct dmtimer_platform_data *pdata;
464
465 if (unlikely(!timer))
466 return -EINVAL;
467
468 pdata = timer->pdev->dev.platform_data;
3392cdd3 469
77900a2f 470 if (source < 0 || source >= 3)
f248076c 471 return -EINVAL;
77900a2f 472
2b2d3523
JH
473 /*
474 * FIXME: Used for OMAP1 devices only because they do not currently
475 * use the clock framework to set the parent clock. To be removed
476 * once OMAP1 migrated to using clock framework for dmtimers
477 */
9725f445 478 if (pdata && pdata->set_timer_src)
2b2d3523
JH
479 return pdata->set_timer_src(timer->pdev, source);
480
481 fclk = clk_get(&timer->pdev->dev, "fck");
482 if (IS_ERR_OR_NULL(fclk)) {
483 pr_err("%s: fck not found\n", __func__);
484 return -EINVAL;
485 }
486
487 switch (source) {
488 case OMAP_TIMER_SRC_SYS_CLK:
c59b537d 489 parent_name = "timer_sys_ck";
2b2d3523
JH
490 break;
491
492 case OMAP_TIMER_SRC_32_KHZ:
c59b537d 493 parent_name = "timer_32k_ck";
2b2d3523
JH
494 break;
495
496 case OMAP_TIMER_SRC_EXT_CLK:
c59b537d 497 parent_name = "timer_ext_ck";
2b2d3523
JH
498 break;
499 }
500
501 parent = clk_get(&timer->pdev->dev, parent_name);
502 if (IS_ERR_OR_NULL(parent)) {
503 pr_err("%s: %s not found\n", __func__, parent_name);
504 ret = -EINVAL;
505 goto out;
506 }
507
508 ret = clk_set_parent(fclk, parent);
509 if (IS_ERR_VALUE(ret))
510 pr_err("%s: failed to set %s as parent\n", __func__,
511 parent_name);
512
513 clk_put(parent);
514out:
515 clk_put(fclk);
3392cdd3
TKD
516
517 return ret;
92105bb7 518}
6c366e32 519EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
92105bb7 520
ab4eb8b0 521int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
77900a2f 522 unsigned int load)
92105bb7
TL
523{
524 u32 l;
77900a2f 525
ab4eb8b0
TKD
526 if (unlikely(!timer))
527 return -EINVAL;
528
b481113a 529 omap_dm_timer_enable(timer);
92105bb7 530 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
531 if (autoreload)
532 l |= OMAP_TIMER_CTRL_AR;
533 else
534 l &= ~OMAP_TIMER_CTRL_AR;
92105bb7 535 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
77900a2f 536 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
0f0d0807 537
77900a2f 538 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
b481113a
TKD
539 /* Save the context */
540 timer->context.tclr = l;
541 timer->context.tldr = load;
542 omap_dm_timer_disable(timer);
ab4eb8b0 543 return 0;
92105bb7 544}
6c366e32 545EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
92105bb7 546
3fddd09e 547/* Optimized set_load which removes costly spin wait in timer_start */
ab4eb8b0 548int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
3fddd09e
RW
549 unsigned int load)
550{
551 u32 l;
552
ab4eb8b0
TKD
553 if (unlikely(!timer))
554 return -EINVAL;
555
b481113a
TKD
556 omap_dm_timer_enable(timer);
557
1c2d076b 558 if (!(timer->capability & OMAP_TIMER_ALWON)) {
6e740f9a
TL
559 if (timer->get_context_loss_count &&
560 timer->get_context_loss_count(&timer->pdev->dev) !=
0b30ec1c 561 timer->ctx_loss_count)
b481113a
TKD
562 omap_timer_restore_context(timer);
563 }
564
3fddd09e 565 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
64ce2907 566 if (autoreload) {
3fddd09e 567 l |= OMAP_TIMER_CTRL_AR;
64ce2907
PW
568 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
569 } else {
3fddd09e 570 l &= ~OMAP_TIMER_CTRL_AR;
64ce2907 571 }
3fddd09e
RW
572 l |= OMAP_TIMER_CTRL_ST;
573
ee17f114 574 __omap_dm_timer_load_start(timer, l, load, timer->posted);
b481113a
TKD
575
576 /* Save the context */
577 timer->context.tclr = l;
578 timer->context.tldr = load;
579 timer->context.tcrr = load;
ab4eb8b0 580 return 0;
3fddd09e 581}
6c366e32 582EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
3fddd09e 583
ab4eb8b0 584int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
77900a2f 585 unsigned int match)
92105bb7
TL
586{
587 u32 l;
588
ab4eb8b0
TKD
589 if (unlikely(!timer))
590 return -EINVAL;
591
b481113a 592 omap_dm_timer_enable(timer);
92105bb7 593 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
83379c81 594 if (enable)
77900a2f
TT
595 l |= OMAP_TIMER_CTRL_CE;
596 else
597 l &= ~OMAP_TIMER_CTRL_CE;
92105bb7 598 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
77900a2f 599 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
b481113a
TKD
600
601 /* Save the context */
602 timer->context.tclr = l;
603 timer->context.tmar = match;
604 omap_dm_timer_disable(timer);
ab4eb8b0 605 return 0;
92105bb7 606}
6c366e32 607EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
92105bb7 608
ab4eb8b0 609int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
77900a2f 610 int toggle, int trigger)
92105bb7
TL
611{
612 u32 l;
613
ab4eb8b0
TKD
614 if (unlikely(!timer))
615 return -EINVAL;
616
b481113a 617 omap_dm_timer_enable(timer);
92105bb7 618 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
619 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
620 OMAP_TIMER_CTRL_PT | (0x03 << 10));
621 if (def_on)
622 l |= OMAP_TIMER_CTRL_SCPWM;
623 if (toggle)
624 l |= OMAP_TIMER_CTRL_PT;
625 l |= trigger << 10;
92105bb7 626 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
b481113a
TKD
627
628 /* Save the context */
629 timer->context.tclr = l;
630 omap_dm_timer_disable(timer);
ab4eb8b0 631 return 0;
92105bb7 632}
6c366e32 633EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
92105bb7 634
ab4eb8b0 635int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
92105bb7
TL
636{
637 u32 l;
638
ab4eb8b0
TKD
639 if (unlikely(!timer))
640 return -EINVAL;
641
b481113a 642 omap_dm_timer_enable(timer);
92105bb7 643 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
644 l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
645 if (prescaler >= 0x00 && prescaler <= 0x07) {
646 l |= OMAP_TIMER_CTRL_PRE;
647 l |= prescaler << 2;
648 }
92105bb7 649 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
b481113a
TKD
650
651 /* Save the context */
652 timer->context.tclr = l;
653 omap_dm_timer_disable(timer);
ab4eb8b0 654 return 0;
92105bb7 655}
6c366e32 656EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
92105bb7 657
ab4eb8b0 658int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
77900a2f 659 unsigned int value)
92105bb7 660{
ab4eb8b0
TKD
661 if (unlikely(!timer))
662 return -EINVAL;
663
b481113a 664 omap_dm_timer_enable(timer);
ee17f114 665 __omap_dm_timer_int_enable(timer, value);
b481113a
TKD
666
667 /* Save the context */
668 timer->context.tier = value;
669 timer->context.twer = value;
670 omap_dm_timer_disable(timer);
ab4eb8b0 671 return 0;
92105bb7 672}
6c366e32 673EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
92105bb7 674
77900a2f 675unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
92105bb7 676{
fa4bb626
TT
677 unsigned int l;
678
ab4eb8b0
TKD
679 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
680 pr_err("%s: timer not available or enabled.\n", __func__);
b481113a
TKD
681 return 0;
682 }
683
ee17f114 684 l = __raw_readl(timer->irq_stat);
fa4bb626
TT
685
686 return l;
92105bb7 687}
6c366e32 688EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
92105bb7 689
ab4eb8b0 690int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
92105bb7 691{
ab4eb8b0
TKD
692 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
693 return -EINVAL;
694
ee17f114 695 __omap_dm_timer_write_status(timer, value);
b481113a
TKD
696 /* Save the context */
697 timer->context.tisr = value;
ab4eb8b0 698 return 0;
92105bb7 699}
6c366e32 700EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
92105bb7 701
77900a2f 702unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
92105bb7 703{
ab4eb8b0
TKD
704 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
705 pr_err("%s: timer not iavailable or enabled.\n", __func__);
b481113a
TKD
706 return 0;
707 }
708
ee17f114 709 return __omap_dm_timer_read_counter(timer, timer->posted);
92105bb7 710}
6c366e32 711EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
92105bb7 712
ab4eb8b0 713int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
83379c81 714{
ab4eb8b0
TKD
715 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
716 pr_err("%s: timer not available or enabled.\n", __func__);
717 return -EINVAL;
b481113a
TKD
718 }
719
fa4bb626 720 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
b481113a
TKD
721
722 /* Save the context */
723 timer->context.tcrr = value;
ab4eb8b0 724 return 0;
83379c81 725}
6c366e32 726EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
83379c81 727
77900a2f 728int omap_dm_timers_active(void)
92105bb7 729{
3392cdd3 730 struct omap_dm_timer *timer;
12583a70 731
3392cdd3 732 list_for_each_entry(timer, &omap_timer_list, node) {
ffe07cea 733 if (!timer->reserved)
12583a70
TT
734 continue;
735
77900a2f 736 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
fa4bb626 737 OMAP_TIMER_CTRL_ST) {
77900a2f 738 return 1;
fa4bb626 739 }
77900a2f
TT
740 }
741 return 0;
742}
6c366e32 743EXPORT_SYMBOL_GPL(omap_dm_timers_active);
92105bb7 744
df28472a
TKD
745/**
746 * omap_dm_timer_probe - probe function called for every registered device
747 * @pdev: pointer to current timer platform device
748 *
749 * Called by driver framework at the end of device registration for all
750 * timer devices.
751 */
752static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
753{
df28472a
TKD
754 unsigned long flags;
755 struct omap_dm_timer *timer;
74dd9ec6
TKD
756 struct resource *mem, *irq;
757 struct device *dev = &pdev->dev;
df28472a
TKD
758 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
759
9725f445 760 if (!pdata && !dev->of_node) {
74dd9ec6 761 dev_err(dev, "%s: no platform data.\n", __func__);
df28472a
TKD
762 return -ENODEV;
763 }
764
765 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
766 if (unlikely(!irq)) {
74dd9ec6 767 dev_err(dev, "%s: no IRQ resource.\n", __func__);
df28472a
TKD
768 return -ENODEV;
769 }
770
771 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
772 if (unlikely(!mem)) {
74dd9ec6 773 dev_err(dev, "%s: no memory resource.\n", __func__);
df28472a
TKD
774 return -ENODEV;
775 }
776
74dd9ec6 777 timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
df28472a 778 if (!timer) {
74dd9ec6
TKD
779 dev_err(dev, "%s: memory alloc failed!\n", __func__);
780 return -ENOMEM;
df28472a
TKD
781 }
782
74dd9ec6 783 timer->io_base = devm_request_and_ioremap(dev, mem);
df28472a 784 if (!timer->io_base) {
74dd9ec6
TKD
785 dev_err(dev, "%s: region already claimed.\n", __func__);
786 return -ENOMEM;
df28472a
TKD
787 }
788
9725f445
JH
789 if (dev->of_node) {
790 if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
791 timer->capability |= OMAP_TIMER_ALWON;
792 if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
793 timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
794 if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
795 timer->capability |= OMAP_TIMER_HAS_PWM;
796 if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
797 timer->capability |= OMAP_TIMER_SECURE;
798 } else {
799 timer->id = pdev->id;
bfd6d021 800 timer->errata = pdata->timer_errata;
9725f445
JH
801 timer->capability = pdata->timer_capability;
802 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
f56f52e0 803 timer->get_context_loss_count = pdata->get_context_loss_count;
9725f445
JH
804 }
805
df28472a
TKD
806 timer->irq = irq->start;
807 timer->pdev = pdev;
df28472a 808
ffe07cea 809 /* Skip pm_runtime_enable for OMAP1 */
6615975b 810 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
74dd9ec6
TKD
811 pm_runtime_enable(dev);
812 pm_runtime_irq_safe(dev);
ffe07cea
TKD
813 }
814
0dad9fae 815 if (!timer->reserved) {
74dd9ec6 816 pm_runtime_get_sync(dev);
0dad9fae 817 __omap_dm_timer_init_regs(timer);
74dd9ec6 818 pm_runtime_put(dev);
0dad9fae
TL
819 }
820
df28472a
TKD
821 /* add the timer element to the list */
822 spin_lock_irqsave(&dm_timer_lock, flags);
823 list_add_tail(&timer->node, &omap_timer_list);
824 spin_unlock_irqrestore(&dm_timer_lock, flags);
825
74dd9ec6 826 dev_dbg(dev, "Device Probed.\n");
df28472a
TKD
827
828 return 0;
df28472a
TKD
829}
830
831/**
832 * omap_dm_timer_remove - cleanup a registered timer device
833 * @pdev: pointer to current timer platform device
834 *
835 * Called by driver framework whenever a timer device is unregistered.
836 * In addition to freeing platform resources it also deletes the timer
837 * entry from the local list.
838 */
839static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
840{
841 struct omap_dm_timer *timer;
842 unsigned long flags;
843 int ret = -EINVAL;
844
845 spin_lock_irqsave(&dm_timer_lock, flags);
846 list_for_each_entry(timer, &omap_timer_list, node)
9725f445
JH
847 if (!strcmp(dev_name(&timer->pdev->dev),
848 dev_name(&pdev->dev))) {
df28472a 849 list_del(&timer->node);
df28472a
TKD
850 ret = 0;
851 break;
852 }
853 spin_unlock_irqrestore(&dm_timer_lock, flags);
854
855 return ret;
856}
857
9725f445
JH
858static const struct of_device_id omap_timer_match[] = {
859 { .compatible = "ti,omap2-timer", },
860 {},
861};
862MODULE_DEVICE_TABLE(of, omap_timer_match);
863
df28472a
TKD
864static struct platform_driver omap_dm_timer_driver = {
865 .probe = omap_dm_timer_probe,
4c23c8da 866 .remove = __devexit_p(omap_dm_timer_remove),
df28472a
TKD
867 .driver = {
868 .name = "omap_timer",
9725f445 869 .of_match_table = of_match_ptr(omap_timer_match),
df28472a
TKD
870 },
871};
872
873static int __init omap_dm_timer_driver_init(void)
874{
875 return platform_driver_register(&omap_dm_timer_driver);
876}
877
878static void __exit omap_dm_timer_driver_exit(void)
879{
880 platform_driver_unregister(&omap_dm_timer_driver);
881}
882
883early_platform_init("earlytimer", &omap_dm_timer_driver);
884module_init(omap_dm_timer_driver_init);
885module_exit(omap_dm_timer_driver_exit);
886
887MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
888MODULE_LICENSE("GPL");
889MODULE_ALIAS("platform:" DRIVER_NAME);
890MODULE_AUTHOR("Texas Instruments Inc");