diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 14:39:59 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 14:39:59 -0800 |
commit | b3c37522928b5452588fc202eaa0f11f6e339256 (patch) | |
tree | 37bfe21d9977b15271903d1a4b304289a232e364 /arch/arm/mach-omap2/mux.c | |
parent | 2ac9d7aaccbd598b5bd19ac40761b723bb675442 (diff) | |
parent | 6d0a5636fba5a3f82ec80ab124dd4748344549c3 (diff) |
Merge tag 'pm' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
power management changes for omap and imx
A significant part of the changes for these two platforms went into
power management, so they are split out into a separate branch.
* tag 'pm' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (65 commits)
ARM: imx6: remove __CPUINIT annotation from v7_invalidate_l1
ARM: imx6: fix v7_invalidate_l1 by adding I-Cache invalidation
ARM: imx6q: resume PL310 only when CACHE_L2X0 defined
ARM: imx6q: build pm code only when CONFIG_PM selected
ARM: mx5: use generic irq chip pm interface for pm functions on
ARM: omap: pass minimal SoC/board data for UART from dt
arm/dts: Add minimal device tree support for omap2420 and omap2430
omap-serial: Add minimal device tree support
omap-serial: Use default clock speed (48Mhz) if not specified
omap-serial: Get rid of all pdev->id usage
ARM: OMAP2+: hwmod: Add a new flag to handle hwmods left enabled at init
ARM: OMAP4: PRM: use PRCM interrupt handler
ARM: OMAP3: pm: use prcm chain handler
ARM: OMAP: hwmod: add support for selecting mpu_irq for each wakeup pad
ARM: OMAP2+: mux: add support for PAD wakeup interrupts
ARM: OMAP: PRCM: add suspend prepare / finish support
ARM: OMAP: PRCM: add support for chain interrupt handler
ARM: OMAP3/4: PRM: add functions to read pending IRQs, PRM barrier
ARM: OMAP2+: hwmod: Add API to enable IO ring wakeup
ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list
...
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 655e9480eb9..e1cc75d1a57 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -32,6 +32,8 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/uaccess.h> +#include <linux/irq.h> +#include <linux/interrupt.h> #include <asm/system.h> @@ -39,6 +41,7 @@ #include "control.h" #include "mux.h" +#include "prm.h" #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ #define OMAP_MUX_BASE_SZ 0x5ca @@ -306,7 +309,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads) pad->idle = bpad->idle; pad->off = bpad->off; - if (pad->flags & OMAP_DEVICE_PAD_REMUX) + if (pad->flags & + (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) nr_pads_dynamic++; 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) for (i = 0; i < hmux->nr_pads; i++) { struct omap_device_pad *pad = &hmux->pads[i]; - if (pad->flags & OMAP_DEVICE_PAD_REMUX) { + if (pad->flags & + (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) { pr_debug("%s: pad %s tagged dynamic\n", __func__, pad->name); hmux->pads_dynamic[nr_pads_dynamic] = pad; @@ -351,6 +356,78 @@ err1: return NULL; } +/** + * omap_hwmod_mux_scan_wakeups - omap hwmod scan wakeup pads + * @hmux: Pads for a hwmod + * @mpu_irqs: MPU irq array for a hwmod + * + * Scans the wakeup status of pads for a single hwmod. If an irq + * array is defined for this mux, the parser will call the registered + * ISRs for corresponding pads, otherwise the parser will stop at the + * first wakeup active pad and return. Returns true if there is a + * pending and non-served wakeup event for the mux, otherwise false. + */ +static bool omap_hwmod_mux_scan_wakeups(struct omap_hwmod_mux_info *hmux, + struct omap_hwmod_irq_info *mpu_irqs) +{ + int i, irq; + unsigned int val; + u32 handled_irqs = 0; + + for (i = 0; i < hmux->nr_pads_dynamic; i++) { + struct omap_device_pad *pad = hmux->pads_dynamic[i]; + + if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP) || + !(pad->idle & OMAP_WAKEUP_EN)) + continue; + + val = omap_mux_read(pad->partition, pad->mux->reg_offset); + if (!(val & OMAP_WAKEUP_EVENT)) + continue; + + if (!hmux->irqs) + return true; + + irq = hmux->irqs[i]; + /* make sure we only handle each irq once */ + if (handled_irqs & 1 << irq) + continue; + + handled_irqs |= 1 << irq; + + generic_handle_irq(mpu_irqs[irq].irq); + } + + return false; +} + +/** + * _omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod + * + * Checks a single hwmod for every wakeup capable pad to see if there is an + * active wakeup event. If this is the case, call the corresponding ISR. + */ +static int _omap_hwmod_mux_handle_irq(struct omap_hwmod *oh, void *data) +{ + if (!oh->mux || !oh->mux->enabled) + return 0; + if (omap_hwmod_mux_scan_wakeups(oh->mux, oh->mpu_irqs)) + generic_handle_irq(oh->mpu_irqs[0].irq); + return 0; +} + +/** + * omap_hwmod_mux_handle_irq - Process pad wakeup irqs. + * + * Calls a function for each registered omap_hwmod to check + * pad wakeup statuses. + */ +static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused) +{ + omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL); + return IRQ_HANDLED; +} + /* Assumes the calling function takes care of locking */ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) { @@ -715,6 +792,7 @@ static void __init omap_mux_free_names(struct omap_mux *m) static int __init omap_mux_late_init(void) { struct omap_mux_partition *partition; + int ret; list_for_each_entry(partition, &mux_partitions, node) { struct omap_mux_entry *e, *tmp; @@ -735,6 +813,13 @@ static int __init omap_mux_late_init(void) } } + ret = request_irq(omap_prcm_event_to_irq("io"), + omap_hwmod_mux_handle_irq, IRQF_SHARED | IRQF_NO_SUSPEND, + "hwmod_io", omap_mux_late_init); + + if (ret) + pr_warning("mux: Failed to setup hwmod io irq %d\n", ret); + omap_mux_dbg_init(); return 0; |