diff options
Diffstat (limited to 'arch/arm/plat-s5p/irq-eint.c')
-rw-r--r-- | arch/arm/plat-s5p/irq-eint.c | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c index b5bb774..8380951 100644 --- a/arch/arm/plat-s5p/irq-eint.c +++ b/arch/arm/plat-s5p/irq-eint.c @@ -37,21 +37,31 @@ static inline void s5p_irq_eint_mask(struct irq_data *data) __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq))); } +static inline void s5p_irq_eint_ack(struct irq_data *data) +{ + __raw_writel(eint_irq_to_bit(data->irq), + S5P_EINT_PEND(EINT_REG_NR(data->irq))); +} + static void s5p_irq_eint_unmask(struct irq_data *data) { u32 mask; + /* for level triggered interrupts, masking doesn't prevent + * the interrupt from becoming pending again. by the time + * the handler (either irq or thread) can do its thing to clear + * the interrupt, it's too late because it could be pending + * already. we have to ack it here, after the handler runs, + * or else we get a false interrupt. + */ + if (irqd_is_level_type(data)) + s5p_irq_eint_ack(data); + 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))); } -static inline void s5p_irq_eint_ack(struct irq_data *data) -{ - __raw_writel(eint_irq_to_bit(data->irq), - S5P_EINT_PEND(EINT_REG_NR(data->irq))); -} - static void s5p_irq_eint_maskack(struct irq_data *data) { /* compiler should in-line these */ @@ -65,6 +75,7 @@ static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type) int shift; u32 ctrl, mask; u32 newvalue = 0; + struct irq_desc *desc = irq_to_desc(data->irq); switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -115,6 +126,11 @@ static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type) else printk(KERN_ERR "No such irq number %d", offs); + if (type & IRQ_TYPE_EDGE_BOTH) + desc->handle_irq = handle_edge_irq; + else + desc->handle_irq = handle_level_irq; + return 0; } |