drivers/tca64xx: Add support for PCAL6416

- Added new part support for PCAL6416
- Added pullup/pulldown configuration support

Signed-off-by: Jouni Ukkonen <jouni.ukkonen@unikie.com>
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
Jouni Ukkonen 2024-11-06 10:33:20 +02:00 committed by Xiang Xiao
parent 710bd199e5
commit 9b8c8bdd7b
3 changed files with 160 additions and 7 deletions

View file

@ -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, &regval, 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, &regval, 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, &regval, 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, &regval, 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, &regval, 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, &regval, 1);
}
}
errout_with_lock:
nxmutex_unlock(&priv->lock);
return ret;

View file

@ -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

View file

@ -43,6 +43,7 @@ enum tca64xx_part_e
TCA6408_PART = 0,
TCA6416_PART,
TCA6424_PART,
PCAL6416A_PART,
TCA64_NPARTS
};