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---
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
config IOEXPANDER_TCA64XX
@ -52,7 +72,7 @@ config IOEXPANDER_TCA64XX
select I2C
depends on EXPERIMENTAL
---help---
Enable support for the NXP TCA64XX IO Expander
Enable support for the TCA64XX IO Expander
if IOEXPANDER_TCA64XX
@ -91,6 +111,51 @@ config TCA64XX_INT_POLLDELAY
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
bool
default n
@ -110,26 +175,6 @@ config IOEXPANDER_MULTIPIN
This settings enable the definition of routines for
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
config DEV_GPIO

View File

@ -48,6 +48,10 @@ ifeq ($(CONFIG_IOEXPANDER_TCA64XX),y)
CSRCS += tca64xx.c
endif
ifeq ($(CONFIG_IOEXPANDER_PCF8574),y)
CSRCS += pcf8574.c
endif
endif # CONFIG_IOEXPANDER
# 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;
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE
#ifdef CONFIG_PCA9555_SHADOW_MODE
/* Get the shadowed register value */
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);
}
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE
#ifdef CONFIG_PCA9555_SHADOW_MODE
/* Save the new register value in the shadow register */
pca->sreg[addr] = buf[1];
#endif
ret = pca9555_write(pca, buf, 2);
#ifdef CONFIG_IOEXPANDER_RETRY
#ifdef CONFIG_PCA9555_RETRY
if (ret != OK)
{
/* Try again (only once) */
@ -308,7 +308,7 @@ static int pca9555_getbit(FAR struct pca9555_dev_s *pca, uint8_t addr,
return ret;
}
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE
#ifdef CONFIG_PCA9555_SHADOW_MODE
/* Save the new register value in the shadow register */
pca->sreg[addr] = buf;
@ -508,7 +508,7 @@ static int pca9555_getmultibits(FAR struct pca9555_dev_s *pca, uint8_t addr,
return ret;
}
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE
#ifdef CONFIG_PCA9555_SHADOW_MODE
/* Save the new register value in the shadow register */
pca->sreg[addr] = buf[0];
@ -575,7 +575,7 @@ static int pca9555_multiwritepin(FAR struct ioexpander_dev_s *dev,
* this would not save much.
*/
#ifndef CONFIG_IOEXPANDER_SHADOW_MODE
#ifndef CONFIG_PCA9555_SHADOW_MODE
ret = pca9555_writeread(pca, &addr, 1, &buf[1], 2);
if (ret < 0)
{
@ -619,7 +619,7 @@ static int pca9555_multiwritepin(FAR struct ioexpander_dev_s *dev,
/* Now write back the new pins states */
buf[0] = addr;
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE
#ifdef CONFIG_PCA9555_SHADOW_MODE
/* Save the new register values in the shadow register */
pca->sreg[addr] = buf[1];
pca->sreg[addr+1] = buf[2];
@ -809,7 +809,7 @@ static void pca9555_irqworker(void *arg)
ret = pca9555_writeread(pca, &addr, 1, buf, 2);
if (ret == OK)
{
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE
#ifdef CONFIG_PCA9555_SHADOW_MODE
/* Don't forget to update the shadow registers at this point */
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
* expander. */
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE
#ifdef CONFIG_PCA9555_SHADOW_MODE
uint8_t sreg[8]; /* Shadowed registers of the PCA9555 */
#endif
#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 &&
pin < CONFIG_IOEXPANDER_NPINS &&
(direction == IOEXPANDER_DIRECTION_IN ||
direction == IOEXPANDER_DIRECTION_IN));
direction == IOEXPANDER_DIRECTION_OUT));
gpioinfo("I2C addr=%02x pin=%u direction=%s\n",
priv->config->address, pin,
@ -1029,8 +1029,9 @@ static void tca64_int_update(void *handle, ioe_pinset_t input,
ioe_pinset_t mask)
{
struct tca64_dev_s *priv = handle;
uint32_t diff, ngios = tca64_ngpios(priv);
ioe_pinset_t diff;
irqstate_t flags;
int ngios = tca64_ngpios(priv);
int pin;
flags = enter_critical_section();