Commit 30ac0d3b authored by Ken Ma's avatar Ken Ma Committed by Linus Walleij

pinctrl: armada-37xx: Add edge both type gpio irq support

Current edge both type gpio irqs which need to swap polarity in each
interrupt are not supported, this patch adds edge both type gpio irq
support.
Signed-off-by: default avatarKen Ma <make@marvell.com>
Signed-off-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 0cc449f6
......@@ -576,6 +576,19 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
case IRQ_TYPE_EDGE_FALLING:
val |= (BIT(d->hwirq % GPIO_PER_REG));
break;
case IRQ_TYPE_EDGE_BOTH: {
u32 in_val, in_reg = INPUT_VAL;
armada_37xx_irq_update_reg(&in_reg, d);
regmap_read(info->regmap, in_reg, &in_val);
/* Set initial polarity based on current input level. */
if (in_val & d->mask)
val |= d->mask; /* falling */
else
val &= ~d->mask; /* rising */
break;
}
default:
spin_unlock_irqrestore(&info->irq_lock, flags);
return -EINVAL;
......@@ -586,6 +599,40 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
return 0;
}
static int armada_37xx_edge_both_irq_swap_pol(struct armada_37xx_pinctrl *info,
u32 pin_idx)
{
u32 reg_idx = pin_idx / GPIO_PER_REG;
u32 bit_num = pin_idx % GPIO_PER_REG;
u32 p, l, ret;
unsigned long flags;
regmap_read(info->regmap, INPUT_VAL + 4*reg_idx, &l);
spin_lock_irqsave(&info->irq_lock, flags);
p = readl(info->base + IRQ_POL + 4 * reg_idx);
if ((p ^ l) & (1 << bit_num)) {
/*
* For the gpios which are used for both-edge irqs, when their
* interrupts happen, their input levels are changed,
* yet their interrupt polarities are kept in old values, we
* should synchronize their interrupt polarities; for example,
* at first a gpio's input level is low and its interrupt
* polarity control is "Detect rising edge", then the gpio has
* a interrupt , its level turns to high, we should change its
* polarity control to "Detect falling edge" correspondingly.
*/
p ^= 1 << bit_num;
writel(p, info->base + IRQ_POL + 4 * reg_idx);
ret = 0;
} else {
/* Spurious irq */
ret = -1;
}
spin_unlock_irqrestore(&info->irq_lock, flags);
return ret;
}
static void armada_37xx_irq_handler(struct irq_desc *desc)
{
......@@ -609,6 +656,23 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
u32 hwirq = ffs(status) - 1;
u32 virq = irq_find_mapping(d, hwirq +
i * GPIO_PER_REG);
u32 t = irq_get_trigger_type(virq);
if ((t & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
/* Swap polarity (race with GPIO line) */
if (armada_37xx_edge_both_irq_swap_pol(info,
hwirq + i * GPIO_PER_REG)) {
/*
* For spurious irq, which gpio level
* is not as expected after incoming
* edge, just ack the gpio irq.
*/
writel(1 << hwirq,
info->base +
IRQ_STATUS + 4 * i);
continue;
}
}
generic_handle_irq(virq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment