From dae7cae0773c97cb7be78b9f2cd6ec4d7327cf13 Mon Sep 17 00:00:00 2001
From: Tobias Poganiuch <tobias.poganiuch@seco.com>
Date: Tue, 27 Feb 2024 08:34:46 +0000
Subject: [PATCH] driver:pca953x: Disable input latching for level interrupts

For level interrupts, the latching of the inputs is rather unwanted. The
latching might lead to false interrupt states which occur if the input changes
again before the interrupt is completely processed. This can either be
resolved by reading the input status register twice or by disabling the
latching for level interrupt pins. Without the latching, very short level
interrupt changes are ignored. Since we don't want them anyway, we opt for
the second solution.
---
 drivers/gpio/gpio-pca953x.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 4d404d01b97b4..3a97cb2542fdb 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -684,9 +684,24 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 	DECLARE_BITMAP(reg_direction, MAX_LINE);
 	int level;
 
+	bitmap_or(irq_edge_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
+	bitmap_or(irq_level_mask, chip->irq_trig_level_high, chip->irq_trig_level_low, gc->ngpio);
+
 	if (chip->driver_data & PCA_PCAL) {
+		/*
+		 * The irq_trig_* variables contain the interrupts that are enabled
+		 * in the interrupt controller (= this GPIO-Expander).
+		 * The chip->irq_mask contains the interrupts that are actually active
+		 * at the moment. The latching is only activated for the inputs
+		 * that are interrupt-enabled and active right now. Since we only
+		 * want to enable latching for edge interrupts, we combine the irq_edge_mask
+		 * with the chip->irq_mask and then set the result in the latch registers
+		 * of the GPIO-Expander.
+		 */
+		bitmap_and(irq_mask, irq_edge_mask, chip->irq_mask, gc->ngpio);
+
 		/* Enable latch on interrupt-enabled inputs */
-		pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
+		pca953x_write_regs(chip, PCAL953X_IN_LATCH, irq_mask);
 
 		bitmap_complement(irq_mask, chip->irq_mask, gc->ngpio);
 
@@ -697,8 +712,6 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 	/* Switch direction to input if needed */
 	pca953x_read_regs(chip, chip->regs->direction, reg_direction);
 
-	bitmap_or(irq_edge_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
-	bitmap_or(irq_level_mask, chip->irq_trig_level_high, chip->irq_trig_level_low, gc->ngpio);
 	bitmap_or(irq_mask, irq_edge_mask, irq_level_mask, gc->ngpio);
 
 	bitmap_complement(reg_direction, reg_direction, gc->ngpio);
-- 
GitLab