From d47aa75669b6960fe286bcd0b4a2a2d3afc40d8d Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 1 Aug 2016 11:10:11 -0600 Subject: [PATCH] Add PCF8574 I/O Expander driver. Some cleanup also of other expander drivers. --- drivers/ioexpander/Kconfig | 87 +++++++++++++++++++++++++++--------- drivers/ioexpander/Make.defs | 4 ++ drivers/ioexpander/pca9555.c | 16 +++---- drivers/ioexpander/pca9555.h | 2 +- drivers/ioexpander/tca64xx.c | 7 +-- 5 files changed, 83 insertions(+), 33 deletions(-) diff --git a/drivers/ioexpander/Kconfig b/drivers/ioexpander/Kconfig index 470782d61e..5cbc6ba6bf 100644 --- a/drivers/ioexpander/Kconfig +++ b/drivers/ioexpander/Kconfig @@ -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 diff --git a/drivers/ioexpander/Make.defs b/drivers/ioexpander/Make.defs index 0a985e5df8..8c3107993e 100644 --- a/drivers/ioexpander/Make.defs +++ b/drivers/ioexpander/Make.defs @@ -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) diff --git a/drivers/ioexpander/pca9555.c b/drivers/ioexpander/pca9555.c index c473dfed3e..3da9849dc3 100644 --- a/drivers/ioexpander/pca9555.c +++ b/drivers/ioexpander/pca9555.c @@ -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]; diff --git a/drivers/ioexpander/pca9555.h b/drivers/ioexpander/pca9555.h index 1782222592..815d92de23 100644 --- a/drivers/ioexpander/pca9555.h +++ b/drivers/ioexpander/pca9555.h @@ -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 diff --git a/drivers/ioexpander/tca64xx.c b/drivers/ioexpander/tca64xx.c index 1cde899b45..3afcc8b686 100644 --- a/drivers/ioexpander/tca64xx.c +++ b/drivers/ioexpander/tca64xx.c @@ -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, @@ -702,7 +702,7 @@ errout_with_lock: * * Description: * Read the actual PIN level. This can be different from the last value written - * to this pin. Required. + * to this pin. Required. * * Input Parameters: * dev - Device-specific state data @@ -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();