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
==========================
- ``include/nuttx/ioexpander/ioexpander.h`` and ``include/nuttx/ioexpander/gpio.h``.
All structures and APIs needed to work with ioexpander drivers are provided in
this header file.
The IO Expander subsystem is defined in the following headers:
- ``struct ioexpander_ops_s``. Each ioexpand device driver must implement
an instance of ``struct ioexpander_ops_s``. That structure defines a
call table with the methods, and we also provide macros to help access methods.
- ``include/nuttx/ioexpander/ioexpander.h`` — defines the public IO expander
interface: macros, types, and helper access macros used by drivers and
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
accessed by user code, we should always get lower level drivers, for example I2C,
and map extended gpio feature same asa normal gpio. See for example,
``int nrf52_sx1509_initialize(void)``
in ``boards/arm/nrf52/thingy52/src/nrf52_sx1509.c``. In general, the binding
sequence is:
The helper ``gpio_lower_half`` can be used to register individual expander
pins as standard GPIO devices so that upper-half GPIO consumers can access
expander pins through the common GPIO character driver.
#. Get an instance of ``struct i2c_master_s`` from the
hardware-specific I2C device driver, and
#. Provide that instance and configurations to the ioexpander initialization method
to get the ``struct ioexpander_dev_s`` ioe device instance.
#. Then use ioe device instance to do ioexpander operations, or use ``gpio_lower_half``
to make ioexpand compatible with normal gpio.
**Binding IO expander drivers**
IO expander drivers are usually bound by board-specific code rather than
accessed directly from application code. For I2C- or SPI-connected
expanders the typical sequence is:
#. 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``,
@@ -33,3 +41,213 @@ IO Expander Device Drivers
``drivers/ioexpander/ioe_rpmsg.c``,
``boards/sim/sim/sim/src/sim_ioexpander.c``,
``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_ENABLE 1 /* Cfg the pin as wake up source */
#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_MASK_DISABLE 0 /* Unmask the interrupter */
# define IOEXPANDER_MASK_ENABLE 1 /* Mask the interrupter */
/* Access macros ************************************************************/