Merged in slorquet/nuttx/pca9555 (pull request #32)
Pca9555 interrupt support.
This commit is contained in:
commit
f5722bc6dd
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user