From e337fcb02607bc8ef244c5eeea515c0a687485a9 Mon Sep 17 00:00:00 2001 From: Jouni Ukkonen Date: Wed, 6 Nov 2024 10:33:20 +0200 Subject: [PATCH] drivers/tca64xx: Add support for PCAL6416 New part support added to driver, pullup/pulldown configuration support Signed-off-by: Jouni Ukkonen --- drivers/ioexpander/tca64xx.c | 106 +++++++++++++++++++++++++++-- drivers/ioexpander/tca64xx.h | 16 +++++ include/nuttx/ioexpander/tca64xx.h | 1 + 3 files changed, 116 insertions(+), 7 deletions(-) diff --git a/drivers/ioexpander/tca64xx.c b/drivers/ioexpander/tca64xx.c index c2fd74cb9a155..0449f2a57597c 100644 --- a/drivers/ioexpander/tca64xx.c +++ b/drivers/ioexpander/tca64xx.c @@ -51,6 +51,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, @@ -149,6 +152,16 @@ static const struct tca64_part_s g_tca64_parts[TCA64_NPARTS] = TCA6424_POLARITY0_REG, TCA6424_CONFIG0_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, + }, }; /**************************************************************************** @@ -254,6 +267,40 @@ 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; + + 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_pu_select; + + DEBUGASSERT(pin <= part->tp_ngpios); + return reg + (pin >> 3); +} + /**************************************************************************** * Name: tca64_getreg * @@ -373,12 +420,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); @@ -409,7 +450,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 @@ -439,6 +482,55 @@ 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); + 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; + } + } + errout_with_lock: nxmutex_unlock(&priv->lock); return ret; diff --git a/drivers/ioexpander/tca64xx.h b/drivers/ioexpander/tca64xx.h index bcec8af971a9f..f5b76d8d1d521 100644 --- a/drivers/ioexpander/tca64xx.h +++ b/drivers/ioexpander/tca64xx.h @@ -132,6 +132,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 @@ -181,6 +195,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_pu_select; }; #ifdef CONFIG_IOEXPANDER_INT_ENABLE diff --git a/include/nuttx/ioexpander/tca64xx.h b/include/nuttx/ioexpander/tca64xx.h index 96f7582675ba8..95892c6910d1a 100644 --- a/include/nuttx/ioexpander/tca64xx.h +++ b/include/nuttx/ioexpander/tca64xx.h @@ -60,6 +60,7 @@ enum tca64xx_part_e TCA6408_PART = 0, TCA6416_PART, TCA6424_PART, + PCAL6416A_PART, TCA64_NPARTS };