Merge branches 'cleanup-part3', 'voltage', 'dmtimer' and 'l3' into dt-base
[linux-2.6-block.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
fced80c7 38#include <linux/io.h>
df28472a 39#include <linux/slab.h>
3392cdd3 40#include <linux/err.h>
ffe07cea 41#include <linux/pm_runtime.h>
44169075 42
3392cdd3 43#include <plat/dmtimer.h>
471b3aa7 44
df28472a 45static LIST_HEAD(omap_timer_list);
3392cdd3 46static DEFINE_SPINLOCK(dm_timer_lock);
92105bb7 47
3392cdd3
TKD
48/**
49 * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
50 * @timer: timer pointer over which read operation to perform
51 * @reg: lowest byte holds the register offset
52 *
53 * The posted mode bit is encoded in reg. Note that in posted mode write
54 * pending bit must be checked. Otherwise a read of a non completed write
55 * will produce an error.
0f0d0807
RW
56 */
57static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
77900a2f 58{
ee17f114
TL
59 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
60 return __omap_dm_timer_read(timer, reg, timer->posted);
77900a2f 61}
92105bb7 62
3392cdd3
TKD
63/**
64 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
65 * @timer: timer pointer over which write operation is to perform
66 * @reg: lowest byte holds the register offset
67 * @value: data to write into the register
68 *
69 * The posted mode bit is encoded in reg. Note that in posted mode the write
70 * pending bit must be checked. Otherwise a write on a register which has a
71 * pending write will be lost.
0f0d0807
RW
72 */
73static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
74 u32 value)
92105bb7 75{
ee17f114
TL
76 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
77 __omap_dm_timer_write(timer, reg, value, timer->posted);
92105bb7
TL
78}
79
b481113a
TKD
80static void omap_timer_restore_context(struct omap_dm_timer *timer)
81{
82 omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
83 timer->context.tiocp_cfg);
84 if (timer->revision > 1)
85 __raw_writel(timer->context.tistat, timer->sys_stat);
86
87 __raw_writel(timer->context.tisr, timer->irq_stat);
88 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
89 timer->context.twer);
90 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
91 timer->context.tcrr);
92 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
93 timer->context.tldr);
94 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
95 timer->context.tmar);
96 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
97 timer->context.tsicr);
98 __raw_writel(timer->context.tier, timer->irq_ena);
99 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
100 timer->context.tclr);
101}
102
77900a2f 103static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
92105bb7 104{
77900a2f
TT
105 int c;
106
ee17f114
TL
107 if (!timer->sys_stat)
108 return;
109
77900a2f 110 c = 0;
ee17f114 111 while (!(__raw_readl(timer->sys_stat) & 1)) {
77900a2f
TT
112 c++;
113 if (c > 100000) {
114 printk(KERN_ERR "Timer failed to reset\n");
115 return;
116 }
117 }
92105bb7
TL
118}
119
77900a2f
TT
120static void omap_dm_timer_reset(struct omap_dm_timer *timer)
121{
b481113a 122 omap_dm_timer_enable(timer);
3392cdd3 123 if (timer->pdev->id != 1) {
e32f7ec2
TT
124 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
125 omap_dm_timer_wait_for_reset(timer);
126 }
0f0d0807 127
3392cdd3 128 __omap_dm_timer_reset(timer, 0, 0);
b481113a 129 omap_dm_timer_disable(timer);
0f0d0807 130 timer->posted = 1;
77900a2f
TT
131}
132
3392cdd3 133int omap_dm_timer_prepare(struct omap_dm_timer *timer)
77900a2f 134{
3392cdd3
TKD
135 struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
136 int ret;
137
138 timer->fclk = clk_get(&timer->pdev->dev, "fck");
139 if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
140 timer->fclk = NULL;
141 dev_err(&timer->pdev->dev, ": No fclk handle.\n");
142 return -EINVAL;
143 }
144
3392cdd3
TKD
145 if (pdata->needs_manual_reset)
146 omap_dm_timer_reset(timer);
147
148 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
149
150 timer->posted = 1;
151 return ret;
77900a2f
TT
152}
153
154struct omap_dm_timer *omap_dm_timer_request(void)
155{
3392cdd3 156 struct omap_dm_timer *timer = NULL, *t;
77900a2f 157 unsigned long flags;
3392cdd3 158 int ret = 0;
77900a2f
TT
159
160 spin_lock_irqsave(&dm_timer_lock, flags);
3392cdd3
TKD
161 list_for_each_entry(t, &omap_timer_list, node) {
162 if (t->reserved)
77900a2f
TT
163 continue;
164
3392cdd3 165 timer = t;
83379c81 166 timer->reserved = 1;
77900a2f
TT
167 break;
168 }
3392cdd3
TKD
169
170 if (timer) {
171 ret = omap_dm_timer_prepare(timer);
172 if (ret) {
173 timer->reserved = 0;
174 timer = NULL;
175 }
176 }
77900a2f
TT
177 spin_unlock_irqrestore(&dm_timer_lock, flags);
178
3392cdd3
TKD
179 if (!timer)
180 pr_debug("%s: timer request failed!\n", __func__);
83379c81 181
77900a2f
TT
182 return timer;
183}
6c366e32 184EXPORT_SYMBOL_GPL(omap_dm_timer_request);
77900a2f
TT
185
186struct omap_dm_timer *omap_dm_timer_request_specific(int id)
92105bb7 187{
3392cdd3 188 struct omap_dm_timer *timer = NULL, *t;
77900a2f 189 unsigned long flags;
3392cdd3 190 int ret = 0;
92105bb7 191
77900a2f 192 spin_lock_irqsave(&dm_timer_lock, flags);
3392cdd3
TKD
193 list_for_each_entry(t, &omap_timer_list, node) {
194 if (t->pdev->id == id && !t->reserved) {
195 timer = t;
196 timer->reserved = 1;
197 break;
198 }
77900a2f 199 }
92105bb7 200
3392cdd3
TKD
201 if (timer) {
202 ret = omap_dm_timer_prepare(timer);
203 if (ret) {
204 timer->reserved = 0;
205 timer = NULL;
206 }
207 }
77900a2f
TT
208 spin_unlock_irqrestore(&dm_timer_lock, flags);
209
3392cdd3
TKD
210 if (!timer)
211 pr_debug("%s: timer%d request failed!\n", __func__, id);
83379c81 212
77900a2f 213 return timer;
92105bb7 214}
6c366e32 215EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
92105bb7 216
ab4eb8b0 217int omap_dm_timer_free(struct omap_dm_timer *timer)
77900a2f 218{
ab4eb8b0
TKD
219 if (unlikely(!timer))
220 return -EINVAL;
221
3392cdd3 222 clk_put(timer->fclk);
fa4bb626 223
77900a2f
TT
224 WARN_ON(!timer->reserved);
225 timer->reserved = 0;
ab4eb8b0 226 return 0;
77900a2f 227}
6c366e32 228EXPORT_SYMBOL_GPL(omap_dm_timer_free);
77900a2f 229
12583a70
TT
230void omap_dm_timer_enable(struct omap_dm_timer *timer)
231{
ffe07cea 232 pm_runtime_get_sync(&timer->pdev->dev);
12583a70 233}
6c366e32 234EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
12583a70
TT
235
236void omap_dm_timer_disable(struct omap_dm_timer *timer)
237{
ffe07cea 238 pm_runtime_put(&timer->pdev->dev);
12583a70 239}
6c366e32 240EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
12583a70 241
77900a2f
TT
242int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
243{
ab4eb8b0
TKD
244 if (timer)
245 return timer->irq;
246 return -EINVAL;
77900a2f 247}
6c366e32 248EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
77900a2f
TT
249
250#if defined(CONFIG_ARCH_OMAP1)
251
a569c6ec
TL
252/**
253 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
254 * @inputmask: current value of idlect mask
255 */
256__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
257{
3392cdd3
TKD
258 int i = 0;
259 struct omap_dm_timer *timer = NULL;
260 unsigned long flags;
a569c6ec
TL
261
262 /* If ARMXOR cannot be idled this function call is unnecessary */
263 if (!(inputmask & (1 << 1)))
264 return inputmask;
265
266 /* If any active timer is using ARMXOR return modified mask */
3392cdd3
TKD
267 spin_lock_irqsave(&dm_timer_lock, flags);
268 list_for_each_entry(timer, &omap_timer_list, node) {
77900a2f
TT
269 u32 l;
270
3392cdd3 271 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
272 if (l & OMAP_TIMER_CTRL_ST) {
273 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
a569c6ec
TL
274 inputmask &= ~(1 << 1);
275 else
276 inputmask &= ~(1 << 2);
277 }
3392cdd3 278 i++;
77900a2f 279 }
3392cdd3 280 spin_unlock_irqrestore(&dm_timer_lock, flags);
a569c6ec
TL
281
282 return inputmask;
283}
6c366e32 284EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
a569c6ec 285
140455fa 286#else
a569c6ec 287
77900a2f 288struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
92105bb7 289{
ab4eb8b0
TKD
290 if (timer)
291 return timer->fclk;
292 return NULL;
77900a2f 293}
6c366e32 294EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
92105bb7 295
77900a2f
TT
296__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
297{
298 BUG();
2121880e
DB
299
300 return 0;
92105bb7 301}
6c366e32 302EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
92105bb7 303
77900a2f 304#endif
92105bb7 305
ab4eb8b0 306int omap_dm_timer_trigger(struct omap_dm_timer *timer)
92105bb7 307{
ab4eb8b0
TKD
308 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
309 pr_err("%s: timer not available or enabled.\n", __func__);
310 return -EINVAL;
b481113a
TKD
311 }
312
77900a2f 313 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
ab4eb8b0 314 return 0;
92105bb7 315}
6c366e32 316EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
92105bb7 317
ab4eb8b0 318int omap_dm_timer_start(struct omap_dm_timer *timer)
77900a2f
TT
319{
320 u32 l;
92105bb7 321
ab4eb8b0
TKD
322 if (unlikely(!timer))
323 return -EINVAL;
324
b481113a
TKD
325 omap_dm_timer_enable(timer);
326
327 if (timer->loses_context) {
328 u32 ctx_loss_cnt_after =
329 timer->get_context_loss_count(&timer->pdev->dev);
330 if (ctx_loss_cnt_after != timer->ctx_loss_count)
331 omap_timer_restore_context(timer);
332 }
333
77900a2f
TT
334 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
335 if (!(l & OMAP_TIMER_CTRL_ST)) {
336 l |= OMAP_TIMER_CTRL_ST;
337 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
338 }
b481113a
TKD
339
340 /* Save the context */
341 timer->context.tclr = l;
ab4eb8b0 342 return 0;
77900a2f 343}
6c366e32 344EXPORT_SYMBOL_GPL(omap_dm_timer_start);
92105bb7 345
ab4eb8b0 346int omap_dm_timer_stop(struct omap_dm_timer *timer)
92105bb7 347{
caf64f2f 348 unsigned long rate = 0;
3392cdd3 349 struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
92105bb7 350
ab4eb8b0
TKD
351 if (unlikely(!timer))
352 return -EINVAL;
353
3392cdd3
TKD
354 if (!pdata->needs_manual_reset)
355 rate = clk_get_rate(timer->fclk);
caf64f2f 356
ee17f114 357 __omap_dm_timer_stop(timer, timer->posted, rate);
ab4eb8b0
TKD
358
359 return 0;
92105bb7 360}
6c366e32 361EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
92105bb7 362
f248076c 363int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
92105bb7 364{
3392cdd3 365 int ret;
ab4eb8b0
TKD
366 struct dmtimer_platform_data *pdata;
367
368 if (unlikely(!timer))
369 return -EINVAL;
370
371 pdata = timer->pdev->dev.platform_data;
3392cdd3 372
77900a2f 373 if (source < 0 || source >= 3)
f248076c 374 return -EINVAL;
77900a2f 375
3392cdd3 376 ret = pdata->set_timer_src(timer->pdev, source);
3392cdd3
TKD
377
378 return ret;
92105bb7 379}
6c366e32 380EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
92105bb7 381
ab4eb8b0 382int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
77900a2f 383 unsigned int load)
92105bb7
TL
384{
385 u32 l;
77900a2f 386
ab4eb8b0
TKD
387 if (unlikely(!timer))
388 return -EINVAL;
389
b481113a 390 omap_dm_timer_enable(timer);
92105bb7 391 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
392 if (autoreload)
393 l |= OMAP_TIMER_CTRL_AR;
394 else
395 l &= ~OMAP_TIMER_CTRL_AR;
92105bb7 396 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
77900a2f 397 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
0f0d0807 398
77900a2f 399 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
b481113a
TKD
400 /* Save the context */
401 timer->context.tclr = l;
402 timer->context.tldr = load;
403 omap_dm_timer_disable(timer);
ab4eb8b0 404 return 0;
92105bb7 405}
6c366e32 406EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
92105bb7 407
3fddd09e 408/* Optimized set_load which removes costly spin wait in timer_start */
ab4eb8b0 409int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
3fddd09e
RW
410 unsigned int load)
411{
412 u32 l;
413
ab4eb8b0
TKD
414 if (unlikely(!timer))
415 return -EINVAL;
416
b481113a
TKD
417 omap_dm_timer_enable(timer);
418
419 if (timer->loses_context) {
420 u32 ctx_loss_cnt_after =
421 timer->get_context_loss_count(&timer->pdev->dev);
422 if (ctx_loss_cnt_after != timer->ctx_loss_count)
423 omap_timer_restore_context(timer);
424 }
425
3fddd09e 426 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
64ce2907 427 if (autoreload) {
3fddd09e 428 l |= OMAP_TIMER_CTRL_AR;
64ce2907
PW
429 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
430 } else {
3fddd09e 431 l &= ~OMAP_TIMER_CTRL_AR;
64ce2907 432 }
3fddd09e
RW
433 l |= OMAP_TIMER_CTRL_ST;
434
ee17f114 435 __omap_dm_timer_load_start(timer, l, load, timer->posted);
b481113a
TKD
436
437 /* Save the context */
438 timer->context.tclr = l;
439 timer->context.tldr = load;
440 timer->context.tcrr = load;
ab4eb8b0 441 return 0;
3fddd09e 442}
6c366e32 443EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
3fddd09e 444
ab4eb8b0 445int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
77900a2f 446 unsigned int match)
92105bb7
TL
447{
448 u32 l;
449
ab4eb8b0
TKD
450 if (unlikely(!timer))
451 return -EINVAL;
452
b481113a 453 omap_dm_timer_enable(timer);
92105bb7 454 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
83379c81 455 if (enable)
77900a2f
TT
456 l |= OMAP_TIMER_CTRL_CE;
457 else
458 l &= ~OMAP_TIMER_CTRL_CE;
92105bb7 459 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
77900a2f 460 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
b481113a
TKD
461
462 /* Save the context */
463 timer->context.tclr = l;
464 timer->context.tmar = match;
465 omap_dm_timer_disable(timer);
ab4eb8b0 466 return 0;
92105bb7 467}
6c366e32 468EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
92105bb7 469
ab4eb8b0 470int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
77900a2f 471 int toggle, int trigger)
92105bb7
TL
472{
473 u32 l;
474
ab4eb8b0
TKD
475 if (unlikely(!timer))
476 return -EINVAL;
477
b481113a 478 omap_dm_timer_enable(timer);
92105bb7 479 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
480 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
481 OMAP_TIMER_CTRL_PT | (0x03 << 10));
482 if (def_on)
483 l |= OMAP_TIMER_CTRL_SCPWM;
484 if (toggle)
485 l |= OMAP_TIMER_CTRL_PT;
486 l |= trigger << 10;
92105bb7 487 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
b481113a
TKD
488
489 /* Save the context */
490 timer->context.tclr = l;
491 omap_dm_timer_disable(timer);
ab4eb8b0 492 return 0;
92105bb7 493}
6c366e32 494EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
92105bb7 495
ab4eb8b0 496int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
92105bb7
TL
497{
498 u32 l;
499
ab4eb8b0
TKD
500 if (unlikely(!timer))
501 return -EINVAL;
502
b481113a 503 omap_dm_timer_enable(timer);
92105bb7 504 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
77900a2f
TT
505 l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
506 if (prescaler >= 0x00 && prescaler <= 0x07) {
507 l |= OMAP_TIMER_CTRL_PRE;
508 l |= prescaler << 2;
509 }
92105bb7 510 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
b481113a
TKD
511
512 /* Save the context */
513 timer->context.tclr = l;
514 omap_dm_timer_disable(timer);
ab4eb8b0 515 return 0;
92105bb7 516}
6c366e32 517EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
92105bb7 518
ab4eb8b0 519int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
77900a2f 520 unsigned int value)
92105bb7 521{
ab4eb8b0
TKD
522 if (unlikely(!timer))
523 return -EINVAL;
524
b481113a 525 omap_dm_timer_enable(timer);
ee17f114 526 __omap_dm_timer_int_enable(timer, value);
b481113a
TKD
527
528 /* Save the context */
529 timer->context.tier = value;
530 timer->context.twer = value;
531 omap_dm_timer_disable(timer);
ab4eb8b0 532 return 0;
92105bb7 533}
6c366e32 534EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
92105bb7 535
77900a2f 536unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
92105bb7 537{
fa4bb626
TT
538 unsigned int l;
539
ab4eb8b0
TKD
540 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
541 pr_err("%s: timer not available or enabled.\n", __func__);
b481113a
TKD
542 return 0;
543 }
544
ee17f114 545 l = __raw_readl(timer->irq_stat);
fa4bb626
TT
546
547 return l;
92105bb7 548}
6c366e32 549EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
92105bb7 550
ab4eb8b0 551int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
92105bb7 552{
ab4eb8b0
TKD
553 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
554 return -EINVAL;
555
ee17f114 556 __omap_dm_timer_write_status(timer, value);
b481113a
TKD
557 /* Save the context */
558 timer->context.tisr = value;
ab4eb8b0 559 return 0;
92105bb7 560}
6c366e32 561EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
92105bb7 562
77900a2f 563unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
92105bb7 564{
ab4eb8b0
TKD
565 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
566 pr_err("%s: timer not iavailable or enabled.\n", __func__);
b481113a
TKD
567 return 0;
568 }
569
ee17f114 570 return __omap_dm_timer_read_counter(timer, timer->posted);
92105bb7 571}
6c366e32 572EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
92105bb7 573
ab4eb8b0 574int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
83379c81 575{
ab4eb8b0
TKD
576 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
577 pr_err("%s: timer not available or enabled.\n", __func__);
578 return -EINVAL;
b481113a
TKD
579 }
580
fa4bb626 581 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
b481113a
TKD
582
583 /* Save the context */
584 timer->context.tcrr = value;
ab4eb8b0 585 return 0;
83379c81 586}
6c366e32 587EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
83379c81 588
77900a2f 589int omap_dm_timers_active(void)
92105bb7 590{
3392cdd3 591 struct omap_dm_timer *timer;
12583a70 592
3392cdd3 593 list_for_each_entry(timer, &omap_timer_list, node) {
ffe07cea 594 if (!timer->reserved)
12583a70
TT
595 continue;
596
77900a2f 597 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
fa4bb626 598 OMAP_TIMER_CTRL_ST) {
77900a2f 599 return 1;
fa4bb626 600 }
77900a2f
TT
601 }
602 return 0;
603}
6c366e32 604EXPORT_SYMBOL_GPL(omap_dm_timers_active);
92105bb7 605
df28472a
TKD
606/**
607 * omap_dm_timer_probe - probe function called for every registered device
608 * @pdev: pointer to current timer platform device
609 *
610 * Called by driver framework at the end of device registration for all
611 * timer devices.
612 */
613static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
614{
615 int ret;
616 unsigned long flags;
617 struct omap_dm_timer *timer;
618 struct resource *mem, *irq, *ioarea;
619 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
620
621 if (!pdata) {
622 dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
623 return -ENODEV;
624 }
625
626 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
627 if (unlikely(!irq)) {
628 dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
629 return -ENODEV;
630 }
631
632 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
633 if (unlikely(!mem)) {
634 dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
635 return -ENODEV;
636 }
637
638 ioarea = request_mem_region(mem->start, resource_size(mem),
639 pdev->name);
640 if (!ioarea) {
641 dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
642 return -EBUSY;
643 }
644
645 timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
646 if (!timer) {
647 dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n",
648 __func__);
649 ret = -ENOMEM;
650 goto err_free_ioregion;
651 }
652
653 timer->io_base = ioremap(mem->start, resource_size(mem));
654 if (!timer->io_base) {
655 dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__);
656 ret = -ENOMEM;
657 goto err_free_mem;
658 }
659
660 timer->id = pdev->id;
661 timer->irq = irq->start;
0dad9fae 662 timer->reserved = pdata->reserved;
df28472a 663 timer->pdev = pdev;
b481113a
TKD
664 timer->loses_context = pdata->loses_context;
665 timer->get_context_loss_count = pdata->get_context_loss_count;
df28472a 666
ffe07cea
TKD
667 /* Skip pm_runtime_enable for OMAP1 */
668 if (!pdata->needs_manual_reset) {
669 pm_runtime_enable(&pdev->dev);
670 pm_runtime_irq_safe(&pdev->dev);
671 }
672
0dad9fae
TL
673 if (!timer->reserved) {
674 pm_runtime_get_sync(&pdev->dev);
675 __omap_dm_timer_init_regs(timer);
676 pm_runtime_put(&pdev->dev);
677 }
678
df28472a
TKD
679 /* add the timer element to the list */
680 spin_lock_irqsave(&dm_timer_lock, flags);
681 list_add_tail(&timer->node, &omap_timer_list);
682 spin_unlock_irqrestore(&dm_timer_lock, flags);
683
684 dev_dbg(&pdev->dev, "Device Probed.\n");
685
686 return 0;
687
688err_free_mem:
689 kfree(timer);
690
691err_free_ioregion:
692 release_mem_region(mem->start, resource_size(mem));
693
694 return ret;
695}
696
697/**
698 * omap_dm_timer_remove - cleanup a registered timer device
699 * @pdev: pointer to current timer platform device
700 *
701 * Called by driver framework whenever a timer device is unregistered.
702 * In addition to freeing platform resources it also deletes the timer
703 * entry from the local list.
704 */
705static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
706{
707 struct omap_dm_timer *timer;
708 unsigned long flags;
709 int ret = -EINVAL;
710
711 spin_lock_irqsave(&dm_timer_lock, flags);
712 list_for_each_entry(timer, &omap_timer_list, node)
713 if (timer->pdev->id == pdev->id) {
714 list_del(&timer->node);
715 kfree(timer);
716 ret = 0;
717 break;
718 }
719 spin_unlock_irqrestore(&dm_timer_lock, flags);
720
721 return ret;
722}
723
724static struct platform_driver omap_dm_timer_driver = {
725 .probe = omap_dm_timer_probe,
726 .remove = omap_dm_timer_remove,
727 .driver = {
728 .name = "omap_timer",
729 },
730};
731
732static int __init omap_dm_timer_driver_init(void)
733{
734 return platform_driver_register(&omap_dm_timer_driver);
735}
736
737static void __exit omap_dm_timer_driver_exit(void)
738{
739 platform_driver_unregister(&omap_dm_timer_driver);
740}
741
742early_platform_init("earlytimer", &omap_dm_timer_driver);
743module_init(omap_dm_timer_driver_init);
744module_exit(omap_dm_timer_driver_exit);
745
746MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
747MODULE_LICENSE("GPL");
748MODULE_ALIAS("platform:" DRIVER_NAME);
749MODULE_AUTHOR("Texas Instruments Inc");