aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r--arch/arm/mach-omap2/timer.c200
1 files changed, 50 insertions, 150 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 07dd692c4737..6a861c0ac343 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -68,6 +68,9 @@
68static struct omap_dm_timer clkev; 68static struct omap_dm_timer clkev;
69static struct clock_event_device clockevent_gpt; 69static struct clock_event_device clockevent_gpt;
70 70
71/* Clockevent hwmod for am335x and am437x suspend */
72static struct omap_hwmod *clockevent_gpt_hwmod;
73
71#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER 74#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
72static unsigned long arch_timer_freq; 75static unsigned long arch_timer_freq;
73 76
@@ -125,6 +128,23 @@ static int omap2_gp_timer_set_periodic(struct clock_event_device *evt)
125 return 0; 128 return 0;
126} 129}
127 130
131static void omap_clkevt_idle(struct clock_event_device *unused)
132{
133 if (!clockevent_gpt_hwmod)
134 return;
135
136 omap_hwmod_idle(clockevent_gpt_hwmod);
137}
138
139static void omap_clkevt_unidle(struct clock_event_device *unused)
140{
141 if (!clockevent_gpt_hwmod)
142 return;
143
144 omap_hwmod_enable(clockevent_gpt_hwmod);
145 __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
146}
147
128static struct clock_event_device clockevent_gpt = { 148static struct clock_event_device clockevent_gpt = {
129 .features = CLOCK_EVT_FEAT_PERIODIC | 149 .features = CLOCK_EVT_FEAT_PERIODIC |
130 CLOCK_EVT_FEAT_ONESHOT, 150 CLOCK_EVT_FEAT_ONESHOT,
@@ -232,37 +252,29 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
232 const char **timer_name, 252 const char **timer_name,
233 int posted) 253 int posted)
234{ 254{
235 char name[10]; /* 10 = sizeof("gptXX_Xck0") */
236 const char *oh_name = NULL; 255 const char *oh_name = NULL;
237 struct device_node *np; 256 struct device_node *np;
238 struct omap_hwmod *oh; 257 struct omap_hwmod *oh;
239 struct resource irq, mem;
240 struct clk *src; 258 struct clk *src;
241 int r = 0; 259 int r = 0;
242 260
243 if (of_have_populated_dt()) { 261 np = omap_get_timer_dt(omap_timer_match, property);
244 np = omap_get_timer_dt(omap_timer_match, property); 262 if (!np)
245 if (!np) 263 return -ENODEV;
246 return -ENODEV;
247 264
248 of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); 265 of_property_read_string_index(np, "ti,hwmods", 0, &oh_name);
249 if (!oh_name) 266 if (!oh_name)
250 return -ENODEV; 267 return -ENODEV;
251 268
252 timer->irq = irq_of_parse_and_map(np, 0); 269 timer->irq = irq_of_parse_and_map(np, 0);
253 if (!timer->irq) 270 if (!timer->irq)
254 return -ENXIO; 271 return -ENXIO;
255 272
256 timer->io_base = of_iomap(np, 0); 273 timer->io_base = of_iomap(np, 0);
257 274
258 of_node_put(np); 275 timer->fclk = of_clk_get_by_name(np, "fck");
259 } else {
260 if (omap_dm_timer_reserve_systimer(timer->id))
261 return -ENODEV;
262 276
263 sprintf(name, "timer%d", timer->id); 277 of_node_put(np);
264 oh_name = name;
265 }
266 278
267 oh = omap_hwmod_lookup(oh_name); 279 oh = omap_hwmod_lookup(oh_name);
268 if (!oh) 280 if (!oh)
@@ -270,29 +282,14 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
270 282
271 *timer_name = oh->name; 283 *timer_name = oh->name;
272 284
273 if (!of_have_populated_dt()) {
274 r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL,
275 &irq);
276 if (r)
277 return -ENXIO;
278 timer->irq = irq.start;
279
280 r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL,
281 &mem);
282 if (r)
283 return -ENXIO;
284
285 /* Static mapping, never released */
286 timer->io_base = ioremap(mem.start, mem.end - mem.start);
287 }
288
289 if (!timer->io_base) 285 if (!timer->io_base)
290 return -ENXIO; 286 return -ENXIO;
291 287
292 omap_hwmod_setup_one(oh_name); 288 omap_hwmod_setup_one(oh_name);
293 289
294 /* After the dmtimer is using hwmod these clocks won't be needed */ 290 /* After the dmtimer is using hwmod these clocks won't be needed */
295 timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); 291 if (IS_ERR_OR_NULL(timer->fclk))
292 timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh));
296 if (IS_ERR(timer->fclk)) 293 if (IS_ERR(timer->fclk))
297 return PTR_ERR(timer->fclk); 294 return PTR_ERR(timer->fclk);
298 295
@@ -358,6 +355,14 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
358 3, /* Timer internal resynch latency */ 355 3, /* Timer internal resynch latency */
359 0xffffffff); 356 0xffffffff);
360 357
358 if (soc_is_am33xx() || soc_is_am43xx()) {
359 clockevent_gpt.suspend = omap_clkevt_idle;
360 clockevent_gpt.resume = omap_clkevt_unidle;
361
362 clockevent_gpt_hwmod =
363 omap_hwmod_lookup(clockevent_gpt.name);
364 }
365
361 pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name, 366 pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name,
362 clkev.rate); 367 clkev.rate);
363} 368}
@@ -405,18 +410,15 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
405 const char *oh_name = "counter_32k"; 410 const char *oh_name = "counter_32k";
406 411
407 /* 412 /*
408 * If device-tree is present, then search the DT blob 413 * See if the 32kHz counter is supported.
409 * to see if the 32kHz counter is supported.
410 */ 414 */
411 if (of_have_populated_dt()) { 415 np = omap_get_timer_dt(omap_counter_match, NULL);
412 np = omap_get_timer_dt(omap_counter_match, NULL); 416 if (!np)
413 if (!np) 417 return -ENODEV;
414 return -ENODEV; 418
415 419 of_property_read_string_index(np, "ti,hwmods", 0, &oh_name);
416 of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); 420 if (!oh_name)
417 if (!oh_name) 421 return -ENODEV;
418 return -ENODEV;
419 }
420 422
421 /* 423 /*
422 * First check hwmod data is available for sync32k counter 424 * First check hwmod data is available for sync32k counter
@@ -434,18 +436,6 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
434 return ret; 436 return ret;
435 } 437 }
436 438
437 if (!of_have_populated_dt()) {
438 void __iomem *vbase;
439
440 vbase = omap_hwmod_get_mpu_rt_va(oh);
441
442 ret = omap_init_clocksource_32k(vbase);
443 if (ret) {
444 pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n",
445 __func__, ret);
446 omap_hwmod_idle(oh);
447 }
448 }
449 return ret; 439 return ret;
450} 440}
451 441
@@ -661,96 +651,6 @@ void __init omap5_realtime_timer_init(void)
661#endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ 651#endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */
662 652
663/** 653/**
664 * omap_timer_init - build and register timer device with an
665 * associated timer hwmod
666 * @oh: timer hwmod pointer to be used to build timer device
667 * @user: parameter that can be passed from calling hwmod API
668 *
669 * Called by omap_hwmod_for_each_by_class to register each of the timer
670 * devices present in the system. The number of timer devices is known
671 * by parsing through the hwmod database for a given class name. At the
672 * end of function call memory is allocated for timer device and it is
673 * registered to the framework ready to be proved by the driver.
674 */
675static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
676{
677 int id;
678 int ret = 0;
679 char *name = "omap_timer";
680 struct dmtimer_platform_data *pdata;
681 struct platform_device *pdev;
682 struct omap_timer_capability_dev_attr *timer_dev_attr;
683
684 pr_debug("%s: %s\n", __func__, oh->name);
685
686 /* on secure device, do not register secure timer */
687 timer_dev_attr = oh->dev_attr;
688 if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr)
689 if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE)
690 return ret;
691
692 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
693 if (!pdata) {
694 pr_err("%s: No memory for [%s]\n", __func__, oh->name);
695 return -ENOMEM;
696 }
697
698 /*
699 * Extract the IDs from name field in hwmod database
700 * and use the same for constructing ids' for the
701 * timer devices. In a way, we are avoiding usage of
702 * static variable witin the function to do the same.
703 * CAUTION: We have to be careful and make sure the
704 * name in hwmod database does not change in which case
705 * we might either make corresponding change here or
706 * switch back static variable mechanism.
707 */
708 sscanf(oh->name, "timer%2d", &id);
709
710 if (timer_dev_attr)
711 pdata->timer_capability = timer_dev_attr->timer_capability;
712
713 pdata->timer_errata = omap_dm_timer_get_errata();
714 pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
715
716 pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata));
717
718 if (IS_ERR(pdev)) {
719 pr_err("%s: Can't build omap_device for %s: %s.\n",
720 __func__, name, oh->name);
721 ret = -EINVAL;
722 }
723
724 kfree(pdata);
725
726 return ret;
727}
728
729/**
730 * omap2_dm_timer_init - top level regular device initialization
731 *
732 * Uses dedicated hwmod api to parse through hwmod database for
733 * given class name and then build and register the timer device.
734 */
735static int __init omap2_dm_timer_init(void)
736{
737 int ret;
738
739 /* If dtb is there, the devices will be created dynamically */
740 if (of_have_populated_dt())
741 return -ENODEV;
742
743 ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
744 if (unlikely(ret)) {
745 pr_err("%s: device registration failed.\n", __func__);
746 return -EINVAL;
747 }
748
749 return 0;
750}
751omap_arch_initcall(omap2_dm_timer_init);
752
753/**
754 * omap2_override_clocksource - clocksource override with user configuration 654 * omap2_override_clocksource - clocksource override with user configuration
755 * 655 *
756 * Allows user to override default clocksource, using kernel parameter 656 * Allows user to override default clocksource, using kernel parameter