Merged in slorquet/nuttx/pca9555 (pull request #32)

Pca9555 interrupt support.
This commit is contained in:
Gregory Nutt 2015-11-17 07:45:33 -06:00
commit f5722bc6dd
5 changed files with 107 additions and 65 deletions

View File

@ -12,13 +12,6 @@ menuconfig IOEXPANDER
if IOEXPANDER
config IOEXPANDER_MULTIPIN
bool "Support multi-pin access routines"
default n
---help---
This settings enable the definition of routines for
optimized simultaneous access to multiple pins.
config IOEXPANDER_PCA9555
bool "PCA9555 I2C IO expander"
default n
@ -34,13 +27,28 @@ config PCA9555_MULTIPLE
---help---
Can be defined to support multiple PCA9555 devices on board.
config PCA9555_INT_DISABLE
bool "Disable PCA9555 Interrupt Support"
default y
config PCA9555_INT_ENABLE
bool "Enable PCA9555 Interrupt Support"
default n
select IOEXPANDER_INT_ENABLE
---help---
Disable driver interrupt functionality
Enable driver interrupt functionality
endif # IOEXPANDER_PCA9555
config IOEXPANDER_INT_ENABLE
bool
default y if PCA9555_INT_ENABLE
---help---
This is the global INT supported flag for io expanders
config IOEXPANDER_MULTIPIN
bool "Support multi-pin access routines"
default n
---help---
This settings enable the definition of routines for
optimized simultaneous access to multiple pins.
endif # IOEXPANDER
config USERLED

View File

@ -47,6 +47,7 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/i2c.h>
#include <nuttx/kmalloc.h>
#include <nuttx/discrete/ioexpander.h>
@ -435,22 +436,7 @@ static int pca9555_multireadbuf(FAR struct ioexpander_dev_s *dev,
#endif
#ifndef CONFIG_PCA9555_INT_DISABLE
/****************************************************************************
* Name: pca9555_gpioworker
*
* Description:
* See include/nuttx/discrete/ioexpander.h
*
****************************************************************************/
static int pca9555_attach(FAR struct ioexpander_dev_s *dev, uint8_t pin,
ioexpander_handler_t handler)
{
FAR struct pca9555_dev_s *pca = (FAR struct pca9555_dev_s *)dev;
return 0;
}
#ifdef CONFIG_PCA9555_INT_ENABLE
/****************************************************************************
* Name: pca9555_irqworker
@ -461,32 +447,77 @@ static int pca9555_attach(FAR struct ioexpander_dev_s *dev, uint8_t pin,
*
****************************************************************************/
static void pca9555_irqworker(FAR struct pca9555_dev_s *priv)
static void pca9555_irqworker(void *arg)
{
uint8_t regval;
uint8_t pinmask;
int pin;
uint8_t addr = PCA9555_REG_INPUT;
uint8_t buf[2];
int ret, bits;
FAR struct pca9555_dev_s *pca = (FAR struct pca9555_dev_s*)arg;
/* Get the set of pending GPIO interrupts */
/* Look at each pin */
for (pin = 0; pin < PCA9555_GPIO_NPINS; pin++)
/* read inputs */
ret = I2C_WRITEREAD(pca->i2c, &addr, 1, buf, 2);
if( ret != OK)
{
/* Check if we have a handler for this interrupt (there should
* be one)
*/
/* Interrupt is pending... dispatch the interrupt to the
* callback
*/
/* Clear the pending GPIO interrupt by writing a '1' to the
* pin position in the status register.
*/
return;
}
bits = (buf[0]<<8) | buf[1];
/* if signal PID is registered, enqueue signal. */
if(pca->dev.sigpid)
{
#ifdef CONFIG_CAN_PASS_STRUCTS
union sigval value;
value.sival_int = bits;
ret = sigqueue(pca->dev.sigpid, pca->dev.sigval, value);
#else
ret = sigqueue(pca->dev.sigpid, pca->dev.sigval, (FAR void*)bits);
#endif
dbg("pca signal %04X (sig %d to pid %d)\n",bits, pca->dev.sigval, pca->dev.sigpid);
}
else
{
dbg("no handler registered\n");
}
/* re-enable */
pca->config->enable(pca->config, TRUE);
}
/****************************************************************************
* Name: pca9555_interrupt
*
* Description:
* Handle GPIO interrupt events (this function executes in the
* context of the interrupt).
*
****************************************************************************/
static int pca9555_interrupt(int irq, FAR void *context)
{
/* To support multiple devices,
* retrieve the priv structure using the irq number */
register FAR struct pca9555_dev_s *pca = &g_pca9555;
/* In complex environments, we cannot do I2C transfers from the interrupt
* handler because semaphores are probably used to lock the I2C bus. In
* this case, we will defer processing to the worker thread. This is also
* much kinder in the use of system resources and is, therefore, probably
* a good thing to do in any event.
*/
DEBUGASSERT(work_available(&pca->dev.work));
/* Notice that further GPIO interrupts are disabled until the work is
* actually performed. This is to prevent overrun of the worker thread.
* Interrupts are re-enabled in pca9555_irqworker() when the work is completed.
*/
pca->config->enable(pca->config, FALSE);
return work_queue(HPWORK, &pca->dev.work, pca9555_irqworker, (FAR void *)pca, 0);
}
#endif
/****************************************************************************
@ -536,6 +567,7 @@ FAR struct ioexpander_dev_s *pca9555_initialize(FAR struct i2c_dev_s *i2cdev,
pcadev->i2c = i2cdev;
pcadev->dev.ops = &g_pca9555_ops;
pcadev->config = config;
/* Set the I2C address and frequency. REVISIT: This logic would be
* insufficient if we share the I2C bus with any other devices that also
@ -545,6 +577,10 @@ FAR struct ioexpander_dev_s *pca9555_initialize(FAR struct i2c_dev_s *i2cdev,
I2C_SETADDRESS(i2cdev, config->address, 7);
I2C_SETFREQUENCY(i2cdev, config->frequency);
#ifdef CONFIG_PCA9555_INT_ENABLE
pcadev->config->attach(pcadev->config, pca9555_interrupt);
pcadev->config->enable(pcadev->config, TRUE);
#endif
return &pcadev->dev;
}

View File

@ -48,7 +48,6 @@
#include <nuttx/wdog.h>
#include <nuttx/clock.h>
#include <nuttx/wqueue.h>
#include <nuttx/discrete/ioexpander.h>
#include <nuttx/discrete/pca9555.h>
@ -95,12 +94,6 @@
#error "CONFIG_I2C is required by PCA9555"
#endif
#ifndef CONFIG_PCA9555_INT_DISABLE
#ifndef CONFIG_SCHED_WORKQUEUE
#error "Work queue support required. CONFIG_SCHED_WORKQUEUE must be selected."
#endif
#endif
#define PCA9555_MAXDEVS 8
/* I2C frequency */
@ -123,19 +116,15 @@
struct pca9555_dev_s
{
struct ioexpander_dev_s dev; /* Nested structure to allow casting as public gpio expander. */
struct ioexpander_dev_s dev; /* Nested structure to allow casting as public gpio expander. */
#ifdef CONFIG_PCA9555_MULTIPLE
FAR struct pca9555_dev_s *flink; /* Supports a singly linked list of drivers */
FAR struct pca9555_dev_s * flink; /* Supports a singly linked list of drivers */
#endif
FAR struct pca9555_config_s *config; /* Board configuration data */
FAR struct i2c_dev_s *i2c; /* Saved I2C driver instance */
FAR struct i2c_dev_s * i2c; /* Saved I2C driver instance */
#ifndef CONFIG_PCA9555_INT_DISABLE
struct work_s work; /* Supports the interrupt handling "bottom half" */
pca9555_handler_t handlers[PCA9555_GPIO_NPINS]; /* GPIO "interrupt handlers" */
#endif
};
#endif /* CONFIG_IOEXPANDER && CONFIG_IOEXPANDER_PCA9555 */

View File

@ -41,9 +41,16 @@
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/wqueue.h>
#if defined(CONFIG_IOEXPANDER)
#ifndef CONFIG_PCA9555_INT_DISABLE
#ifndef CONFIG_SCHED_WORKQUEUE
#error "Work queue support required. CONFIG_SCHED_WORKQUEUE must be selected."
#endif
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -249,6 +256,11 @@ struct ioexpander_ops_s
struct ioexpander_dev_s
{
FAR const struct ioexpander_ops_s *ops;
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
struct work_s work; /* Supports the interrupt handling "bottom half" */
int sigpid; /* PID to be signaled in case of interrupt */
int sigval; /* signal to be sent in case of interrupt */
#endif
};
#endif //CONFIG_IOEXPANDER

View File

@ -63,7 +63,6 @@ struct pca9555_config_s
*/
#ifndef CONFIG_PCA9555_INT_DISABLE
/* IRQ support TODO */
#ifdef CONFIG_PCA9555_MULTIPLE
int irq; /* IRQ number received by interrupt handler. */
@ -75,12 +74,10 @@ struct pca9555_config_s
*
* attach - Attach the PCA9555 interrupt handler to the GPIO interrupt
* enable - Enable or disable the GPIO interrupt
* clear - Acknowledge/clear any pending GPIO interrupt
*/
CODE int (*attach)(FAR struct pca9555_config_s *state, xcpt_t isr);
CODE void (*enable)(FAR struct pca9555_config_s *state, bool enable);
CODE void (*clear)(FAR struct pca9555_config_s *state);
#endif
};