drivers/ioexpander: add enable & disable macro for gpio SETDEBOUNCE and SETMASK

IOEXPANDER_DEBOUNCE_DISABLE (0): Disable debounce filtering
IOEXPANDER_DEBOUNCE_ENABLE (1): Enable debounce filtering
IOEXPANDER_MASK_DISABLE (0): Unmask the interrupter
IOEXPANDER_MASK_ENABLE (1): Mask the interrupter

Signed-off-by: chenzihan1 <chenzihan1@xiaomi.com>
This commit is contained in:
chenzihan1
2025-02-14 15:02:40 +08:00
committed by Alan C. Assis
parent a938926b52
commit 513673c11a
2 changed files with 241 additions and 19 deletions
@@ -2,29 +2,37 @@
IO Expander Device Drivers IO Expander Device Drivers
========================== ==========================
- ``include/nuttx/ioexpander/ioexpander.h`` and ``include/nuttx/ioexpander/gpio.h``. The IO Expander subsystem is defined in the following headers:
All structures and APIs needed to work with ioexpander drivers are provided in
this header file.
- ``struct ioexpander_ops_s``. Each ioexpand device driver must implement - ``include/nuttx/ioexpander/ioexpander.h`` — defines the public IO expander
an instance of ``struct ioexpander_ops_s``. That structure defines a interface: macros, types, and helper access macros used by drivers and
call table with the methods, and we also provide macros to help access methods. consumers.
- ``include/nuttx/ioexpander/gpio.h`` — provides the "gpio lower half"
helper that allows registering an IO expander pin as a standard GPIO
character device (see ``gpio_lower_half`` and ``gpio_lower_half_byname``).
- we also provide method ``gpio_lower_half`` to make ioexpander compatible with normal gpio. Each IO expander driver must implement an instance of ``struct
ioexpander_ops_s``. That structure defines the lower-half call table and
the operations a driver must provide; the public header also includes
helper macros that dispatch to the lower-half operations table.
- **Binding ioexpander Drivers**. ioexpander drivers are not normally directly The helper ``gpio_lower_half`` can be used to register individual expander
accessed by user code, we should always get lower level drivers, for example I2C, pins as standard GPIO devices so that upper-half GPIO consumers can access
and map extended gpio feature same asa normal gpio. See for example, expander pins through the common GPIO character driver.
``int nrf52_sx1509_initialize(void)``
in ``boards/arm/nrf52/thingy52/src/nrf52_sx1509.c``. In general, the binding
sequence is:
#. Get an instance of ``struct i2c_master_s`` from the **Binding IO expander drivers**
hardware-specific I2C device driver, and
#. Provide that instance and configurations to the ioexpander initialization method IO expander drivers are usually bound by board-specific code rather than
to get the ``struct ioexpander_dev_s`` ioe device instance. accessed directly from application code. For I2C- or SPI-connected
#. Then use ioe device instance to do ioexpander operations, or use ``gpio_lower_half`` expanders the typical sequence is:
to make ioexpand compatible with normal gpio.
#. Obtain the bus instance (for example, a ``struct i2c_master_s *``) from
the hardware-specific bus driver.
#. Call the expander driver's initialization routine with the bus instance
and device-specific configuration; the init routine returns a
``struct ioexpander_dev_s *`` instance.
#. Use the returned ``ioe`` instance directly, or register individual
expander pins with the upper-half GPIO driver via ``gpio_lower_half``.
- **Examples**: ``drivers/ioexpander/pca9555.c``, - **Examples**: ``drivers/ioexpander/pca9555.c``,
@@ -33,3 +41,213 @@ IO Expander Device Drivers
``drivers/ioexpander/ioe_rpmsg.c``, ``drivers/ioexpander/ioe_rpmsg.c``,
``boards/sim/sim/sim/src/sim_ioexpander.c``, ``boards/sim/sim/sim/src/sim_ioexpander.c``,
``boards/arm/nrf52/thingy52/src/nrf52_sx1509.c`` etc. ``boards/arm/nrf52/thingy52/src/nrf52_sx1509.c`` etc.
Further details
===============
Header files
------------
The relevant header files are:
- ``include/nuttx/ioexpander/ioexpander.h`` — defines macros, types and access
macros used to interact with IO expanders.
- ``include/nuttx/ioexpander/gpio.h`` — provides the "gpio lower half" helper
that allows registering an IO expander pin as a standard GPIO device.
Overview of key macros and options
----------------------------------
The following is a concise reference of the important macros defined in the
header. These are the options you will typically use through ``IOEXP_SETOPTION``
and the various access macros. The primary preprocessor definitions are
listed below (C syntax):
.. code-block:: c
/* Direction definitions */
#define IOEXPANDER_DIRECTION_IN 0 /* float */
#define IOEXPANDER_DIRECTION_IN_PULLUP 1
#define IOEXPANDER_DIRECTION_IN_PULLDOWN 2
#define IOEXPANDER_DIRECTION_OUT 3 /* push-pull */
#define IOEXPANDER_DIRECTION_OUT_OPENDRAIN 4
#define IOEXPANDER_DIRECTION_OUT_LED 5 /* LED output */
/* Pinset mask helpers */
#define IOEXPANDER_PINMASK (((ioe_pinset_t)1 << CONFIG_IOEXPANDER_NPINS) - 1)
#define PINSET_ALL (~((ioe_pinset_t)0))
/* Common option values (used with IOEXP_SETOPTION) */
/* Invert (active level) */
#define IOEXPANDER_OPTION_INVERT 1
#define IOEXPANDER_VAL_NORMAL 0 /* normal polarity */
#define IOEXPANDER_VAL_INVERT 1 /* inverted polarity */
/* Interrupt configuration (level/edge and high/low/rising/falling/both) */
#define IOEXPANDER_OPTION_INTCFG 2
#define IOEXPANDER_VAL_DISABLE 0 /* 0000 disable interrupts */
#define IOEXPANDER_VAL_LEVEL 1 /* xx01: level triggered */
#define IOEXPANDER_VAL_EDGE 2 /* xx10: edge triggered */
#define IOEXPANDER_VAL_HIGH 5 /* 0101: high level */
#define IOEXPANDER_VAL_LOW 9 /* 1001: low level */
#define IOEXPANDER_VAL_RISING 6 /* 0110: rising edge */
#define IOEXPANDER_VAL_FALLING 10 /* 1010: falling edge */
#define IOEXPANDER_VAL_BOTH 14 /* 1110: both edges */
/* LED configuration */
#define IOEXPANDER_OPTION_LEDCFG 3 /* assign an LED number to a pin */
/* Non-generic (driver-specific) option */
#define IOEXPANDER_OPTION_NONGENERIC 4 /* pass driver-specific struct */
/* Wakeup configuration (configure pin as SoC wake-up source) */
#define IOEXPANDER_OPTION_WAKEUPCFG 5
#define IOEXPANDER_WAKEUP_DISABLE 0
#define IOEXPANDER_WAKEUP_ENABLE 1
/* Debounce and interrupt mask (recent additions) */
#define IOEXPANDER_OPTION_SETDEBOUNCE 6 /* configure debounce */
#define IOEXPANDER_DEBOUNCE_DISABLE 0
#define IOEXPANDER_DEBOUNCE_ENABLE 1
#define IOEXPANDER_OPTION_SETMASK 7 /* control interrupt masking */
#define IOEXPANDER_MASK_DISABLE 0 /* unmask (enable) interrupts */
#define IOEXPANDER_MASK_ENABLE 1 /* mask (suppress) interrupts */
Access macros (API)
-------------------
The header exposes a set of helper macros that dispatch to the underlying
driver operations table (``struct ioexpander_ops_s``):
.. c:macro:: IOEXP_SETDIRECTION(dev, pin, dir)
Set a pin direction (input, output, open-drain, LED, pull-up/down).
Returns 0 on success or a negative errno on failure.
.. c:macro:: IOEXP_SETOPTION(dev, pin, opt, val)
Generic option setting interface used to configure the options listed
above. Note that ``val`` is a ``void *``; drivers may accept an integer
casted to a pointer or a pointer to a driver-specific structure.
Examples::
/* Invert pin polarity */
IOEXP_SETOPTION(dev, 3, IOEXPANDER_OPTION_INVERT,
(FAR void *)IOEXPANDER_VAL_INVERT);
/* Enable debounce on pin 2 */
IOEXP_SETOPTION(dev, 2, IOEXPANDER_OPTION_SETDEBOUNCE,
(FAR void *)IOEXPANDER_DEBOUNCE_ENABLE);
/* Mask interrupts for pin 5 */
IOEXP_SETOPTION(dev, 5, IOEXPANDER_OPTION_SETMASK,
(FAR void *)IOEXPANDER_MASK_ENABLE);
.. c:macro:: IOEXP_WRITEPIN(dev, pin, val)
Set the pin level. Returns 0 on success or a negative errno on error.
.. c:macro:: IOEXP_READPIN(dev, pin, valptr)
Read the actual physical pin level. The value is returned via ``valptr``.
.. c:macro:: IOEXP_READBUF(dev, pin, valptr)
Read the buffered/register value cached by the expander.
- ``IOEXP_WRITEPIN`` sets the pin level (TRUE typically means high).
Drivers handle polarity inversion if configured.
- ``IOEXP_READPIN`` reads the actual physical pin level.
- ``IOEXP_READBUF`` reads the buffered/register value cached by the
expander.
Multi-pin operations
--------------------
When ``CONFIG_IOEXPANDER_MULTIPIN`` is enabled, batch operations are
available that may be more efficient than repeated single-pin calls:
- ``IOEXP_MULTIWRITEPIN(dev, pins, vals, count)``
- ``IOEXP_MULTIREADPIN(dev, pins, vals, count)``
- ``IOEXP_MULTIREADBUF(dev, pins, vals, count)``
Interrupts and callbacks
------------------------
If ``CONFIG_IOEXPANDER_INT_ENABLE`` is enabled the header defines the
callback type and attach/detach helper macros. The callback signature
is::
typedef CODE int (*ioe_callback_t)(FAR struct ioexpander_dev_s *dev,
ioe_pinset_t pinset, FAR void *arg);
The callback is invoked when events occur for the monitored pinset. The
attach/detach helpers are provided as macros that dispatch to the lower-half
driver when ``CONFIG_IOEXPANDER_INT_ENABLE`` is enabled:
.. c:macro:: IOEP_ATTACH(dev, pinset, callback, arg)
Attach and enable a pin interrupt callback. Returns a non-NULL opaque
handle on success. ``pinset`` selects which pin(s) will generate the
callback; ``callback`` is a function of type ``ioe_callback_t`` and
``arg`` is passed through to the callback.
.. c:macro:: IOEP_DETACH(dev, handle)
Detach and disable a previously attached callback referenced by ``handle``.
Note: when ``CONFIG_IOEXPANDER_NPINS`` > 64, ``ioe_pinset_t`` represents a
single interrupt pin number rather than a bitmask.
Driver interface (lower-half)
-----------------------------
Each IO expander driver must implement the operations table
``struct ioexpander_ops_s``. At minimum the driver should provide:
- ``ioe_direction``
- ``ioe_option``
- ``ioe_writepin``
- ``ioe_readpin``
- ``ioe_readbuf``
Optional multi-pin and interrupt attach/detach methods should be provided
when the corresponding configuration options are enabled.
Binding to the upper layer (gpio_lower_half)
--------------------------------------------
Applications normally do not access IO expander drivers directly. Typical
binding steps are:
1. Obtain the bus instance (for example, ``struct i2c_master_s *``) from
the hardware-specific bus driver.
2. Call the expander driver's initialization routine with the bus instance
and device configuration to obtain a ``struct ioexpander_dev_s *``.
3. Use the returned ``ioe`` instance directly, or register individual
expander pins as standard GPIO devices via ``gpio_lower_half`` or
``gpio_lower_half_byname``.
Example (pseudocode)::
/* Get the I2C bus */
struct i2c_master_s *i2c = up_i2cinitialize(0);
/* Initialize the expander (driver-specific init) */
struct ioexpander_dev_s *ioe = pca9555_initialize(i2c, CONFIG_PCA9555_ADDR);
/* Configure pin 0 as input with pull-up and enable debounce */
IOEXP_SETDIRECTION(ioe, 0, IOEXPANDER_DIRECTION_IN_PULLUP);
IOEXP_SETOPTION(ioe, 0, IOEXPANDER_OPTION_SETDEBOUNCE,
(FAR void *)IOEXPANDER_DEBOUNCE_ENABLE);
Examples and references
-----------------------
See the following drivers and board examples for concrete usage:
- ``drivers/ioexpander/pca9555.c`` — I2C IO expander implementation.
- ``drivers/ioexpander/ioe_rpmsg.c`` — RPMSG-based IO expander.
- ``boards/arm/nrf52/thingy52/src/nrf52_sx1509.c`` — binding example.
+4
View File
@@ -83,7 +83,11 @@
#define IOEXPANDER_WAKEUP_DISABLE 0 /* Do not cfg the pin as wake up source */ #define IOEXPANDER_WAKEUP_DISABLE 0 /* Do not cfg the pin as wake up source */
#define IOEXPANDER_WAKEUP_ENABLE 1 /* Cfg the pin as wake up source */ #define IOEXPANDER_WAKEUP_ENABLE 1 /* Cfg the pin as wake up source */
#define IOEXPANDER_OPTION_SETDEBOUNCE 6 /* Configure debounce duration */ #define IOEXPANDER_OPTION_SETDEBOUNCE 6 /* Configure debounce duration */
# define IOEXPANDER_DEBOUNCE_DISABLE 0 /* Disable debounce */
# define IOEXPANDER_DEBOUNCE_ENABLE 1 /* Enable debounce */
#define IOEXPANDER_OPTION_SETMASK 7 /* Mask the interrupter */ #define IOEXPANDER_OPTION_SETMASK 7 /* Mask the interrupter */
# define IOEXPANDER_MASK_DISABLE 0 /* Unmask the interrupter */
# define IOEXPANDER_MASK_ENABLE 1 /* Mask the interrupter */
/* Access macros ************************************************************/ /* Access macros ************************************************************/