aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/dmtimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r--arch/arm/plat-omap/dmtimer.c164
1 files changed, 103 insertions, 61 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 3b0cfeb33d05..626ad8cad7a9 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -37,14 +37,16 @@
37 37
38#include <linux/module.h> 38#include <linux/module.h>
39#include <linux/io.h> 39#include <linux/io.h>
40#include <linux/slab.h> 40#include <linux/device.h>
41#include <linux/err.h> 41#include <linux/err.h>
42#include <linux/pm_runtime.h> 42#include <linux/pm_runtime.h>
43 43
44#include <plat/dmtimer.h> 44#include <plat/dmtimer.h>
45#include <plat/omap-pm.h>
45 46
46#include <mach/hardware.h> 47#include <mach/hardware.h>
47 48
49static u32 omap_reserved_systimers;
48static LIST_HEAD(omap_timer_list); 50static LIST_HEAD(omap_timer_list);
49static DEFINE_SPINLOCK(dm_timer_lock); 51static DEFINE_SPINLOCK(dm_timer_lock);
50 52
@@ -133,17 +135,22 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
133 135
134int omap_dm_timer_prepare(struct omap_dm_timer *timer) 136int omap_dm_timer_prepare(struct omap_dm_timer *timer)
135{ 137{
136 struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
137 int ret; 138 int ret;
138 139
139 timer->fclk = clk_get(&timer->pdev->dev, "fck"); 140 /*
140 if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) { 141 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
141 timer->fclk = NULL; 142 * do not call clk_get() for these devices.
142 dev_err(&timer->pdev->dev, ": No fclk handle.\n"); 143 */
143 return -EINVAL; 144 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
145 timer->fclk = clk_get(&timer->pdev->dev, "fck");
146 if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
147 timer->fclk = NULL;
148 dev_err(&timer->pdev->dev, ": No fclk handle.\n");
149 return -EINVAL;
150 }
144 } 151 }
145 152
146 if (pdata->needs_manual_reset) 153 if (timer->capability & OMAP_TIMER_NEEDS_RESET)
147 omap_dm_timer_reset(timer); 154 omap_dm_timer_reset(timer);
148 155
149 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); 156 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
@@ -152,6 +159,21 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
152 return ret; 159 return ret;
153} 160}
154 161
162static inline u32 omap_dm_timer_reserved_systimer(int id)
163{
164 return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
165}
166
167int omap_dm_timer_reserve_systimer(int id)
168{
169 if (omap_dm_timer_reserved_systimer(id))
170 return -ENODEV;
171
172 omap_reserved_systimers |= (1 << (id - 1));
173
174 return 0;
175}
176
155struct omap_dm_timer *omap_dm_timer_request(void) 177struct omap_dm_timer *omap_dm_timer_request(void)
156{ 178{
157 struct omap_dm_timer *timer = NULL, *t; 179 struct omap_dm_timer *timer = NULL, *t;
@@ -325,10 +347,9 @@ int omap_dm_timer_start(struct omap_dm_timer *timer)
325 347
326 omap_dm_timer_enable(timer); 348 omap_dm_timer_enable(timer);
327 349
328 if (timer->loses_context) { 350 if (!(timer->capability & OMAP_TIMER_ALWON)) {
329 u32 ctx_loss_cnt_after = 351 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
330 timer->get_context_loss_count(&timer->pdev->dev); 352 timer->ctx_loss_count)
331 if (ctx_loss_cnt_after != timer->ctx_loss_count)
332 omap_timer_restore_context(timer); 353 omap_timer_restore_context(timer);
333 } 354 }
334 355
@@ -347,20 +368,18 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
347int omap_dm_timer_stop(struct omap_dm_timer *timer) 368int omap_dm_timer_stop(struct omap_dm_timer *timer)
348{ 369{
349 unsigned long rate = 0; 370 unsigned long rate = 0;
350 struct dmtimer_platform_data *pdata;
351 371
352 if (unlikely(!timer)) 372 if (unlikely(!timer))
353 return -EINVAL; 373 return -EINVAL;
354 374
355 pdata = timer->pdev->dev.platform_data; 375 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
356 if (!pdata->needs_manual_reset)
357 rate = clk_get_rate(timer->fclk); 376 rate = clk_get_rate(timer->fclk);
358 377
359 __omap_dm_timer_stop(timer, timer->posted, rate); 378 __omap_dm_timer_stop(timer, timer->posted, rate);
360 379
361 if (timer->loses_context && timer->get_context_loss_count) 380 if (!(timer->capability & OMAP_TIMER_ALWON))
362 timer->ctx_loss_count = 381 timer->ctx_loss_count =
363 timer->get_context_loss_count(&timer->pdev->dev); 382 omap_pm_get_dev_context_loss_count(&timer->pdev->dev);
364 383
365 /* 384 /*
366 * Since the register values are computed and written within 385 * Since the register values are computed and written within
@@ -378,6 +397,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
378int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) 397int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
379{ 398{
380 int ret; 399 int ret;
400 char *parent_name = NULL;
401 struct clk *fclk, *parent;
381 struct dmtimer_platform_data *pdata; 402 struct dmtimer_platform_data *pdata;
382 403
383 if (unlikely(!timer)) 404 if (unlikely(!timer))
@@ -388,7 +409,49 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
388 if (source < 0 || source >= 3) 409 if (source < 0 || source >= 3)
389 return -EINVAL; 410 return -EINVAL;
390 411
391 ret = pdata->set_timer_src(timer->pdev, source); 412 /*
413 * FIXME: Used for OMAP1 devices only because they do not currently
414 * use the clock framework to set the parent clock. To be removed
415 * once OMAP1 migrated to using clock framework for dmtimers
416 */
417 if (pdata->set_timer_src)
418 return pdata->set_timer_src(timer->pdev, source);
419
420 fclk = clk_get(&timer->pdev->dev, "fck");
421 if (IS_ERR_OR_NULL(fclk)) {
422 pr_err("%s: fck not found\n", __func__);
423 return -EINVAL;
424 }
425
426 switch (source) {
427 case OMAP_TIMER_SRC_SYS_CLK:
428 parent_name = "timer_sys_ck";
429 break;
430
431 case OMAP_TIMER_SRC_32_KHZ:
432 parent_name = "timer_32k_ck";
433 break;
434
435 case OMAP_TIMER_SRC_EXT_CLK:
436 parent_name = "timer_ext_ck";
437 break;
438 }
439
440 parent = clk_get(&timer->pdev->dev, parent_name);
441 if (IS_ERR_OR_NULL(parent)) {
442 pr_err("%s: %s not found\n", __func__, parent_name);
443 ret = -EINVAL;
444 goto out;
445 }
446
447 ret = clk_set_parent(fclk, parent);
448 if (IS_ERR_VALUE(ret))
449 pr_err("%s: failed to set %s as parent\n", __func__,
450 parent_name);
451
452 clk_put(parent);
453out:
454 clk_put(fclk);
392 455
393 return ret; 456 return ret;
394} 457}
@@ -431,10 +494,9 @@ int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
431 494
432 omap_dm_timer_enable(timer); 495 omap_dm_timer_enable(timer);
433 496
434 if (timer->loses_context) { 497 if (!(timer->capability & OMAP_TIMER_ALWON)) {
435 u32 ctx_loss_cnt_after = 498 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
436 timer->get_context_loss_count(&timer->pdev->dev); 499 timer->ctx_loss_count)
437 if (ctx_loss_cnt_after != timer->ctx_loss_count)
438 omap_timer_restore_context(timer); 500 omap_timer_restore_context(timer);
439 } 501 }
440 502
@@ -627,68 +689,57 @@ EXPORT_SYMBOL_GPL(omap_dm_timers_active);
627 */ 689 */
628static int __devinit omap_dm_timer_probe(struct platform_device *pdev) 690static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
629{ 691{
630 int ret;
631 unsigned long flags; 692 unsigned long flags;
632 struct omap_dm_timer *timer; 693 struct omap_dm_timer *timer;
633 struct resource *mem, *irq, *ioarea; 694 struct resource *mem, *irq;
695 struct device *dev = &pdev->dev;
634 struct dmtimer_platform_data *pdata = pdev->dev.platform_data; 696 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
635 697
636 if (!pdata) { 698 if (!pdata) {
637 dev_err(&pdev->dev, "%s: no platform data.\n", __func__); 699 dev_err(dev, "%s: no platform data.\n", __func__);
638 return -ENODEV; 700 return -ENODEV;
639 } 701 }
640 702
641 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 703 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
642 if (unlikely(!irq)) { 704 if (unlikely(!irq)) {
643 dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__); 705 dev_err(dev, "%s: no IRQ resource.\n", __func__);
644 return -ENODEV; 706 return -ENODEV;
645 } 707 }
646 708
647 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 709 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
648 if (unlikely(!mem)) { 710 if (unlikely(!mem)) {
649 dev_err(&pdev->dev, "%s: no memory resource.\n", __func__); 711 dev_err(dev, "%s: no memory resource.\n", __func__);
650 return -ENODEV; 712 return -ENODEV;
651 } 713 }
652 714
653 ioarea = request_mem_region(mem->start, resource_size(mem), 715 timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
654 pdev->name);
655 if (!ioarea) {
656 dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
657 return -EBUSY;
658 }
659
660 timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
661 if (!timer) { 716 if (!timer) {
662 dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n", 717 dev_err(dev, "%s: memory alloc failed!\n", __func__);
663 __func__); 718 return -ENOMEM;
664 ret = -ENOMEM;
665 goto err_free_ioregion;
666 } 719 }
667 720
668 timer->io_base = ioremap(mem->start, resource_size(mem)); 721 timer->io_base = devm_request_and_ioremap(dev, mem);
669 if (!timer->io_base) { 722 if (!timer->io_base) {
670 dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__); 723 dev_err(dev, "%s: region already claimed.\n", __func__);
671 ret = -ENOMEM; 724 return -ENOMEM;
672 goto err_free_mem;
673 } 725 }
674 726
675 timer->id = pdev->id; 727 timer->id = pdev->id;
676 timer->irq = irq->start; 728 timer->irq = irq->start;
677 timer->reserved = pdata->reserved; 729 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
678 timer->pdev = pdev; 730 timer->pdev = pdev;
679 timer->loses_context = pdata->loses_context; 731 timer->capability = pdata->timer_capability;
680 timer->get_context_loss_count = pdata->get_context_loss_count;
681 732
682 /* Skip pm_runtime_enable for OMAP1 */ 733 /* Skip pm_runtime_enable for OMAP1 */
683 if (!pdata->needs_manual_reset) { 734 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
684 pm_runtime_enable(&pdev->dev); 735 pm_runtime_enable(dev);
685 pm_runtime_irq_safe(&pdev->dev); 736 pm_runtime_irq_safe(dev);
686 } 737 }
687 738
688 if (!timer->reserved) { 739 if (!timer->reserved) {
689 pm_runtime_get_sync(&pdev->dev); 740 pm_runtime_get_sync(dev);
690 __omap_dm_timer_init_regs(timer); 741 __omap_dm_timer_init_regs(timer);
691 pm_runtime_put(&pdev->dev); 742 pm_runtime_put(dev);
692 } 743 }
693 744
694 /* add the timer element to the list */ 745 /* add the timer element to the list */
@@ -696,17 +747,9 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
696 list_add_tail(&timer->node, &omap_timer_list); 747 list_add_tail(&timer->node, &omap_timer_list);
697 spin_unlock_irqrestore(&dm_timer_lock, flags); 748 spin_unlock_irqrestore(&dm_timer_lock, flags);
698 749
699 dev_dbg(&pdev->dev, "Device Probed.\n"); 750 dev_dbg(dev, "Device Probed.\n");
700 751
701 return 0; 752 return 0;
702
703err_free_mem:
704 kfree(timer);
705
706err_free_ioregion:
707 release_mem_region(mem->start, resource_size(mem));
708
709 return ret;
710} 753}
711 754
712/** 755/**
@@ -727,7 +770,6 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
727 list_for_each_entry(timer, &omap_timer_list, node) 770 list_for_each_entry(timer, &omap_timer_list, node)
728 if (timer->pdev->id == pdev->id) { 771 if (timer->pdev->id == pdev->id) {
729 list_del(&timer->node); 772 list_del(&timer->node);
730 kfree(timer);
731 ret = 0; 773 ret = 0;
732 break; 774 break;
733 } 775 }