Add irq_domain support for the 32 wakeup interrupt sources.

Cc: Grant Likely <grant.lik...@secretlab.ca>
Signed-off-by: Thomas Abraham <thomas.abra...@linaro.org>
---
 arch/arm/mach-exynos/include/mach/regs-gpio.h |    4 +-
 arch/arm/mach-exynos/irq-eint.c               |   69 ++++++++++++++++---------
 2 files changed, 46 insertions(+), 27 deletions(-)

diff --git a/arch/arm/mach-exynos/include/mach/regs-gpio.h 
b/arch/arm/mach-exynos/include/mach/regs-gpio.h
index 1401b21..2e6ec6b 100644
--- a/arch/arm/mach-exynos/include/mach/regs-gpio.h
+++ b/arch/arm/mach-exynos/include/mach/regs-gpio.h
@@ -28,9 +28,9 @@
 #define EXYNOS4_EINT40PEND             (S5P_VA_GPIO2 + 0xF40)
 #define S5P_EINT_PEND(x)               (EXYNOS4_EINT40PEND + ((x) * 0x4))
 
-#define EINT_REG_NR(x)                 (EINT_OFFSET(x) >> 3)
+#define EINT_REG_NR(x)                 ((x) >> 3)
 
-#define eint_irq_to_bit(irq)           (1 << (EINT_OFFSET(irq) & 0x7))
+#define eint_irq_to_bit(irq)           (1 << ((irq) & 0x7))
 
 #define EINT_MODE                      S3C_GPIO_SFN(0xf)
 
diff --git a/arch/arm/mach-exynos/irq-eint.c b/arch/arm/mach-exynos/irq-eint.c
index 5e89412..a65da64 100644
--- a/arch/arm/mach-exynos/irq-eint.c
+++ b/arch/arm/mach-exynos/irq-eint.c
@@ -16,6 +16,8 @@
 #include <linux/io.h>
 #include <linux/sysdev.h>
 #include <linux/gpio.h>
+#include <linux/irqdomain.h>
+#include <linux/export.h>
 
 #include <plat/pm.h>
 #include <plat/cpu.h>
@@ -28,17 +30,19 @@
 static DEFINE_SPINLOCK(eint_lock);
 
 static unsigned int eint0_15_data[16];
+static struct irq_domain exynos4_eint_irq_domain;
 
 #define exynos4_irq_eint_to_gic_irq(number) (IRQ_EINT0 + number)
+#define EXYNOS4_EINT_NR 32
 
 static inline void exynos4_irq_eint_mask(struct irq_data *data)
 {
        u32 mask;
 
        spin_lock(&eint_lock);
-       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-       mask |= eint_irq_to_bit(data->irq);
-       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->hwirq)));
+       mask |= eint_irq_to_bit(data->hwirq);
+       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->hwirq)));
        spin_unlock(&eint_lock);
 }
 
@@ -47,16 +51,16 @@ static void exynos4_irq_eint_unmask(struct irq_data *data)
        u32 mask;
 
        spin_lock(&eint_lock);
-       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-       mask &= ~(eint_irq_to_bit(data->irq));
-       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->hwirq)));
+       mask &= ~(eint_irq_to_bit(data->hwirq));
+       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->hwirq)));
        spin_unlock(&eint_lock);
 }
 
 static inline void exynos4_irq_eint_ack(struct irq_data *data)
 {
-       __raw_writel(eint_irq_to_bit(data->irq),
-                    S5P_EINT_PEND(EINT_REG_NR(data->irq)));
+       __raw_writel(eint_irq_to_bit(data->hwirq),
+                       S5P_EINT_PEND(EINT_REG_NR(data->hwirq)));
 }
 
 static void exynos4_irq_eint_maskack(struct irq_data *data)
@@ -67,7 +71,7 @@ static void exynos4_irq_eint_maskack(struct irq_data *data)
 
 static int exynos4_irq_eint_set_type(struct irq_data *data, unsigned int type)
 {
-       int offs = EINT_OFFSET(data->irq);
+       int offs = data->hwirq;
        int shift;
        u32 ctrl, mask;
        u32 newvalue = 0;
@@ -102,10 +106,10 @@ static int exynos4_irq_eint_set_type(struct irq_data 
*data, unsigned int type)
        mask = 0x7 << shift;
 
        spin_lock(&eint_lock);
-       ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
+       ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->hwirq)));
        ctrl &= ~mask;
        ctrl |= newvalue << shift;
-       __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
+       __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->hwirq)));
        spin_unlock(&eint_lock);
 
        switch (offs) {
@@ -148,19 +152,19 @@ static struct irq_chip exynos4_irq_eint = {
  *
  * Each EINT pend/mask registers handle eight of them.
  */
-static inline void exynos4_irq_demux_eint(unsigned int start)
+static inline void exynos4_irq_demux_eint(unsigned int base, unsigned int offs)
 {
        unsigned int irq;
 
-       u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
-       u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
+       u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(offs)));
+       u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(offs)));
 
        status &= ~mask;
        status &= 0xff;
 
        while (status) {
                irq = fls(status) - 1;
-               generic_handle_irq(irq + start);
+               generic_handle_irq(irq + offs + base);
                status &= ~(1 << irq);
        }
 }
@@ -168,9 +172,11 @@ static inline void exynos4_irq_demux_eint(unsigned int 
start)
 static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc 
*desc)
 {
        struct irq_chip *chip = irq_get_chip(irq);
+       u32 *irq_data = irq_get_handler_data(irq);
+
        chained_irq_enter(chip, desc);
-       exynos4_irq_demux_eint(IRQ_EINT(16));
-       exynos4_irq_demux_eint(IRQ_EINT(24));
+       exynos4_irq_demux_eint(*irq_data, 16);
+       exynos4_irq_demux_eint(*irq_data, 24);
        chained_irq_exit(chip, desc);
 }
 
@@ -193,22 +199,35 @@ static void exynos4_irq_eint0_15(unsigned int irq, struct 
irq_desc *desc)
 
 int __init exynos4_init_irq_eint(void)
 {
-       int irq;
+       int irq, hwirq;
+       struct irq_domain *domain = &exynos4_eint_irq_domain;
+
+       domain->irq_base = irq_alloc_descs(IRQ_EINT(0), IRQ_EINT(0),
+                                               EXYNOS4_EINT_NR, 0);
+       if (domain->irq_base < 0) {
+               pr_err("exynos4_init_irq_eint: Failed to alloc irq descs\n");
+               return -EBUSY;
+       }
+       domain->nr_irq = EXYNOS4_EINT_NR;
+       domain->ops = &irq_domain_simple_ops;
+       irq_domain_add(domain);
 
-       for (irq = 0 ; irq <= 31 ; irq++) {
-               irq_set_chip_and_handler(IRQ_EINT(irq), &exynos4_irq_eint,
+       irq_domain_for_each_irq(domain, hwirq, irq) {
+               irq_set_chip_and_handler(irq, &exynos4_irq_eint,
                                         handle_level_irq);
-               set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
+               set_irq_flags(irq, IRQF_VALID);
        }
 
        irq_set_chained_handler(IRQ_EINT16_31, exynos4_irq_demux_eint16_31);
+       irq_set_handler_data(IRQ_EINT16_31, &domain->irq_base);
 
-       for (irq = 0 ; irq <= 15 ; irq++) {
-               eint0_15_data[irq] = IRQ_EINT(irq);
+       for (hwirq = 0 ; hwirq <= 15 ; hwirq++) {
+               irq = irq_domain_to_irq(domain, hwirq);
+               eint0_15_data[irq] = irq;
 
-               irq_set_handler_data(exynos4_irq_eint_to_gic_irq(irq),
+               irq_set_handler_data(exynos4_irq_eint_to_gic_irq(hwirq),
                                     &eint0_15_data[irq]);
-               irq_set_chained_handler(exynos4_irq_eint_to_gic_irq(irq),
+               irq_set_chained_handler(exynos4_irq_eint_to_gic_irq(hwirq),
                                        exynos4_irq_eint0_15);
        }
 
-- 
1.6.6.rc2

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to