From nobody Sun Feb 8 01:21:27 2026 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4343F36D4F3 for ; Wed, 17 Dec 2025 15:31:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765985490; cv=none; b=U1m5SLSgLAiS4szdIUN4lJTSesC9BRN6S9buri1uMYwNilSj5xbHRqLG4pu9dskQTvkQIzoIwrZYKzwR0//NsHr4ZBhJXEZE6foHEHtu9AFlB3Oseh2rIn11f6gwsBGhF5x5STT+s4Ai6Lx6cQUQTko9C4L6Atg3h099DY2xyak= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765985490; c=relaxed/simple; bh=CMtwWAi2fkoiRarX+6iA9N44M+zhbMk+AqcIvLqsXys=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=iFfo4Augl99xAjagB5h3tP8cZrKNsc/HEd0k0CXkWP2o4eqSaIlBWZUpv27rboAddjHsvUMTTEWfbDbHOlLQXVbs8eVKXxGOpluVmR+FbJ14fsr3KlNo13EznGBUCcyj8N2GD0Oe2KrGyzykh2MhJPj8DSKBf8aS3iW9Top5Wbc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GWH2eSHE; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GWH2eSHE" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-4779cb0a33fso70296855e9.0 for ; Wed, 17 Dec 2025 07:31:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1765985486; x=1766590286; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=RHDQGyujZInuJroxva8Z/Ny8BLqAj/X/TbF4qXI6JtQ=; b=GWH2eSHE296c+HgUJ2zRU7hX1S+QB36mwrJAC9JOL18UCD1XDr7Q0x/04pLD0+pCIF 400CWeBfLVNCF4syCA+kFwBKM6MwcAorLRNtyDQW1ZTSS6Km/zqhoqhajHcBLPDkHvLb +l3O6UPkDEJsW831Ytty243bt383bGUr70jaykYgKPvdV3nAxHsYtpwhuSF0o1GFRyRe T58Paa+kmmucX/0qOh26m3jFDCTxr1KAYGgeU+9gJdPOETSgDZjl/RMD0Fusgow2dGba 8pu/8b1GMlrAG0Qg25FS3I73T2hHi+CIzWnTU2jaZxjkt2phT0YfFIxHCy5iuio5YUFe dEvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765985486; x=1766590286; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=RHDQGyujZInuJroxva8Z/Ny8BLqAj/X/TbF4qXI6JtQ=; b=N/f2TKNncSVdDSFl3MrSE2D2VW8J4qbV7l11bnWrawMUiIsxUAh5AcFo5jxLUbl88b jKEtkWPu7fyKjKQsZIiQHzTXEfvFa24kqVi30FUkT07eVyV/jE2SAXfe1XgkwFN7UjRG 2WUz9MaEsepTfaCr+XInPuPanGWhIcEwEmwhTMyJHp7kc93rwbZBylkIlWYfjYxz8tjC TzUYprknFKJOpgLi3VV22GCWSukjhGu9Q9Sq+sy1Vr3+Zk9Sq+h+ljbcNLzhGtn16LjF 96CsoVK4EBAak6BsZyBmckXXVLE1PcjCcHFSKtza7i+ZvPEqptnjk+1d46vz7pcgCqKd Y1hQ== X-Forwarded-Encrypted: i=1; AJvYcCX03oRXdB61EFnPZtoaoxYPu2jeCAZbA73PEgnfYIq6EEpVQTVYTgkCjCB93lYqtCcFv38LPYeEX8f2onM=@vger.kernel.org X-Gm-Message-State: AOJu0Yy4StPhShx6bKbTl9otILWO72JT/y/VMn8USL0KjX1ucLp4w+Au Toyk+kAizdqZ+9zqaa73a0MEnfVKqHREEUGvO5jvlbuh9RUkiFpMJ2qp X-Gm-Gg: AY/fxX4y2OvFvoteJnFXBvsmqFIlIYxuzH2WhLye5BW/N0scO9Yq5pCu/uCWQXFnXUr j4V4zsCy5U7dsonx6s1a+xCTDaseHwt6kPEpFW+RaOaauJsKB99zDlositvZUND1oRZLrOVfOTk Tr1LNZqIpcSJ9PTwbj1wuAKf4Cyqn2KHYLe1tsTUfFunuPtEqMHv35HeD7EwAM+maVSYAPCfTcb 9zx87FhtIUMYOC0Nm1D5jWYVArBGIk8G2YIdoiJ/KBWY4oU99YZecoQq9bNt2Smpw8debkKsTuB k4fOIZKpvw72VfNFrVha8ThdaDCjsKMj5cTkMHl1AGSWTtR0pBe1bCUG250I4pEGdqKuObMWcx1 H9mQ3rEJXJUo/jzzLQpTYtw/aE6IciK0UjoHZ406HkJKToS1wq8iWZY6Emc8+iVIQmMAT9enl+d OSYWO6CNsQLvlXvSQVlHsZZlwkuW2adp4SqJqBSdvLen4mx0aw12oF16dna/yA3rlbXoIv6E85P HBJVqb2pdHvWmisL3/+8Po= X-Google-Smtp-Source: AGHT+IEb5ar6TM/WR/l3CSudJ9bJ/KvuD26w9G8hDOQq44+5wMBJg8tkAOMbmfbWPSiXDyoVpP+ylA== X-Received: by 2002:a05:600c:6994:b0:477:a54a:acba with SMTP id 5b1f17b1804b1-47a8f904080mr173746195e9.17.1765985486324; Wed, 17 Dec 2025 07:31:26 -0800 (PST) Received: from ernest.corp.toradex.com (248.201.173.83.static.wline.lns.sme.cust.swisscom.ch. [83.173.201.248]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-47bdc1cb6b3sm43272875e9.3.2025.12.17.07.31.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 Dec 2025 07:31:25 -0800 (PST) From: Ernest Van Hoecke To: Linus Walleij , Bartosz Golaszewski , Mark Tomlinson , Andy Shevchenko Cc: Ernest Van Hoecke , Emanuele Ghidoli , Francesco Dolcini , lakabd , Yong Li , linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v1] gpio: pca953x: handle short interrupt pulses on PCAL devices Date: Wed, 17 Dec 2025 16:30:25 +0100 Message-ID: <20251217153050.142057-1-ernestvanhoecke@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Ernest Van Hoecke GPIO drivers with latch input support may miss short pulses on input pins even when input latching is enabled. The generic interrupt logic in the pca953x driver reports interrupts by comparing the current input value against the previously sampled one and only signals an event when a level change is observed between two reads. For short pulses, the first edge is captured when the input register is read, but if the signal returns to its previous level before the read, the second edge is not observed. As a result, successive pulses can produce identical input values at read time and no level change is detected, causing interrupts to be missed. Below timing diagram shows this situation where the top signal is the input pin level and the bottom signal indicates the latched value. =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=90 =E2=94=8C=E2=94= =80=E2=94=80*=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=90 =E2=94=8C=E2=94=80=E2=94=80*=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=90 =E2=94=8C=E2=94= =80=E2=94=80*=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 =E2=94=82 . =E2=94=82 =E2=94=82 . = =E2=94=82 =E2=94=82 . =E2=94=82 =E2=94=82 =E2=94=82 =E2=94=82 =E2=94= =82 =E2=94=82 =E2=94=82 =E2=94=82 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80*=E2=94=80=E2=94=80=E2=94=98 =E2=94=82 = =E2=94=94=E2=94=80=E2=94=80*=E2=94=80=E2=94=80=E2=94=98 =E2=94= =82 =E2=94=94=E2=94=80=E2=94=80*=E2=94=80=E2=94=80=E2=94=98= =E2=94=82 Input =E2=94=82 =E2=94=82 =E2=94=82 =E2=94=82 = =E2=94=82 =E2=94=82 =E2=96=BC =E2=94=82 =E2=96=BC =E2=94=82 = =E2=96=BC =E2=94=82 IRQ =E2=94=82 IRQ =E2=94=82 = IRQ =E2=94=82 . . . =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=90 .=E2=94=8C=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=90 .=E2=94=8C= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =90 .=E2=94=8C=E2=94=80=E2=94=80 =E2=94=82 =E2=94=82 =E2=94=82 =E2=94=82 = =E2=94=82 =E2=94=82 =E2=94=82 =E2=94=82 =E2=94=82 =E2=94=82 = =E2=94=82 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80*=E2=94=98 =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80*=E2=94=98 =E2=94= =94=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= *=E2=94=98 Latched =E2=94=82 =E2=94=82 = =E2=94=82 =E2=96=BC =E2=96=BC = =E2=96=BC READ 0 READ 0 READ 0 NO CHANGE NO CHANGE PCAL variants provide an interrupt status register that records which pins triggered an interrupt, but the status and input registers cannot be read atomically. The interrupt status is only cleared when the input port is read, and the input value must also be read to determine the triggering edge. If another interrupt occurs on a different line after the status register has been read but before the input register is sampled, that event will not be reflected in the earlier status snapshot, so relying solely on the interrupt status register is also insufficient. Support for input latching and interrupt status handling was previously added by [1], but the interrupt status-based logic was reverted by [2] due to these issues. This patch addresses the original problem by combining both sources of information. Events indicated by the interrupt status register are merged with events detected through the existing level-change logic. As a result: * short pulses, whose second edges are invisible, are detected via the interrupt status register, and * interrupts that occur between the status and input reads are still caught by the generic level-change logic. This significantly improves robustness on devices that signal interrupts as short pulses, while avoiding the issues that led to the earlier reversion. In practice, even if only the first edge of a pulse is observable, the interrupt is reliably detected. This fixes missed interrupts from an Ilitek touch controller with its interrupt line connected to a PCAL6416A, where active-low pulses are approximately 200 us long. [1] commit 44896beae605 ("gpio: pca953x: add PCAL9535 interrupt support for= Galileo Gen2") [2] commit d6179f6c6204 ("gpio: pca953x: Improve interrupt support") Fixes: d6179f6c6204 ("gpio: pca953x: Improve interrupt support") Signed-off-by: Ernest Van Hoecke Reviewed-by: Andy Shevchenko --- drivers/gpio/gpio-pca953x.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 0a3916cc2772..8727ae54bc57 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -943,14 +943,35 @@ static bool pca953x_irq_pending(struct pca953x_chip *= chip, unsigned long *pendin DECLARE_BITMAP(old_stat, MAX_LINE); DECLARE_BITMAP(cur_stat, MAX_LINE); DECLARE_BITMAP(new_stat, MAX_LINE); + DECLARE_BITMAP(int_stat, MAX_LINE); DECLARE_BITMAP(trigger, MAX_LINE); DECLARE_BITMAP(edges, MAX_LINE); int ret; =20 + if (chip->driver_data & PCA_PCAL) { + /* Read INT_STAT before it is cleared by the input-port read. */ + ret =3D pca953x_read_regs(chip, PCAL953X_INT_STAT, int_stat); + if (ret) + return false; + } + ret =3D pca953x_read_regs(chip, chip->regs->input, cur_stat); if (ret) return false; =20 + if (chip->driver_data & PCA_PCAL) { + /* Detect short pulses via INT_STAT. */ + bitmap_and(trigger, int_stat, chip->irq_mask, gc->ngpio); + + /* Apply filter for rising/falling edge selection. */ + bitmap_replace(new_stat, chip->irq_trig_fall, chip->irq_trig_raise, + cur_stat, gc->ngpio); + + bitmap_and(int_stat, new_stat, trigger, gc->ngpio); + } else { + bitmap_zero(int_stat, gc->ngpio); + } + /* Remove output pins from the equation */ pca953x_read_regs(chip, chip->regs->direction, reg_direction); =20 @@ -964,7 +985,8 @@ static bool pca953x_irq_pending(struct pca953x_chip *ch= ip, unsigned long *pendin =20 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)) + if (bitmap_empty(trigger, gc->ngpio) && + bitmap_empty(int_stat, gc->ngpio)) return false; } =20 @@ -972,6 +994,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *ch= ip, unsigned long *pendin bitmap_and(old_stat, chip->irq_trig_raise, new_stat, gc->ngpio); bitmap_or(edges, old_stat, cur_stat, gc->ngpio); bitmap_and(pending, edges, trigger, gc->ngpio); + bitmap_or(pending, pending, int_stat, gc->ngpio); =20 bitmap_and(cur_stat, new_stat, chip->irq_trig_level_high, gc->ngpio); bitmap_and(cur_stat, cur_stat, chip->irq_mask, gc->ngpio); --=20 2.43.0