drivers/ioexpander/aw9523b: New driver for AW9523B i/o expander

This is an I2C driver for the Awinic AW9523B I/O expander. As well
as the supporting usual digital I/Os, this device features the
ability to drive LEDs directly, and can control the drive current
to each LED individually. The driver was derived from the PCA9555
driver, provides all the standard interfaces of an i/o expander
driver. It also features support for the special features of the
AW9523B through pin direction IOEXPANDER_DIRECTION_OUT_LED and
IOEXPANDER_OPTION_NONGENERIC with AW9523B_OPTION_* options.

The driver has a number of configurable features including interrupt
handling and a shadow register mode based on the PCA9555 driver,
plus new LED/dimming support.

Testing was done using an ESP32S3 host and I2C connection to the
Adafruit AW9523 breakout board.

Signed-off-by: Zik Saleeba <zik@zikzak.net>
This commit is contained in:
Zik Saleeba 2025-08-29 13:01:34 +10:00 committed by Alan C. Assis
parent 8fc63aaa10
commit 835c535e18
6 changed files with 1959 additions and 0 deletions

View file

@ -82,6 +82,10 @@ if(CONFIG_IOEXPANDER)
if(CONFIG_IOEXPANDER_SX1509) if(CONFIG_IOEXPANDER_SX1509)
list(APPEND SRCS sx1509.c) list(APPEND SRCS sx1509.c)
endif() endif()
if(CONFIG_IOEXPANDER_AW9523B)
list(APPEND SRCS aw9523b.c)
endif()
endif() endif()
# GPIO test device driver (independent of IOEXPANDERS) # GPIO test device driver (independent of IOEXPANDERS)

View file

@ -495,6 +495,63 @@ config SX1509_RETRY
endif # IOEXPANDER_SX1509 endif # IOEXPANDER_SX1509
config IOEXPANDER_AW9523B
bool "AW9523B I2C IO expander"
default n
depends on I2C
---help---
Enable support for the Awinic AW9523B IO Expander
if IOEXPANDER_AW9523B
config AW9523B_MULTIPLE
bool "Multiple AW9523B Devices"
default n
---help---
Can be defined to support multiple AW9523B devices on board.
config AW9523B_LED_ENABLE
bool "Enable AW9523B LED Support"
default y
---help---
Enable driver LED functionality
config AW9523B_INT_ENABLE
bool "Enable AW9523B Interrupt Support"
default n
select IOEXPANDER_INT_ENABLE
---help---
Enable driver interrupt functionality
config AW9523B_INT_NCALLBACKS
int "Max number of interrupt callbacks"
default 4
depends on AW9523B_INT_ENABLE
---help---
This is the maximum number of interrupt callbacks supported
config AW9523B_SHADOW_MODE
bool "Use Shadow Mode instead of Read-Modify-Write Operations"
default n
---help---
This setting enables a mode where the output and pin
configuration registers are held in RAM.
With this for example we do not need to read back the
output-register every time we want to change one pin.
We do instead change the bit in the internal register
and then just write this register to the IO-Expander.
This reduces bus traffic and eliminates the problem of
EMC-caused toggling of output pins.
config AW9523B_RETRY
bool "Retry to send commands and data at I2C communication errors"
default n
---help---
Retry to send commands and data if a I2C-communication
error occurs (eg. caused by EMC).
endif # IOEXPANDER_AW9523B
config IOEXPANDER_INT_ENABLE config IOEXPANDER_INT_ENABLE
bool bool
default n default n

View file

@ -82,6 +82,10 @@ ifeq ($(CONFIG_IOEXPANDER_SX1509),y)
CSRCS += sx1509.c CSRCS += sx1509.c
endif endif
ifeq ($(CONFIG_IOEXPANDER_AW9523B),y)
CSRCS += aw9523b.c
endif
endif # CONFIG_IOEXPANDER endif # CONFIG_IOEXPANDER
# GPIO test device driver (independent of IOEXPANDERS) # GPIO test device driver (independent of IOEXPANDERS)

1529
drivers/ioexpander/aw9523b.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,188 @@
/****************************************************************************
* drivers/ioexpander/aw9523b.h
*
* 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.
*
****************************************************************************/
/* References:
* "16 Multi-function LED Driver and GPIO Controller with I2C Interface",
* May 2016, v1.1.1, Shanghai Awinic Technology Co., Ltd.
* Derived from the PCA9555 driver.
*/
#ifndef __DRIVERS_IOEXPANDER_AW9523B_H
#define __DRIVERS_IOEXPANDER_AW9523B_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/wdog.h>
#include <nuttx/clock.h>
#include <nuttx/semaphore.h>
#include <nuttx/wqueue.h>
#include <nuttx/ioexpander/ioexpander.h>
#include <nuttx/ioexpander/aw9523b.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/irq.h>
#if defined(CONFIG_IOEXPANDER) && defined(CONFIG_IOEXPANDER_AW9523B)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* Prerequisites:
* CONFIG_I2C
* I2C support is required
* CONFIG_IOEXPANDER
* Enables support for the AW9523B I/O expander
*
* CONFIG_IOEXPANDER_AW9523B
* Enables support for the AW9523B driver (Needs CONFIG_INPUT)
* CONFIG_AW9523B_MULTIPLE
* Can be defined to support multiple AW9523B devices on board.
* CONFIG_AW9523B_INT_ENABLE
* Enables support for pin on-change interrupts.
* CONFIG_AW9523B_INT_NCALLBACKS
* Maximum number of supported pin interrupt callbacks.
*/
#ifdef CONFIG_AW9523B_INT_ENABLE
# ifndef CONFIG_AW9523B_INT_NCALLBACKS
# define CONFIG_AW9523B_INT_NCALLBACKS 4
# endif
# ifndef CONFIG_SCHED_WORKQUEUE
# error Work queue support required. CONFIG_SCHED_WORKQUEUE must be selected.
# endif
#endif
#undef CONFIG_AW9523B_REFCNT
/* Driver support ***********************************************************/
/* This format is used to construct the /dev/input[n] device driver path.
* It defined here
* so that it will be used consistently in all places.
*/
/* AW9523B Resources ********************************************************/
#ifndef CONFIG_I2C
#error "CONFIG_I2C is required by AW9523B"
#endif
#define AW9523B_MAXDEVS 4
/* AW9523B Registers ********************************************************/
#define AW9523B_I2C_ADDR_BASE 0x58 /* 7-bit base address for AW9523B */
/* AW9523B register addresses */
#define AW9523B_REG_INPUT0 0x00
#define AW9523B_REG_INPUT1 0x01
#define AW9523B_REG_OUTPUT0 0x02
#define AW9523B_REG_OUTPUT1 0x03
#define AW9523B_REG_CONFIG0 0x04
#define AW9523B_REG_CONFIG1 0x05
#define AW9523B_REG_INT0 0x06
#define AW9523B_REG_INT1 0x07
#define AW9523B_REG_ID 0x10
#define AW9523B_REG_GCR 0x11
#define AW9523B_REG_LEDMODE0 0x12
#define AW9523B_REG_LEDMODE1 0x13
#define AW9523B_REG_DIM_P1_0 0x20
#define AW9523B_REG_DIM_P0_0 0x24
#define AW9523B_REG_DIM_P1_4 0x2c
#define AW9523B_REG_RESET 0x7f
#define AW9523B_REG_GCR_DIMMING_MASK 0x03
/* The number of registers to shadow if we're using shadow mode */
#define AW9523B_NUM_SHADOW_REGS 0x14
/* LED default current = 5mA. 5mA / 37mA * 255 = 34 */
#define AW9523B_LED_DEFAULT_DIMMING 34
/* Default output values for each of the subaddresses. */
#define AW9523B_DEFAULT_OUT_0 0x0000
#define AW9523B_DEFAULT_OUT_1 0x0f00
#define AW9523B_DEFAULT_OUT_2 0xf000
#define AW9523B_DEFAULT_OUT_3 0xff00
/* All pins are GPIOs by default, not LEDs. */
#define AW9523B_LEDMODE_ALL_GPIO 0xff
/****************************************************************************
* Public Types
****************************************************************************/
#ifdef CONFIG_AW9523B_INT_ENABLE
/* This type represents on registered pin interrupt callback */
struct aw9523b_callback_s
{
ioe_pinset_t pinset; /* Set of pin interrupts that will generate
* the callback. */
ioe_callback_t cbfunc; /* The saved callback function pointer */
FAR void *cbarg; /* Callback argument */
};
#endif
/* This structure represents the state of the AW9523B driver */
struct aw9523b_dev_s
{
struct ioexpander_dev_s dev; /* Nested structure to allow casting as public gpio
* expander. */
#ifdef CONFIG_AW9523B_SHADOW_MODE
uint8_t sreg[AW9523B_NUM_SHADOW_REGS]; /* Shadowed registers of the AW9523B */
#endif
#ifdef CONFIG_AW9523B_MULTIPLE
FAR struct aw9523b_dev_s *flink; /* Supports a singly linked list of drivers */
#endif
FAR struct aw9523b_config_s *config; /* Board configuration data */
FAR struct i2c_master_s *i2c; /* Saved I2C driver instance */
sem_t exclsem; /* Mutual exclusion */
#ifdef CONFIG_AW9523B_INT_ENABLE
struct work_s work; /* Supports the interrupt handling "bottom half" */
/* Saved callback information for each I/O expander client */
struct aw9523b_callback_s cb[CONFIG_AW9523B_INT_NCALLBACKS];
#endif
#ifdef CONFIG_AW9523B_LED_ENABLE
ioe_pinset_t output_is_on_bitset; /* Indicates if each output is active */
ioe_pinset_t is_led_bitset; /* Indicates if each pin is a LED */
uint8_t led_current[AW9523B_GPIO_NPINS]; /* LED current for each pin */
#endif
ioe_pinset_t invert_pin; /* Pins that are inverted (either input or output) */
};
#endif /* CONFIG_IOEXPANDER && CONFIG_IOEXPANDER_AW9523B */
#endif /* __DRIVERS_IOEXPANDER_AW9523B_H */

View file

@ -0,0 +1,177 @@
/****************************************************************************
* include/nuttx/ioexpander/aw9523b.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.
*
****************************************************************************/
/* References:
* "16-bit I2C-bus and SMBus I/O port with interrupt product datasheet",
* Rev. 08 - 22 October 2009, NXP
*/
#ifndef __INCLUDE_NUTTX_IOEXPANDER_AW9523B_H
#define __INCLUDE_NUTTX_IOEXPANDER_AW9523B_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/i2c/i2c_master.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define AW9523B_GPIO_NPINS 16 /* All pins can be used as GPIOs */
#define AW9523B_ID 0x23 /* Device ID */
/****************************************************************************
* Public Types
****************************************************************************/
/* A reference to a structure of this type must be passed to the AW9523B
* driver when the driver is instantiated. This structure provides
* information about the configuration of the AW9523B and provides some
* board-specific hooks.
*
* 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. The
* memory must be writeable because, under certain circumstances, the driver
* may modify the frequency.
*/
struct aw9523b_config_s
{
/* Device characterization */
uint8_t sub_address; /* configured via the ad1 and ad0 pins. 0-3 */
uint32_t frequency; /* I2C or SPI frequency */
#ifdef CONFIG_AW9523B_INT_ENABLE
uint8_t irq; /* IRQ number for the device */
/* If multiple AW9523B devices are supported, then an IRQ number must
* be provided for each so that their interrupts can be distinguished.
*/
/* IRQ/GPIO access callbacks. These operations all hidden behind
* callbacks to isolate the AW9523B driver from differences in GPIO
* interrupt handling by varying boards and MCUs.
*
* attach - Attach the AW9523B interrupt handler to the GPIO interrupt
* enable - Enable or disable the GPIO interrupt
*/
CODE int (*attach)(FAR struct aw9523b_config_s *state, xcpt_t isr,
FAR void *arg);
CODE void (*enable)(FAR struct aw9523b_config_s *state, bool enable);
#endif
};
/* AW9523B-specific options */
enum aw9523b_option_e
{
AW9523B_OPTION_SOFTWARE_RESET = 1, /* Software reset the device */
AW9523B_OPTION_PORT0_PUSH_PULL, /* Set port 0 as push-pull */
AW9523B_OPTION_READ_ID, /* Read the ID register */
#ifdef CONFIG_AW9523B_LED_ENABLE
AW9523B_OPTION_DIMMING, /* Set the dimming range for LEDs */
AW9523B_OPTION_LED_CURRENT, /* Set the LED current for a pin */
#endif
};
typedef enum aw9523b_option_e aw9523b_option_t;
/* Values for AW9523B_OPTION_* */
#define AW9523B_OPTION_DIMMING_100 0
#define AW9523B_OPTION_DIMMING_75 1
#define AW9523B_OPTION_DIMMING_50 2
#define AW9523B_OPTION_DIMMING_25 3
#define AW9523B_OPTION_P0_PP_OPEN_DRAIN 0
#define AW9523B_OPTION_P0_PP_PUSH_PULL 1
#define AW9523B_OPTION_LED_CURRENT_MAX 255 /* Max. LED current setting */
/* aw9523b-specific option structure
*
* Options:
* port0_push_pull - Set port 0 as push-pull vs open-drain.
* 1 = push-pull, 0 = open-drain.
* id - Returned by AW9523B_OPTION_READ_ID.
* dimming - Dimming range for LEDs. 0-3.
* 0 = max. 1 = 0.75x. 2 = 0.5x. 3 = 0.25x.
* led_current - LED current 0-255.
* Total current = 37mA * dimming * led_current/255.
*/
struct aw9523b_nongeneric_option_s
{
aw9523b_option_t command; /* Option command */
union
{
uint8_t port0_push_pull;
uint8_t id;
#ifdef CONFIG_AW9523B_LED_ENABLE
uint8_t dimming;
uint8_t led_current;
#endif
} value;
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: aw9523b_initialize
*
* Description:
* Instantiate and configure the AW9523B device driver to use the provided
* I2C device
* instance.
*
* Input Parameters:
* dev - An I2C driver instance
* minor - The device i2c address
* config - Persistent board configuration data
*
* Returned Value:
* an ioexpander_dev_s instance on success, NULL on failure.
*
****************************************************************************/
FAR struct ioexpander_dev_s *aw9523b_initialize(FAR struct i2c_master_s *dev,
FAR struct aw9523b_config_s *config);
#ifdef __cplusplus
}
#endif
#endif /* __INCLUDE_NUTTX_IOEXPANDER_AW9523B_H */