This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new ef71625eded input: add keyboard matrix driver
ef71625eded is described below
commit ef71625eded3e5795733b32216188c0ffee28837
Author: Felipe Moura <[email protected]>
AuthorDate: Sun Feb 8 11:46:26 2026 -0300
input: add keyboard matrix driver
Add a generic kmatrix lower-half with polling/debounce, STM32 board
adapters, Kconfig options, a public API header, and a test
example/documentation.
Signed-off-by: Felipe Moura <[email protected]>
decouple kbd / keypad.
Fix some comments
add documentation
fix rule issues
Update CMakeLists.txt
update documentation.
improve documentation
---
.../character/input/images/keypad-example.png | 1 +
.../components/drivers/character/input/index.rst | 1 +
.../input/{keypad.rst => keypad-keyboard.rst} | 9 +-
.../components/drivers/character/input/keypad.rst | 217 +++++-------
.../arm/stm32/common/include/stm32_kmatrix_gpio.h | 87 +++++
.../arm/stm32/common/include/stm32_kmatrix_i2c.h | 87 +++++
boards/arm/stm32/common/src/CMakeLists.txt | 8 +
boards/arm/stm32/common/src/Make.defs | 8 +
boards/arm/stm32/common/src/stm32_kmatrix_gpio.c | 355 ++++++++++++++++++++
boards/arm/stm32/common/src/stm32_kmatrix_i2c.c | 210 ++++++++++++
boards/arm/stm32/stm32f4discovery/Kconfig | 19 ++
boards/arm/stm32/stm32f4discovery/include/board.h | 72 ++++
.../arm/stm32/stm32f4discovery/src/stm32_bringup.c | 29 ++
drivers/input/CMakeLists.txt | 8 +
drivers/input/Kconfig | 68 +++-
drivers/input/Make.defs | 8 +
drivers/input/kmatrix.c | 362 +++++++++++++++++++++
drivers/input/kmatrix_i2c.c | 262 +++++++++++++++
include/nuttx/input/kmatrix.h | 160 +++++++++
19 files changed, 1828 insertions(+), 143 deletions(-)
diff --git
a/Documentation/components/drivers/character/input/images/keypad-example.png
b/Documentation/components/drivers/character/input/images/keypad-example.png
new file mode 100644
index 00000000000..9fb4ea439c4
--- /dev/null
+++ b/Documentation/components/drivers/character/input/images/keypad-example.png
@@ -0,0 +1 @@
+<binary image placeholder>
\ No newline at end of file
diff --git a/Documentation/components/drivers/character/input/index.rst
b/Documentation/components/drivers/character/input/index.rst
index c1317ebd493..3ef4746c003 100644
--- a/Documentation/components/drivers/character/input/index.rst
+++ b/Documentation/components/drivers/character/input/index.rst
@@ -5,6 +5,7 @@ Input Devices
.. toctree::
:caption: Supported Drivers
+ keypad-keyboard.rst
keypad.rst
sbutton.rst
diff --git a/Documentation/components/drivers/character/input/keypad.rst
b/Documentation/components/drivers/character/input/keypad-keyboard.rst
similarity index 95%
copy from Documentation/components/drivers/character/input/keypad.rst
copy to Documentation/components/drivers/character/input/keypad-keyboard.rst
index 3724b8daa59..5e726b887dd 100644
--- a/Documentation/components/drivers/character/input/keypad.rst
+++ b/Documentation/components/drivers/character/input/keypad-keyboard.rst
@@ -2,9 +2,10 @@
Keyboard/Keypad Drivers
=======================
-**Keypads vs. Keyboards** Keyboards and keypads are really the
-same devices for NuttX. A keypad is thought of as simply a
-keyboard with fewer keys.
+
+**Keypads vs. Keyboards** Keyboards and keypads are really the same
+devices for NuttX. A keypad is thought of as simply a keyboard with
+fewer keys.
**Special Commands**. In NuttX, a keyboard/keypad driver is simply
a character driver that may have an (optional) encoding/decoding
@@ -30,7 +31,7 @@ can be used with the basic character driver to encode the
keyboard
events into the text data stream. The function interfaces that
comprise that encoding/decoding layer are defined in the header
file ``include/nuttx/input/kbd_code.h``. These functions provide
-an matched set of (a) driver encoding interfaces, and (b)
+a matched set of (a) driver encoding interfaces, and (b)
application decoding interfaces.
#. **Driver Encoding Interfaces**. These are interfaces used by
diff --git a/Documentation/components/drivers/character/input/keypad.rst
b/Documentation/components/drivers/character/input/keypad.rst
index 3724b8daa59..93d357bc7ac 100644
--- a/Documentation/components/drivers/character/input/keypad.rst
+++ b/Documentation/components/drivers/character/input/keypad.rst
@@ -1,142 +1,83 @@
=======================
-Keyboard/Keypad Drivers
+Matrix Keypad (KMATRIX)
=======================
-**Keypads vs. Keyboards** Keyboards and keypads are really the
-same devices for NuttX. A keypad is thought of as simply a
-keyboard with fewer keys.
-
-**Special Commands**. In NuttX, a keyboard/keypad driver is simply
-a character driver that may have an (optional) encoding/decoding
-layer on the data returned by the character driver. A keyboard may
-return simple text data (alphabetic, numeric, and punctuation) or
-control characters (enter, control-C, etc.) when a key is pressed.
-We can think about this the "normal" keyboard data stream.
-However, in addition, most keyboards support actions that cannot
-be represented as text or control data. Such actions include
-things like cursor controls (home, up arrow, page down, etc.),
-editing functions (insert, delete, etc.), volume controls, (mute,
-volume up, etc.) and other special functions. In this case, some
-special encoding may be required to multiplex the normal text data
-and special command key press data streams.
-
-**Key Press and Release Events** Sometimes the time that a key is
-released is needed by applications as well. Thus, in addition to
-normal and special key press events, it may also be necessary to
-encode normal and special key release events.
-
-**Encoding/Decoding** Layer. An optional encoding/decoding layer
-can be used with the basic character driver to encode the keyboard
-events into the text data stream. The function interfaces that
-comprise that encoding/decoding layer are defined in the header
-file ``include/nuttx/input/kbd_code.h``. These functions provide
-an matched set of (a) driver encoding interfaces, and (b)
-application decoding interfaces.
-
-#. **Driver Encoding Interfaces**. These are interfaces used by
- the keyboard/keypad driver to encode keyboard events and data.
-
- - ``kbd_press()``
-
- **Function Prototype:**
-
- **Description:**
-
- **Input Parameters:**
-
- - ``ch``: The character to be added to the output stream.
- - ``stream``: An instance of ``lib_outstream_s`` to perform
- the actual low-level put operation.
-
- **Returned Value:**
-
- - ``kbd_release()``
-
- **Function Prototype:**
-
- **Description:**
-
- **Input Parameters:**
-
- - ``ch``: The character associated with the key that was
- released.
- - ``stream``: An instance of ``lib_outstream_s`` to perform
- the actual low-level put operation.
-
- **Returned Value:**
-
- - ``kbd_specpress()``
-
- **Function Prototype:**
-
- **Description:**
-
- **Input Parameters:**
-
- - ``keycode``: The command to be added to the output
- stream. The enumeration ``enum kbd_keycode_e keycode``
- identifies all commands known to the system.
- - ``stream``: An instance of ``lib_outstream_s`` to perform
- the actual low-level put operation.
-
- **Returned Value:**
-
- - ``kbd_specrel()``
-
- **Function Prototype:**
-
- **Description:**
-
- **Input Parameters:**
-
- - ``keycode``: The command to be added to the output
- stream. The enumeration ``enum kbd_keycode_e keycode``
- identifies all commands known to the system.
- - ``stream``: An instance of ``lib_outstream_s`` to perform
- the actual low-level put operation.
-
- **Returned Value:**
-
-#. **Application Decoding Interfaces**. These are user interfaces
- to decode the values returned by the keyboard/keypad driver.
-
- - ``kbd_decode()``
-
- **Function Prototype:**
-
- **Description:**
-
- **Input Parameters:**
-
- - ``stream``: An instance of ``lib_instream_s`` to perform
- the actual low-level get operation.
- - ``pch``: The location to save the returned value. This
- may be either a normal, character code or a special
- command (i.e., a value from ``enum kbd_getstate_s``.
- - ``state``: A user provided buffer to support parsing.
- This structure should be cleared the first time that
- ``kbd_decode()`` is called.
-
- **Returned Value:**
-
- - ``KBD_PRESS`` (0)**: Indicates the successful receipt
- of normal, keyboard data. This corresponds to a keypress
- event. The returned value in ``pch`` is a simple byte of
- text or control data.
- - ``KBD_RELEASE`` (1)**: Indicates a key release event.
- The returned value in ``pch`` is the byte of text or
- control data corresponding to the released key.
- - ``KBD_SPECPRESS`` (2)**: Indicates the successful
- receipt of a special keyboard command. The returned value
- in ``pch`` is a value from ``enum kbd_getstate_s``.
- - ``KBD_SPECREL`` (3)**: Indicates a special command key
- release event. The returned value in ``pch`` is a value
- from ``enum kbd_getstate_s``.
- - ``KBD_ERROR`` (``EOF``)**: An error has getting the
- next character (reported by the ``stream``). Normally
- indicates the end of file.
-
-**I/O Streams**. Notice the use of the abstract I/O streams in
-these interfaces. These stream interfaces are defined in
-``include/nuttx/streams.h``.
+**What is a Keypad?**
+A keypad is a small keyboard with a limited set of keys, typically
+arranged in a matrix. It is commonly used for numeric input, access
+control, or simple user interfaces.
+
+For example, a typical 12-key numeric keypad looks like this:
+
+.. image:: images/keypad-example.png
+ :alt: Example of a 12-key matrix keypad
+ :align: center
+ :width: 200px
+
+**Purpose**. The KMATRIX driver provides a generic keypad
+implementation for boards that expose a switch matrix through GPIOs.
+It periodically scans rows and columns, detects state changes with a
+simple debounce, and emits keyboard events through the common keyboard
+upper-half. This makes the device available as a character driver
+(e.g., ``/dev/keypad0``) using the standard keyboard
+interfaces.
+
+**Why Polling**. This first version uses polling to be broadly usable
+on any board with available GPIOs, without requiring per-board IRQ
+wiring, pin interrupt capabilities, or expander-specific interrupt
+support. Polling also simplifies early bring-up and makes the driver
+predictable while the keymap and GPIO configuration are validated.
+Future iterations are expected to add interrupt-driven scanning and
+I2C expander variants; the GPIO polling path remains a good baseline
+and fallback.
+
+**Driver Overview**. The KMATRIX lower-half scans the matrix and calls
+``keyboard_event()`` when it detects a press or release. The keyboard
+upper-half registers the character device at the requested ``devpath``
+and stores events in a circular buffer. Applications read
+``struct keyboard_event_s`` from the device or use the optional
+kbd-codec layer.
+
+**Board Support**. To support KMATRIX, a board must provide:
+
+#. **GPIO Definitions**
+
+ - Define the row and column GPIOs (arrays of pins).
+ - Provide a keymap array indexed by ``row * ncols + col``.
+
+#. **Configuration Callbacks**
+
+ - ``config_row(pin)``: Configure a row GPIO as output.
+ - ``config_col(pin)``: Configure a column GPIO as input with pull-up
+ or pull-down consistent with the wiring.
+ - ``row_set(pin, active)``: Drive a row active/inactive. For the
+ STM32F4Discovery example, rows are driven low to activate.
+ - ``col_get(pin)``: Read a column and return ``true`` when pressed.
+
+#. **Registration Hook**
+
+ - Implement ``board_kmatrix_initialize(const char *devpath)`` to
+ call ``kmatrix_register(&config, devpath)``.
+ - Invoke the board hook during bring-up (for example,
+ ``board_kmatrix_initialize("/dev/keypad0")``).
+
+**Reference Implementation (STM32F4Discovery)**. The current reference
+is in ``boards/arm/stm32/common/src/stm32_kmatrix_gpio.c``:
+
+- Rows: ``BOARD_KMATRIX_ROW0..3`` (outputs)
+- Columns: ``BOARD_KMATRIX_COL0..2`` (inputs with pull-up)
+- Keymap: 4x3 phone keypad layout
+- Callbacks: ``km_stm32_config_row``, ``km_stm32_config_col``,
+ ``km_stm32_row_set``, ``km_stm32_col_get``
+- Registration: ``board_kmatrix_initialize()`` calls
+ ``kmatrix_register()``
+
+**Data Path Summary**.
+
+- Board calls ``board_kmatrix_initialize("/dev/keypad0")``
+- ``kmatrix_register()`` configures GPIOs and calls
+ ``keyboard_register(&lower, devpath, buflen)``
+- The upper-half registers the device node at ``devpath``
+- ``kmatrix_scan_worker()`` calls ``keyboard_event()`` on press/release
+- Applications read events from the device node
diff --git a/boards/arm/stm32/common/include/stm32_kmatrix_gpio.h
b/boards/arm/stm32/common/include/stm32_kmatrix_gpio.h
new file mode 100644
index 00000000000..6615fcc9b36
--- /dev/null
+++ b/boards/arm/stm32/common/include/stm32_kmatrix_gpio.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+ * boards/arm/stm32/common/include/stm32_kmatrix_gpio.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_GPIO_H
+#define __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_GPIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_kmatrix_initialize
+ *
+ * Description:
+ * This function is called by application-specific setup logic to
+ * configure the keyboard matrix device.
+ *
+ * Input Parameters:
+ * devpath - The device path, typically "/dev/kbd0"
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno value is
+ * returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int board_kmatrix_initialize(const char *devpath);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_GPIO_H */
diff --git a/boards/arm/stm32/common/include/stm32_kmatrix_i2c.h
b/boards/arm/stm32/common/include/stm32_kmatrix_i2c.h
new file mode 100644
index 00000000000..82669a943db
--- /dev/null
+++ b/boards/arm/stm32/common/include/stm32_kmatrix_i2c.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+ * boards/arm/stm32/common/include/stm32_kmatrix_i2c.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_I2C_H
+#define __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_I2C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_kmatrix_i2c_initialize
+ *
+ * Description:
+ * This function is called by application-specific setup logic to
+ * configure the keyboard matrix device using an I2C GPIO expander.
+ *
+ * Input Parameters:
+ * devpath - The device path, typically "/dev/kbd0"
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno value is
+ * returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int board_kmatrix_i2c_initialize(const char *devpath);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_I2C_H */
diff --git a/boards/arm/stm32/common/src/CMakeLists.txt
b/boards/arm/stm32/common/src/CMakeLists.txt
index d13a75b1a4d..acbd4200a7f 100644
--- a/boards/arm/stm32/common/src/CMakeLists.txt
+++ b/boards/arm/stm32/common/src/CMakeLists.txt
@@ -158,4 +158,12 @@ if(CONFIG_INPUT_SBUTTON)
list(APPEND SRCS stm32_sbutton.c)
endif()
+if(CONFIG_INPUT_KMATRIX)
+ list(APPEND SRCS stm32_kmatrix_gpio.c)
+endif()
+
+if(CONFIG_INPUT_KMATRIX_I2C)
+ list(APPEND SRCS stm32_kmatrix_i2c.c)
+endif()
+
target_sources(board PRIVATE ${SRCS})
diff --git a/boards/arm/stm32/common/src/Make.defs
b/boards/arm/stm32/common/src/Make.defs
index 1048df7d17a..a86d230436e 100644
--- a/boards/arm/stm32/common/src/Make.defs
+++ b/boards/arm/stm32/common/src/Make.defs
@@ -166,6 +166,14 @@ ifeq ($(CONFIG_INPUT_SBUTTON),y)
CSRCS += stm32_sbutton.c
endif
+ifeq ($(CONFIG_INPUT_KMATRIX),y)
+ CSRCS += stm32_kmatrix_gpio.c
+endif
+
+ifeq ($(CONFIG_INPUT_KMATRIX_I2C),y)
+ CSRCS += stm32_kmatrix_i2c.c
+endif
+
DEPPATH += --dep-path src
VPATH += :src
CFLAGS +=
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
diff --git a/boards/arm/stm32/common/src/stm32_kmatrix_gpio.c
b/boards/arm/stm32/common/src/stm32_kmatrix_gpio.c
new file mode 100644
index 00000000000..fd107c71687
--- /dev/null
+++ b/boards/arm/stm32/common/src/stm32_kmatrix_gpio.c
@@ -0,0 +1,355 @@
+/****************************************************************************
+ * boards/arm/stm32/common/src/stm32_kmatrix_gpio.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <debug.h>
+#include <unistd.h>
+
+#include <nuttx/board.h>
+#include <arch/board/board.h>
+#include <nuttx/input/kmatrix.h>
+
+#include "stm32.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef uint32_t kmatrix_pin_t;
+
+struct stm32_kmatrix_gpio_config_s
+{
+ /* Configuration structure as seen by the kmatrix driver */
+
+ struct kmatrix_config_s config;
+
+ /* Additional private definitions only known to this driver */
+
+ void *arg; /* Argument to pass if needed */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void km_stm32_config_row(kmatrix_pin_t pin);
+static void km_stm32_config_col(kmatrix_pin_t pin);
+static void km_stm32_row_set(kmatrix_pin_t pin, bool active);
+static bool km_stm32_col_get(kmatrix_pin_t pin);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Row and column GPIO pin definitions for 4x3 keypad matrix on
+ * STM32F4Discovery
+ * Rows: PB0-PB3 (outputs)
+ * Columns: PC0-PC2 (inputs with pull-up)
+ */
+
+static const kmatrix_pin_t g_km_rows[] =
+{
+ BOARD_KMATRIX_ROW0,
+ BOARD_KMATRIX_ROW1,
+ BOARD_KMATRIX_ROW2,
+ BOARD_KMATRIX_ROW3,
+};
+
+static const kmatrix_pin_t g_km_cols[] =
+{
+ BOARD_KMATRIX_COL0,
+ BOARD_KMATRIX_COL1,
+ BOARD_KMATRIX_COL2,
+};
+
+/* Keymap for 4x3 matrix - Standard phone keypad layout
+ * Rows: 0-3, Columns: 0-2
+ */
+
+static const uint32_t g_km_keymap[] =
+{
+ '1', '2', '3', /* Row 0 */
+ '4', '5', '6', /* Row 1 */
+ '7', '8', '9', /* Row 2 */
+ '*', '0', '#', /* Row 3 */
+};
+
+/* A reference to a structure of this type must be passed to the kmatrix
+ * driver. This structure provides information about the configuration
+ * of the keypad matrix and provides GPIO callbacks.
+ *
+ * Memory for this structure is provided by the caller. It is not copied
+ * by the driver and is presumed to persist while the driver is active.
+ */
+
+static struct stm32_kmatrix_gpio_config_s g_km_config =
+{
+ .config =
+ {
+ .nrows = 4,
+ .ncols = 3,
+ .rows = g_km_rows,
+ .cols = g_km_cols,
+ .keymap = g_km_keymap,
+ .poll_interval_ms = CONFIG_INPUT_KMATRIX_POLL_MS,
+ .config_row = km_stm32_config_row,
+ .config_col = km_stm32_config_col,
+ .row_set = km_stm32_row_set,
+ .col_get = km_stm32_col_get,
+ },
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: km_stm32_config_row
+ *
+ * Description:
+ * Configure a row GPIO pin as an output
+ *
+ ****************************************************************************/
+
+static void km_stm32_config_row(kmatrix_pin_t pin)
+{
+ iinfo("Configuring row pin as output\n");
+ stm32_configgpio(pin);
+ stm32_gpiowrite(pin, true); /* Initialize to inactive (high) */
+}
+
+/****************************************************************************
+ * Name: km_stm32_config_col
+ *
+ * Description:
+ * Configure a column GPIO pin as an input with pull-up
+ *
+ ****************************************************************************/
+
+static void km_stm32_config_col(kmatrix_pin_t pin)
+{
+ iinfo("Configuring column pin as input\n");
+ stm32_configgpio(pin);
+}
+
+/****************************************************************************
+ * Name: km_stm32_row_set
+ *
+ * Description:
+ * Activate or deactivate a row (logic: active=true sets to 0/low to
+ * activate the row, active=false sets to 1/high to deactivate)
+ *
+ ****************************************************************************/
+
+static void km_stm32_row_set(kmatrix_pin_t pin, bool active)
+{
+ /* With diodes, we drive rows low to activate.
+ * active=true -> write 0 (low)
+ * active=false -> write 1 (high)
+ */
+
+ stm32_gpiowrite(pin, active ? 0 : 1);
+}
+
+/****************************************************************************
+ * Name: km_stm32_col_get
+ *
+ * Description:
+ * Read the state of a column GPIO pin
+ *
+ ****************************************************************************/
+
+static bool km_stm32_col_get(kmatrix_pin_t pin)
+{
+ /* With pull-up resistors:
+ * Key pressed -> column goes low (0) when row is driven low
+ * Key released -> column stays high (1)
+ * Return true when pressed (low), false when released (high)
+ */
+
+ return !stm32_gpioread(pin);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_kmatrix_initialize
+ *
+ * Description:
+ * This function is called by application-specific setup logic to
+ * configure the keyboard matrix device.
+ *
+ * Input Parameters:
+ * devpath - The device path, typically "/dev/keypad0"
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno value is
+ * returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int board_kmatrix_initialize(const char *devpath)
+{
+ iinfo("Initializing keyboard matrix at %s\n", devpath);
+
+ /* Register the keyboard matrix with the generic driver */
+
+ return kmatrix_register(&g_km_config.config, devpath);
+}
+
+int board_kmatrix_diag(int loops, int delay_ms)
+{
+ int iter = 0;
+ uint8_t last_bits[4] =
+ {
+ 0xff, 0xff, 0xff, 0xff
+ };
+
+ const useconds_t pulse_us = 200000;
+
+ iinfo("KMATRIX diag: pin identify pulses (disconnect keypad)\n");
+ for (unsigned int r = 0; r < g_km_config.config.nrows; r++)
+ {
+ iinfo("Pulse ROW%u\n", r + 1);
+ stm32_configgpio(g_km_rows[r]);
+ stm32_gpiowrite(g_km_rows[r], true);
+ usleep(pulse_us);
+ stm32_gpiowrite(g_km_rows[r], false);
+ usleep(pulse_us);
+ stm32_gpiowrite(g_km_rows[r], true);
+ usleep(pulse_us);
+ }
+
+ iinfo("KMATRIX diag: column pulses require BOARD_KMATRIX_COLx_OUT\n");
+#ifdef BOARD_KMATRIX_COL0_OUT
+ iinfo("Pulse COL1 (output mode)\n");
+ stm32_configgpio(BOARD_KMATRIX_COL0_OUT);
+ stm32_gpiowrite(BOARD_KMATRIX_COL0_OUT, true);
+ usleep(pulse_us);
+ stm32_gpiowrite(BOARD_KMATRIX_COL0_OUT, false);
+ usleep(pulse_us);
+ stm32_gpiowrite(BOARD_KMATRIX_COL0_OUT, true);
+ usleep(pulse_us);
+#endif
+
+#ifdef BOARD_KMATRIX_COL1_OUT
+ iinfo("Pulse COL2 (output mode)\n");
+ stm32_configgpio(BOARD_KMATRIX_COL1_OUT);
+ stm32_gpiowrite(BOARD_KMATRIX_COL1_OUT, true);
+ usleep(pulse_us);
+ stm32_gpiowrite(BOARD_KMATRIX_COL1_OUT, false);
+ usleep(pulse_us);
+ stm32_gpiowrite(BOARD_KMATRIX_COL1_OUT, true);
+ usleep(pulse_us);
+#endif
+
+#ifdef BOARD_KMATRIX_COL2_OUT
+ iinfo("Pulse COL3 (output mode)\n");
+ stm32_configgpio(BOARD_KMATRIX_COL2_OUT);
+ stm32_gpiowrite(BOARD_KMATRIX_COL2_OUT, true);
+ usleep(pulse_us);
+ stm32_gpiowrite(BOARD_KMATRIX_COL2_OUT, false);
+ usleep(pulse_us);
+ stm32_gpiowrite(BOARD_KMATRIX_COL2_OUT, true);
+ usleep(pulse_us);
+#endif
+
+ for (unsigned int r = 0; r < g_km_config.config.nrows; r++)
+ {
+ km_stm32_config_row(g_km_rows[r]);
+ stm32_gpiowrite(g_km_rows[r], true);
+ }
+
+ for (unsigned int c = 0; c < g_km_config.config.ncols; c++)
+ {
+ km_stm32_config_col(g_km_cols[c]);
+ }
+
+ iinfo("KMATRIX diag: loops=%d delay_ms=%d\n", loops, delay_ms);
+
+ while (loops <= 0 || iter < loops)
+ {
+ for (unsigned int r = 0; r < g_km_config.config.nrows; r++)
+ {
+ for (unsigned int rr = 0; rr < g_km_config.config.nrows; rr++)
+ {
+ stm32_gpiowrite(g_km_rows[rr], true);
+ }
+
+ stm32_gpiowrite(g_km_rows[r], false);
+ usleep(1000);
+
+ if (g_km_config.config.ncols == 3)
+ {
+ bool b0 = stm32_gpioread(g_km_cols[0]);
+ bool b1 = stm32_gpioread(g_km_cols[1]);
+ bool b2 = stm32_gpioread(g_km_cols[2]);
+ uint8_t bits = (b0 ? 1 : 0) |
+ (b1 ? 2 : 0) |
+ (b2 ? 4 : 0);
+
+ if (bits != last_bits[r])
+ {
+ iinfo("ROW=%u COLS(raw)=%d%d%d\n",
+ r + 1, b0 ? 1 : 0, b1 ? 1 : 0, b2 ? 1 : 0);
+ last_bits[r] = bits;
+ }
+ }
+
+ for (unsigned int c = 0; c < g_km_config.config.ncols; c++)
+ {
+ bool pressed = !stm32_gpioread(g_km_cols[c]);
+ if (pressed)
+ {
+ iinfo("ROW=%u COL=%u\n", r + 1, c + 1);
+ while (!stm32_gpioread(g_km_cols[c]))
+ {
+ usleep(1000);
+ }
+ }
+ }
+ }
+
+ if (delay_ms > 0)
+ {
+ usleep(delay_ms * 1000);
+ }
+
+ iter++;
+ }
+
+ return OK;
+}
diff --git a/boards/arm/stm32/common/src/stm32_kmatrix_i2c.c
b/boards/arm/stm32/common/src/stm32_kmatrix_i2c.c
new file mode 100644
index 00000000000..da8ab87a60e
--- /dev/null
+++ b/boards/arm/stm32/common/src/stm32_kmatrix_i2c.c
@@ -0,0 +1,210 @@
+/****************************************************************************
+ * boards/arm/stm32/common/src/stm32_kmatrix_i2c.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/input/kmatrix.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/ioexpander/ioexpander.h>
+
+#include <arch/board/board.h>
+
+#include "stm32.h"
+#include "stm32_i2c.h"
+
+#ifdef CONFIG_IOEXPANDER_MCP23X08
+# include <nuttx/ioexpander/mcp23x08.h>
+#endif
+
+#ifdef CONFIG_IOEXPANDER_PCA9538
+# include <nuttx/ioexpander/pca9538.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+typedef uint32_t kmatrix_pin_t;
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Row and column pin definitions for 4x3 keypad matrix via I2C expander
+ *
+ * For MCP23X08/PCA9538 I2C expanders, pins are numbered 0-7.
+ *
+ * Example mapping:
+ * Rows (outputs): Pins 0-3
+ * Columns (inputs): Pins 4-6 (with pull-ups)
+ */
+
+static const kmatrix_pin_t g_km_rows[] =
+{
+ 0, 1, 2, 3, /* Row 0-3: Output pins on expander */
+};
+
+static const kmatrix_pin_t g_km_cols[] =
+{
+ 4, 5, 6, /* Col 0-2: Input pins on expander (with pull-up) */
+};
+
+/* Keymap for 4x3 matrix - Standard phone keypad layout
+ * Rows: 0-3, Columns: 0-2
+ */
+
+static const uint32_t g_km_keymap[] =
+{
+ '1', '2', '3', /* Row 0 */
+ '4', '5', '6', /* Row 1 */
+ '7', '8', '9', /* Row 2 */
+ '*', '0', '#', /* Row 3 */
+};
+
+/* Get callbacks from I2C driver */
+
+extern FAR struct kmatrix_callbacks_s *kmatrix_i2c_get_callbacks(void);
+
+/* Keyboard matrix configuration structure
+ * Callbacks are set in board_kmatrix_i2c_initialize.
+ */
+
+static struct kmatrix_config_s g_km_i2c_config =
+{
+ .nrows = 4,
+ .ncols = 3,
+ .rows = g_km_rows,
+ .cols = g_km_cols,
+ .keymap = g_km_keymap,
+ .poll_interval_ms = CONFIG_INPUT_KMATRIX_POLL_MS,
+};
+
+/* IO expander configuration */
+
+#ifdef CONFIG_IOEXPANDER_MCP23X08
+static struct mcp23x08_config_s g_mcp23x08_config =
+{
+ .address = CONFIG_STM32_KMATRIX_I2C_ADDR,
+ .frequency = CONFIG_STM32_KMATRIX_I2C_FREQ,
+};
+#endif
+
+#ifdef CONFIG_IOEXPANDER_PCA9538
+static struct pca9538_config_s g_pca9538_config =
+{
+ .address = CONFIG_STM32_KMATRIX_I2C_ADDR,
+ .frequency = CONFIG_STM32_KMATRIX_I2C_FREQ,
+};
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/**
+ * Name: board_kmatrix_i2c_initialize
+ *
+ * Description:
+ * Initialize keyboard matrix driver using I2C GPIO expander.
+ * This function is called by stm32_bringup.c during initialization.
+ *
+ * Input Parameters:
+ * devpath - Device path (e.g., "/dev/kbd0")
+ *
+ * Returned Value:
+ * Zero on success; negated errno on failure.
+ */
+
+int board_kmatrix_i2c_initialize(const char *devpath)
+{
+ FAR struct i2c_master_s *i2c;
+ FAR struct ioexpander_dev_s *ioe;
+ FAR struct kmatrix_callbacks_s *callbacks;
+ int ret;
+
+ iinfo("Initializing keyboard matrix via I2C expander\n");
+
+ /* Initialize I2C bus */
+
+ i2c = stm32_i2cbus_initialize(CONFIG_STM32_KMATRIX_I2C_BUS);
+ if (i2c == NULL)
+ {
+ ierr("ERROR: Failed to initialize I2C bus %d\n",
+ CONFIG_STM32_KMATRIX_I2C_BUS);
+ return -ENODEV;
+ }
+
+ /* Initialize IO expander */
+
+#ifdef CONFIG_IOEXPANDER_MCP23X08
+ ioe = mcp23x08_initialize(i2c, &g_mcp23x08_config);
+ if (ioe == NULL)
+ {
+ ierr("ERROR: Failed to initialize MCP23X08\n");
+ stm32_i2cbus_uninitialize(i2c);
+ return -ENODEV;
+ }
+
+ iinfo("MCP23X08 initialized at 0x%02x\n", CONFIG_STM32_KMATRIX_I2C_ADDR);
+#elif defined(CONFIG_IOEXPANDER_PCA9538)
+ ioe = pca9538_initialize(i2c, &g_pca9538_config);
+ if (ioe == NULL)
+ {
+ ierr("ERROR: Failed to initialize PCA9538\n");
+ stm32_i2cbus_uninitialize(i2c);
+ return -ENODEV;
+ }
+
+ iinfo("PCA9538 initialized at 0x%02x\n", CONFIG_STM32_KMATRIX_I2C_ADDR);
+#else
+# error "No IO expander configured"
+#endif
+
+ /* Get callbacks from I2C driver */
+
+ callbacks = kmatrix_i2c_get_callbacks();
+ g_km_i2c_config.config_row = callbacks->config_row;
+ g_km_i2c_config.config_col = callbacks->config_col;
+ g_km_i2c_config.row_set = callbacks->row_set;
+ g_km_i2c_config.col_get = callbacks->col_get;
+
+ /* Register keyboard matrix driver */
+
+ ret = kmatrix_i2c_register(ioe, &g_km_i2c_config, devpath);
+ if (ret < 0)
+ {
+ ierr("ERROR: Failed to register keyboard matrix: %d\n", ret);
+ stm32_i2cbus_uninitialize(i2c);
+ return ret;
+ }
+
+ iinfo("Keyboard matrix I2C driver registered at %s\n", devpath);
+ return OK;
+}
diff --git a/boards/arm/stm32/stm32f4discovery/Kconfig
b/boards/arm/stm32/stm32f4discovery/Kconfig
index 7b86a5cafe3..084ab04bc12 100644
--- a/boards/arm/stm32/stm32f4discovery/Kconfig
+++ b/boards/arm/stm32/stm32f4discovery/Kconfig
@@ -120,4 +120,23 @@ config PM_SLEEP_WAKEUP_NSEC
Number of additional nanoseconds to wait in PM_SLEEP before
going to
PM_STANDBY mode.
+if INPUT_KMATRIX_I2C
+
+config STM32_KMATRIX_I2C_BUS
+ int "I2C Bus Number"
+ default 1
+ ---help---
+ I2C bus number to use for the keyboard matrix GPIO expander.
+ Common values: 1 or 2 (depends on available I2C interfaces).
+
+config STM32_KMATRIX_I2C_ADDR
+ hex "I2C Slave Address of GPIO Expander"
+ default 0x20
+ ---help---
+ I2C slave address of the GPIO expander (PCF8574 or MCP23017).
+ PCF8574/MCP23017 default addresses (7-bit):
+ 0x20-0x27: varies with A0-A2 pins (default is 0x20)
+
+endif # INPUT_KMATRIX_I2C
+
endif
diff --git a/boards/arm/stm32/stm32f4discovery/include/board.h
b/boards/arm/stm32/stm32f4discovery/include/board.h
index ddc86ddc5fe..7392eff96cb 100644
--- a/boards/arm/stm32/stm32f4discovery/include/board.h
+++ b/boards/arm/stm32/stm32f4discovery/include/board.h
@@ -472,4 +472,76 @@
#define BOARD_XEN1210_PWMTIMER 1
+/* Keyboard Matrix Configuration */
+
+/* Define keyboard matrix row pins (outputs) */
+
+#define GPIO_KMATRIX_ROW0 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
+ GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN7)
+#define GPIO_KMATRIX_ROW1 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
+ GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN8)
+#define GPIO_KMATRIX_ROW2 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
+ GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN9)
+#define GPIO_KMATRIX_ROW3 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
+ GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN10)
+
+/* Row pins as inputs with pull-up for early diagnostics */
+
+#define GPIO_KMATRIX_ROW0_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
+ GPIO_PORTE|GPIO_PIN7)
+#define GPIO_KMATRIX_ROW1_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
+ GPIO_PORTE|GPIO_PIN8)
+#define GPIO_KMATRIX_ROW2_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
+ GPIO_PORTE|GPIO_PIN9)
+#define GPIO_KMATRIX_ROW3_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
+ GPIO_PORTE|GPIO_PIN10)
+
+/* Define keyboard matrix column pins (inputs) */
+
+#define GPIO_KMATRIX_COL0 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
+ GPIO_PORTE|GPIO_PIN11)
+#define GPIO_KMATRIX_COL1 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
+ GPIO_PORTE|GPIO_PIN13)
+#define GPIO_KMATRIX_COL2 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
+ GPIO_PORTE|GPIO_PIN14)
+
+/* Column pins as outputs for diagnostics only */
+
+#define GPIO_KMATRIX_COL0_OUT (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
+ GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN11)
+#define GPIO_KMATRIX_COL1_OUT (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
+ GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN13)
+#define GPIO_KMATRIX_COL2_OUT (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
+ GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN14)
+
+/* Board-level KMATRIX pin definitions */
+
+#define BOARD_KMATRIX_ROW0 GPIO_KMATRIX_ROW0
+#define BOARD_KMATRIX_ROW1 GPIO_KMATRIX_ROW1
+#define BOARD_KMATRIX_ROW2 GPIO_KMATRIX_ROW2
+#define BOARD_KMATRIX_ROW3 GPIO_KMATRIX_ROW3
+
+#define BOARD_KMATRIX_ROW0_IN GPIO_KMATRIX_ROW0_IN
+#define BOARD_KMATRIX_ROW1_IN GPIO_KMATRIX_ROW1_IN
+#define BOARD_KMATRIX_ROW2_IN GPIO_KMATRIX_ROW2_IN
+#define BOARD_KMATRIX_ROW3_IN GPIO_KMATRIX_ROW3_IN
+
+#define BOARD_KMATRIX_COL0 GPIO_KMATRIX_COL0
+#define BOARD_KMATRIX_COL1 GPIO_KMATRIX_COL1
+#define BOARD_KMATRIX_COL2 GPIO_KMATRIX_COL2
+
+#define BOARD_KMATRIX_COL0_OUT GPIO_KMATRIX_COL0_OUT
+#define BOARD_KMATRIX_COL1_OUT GPIO_KMATRIX_COL1_OUT
+#define BOARD_KMATRIX_COL2_OUT GPIO_KMATRIX_COL2_OUT
+
+#ifdef CONFIG_INPUT_KMATRIX
+int board_kmatrix_diag(int loops, int delay_ms);
+#endif
+
+/* Keyboard Matrix I2C Configuration */
+
+#define CONFIG_STM32_KMATRIX_I2C_BUS 1 /* I2C1 */
+#define CONFIG_STM32_KMATRIX_I2C_ADDR 0x20 /* MCP23X08/PCA9538 address */
+#define CONFIG_STM32_KMATRIX_I2C_FREQ 400000 /* 400 kHz */
+
#endif /* __BOARDS_ARM_STM32_STM32F4DISCOVERY_INCLUDE_BOARD_H */
diff --git a/boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c
b/boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c
index 59742accb3e..058e5eead26 100644
--- a/boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c
+++ b/boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c
@@ -102,6 +102,14 @@
#include "board_sbutton.h"
#endif
+#ifdef CONFIG_INPUT_KMATRIX
+#include "stm32_kmatrix_gpio.h"
+#endif
+
+#ifdef CONFIG_INPUT_KMATRIX_I2C
+#include "stm32_kmatrix_i2c.h"
+#endif
+
#ifdef CONFIG_SENSORS_ZEROCROSS
#include "stm32_zerocross.h"
#endif
@@ -414,6 +422,27 @@ int stm32_bringup(void)
}
#endif
+#ifdef CONFIG_INPUT_KMATRIX
+ /* Initialize and register the keyboard matrix driver */
+
+ ret = board_kmatrix_initialize(CONFIG_INPUT_KMATRIX_DEVPATH);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: board_kmatrix_initialize() failed: %d\n", ret);
+ }
+#endif
+
+#ifdef CONFIG_INPUT_KMATRIX_I2C
+ /* Initialize and register the keyboard matrix driver via I2C expander */
+
+ ret = board_kmatrix_i2c_initialize("/dev/kbd0");
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: board_kmatrix_i2c_initialize() failed: %d\n",
+ ret);
+ }
+#endif
+
#ifdef CONFIG_INPUT_NUNCHUCK
/* Register the Nunchuck driver */
diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt
index 3b897b1a733..1b088339188 100644
--- a/drivers/input/CMakeLists.txt
+++ b/drivers/input/CMakeLists.txt
@@ -106,6 +106,14 @@ if(CONFIG_INPUT)
list(APPEND SRCS keyboard_upper.c)
endif()
+ if(CONFIG_INPUT_KMATRIX)
+ list(APPEND SRCS kmatrix.c)
+ endif()
+
+ if(CONFIG_INPUT_KMATRIX_I2C)
+ list(APPEND SRCS kmatrix_i2c.c)
+ endif()
+
if(CONFIG_INPUT_SBUTTON)
list(APPEND SRCS sbutton.c)
endif()
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 3917fe6538e..d1695ee6f26 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -723,7 +723,7 @@ config INPUT_SPQ10KBD
select I2C
---help---
Enable the Solder Party Q10 BlackBerry Keyboard support. This
- exposes itself as a standard keyboard at /dev/kbdN.
+ exposes itself as a standard keyboard at /dev/keypadN.
This keyboard exists both as a standalone module and integrated
into the Solder Party Keyboard FeatherWing. Information on this
can be found at https://www.solder.party/docs/keyboard-pmod/
@@ -749,4 +749,70 @@ config SPQ10KBD_NPOLLWAITERS
endif # INPUT_SPQ10KBD
+config INPUT_KMATRIX
+ bool "Keyboard Matrix Driver"
+ default n
+ select INPUT_KEYBOARD
+ ---help---
+ Enable support for keyboard matrix input devices with
polling-based
+ scanning. This driver supports NxM key matrices with debounce
and
+ anti-ghosting using diodes.
+
+if INPUT_KMATRIX
+
+config INPUT_KMATRIX_BUFSIZE
+ int "Keyboard matrix buffer size"
+ default 64
+ ---help---
+ Size of the keyboard event buffer for each open file descriptor.
+
+config INPUT_KMATRIX_POLL_MS
+ int "Polling interval (milliseconds)"
+ default 10
+ ---help---
+ Time interval in milliseconds between matrix scans. Smaller
values
+ provide lower latency but consume more CPU. Default: 10ms.
+
+config INPUT_KMATRIX_DEBOUNCE
+ int "Debounce threshold (scan cycles)"
+ default 3
+ ---help---
+ Number of consecutive scan cycles a key must maintain the same
state
+ before generating a press/release event. Higher values provide
more
+ robust debounce but increase latency. Default: 3 cycles.
+
+config INPUT_KMATRIX_DEVPATH
+ string "Device path"
+ default "/dev/keypad0"
+ ---help---
+ Path where the keyboard matrix device will be registered.
Default: /dev/keypad0
+
+config INPUT_KMATRIX_I2C
+ bool "Keyboard Matrix via I2C GPIO Expander"
+ depends on INPUT_KMATRIX && I2C
+ default n
+ ---help---
+ Enable keyboard matrix driver using I2C GPIO expander (PCF8574
or MCP23017).
+ Requires I2C support to be enabled.
+
+if INPUT_KMATRIX_I2C
+
+config INPUT_KMATRIX_I2C_PCF8574
+ bool "Use PCF8574 I2C Expander"
+ default n
+ ---help---
+ Use PCF8574 I2C GPIO expander (8-bit, quasi-bidirectional I/O).
+ This is a simple, low-cost 8-bit I/O expander commonly used in
hobbyist projects.
+
+config INPUT_KMATRIX_I2C_MCP23017
+ bool "Use MCP23017 I2C Expander"
+ default n
+ ---help---
+ Use MCP23017 I2C GPIO expander (16-bit, configurable I/O
directions).
+ This offers more features and flexibility than PCF8574.
+
+endif # INPUT_KMATRIX_I2C
+
+endif # INPUT_KMATRIX
+
endif # INPUT
diff --git a/drivers/input/Make.defs b/drivers/input/Make.defs
index 815a4ce847d..66862bbbde3 100644
--- a/drivers/input/Make.defs
+++ b/drivers/input/Make.defs
@@ -126,6 +126,14 @@ ifeq ($(CONFIG_INPUT_SPQ10KBD),y)
CSRCS += spq10kbd.c
endif
+ifeq ($(CONFIG_INPUT_KMATRIX),y)
+ CSRCS += kmatrix.c
+endif
+
+ifeq ($(CONFIG_INPUT_KMATRIX_I2C),y)
+ CSRCS += kmatrix_i2c.c
+endif
+
ifeq ($(CONFIG_INPUT_GOLDFISH_EVENTS),y)
CSRCS += goldfish_events.c
endif
diff --git a/drivers/input/kmatrix.c b/drivers/input/kmatrix.c
new file mode 100644
index 00000000000..23375b7c980
--- /dev/null
+++ b/drivers/input/kmatrix.c
@@ -0,0 +1,362 @@
+/****************************************************************************
+ * drivers/input/kmatrix.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <poll.h>
+#include <fcntl.h>
+
+#include <nuttx/input/kmatrix.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/clock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mutex.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/input/keyboard.h>
+#include <nuttx/input/kbd_codec.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct kmatrix_dev_s
+{
+ FAR const struct kmatrix_config_s *config; /* Board configuration data */
+
+ mutex_t lock; /* Exclusive access to device */
+ struct work_s work; /* Work queue for polling */
+ uint16_t poll_interval; /* Polling interval in milliseconds */
+
+ /* Current and previous state of the matrix (bitfield) */
+
+ FAR uint8_t *state; /* Current state bitmap */
+ FAR uint8_t *debounce; /* Debounce counter */
+
+ /* Keyboard lower-half registration */
+
+ struct keyboard_lowerhalf_s lower;
+};
+
+/****************************************************************************
+ * Static Function Prototypes
+ ****************************************************************************/
+
+static void kmatrix_scan_worker(FAR void *arg);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: kmatrix_get_state
+ *
+ * Description:
+ * Get the current state of a key at position (row, col)
+ *
+ ****************************************************************************/
+
+static bool kmatrix_get_state(FAR struct kmatrix_dev_s *priv,
+ uint8_t row, uint8_t col)
+{
+ uint16_t idx = row * priv->config->ncols + col;
+ uint16_t byte_idx = idx / 8;
+ uint8_t bit_idx = idx % 8;
+
+ return (priv->state[byte_idx] >> bit_idx) & 1;
+}
+
+/****************************************************************************
+ * Name: kmatrix_set_state
+ *
+ * Description:
+ * Set the current state of a key at position (row, col)
+ *
+ ****************************************************************************/
+
+static void kmatrix_set_state(FAR struct kmatrix_dev_s *priv,
+ uint8_t row, uint8_t col, bool pressed)
+{
+ uint16_t idx = row * priv->config->ncols + col;
+ uint16_t byte_idx = idx / 8;
+ uint8_t bit_idx = idx % 8;
+
+ if (pressed)
+ {
+ priv->state[byte_idx] |= (1 << bit_idx);
+ }
+ else
+ {
+ priv->state[byte_idx] &= ~(1 << bit_idx);
+ }
+}
+
+/****************************************************************************
+ * Name: kmatrix_inc_debounce
+ *
+ * Description:
+ * Increment debounce counter for a key
+ *
+ ****************************************************************************/
+
+static void kmatrix_inc_debounce(FAR struct kmatrix_dev_s *priv,
+ uint8_t row, uint8_t col)
+{
+ uint16_t idx = row * priv->config->ncols + col;
+
+ if (priv->debounce[idx] < CONFIG_INPUT_KMATRIX_DEBOUNCE)
+ {
+ priv->debounce[idx]++;
+ }
+}
+
+/****************************************************************************
+ * Name: kmatrix_reset_debounce
+ *
+ * Description:
+ * Reset debounce counter for a key
+ *
+ ****************************************************************************/
+
+static void kmatrix_reset_debounce(FAR struct kmatrix_dev_s *priv,
+ uint8_t row, uint8_t col)
+{
+ uint16_t idx = row * priv->config->ncols + col;
+
+ priv->debounce[idx] = 0;
+}
+
+/****************************************************************************
+ * Name: kmatrix_scan_worker
+ *
+ * Description:
+ * Periodic worker that scans the keyboard matrix and detects key presses
+ * and releases.
+ *
+ ****************************************************************************/
+
+static void kmatrix_scan_worker(FAR void *arg)
+{
+ FAR struct kmatrix_dev_s *priv = (FAR struct kmatrix_dev_s *)arg;
+ uint8_t row;
+ uint8_t col;
+ bool pressed;
+ bool old_state;
+ uint32_t keycode;
+ int ret;
+
+ ret = nxmutex_lock(&priv->lock);
+ if (ret < 0)
+ {
+ return;
+ }
+
+ /* Scan each row */
+
+ for (row = 0; row < priv->config->nrows; row++)
+ {
+ /* Activate this row */
+
+ priv->config->row_set(priv->config->rows[row], true);
+
+ /* Read each column */
+
+ for (col = 0; col < priv->config->ncols; col++)
+ {
+ pressed = priv->config->col_get(priv->config->cols[col]);
+ old_state = kmatrix_get_state(priv, row, col);
+
+ /* Check if state changed */
+
+ if (pressed != old_state)
+ {
+ kmatrix_inc_debounce(priv, row, col);
+
+ /* After debounce threshold is reached, update state */
+
+ if (priv->debounce[row * priv->config->ncols + col] >=
+ CONFIG_INPUT_KMATRIX_DEBOUNCE)
+ {
+ kmatrix_set_state(priv, row, col, pressed);
+ kmatrix_reset_debounce(priv, row, col);
+
+ /* Generate keyboard event */
+
+ keycode = priv->config->keymap[
+ row * priv->config->ncols + col];
+ keyboard_event(&priv->lower, (uint16_t)keycode,
+ pressed ? KEYBOARD_PRESS :
+ KEYBOARD_RELEASE);
+
+ iinfo("Key [%d,%d]: %s (code %lu)\n", row, col,
+ pressed ? "PRESS" : "RELEASE",
+ (unsigned long)keycode);
+ }
+ }
+ else
+ {
+ kmatrix_reset_debounce(priv, row, col);
+ }
+ }
+
+ /* Deactivate this row */
+
+ priv->config->row_set(priv->config->rows[row], false);
+ }
+
+ nxmutex_unlock(&priv->lock);
+
+ /* Reschedule the worker */
+
+ work_queue(LPWORK, &priv->work, kmatrix_scan_worker, priv,
+ MSEC2TICK(priv->poll_interval));
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: kmatrix_register
+ *
+ * Description:
+ * Configure and register a keyboard matrix device.
+ *
+ ****************************************************************************/
+
+int kmatrix_register(FAR const struct kmatrix_config_s *config,
+ FAR const char *devpath)
+{
+ FAR struct kmatrix_dev_s *priv;
+ int ret;
+ uint16_t state_size;
+ uint16_t debounce_size;
+ uint16_t keys;
+
+ iinfo("Registering keypad matrix: %dx%d at %s\n", config->nrows,
+ config->ncols, devpath);
+
+ /* Validate configuration */
+
+ DEBUGASSERT(config != NULL);
+ DEBUGASSERT(devpath != NULL);
+ DEBUGASSERT(config->rows != NULL);
+ DEBUGASSERT(config->cols != NULL);
+ DEBUGASSERT(config->keymap != NULL);
+ DEBUGASSERT(config->config_row != NULL);
+ DEBUGASSERT(config->config_col != NULL);
+ DEBUGASSERT(config->row_set != NULL);
+ DEBUGASSERT(config->col_get != NULL);
+
+ /* Allocate driver instance */
+
+ priv = kmm_zalloc(sizeof(struct kmatrix_dev_s));
+ if (!priv)
+ {
+ ierr("ERROR: kmm_zalloc(%zu) failed\n", sizeof(struct kmatrix_dev_s));
+ return -ENOMEM;
+ }
+
+ /* Calculate bitmap sizes */
+
+ keys = config->nrows * config->ncols;
+ state_size = (keys + 7) / 8;
+ debounce_size = keys;
+
+ /* Allocate state and debounce bitmaps */
+
+ priv->state = kmm_zalloc(state_size);
+ if (!priv->state)
+ {
+ ierr("ERROR: Failed to allocate state bitmap\n");
+ kmm_free(priv);
+ return -ENOMEM;
+ }
+
+ priv->debounce = kmm_zalloc(debounce_size);
+ if (!priv->debounce)
+ {
+ ierr("ERROR: Failed to allocate debounce bitmap\n");
+ kmm_free(priv->state);
+ kmm_free(priv);
+ return -ENOMEM;
+ }
+
+ /* Initialize device structure */
+
+ priv->config = config;
+ priv->poll_interval = config->poll_interval_ms > 0 ?
+ config->poll_interval_ms :
+ CONFIG_INPUT_KMATRIX_POLL_MS;
+
+ nxmutex_init(&priv->lock);
+
+ /* Configure all GPIO pins */
+
+ for (int i = 0; i < config->nrows; i++)
+ {
+ config->config_row(config->rows[i]);
+ }
+
+ for (int i = 0; i < config->ncols; i++)
+ {
+ config->config_col(config->cols[i]);
+ }
+
+ /* Register as keyboard device */
+
+ ret = keyboard_register(&priv->lower, devpath,
+ CONFIG_INPUT_KMATRIX_BUFSIZE);
+ if (ret < 0)
+ {
+ ierr("ERROR: keyboard_register() failed: %d\n", ret);
+ goto errout_with_priv;
+ }
+
+ /* Start the scanning worker */
+
+ work_queue(LPWORK, &priv->work, kmatrix_scan_worker, priv,
+ MSEC2TICK(priv->poll_interval));
+
+ iinfo("Keypad matrix registered as %s\n", devpath);
+ return OK;
+
+errout_with_priv:
+ nxmutex_destroy(&priv->lock);
+ kmm_free(priv->debounce);
+ kmm_free(priv->state);
+ kmm_free(priv);
+ return ret;
+}
diff --git a/drivers/input/kmatrix_i2c.c b/drivers/input/kmatrix_i2c.c
new file mode 100644
index 00000000000..1b366f9c8bd
--- /dev/null
+++ b/drivers/input/kmatrix_i2c.c
@@ -0,0 +1,262 @@
+/****************************************************************************
+ * drivers/input/kmatrix_i2c.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/input/kmatrix.h>
+#include <nuttx/ioexpander/ioexpander.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Verify IO expander support is enabled */
+
+#if !defined(CONFIG_IOEXPANDER_PCA9538) && !defined(CONFIG_IOEXPANDER_MCP23X08)
+# error "Either CONFIG_IOEXPANDER_PCA9538 or " \
+ "CONFIG_IOEXPANDER_MCP23X08 must be enabled"
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef uint32_t kmatrix_pin_t;
+
+struct kmatrix_i2c_dev_s
+{
+ FAR struct ioexpander_dev_s *ioe; /* IO expander device */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void km_i2c_config_row(kmatrix_pin_t pin);
+static void km_i2c_config_col(kmatrix_pin_t pin);
+static void km_i2c_row_set(kmatrix_pin_t pin, bool active);
+static bool km_i2c_col_get(kmatrix_pin_t pin);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Global I2C device instance (simplified - one per board) */
+
+static struct kmatrix_i2c_dev_s g_km_i2c_dev;
+
+/****************************************************************************
+ * I2C Keyboard Matrix Callbacks
+ ****************************************************************************/
+
+/**
+ * Name: km_i2c_config_row
+ *
+ * Description:
+ * Configure row pins as outputs using IO expander API.
+ */
+
+static void km_i2c_config_row(kmatrix_pin_t pin)
+{
+ int ret;
+
+ iinfo("I2C: Configuring pin %lu as output (row)\n", (unsigned long)pin);
+
+ ret = IOEXP_SETDIRECTION(g_km_i2c_dev.ioe, (uint8_t)pin,
+ IOEXPANDER_DIRECTION_OUT);
+ if (ret < 0)
+ {
+ ierr("ERROR: Failed to configure row pin %lu: %d\n",
+ (unsigned long)pin, ret);
+ }
+}
+
+/**
+ * Name: km_i2c_config_col
+ *
+ * Description:
+ * Configure column pins as inputs with pull-up using IO expander API.
+ */
+
+static void km_i2c_config_col(kmatrix_pin_t pin)
+{
+ int ret;
+
+ iinfo("I2C: Configuring pin %lu as input (column)\n", (unsigned long)pin);
+
+ ret = IOEXP_SETDIRECTION(g_km_i2c_dev.ioe, (uint8_t)pin,
+ IOEXPANDER_DIRECTION_IN_PULLUP);
+ if (ret < 0)
+ {
+ /* PCA9538 does not support IN_PULLUP; fall back to plain input. */
+
+ iinfo("I2C: IN_PULLUP not supported for pin %lu, falling back to IN\n",
+ (unsigned long)pin);
+
+ ret = IOEXP_SETDIRECTION(g_km_i2c_dev.ioe, (uint8_t)pin,
+ IOEXPANDER_DIRECTION_IN);
+ if (ret < 0)
+ {
+ ierr("ERROR: Failed to configure col pin %lu: %d\n",
+ (unsigned long)pin, ret);
+ }
+ }
+}
+
+/**
+ * Name: km_i2c_row_set
+ *
+ * Description:
+ * Control row output (active-low for matrix with diodes).
+ */
+
+static void km_i2c_row_set(kmatrix_pin_t pin, bool active)
+{
+ int ret;
+
+ /* For active-low: active=true means write LOW (false) */
+
+ ret = IOEXP_WRITEPIN(g_km_i2c_dev.ioe, (uint8_t)pin, !active);
+ if (ret < 0)
+ {
+ ierr("ERROR: Failed to set row pin %lu: %d\n",
+ (unsigned long)pin, ret);
+ }
+
+ iinfo("I2C: Row set pin %lu to %d\n", (unsigned long)pin, active ? 0 : 1);
+}
+
+/**
+ * Name: km_i2c_col_get
+ *
+ * Description:
+ * Read column input (active-low with pull-up).
+ */
+
+static bool km_i2c_col_get(kmatrix_pin_t pin)
+{
+ bool value;
+ int ret;
+
+ ret = IOEXP_READPIN(g_km_i2c_dev.ioe, (uint8_t)pin, &value);
+ if (ret < 0)
+ {
+ ierr("ERROR: Failed to read col pin %lu: %d\n",
+ (unsigned long)pin, ret);
+ return false;
+ }
+
+ /* Return inverted: true = active (low), false = inactive (high) */
+
+ bool result = !value;
+
+ iinfo("I2C: Col get pin %lu = %d\n", (unsigned long)pin, result);
+
+ return result;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/**
+ * Name: kmatrix_i2c_get_callbacks
+ *
+ * Description:
+ * Get the I2C callback functions to use in keyboard matrix config.
+ * This is called by board adapters to populate the callbacks.
+ *
+ * Returned Value:
+ * Structure with the callback function pointers.
+ */
+
+static struct kmatrix_callbacks_s g_km_i2c_callbacks =
+{
+ .config_row = km_i2c_config_row,
+ .config_col = km_i2c_config_col,
+ .row_set = km_i2c_row_set,
+ .col_get = km_i2c_col_get,
+};
+
+FAR struct kmatrix_callbacks_s *kmatrix_i2c_get_callbacks(void)
+{
+ return &g_km_i2c_callbacks;
+}
+
+/**
+ * Name: kmatrix_i2c_register
+ *
+ * Description:
+ * Register keyboard matrix driver using I2C GPIO expander.
+ * The IO expander device must already be initialized.
+ *
+ * Input Parameters:
+ * ioe_dev - IO expander device (from mcp23x08_initialize or
+ * pca9538_initialize)
+ * config - Keyboard matrix configuration (with callbacks set)
+ * devpath - Device path (e.g., "/dev/kbd0")
+ *
+ * Returned Value:
+ * Zero on success; negated errno on failure.
+ */
+
+int kmatrix_i2c_register(FAR struct ioexpander_dev_s *ioe_dev,
+ FAR const struct kmatrix_config_s *config,
+ FAR const char *devpath)
+{
+ int ret;
+
+ if (ioe_dev == NULL)
+ {
+ ierr("ERROR: IO expander device is NULL\n");
+ return -EINVAL;
+ }
+
+ iinfo("Initializing keyboard matrix via I2C IO expander\n");
+
+ /* Store IO expander device in global for callbacks */
+
+ g_km_i2c_dev.ioe = ioe_dev;
+
+ /* Register the keyboard matrix driver with provided config
+ * (which must have callbacks already set by the board adapter)
+ */
+
+ ret = kmatrix_register(config, devpath);
+ if (ret < 0)
+ {
+ ierr("ERROR: kmatrix_register failed: %d\n", ret);
+ return ret;
+ }
+
+ iinfo("Keyboard matrix I2C driver registered successfully\n");
+ return OK;
+}
diff --git a/include/nuttx/input/kmatrix.h b/include/nuttx/input/kmatrix.h
new file mode 100644
index 00000000000..cec15acfddd
--- /dev/null
+++ b/include/nuttx/input/kmatrix.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+ * include/nuttx/input/kmatrix.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_INPUT_KMATRIX_H
+#define __INCLUDE_NUTTX_INPUT_KMATRIX_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/input/keyboard.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef uint32_t kmatrix_pin_t;
+
+/* Keyboard matrix configuration structure passed to kmatrix_register() */
+
+struct kmatrix_config_s
+{
+ uint8_t nrows; /* Number of rows */
+ uint8_t ncols; /* Number of columns */
+ FAR const kmatrix_pin_t *rows; /* Array of row GPIO pins */
+ FAR const kmatrix_pin_t *cols; /* Array of column GPIO pins */
+
+ /* Keymap: keycode[row * cols + col] */
+
+ FAR const uint32_t *keymap;
+ uint16_t poll_interval_ms; /* Polling interval in milliseconds
*/
+
+ /* GPIO callback functions specific to the SoC/board */
+
+ void (*config_row)(kmatrix_pin_t pin);
+ void (*config_col)(kmatrix_pin_t pin);
+ void (*row_set)(kmatrix_pin_t pin, bool active);
+ bool (*col_get)(kmatrix_pin_t pin);
+};
+
+#ifdef CONFIG_INPUT_KMATRIX_I2C
+
+/* Keyboard matrix callback structure for I2C expanders */
+
+struct kmatrix_callbacks_s
+{
+ void (*config_row)(kmatrix_pin_t pin);
+ void (*config_col)(kmatrix_pin_t pin);
+ void (*row_set)(kmatrix_pin_t pin, bool active);
+ bool (*col_get)(kmatrix_pin_t pin);
+};
+
+#endif /* CONFIG_INPUT_KMATRIX_I2C */
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Name: kmatrix_register
+ *
+ * Description:
+ * Configure and register a keyboard matrix device. This will create the
+ * /dev/keypadN device node and enable keyboard scanning.
+ *
+ * Input Parameters:
+ * config - The keyboard matrix configuration. This structure is not
+ * copied; it must persist for the lifetime of the driver.
+ * devpath - The device path for the /dev/keypadN device.
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno value is
+ * returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int kmatrix_register(FAR const struct kmatrix_config_s *config,
+ FAR const char *devpath);
+
+#ifdef CONFIG_INPUT_KMATRIX_I2C
+
+/* Forward declaration */
+
+struct ioexpander_dev_s;
+
+/****************************************************************************
+ * Name: kmatrix_i2c_register
+ *
+ * Description:
+ * Register keyboard matrix driver using I2C GPIO expander.
+ * The IO expander device must already be initialized using
+ * mcp23x08_initialize() or pca9538_initialize().
+ *
+ * Input Parameters:
+ * ioe_dev - IO expander device (from mcp23x08_initialize or
+ * pca9538_initialize)
+ * config - The keyboard matrix configuration (with callbacks set)
+ * devpath - The device path for the /dev/keypadN device
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno value is
+ * returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int kmatrix_i2c_register(FAR struct ioexpander_dev_s *ioe_dev,
+ FAR const struct kmatrix_config_s *config,
+ FAR const char *devpath);
+
+/****************************************************************************
+ * Name: kmatrix_i2c_get_callbacks
+ *
+ * Description:
+ * Get the I2C callback functions to use in keyboard matrix config.
+ * This is called by board adapters to populate the callbacks.
+ *
+ * Returned Value:
+ * Structure with the callback function pointers.
+ *
+ ****************************************************************************/
+
+FAR struct kmatrix_callbacks_s *kmatrix_i2c_get_callbacks(void);
+
+#endif /* CONFIG_INPUT_KMATRIX_I2C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_INPUT_KMATRIX_H */