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