diff options
| -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); |
