diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 125 |
1 files changed, 124 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 529142aff766..ee9416bcc3e6 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -136,6 +136,7 @@ | |||
136 | #include <linux/list.h> | 136 | #include <linux/list.h> |
137 | #include <linux/mutex.h> | 137 | #include <linux/mutex.h> |
138 | #include <linux/spinlock.h> | 138 | #include <linux/spinlock.h> |
139 | #include <linux/slab.h> | ||
139 | 140 | ||
140 | #include "common.h" | 141 | #include "common.h" |
141 | #include <plat/cpu.h> | 142 | #include <plat/cpu.h> |
@@ -381,6 +382,51 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, | |||
381 | } | 382 | } |
382 | 383 | ||
383 | /** | 384 | /** |
385 | * _set_idle_ioring_wakeup - enable/disable IO pad wakeup on hwmod idle for mux | ||
386 | * @oh: struct omap_hwmod * | ||
387 | * @set_wake: bool value indicating to set (true) or clear (false) wakeup enable | ||
388 | * | ||
389 | * Set or clear the I/O pad wakeup flag in the mux entries for the | ||
390 | * hwmod @oh. This function changes the @oh->mux->pads_dynamic array | ||
391 | * in memory. If the hwmod is currently idled, and the new idle | ||
392 | * values don't match the previous ones, this function will also | ||
393 | * update the SCM PADCTRL registers. Otherwise, if the hwmod is not | ||
394 | * currently idled, this function won't touch the hardware: the new | ||
395 | * mux settings are written to the SCM PADCTRL registers when the | ||
396 | * hwmod is idled. No return value. | ||
397 | */ | ||
398 | static void _set_idle_ioring_wakeup(struct omap_hwmod *oh, bool set_wake) | ||
399 | { | ||
400 | struct omap_device_pad *pad; | ||
401 | bool change = false; | ||
402 | u16 prev_idle; | ||
403 | int j; | ||
404 | |||
405 | if (!oh->mux || !oh->mux->enabled) | ||
406 | return; | ||
407 | |||
408 | for (j = 0; j < oh->mux->nr_pads_dynamic; j++) { | ||
409 | pad = oh->mux->pads_dynamic[j]; | ||
410 | |||
411 | if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP)) | ||
412 | continue; | ||
413 | |||
414 | prev_idle = pad->idle; | ||
415 | |||
416 | if (set_wake) | ||
417 | pad->idle |= OMAP_WAKEUP_EN; | ||
418 | else | ||
419 | pad->idle &= ~OMAP_WAKEUP_EN; | ||
420 | |||
421 | if (prev_idle != pad->idle) | ||
422 | change = true; | ||
423 | } | ||
424 | |||
425 | if (change && oh->_state == _HWMOD_STATE_IDLE) | ||
426 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); | ||
427 | } | ||
428 | |||
429 | /** | ||
384 | * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware | 430 | * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware |
385 | * @oh: struct omap_hwmod * | 431 | * @oh: struct omap_hwmod * |
386 | * | 432 | * |
@@ -1441,6 +1487,25 @@ static int _enable(struct omap_hwmod *oh) | |||
1441 | 1487 | ||
1442 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); | 1488 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); |
1443 | 1489 | ||
1490 | /* | ||
1491 | * hwmods with HWMOD_INIT_NO_IDLE flag set are left | ||
1492 | * in enabled state at init. | ||
1493 | * Now that someone is really trying to enable them, | ||
1494 | * just ensure that the hwmod mux is set. | ||
1495 | */ | ||
1496 | if (oh->_int_flags & _HWMOD_SKIP_ENABLE) { | ||
1497 | /* | ||
1498 | * If the caller has mux data populated, do the mux'ing | ||
1499 | * which wouldn't have been done as part of the _enable() | ||
1500 | * done during setup. | ||
1501 | */ | ||
1502 | if (oh->mux) | ||
1503 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); | ||
1504 | |||
1505 | oh->_int_flags &= ~_HWMOD_SKIP_ENABLE; | ||
1506 | return 0; | ||
1507 | } | ||
1508 | |||
1444 | if (oh->_state != _HWMOD_STATE_INITIALIZED && | 1509 | if (oh->_state != _HWMOD_STATE_INITIALIZED && |
1445 | oh->_state != _HWMOD_STATE_IDLE && | 1510 | oh->_state != _HWMOD_STATE_IDLE && |
1446 | oh->_state != _HWMOD_STATE_DISABLED) { | 1511 | oh->_state != _HWMOD_STATE_DISABLED) { |
@@ -1744,8 +1809,10 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1744 | * it should be set by the core code as a runtime flag during startup | 1809 | * it should be set by the core code as a runtime flag during startup |
1745 | */ | 1810 | */ |
1746 | if ((oh->flags & HWMOD_INIT_NO_IDLE) && | 1811 | if ((oh->flags & HWMOD_INIT_NO_IDLE) && |
1747 | (postsetup_state == _HWMOD_STATE_IDLE)) | 1812 | (postsetup_state == _HWMOD_STATE_IDLE)) { |
1813 | oh->_int_flags |= _HWMOD_SKIP_ENABLE; | ||
1748 | postsetup_state = _HWMOD_STATE_ENABLED; | 1814 | postsetup_state = _HWMOD_STATE_ENABLED; |
1815 | } | ||
1749 | 1816 | ||
1750 | if (postsetup_state == _HWMOD_STATE_IDLE) | 1817 | if (postsetup_state == _HWMOD_STATE_IDLE) |
1751 | _idle(oh); | 1818 | _idle(oh); |
@@ -2416,6 +2483,7 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) | |||
2416 | v = oh->_sysc_cache; | 2483 | v = oh->_sysc_cache; |
2417 | _enable_wakeup(oh, &v); | 2484 | _enable_wakeup(oh, &v); |
2418 | _write_sysconfig(v, oh); | 2485 | _write_sysconfig(v, oh); |
2486 | _set_idle_ioring_wakeup(oh, true); | ||
2419 | spin_unlock_irqrestore(&oh->_lock, flags); | 2487 | spin_unlock_irqrestore(&oh->_lock, flags); |
2420 | 2488 | ||
2421 | return 0; | 2489 | return 0; |
@@ -2446,6 +2514,7 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) | |||
2446 | v = oh->_sysc_cache; | 2514 | v = oh->_sysc_cache; |
2447 | _disable_wakeup(oh, &v); | 2515 | _disable_wakeup(oh, &v); |
2448 | _write_sysconfig(v, oh); | 2516 | _write_sysconfig(v, oh); |
2517 | _set_idle_ioring_wakeup(oh, false); | ||
2449 | spin_unlock_irqrestore(&oh->_lock, flags); | 2518 | spin_unlock_irqrestore(&oh->_lock, flags); |
2450 | 2519 | ||
2451 | return 0; | 2520 | return 0; |
@@ -2662,3 +2731,57 @@ int omap_hwmod_no_setup_reset(struct omap_hwmod *oh) | |||
2662 | 2731 | ||
2663 | return 0; | 2732 | return 0; |
2664 | } | 2733 | } |
2734 | |||
2735 | /** | ||
2736 | * omap_hwmod_pad_route_irq - route an I/O pad wakeup to a particular MPU IRQ | ||
2737 | * @oh: struct omap_hwmod * containing hwmod mux entries | ||
2738 | * @pad_idx: array index in oh->mux of the hwmod mux entry to route wakeup | ||
2739 | * @irq_idx: the hwmod mpu_irqs array index of the IRQ to trigger on wakeup | ||
2740 | * | ||
2741 | * When an I/O pad wakeup arrives for the dynamic or wakeup hwmod mux | ||
2742 | * entry number @pad_idx for the hwmod @oh, trigger the interrupt | ||
2743 | * service routine for the hwmod's mpu_irqs array index @irq_idx. If | ||
2744 | * this function is not called for a given pad_idx, then the ISR | ||
2745 | * associated with @oh's first MPU IRQ will be triggered when an I/O | ||
2746 | * pad wakeup occurs on that pad. Note that @pad_idx is the index of | ||
2747 | * the _dynamic or wakeup_ entry: if there are other entries not | ||
2748 | * marked with OMAP_DEVICE_PAD_WAKEUP or OMAP_DEVICE_PAD_REMUX, these | ||
2749 | * entries are NOT COUNTED in the dynamic pad index. This function | ||
2750 | * must be called separately for each pad that requires its interrupt | ||
2751 | * to be re-routed this way. Returns -EINVAL if there is an argument | ||
2752 | * problem or if @oh does not have hwmod mux entries or MPU IRQs; | ||
2753 | * returns -ENOMEM if memory cannot be allocated; or 0 upon success. | ||
2754 | * | ||
2755 | * XXX This function interface is fragile. Rather than using array | ||
2756 | * indexes, which are subject to unpredictable change, it should be | ||
2757 | * using hwmod IRQ names, and some other stable key for the hwmod mux | ||
2758 | * pad records. | ||
2759 | */ | ||
2760 | int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx) | ||
2761 | { | ||
2762 | int nr_irqs; | ||
2763 | |||
2764 | might_sleep(); | ||
2765 | |||
2766 | if (!oh || !oh->mux || !oh->mpu_irqs || pad_idx < 0 || | ||
2767 | pad_idx >= oh->mux->nr_pads_dynamic) | ||
2768 | return -EINVAL; | ||
2769 | |||
2770 | /* Check the number of available mpu_irqs */ | ||
2771 | for (nr_irqs = 0; oh->mpu_irqs[nr_irqs].irq >= 0; nr_irqs++) | ||
2772 | ; | ||
2773 | |||
2774 | if (irq_idx >= nr_irqs) | ||
2775 | return -EINVAL; | ||
2776 | |||
2777 | if (!oh->mux->irqs) { | ||
2778 | /* XXX What frees this? */ | ||
2779 | oh->mux->irqs = kzalloc(sizeof(int) * oh->mux->nr_pads_dynamic, | ||
2780 | GFP_KERNEL); | ||
2781 | if (!oh->mux->irqs) | ||
2782 | return -ENOMEM; | ||
2783 | } | ||
2784 | oh->mux->irqs[pad_idx] = irq_idx; | ||
2785 | |||
2786 | return 0; | ||
2787 | } | ||