1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
51static u32 omap_reserved_systimers;
52static LIST_HEAD(omap_timer_list);
53static DEFINE_SPINLOCK(dm_timer_lock);
54
55enum {
56 REQUEST_ANY = 0,
57 REQUEST_BY_ID,
58 REQUEST_BY_CAP,
59 REQUEST_BY_NODE,
60};
61
62
63
64
65
66
67
68
69
70
71static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
72{
73 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
74 return __omap_dm_timer_read(timer, reg, timer->posted);
75}
76
77
78
79
80
81
82
83
84
85
86
87static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
88 u32 value)
89{
90 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
91 __omap_dm_timer_write(timer, reg, value, timer->posted);
92}
93
94static void omap_timer_restore_context(struct omap_dm_timer *timer)
95{
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);
106 __raw_writel(timer->context.tier, timer->irq_ena);
107 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
108 timer->context.tclr);
109}
110
111static int omap_dm_timer_reset(struct omap_dm_timer *timer)
112{
113 u32 l, timeout = 100000;
114
115 if (timer->revision != 1)
116 return -EINVAL;
117
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;
128 }
129
130
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;
138}
139
140static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
141{
142 int rc;
143
144
145
146
147
148 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
149 timer->fclk = clk_get(&timer->pdev->dev, "fck");
150 if (WARN_ON_ONCE(IS_ERR(timer->fclk))) {
151 dev_err(&timer->pdev->dev, ": No fclk handle.\n");
152 return -EINVAL;
153 }
154 }
155
156 omap_dm_timer_enable(timer);
157
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 }
165
166 __omap_dm_timer_enable_posted(timer);
167 omap_dm_timer_disable(timer);
168
169 return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
170}
171
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
187static struct omap_dm_timer *_omap_dm_timer_request(int req_type, void *data)
188{
189 struct omap_dm_timer *timer = NULL, *t;
190 struct device_node *np = NULL;
191 unsigned long flags;
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
207 break;
208 }
209
210 spin_lock_irqsave(&dm_timer_lock, flags);
211 list_for_each_entry(t, &omap_timer_list, node) {
212 if (t->reserved)
213 continue;
214
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
227
228
229
230
231
232
233 if (timer)
234 timer->reserved = 0;
235 timer = t;
236 timer->reserved = 1;
237
238
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
252 timer = t;
253 timer->reserved = 1;
254 goto found;
255 }
256 }
257found:
258 spin_unlock_irqrestore(&dm_timer_lock, flags);
259
260 if (timer && omap_dm_timer_prepare(timer)) {
261 timer->reserved = 0;
262 timer = NULL;
263 }
264
265 if (!timer)
266 pr_debug("%s: timer request failed!\n", __func__);
267
268 return timer;
269}
270
271struct omap_dm_timer *omap_dm_timer_request(void)
272{
273 return _omap_dm_timer_request(REQUEST_ANY, NULL);
274}
275EXPORT_SYMBOL_GPL(omap_dm_timer_request);
276
277struct omap_dm_timer *omap_dm_timer_request_specific(int id)
278{
279
280 if (of_have_populated_dt()) {
281 pr_warn("%s: Please use omap_dm_timer_request_by_cap/node()\n",
282 __func__);
283 return NULL;
284 }
285
286 return _omap_dm_timer_request(REQUEST_BY_ID, &id);
287}
288EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
289
290
291
292
293
294
295
296
297
298
299struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
300{
301 return _omap_dm_timer_request(REQUEST_BY_CAP, &cap);
302}
303EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
304
305
306
307
308
309
310
311
312struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np)
313{
314 if (!np)
315 return NULL;
316
317 return _omap_dm_timer_request(REQUEST_BY_NODE, np);
318}
319EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_node);
320
321int omap_dm_timer_free(struct omap_dm_timer *timer)
322{
323 if (unlikely(!timer))
324 return -EINVAL;
325
326 clk_put(timer->fclk);
327
328 WARN_ON(!timer->reserved);
329 timer->reserved = 0;
330 return 0;
331}
332EXPORT_SYMBOL_GPL(omap_dm_timer_free);
333
334void omap_dm_timer_enable(struct omap_dm_timer *timer)
335{
336 int c;
337
338 pm_runtime_get_sync(&timer->pdev->dev);
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 }
347 } else {
348 omap_timer_restore_context(timer);
349 }
350 }
351}
352EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
353
354void omap_dm_timer_disable(struct omap_dm_timer *timer)
355{
356 pm_runtime_put_sync(&timer->pdev->dev);
357}
358EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
359
360int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
361{
362 if (timer)
363 return timer->irq;
364 return -EINVAL;
365}
366EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
367
368#if defined(CONFIG_ARCH_OMAP1)
369#include <mach/hardware.h>
370
371
372
373
374__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
375{
376 int i = 0;
377 struct omap_dm_timer *timer = NULL;
378 unsigned long flags;
379
380
381 if (!(inputmask & (1 << 1)))
382 return inputmask;
383
384
385 spin_lock_irqsave(&dm_timer_lock, flags);
386 list_for_each_entry(timer, &omap_timer_list, node) {
387 u32 l;
388
389 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
390 if (l & OMAP_TIMER_CTRL_ST) {
391 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
392 inputmask &= ~(1 << 1);
393 else
394 inputmask &= ~(1 << 2);
395 }
396 i++;
397 }
398 spin_unlock_irqrestore(&dm_timer_lock, flags);
399
400 return inputmask;
401}
402EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
403
404#else
405
406struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
407{
408 if (timer && !IS_ERR(timer->fclk))
409 return timer->fclk;
410 return NULL;
411}
412EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
413
414__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
415{
416 BUG();
417
418 return 0;
419}
420EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
421
422#endif
423
424int omap_dm_timer_trigger(struct omap_dm_timer *timer)
425{
426 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
427 pr_err("%s: timer not available or enabled.\n", __func__);
428 return -EINVAL;
429 }
430
431 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
432 return 0;
433}
434EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
435
436int omap_dm_timer_start(struct omap_dm_timer *timer)
437{
438 u32 l;
439
440 if (unlikely(!timer))
441 return -EINVAL;
442
443 omap_dm_timer_enable(timer);
444
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 }
450
451
452 timer->context.tclr = l;
453 return 0;
454}
455EXPORT_SYMBOL_GPL(omap_dm_timer_start);
456
457int omap_dm_timer_stop(struct omap_dm_timer *timer)
458{
459 unsigned long rate = 0;
460
461 if (unlikely(!timer))
462 return -EINVAL;
463
464 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
465 rate = clk_get_rate(timer->fclk);
466
467 __omap_dm_timer_stop(timer, timer->posted, rate);
468
469
470
471
472
473
474 timer->context.tclr =
475 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
476 omap_dm_timer_disable(timer);
477 return 0;
478}
479EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
480
481int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
482{
483 int ret;
484 char *parent_name = NULL;
485 struct clk *parent;
486 struct dmtimer_platform_data *pdata;
487
488 if (unlikely(!timer))
489 return -EINVAL;
490
491 pdata = timer->pdev->dev.platform_data;
492
493 if (source < 0 || source >= 3)
494 return -EINVAL;
495
496
497
498
499
500
501 if (pdata && pdata->set_timer_src)
502 return pdata->set_timer_src(timer->pdev, source);
503
504 if (IS_ERR(timer->fclk))
505 return -EINVAL;
506
507 switch (source) {
508 case OMAP_TIMER_SRC_SYS_CLK:
509 parent_name = "timer_sys_ck";
510 break;
511
512 case OMAP_TIMER_SRC_32_KHZ:
513 parent_name = "timer_32k_ck";
514 break;
515
516 case OMAP_TIMER_SRC_EXT_CLK:
517 parent_name = "timer_ext_ck";
518 break;
519 }
520
521 parent = clk_get(&timer->pdev->dev, parent_name);
522 if (IS_ERR(parent)) {
523 pr_err("%s: %s not found\n", __func__, parent_name);
524 return -EINVAL;
525 }
526
527 ret = clk_set_parent(timer->fclk, parent);
528 if (ret < 0)
529 pr_err("%s: failed to set %s as parent\n", __func__,
530 parent_name);
531
532 clk_put(parent);
533
534 return ret;
535}
536EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
537
538int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
539 unsigned int load)
540{
541 u32 l;
542
543 if (unlikely(!timer))
544 return -EINVAL;
545
546 omap_dm_timer_enable(timer);
547 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
548 if (autoreload)
549 l |= OMAP_TIMER_CTRL_AR;
550 else
551 l &= ~OMAP_TIMER_CTRL_AR;
552 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
553 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
554
555 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
556
557 timer->context.tclr = l;
558 timer->context.tldr = load;
559 omap_dm_timer_disable(timer);
560 return 0;
561}
562EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
563
564
565int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
566 unsigned int load)
567{
568 u32 l;
569
570 if (unlikely(!timer))
571 return -EINVAL;
572
573 omap_dm_timer_enable(timer);
574
575 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
576 if (autoreload) {
577 l |= OMAP_TIMER_CTRL_AR;
578 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
579 } else {
580 l &= ~OMAP_TIMER_CTRL_AR;
581 }
582 l |= OMAP_TIMER_CTRL_ST;
583
584 __omap_dm_timer_load_start(timer, l, load, timer->posted);
585
586
587 timer->context.tclr = l;
588 timer->context.tldr = load;
589 timer->context.tcrr = load;
590 return 0;
591}
592EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
593
594int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
595 unsigned int match)
596{
597 u32 l;
598
599 if (unlikely(!timer))
600 return -EINVAL;
601
602 omap_dm_timer_enable(timer);
603 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
604 if (enable)
605 l |= OMAP_TIMER_CTRL_CE;
606 else
607 l &= ~OMAP_TIMER_CTRL_CE;
608 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
609 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
610
611
612 timer->context.tclr = l;
613 timer->context.tmar = match;
614 omap_dm_timer_disable(timer);
615 return 0;
616}
617EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
618
619int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
620 int toggle, int trigger)
621{
622 u32 l;
623
624 if (unlikely(!timer))
625 return -EINVAL;
626
627 omap_dm_timer_enable(timer);
628 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
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;
636 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
637
638
639 timer->context.tclr = l;
640 omap_dm_timer_disable(timer);
641 return 0;
642}
643EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
644
645int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
646{
647 u32 l;
648
649 if (unlikely(!timer))
650 return -EINVAL;
651
652 omap_dm_timer_enable(timer);
653 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
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 }
659 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
660
661
662 timer->context.tclr = l;
663 omap_dm_timer_disable(timer);
664 return 0;
665}
666EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
667
668int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
669 unsigned int value)
670{
671 if (unlikely(!timer))
672 return -EINVAL;
673
674 omap_dm_timer_enable(timer);
675 __omap_dm_timer_int_enable(timer, value);
676
677
678 timer->context.tier = value;
679 timer->context.twer = value;
680 omap_dm_timer_disable(timer);
681 return 0;
682}
683EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
684
685
686
687
688
689
690
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)
702 l = __raw_readl(timer->irq_ena) & ~mask;
703
704 __raw_writel(l, timer->irq_dis);
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
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
716unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
717{
718 unsigned int l;
719
720 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
721 pr_err("%s: timer not available or enabled.\n", __func__);
722 return 0;
723 }
724
725 l = __raw_readl(timer->irq_stat);
726
727 return l;
728}
729EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
730
731int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
732{
733 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
734 return -EINVAL;
735
736 __omap_dm_timer_write_status(timer, value);
737
738 return 0;
739}
740EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
741
742unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
743{
744 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
745 pr_err("%s: timer not iavailable or enabled.\n", __func__);
746 return 0;
747 }
748
749 return __omap_dm_timer_read_counter(timer, timer->posted);
750}
751EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
752
753int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
754{
755 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
756 pr_err("%s: timer not available or enabled.\n", __func__);
757 return -EINVAL;
758 }
759
760 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
761
762
763 timer->context.tcrr = value;
764 return 0;
765}
766EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
767
768int omap_dm_timers_active(void)
769{
770 struct omap_dm_timer *timer;
771
772 list_for_each_entry(timer, &omap_timer_list, node) {
773 if (!timer->reserved)
774 continue;
775
776 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
777 OMAP_TIMER_CTRL_ST) {
778 return 1;
779 }
780 }
781 return 0;
782}
783EXPORT_SYMBOL_GPL(omap_dm_timers_active);
784
785static const struct of_device_id omap_timer_match[];
786
787
788
789
790
791
792
793
794static int omap_dm_timer_probe(struct platform_device *pdev)
795{
796 unsigned long flags;
797 struct omap_dm_timer *timer;
798 struct resource *mem, *irq;
799 struct device *dev = &pdev->dev;
800 const struct of_device_id *match;
801 const struct dmtimer_platform_data *pdata;
802
803 match = of_match_device(of_match_ptr(omap_timer_match), dev);
804 pdata = match ? match->data : dev->platform_data;
805
806 if (!pdata && !dev->of_node) {
807 dev_err(dev, "%s: no platform data.\n", __func__);
808 return -ENODEV;
809 }
810
811 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
812 if (unlikely(!irq)) {
813 dev_err(dev, "%s: no IRQ resource.\n", __func__);
814 return -ENODEV;
815 }
816
817 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
818 if (unlikely(!mem)) {
819 dev_err(dev, "%s: no memory resource.\n", __func__);
820 return -ENODEV;
821 }
822
823 timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
824 if (!timer) {
825 dev_err(dev, "%s: memory alloc failed!\n", __func__);
826 return -ENOMEM;
827 }
828
829 timer->fclk = ERR_PTR(-ENODEV);
830 timer->io_base = devm_ioremap_resource(dev, mem);
831 if (IS_ERR(timer->io_base))
832 return PTR_ERR(timer->io_base);
833
834 if (dev->of_node) {
835 if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
836 timer->capability |= OMAP_TIMER_ALWON;
837 if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
838 timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
839 if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
840 timer->capability |= OMAP_TIMER_HAS_PWM;
841 if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
842 timer->capability |= OMAP_TIMER_SECURE;
843 } else {
844 timer->id = pdev->id;
845 timer->capability = pdata->timer_capability;
846 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
847 timer->get_context_loss_count = pdata->get_context_loss_count;
848 }
849
850 if (pdata)
851 timer->errata = pdata->timer_errata;
852
853 timer->irq = irq->start;
854 timer->pdev = pdev;
855
856
857 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
858 pm_runtime_enable(dev);
859 pm_runtime_irq_safe(dev);
860 }
861
862 if (!timer->reserved) {
863 pm_runtime_get_sync(dev);
864 __omap_dm_timer_init_regs(timer);
865 pm_runtime_put(dev);
866 }
867
868
869 spin_lock_irqsave(&dm_timer_lock, flags);
870 list_add_tail(&timer->node, &omap_timer_list);
871 spin_unlock_irqrestore(&dm_timer_lock, flags);
872
873 dev_dbg(dev, "Device Probed.\n");
874
875 return 0;
876}
877
878
879
880
881
882
883
884
885
886static int omap_dm_timer_remove(struct platform_device *pdev)
887{
888 struct omap_dm_timer *timer;
889 unsigned long flags;
890 int ret = -EINVAL;
891
892 spin_lock_irqsave(&dm_timer_lock, flags);
893 list_for_each_entry(timer, &omap_timer_list, node)
894 if (!strcmp(dev_name(&timer->pdev->dev),
895 dev_name(&pdev->dev))) {
896 list_del(&timer->node);
897 ret = 0;
898 break;
899 }
900 spin_unlock_irqrestore(&dm_timer_lock, flags);
901
902 return ret;
903}
904
905static const struct dmtimer_platform_data omap3plus_pdata = {
906 .timer_errata = OMAP_TIMER_ERRATA_I103_I767,
907};
908
909static const struct of_device_id omap_timer_match[] = {
910 {
911 .compatible = "ti,omap2420-timer",
912 },
913 {
914 .compatible = "ti,omap3430-timer",
915 .data = &omap3plus_pdata,
916 },
917 {
918 .compatible = "ti,omap4430-timer",
919 .data = &omap3plus_pdata,
920 },
921 {
922 .compatible = "ti,omap5430-timer",
923 .data = &omap3plus_pdata,
924 },
925 {
926 .compatible = "ti,am335x-timer",
927 .data = &omap3plus_pdata,
928 },
929 {
930 .compatible = "ti,am335x-timer-1ms",
931 .data = &omap3plus_pdata,
932 },
933 {},
934};
935MODULE_DEVICE_TABLE(of, omap_timer_match);
936
937static struct platform_driver omap_dm_timer_driver = {
938 .probe = omap_dm_timer_probe,
939 .remove = omap_dm_timer_remove,
940 .driver = {
941 .name = "omap_timer",
942 .of_match_table = of_match_ptr(omap_timer_match),
943 },
944};
945
946early_platform_init("earlytimer", &omap_dm_timer_driver);
947module_platform_driver(omap_dm_timer_driver);
948
949MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
950MODULE_LICENSE("GPL");
951MODULE_ALIAS("platform:" DRIVER_NAME);
952MODULE_AUTHOR("Texas Instruments Inc");
953