Add irq_domain support for the 32 wakeup interrupt sources. Cc: Grant Likely <grant.likely@xxxxxxxxxxxx> Signed-off-by: Thomas Abraham <thomas.abraham@xxxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html