mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 11:26:12 +08:00
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 <moura.fmo@gmail.com> decouple kbd / keypad. Fix some comments add documentation fix rule issues Update CMakeLists.txt update documentation. improve documentation
This commit is contained in:
committed by
Alan C. Assis
parent
6c37217c36
commit
ef71625ede
@@ -0,0 +1 @@
|
|||||||
|
<binary image placeholder>
|
||||||
@@ -5,6 +5,7 @@ Input Devices
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:caption: Supported Drivers
|
:caption: Supported Drivers
|
||||||
|
|
||||||
|
keypad-keyboard.rst
|
||||||
keypad.rst
|
keypad.rst
|
||||||
sbutton.rst
|
sbutton.rst
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
=======================
|
||||||
|
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.
|
||||||
|
|
||||||
|
**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
|
||||||
|
a 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``.
|
||||||
|
|
||||||
@@ -1,142 +1,83 @@
|
|||||||
=======================
|
=======================
|
||||||
Keyboard/Keypad Drivers
|
Matrix Keypad (KMATRIX)
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
**Keypads vs. Keyboards** Keyboards and keypads are really the
|
**What is a Keypad?**
|
||||||
same devices for NuttX. A keypad is thought of as simply a
|
A keypad is a small keyboard with a limited set of keys, typically
|
||||||
keyboard with fewer keys.
|
arranged in a matrix. It is commonly used for numeric input, access
|
||||||
|
control, or simple user interfaces.
|
||||||
|
|
||||||
**Special Commands**. In NuttX, a keyboard/keypad driver is simply
|
For example, a typical 12-key numeric keypad looks like this:
|
||||||
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
|
.. image:: images/keypad-example.png
|
||||||
released is needed by applications as well. Thus, in addition to
|
:alt: Example of a 12-key matrix keypad
|
||||||
normal and special key press events, it may also be necessary to
|
:align: center
|
||||||
encode normal and special key release events.
|
:width: 200px
|
||||||
|
|
||||||
**Encoding/Decoding** Layer. An optional encoding/decoding layer
|
**Purpose**. The KMATRIX driver provides a generic keypad
|
||||||
can be used with the basic character driver to encode the keyboard
|
implementation for boards that expose a switch matrix through GPIOs.
|
||||||
events into the text data stream. The function interfaces that
|
It periodically scans rows and columns, detects state changes with a
|
||||||
comprise that encoding/decoding layer are defined in the header
|
simple debounce, and emits keyboard events through the common keyboard
|
||||||
file ``include/nuttx/input/kbd_code.h``. These functions provide
|
upper-half. This makes the device available as a character driver
|
||||||
an matched set of (a) driver encoding interfaces, and (b)
|
(e.g., ``/dev/keypad0``) using the standard keyboard
|
||||||
application decoding interfaces.
|
interfaces.
|
||||||
|
|
||||||
#. **Driver Encoding Interfaces**. These are interfaces used by
|
**Why Polling**. This first version uses polling to be broadly usable
|
||||||
the keyboard/keypad driver to encode keyboard events and data.
|
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.
|
||||||
|
|
||||||
- ``kbd_press()``
|
**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.
|
||||||
|
|
||||||
**Function Prototype:**
|
**Board Support**. To support KMATRIX, a board must provide:
|
||||||
|
|
||||||
**Description:**
|
#. **GPIO Definitions**
|
||||||
|
|
||||||
**Input Parameters:**
|
- Define the row and column GPIOs (arrays of pins).
|
||||||
|
- Provide a keymap array indexed by ``row * ncols + col``.
|
||||||
|
|
||||||
- ``ch``: The character to be added to the output stream.
|
#. **Configuration Callbacks**
|
||||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
|
||||||
the actual low-level put operation.
|
|
||||||
|
|
||||||
**Returned Value:**
|
- ``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.
|
||||||
|
|
||||||
- ``kbd_release()``
|
#. **Registration Hook**
|
||||||
|
|
||||||
**Function Prototype:**
|
- 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")``).
|
||||||
|
|
||||||
**Description:**
|
**Reference Implementation (STM32F4Discovery)**. The current reference
|
||||||
|
is in ``boards/arm/stm32/common/src/stm32_kmatrix_gpio.c``:
|
||||||
|
|
||||||
**Input Parameters:**
|
- 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()``
|
||||||
|
|
||||||
- ``ch``: The character associated with the key that was
|
**Data Path Summary**.
|
||||||
released.
|
|
||||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
|
||||||
the actual low-level put operation.
|
|
||||||
|
|
||||||
**Returned Value:**
|
- Board calls ``board_kmatrix_initialize("/dev/keypad0")``
|
||||||
|
- ``kmatrix_register()`` configures GPIOs and calls
|
||||||
- ``kbd_specpress()``
|
``keyboard_register(&lower, devpath, buflen)``
|
||||||
|
- The upper-half registers the device node at ``devpath``
|
||||||
**Function Prototype:**
|
- ``kmatrix_scan_worker()`` calls ``keyboard_event()`` on press/release
|
||||||
|
- Applications read events from the device node
|
||||||
**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``.
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
@@ -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 */
|
||||||
@@ -158,4 +158,12 @@ if(CONFIG_INPUT_SBUTTON)
|
|||||||
list(APPEND SRCS stm32_sbutton.c)
|
list(APPEND SRCS stm32_sbutton.c)
|
||||||
endif()
|
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})
|
target_sources(board PRIVATE ${SRCS})
|
||||||
|
|||||||
@@ -166,6 +166,14 @@ ifeq ($(CONFIG_INPUT_SBUTTON),y)
|
|||||||
CSRCS += stm32_sbutton.c
|
CSRCS += stm32_sbutton.c
|
||||||
endif
|
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
|
DEPPATH += --dep-path src
|
||||||
VPATH += :src
|
VPATH += :src
|
||||||
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
|
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -120,4 +120,23 @@ config PM_SLEEP_WAKEUP_NSEC
|
|||||||
Number of additional nanoseconds to wait in PM_SLEEP before going to
|
Number of additional nanoseconds to wait in PM_SLEEP before going to
|
||||||
PM_STANDBY mode.
|
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
|
endif
|
||||||
|
|||||||
@@ -472,4 +472,76 @@
|
|||||||
|
|
||||||
#define BOARD_XEN1210_PWMTIMER 1
|
#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 */
|
#endif /* __BOARDS_ARM_STM32_STM32F4DISCOVERY_INCLUDE_BOARD_H */
|
||||||
|
|||||||
@@ -102,6 +102,14 @@
|
|||||||
#include "board_sbutton.h"
|
#include "board_sbutton.h"
|
||||||
#endif
|
#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
|
#ifdef CONFIG_SENSORS_ZEROCROSS
|
||||||
#include "stm32_zerocross.h"
|
#include "stm32_zerocross.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -414,6 +422,27 @@ int stm32_bringup(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef CONFIG_INPUT_NUNCHUCK
|
||||||
/* Register the Nunchuck driver */
|
/* Register the Nunchuck driver */
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,14 @@ if(CONFIG_INPUT)
|
|||||||
list(APPEND SRCS keyboard_upper.c)
|
list(APPEND SRCS keyboard_upper.c)
|
||||||
endif()
|
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)
|
if(CONFIG_INPUT_SBUTTON)
|
||||||
list(APPEND SRCS sbutton.c)
|
list(APPEND SRCS sbutton.c)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
+67
-1
@@ -723,7 +723,7 @@ config INPUT_SPQ10KBD
|
|||||||
select I2C
|
select I2C
|
||||||
---help---
|
---help---
|
||||||
Enable the Solder Party Q10 BlackBerry Keyboard support. This
|
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
|
This keyboard exists both as a standalone module and integrated
|
||||||
into the Solder Party Keyboard FeatherWing. Information on this
|
into the Solder Party Keyboard FeatherWing. Information on this
|
||||||
can be found at https://www.solder.party/docs/keyboard-pmod/
|
can be found at https://www.solder.party/docs/keyboard-pmod/
|
||||||
@@ -749,4 +749,70 @@ config SPQ10KBD_NPOLLWAITERS
|
|||||||
|
|
||||||
endif # INPUT_SPQ10KBD
|
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
|
endif # INPUT
|
||||||
|
|||||||
@@ -126,6 +126,14 @@ ifeq ($(CONFIG_INPUT_SPQ10KBD),y)
|
|||||||
CSRCS += spq10kbd.c
|
CSRCS += spq10kbd.c
|
||||||
endif
|
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)
|
ifeq ($(CONFIG_INPUT_GOLDFISH_EVENTS),y)
|
||||||
CSRCS += goldfish_events.c
|
CSRCS += goldfish_events.c
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 */
|
||||||
Reference in New Issue
Block a user