Add PCF8574 I/O Expander driver. Some cleanup also of other expander drivers.

This commit is contained in:
Gregory Nutt 2016-08-01 11:10:11 -06:00
parent e0f3df5d97
commit d47aa75669
5 changed files with 83 additions and 33 deletions

View File

@ -44,6 +44,26 @@ config PCA9555_INT_NCALLBACKS
---help--- ---help---
This is the maximum number of interrupt callbacks supported This is the maximum number of interrupt callbacks supported
config PCA9555_SHADOW_MODE
bool "Use Shadow Mode instead of Read-Modify-Write Operations"
default n
---help---
This setting enables a mode where the output and pin
configuration registers are held in RAM.
With this for example we do not need to read back the
output-register every time we want to change one pin.
We do instead change the bit in the internal register
and then just write this register to the IO-Expander.
This reduces bus traffic and eliminates the problem of
EMC-caused toggling of output pins.
config PCA9555_RETRY
bool "Retry to send commands and data at I2C communication errors"
default n
---help---
Retry to send commands and data if a I2C-communication
error occurs (eg. caused by EMC).
endif # IOEXPANDER_PCA9555 endif # IOEXPANDER_PCA9555
config IOEXPANDER_TCA64XX config IOEXPANDER_TCA64XX
@ -52,7 +72,7 @@ config IOEXPANDER_TCA64XX
select I2C select I2C
depends on EXPERIMENTAL depends on EXPERIMENTAL
---help--- ---help---
Enable support for the NXP TCA64XX IO Expander Enable support for the TCA64XX IO Expander
if IOEXPANDER_TCA64XX if IOEXPANDER_TCA64XX
@ -91,6 +111,51 @@ config TCA64XX_INT_POLLDELAY
endif # IOEXPANDER_TCA64XX endif # IOEXPANDER_TCA64XX
config IOEXPANDER_PCF8574
bool "PCF8574 I2C IO expander"
default n
select I2C
depends on EXPERIMENTAL
---help---
Enable support for the PCF8574 IO Expander
if IOEXPANDER_PCF8574
config PCF8574_MULTIPLE
bool "Multiple PCF8574 Devices"
default n
---help---
Can be defined to support multiple PCF8574 devices on board.
config PCF8574_INT_ENABLE
bool "Enable PCF8574 Interrupt Support"
default n
select IOEXPANDER_INT_ENABLE
---help---
Enable driver interrupt functionality
config PCF8574_INT_NCALLBACKS
int "Max number of interrupt callbacks"
default 4
depends on PCF8574_INT_ENABLE
---help---
This is the maximum number of interrupt callbacks supported
config PCF8574_INT_POLL
bool "Enable interrupt poll"
default n
---help---
Enable polling for missed interrupts.
config PCF8574_INT_POLLDELAY
int "Interrupt poll delay (used)"
default 500000
depends on PCF8574_INT_POLL
---help---
This microsecond delay defines the polling rate for missed interrupts.
endif # IOEXPANDER_PCF8574
config IOEXPANDER_INT_ENABLE config IOEXPANDER_INT_ENABLE
bool bool
default n default n
@ -110,26 +175,6 @@ config IOEXPANDER_MULTIPIN
This settings enable the definition of routines for This settings enable the definition of routines for
optimized simultaneous access to multiple pins. optimized simultaneous access to multiple pins.
config IOEXPANDER_SHADOW_MODE
bool "Use Shadow Mode instead of Read-Modify-Write Operations"
default n
---help---
This setting enables a mode where the output and pin
configuration registers are held in RAM.
With this for example we do not need to read back the
output-register every time we want to change one pin.
We do instead change the bit in the internal register
and then just write this register to the IO-Expander.
This reduces bus traffic and eliminates the problem of
EMC-caused toggling of output pins.
config IOEXPANDER_RETRY
bool "Retry to send commands and data at I2C communication errors"
default n
---help---
Retry to send commands and data if a I2C-communication
error occurs (eg. caused by EMC).
endif # IOEXPANDER endif # IOEXPANDER
config DEV_GPIO config DEV_GPIO

View File

@ -48,6 +48,10 @@ ifeq ($(CONFIG_IOEXPANDER_TCA64XX),y)
CSRCS += tca64xx.c CSRCS += tca64xx.c
endif endif
ifeq ($(CONFIG_IOEXPANDER_PCF8574),y)
CSRCS += pcf8574.c
endif
endif # CONFIG_IOEXPANDER endif # CONFIG_IOEXPANDER
# GPIO test device driver (independent of IOEXPANDERS) # GPIO test device driver (independent of IOEXPANDERS)

View File

@ -235,7 +235,7 @@ static int pca9555_setbit(FAR struct pca9555_dev_s *pca, uint8_t addr,
buf[0] = addr; buf[0] = addr;
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE #ifdef CONFIG_PCA9555_SHADOW_MODE
/* Get the shadowed register value */ /* Get the shadowed register value */
buf[1] = pca->sreg[addr]; buf[1] = pca->sreg[addr];
@ -259,14 +259,14 @@ static int pca9555_setbit(FAR struct pca9555_dev_s *pca, uint8_t addr,
buf[1] &= ~(1 << pin); buf[1] &= ~(1 << pin);
} }
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE #ifdef CONFIG_PCA9555_SHADOW_MODE
/* Save the new register value in the shadow register */ /* Save the new register value in the shadow register */
pca->sreg[addr] = buf[1]; pca->sreg[addr] = buf[1];
#endif #endif
ret = pca9555_write(pca, buf, 2); ret = pca9555_write(pca, buf, 2);
#ifdef CONFIG_IOEXPANDER_RETRY #ifdef CONFIG_PCA9555_RETRY
if (ret != OK) if (ret != OK)
{ {
/* Try again (only once) */ /* Try again (only once) */
@ -308,7 +308,7 @@ static int pca9555_getbit(FAR struct pca9555_dev_s *pca, uint8_t addr,
return ret; return ret;
} }
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE #ifdef CONFIG_PCA9555_SHADOW_MODE
/* Save the new register value in the shadow register */ /* Save the new register value in the shadow register */
pca->sreg[addr] = buf; pca->sreg[addr] = buf;
@ -508,7 +508,7 @@ static int pca9555_getmultibits(FAR struct pca9555_dev_s *pca, uint8_t addr,
return ret; return ret;
} }
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE #ifdef CONFIG_PCA9555_SHADOW_MODE
/* Save the new register value in the shadow register */ /* Save the new register value in the shadow register */
pca->sreg[addr] = buf[0]; pca->sreg[addr] = buf[0];
@ -575,7 +575,7 @@ static int pca9555_multiwritepin(FAR struct ioexpander_dev_s *dev,
* this would not save much. * this would not save much.
*/ */
#ifndef CONFIG_IOEXPANDER_SHADOW_MODE #ifndef CONFIG_PCA9555_SHADOW_MODE
ret = pca9555_writeread(pca, &addr, 1, &buf[1], 2); ret = pca9555_writeread(pca, &addr, 1, &buf[1], 2);
if (ret < 0) if (ret < 0)
{ {
@ -619,7 +619,7 @@ static int pca9555_multiwritepin(FAR struct ioexpander_dev_s *dev,
/* Now write back the new pins states */ /* Now write back the new pins states */
buf[0] = addr; buf[0] = addr;
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE #ifdef CONFIG_PCA9555_SHADOW_MODE
/* Save the new register values in the shadow register */ /* Save the new register values in the shadow register */
pca->sreg[addr] = buf[1]; pca->sreg[addr] = buf[1];
pca->sreg[addr+1] = buf[2]; pca->sreg[addr+1] = buf[2];
@ -809,7 +809,7 @@ static void pca9555_irqworker(void *arg)
ret = pca9555_writeread(pca, &addr, 1, buf, 2); ret = pca9555_writeread(pca, &addr, 1, buf, 2);
if (ret == OK) if (ret == OK)
{ {
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE #ifdef CONFIG_PCA9555_SHADOW_MODE
/* Don't forget to update the shadow registers at this point */ /* Don't forget to update the shadow registers at this point */
pca->sreg[addr] = buf[0]; pca->sreg[addr] = buf[0];

View File

@ -144,7 +144,7 @@ struct pca9555_dev_s
{ {
struct ioexpander_dev_s dev; /* Nested structure to allow casting as public gpio struct ioexpander_dev_s dev; /* Nested structure to allow casting as public gpio
* expander. */ * expander. */
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE #ifdef CONFIG_PCA9555_SHADOW_MODE
uint8_t sreg[8]; /* Shadowed registers of the PCA9555 */ uint8_t sreg[8]; /* Shadowed registers of the PCA9555 */
#endif #endif
#ifdef CONFIG_PCA9555_MULTIPLE #ifdef CONFIG_PCA9555_MULTIPLE

View File

@ -427,7 +427,7 @@ static int tca64_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin,
DEBUGASSERT(priv != NULL && priv->config != NULL && DEBUGASSERT(priv != NULL && priv->config != NULL &&
pin < CONFIG_IOEXPANDER_NPINS && pin < CONFIG_IOEXPANDER_NPINS &&
(direction == IOEXPANDER_DIRECTION_IN || (direction == IOEXPANDER_DIRECTION_IN ||
direction == IOEXPANDER_DIRECTION_IN)); direction == IOEXPANDER_DIRECTION_OUT));
gpioinfo("I2C addr=%02x pin=%u direction=%s\n", gpioinfo("I2C addr=%02x pin=%u direction=%s\n",
priv->config->address, pin, priv->config->address, pin,
@ -702,7 +702,7 @@ errout_with_lock:
* *
* Description: * Description:
* Read the actual PIN level. This can be different from the last value written * Read the actual PIN level. This can be different from the last value written
* to this pin. Required. * to this pin. Required.
* *
* Input Parameters: * Input Parameters:
* dev - Device-specific state data * dev - Device-specific state data
@ -1029,8 +1029,9 @@ static void tca64_int_update(void *handle, ioe_pinset_t input,
ioe_pinset_t mask) ioe_pinset_t mask)
{ {
struct tca64_dev_s *priv = handle; struct tca64_dev_s *priv = handle;
uint32_t diff, ngios = tca64_ngpios(priv); ioe_pinset_t diff;
irqstate_t flags; irqstate_t flags;
int ngios = tca64_ngpios(priv);
int pin; int pin;
flags = enter_critical_section(); flags = enter_critical_section();