Bug fixes and improved interrupt support for mcp23x17 driver
This commit is contained in:
parent
468f2e3222
commit
97b4900c59
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user