mirror of
https://github.com/apache/nuttx.git
synced 2026-05-21 04:52:02 +08:00
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:
committed by
Alan C. Assis
parent
a938926b52
commit
513673c11a
@@ -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.
|
||||
|
||||
@@ -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 ************************************************************/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user