ARM: OMAP2+: mux: add support for PAD wakeup interrupts
OMAP mux now parses active wakeup events from pad registers and calls corresponding hwmod ISRs once a wakeup is detected. This is accomplished by registering an interrupt handler for PRCM IO event, which is raised every time the HW detects wakeups. [paul@pwsan.com: This patch is a merge of Govindraj R's "ARM: OMAP2+: hwmod: Add API to check IO PAD wakeup status" patch, Tero Kristo's "ARM: OMAP2+: mux: add support for PAD wakeup interrupts" patch, and part of Tero's "ARM: OMAP: mux: add support for selecting mpu_irq for each wakeup pad" patch.] Signed-off-by: Tero Kristo <t-kristo@ti.com> Cc: Govindraj.R <govindraj.raja@ti.com> Tested-by: Kevin Hilman <khilman@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Acked-by: Tony Lindgren <tony@atomide.com> [paul@pwsan.com: reduced indentation level; renamed omap_hwmod function; improved function documentation; modified to iterate only through dynamic pads; modified to skip pads where idle mode doesn't enable wakeups; split patches] Signed-off-by: Paul Walmsley <paul@pwsan.com>
This commit is contained in:
parent
91285b6fa2
commit
13a3fe52f7
2 changed files with 84 additions and 0 deletions
|
@ -32,6 +32,8 @@
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
|
||||||
|
@ -39,6 +41,7 @@
|
||||||
|
|
||||||
#include "control.h"
|
#include "control.h"
|
||||||
#include "mux.h"
|
#include "mux.h"
|
||||||
|
#include "prm.h"
|
||||||
|
|
||||||
#define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */
|
#define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */
|
||||||
#define OMAP_MUX_BASE_SZ 0x5ca
|
#define OMAP_MUX_BASE_SZ 0x5ca
|
||||||
|
@ -353,6 +356,78 @@ err1:
|
||||||
return NULL;
|
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 */
|
/* Assumes the calling function takes care of locking */
|
||||||
void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
|
void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
|
||||||
{
|
{
|
||||||
|
@ -717,6 +792,7 @@ static void __init omap_mux_free_names(struct omap_mux *m)
|
||||||
static int __init omap_mux_late_init(void)
|
static int __init omap_mux_late_init(void)
|
||||||
{
|
{
|
||||||
struct omap_mux_partition *partition;
|
struct omap_mux_partition *partition;
|
||||||
|
int ret;
|
||||||
|
|
||||||
list_for_each_entry(partition, &mux_partitions, node) {
|
list_for_each_entry(partition, &mux_partitions, node) {
|
||||||
struct omap_mux_entry *e, *tmp;
|
struct omap_mux_entry *e, *tmp;
|
||||||
|
@ -737,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();
|
omap_mux_dbg_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -97,6 +97,7 @@ struct omap_hwmod_mux_info {
|
||||||
struct omap_device_pad *pads;
|
struct omap_device_pad *pads;
|
||||||
int nr_pads_dynamic;
|
int nr_pads_dynamic;
|
||||||
struct omap_device_pad **pads_dynamic;
|
struct omap_device_pad **pads_dynamic;
|
||||||
|
int *irqs;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue