This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 9b8c8bdd7b015ae34337e0b3b44620136dca1db6 Author: Jouni Ukkonen <jouni.ukko...@unikie.com> AuthorDate: Wed Nov 6 10:33:20 2024 +0200 drivers/tca64xx: Add support for PCAL6416 - Added new part support for PCAL6416 - Added pullup/pulldown configuration support Signed-off-by: Jouni Ukkonen <jouni.ukko...@unikie.com> Signed-off-by: Jukka Laitinen <jukka.laiti...@tii.ae> --- drivers/ioexpander/tca64xx.c | 148 +++++++++++++++++++++++++++++++++++-- drivers/ioexpander/tca64xx.h | 18 +++++ include/nuttx/ioexpander/tca64xx.h | 1 + 3 files changed, 160 insertions(+), 7 deletions(-) diff --git a/drivers/ioexpander/tca64xx.c b/drivers/ioexpander/tca64xx.c index a830322e6e..11fe4fec4d 100644 --- a/drivers/ioexpander/tca64xx.c +++ b/drivers/ioexpander/tca64xx.c @@ -53,6 +53,9 @@ static uint8_t tca64_input_reg(FAR struct tca64_dev_s *priv, uint8_t pin); static uint8_t tca64_output_reg(FAR struct tca64_dev_s *priv, uint8_t pin); static uint8_t tca64_polarity_reg(FAR struct tca64_dev_s *priv, uint8_t pin); static uint8_t tca64_config_reg(FAR struct tca64_dev_s *priv, uint8_t pin); +static uint8_t tca64_pdenable_reg(FAR struct tca64_dev_s *priv, uint8_t pin); +static uint8_t tca64_pdselect_reg(FAR struct tca64_dev_s *priv, uint8_t pin); + static int tca64_getreg(FAR struct tca64_dev_s *priv, uint8_t regaddr, FAR uint8_t *regval, unsigned int count); static int tca64_putreg(struct tca64_dev_s *priv, uint8_t regaddr, @@ -134,6 +137,8 @@ static const struct tca64_part_s g_tca64_parts[TCA64_NPARTS] = TCA6408_OUTPUT_REG, TCA6408_POLARITY_REG, TCA6408_CONFIG_REG, + TCA64XX_INVALID_REG, + TCA64XX_INVALID_REG, }, { TCA6416_PART, @@ -142,6 +147,8 @@ static const struct tca64_part_s g_tca64_parts[TCA64_NPARTS] = TCA6416_OUTPUT0_REG, TCA6416_POLARITY0_REG, TCA6416_CONFIG0_REG, + TCA64XX_INVALID_REG, + TCA64XX_INVALID_REG, }, { TCA6424_PART, @@ -150,6 +157,18 @@ static const struct tca64_part_s g_tca64_parts[TCA64_NPARTS] = TCA6424_OUTPUT0_REG, TCA6424_POLARITY0_REG, TCA6424_CONFIG0_REG, + TCA64XX_INVALID_REG, + TCA64XX_INVALID_REG, + }, + { + PCAL6416A_PART, + MIN(PCAL6416A_NR_GPIOS, CONFIG_IOEXPANDER_NPINS), + PCAL6416A_INPUT0_REG, + PCAL6416A_OUTPUT0_REG, + PCAL6416A_POLARITY0_REG, + PCAL6416A_CONFIG0_REG, + PCAL6416A_PU_ENABLE0_REG, + PCAL6416A_PUPD_SELECT0_REG, }, }; @@ -256,6 +275,50 @@ static uint8_t tca64_config_reg(FAR struct tca64_dev_s *priv, uint8_t pin) return reg + (pin >> 3); } +/**************************************************************************** + * Name: tca64_pdenable_reg + * + * Description: + * Return the address of the pu/pd enable register for the specified pin. + * + ****************************************************************************/ + +static uint8_t tca64_pdenable_reg(FAR struct tca64_dev_s *priv, uint8_t pin) +{ + FAR const struct tca64_part_s *part = tca64_getpart(priv); + uint8_t reg = part->tp_puenable; + + if (reg == TCA64XX_INVALID_REG) + { + return reg; + } + + DEBUGASSERT(pin <= part->tp_ngpios); + return reg + (pin >> 3); +} + +/**************************************************************************** + * Name: tca64_pdselect_reg + * + * Description: + * Return the address of the pu/pd selection register for the specified pin. + * + ****************************************************************************/ + +static uint8_t tca64_pdselect_reg(FAR struct tca64_dev_s *priv, uint8_t pin) +{ + FAR const struct tca64_part_s *part = tca64_getpart(priv); + uint8_t reg = part->tp_puselect; + + if (reg == TCA64XX_INVALID_REG) + { + return reg; + } + + DEBUGASSERT(pin <= part->tp_ngpios); + return reg + (pin >> 3); +} + /**************************************************************************** * Name: tca64_getreg * @@ -375,12 +438,6 @@ static int tca64_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin, uint8_t regval; int ret; - if (direction != IOEXPANDER_DIRECTION_IN && - direction != IOEXPANDER_DIRECTION_OUT) - { - return -EINVAL; - } - DEBUGASSERT(priv != NULL && priv->config != NULL && pin < CONFIG_IOEXPANDER_NPINS); @@ -411,7 +468,9 @@ static int tca64_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin, /* Set the pin direction in the I/O Expander */ - if (direction == IOEXPANDER_DIRECTION_IN) + if ((direction == IOEXPANDER_DIRECTION_IN) || + (direction == IOEXPANDER_DIRECTION_IN_PULLDOWN) || + (direction == IOEXPANDER_DIRECTION_IN_PULLUP)) { /* Configure pin as input. If a bit in the configuration register is * set to 1, the corresponding port pin is enabled as an input with a @@ -441,6 +500,81 @@ static int tca64_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin, regaddr, ret); } + if ((direction == IOEXPANDER_DIRECTION_IN_PULLDOWN) || + (direction == IOEXPANDER_DIRECTION_IN_PULLUP)) + { + regaddr = tca64_pdenable_reg(priv, pin); + if (regaddr == TCA64XX_INVALID_REG) + { + gpioerr("ERROR: This part does not support PU/PD settings\n"); + ret = -EINVAL; + goto errout_with_lock; + } + + ret = tca64_getreg(priv, regaddr, ®val, 1); + if (ret < 0) + { + gpioerr("ERROR: Failed to read pu config register at %u: %d\n", + regaddr, ret); + goto errout_with_lock; + } + + regval |= (1 << (pin & 7)); + + ret = tca64_putreg(priv, regaddr, ®val, 1); + if (ret < 0) + { + gpioerr("ERROR: Failed to write pu config register at %u: %d\n", + regaddr, ret); + goto errout_with_lock; + } + + regaddr = tca64_pdselect_reg(priv, pin); + ret = tca64_getreg(priv, regaddr, ®val, 1); + if (ret < 0) + { + gpioerr("ERROR: Failed to read pu select register at %u: %d\n", + regaddr, ret); + goto errout_with_lock; + } + + if (direction == IOEXPANDER_DIRECTION_IN_PULLUP) + { + regval |= (1 << (pin & 7)); + } + else + { + regval &= ~(1 << (pin & 7)); + } + + ret = tca64_putreg(priv, regaddr, ®val, 1); + if (ret < 0) + { + gpioerr("ERROR: Failed to write pu select register at %u: %d\n", + regaddr, ret); + goto errout_with_lock; + } + } + else if (direction == IOEXPANDER_DIRECTION_IN) + { + /* Disable pu/pd if that is available */ + + regaddr = tca64_pdenable_reg(priv, pin); + if (regaddr != TCA64XX_INVALID_REG) + { + ret = tca64_getreg(priv, regaddr, ®val, 1); + if (ret < 0) + { + gpioerr("ERROR: Failed to read pu config register at %u: %d\n", + regaddr, ret); + goto errout_with_lock; + } + + regval &= ~(1 << (pin & 7)); + ret = tca64_putreg(priv, regaddr, ®val, 1); + } + } + errout_with_lock: nxmutex_unlock(&priv->lock); return ret; diff --git a/drivers/ioexpander/tca64xx.h b/drivers/ioexpander/tca64xx.h index 47695874e4..5c2c64a36b 100644 --- a/drivers/ioexpander/tca64xx.h +++ b/drivers/ioexpander/tca64xx.h @@ -99,6 +99,8 @@ /* TCA64XX Parts ************************************************************/ +#define TCA64XX_INVALID_REG 0xff + #define TCA6408_INPUT_REG 0x00 #define TCA6408_OUTPUT_REG 0x01 #define TCA6408_POLARITY_REG 0x02 @@ -134,6 +136,20 @@ #define TCA64XX_NR_GPIO_MAX TCA6424_NR_GPIOS +#define PCAL6416A_INPUT0_REG 0x00 +#define PCAL6416A_INPUT1_REG 0x01 +#define PCAL6416A_OUTPUT0_REG 0x02 +#define PCAL6416A_OUTPUT1_REG 0x03 +#define PCAL6416A_POLARITY0_REG 0x04 +#define PCAL6416A_POLARITY1_REG 0x05 +#define PCAL6416A_CONFIG0_REG 0x06 +#define PCAL6416A_CONFIG1_REG 0x07 +#define PCAL6416A_PU_ENABLE0_REG 0x46 +#define PCAL6416A_PU_ENABLE1_REG 0x47 +#define PCAL6416A_PUPD_SELECT0_REG 0x48 +#define PCAL6416A_PUPD_SELECT1_REG 0x49 +#define PCAL6416A_NR_GPIOS 16 + /* 1us (datasheet: reset pulse duration (Tw) is 4ns */ #define TCA64XX_TW 1 @@ -183,6 +199,8 @@ struct tca64_part_s uint8_t tp_output; /* Address of first output register */ uint8_t tp_polarity; /* Address of first polarity register */ uint8_t tp_config; /* Address of first configuration register */ + uint8_t tp_puenable; + uint8_t tp_puselect; }; #ifdef CONFIG_IOEXPANDER_INT_ENABLE diff --git a/include/nuttx/ioexpander/tca64xx.h b/include/nuttx/ioexpander/tca64xx.h index 263524628b..189353361a 100644 --- a/include/nuttx/ioexpander/tca64xx.h +++ b/include/nuttx/ioexpander/tca64xx.h @@ -43,6 +43,7 @@ enum tca64xx_part_e TCA6408_PART = 0, TCA6416_PART, TCA6424_PART, + PCAL6416A_PART, TCA64_NPARTS };