mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 05:16:47 +08:00
Bug fixes and improved interrupt support for mcp23x17 driver
This commit is contained in:
@@ -78,6 +78,13 @@ config MCP23X17_INT_ENABLE
|
|||||||
---help---
|
---help---
|
||||||
Enable driver interrupt functionality
|
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
|
config MCP23X17_INT_NCALLBACKS
|
||||||
int "Max number of interrupt callbacks"
|
int "Max number of interrupt callbacks"
|
||||||
default 4
|
default 4
|
||||||
|
|||||||
@@ -312,6 +312,7 @@ static int mcp23x17_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (direction != IOEXPANDER_DIRECTION_IN &&
|
if (direction != IOEXPANDER_DIRECTION_IN &&
|
||||||
|
direction != IOEXPANDER_DIRECTION_IN_PULLUP &&
|
||||||
direction != IOEXPANDER_DIRECTION_OUT)
|
direction != IOEXPANDER_DIRECTION_OUT)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
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,
|
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);
|
nxmutex_unlock(&priv->lock);
|
||||||
return ret;
|
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 struct mcp23x17_dev_s *priv = (FAR struct mcp23x17_dev_s *)dev;
|
||||||
FAR void *handle = NULL;
|
FAR void *handle = NULL;
|
||||||
|
uint8_t addr = MCP23X17_GPINTENA;
|
||||||
|
uint8_t buf[3];
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -754,7 +767,25 @@ static FAR void *mcp23x17_attach(FAR struct ioexpander_dev_s *dev,
|
|||||||
ret = nxmutex_lock(&priv->lock);
|
ret = nxmutex_lock(&priv->lock);
|
||||||
if (ret < 0)
|
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 */
|
/* 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(priv != NULL && cb != NULL);
|
||||||
DEBUGASSERT((uintptr_t)cb >= (uintptr_t)&priv->cb[0] &&
|
DEBUGASSERT((uintptr_t)cb >= (uintptr_t)&priv->cb[0] &&
|
||||||
(uintptr_t)cb <=
|
(uintptr_t)cb <=
|
||||||
(uintptr_t)&priv->cb[CONFIG_TCA64XX_INT_NCALLBACKS - 1]);
|
(uintptr_t)&priv->cb[CONFIG_MCP23X17_INT_NCALLBACKS - 1]);
|
||||||
UNUSED(priv);
|
UNUSED(priv);
|
||||||
|
|
||||||
cb->pinset = 0;
|
cb->pinset = 0;
|
||||||
@@ -827,26 +858,20 @@ static int mcp23x17_detach(FAR struct ioexpander_dev_s *dev,
|
|||||||
static void mcp23x17_irqworker(void *arg)
|
static void mcp23x17_irqworker(void *arg)
|
||||||
{
|
{
|
||||||
FAR struct mcp23x17_dev_s *priv = (FAR struct mcp23x17_dev_s *)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];
|
uint8_t buf[2];
|
||||||
ioe_pinset_t pinset;
|
ioe_pinset_t pinset;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Read inputs */
|
/* Read interrupt flags */
|
||||||
|
|
||||||
ret = mcp23x17_writeread(priv, &addr, 1, buf, 2);
|
ret = mcp23x17_writeread(priv, &addr, 1, buf, 2);
|
||||||
if (ret == OK)
|
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 */
|
/* 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 */
|
/* 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 */
|
/* Re-enable interrupts */
|
||||||
@@ -934,6 +972,9 @@ FAR struct ioexpander_dev_s *mcp23x17_initialize(
|
|||||||
FAR struct mcp23x17_config_s *config)
|
FAR struct mcp23x17_config_s *config)
|
||||||
{
|
{
|
||||||
FAR struct mcp23x17_dev_s *priv;
|
FAR struct mcp23x17_dev_s *priv;
|
||||||
|
#ifdef CONFIG_MCP23X17_INT_MIRROR
|
||||||
|
uint8_t buf[3];
|
||||||
|
#endif
|
||||||
|
|
||||||
DEBUGASSERT(i2cdev != NULL && config != NULL);
|
DEBUGASSERT(i2cdev != NULL && config != NULL);
|
||||||
|
|
||||||
@@ -967,6 +1008,14 @@ FAR struct ioexpander_dev_s *mcp23x17_initialize(
|
|||||||
priv->config = config;
|
priv->config = config;
|
||||||
|
|
||||||
#ifdef CONFIG_MCP23X17_INT_ENABLE
|
#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->attach(priv->config, mcp23x17_interrupt, priv);
|
||||||
priv->config->enable(priv->config, TRUE);
|
priv->config->enable(priv->config, TRUE);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ struct mcp23x17_dev_s
|
|||||||
struct ioexpander_dev_s dev; /* Nested structure to allow casting
|
struct ioexpander_dev_s dev; /* Nested structure to allow casting
|
||||||
* as public gpio expander.
|
* 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 mcp23x17_config_s *config; /* Board configuration data */
|
||||||
FAR struct i2c_master_s *i2c; /* Saved I2C driver instance */
|
FAR struct i2c_master_s *i2c; /* Saved I2C driver instance */
|
||||||
mutex_t lock; /* Mutual exclusion */
|
mutex_t lock; /* Mutual exclusion */
|
||||||
|
|||||||
Reference in New Issue
Block a user