From b73d7f2922ae6c91f3b5cc3320df320a81a65e44 Mon Sep 17 00:00:00 2001 From: wangjianyu3 Date: Mon, 24 Mar 2025 19:48:47 +0800 Subject: [PATCH] drivers/ioexpander: Add support for PCA9557 Datasheet: https://www.ti.com/lit/ds/symlink/pca9557.pdf Signed-off-by: wangjianyu3 --- drivers/ioexpander/Kconfig | 31 ++ drivers/ioexpander/Make.defs | 4 + drivers/ioexpander/pca9557.c | 654 +++++++++++++++++++++++++++++ drivers/ioexpander/pca9557.h | 96 +++++ include/nuttx/ioexpander/pca9557.h | 99 +++++ 5 files changed, 884 insertions(+) create mode 100644 drivers/ioexpander/pca9557.c create mode 100644 drivers/ioexpander/pca9557.h create mode 100644 include/nuttx/ioexpander/pca9557.h diff --git a/drivers/ioexpander/Kconfig b/drivers/ioexpander/Kconfig index 6f982b3fbb1..81b73407993 100644 --- a/drivers/ioexpander/Kconfig +++ b/drivers/ioexpander/Kconfig @@ -312,6 +312,37 @@ config PCA9538_RETRY endif # IOEXPANDER_PCA9538 +config IOEXPANDER_PCA9557 + bool "PCA9557 I2C IO expander" + default n + depends on I2C + ---help--- + Enable support for the NXP PCA9557 IO Expander + +if IOEXPANDER_PCA9557 + +config PCA9557_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 PCA9557_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_PCA9557 + config IOEXPANDER_TCA64XX bool "TCA64XX I2C IO expander" default n diff --git a/drivers/ioexpander/Make.defs b/drivers/ioexpander/Make.defs index 290f5f0be2a..8e44fb4c086 100644 --- a/drivers/ioexpander/Make.defs +++ b/drivers/ioexpander/Make.defs @@ -54,6 +54,10 @@ ifeq ($(CONFIG_IOEXPANDER_PCA9538),y) CSRCS += pca9538.c endif +ifeq ($(CONFIG_IOEXPANDER_PCA9557),y) + CSRCS += pca9557.c +endif + ifeq ($(CONFIG_IOEXPANDER_TCA64XX),y) CSRCS += tca64xx.c endif diff --git a/drivers/ioexpander/pca9557.c b/drivers/ioexpander/pca9557.c new file mode 100644 index 00000000000..c9b12a67b99 --- /dev/null +++ b/drivers/ioexpander/pca9557.c @@ -0,0 +1,654 @@ +/**************************************************************************** + * drivers/ioexpander/pca9557.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 + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pca9557.h" + +#if defined(CONFIG_IOEXPANDER_PCA9557) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline int pca9557_i2c_write(FAR struct pca9557_dev_s *pca, + FAR const uint8_t *wbuffer, int wbuflen); +static inline int pca9557_i2c_writeread(FAR struct pca9557_dev_s *pca, + FAR const uint8_t *wbuffer, + int wbuflen, FAR uint8_t *rbuffer, + int rbuflen); +static int pca9557_setbit(FAR struct pca9557_dev_s *pca, uint8_t reg, + uint8_t pin, bool bitval); +static int pca9557_getbit(FAR struct pca9557_dev_s *pca, uint8_t reg, + uint8_t pin, FAR bool *val); +static int pca9557_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin, + int direction); +static int pca9557_option(FAR struct ioexpander_dev_s *dev, uint8_t pin, + int opt, FAR void *value); +static int pca9557_writepin(FAR struct ioexpander_dev_s *dev, uint8_t pin, + bool value); +static int pca9557_readpin(FAR struct ioexpander_dev_s *dev, uint8_t pin, + FAR bool *value); +static int pca9557_readbuf(FAR struct ioexpander_dev_s *dev, uint8_t pin, + FAR bool *value); +#ifdef CONFIG_IOEXPANDER_MULTIPIN +static int pca9557_getmultibits(FAR struct pca9557_dev_s *pca, uint8_t reg, + FAR uint8_t *pins, FAR bool *values, + int count); +static int pca9557_multiwritepin(FAR struct ioexpander_dev_s *dev, + FAR const uint8_t *pins, + FAR const bool *values, int count); +static int pca9557_multireadpin(FAR struct ioexpander_dev_s *dev, + FAR const uint8_t *pins, + FAR bool *values, int count); +static int pca9557_multireadbuf(FAR struct ioexpander_dev_s *dev, + FAR uint8_t *pins, FAR bool *values, + int count); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* I/O expander vtable */ + +static const struct ioexpander_ops_s g_pca9557_ops = +{ + .ioe_direction = pca9557_direction, + .ioe_option = pca9557_option, + .ioe_writepin = pca9557_writepin, + .ioe_readpin = pca9557_readpin, + .ioe_readbuf = pca9557_readbuf, +#ifdef CONFIG_IOEXPANDER_MULTIPIN + .ioe_multiwritepin = pca9557_multiwritepin, + .ioe_multireadpin = pca9557_multireadpin, + .ioe_multireadbuf = pca9557_multireadbuf, +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pca9557_i2c_write + * + * Description: + * Write to the I2C device. + * + ****************************************************************************/ + +static inline int pca9557_i2c_write(FAR struct pca9557_dev_s *pca, + FAR const uint8_t *wbuffer, int wbuflen) +{ + struct i2c_msg_s msg; + int ret; + + /* Setup for the transfer */ + + msg.frequency = pca->config->frequency; + msg.addr = pca->config->address; + msg.flags = 0; + msg.buffer = (FAR uint8_t *)wbuffer; /* Override const */ + msg.length = wbuflen; + + /* Then perform the transfer. */ + + ret = I2C_TRANSFER(pca->i2c, &msg, 1); + return (ret >= 0) ? OK : ret; +} + +/**************************************************************************** + * Name: pca9557_i2c_writeread + * + * Description: + * Write to then read from the I2C device. + * + ****************************************************************************/ + +static inline int pca9557_i2c_writeread(FAR struct pca9557_dev_s *pca, + FAR const uint8_t *wbuffer, + int wbuflen, FAR uint8_t *rbuffer, + int rbuflen) +{ + struct i2c_config_s config; + + /* Set up the configuration and perform the write-read operation */ + + config.frequency = pca->config->frequency; + config.address = pca->config->address; + config.addrlen = 7; + + return i2c_writeread(pca->i2c, &config, wbuffer, + wbuflen, rbuffer, rbuflen); +} + +/**************************************************************************** + * Name: pca9557_setbit + * + * Description: + * Write a bit in a register pair + * + ****************************************************************************/ + +static int pca9557_setbit(FAR struct pca9557_dev_s *pca, uint8_t reg, + uint8_t pin, bool bitval) +{ + uint8_t buf[2]; + int ret; + + if (pin >= PCA9557_GPIO_NPINS) + { + return -ENXIO; + } + + ret = nxrmutex_lock(&pca->lock); + if (ret < 0) + { + return ret; + } + + buf[0] = reg; + +#ifdef CONFIG_PCA9557_SHADOW_MODE + /* Get the shadowed register value */ + + buf[1] = pca->sreg[reg]; + +#else + /* Get the register value from the IO-Expander */ + + ret = pca9557_i2c_writeread(pca, &buf[0], 1, &buf[1], 1); + if (ret < 0) + { + nxrmutex_unlock(&pca->lock); + return ret; + } +#endif + + if (bitval) + { + buf[1] |= (1 << pin); + } + else + { + buf[1] &= ~(1 << pin); + } + + ret = pca9557_i2c_write(pca, buf, 2); +#ifdef CONFIG_PCA9557_RETRY + if (ret != OK) + { + /* Try again (only once) */ + + ret = pca9557_i2c_write(pca, buf, 2); + } +#endif + +#ifdef CONFIG_PCA9557_SHADOW_MODE + if (ret == OK) + { + /* Save the new register value in the shadow register */ + + pca->sreg[reg] = buf[1]; + } +#endif + + nxrmutex_unlock(&pca->lock); + return ret; +} + +/**************************************************************************** + * Name: pca9557_getbit + * + * Description: + * Get a bit from a register pair + * + ****************************************************************************/ + +static int pca9557_getbit(FAR struct pca9557_dev_s *pca, uint8_t reg, + uint8_t pin, FAR bool *val) +{ + uint8_t buf; + int ret; + + if (pin >= PCA9557_GPIO_NPINS) + { + return -ENXIO; + } + + ret = nxrmutex_lock(&pca->lock); + if (ret < 0) + { + return ret; + } + + ret = pca9557_i2c_writeread(pca, ®, 1, &buf, 1); + if (ret < 0) + { + nxrmutex_unlock(&pca->lock); + return ret; + } + +#ifdef CONFIG_PCA9557_SHADOW_MODE + /* Save the new register value in the shadow register */ + + pca->sreg[reg] = buf; +#endif + + *val = (buf >> pin) & 1; + nxrmutex_unlock(&pca->lock); + return OK; +} + +/**************************************************************************** + * Name: pca9557_direction + * + * Description: + * Set the direction of an ioexpander pin. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * dir - One of the IOEXPANDER_DIRECTION_ macros + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int pca9557_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin, + int direction) +{ + if (direction != IOEXPANDER_DIRECTION_IN && + direction != IOEXPANDER_DIRECTION_OUT) + { + return -EINVAL; + } + + return pca9557_setbit((FAR struct pca9557_dev_s *)dev, PCA9557_REG_CONFIG, + pin, (direction == IOEXPANDER_DIRECTION_IN)); +} + +/**************************************************************************** + * Name: pca9557_option + * + * Description: + * Set pin options. Required. + * Since all IO expanders have various pin options, this API allows setting + * pin options in a flexible way. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * opt - One of the IOEXPANDER_OPTION_ macros + * val - The option's value + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int pca9557_option(FAR struct ioexpander_dev_s *dev, uint8_t pin, + int opt, FAR void *value) +{ + int ret = -EINVAL; + + if (opt == IOEXPANDER_OPTION_INVERT) + { + ret = pca9557_setbit((FAR struct pca9557_dev_s *)dev, + PCA9557_REG_POLINV, pin, + ((uintptr_t)value == IOEXPANDER_VAL_INVERT)); + } + + return ret; +} + +/**************************************************************************** + * Name: pca9557_writepin + * + * Description: + * Set the pin level. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * val - The pin level. Usually TRUE will set the pin high, + * except if OPTION_INVERT has been set on this pin. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int pca9557_writepin(FAR struct ioexpander_dev_s *dev, uint8_t pin, + bool value) +{ + return pca9557_setbit((FAR struct pca9557_dev_s *)dev, PCA9557_REG_OUTPUT, + pin, value); +} + +/**************************************************************************** + * Name: pca9557_readpin + * + * Description: + * Read the actual PIN level. This can be different from the last value + * written to this pin. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin + * valptr - Pointer to a buffer where the pin level is stored. + * Usually TRUE if the pin is high, except if OPTION_INVERT + * has been set on this pin. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int pca9557_readpin(FAR struct ioexpander_dev_s *dev, uint8_t pin, + FAR bool *value) +{ + return pca9557_getbit((FAR struct pca9557_dev_s *)dev, PCA9557_REG_INPUT, + pin, value); +} + +/**************************************************************************** + * Name: pca9557_readbuf + * + * Description: + * Read the buffered pin level. + * This can be different from the actual pin state. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin + * valptr - Pointer to a buffer where the level is stored. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int pca9557_readbuf(FAR struct ioexpander_dev_s *dev, uint8_t pin, + FAR bool *value) +{ + return pca9557_getbit((FAR struct pca9557_dev_s *)dev, PCA9557_REG_OUTPUT, + pin, value); +} + +#ifdef CONFIG_IOEXPANDER_MULTIPIN + +/**************************************************************************** + * Name: pca9557_getmultibits + * + * Description: + * Read multiple bits from PCA9557 registers. + * + ****************************************************************************/ + +static int pca9557_getmultibits(FAR struct pca9557_dev_s *pca, uint8_t reg, + FAR uint8_t *pins, FAR bool *values, + int count) +{ + uint8_t val; + int ret = OK; + int i; + int pin; + + ret = nxrmutex_lock(&pca->lock); + if (ret < 0) + { + return ret; + } + + ret = pca9557_i2c_writeread(pca, ®, 1, &val, 1); + if (ret < 0) + { + nxrmutex_unlock(&pca->lock); + return ret; + } + +#ifdef CONFIG_PCA9557_SHADOW_MODE + /* Save the new register value in the shadow register */ + + pca->sreg[reg] = val; +#endif + + /* Read the requested bits */ + + for (i = 0; i < count; i++) + { + pin = pins[i]; + if (pin >= PCA9557_GPIO_NPINS) + { + nxrmutex_unlock(&pca->lock); + return -ENXIO; + } + + values[i] = (val >> pin) & 1; + } + + nxrmutex_unlock(&pca->lock); + return OK; +} + +/**************************************************************************** + * Name: pca9557_multiwritepin + * + * Description: + * Set the pin level for multiple pins. This routine may be faster than + * individual pin accesses. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * pins - The list of pin indexes to alter in this call + * val - The list of pin levels. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int pca9557_multiwritepin(FAR struct ioexpander_dev_s *dev, + FAR const uint8_t *pins, + FAR const bool *values, int count) +{ + FAR struct pca9557_dev_s *pca = (FAR struct pca9557_dev_s *)dev; + uint8_t reg = PCA9557_REG_OUTPUT; + uint8_t buf[2]; + int ret; + int i; + int pin; + + /* Get exclusive access to the PCA9557 */ + + ret = nxrmutex_lock(&pca->lock); + if (ret < 0) + { + return ret; + } + + /* Start by reading both registers, whatever the pins to change. We could + * attempt to read one port only if all pins were on the same port, but + * this would not save much. + */ + +#ifndef CONFIG_PCA9557_SHADOW_MODE + ret = pca9557_i2c_writeread(pca, ®, 1, &buf[1], 1); + if (ret < 0) + { + nxrmutex_unlock(&pca->lock); + return ret; + } +#else + /* In Shadow-Mode we "read" the pin status from the shadow registers */ + + buf[1] = pca->sreg[reg]; +#endif + + /* Apply the user defined changes */ + + for (i = 0; i < count; i++) + { + pin = pins[i]; + if (pin >= PCA9557_GPIO_NPINS) + { + nxrmutex_unlock(&pca->lock); + return -ENXIO; + } + + if (values[i]) + { + buf[1] |= (1 << pin); + } + else + { + buf[1] &= ~(1 << pin); + } + } + + /* Now write back the new pins states */ + + buf[0] = reg; +#ifdef CONFIG_PCA9557_SHADOW_MODE + /* Save the new register values in the shadow register */ + + pca->sreg[reg] = buf[1]; +#endif + ret = pca9557_i2c_write(pca, buf, 2); + + nxrmutex_unlock(&pca->lock); + return ret; +} + +/**************************************************************************** + * Name: pca9557_multireadpin + * + * Description: + * Read the actual level for multiple pins. This routine may be faster than + * individual pin accesses. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The list of pin indexes to read + * valptr - Pointer to a buffer where the pin levels are stored. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int pca9557_multireadpin(FAR struct ioexpander_dev_s *dev, + FAR const uint8_t *pins, + FAR bool *values, int count) +{ + return pca9557_getmultibits((FAR struct pca9557_dev_s *)dev, + PCA9557_REG_INPUT, pins, values, count); +} + +/**************************************************************************** + * Name: pca9557_multireadbuf + * + * Description: + * Read the buffered level of multiple pins. This routine may be faster + * than individual pin accesses. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin + * valptr - Pointer to a buffer where the buffered levels are stored. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int pca9557_multireadbuf(FAR struct ioexpander_dev_s *dev, + FAR uint8_t *pins, FAR bool *values, + int count) +{ + return pca9557_getmultibits((FAR struct pca9557_dev_s *)dev, + PCA9557_REG_OUTPUT, pins, values, count); +} + +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pca9557_initialize + * + * Description: + * Initialize a PCA9557 I2C device. + * + ****************************************************************************/ + +FAR struct ioexpander_dev_s * +pca9557_initialize(FAR struct i2c_master_s *i2cdev, + FAR struct pca9557_config_s *config) +{ + FAR struct pca9557_dev_s *pcadev; + + DEBUGASSERT(i2cdev != NULL && config != NULL); + + if (config->set_nreset_pin) + { + config->set_nreset_pin(true); + } + + /* Allocate the device state structure */ + + pcadev = kmm_zalloc(sizeof(struct pca9557_dev_s)); + if (!pcadev) + { + return NULL; + } + + /* Initialize the device state structure */ + + pcadev->i2c = i2cdev; + pcadev->dev.ops = &g_pca9557_ops; + pcadev->config = config; + + nxrmutex_init(&pcadev->lock); + return &pcadev->dev; +} + +#endif /* CONFIG_IOEXPANDER_PCA9557 */ diff --git a/drivers/ioexpander/pca9557.h b/drivers/ioexpander/pca9557.h new file mode 100644 index 00000000000..1421d24c667 --- /dev/null +++ b/drivers/ioexpander/pca9557.h @@ -0,0 +1,96 @@ +/**************************************************************************** + * drivers/ioexpander/pca9557.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 __DRIVERS_IOEXPANDER_PCA9557_H +#define __DRIVERS_IOEXPANDER_PCA9557_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_IOEXPANDER) && defined(CONFIG_IOEXPANDER_PCA9557) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Prerequisites: + * CONFIG_I2C + * I2C support is required + * CONFIG_IOEXPANDER + * Enables support for the PCA9557 I/O expander + * + * CONFIG_IOEXPANDER_PCA9557 + * Enables support for the PCA9557 driver (Needs CONFIG_INPUT) + */ + +/* PCA9557 Resources ********************************************************/ + +#define PCA9557_GPIO_NPINS 8 +#define PCA9557_MAXDEVS 8 + +/* I2C frequency */ + +#define PCA9557_I2C_MAXFREQUENCY 400000 /* 400KHz */ + +/* PCA9557 Registers ********************************************************/ + +#define PCA9557_REG_NUM 4 +#define PCA9557_REG_INPUT 0x00 +#define PCA9557_REG_OUTPUT 0x01 +#define PCA9557_REG_POLINV 0x02 +#define PCA9557_REG_CONFIG 0x03 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This structure represents the state of the PCA9557 driver */ + +struct pca9557_dev_s +{ + struct ioexpander_dev_s dev; /* Nested structure to allow casting + * as public gpio expander. */ +#ifdef CONFIG_PCA9557_SHADOW_MODE + uint8_t sreg[PCA9557_REG_NUM]; /* Shadowed registers */ +#endif + FAR struct pca9557_config_s *config; /* Board configuration data */ + FAR struct i2c_master_s *i2c; /* Saved I2C driver instance */ + rmutex_t lock; /* Mutual exclusion */ +}; + +#endif /* CONFIG_IOEXPANDER && CONFIG_IOEXPANDER_PCA9557 */ +#endif /* __DRIVERS_IOEXPANDER_PCA9557_H */ diff --git a/include/nuttx/ioexpander/pca9557.h b/include/nuttx/ioexpander/pca9557.h new file mode 100644 index 00000000000..a5ad913fc38 --- /dev/null +++ b/include/nuttx/ioexpander/pca9557.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * include/nuttx/ioexpander/pca9557.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_IOEXPANDER_PCA9557_H +#define __INCLUDE_NUTTX_IOEXPANDER_PCA9557_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* A reference to a structure of this type must be passed to the PCA9557 + * driver when the driver is instantiated. This structure provides + * information about the configuration of the PCA9557 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 pca9557_config_s +{ + /* Device characterization */ + + uint8_t address; /* 7-bit I2C address (only bits 0-6 used) */ + uint32_t frequency; /* I2C or SPI frequency */ + + /* Sets the state of the PCA9557's nReset pin, not invoke if NULL */ + + CODE void (*set_nreset_pin)(bool state); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: pca9557_initialize + * + * Description: + * Instantiate and configure the pca9557 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 * +pca9557_initialize(FAR struct i2c_master_s *dev, + FAR struct pca9557_config_s *config); + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_IOEXPANDER_PCA9557_H */