diff options
Diffstat (limited to 'arch/arm/mach-omap2/mux.c')
| -rw-r--r-- | arch/arm/mach-omap2/mux.c | 89 |
1 files changed, 87 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 655e9480eb98..e1cc75d1a57a 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c | |||
| @@ -32,6 +32,8 @@ | |||
| 32 | #include <linux/debugfs.h> | 32 | #include <linux/debugfs.h> |
| 33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
| 34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
| 35 | #include <linux/irq.h> | ||
| 36 | #include <linux/interrupt.h> | ||
| 35 | 37 | ||
| 36 | #include <asm/system.h> | 38 | #include <asm/system.h> |
| 37 | 39 | ||
| @@ -39,6 +41,7 @@ | |||
| 39 | 41 | ||
| 40 | #include "control.h" | 42 | #include "control.h" |
| 41 | #include "mux.h" | 43 | #include "mux.h" |
| 44 | #include "prm.h" | ||
| 42 | 45 | ||
| 43 | #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ | 46 | #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ |
| 44 | #define OMAP_MUX_BASE_SZ 0x5ca | 47 | #define OMAP_MUX_BASE_SZ 0x5ca |
| @@ -306,7 +309,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads) | |||
| 306 | pad->idle = bpad->idle; | 309 | pad->idle = bpad->idle; |
| 307 | pad->off = bpad->off; | 310 | pad->off = bpad->off; |
| 308 | 311 | ||
| 309 | if (pad->flags & OMAP_DEVICE_PAD_REMUX) | 312 | if (pad->flags & |
| 313 | (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) | ||
| 310 | nr_pads_dynamic++; | 314 | nr_pads_dynamic++; |
| 311 | 315 | ||
| 312 | pr_debug("%s: Initialized %s\n", __func__, pad->name); | 316 | pr_debug("%s: Initialized %s\n", __func__, pad->name); |
| @@ -331,7 +335,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads) | |||
| 331 | for (i = 0; i < hmux->nr_pads; i++) { | 335 | for (i = 0; i < hmux->nr_pads; i++) { |
| 332 | struct omap_device_pad *pad = &hmux->pads[i]; | 336 | struct omap_device_pad *pad = &hmux->pads[i]; |
| 333 | 337 | ||
| 334 | if (pad->flags & OMAP_DEVICE_PAD_REMUX) { | 338 | if (pad->flags & |
| 339 | (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) { | ||
| 335 | pr_debug("%s: pad %s tagged dynamic\n", | 340 | pr_debug("%s: pad %s tagged dynamic\n", |
| 336 | __func__, pad->name); | 341 | __func__, pad->name); |
| 337 | hmux->pads_dynamic[nr_pads_dynamic] = pad; | 342 | hmux->pads_dynamic[nr_pads_dynamic] = pad; |
| @@ -351,6 +356,78 @@ err1: | |||
| 351 | return NULL; | 356 | return NULL; |
| 352 | } | 357 | } |
| 353 | 358 | ||
| 359 | /** | ||
| 360 | * omap_hwmod_mux_scan_wakeups - omap hwmod scan wakeup pads | ||
| 361 | * @hmux: Pads for a hwmod | ||
| 362 | * @mpu_irqs: MPU irq array for a hwmod | ||
| 363 | * | ||
| 364 | * Scans the wakeup status of pads for a single hwmod. If an irq | ||
| 365 | * array is defined for this mux, the parser will call the registered | ||
| 366 | * ISRs for corresponding pads, otherwise the parser will stop at the | ||
| 367 | * first wakeup active pad and return. Returns true if there is a | ||
| 368 | * pending and non-served wakeup event for the mux, otherwise false. | ||
| 369 | */ | ||
| 370 | static bool omap_hwmod_mux_scan_wakeups(struct omap_hwmod_mux_info *hmux, | ||
| 371 | struct omap_hwmod_irq_info *mpu_irqs) | ||
| 372 | { | ||
| 373 | int i, irq; | ||
| 374 | unsigned int val; | ||
| 375 | u32 handled_irqs = 0; | ||
| 376 | |||
| 377 | for (i = 0; i < hmux->nr_pads_dynamic; i++) { | ||
| 378 | struct omap_device_pad *pad = hmux->pads_dynamic[i]; | ||
| 379 | |||
| 380 | if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP) || | ||
| 381 | !(pad->idle & OMAP_WAKEUP_EN)) | ||
| 382 | continue; | ||
| 383 | |||
| 384 | val = omap_mux_read(pad->partition, pad->mux->reg_offset); | ||
| 385 | if (!(val & OMAP_WAKEUP_EVENT)) | ||
| 386 | continue; | ||
| 387 | |||
| 388 | if (!hmux->irqs) | ||
| 389 | return true; | ||
| 390 | |||
| 391 | irq = hmux->irqs[i]; | ||
| 392 | /* make sure we only handle each irq once */ | ||
| 393 | if (handled_irqs & 1 << irq) | ||
| 394 | continue; | ||
| 395 | |||
| 396 | handled_irqs |= 1 << irq; | ||
| 397 | |||
| 398 | generic_handle_irq(mpu_irqs[irq].irq); | ||
| 399 | } | ||
| 400 | |||
| 401 | return false; | ||
| 402 | } | ||
| 403 | |||
| 404 | /** | ||
| 405 | * _omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod | ||
| 406 | * | ||
| 407 | * Checks a single hwmod for every wakeup capable pad to see if there is an | ||
| 408 | * active wakeup event. If this is the case, call the corresponding ISR. | ||
| 409 | */ | ||
| 410 | static int _omap_hwmod_mux_handle_irq(struct omap_hwmod *oh, void *data) | ||
| 411 | { | ||
| 412 | if (!oh->mux || !oh->mux->enabled) | ||
| 413 | return 0; | ||
| 414 | if (omap_hwmod_mux_scan_wakeups(oh->mux, oh->mpu_irqs)) | ||
| 415 | generic_handle_irq(oh->mpu_irqs[0].irq); | ||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | |||
| 419 | /** | ||
| 420 | * omap_hwmod_mux_handle_irq - Process pad wakeup irqs. | ||
| 421 | * | ||
| 422 | * Calls a function for each registered omap_hwmod to check | ||
| 423 | * pad wakeup statuses. | ||
| 424 | */ | ||
| 425 | static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused) | ||
| 426 | { | ||
| 427 | omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL); | ||
| 428 | return IRQ_HANDLED; | ||
| 429 | } | ||
| 430 | |||
| 354 | /* Assumes the calling function takes care of locking */ | 431 | /* Assumes the calling function takes care of locking */ |
| 355 | void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) | 432 | void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) |
| 356 | { | 433 | { |
| @@ -715,6 +792,7 @@ static void __init omap_mux_free_names(struct omap_mux *m) | |||
| 715 | static int __init omap_mux_late_init(void) | 792 | static int __init omap_mux_late_init(void) |
| 716 | { | 793 | { |
| 717 | struct omap_mux_partition *partition; | 794 | struct omap_mux_partition *partition; |
| 795 | int ret; | ||
| 718 | 796 | ||
| 719 | list_for_each_entry(partition, &mux_partitions, node) { | 797 | list_for_each_entry(partition, &mux_partitions, node) { |
| 720 | struct omap_mux_entry *e, *tmp; | 798 | struct omap_mux_entry *e, *tmp; |
| @@ -735,6 +813,13 @@ static int __init omap_mux_late_init(void) | |||
| 735 | } | 813 | } |
| 736 | } | 814 | } |
| 737 | 815 | ||
| 816 | ret = request_irq(omap_prcm_event_to_irq("io"), | ||
| 817 | omap_hwmod_mux_handle_irq, IRQF_SHARED | IRQF_NO_SUSPEND, | ||
| 818 | "hwmod_io", omap_mux_late_init); | ||
| 819 | |||
| 820 | if (ret) | ||
| 821 | pr_warning("mux: Failed to setup hwmod io irq %d\n", ret); | ||
| 822 | |||
| 738 | omap_mux_dbg_init(); | 823 | omap_mux_dbg_init(); |
| 739 | 824 | ||
| 740 | return 0; | 825 | return 0; |
