aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-s5p/irq-eint.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-s5p/irq-eint.c')
-rw-r--r--arch/arm/plat-s5p/irq-eint.c28
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;
}