Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: matrix_keypad - detect change during scan

For a setup where the matrix keypad is connected over a slow interface
(e.g. a gpio-expansion over i2c), the scan can take a longer time to read.

Interrupts need to be disabled during scan. And therefore changes in this
period are not detected.
To improve this situation, scan the matrix again if the row state changed
during interrupts disabled.
The rescan is repeated until no change is detected anymore.

Signed-off-by: Markus Burri <markus.burri@mt.com>
Link: https://lore.kernel.org/r/20250226152843.43932-4-markus.burri@mt.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Markus Burri and committed by
Dmitry Torokhov
353bdd7d a37af8e8

+16
+16
drivers/input/keyboard/matrix_keypad.c
··· 125 125 const unsigned short *keycodes = input_dev->keycode; 126 126 uint32_t new_state[MATRIX_MAX_COLS]; 127 127 int row, col, code; 128 + u32 init_row_state, new_row_state; 129 + 130 + /* read initial row state to detect changes between scan */ 131 + init_row_state = read_row_state(keypad); 128 132 129 133 /* de-activate all columns for scanning */ 130 134 activate_all_cols(keypad, false); ··· 176 172 scoped_guard(spinlock_irq, &keypad->lock) { 177 173 keypad->scan_pending = false; 178 174 enable_row_irqs(keypad); 175 + } 176 + 177 + /* read new row state and detect if value has changed */ 178 + new_row_state = read_row_state(keypad); 179 + if (init_row_state != new_row_state) { 180 + guard(spinlock_irq)(&keypad->lock); 181 + if (unlikely(keypad->scan_pending || keypad->stopped)) 182 + return; 183 + disable_row_irqs(keypad); 184 + keypad->scan_pending = true; 185 + schedule_delayed_work(&keypad->work, 186 + msecs_to_jiffies(keypad->debounce_ms)); 179 187 } 180 188 } 181 189