Implement an irq_set_type callback for the GIC which is used to set the polarity and trigger type of GIC interrupts. Signed-off-by: Andrew Bresticker <abrestic@xxxxxxxxxxxx> --- arch/mips/include/asm/gic.h | 9 ++++++++ drivers/irqchip/irq-mips-gic.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index 1bf7985..662b567 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h @@ -23,6 +23,8 @@ #define GIC_POL_NEG 0 #define GIC_TRIG_EDGE 1 #define GIC_TRIG_LEVEL 0 +#define GIC_TRIG_DUAL_ENABLE 1 +#define GIC_TRIG_DUAL_DISABLE 0 #define MSK(n) ((1 << (n)) - 1) #define REG32(addr) (*(volatile unsigned int *) (addr)) @@ -179,6 +181,13 @@ GIC_INTR_OFS(intr)), (1 << GIC_INTR_BIT(intr)), \ (trig) << GIC_INTR_BIT(intr)) +/* Dual edge triggering : Reset Value is always 0 */ +#define GIC_SH_SET_DUAL_OFS 0x0200 +#define GIC_SET_DUAL(intr, dual) \ + GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_DUAL_OFS + \ + GIC_INTR_OFS(intr)), (1 << GIC_INTR_BIT(intr)), \ + (dual) << GIC_INTR_BIT(intr)) + /* Mask manipulation */ #define GIC_SH_SMASK_OFS 0x0380 #define GIC_SET_INTR_MASK(intr) \ diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 0dc2972..cde743c 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -246,6 +246,56 @@ static void gic_ack_irq(struct irq_data *d) GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), d->irq - gic_irq_base); } +static int gic_set_type(struct irq_data *d, unsigned int type) +{ + unsigned int irq = d->irq - gic_irq_base; + bool is_edge; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_FALLING: + GIC_SET_POLARITY(irq, GIC_POL_NEG); + GIC_SET_TRIGGER(irq, GIC_TRIG_EDGE); + GIC_SET_DUAL(irq, GIC_TRIG_DUAL_DISABLE); + is_edge = true; + break; + case IRQ_TYPE_EDGE_RISING: + GIC_SET_POLARITY(irq, GIC_POL_POS); + GIC_SET_TRIGGER(irq, GIC_TRIG_EDGE); + GIC_SET_DUAL(irq, GIC_TRIG_DUAL_DISABLE); + is_edge = true; + break; + case IRQ_TYPE_EDGE_BOTH: + /* polarity is irrelevant in this case */ + GIC_SET_TRIGGER(irq, GIC_TRIG_EDGE); + GIC_SET_DUAL(irq, GIC_TRIG_DUAL_ENABLE); + is_edge = true; + break; + case IRQ_TYPE_LEVEL_LOW: + GIC_SET_POLARITY(irq, GIC_POL_NEG); + GIC_SET_TRIGGER(irq, GIC_TRIG_LEVEL); + GIC_SET_DUAL(irq, GIC_TRIG_DUAL_DISABLE); + is_edge = false; + break; + case IRQ_TYPE_LEVEL_HIGH: + default: + GIC_SET_POLARITY(irq, GIC_POL_POS); + GIC_SET_TRIGGER(irq, GIC_TRIG_LEVEL); + GIC_SET_DUAL(irq, GIC_TRIG_DUAL_DISABLE); + is_edge = false; + break; + } + + if (is_edge) { + gic_irq_flags[irq] |= GIC_TRIG_EDGE; + __irq_set_handler_locked(d->irq, handle_edge_irq); + } else { + gic_irq_flags[irq] &= ~GIC_TRIG_EDGE; + __irq_set_handler_locked(d->irq, handle_level_irq); + } + + return 0; +} + #ifdef CONFIG_SMP static DEFINE_SPINLOCK(gic_lock); @@ -286,6 +336,7 @@ static struct irq_chip gic_irq_controller = { .irq_mask_ack = gic_ack_irq, .irq_unmask = gic_unmask_irq, .irq_eoi = gic_unmask_irq, + .irq_set_type = gic_set_type, #ifdef CONFIG_SMP .irq_set_affinity = gic_set_affinity, #endif -- 2.1.0.rc2.206.gedb03e5