Documentation: gpio: pca953x: clarify interrupt source detection

There are multiple design tradeoffs and considerations in how the
PCA953x driver detects the source(s) of an interrupt. This driver
supports PCAL variants with input latching, a feature that is
constrained by the fact that the interrupt status and input port
registers cannot be read atomically. These limits and the design
decisions deserve an in-depth explanation.

Update the documentation to clarify these hardware limits and describe
how the driver determines pending interrupts, and how it makes use of
the PCAL input latching.

Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20260107093125.4053468-1-ernestvanhoecke@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
This commit is contained in:
Ernest Van Hoecke 2026-01-07 10:31:22 +01:00 committed by Bartosz Golaszewski
parent da64eb5159
commit 8ba379879a

View file

@ -389,6 +389,13 @@ disabled.
Currently the driver enables the latch for each line with interrupt
enabled.
An interrupt status register records which pins triggered an interrupt.
However, the status register and the input port register must be read
separately; there is no atomic mechanism to read both simultaneously, so races
are possible. Refer to the chapter `Interrupt source detection`_ to understand
the implications of this and how the driver still makes use of the latching
feature.
1. base offset 0x40, bank 2, bank offsets of 2^n
- pcal6408
- pcal6416
@ -523,6 +530,74 @@ bits drive strength
Currently not supported by the driver.
Interrupt source detection
==========================
When triggered by the GPIO expander's interrupt, the driver determines which
IRQs are pending by reading the input port register.
To be able to filter on specific interrupt events for all compatible devices,
the driver keeps track of the previous input state of the lines, and emits an
IRQ only for the correct edge or level. This system works irrespective of the
number of enabled interrupts. Events will not be missed even if they occur
between the GPIO expander's interrupt and the actual I2C read. Edges could of
course be missed if the related signal level changes back to the value
previously saved by the driver before the I2C read. PCAL variants offer input
latching for that reason.
PCAL input latching
-------------------
The PCAL variants have an input latch and the driver enables this for all
interrupt-enabled lines. The interrupt is then only cleared when the input port
is read out. These variants provide an interrupt status register that records
which pins triggered an interrupt, but the status and input registers cannot be
read atomically. If another interrupt occurs on a different line after the
status register has been read but before the input port register is sampled,
that event will not be reflected in the earlier status snapshot, so relying
solely on the interrupt status register is insufficient.
Thus, the PCAL variants also have to use the existing level-change logic.
For short pulses, the first edge is captured when the input register is read,
but if the signal returns to its previous level before this 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::
─────┐ ┌──*───────────────┐ ┌──*─────────────────┐ ┌──*───
│ │ . │ │ . │ │ .
│ │ │ │ │ │ │ │ │
└──*──┘ │ └──*──┘ │ └──*──┘ │
Input │ │ │ │ │ │
▼ │ ▼ │ ▼ │
IRQ │ IRQ │ IRQ │
. . .
─────┐ .┌──────────────┐ .┌────────────────┐ .┌──
│ │ │ │ │ │
│ │ │ │ │ │
└────────*┘ └────────*┘ └────────*┘
Latched │ │ │
▼ ▼ ▼
READ 0 READ 0 READ 0
NO CHANGE NO CHANGE
To deal with this, 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.
Note that this is still best-effort: the status and input registers are read
separately, and short pulses on other lines may occur in between those reads.
Such pulses can still be latched as an interrupt without leaving an observable
level change at read time, and may not be attributable to a specific edge. This
does not reduce detection compared to the generic path, but reflects inherent
atomicity limitations.
Datasheets
==========