diff options
author | Tony Lindgren <tony@atomide.com> | 2017-06-12 03:07:44 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2017-06-12 03:07:44 -0400 |
commit | 018b732458ac39c4858d9840c0e32310bc0930dd (patch) | |
tree | 84f178b1fe40e67eeb8dc523686f73a02dc5cb00 /arch/arm/mach-omap2/timer.c | |
parent | c76e4d2e50068ddd82fe18f86d05a33733877059 (diff) | |
parent | 0e78b1218df37f1a1834dff853d967444e332bab (diff) |
Merge branch 'omap-for-v4.13/legacy-v2' into omap-for-v4.13/soc-v3
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 169 |
1 files changed, 19 insertions, 150 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 70670dfd7135..ce982d193046 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -252,37 +252,27 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
252 | const char **timer_name, | 252 | const char **timer_name, |
253 | int posted) | 253 | int posted) |
254 | { | 254 | { |
255 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ | ||
256 | const char *oh_name = NULL; | 255 | const char *oh_name = NULL; |
257 | struct device_node *np; | 256 | struct device_node *np; |
258 | struct omap_hwmod *oh; | 257 | struct omap_hwmod *oh; |
259 | struct resource irq, mem; | ||
260 | struct clk *src; | 258 | struct clk *src; |
261 | int r = 0; | 259 | int r = 0; |
262 | 260 | ||
263 | if (of_have_populated_dt()) { | 261 | np = omap_get_timer_dt(omap_timer_match, property); |
264 | np = omap_get_timer_dt(omap_timer_match, property); | 262 | if (!np) |
265 | if (!np) | 263 | return -ENODEV; |
266 | return -ENODEV; | ||
267 | 264 | ||
268 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | 265 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); |
269 | if (!oh_name) | 266 | if (!oh_name) |
270 | return -ENODEV; | 267 | return -ENODEV; |
271 | 268 | ||
272 | timer->irq = irq_of_parse_and_map(np, 0); | 269 | timer->irq = irq_of_parse_and_map(np, 0); |
273 | if (!timer->irq) | 270 | if (!timer->irq) |
274 | return -ENXIO; | 271 | return -ENXIO; |
275 | 272 | ||
276 | timer->io_base = of_iomap(np, 0); | 273 | timer->io_base = of_iomap(np, 0); |
277 | 274 | ||
278 | of_node_put(np); | 275 | of_node_put(np); |
279 | } else { | ||
280 | if (omap_dm_timer_reserve_systimer(timer->id)) | ||
281 | return -ENODEV; | ||
282 | |||
283 | sprintf(name, "timer%d", timer->id); | ||
284 | oh_name = name; | ||
285 | } | ||
286 | 276 | ||
287 | oh = omap_hwmod_lookup(oh_name); | 277 | oh = omap_hwmod_lookup(oh_name); |
288 | if (!oh) | 278 | if (!oh) |
@@ -290,22 +280,6 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
290 | 280 | ||
291 | *timer_name = oh->name; | 281 | *timer_name = oh->name; |
292 | 282 | ||
293 | if (!of_have_populated_dt()) { | ||
294 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, | ||
295 | &irq); | ||
296 | if (r) | ||
297 | return -ENXIO; | ||
298 | timer->irq = irq.start; | ||
299 | |||
300 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, | ||
301 | &mem); | ||
302 | if (r) | ||
303 | return -ENXIO; | ||
304 | |||
305 | /* Static mapping, never released */ | ||
306 | timer->io_base = ioremap(mem.start, mem.end - mem.start); | ||
307 | } | ||
308 | |||
309 | if (!timer->io_base) | 283 | if (!timer->io_base) |
310 | return -ENXIO; | 284 | return -ENXIO; |
311 | 285 | ||
@@ -433,18 +407,15 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void) | |||
433 | const char *oh_name = "counter_32k"; | 407 | const char *oh_name = "counter_32k"; |
434 | 408 | ||
435 | /* | 409 | /* |
436 | * If device-tree is present, then search the DT blob | 410 | * See if the 32kHz counter is supported. |
437 | * to see if the 32kHz counter is supported. | ||
438 | */ | 411 | */ |
439 | if (of_have_populated_dt()) { | 412 | np = omap_get_timer_dt(omap_counter_match, NULL); |
440 | np = omap_get_timer_dt(omap_counter_match, NULL); | 413 | if (!np) |
441 | if (!np) | 414 | return -ENODEV; |
442 | return -ENODEV; | 415 | |
443 | 416 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | |
444 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | 417 | if (!oh_name) |
445 | if (!oh_name) | 418 | return -ENODEV; |
446 | return -ENODEV; | ||
447 | } | ||
448 | 419 | ||
449 | /* | 420 | /* |
450 | * First check hwmod data is available for sync32k counter | 421 | * First check hwmod data is available for sync32k counter |
@@ -462,18 +433,6 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void) | |||
462 | return ret; | 433 | return ret; |
463 | } | 434 | } |
464 | 435 | ||
465 | if (!of_have_populated_dt()) { | ||
466 | void __iomem *vbase; | ||
467 | |||
468 | vbase = omap_hwmod_get_mpu_rt_va(oh); | ||
469 | |||
470 | ret = omap_init_clocksource_32k(vbase); | ||
471 | if (ret) { | ||
472 | pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n", | ||
473 | __func__, ret); | ||
474 | omap_hwmod_idle(oh); | ||
475 | } | ||
476 | } | ||
477 | return ret; | 436 | return ret; |
478 | } | 437 | } |
479 | 438 | ||
@@ -689,96 +648,6 @@ void __init omap5_realtime_timer_init(void) | |||
689 | #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ | 648 | #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ |
690 | 649 | ||
691 | /** | 650 | /** |
692 | * omap_timer_init - build and register timer device with an | ||
693 | * associated timer hwmod | ||
694 | * @oh: timer hwmod pointer to be used to build timer device | ||
695 | * @user: parameter that can be passed from calling hwmod API | ||
696 | * | ||
697 | * Called by omap_hwmod_for_each_by_class to register each of the timer | ||
698 | * devices present in the system. The number of timer devices is known | ||
699 | * by parsing through the hwmod database for a given class name. At the | ||
700 | * end of function call memory is allocated for timer device and it is | ||
701 | * registered to the framework ready to be proved by the driver. | ||
702 | */ | ||
703 | static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) | ||
704 | { | ||
705 | int id; | ||
706 | int ret = 0; | ||
707 | char *name = "omap_timer"; | ||
708 | struct dmtimer_platform_data *pdata; | ||
709 | struct platform_device *pdev; | ||
710 | struct omap_timer_capability_dev_attr *timer_dev_attr; | ||
711 | |||
712 | pr_debug("%s: %s\n", __func__, oh->name); | ||
713 | |||
714 | /* on secure device, do not register secure timer */ | ||
715 | timer_dev_attr = oh->dev_attr; | ||
716 | if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr) | ||
717 | if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE) | ||
718 | return ret; | ||
719 | |||
720 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
721 | if (!pdata) { | ||
722 | pr_err("%s: No memory for [%s]\n", __func__, oh->name); | ||
723 | return -ENOMEM; | ||
724 | } | ||
725 | |||
726 | /* | ||
727 | * Extract the IDs from name field in hwmod database | ||
728 | * and use the same for constructing ids' for the | ||
729 | * timer devices. In a way, we are avoiding usage of | ||
730 | * static variable witin the function to do the same. | ||
731 | * CAUTION: We have to be careful and make sure the | ||
732 | * name in hwmod database does not change in which case | ||
733 | * we might either make corresponding change here or | ||
734 | * switch back static variable mechanism. | ||
735 | */ | ||
736 | sscanf(oh->name, "timer%2d", &id); | ||
737 | |||
738 | if (timer_dev_attr) | ||
739 | pdata->timer_capability = timer_dev_attr->timer_capability; | ||
740 | |||
741 | pdata->timer_errata = omap_dm_timer_get_errata(); | ||
742 | pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; | ||
743 | |||
744 | pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata)); | ||
745 | |||
746 | if (IS_ERR(pdev)) { | ||
747 | pr_err("%s: Can't build omap_device for %s: %s.\n", | ||
748 | __func__, name, oh->name); | ||
749 | ret = -EINVAL; | ||
750 | } | ||
751 | |||
752 | kfree(pdata); | ||
753 | |||
754 | return ret; | ||
755 | } | ||
756 | |||
757 | /** | ||
758 | * omap2_dm_timer_init - top level regular device initialization | ||
759 | * | ||
760 | * Uses dedicated hwmod api to parse through hwmod database for | ||
761 | * given class name and then build and register the timer device. | ||
762 | */ | ||
763 | static int __init omap2_dm_timer_init(void) | ||
764 | { | ||
765 | int ret; | ||
766 | |||
767 | /* If dtb is there, the devices will be created dynamically */ | ||
768 | if (of_have_populated_dt()) | ||
769 | return -ENODEV; | ||
770 | |||
771 | ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); | ||
772 | if (unlikely(ret)) { | ||
773 | pr_err("%s: device registration failed.\n", __func__); | ||
774 | return -EINVAL; | ||
775 | } | ||
776 | |||
777 | return 0; | ||
778 | } | ||
779 | omap_arch_initcall(omap2_dm_timer_init); | ||
780 | |||
781 | /** | ||
782 | * omap2_override_clocksource - clocksource override with user configuration | 651 | * omap2_override_clocksource - clocksource override with user configuration |
783 | * | 652 | * |
784 | * Allows user to override default clocksource, using kernel parameter | 653 | * Allows user to override default clocksource, using kernel parameter |