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 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;  |