]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
mfd : Check if there are pending irq on the db8500 gic
authorDaniel Lezcano <daniel.lezcano@linaro.org>
Tue, 28 Feb 2012 21:46:06 +0000 (22:46 +0100)
committerSamuel Ortiz <sameo@linux.intel.com>
Tue, 6 Mar 2012 17:46:55 +0000 (18:46 +0100)
This patch introduces a routine to check if there are some
irqs pending on the gic. Usually this check is not relevant because
it appears racy (an irq can arrive right after this check), but in
the ux500 it makes sense because the prcmu decouples the gic from
the A9 cores.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/mfd/db8500-prcmu.c
include/linux/mfd/db8500-prcmu.h
include/linux/mfd/dbx500-prcmu.h

index d2244dc5d3b16d54eee188999ddc5e3974950b4a..8346a0e399493a88fe6b163c3c140e1129444662 100644 (file)
@@ -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>
@@ -850,6 +851,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)
 {
index cf48aa76acc39f9a90d7c1c7738c6291e6cec5dc..92dac13b9ee525125bea5b02816478553a6f23d6 100644 (file)
@@ -582,6 +582,7 @@ int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
 u8 db8500_prcmu_get_power_state_result(void);
 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);
index 5bf5c4f0132cd2deb69e7dfdda6a785357e97d7b..16418747dad146ba2f9409f886c38e0b33f5b8e3 100644 (file)
@@ -297,6 +297,14 @@ static inline int prcmu_gic_recouple(void)
                return db8500_prcmu_gic_recouple();
 }
 
+static inline bool prcmu_gic_pending_irq(void)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_gic_pending_irq();
+}
+
 static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
 {
        if (cpu_is_u5500())