Bug fixes and improved interrupt support for mcp23x17 driver

This commit is contained in:
jturnsek 2023-03-05 18:38:24 +01:00 committed by Xiang Xiao
parent 468f2e3222
commit 97b4900c59
3 changed files with 72 additions and 12 deletions

View File

@ -78,6 +78,13 @@ config MCP23X17_INT_ENABLE
---help---
Enable driver interrupt functionality
config MCP23X17_INT_MIRROR
bool "Enable MCP23x17 Interrupt Mirror"
default n
select MCP23X17_INT_ENABLE
---help---
Enable driver interrupt mirror functionality
config MCP23X17_INT_NCALLBACKS
int "Max number of interrupt callbacks"
default 4

View File

@ -312,6 +312,7 @@ static int mcp23x17_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin,
int ret;
if (direction != IOEXPANDER_DIRECTION_IN &&
direction != IOEXPANDER_DIRECTION_IN_PULLUP &&
direction != IOEXPANDER_DIRECTION_OUT)
{
return -EINVAL;
@ -326,7 +327,17 @@ static int mcp23x17_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin,
}
ret = mcp23x17_setbit(priv, MCP23X17_IODIRA, pin,
(direction == IOEXPANDER_DIRECTION_IN));
(direction == IOEXPANDER_DIRECTION_IN) ||
(direction == IOEXPANDER_DIRECTION_IN_PULLUP));
if (ret < 0)
{
nxmutex_unlock(&priv->lock);
return ret;
}
ret = mcp23x17_setbit(priv, MCP23X17_GPPUA, pin,
(direction == IOEXPANDER_DIRECTION_IN_PULLUP));
nxmutex_unlock(&priv->lock);
return ret;
}
@ -746,6 +757,8 @@ static FAR void *mcp23x17_attach(FAR struct ioexpander_dev_s *dev,
{
FAR struct mcp23x17_dev_s *priv = (FAR struct mcp23x17_dev_s *)dev;
FAR void *handle = NULL;
uint8_t addr = MCP23X17_GPINTENA;
uint8_t buf[3];
int i;
int ret;
@ -754,7 +767,25 @@ static FAR void *mcp23x17_attach(FAR struct ioexpander_dev_s *dev,
ret = nxmutex_lock(&priv->lock);
if (ret < 0)
{
return ret;
return NULL;
}
ret = mcp23x17_writeread(priv, &addr, 1, &buf[1], 2);
if (ret < 0)
{
nxmutex_unlock(&priv->lock);
return NULL;
}
buf[0] = addr;
buf[1] |= (uint8_t)(pinset & 0x00ff);
buf[2] |= (uint8_t)((pinset & 0xff00) >> 8);
ret = mcp23x17_write(priv, buf, 3);
if (ret < 0)
{
nxmutex_unlock(&priv->lock);
return NULL;
}
/* Find and available in entry in the callback table */
@ -806,7 +837,7 @@ static int mcp23x17_detach(FAR struct ioexpander_dev_s *dev,
DEBUGASSERT(priv != NULL && cb != NULL);
DEBUGASSERT((uintptr_t)cb >= (uintptr_t)&priv->cb[0] &&
(uintptr_t)cb <=
(uintptr_t)&priv->cb[CONFIG_TCA64XX_INT_NCALLBACKS - 1]);
(uintptr_t)&priv->cb[CONFIG_MCP23X17_INT_NCALLBACKS - 1]);
UNUSED(priv);
cb->pinset = 0;
@ -827,26 +858,20 @@ static int mcp23x17_detach(FAR struct ioexpander_dev_s *dev,
static void mcp23x17_irqworker(void *arg)
{
FAR struct mcp23x17_dev_s *priv = (FAR struct mcp23x17_dev_s *)arg;
uint8_t addr = MCP23X17_GPIOA;
uint8_t addr = MCP23X17_INTFA;
uint8_t buf[2];
ioe_pinset_t pinset;
int ret;
int i;
/* Read inputs */
/* Read interrupt flags */
ret = mcp23x17_writeread(priv, &addr, 1, buf, 2);
if (ret == OK)
{
#ifdef CONFIG_MCP23X17_SHADOW_MODE
/* Don't forget to update the shadow registers at this point */
priv->sreg[addr] = buf[0];
priv->sreg[addr + 1] = buf[1];
#endif
/* Create a 16-bit pinset */
pinset = ((unsigned int)buf[0] << 8) | buf[1];
pinset = ((unsigned int)buf[1] << 8) | buf[0];
/* Perform pin interrupt callbacks */
@ -870,6 +895,19 @@ static void mcp23x17_irqworker(void *arg)
}
}
}
/* Read GPIOs to clear interrupt condition */
addr = MCP23X17_INTCAPA;
mcp23x17_writeread(priv, &addr, 1, buf, 2);
#ifdef CONFIG_MCP23X17_SHADOW_MODE
/* Don't forget to update the shadow registers at this point */
priv->sreg[addr] = buf[0];
priv->sreg[addr + 1] = buf[1];
#endif
}
/* Re-enable interrupts */
@ -934,6 +972,9 @@ FAR struct ioexpander_dev_s *mcp23x17_initialize(
FAR struct mcp23x17_config_s *config)
{
FAR struct mcp23x17_dev_s *priv;
#ifdef CONFIG_MCP23X17_INT_MIRROR
uint8_t buf[3];
#endif
DEBUGASSERT(i2cdev != NULL && config != NULL);
@ -967,6 +1008,14 @@ FAR struct ioexpander_dev_s *mcp23x17_initialize(
priv->config = config;
#ifdef CONFIG_MCP23X17_INT_ENABLE
#ifdef CONFIG_MCP23X17_INT_MIRROR
buf[0] = MCP23X17_IOCON;
buf[1] = 0x40;
buf[2] = 0x40;
mcp23x17_write(priv, buf, 3);
#endif
priv->config->attach(priv->config, mcp23x17_interrupt, priv);
priv->config->enable(priv->config, TRUE);
#endif

View File

@ -152,6 +152,10 @@ struct mcp23x17_dev_s
struct ioexpander_dev_s dev; /* Nested structure to allow casting
* as public gpio expander.
*/
#ifdef CONFIG_MCP23X17_MULTIPLE
FAR struct mcp23x17_dev_s *flink; /* Supports a singly linked list of drivers */
#endif
FAR struct mcp23x17_config_s *config; /* Board configuration data */
FAR struct i2c_master_s *i2c; /* Saved I2C driver instance */
mutex_t lock; /* Mutual exclusion */