summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2012-03-19 20:15:52 -0500
committerRobert Lee <b18647@b18647-12.(none)>2012-03-19 20:42:47 -0500
commit01d9ee53ab2c4f6088ac8a2661f5ce5977e57d10 (patch)
tree428c2c6efdca9df7dc700e5bdcfbf3c44e7194b9
parent324ae6098c81213ab7de035dcd0cbabf29029b1f (diff)
mfd : ux500 : check pending irq on gic
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
-rw-r--r--drivers/mfd/db8500-prcmu.c33
-rw-r--r--include/linux/mfd/db8500-prcmu.h1
-rw-r--r--include/linux/mfd/dbx500-prcmu.h8
3 files changed, 42 insertions, 0 deletions
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 9d2399284b1..4a89b223790 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -30,6 +30,7 @@
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
+#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/db8500-regs.h>
@@ -816,6 +817,38 @@ int db8500_prcmu_gic_recouple(void)
return 0;
}
+#define PRCMU_GIC_NUMBER_REGS 5
+
+/*
+ * This function checks if there are pending irq on the gic. It only
+ * makes sense if the gic has been decoupled before with the
+ * db8500_prcmu_gic_decouple function. Disabling an interrupt only
+ * disables the forwarding of the interrupt to any CPU interface. It
+ * does not prevent the interrupt from changing state, for example
+ * becoming pending, or active and pending if it is already
+ * active. Hence, we have to check the interrupt is pending *and* is
+ * active.
+ */
+bool db8500_prcmu_gic_pending_irq(void)
+{
+ u32 pr; /* Pending register */
+ u32 er; /* Enable register */
+ void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+ int i;
+
+ /* 5 registers. STI & PPI not skipped */
+ for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) {
+
+ pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4);
+ er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ if (pr & er)
+ return true; /* There is a pending interrupt */
+ }
+
+ return false;
+}
+
/* This function should only be called while mb0_transfer.lock is held. */
static void config_wakeups(void)
{
diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
index a3c7eba8e6f..8bf0dc3ba04 100644
--- a/include/linux/mfd/db8500-prcmu.h
+++ b/include/linux/mfd/db8500-prcmu.h
@@ -538,6 +538,7 @@ void db8500_prcmu_system_reset(u16 reset_code);
int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
int db8500_prcmu_gic_decouple(void);
int db8500_prcmu_gic_recouple(void);
+bool db8500_prcmu_gic_pending_irq(void);
void db8500_prcmu_enable_wakeups(u32 wakeups);
int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state);
int db8500_prcmu_request_clock(u8 clock, bool enable);
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index d38cf7d9657..82c6d516d0b 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -253,6 +253,14 @@ static inline int prcmu_gic_recouple(void)
return db8500_prcmu_gic_recouple();
}
+static inline bool prcmu_gic_pending_irq(void)
+{
+ if (machine_is_u5500())
+ return -EINVAL;
+ else
+ return db8500_prcmu_gic_pending_irq();
+}
+
static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
{
if (machine_is_u5500())