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