Skip to content

Commit

Permalink
drivers/tca64xx: Add support for PCAL6416
Browse files Browse the repository at this point in the history
New part support added to driver,
pullup/pulldown configuration support

Signed-off-by: Jouni Ukkonen <[email protected]>
  • Loading branch information
joukkone committed Nov 7, 2024
1 parent 2b85095 commit 27ee0b4
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 7 deletions.
148 changes: 141 additions & 7 deletions drivers/ioexpander/tca64xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -132,6 +135,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,
Expand All @@ -140,6 +145,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,
Expand All @@ -148,6 +155,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,
},
};

Expand Down Expand Up @@ -254,6 +273,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_pu_select;

if (reg == TCA64XX_INVALID_REG)
{
return reg;
}

DEBUGASSERT(pin <= part->tp_ngpios);
return reg + (pin >> 3);
}

/****************************************************************************
* Name: tca64_getreg
*
Expand Down Expand Up @@ -373,12 +436,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);

Expand Down Expand Up @@ -409,7 +466,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
Expand Down Expand Up @@ -439,6 +498,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;
Expand Down
18 changes: 18 additions & 0 deletions drivers/ioexpander/tca64xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@

/* TCA64XX Parts ************************************************************/

#define TCA64XX_INVALID_REG 0xff

#define TCA6408_INPUT_REG 0x00
#define TCA6408_OUTPUT_REG 0x01
#define TCA6408_POLARITY_REG 0x02
Expand Down Expand Up @@ -132,6 +134,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
Expand Down Expand Up @@ -181,6 +197,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
Expand Down
1 change: 1 addition & 0 deletions include/nuttx/ioexpander/tca64xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ enum tca64xx_part_e
TCA6408_PART = 0,
TCA6416_PART,
TCA6424_PART,
PCAL6416A_PART,
TCA64_NPARTS
};

Expand Down

0 comments on commit 27ee0b4

Please sign in to comment.