forked from Minki/linux
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: Ken Ma <make@marvell.com> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
0cc449f675
commit
30ac0d3b07
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user