diff options
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 113 |
1 files changed, 98 insertions, 15 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 938b50a33439..9dca23e4d6b0 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c | |||
@@ -40,11 +40,10 @@ | |||
40 | #include <linux/device.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 | #include <linux/of.h> | ||
44 | #include <linux/of_device.h> | ||
43 | 45 | ||
44 | #include <plat/dmtimer.h> | 46 | #include <plat/dmtimer.h> |
45 | #include <plat/omap-pm.h> | ||
46 | |||
47 | #include <mach/hardware.h> | ||
48 | 47 | ||
49 | static u32 omap_reserved_systimers; | 48 | static u32 omap_reserved_systimers; |
50 | static LIST_HEAD(omap_timer_list); | 49 | static LIST_HEAD(omap_timer_list); |
@@ -212,6 +211,13 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id) | |||
212 | unsigned long flags; | 211 | unsigned long flags; |
213 | int ret = 0; | 212 | int ret = 0; |
214 | 213 | ||
214 | /* Requesting timer by ID is not supported when device tree is used */ | ||
215 | if (of_have_populated_dt()) { | ||
216 | pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n", | ||
217 | __func__); | ||
218 | return NULL; | ||
219 | } | ||
220 | |||
215 | spin_lock_irqsave(&dm_timer_lock, flags); | 221 | spin_lock_irqsave(&dm_timer_lock, flags); |
216 | list_for_each_entry(t, &omap_timer_list, node) { | 222 | list_for_each_entry(t, &omap_timer_list, node) { |
217 | if (t->pdev->id == id && !t->reserved) { | 223 | if (t->pdev->id == id && !t->reserved) { |
@@ -237,6 +243,58 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id) | |||
237 | } | 243 | } |
238 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); | 244 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); |
239 | 245 | ||
246 | /** | ||
247 | * omap_dm_timer_request_by_cap - Request a timer by capability | ||
248 | * @cap: Bit mask of capabilities to match | ||
249 | * | ||
250 | * Find a timer based upon capabilities bit mask. Callers of this function | ||
251 | * should use the definitions found in the plat/dmtimer.h file under the | ||
252 | * comment "timer capabilities used in hwmod database". Returns pointer to | ||
253 | * timer handle on success and a NULL pointer on failure. | ||
254 | */ | ||
255 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap) | ||
256 | { | ||
257 | struct omap_dm_timer *timer = NULL, *t; | ||
258 | unsigned long flags; | ||
259 | |||
260 | if (!cap) | ||
261 | return NULL; | ||
262 | |||
263 | spin_lock_irqsave(&dm_timer_lock, flags); | ||
264 | list_for_each_entry(t, &omap_timer_list, node) { | ||
265 | if ((!t->reserved) && ((t->capability & cap) == cap)) { | ||
266 | /* | ||
267 | * If timer is not NULL, we have already found one timer | ||
268 | * but it was not an exact match because it had more | ||
269 | * capabilites that what was required. Therefore, | ||
270 | * unreserve the last timer found and see if this one | ||
271 | * is a better match. | ||
272 | */ | ||
273 | if (timer) | ||
274 | timer->reserved = 0; | ||
275 | |||
276 | timer = t; | ||
277 | timer->reserved = 1; | ||
278 | |||
279 | /* Exit loop early if we find an exact match */ | ||
280 | if (t->capability == cap) | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
285 | |||
286 | if (timer && omap_dm_timer_prepare(timer)) { | ||
287 | timer->reserved = 0; | ||
288 | timer = NULL; | ||
289 | } | ||
290 | |||
291 | if (!timer) | ||
292 | pr_debug("%s: timer request failed!\n", __func__); | ||
293 | |||
294 | return timer; | ||
295 | } | ||
296 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap); | ||
297 | |||
240 | int omap_dm_timer_free(struct omap_dm_timer *timer) | 298 | int omap_dm_timer_free(struct omap_dm_timer *timer) |
241 | { | 299 | { |
242 | if (unlikely(!timer)) | 300 | if (unlikely(!timer)) |
@@ -271,7 +329,7 @@ int omap_dm_timer_get_irq(struct omap_dm_timer *timer) | |||
271 | EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq); | 329 | EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq); |
272 | 330 | ||
273 | #if defined(CONFIG_ARCH_OMAP1) | 331 | #if defined(CONFIG_ARCH_OMAP1) |
274 | 332 | #include <mach/hardware.h> | |
275 | /** | 333 | /** |
276 | * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR | 334 | * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR |
277 | * @inputmask: current value of idlect mask | 335 | * @inputmask: current value of idlect mask |
@@ -348,7 +406,8 @@ int omap_dm_timer_start(struct omap_dm_timer *timer) | |||
348 | omap_dm_timer_enable(timer); | 406 | omap_dm_timer_enable(timer); |
349 | 407 | ||
350 | if (!(timer->capability & OMAP_TIMER_ALWON)) { | 408 | if (!(timer->capability & OMAP_TIMER_ALWON)) { |
351 | if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) != | 409 | if (timer->get_context_loss_count && |
410 | timer->get_context_loss_count(&timer->pdev->dev) != | ||
352 | timer->ctx_loss_count) | 411 | timer->ctx_loss_count) |
353 | omap_timer_restore_context(timer); | 412 | omap_timer_restore_context(timer); |
354 | } | 413 | } |
@@ -377,9 +436,11 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer) | |||
377 | 436 | ||
378 | __omap_dm_timer_stop(timer, timer->posted, rate); | 437 | __omap_dm_timer_stop(timer, timer->posted, rate); |
379 | 438 | ||
380 | if (!(timer->capability & OMAP_TIMER_ALWON)) | 439 | if (!(timer->capability & OMAP_TIMER_ALWON)) { |
381 | timer->ctx_loss_count = | 440 | if (timer->get_context_loss_count) |
382 | omap_pm_get_dev_context_loss_count(&timer->pdev->dev); | 441 | timer->ctx_loss_count = |
442 | timer->get_context_loss_count(&timer->pdev->dev); | ||
443 | } | ||
383 | 444 | ||
384 | /* | 445 | /* |
385 | * Since the register values are computed and written within | 446 | * Since the register values are computed and written within |
@@ -414,7 +475,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) | |||
414 | * use the clock framework to set the parent clock. To be removed | 475 | * use the clock framework to set the parent clock. To be removed |
415 | * once OMAP1 migrated to using clock framework for dmtimers | 476 | * once OMAP1 migrated to using clock framework for dmtimers |
416 | */ | 477 | */ |
417 | if (pdata->set_timer_src) | 478 | if (pdata && pdata->set_timer_src) |
418 | return pdata->set_timer_src(timer->pdev, source); | 479 | return pdata->set_timer_src(timer->pdev, source); |
419 | 480 | ||
420 | fclk = clk_get(&timer->pdev->dev, "fck"); | 481 | fclk = clk_get(&timer->pdev->dev, "fck"); |
@@ -495,7 +556,8 @@ int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, | |||
495 | omap_dm_timer_enable(timer); | 556 | omap_dm_timer_enable(timer); |
496 | 557 | ||
497 | if (!(timer->capability & OMAP_TIMER_ALWON)) { | 558 | if (!(timer->capability & OMAP_TIMER_ALWON)) { |
498 | if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) != | 559 | if (timer->get_context_loss_count && |
560 | timer->get_context_loss_count(&timer->pdev->dev) != | ||
499 | timer->ctx_loss_count) | 561 | timer->ctx_loss_count) |
500 | omap_timer_restore_context(timer); | 562 | omap_timer_restore_context(timer); |
501 | } | 563 | } |
@@ -695,7 +757,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev) | |||
695 | struct device *dev = &pdev->dev; | 757 | struct device *dev = &pdev->dev; |
696 | struct dmtimer_platform_data *pdata = pdev->dev.platform_data; | 758 | struct dmtimer_platform_data *pdata = pdev->dev.platform_data; |
697 | 759 | ||
698 | if (!pdata) { | 760 | if (!pdata && !dev->of_node) { |
699 | dev_err(dev, "%s: no platform data.\n", __func__); | 761 | dev_err(dev, "%s: no platform data.\n", __func__); |
700 | return -ENODEV; | 762 | return -ENODEV; |
701 | } | 763 | } |
@@ -724,11 +786,24 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev) | |||
724 | return -ENOMEM; | 786 | return -ENOMEM; |
725 | } | 787 | } |
726 | 788 | ||
727 | timer->id = pdev->id; | 789 | if (dev->of_node) { |
790 | if (of_find_property(dev->of_node, "ti,timer-alwon", NULL)) | ||
791 | timer->capability |= OMAP_TIMER_ALWON; | ||
792 | if (of_find_property(dev->of_node, "ti,timer-dsp", NULL)) | ||
793 | timer->capability |= OMAP_TIMER_HAS_DSP_IRQ; | ||
794 | if (of_find_property(dev->of_node, "ti,timer-pwm", NULL)) | ||
795 | timer->capability |= OMAP_TIMER_HAS_PWM; | ||
796 | if (of_find_property(dev->of_node, "ti,timer-secure", NULL)) | ||
797 | timer->capability |= OMAP_TIMER_SECURE; | ||
798 | } else { | ||
799 | timer->id = pdev->id; | ||
800 | timer->capability = pdata->timer_capability; | ||
801 | timer->reserved = omap_dm_timer_reserved_systimer(timer->id); | ||
802 | timer->get_context_loss_count = pdata->get_context_loss_count; | ||
803 | } | ||
804 | |||
728 | timer->irq = irq->start; | 805 | timer->irq = irq->start; |
729 | timer->reserved = omap_dm_timer_reserved_systimer(timer->id); | ||
730 | timer->pdev = pdev; | 806 | timer->pdev = pdev; |
731 | timer->capability = pdata->timer_capability; | ||
732 | 807 | ||
733 | /* Skip pm_runtime_enable for OMAP1 */ | 808 | /* Skip pm_runtime_enable for OMAP1 */ |
734 | if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { | 809 | if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { |
@@ -768,7 +843,8 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev) | |||
768 | 843 | ||
769 | spin_lock_irqsave(&dm_timer_lock, flags); | 844 | spin_lock_irqsave(&dm_timer_lock, flags); |
770 | list_for_each_entry(timer, &omap_timer_list, node) | 845 | list_for_each_entry(timer, &omap_timer_list, node) |
771 | if (timer->pdev->id == pdev->id) { | 846 | if (!strcmp(dev_name(&timer->pdev->dev), |
847 | dev_name(&pdev->dev))) { | ||
772 | list_del(&timer->node); | 848 | list_del(&timer->node); |
773 | ret = 0; | 849 | ret = 0; |
774 | break; | 850 | break; |
@@ -778,11 +854,18 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev) | |||
778 | return ret; | 854 | return ret; |
779 | } | 855 | } |
780 | 856 | ||
857 | static const struct of_device_id omap_timer_match[] = { | ||
858 | { .compatible = "ti,omap2-timer", }, | ||
859 | {}, | ||
860 | }; | ||
861 | MODULE_DEVICE_TABLE(of, omap_timer_match); | ||
862 | |||
781 | static struct platform_driver omap_dm_timer_driver = { | 863 | static struct platform_driver omap_dm_timer_driver = { |
782 | .probe = omap_dm_timer_probe, | 864 | .probe = omap_dm_timer_probe, |
783 | .remove = __devexit_p(omap_dm_timer_remove), | 865 | .remove = __devexit_p(omap_dm_timer_remove), |
784 | .driver = { | 866 | .driver = { |
785 | .name = "omap_timer", | 867 | .name = "omap_timer", |
868 | .of_match_table = of_match_ptr(omap_timer_match), | ||
786 | }, | 869 | }, |
787 | }; | 870 | }; |
788 | 871 | ||