mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 04:23:35 +02:00
gpio: pca953x: Add support for level-triggered interrupts
Adds support for level-triggered interrupts in the PCA953x GPIO expander driver. Previously, the driver only supported edge-triggered interrupts, which could lead to missed events in scenarios where an interrupt condition persists until it is explicitly cleared. By enabling level-triggered interrupts, the driver can now detect and respond to sustained interrupt conditions more reliably. Signed-off-by: Potin Lai <potin.lai.pt@gmail.com> Link: https://lore.kernel.org/r/20250409-gpio-pca953x-level-triggered-irq-v3-1-7f184d814934@gmail.com Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
This commit is contained in:
parent
73dc041f8a
commit
417b0f8d08
|
|
@ -215,6 +215,8 @@ struct pca953x_chip {
|
|||
DECLARE_BITMAP(irq_stat, MAX_LINE);
|
||||
DECLARE_BITMAP(irq_trig_raise, MAX_LINE);
|
||||
DECLARE_BITMAP(irq_trig_fall, MAX_LINE);
|
||||
DECLARE_BITMAP(irq_trig_level_high, MAX_LINE);
|
||||
DECLARE_BITMAP(irq_trig_level_low, MAX_LINE);
|
||||
#endif
|
||||
atomic_t wakeup_path;
|
||||
|
||||
|
|
@ -774,6 +776,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
|
|||
pca953x_read_regs(chip, chip->regs->direction, reg_direction);
|
||||
|
||||
bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
|
||||
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_high, gc->ngpio);
|
||||
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_low, gc->ngpio);
|
||||
bitmap_complement(reg_direction, reg_direction, gc->ngpio);
|
||||
bitmap_and(irq_mask, irq_mask, reg_direction, gc->ngpio);
|
||||
|
||||
|
|
@ -791,13 +795,15 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
struct device *dev = &chip->client->dev;
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
|
||||
if (!(type & IRQ_TYPE_EDGE_BOTH)) {
|
||||
if (!(type & IRQ_TYPE_SENSE_MASK)) {
|
||||
dev_err(dev, "irq %d: unsupported type %d\n", d->irq, type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
assign_bit(hwirq, chip->irq_trig_fall, type & IRQ_TYPE_EDGE_FALLING);
|
||||
assign_bit(hwirq, chip->irq_trig_raise, type & IRQ_TYPE_EDGE_RISING);
|
||||
assign_bit(hwirq, chip->irq_trig_level_low, type & IRQ_TYPE_LEVEL_LOW);
|
||||
assign_bit(hwirq, chip->irq_trig_level_high, type & IRQ_TYPE_LEVEL_HIGH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -810,6 +816,8 @@ static void pca953x_irq_shutdown(struct irq_data *d)
|
|||
|
||||
clear_bit(hwirq, chip->irq_trig_raise);
|
||||
clear_bit(hwirq, chip->irq_trig_fall);
|
||||
clear_bit(hwirq, chip->irq_trig_level_low);
|
||||
clear_bit(hwirq, chip->irq_trig_level_high);
|
||||
}
|
||||
|
||||
static void pca953x_irq_print_chip(struct irq_data *data, struct seq_file *p)
|
||||
|
|
@ -840,6 +848,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin
|
|||
DECLARE_BITMAP(cur_stat, MAX_LINE);
|
||||
DECLARE_BITMAP(new_stat, MAX_LINE);
|
||||
DECLARE_BITMAP(trigger, MAX_LINE);
|
||||
DECLARE_BITMAP(edges, MAX_LINE);
|
||||
int ret;
|
||||
|
||||
ret = pca953x_read_regs(chip, chip->regs->input, cur_stat);
|
||||
|
|
@ -857,13 +866,26 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin
|
|||
|
||||
bitmap_copy(chip->irq_stat, new_stat, gc->ngpio);
|
||||
|
||||
if (bitmap_empty(trigger, gc->ngpio))
|
||||
return false;
|
||||
if (bitmap_empty(chip->irq_trig_level_high, gc->ngpio) &&
|
||||
bitmap_empty(chip->irq_trig_level_low, gc->ngpio)) {
|
||||
if (bitmap_empty(trigger, gc->ngpio))
|
||||
return false;
|
||||
}
|
||||
|
||||
bitmap_and(cur_stat, chip->irq_trig_fall, old_stat, gc->ngpio);
|
||||
bitmap_and(old_stat, chip->irq_trig_raise, new_stat, gc->ngpio);
|
||||
bitmap_or(new_stat, old_stat, cur_stat, gc->ngpio);
|
||||
bitmap_and(pending, new_stat, trigger, gc->ngpio);
|
||||
bitmap_or(edges, old_stat, cur_stat, gc->ngpio);
|
||||
bitmap_and(pending, edges, trigger, gc->ngpio);
|
||||
|
||||
bitmap_and(cur_stat, new_stat, chip->irq_trig_level_high, gc->ngpio);
|
||||
bitmap_and(cur_stat, cur_stat, chip->irq_mask, gc->ngpio);
|
||||
bitmap_or(pending, pending, cur_stat, gc->ngpio);
|
||||
|
||||
bitmap_complement(cur_stat, new_stat, gc->ngpio);
|
||||
bitmap_and(cur_stat, cur_stat, reg_direction, gc->ngpio);
|
||||
bitmap_and(old_stat, cur_stat, chip->irq_trig_level_low, gc->ngpio);
|
||||
bitmap_and(old_stat, old_stat, chip->irq_mask, gc->ngpio);
|
||||
bitmap_or(pending, pending, old_stat, gc->ngpio);
|
||||
|
||||
return !bitmap_empty(pending, gc->ngpio);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user