diff options
author | Tony Lindgren <tony@atomide.com> | 2012-11-06 19:09:51 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2012-11-06 19:09:51 -0500 |
commit | 2580390c563d3a4a6bea820588b188fe76303b5d (patch) | |
tree | 18419de768373eeb00fb215f4924d926a67e508f | |
parent | ad3252556f02cba81f644665ff1fd5a8aa3d97d2 (diff) | |
parent | 9883f7c8dd21acb90697582ca331f3f8a66ac054 (diff) |
Merge branch 'dev-dt-timer' of github.com:jonhunter/linux into omap-for-v3.8/dt
-rw-r--r-- | arch/arm/mach-omap2/board-generic.c | 17 | ||||
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 203 | ||||
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 93 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 1 |
4 files changed, 275 insertions, 39 deletions
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 601ecdfb1cf9..d69018028d96 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c | |||
@@ -97,6 +97,23 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)") | |||
97 | .dt_compat = omap3_boards_compat, | 97 | .dt_compat = omap3_boards_compat, |
98 | .restart = omap_prcm_restart, | 98 | .restart = omap_prcm_restart, |
99 | MACHINE_END | 99 | MACHINE_END |
100 | |||
101 | static const char *omap3_gp_boards_compat[] __initdata = { | ||
102 | "ti,omap3-beagle", | ||
103 | NULL, | ||
104 | }; | ||
105 | |||
106 | DT_MACHINE_START(OMAP3_GP_DT, "Generic OMAP3-GP (Flattened Device Tree)") | ||
107 | .reserve = omap_reserve, | ||
108 | .map_io = omap3_map_io, | ||
109 | .init_early = omap3430_init_early, | ||
110 | .init_irq = omap_intc_of_init, | ||
111 | .handle_irq = omap3_intc_handle_irq, | ||
112 | .init_machine = omap_generic_init, | ||
113 | .timer = &omap3_secure_timer, | ||
114 | .dt_compat = omap3_gp_boards_compat, | ||
115 | .restart = omap_prcm_restart, | ||
116 | MACHINE_END | ||
100 | #endif | 117 | #endif |
101 | 118 | ||
102 | #ifdef CONFIG_SOC_AM33XX | 119 | #ifdef CONFIG_SOC_AM33XX |
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 69e46631a7cd..0758bae3a57a 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/clockchips.h> | 37 | #include <linux/clockchips.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/of.h> | 39 | #include <linux/of.h> |
40 | #include <linux/of_address.h> | ||
41 | #include <linux/of_irq.h> | ||
40 | 42 | ||
41 | #include <asm/mach/time.h> | 43 | #include <asm/mach/time.h> |
42 | #include <asm/smp_twd.h> | 44 | #include <asm/smp_twd.h> |
@@ -66,11 +68,13 @@ | |||
66 | #define OMAP3_CLKEV_SOURCE OMAP3_32K_SOURCE | 68 | #define OMAP3_CLKEV_SOURCE OMAP3_32K_SOURCE |
67 | #define OMAP4_CLKEV_SOURCE OMAP4_32K_SOURCE | 69 | #define OMAP4_CLKEV_SOURCE OMAP4_32K_SOURCE |
68 | #define OMAP3_SECURE_TIMER 12 | 70 | #define OMAP3_SECURE_TIMER 12 |
71 | #define TIMER_PROP_SECURE "ti,timer-secure" | ||
69 | #else | 72 | #else |
70 | #define OMAP2_CLKEV_SOURCE OMAP2_MPU_SOURCE | 73 | #define OMAP2_CLKEV_SOURCE OMAP2_MPU_SOURCE |
71 | #define OMAP3_CLKEV_SOURCE OMAP3_MPU_SOURCE | 74 | #define OMAP3_CLKEV_SOURCE OMAP3_MPU_SOURCE |
72 | #define OMAP4_CLKEV_SOURCE OMAP4_MPU_SOURCE | 75 | #define OMAP4_CLKEV_SOURCE OMAP4_MPU_SOURCE |
73 | #define OMAP3_SECURE_TIMER 1 | 76 | #define OMAP3_SECURE_TIMER 1 |
77 | #define TIMER_PROP_SECURE "ti,timer-alwon" | ||
74 | #endif | 78 | #endif |
75 | 79 | ||
76 | #define REALTIME_COUNTER_BASE 0x48243200 | 80 | #define REALTIME_COUNTER_BASE 0x48243200 |
@@ -144,36 +148,141 @@ static struct clock_event_device clockevent_gpt = { | |||
144 | .set_mode = omap2_gp_timer_set_mode, | 148 | .set_mode = omap2_gp_timer_set_mode, |
145 | }; | 149 | }; |
146 | 150 | ||
151 | static struct property device_disabled = { | ||
152 | .name = "status", | ||
153 | .length = sizeof("disabled"), | ||
154 | .value = "disabled", | ||
155 | }; | ||
156 | |||
157 | static struct of_device_id omap_timer_match[] __initdata = { | ||
158 | { .compatible = "ti,omap2-timer", }, | ||
159 | { } | ||
160 | }; | ||
161 | |||
162 | static struct of_device_id omap_counter_match[] __initdata = { | ||
163 | { .compatible = "ti,omap-counter32k", }, | ||
164 | { } | ||
165 | }; | ||
166 | |||
167 | /** | ||
168 | * omap_get_timer_dt - get a timer using device-tree | ||
169 | * @match - device-tree match structure for matching a device type | ||
170 | * @property - optional timer property to match | ||
171 | * | ||
172 | * Helper function to get a timer during early boot using device-tree for use | ||
173 | * as kernel system timer. Optionally, the property argument can be used to | ||
174 | * select a timer with a specific property. Once a timer is found then mark | ||
175 | * the timer node in device-tree as disabled, to prevent the kernel from | ||
176 | * registering this timer as a platform device and so no one else can use it. | ||
177 | */ | ||
178 | static struct device_node * __init omap_get_timer_dt(struct of_device_id *match, | ||
179 | const char *property) | ||
180 | { | ||
181 | struct device_node *np; | ||
182 | |||
183 | for_each_matching_node(np, match) { | ||
184 | if (!of_device_is_available(np)) { | ||
185 | of_node_put(np); | ||
186 | continue; | ||
187 | } | ||
188 | |||
189 | if (property && !of_get_property(np, property, NULL)) { | ||
190 | of_node_put(np); | ||
191 | continue; | ||
192 | } | ||
193 | |||
194 | prom_add_property(np, &device_disabled); | ||
195 | return np; | ||
196 | } | ||
197 | |||
198 | return NULL; | ||
199 | } | ||
200 | |||
201 | /** | ||
202 | * omap_dmtimer_init - initialisation function when device tree is used | ||
203 | * | ||
204 | * For secure OMAP3 devices, timers with device type "timer-secure" cannot | ||
205 | * be used by the kernel as they are reserved. Therefore, to prevent the | ||
206 | * kernel registering these devices remove them dynamically from the device | ||
207 | * tree on boot. | ||
208 | */ | ||
209 | void __init omap_dmtimer_init(void) | ||
210 | { | ||
211 | struct device_node *np; | ||
212 | |||
213 | if (!cpu_is_omap34xx()) | ||
214 | return; | ||
215 | |||
216 | /* If we are a secure device, remove any secure timer nodes */ | ||
217 | if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) { | ||
218 | np = omap_get_timer_dt(omap_timer_match, "ti,timer-secure"); | ||
219 | if (np) | ||
220 | of_node_put(np); | ||
221 | } | ||
222 | } | ||
223 | |||
147 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | 224 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, |
148 | int gptimer_id, | 225 | int gptimer_id, |
149 | const char *fck_source) | 226 | const char *fck_source, |
227 | const char *property) | ||
150 | { | 228 | { |
151 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ | 229 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ |
230 | const char *oh_name; | ||
231 | struct device_node *np; | ||
152 | struct omap_hwmod *oh; | 232 | struct omap_hwmod *oh; |
153 | struct resource irq_rsrc, mem_rsrc; | 233 | struct resource irq_rsrc, mem_rsrc; |
154 | size_t size; | 234 | size_t size; |
155 | int res = 0; | 235 | int res = 0; |
156 | int r; | 236 | int r; |
157 | 237 | ||
158 | sprintf(name, "timer%d", gptimer_id); | 238 | if (of_have_populated_dt()) { |
159 | omap_hwmod_setup_one(name); | 239 | np = omap_get_timer_dt(omap_timer_match, NULL); |
160 | oh = omap_hwmod_lookup(name); | 240 | if (!np) |
241 | return -ENODEV; | ||
242 | |||
243 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | ||
244 | if (!oh_name) | ||
245 | return -ENODEV; | ||
246 | |||
247 | timer->irq = irq_of_parse_and_map(np, 0); | ||
248 | if (!timer->irq) | ||
249 | return -ENXIO; | ||
250 | |||
251 | timer->io_base = of_iomap(np, 0); | ||
252 | |||
253 | of_node_put(np); | ||
254 | } else { | ||
255 | if (omap_dm_timer_reserve_systimer(gptimer_id)) | ||
256 | return -ENODEV; | ||
257 | |||
258 | sprintf(name, "timer%d", gptimer_id); | ||
259 | oh_name = name; | ||
260 | } | ||
261 | |||
262 | omap_hwmod_setup_one(oh_name); | ||
263 | oh = omap_hwmod_lookup(oh_name); | ||
264 | |||
161 | if (!oh) | 265 | if (!oh) |
162 | return -ENODEV; | 266 | return -ENODEV; |
163 | 267 | ||
164 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq_rsrc); | 268 | if (!of_have_populated_dt()) { |
165 | if (r) | 269 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, |
166 | return -ENXIO; | 270 | &irq_rsrc); |
167 | timer->irq = irq_rsrc.start; | 271 | if (r) |
168 | 272 | return -ENXIO; | |
169 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, &mem_rsrc); | 273 | timer->irq = irq_rsrc.start; |
170 | if (r) | 274 | |
171 | return -ENXIO; | 275 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, |
172 | timer->phys_base = mem_rsrc.start; | 276 | &mem_rsrc); |
173 | size = mem_rsrc.end - mem_rsrc.start; | 277 | if (r) |
278 | return -ENXIO; | ||
279 | timer->phys_base = mem_rsrc.start; | ||
280 | size = mem_rsrc.end - mem_rsrc.start; | ||
281 | |||
282 | /* Static mapping, never released */ | ||
283 | timer->io_base = ioremap(timer->phys_base, size); | ||
284 | } | ||
174 | 285 | ||
175 | /* Static mapping, never released */ | ||
176 | timer->io_base = ioremap(timer->phys_base, size); | ||
177 | if (!timer->io_base) | 286 | if (!timer->io_base) |
178 | return -ENXIO; | 287 | return -ENXIO; |
179 | 288 | ||
@@ -184,9 +293,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
184 | 293 | ||
185 | omap_hwmod_enable(oh); | 294 | omap_hwmod_enable(oh); |
186 | 295 | ||
187 | if (omap_dm_timer_reserve_systimer(gptimer_id)) | 296 | /* FIXME: Need to remove hard-coded test on timer ID */ |
188 | return -ENODEV; | ||
189 | |||
190 | if (gptimer_id != 12) { | 297 | if (gptimer_id != 12) { |
191 | struct clk *src; | 298 | struct clk *src; |
192 | 299 | ||
@@ -196,8 +303,8 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
196 | } else { | 303 | } else { |
197 | res = __omap_dm_timer_set_source(timer->fclk, src); | 304 | res = __omap_dm_timer_set_source(timer->fclk, src); |
198 | if (IS_ERR_VALUE(res)) | 305 | if (IS_ERR_VALUE(res)) |
199 | pr_warning("%s: timer%i cannot set source\n", | 306 | pr_warn("%s: %s cannot set source\n", |
200 | __func__, gptimer_id); | 307 | __func__, oh->name); |
201 | clk_put(src); | 308 | clk_put(src); |
202 | } | 309 | } |
203 | } | 310 | } |
@@ -213,11 +320,12 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
213 | } | 320 | } |
214 | 321 | ||
215 | static void __init omap2_gp_clockevent_init(int gptimer_id, | 322 | static void __init omap2_gp_clockevent_init(int gptimer_id, |
216 | const char *fck_source) | 323 | const char *fck_source, |
324 | const char *property) | ||
217 | { | 325 | { |
218 | int res; | 326 | int res; |
219 | 327 | ||
220 | res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source); | 328 | res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property); |
221 | BUG_ON(res); | 329 | BUG_ON(res); |
222 | 330 | ||
223 | omap2_gp_timer_irq.dev_id = &clkev; | 331 | omap2_gp_timer_irq.dev_id = &clkev; |
@@ -274,11 +382,26 @@ static u32 notrace dmtimer_read_sched_clock(void) | |||
274 | static int __init omap2_sync32k_clocksource_init(void) | 382 | static int __init omap2_sync32k_clocksource_init(void) |
275 | { | 383 | { |
276 | int ret; | 384 | int ret; |
385 | struct device_node *np = NULL; | ||
277 | struct omap_hwmod *oh; | 386 | struct omap_hwmod *oh; |
278 | void __iomem *vbase; | 387 | void __iomem *vbase; |
279 | const char *oh_name = "counter_32k"; | 388 | const char *oh_name = "counter_32k"; |
280 | 389 | ||
281 | /* | 390 | /* |
391 | * If device-tree is present, then search the DT blob | ||
392 | * to see if the 32kHz counter is supported. | ||
393 | */ | ||
394 | if (of_have_populated_dt()) { | ||
395 | np = omap_get_timer_dt(omap_counter_match, NULL); | ||
396 | if (!np) | ||
397 | return -ENODEV; | ||
398 | |||
399 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | ||
400 | if (!oh_name) | ||
401 | return -ENODEV; | ||
402 | } | ||
403 | |||
404 | /* | ||
282 | * First check hwmod data is available for sync32k counter | 405 | * First check hwmod data is available for sync32k counter |
283 | */ | 406 | */ |
284 | oh = omap_hwmod_lookup(oh_name); | 407 | oh = omap_hwmod_lookup(oh_name); |
@@ -287,7 +410,13 @@ static int __init omap2_sync32k_clocksource_init(void) | |||
287 | 410 | ||
288 | omap_hwmod_setup_one(oh_name); | 411 | omap_hwmod_setup_one(oh_name); |
289 | 412 | ||
290 | vbase = omap_hwmod_get_mpu_rt_va(oh); | 413 | if (np) { |
414 | vbase = of_iomap(np, 0); | ||
415 | of_node_put(np); | ||
416 | } else { | ||
417 | vbase = omap_hwmod_get_mpu_rt_va(oh); | ||
418 | } | ||
419 | |||
291 | if (!vbase) { | 420 | if (!vbase) { |
292 | pr_warn("%s: failed to get counter_32k resource\n", __func__); | 421 | pr_warn("%s: failed to get counter_32k resource\n", __func__); |
293 | return -ENXIO; | 422 | return -ENXIO; |
@@ -321,7 +450,7 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id, | |||
321 | { | 450 | { |
322 | int res; | 451 | int res; |
323 | 452 | ||
324 | res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source); | 453 | res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL); |
325 | BUG_ON(res); | 454 | BUG_ON(res); |
326 | 455 | ||
327 | __omap_dm_timer_load_start(&clksrc, | 456 | __omap_dm_timer_load_start(&clksrc, |
@@ -433,11 +562,12 @@ static inline void __init realtime_counter_init(void) | |||
433 | {} | 562 | {} |
434 | #endif | 563 | #endif |
435 | 564 | ||
436 | #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ | 565 | #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ |
437 | clksrc_nr, clksrc_src) \ | 566 | clksrc_nr, clksrc_src) \ |
438 | static void __init omap##name##_timer_init(void) \ | 567 | static void __init omap##name##_timer_init(void) \ |
439 | { \ | 568 | { \ |
440 | omap2_gp_clockevent_init((clkev_nr), clkev_src); \ | 569 | omap_dmtimer_init(); \ |
570 | omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ | ||
441 | omap2_clocksource_init((clksrc_nr), clksrc_src); \ | 571 | omap2_clocksource_init((clksrc_nr), clksrc_src); \ |
442 | } | 572 | } |
443 | 573 | ||
@@ -447,20 +577,23 @@ struct sys_timer omap##name##_timer = { \ | |||
447 | }; | 577 | }; |
448 | 578 | ||
449 | #ifdef CONFIG_ARCH_OMAP2 | 579 | #ifdef CONFIG_ARCH_OMAP2 |
450 | OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE, 2, OMAP2_MPU_SOURCE) | 580 | OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE, "ti,timer-alwon", |
581 | 2, OMAP2_MPU_SOURCE) | ||
451 | OMAP_SYS_TIMER(2) | 582 | OMAP_SYS_TIMER(2) |
452 | #endif | 583 | #endif |
453 | 584 | ||
454 | #ifdef CONFIG_ARCH_OMAP3 | 585 | #ifdef CONFIG_ARCH_OMAP3 |
455 | OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE, 2, OMAP3_MPU_SOURCE) | 586 | OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE, "ti,timer-alwon", |
587 | 2, OMAP3_MPU_SOURCE) | ||
456 | OMAP_SYS_TIMER(3) | 588 | OMAP_SYS_TIMER(3) |
457 | OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE, | 589 | OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE, |
458 | 2, OMAP3_MPU_SOURCE) | 590 | TIMER_PROP_SECURE, 2, OMAP3_MPU_SOURCE) |
459 | OMAP_SYS_TIMER(3_secure) | 591 | OMAP_SYS_TIMER(3_secure) |
460 | #endif | 592 | #endif |
461 | 593 | ||
462 | #ifdef CONFIG_SOC_AM33XX | 594 | #ifdef CONFIG_SOC_AM33XX |
463 | OMAP_SYS_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, 2, OMAP4_MPU_SOURCE) | 595 | OMAP_SYS_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon", |
596 | 2, OMAP4_MPU_SOURCE) | ||
464 | OMAP_SYS_TIMER(3_am33xx) | 597 | OMAP_SYS_TIMER(3_am33xx) |
465 | #endif | 598 | #endif |
466 | 599 | ||
@@ -472,7 +605,7 @@ static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, | |||
472 | 605 | ||
473 | static void __init omap4_timer_init(void) | 606 | static void __init omap4_timer_init(void) |
474 | { | 607 | { |
475 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); | 608 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE, "ti,timer-alwon"); |
476 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); | 609 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); |
477 | #ifdef CONFIG_LOCAL_TIMERS | 610 | #ifdef CONFIG_LOCAL_TIMERS |
478 | /* Local timers are not supprted on OMAP4430 ES1.0 */ | 611 | /* Local timers are not supprted on OMAP4430 ES1.0 */ |
@@ -498,7 +631,7 @@ static void __init omap5_timer_init(void) | |||
498 | { | 631 | { |
499 | int err; | 632 | int err; |
500 | 633 | ||
501 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); | 634 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE, "ti,timer-alwon"); |
502 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); | 635 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); |
503 | realtime_counter_init(); | 636 | realtime_counter_init(); |
504 | 637 | ||
@@ -583,6 +716,10 @@ static int __init omap2_dm_timer_init(void) | |||
583 | { | 716 | { |
584 | int ret; | 717 | int ret; |
585 | 718 | ||
719 | /* If dtb is there, the devices will be created dynamically */ | ||
720 | if (of_have_populated_dt()) | ||
721 | return -ENODEV; | ||
722 | |||
586 | ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); | 723 | ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); |
587 | if (unlikely(ret)) { | 724 | if (unlikely(ret)) { |
588 | pr_err("%s: device registration failed.\n", __func__); | 725 | pr_err("%s: device registration failed.\n", __func__); |
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 938b50a33439..b09e55632f4b 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c | |||
@@ -40,6 +40,8 @@ | |||
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> | 47 | #include <plat/omap-pm.h> |
@@ -212,6 +214,13 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id) | |||
212 | unsigned long flags; | 214 | unsigned long flags; |
213 | int ret = 0; | 215 | int ret = 0; |
214 | 216 | ||
217 | /* Requesting timer by ID is not supported when device tree is used */ | ||
218 | if (of_have_populated_dt()) { | ||
219 | pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n", | ||
220 | __func__); | ||
221 | return NULL; | ||
222 | } | ||
223 | |||
215 | spin_lock_irqsave(&dm_timer_lock, flags); | 224 | spin_lock_irqsave(&dm_timer_lock, flags); |
216 | list_for_each_entry(t, &omap_timer_list, node) { | 225 | list_for_each_entry(t, &omap_timer_list, node) { |
217 | if (t->pdev->id == id && !t->reserved) { | 226 | if (t->pdev->id == id && !t->reserved) { |
@@ -237,6 +246,58 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id) | |||
237 | } | 246 | } |
238 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); | 247 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); |
239 | 248 | ||
249 | /** | ||
250 | * omap_dm_timer_request_by_cap - Request a timer by capability | ||
251 | * @cap: Bit mask of capabilities to match | ||
252 | * | ||
253 | * Find a timer based upon capabilities bit mask. Callers of this function | ||
254 | * should use the definitions found in the plat/dmtimer.h file under the | ||
255 | * comment "timer capabilities used in hwmod database". Returns pointer to | ||
256 | * timer handle on success and a NULL pointer on failure. | ||
257 | */ | ||
258 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap) | ||
259 | { | ||
260 | struct omap_dm_timer *timer = NULL, *t; | ||
261 | unsigned long flags; | ||
262 | |||
263 | if (!cap) | ||
264 | return NULL; | ||
265 | |||
266 | spin_lock_irqsave(&dm_timer_lock, flags); | ||
267 | list_for_each_entry(t, &omap_timer_list, node) { | ||
268 | if ((!t->reserved) && ((t->capability & cap) == cap)) { | ||
269 | /* | ||
270 | * If timer is not NULL, we have already found one timer | ||
271 | * but it was not an exact match because it had more | ||
272 | * capabilites that what was required. Therefore, | ||
273 | * unreserve the last timer found and see if this one | ||
274 | * is a better match. | ||
275 | */ | ||
276 | if (timer) | ||
277 | timer->reserved = 0; | ||
278 | |||
279 | timer = t; | ||
280 | timer->reserved = 1; | ||
281 | |||
282 | /* Exit loop early if we find an exact match */ | ||
283 | if (t->capability == cap) | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
288 | |||
289 | if (timer && omap_dm_timer_prepare(timer)) { | ||
290 | timer->reserved = 0; | ||
291 | timer = NULL; | ||
292 | } | ||
293 | |||
294 | if (!timer) | ||
295 | pr_debug("%s: timer request failed!\n", __func__); | ||
296 | |||
297 | return timer; | ||
298 | } | ||
299 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap); | ||
300 | |||
240 | int omap_dm_timer_free(struct omap_dm_timer *timer) | 301 | int omap_dm_timer_free(struct omap_dm_timer *timer) |
241 | { | 302 | { |
242 | if (unlikely(!timer)) | 303 | if (unlikely(!timer)) |
@@ -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"); |
@@ -695,7 +756,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev) | |||
695 | struct device *dev = &pdev->dev; | 756 | struct device *dev = &pdev->dev; |
696 | struct dmtimer_platform_data *pdata = pdev->dev.platform_data; | 757 | struct dmtimer_platform_data *pdata = pdev->dev.platform_data; |
697 | 758 | ||
698 | if (!pdata) { | 759 | if (!pdata && !dev->of_node) { |
699 | dev_err(dev, "%s: no platform data.\n", __func__); | 760 | dev_err(dev, "%s: no platform data.\n", __func__); |
700 | return -ENODEV; | 761 | return -ENODEV; |
701 | } | 762 | } |
@@ -724,11 +785,23 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev) | |||
724 | return -ENOMEM; | 785 | return -ENOMEM; |
725 | } | 786 | } |
726 | 787 | ||
727 | timer->id = pdev->id; | 788 | if (dev->of_node) { |
789 | if (of_find_property(dev->of_node, "ti,timer-alwon", NULL)) | ||
790 | timer->capability |= OMAP_TIMER_ALWON; | ||
791 | if (of_find_property(dev->of_node, "ti,timer-dsp", NULL)) | ||
792 | timer->capability |= OMAP_TIMER_HAS_DSP_IRQ; | ||
793 | if (of_find_property(dev->of_node, "ti,timer-pwm", NULL)) | ||
794 | timer->capability |= OMAP_TIMER_HAS_PWM; | ||
795 | if (of_find_property(dev->of_node, "ti,timer-secure", NULL)) | ||
796 | timer->capability |= OMAP_TIMER_SECURE; | ||
797 | } else { | ||
798 | timer->id = pdev->id; | ||
799 | timer->capability = pdata->timer_capability; | ||
800 | timer->reserved = omap_dm_timer_reserved_systimer(timer->id); | ||
801 | } | ||
802 | |||
728 | timer->irq = irq->start; | 803 | timer->irq = irq->start; |
729 | timer->reserved = omap_dm_timer_reserved_systimer(timer->id); | ||
730 | timer->pdev = pdev; | 804 | timer->pdev = pdev; |
731 | timer->capability = pdata->timer_capability; | ||
732 | 805 | ||
733 | /* Skip pm_runtime_enable for OMAP1 */ | 806 | /* Skip pm_runtime_enable for OMAP1 */ |
734 | if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { | 807 | if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { |
@@ -768,7 +841,8 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev) | |||
768 | 841 | ||
769 | spin_lock_irqsave(&dm_timer_lock, flags); | 842 | spin_lock_irqsave(&dm_timer_lock, flags); |
770 | list_for_each_entry(timer, &omap_timer_list, node) | 843 | list_for_each_entry(timer, &omap_timer_list, node) |
771 | if (timer->pdev->id == pdev->id) { | 844 | if (!strcmp(dev_name(&timer->pdev->dev), |
845 | dev_name(&pdev->dev))) { | ||
772 | list_del(&timer->node); | 846 | list_del(&timer->node); |
773 | ret = 0; | 847 | ret = 0; |
774 | break; | 848 | break; |
@@ -778,11 +852,18 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev) | |||
778 | return ret; | 852 | return ret; |
779 | } | 853 | } |
780 | 854 | ||
855 | static const struct of_device_id omap_timer_match[] = { | ||
856 | { .compatible = "ti,omap2-timer", }, | ||
857 | {}, | ||
858 | }; | ||
859 | MODULE_DEVICE_TABLE(of, omap_timer_match); | ||
860 | |||
781 | static struct platform_driver omap_dm_timer_driver = { | 861 | static struct platform_driver omap_dm_timer_driver = { |
782 | .probe = omap_dm_timer_probe, | 862 | .probe = omap_dm_timer_probe, |
783 | .remove = __devexit_p(omap_dm_timer_remove), | 863 | .remove = __devexit_p(omap_dm_timer_remove), |
784 | .driver = { | 864 | .driver = { |
785 | .name = "omap_timer", | 865 | .name = "omap_timer", |
866 | .of_match_table = of_match_ptr(omap_timer_match), | ||
786 | }, | 867 | }, |
787 | }; | 868 | }; |
788 | 869 | ||
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 85868e98c11c..348f855d3dab 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h | |||
@@ -99,6 +99,7 @@ struct dmtimer_platform_data { | |||
99 | int omap_dm_timer_reserve_systimer(int id); | 99 | int omap_dm_timer_reserve_systimer(int id); |
100 | struct omap_dm_timer *omap_dm_timer_request(void); | 100 | struct omap_dm_timer *omap_dm_timer_request(void); |
101 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); | 101 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); |
102 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap); | ||
102 | int omap_dm_timer_free(struct omap_dm_timer *timer); | 103 | int omap_dm_timer_free(struct omap_dm_timer *timer); |
103 | void omap_dm_timer_enable(struct omap_dm_timer *timer); | 104 | void omap_dm_timer_enable(struct omap_dm_timer *timer); |
104 | void omap_dm_timer_disable(struct omap_dm_timer *timer); | 105 | void omap_dm_timer_disable(struct omap_dm_timer *timer); |