I/O Expander: Remove hard-coded PCA9555 fields from ioexpander.h definitons. Add support for an attach() method that may be used when any subset of pin interrupts occur.
PCA9555 Driver: Replace the signalling logic with a simple callback using the new definitons of ioexpander.h. This repartitioning of functionality is necessary because (1) the I/O expander driver is the lower-lower part of any driver that uses GPIOs (include the GPIO driver itself) and should not be interacting directly with the much higher level application layer. And (2) in order to be compatible with the GPIO driver (and any arbitrary upper half driver), the PCA9555 should not directly signal, but should call back into the upper half. The upper half driver that interacts directly with the application is the appropriate place to be generating signal.
This commit is contained in:
parent
4daa553328
commit
5f9ee79298
14
ChangeLog
14
ChangeLog
@ -12407,3 +12407,17 @@
|
||||
20160-07-28).
|
||||
* arch/arm/src/stm32: Add timekeeping support for the STM32 tickless
|
||||
mode. From Max Neklyudov (Merged on 20160-07-28).
|
||||
* I/O Expander: Remove hard-coded PCA9555 fields from ioexpander.h
|
||||
definitons. Add support for an attach() method that may be used when
|
||||
any subset of pin interrupts occur (2016-07-31).
|
||||
* PCA9555 Driver: Replace the signalling logic with a simple callback
|
||||
using the new definitons of ioexpander.h. This repartitioning of
|
||||
functionality is necessary because (1) the I/O expander driver is the
|
||||
lower-lower part of any driver that uses GPIOs (include the GPIO
|
||||
driver itself) and should not be interacting directly with the much
|
||||
higher level application layer. And (2) in order to be compatible
|
||||
with the GPIO driver (and any arbitrary upper half driver), the
|
||||
PCA9555 should not directly signal, but should call back into the
|
||||
upper half. The upper half driver that interacts directly with the
|
||||
application is the appropriate place to be generating signal
|
||||
(2016-07-31).
|
||||
|
2
TODO
2
TODO
@ -1340,6 +1340,8 @@ o Libraries (libc/)
|
||||
|
||||
UPDATE: 2015-09-01: A fix for the noted problems with asin()
|
||||
has been applied.
|
||||
2016-07-30: Numerous fixes and performance improvements from
|
||||
David Alessio.
|
||||
|
||||
Status: Open
|
||||
Priority: Low for casual users but clearly high if you need care about
|
||||
|
@ -37,6 +37,13 @@ config PCA9555_INT_ENABLE
|
||||
---help---
|
||||
Enable driver interrupt functionality
|
||||
|
||||
config PCA9555_INT_NCALLBACKS
|
||||
int "Max number of interrupt callbacks"
|
||||
default 4
|
||||
depends on IOEXPANDER_INT_ENABLE
|
||||
---help---
|
||||
This is the maximum number of interrupt callbacks supported
|
||||
|
||||
endif # IOEXPANDER_PCA9555
|
||||
|
||||
config IOEXPANDER_INT_ENABLE
|
||||
@ -45,6 +52,12 @@ config IOEXPANDER_INT_ENABLE
|
||||
---help---
|
||||
This is the global INT supported flag for io expanders
|
||||
|
||||
config IOEXPANDER_NPINS
|
||||
int "Number of pins"
|
||||
default 16
|
||||
---help---
|
||||
Maximum number of pins supported per driver.
|
||||
|
||||
config IOEXPANDER_MULTIPIN
|
||||
bool "Support multi-pin access routines"
|
||||
default n
|
||||
|
@ -303,7 +303,7 @@ int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor)
|
||||
DEBUGASSERT(dev->gp_ops->go_read != NULL &&
|
||||
dev->gp_ops->go_write != NULL);
|
||||
fmt = "/dev/gpout%u";
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
@ -321,12 +321,12 @@ int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fmt = "/dev/gpint%u";
|
||||
fmt = "/dev/gpint%u";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(devname, 16, fmt, (unsigned int)minor);
|
||||
|
@ -92,6 +92,10 @@ static int pca9555_multireadpin(FAR struct ioexpander_dev_s *dev,
|
||||
static int pca9555_multireadbuf(FAR struct ioexpander_dev_s *dev,
|
||||
FAR uint8_t *pins, FAR bool *values, int count);
|
||||
#endif
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
static int pca9555_attach(FAR struct ioexpander_dev_s *dev,
|
||||
ioe_pinset_t pinset, ioe_callback_t callback);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
@ -110,17 +114,22 @@ static struct pca9555_dev_s g_pca9555;
|
||||
static struct pca9555_dev_s *g_pca9555list;
|
||||
#endif
|
||||
|
||||
/* I/O expander vtable */
|
||||
|
||||
static const struct ioexpander_ops_s g_pca9555_ops =
|
||||
{
|
||||
pca9555_direction,
|
||||
pca9555_option,
|
||||
pca9555_writepin,
|
||||
pca9555_readpin,
|
||||
pca9555_readbuf,
|
||||
pca9555_readbuf
|
||||
#ifdef CONFIG_IOEXPANDER_MULTIPIN
|
||||
pca9555_multiwritepin,
|
||||
pca9555_multireadpin,
|
||||
pca9555_multireadbuf,
|
||||
, pca9555_multiwritepin
|
||||
, pca9555_multireadpin
|
||||
, pca9555_multireadbuf
|
||||
#endif
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
, pca9555_attach
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -613,6 +622,57 @@ static int pca9555_multireadbuf(FAR struct ioexpander_dev_s *dev,
|
||||
|
||||
#ifdef CONFIG_PCA9555_INT_ENABLE
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pca9555_attach
|
||||
*
|
||||
* Description:
|
||||
* Attach a pin interrupt callback function.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* pinset - The set of pin events that will generate the callback
|
||||
* callback - The pointer to callback function. NULL will detach the
|
||||
* callback.
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success, else a negative error code
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pca9555_attach(FAR struct ioexpander_dev_s *dev,
|
||||
ioe_pinset_t pinset, ioe_callback_t callback)
|
||||
{
|
||||
FAR struct pca9555_dev_s *pca = (FAR struct pca9555_dev_s *)dev;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Get exclusive access to the PCA555 */
|
||||
|
||||
pca9555_lock(pca);
|
||||
|
||||
/* Find and available in entry in the callback table */
|
||||
|
||||
ret = -ENOSPC;
|
||||
for (i = 0; i < CONFIG_PCA9555_INT_NCALLBACKS; i++)
|
||||
{
|
||||
/* Is this entry available (i.e., no callback attached) */
|
||||
|
||||
if (pca->cb[i].cbfunc == NULL)
|
||||
{
|
||||
/* Yes.. use this entry */
|
||||
|
||||
pca->cb[i].pinset = pinset;
|
||||
pca->cb[i].cbfunc = callback;
|
||||
ret = OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add this callback to the table */
|
||||
|
||||
pca9555_unlock(pca);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pca9555_irqworker
|
||||
*
|
||||
@ -627,8 +687,9 @@ static void pca9555_irqworker(void *arg)
|
||||
FAR struct pca9555_dev_s *pca = (FAR struct pca9555_dev_s *)arg;
|
||||
uint8_t addr = PCA9555_REG_INPUT;
|
||||
uint8_t buf[2];
|
||||
unsigned int bits;
|
||||
ioe_pinset_t pinset;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Read inputs */
|
||||
|
||||
@ -638,22 +699,33 @@ static void pca9555_irqworker(void *arg)
|
||||
#ifdef CONFIG_IOEXPANDER_SHADOW_MODE
|
||||
/* Don't forget to update the shadow registers at this point */
|
||||
|
||||
pca->sreg[addr] = buf;
|
||||
pca->sreg[addr] = buf[0];
|
||||
pca->sreg[addr+1] = buf[1];
|
||||
#endif
|
||||
bits = ((unsigned int)buf[0] << 8) | buf[1];
|
||||
/* Create a 16-bit pinset */
|
||||
|
||||
/* If signal PID is registered, enqueue signal. */
|
||||
pinset = ((unsigned int)buf[0] << 8) | buf[1];
|
||||
|
||||
if (pca->dev.sigpid)
|
||||
/* Perform pin interrupt callbacks */
|
||||
|
||||
for (i = 0; i < CONFIG_PCA9555_INT_NCALLBACKS; i++)
|
||||
{
|
||||
#ifdef CONFIG_CAN_PASS_STRUCTS
|
||||
union sigval value;
|
||||
value.sival_int = (int)bits;
|
||||
ret = sigqueue(pca->dev.sigpid, pca->dev.sigval, value);
|
||||
#else
|
||||
ret = sigqueue(pca->dev.sigpid, pca->dev.sigval,
|
||||
(FAR void *)bits);
|
||||
#endif
|
||||
/* Is this entry valid (i.e., callback attached)? If so, did
|
||||
* any of the requested pin interrupts occur?
|
||||
*/
|
||||
|
||||
if (pca->cb[i].cbfunc != NULL)
|
||||
{
|
||||
/* Did any of the requested pin interrupts occur? */
|
||||
|
||||
ioe_pinset_t match = pinset & pca->cb[i].pinset;
|
||||
if (match != 0)
|
||||
{
|
||||
/* Yes.. perform the callback */
|
||||
|
||||
(void)pca->cb[i].cbfunc(&pca->dev, match);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,10 +769,10 @@ static int pca9555_interrupt(int irq, FAR void *context)
|
||||
* completed.
|
||||
*/
|
||||
|
||||
if (work_available(&pca->dev.work))
|
||||
if (work_available(&pca->work))
|
||||
{
|
||||
pca->config->enable(pca->config, FALSE);
|
||||
work_queue(HPWORK, &pca->dev.work, pca9555_irqworker,
|
||||
work_queue(HPWORK, &pca->work, pca9555_irqworker,
|
||||
(FAR void *)pca, 0);
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,8 @@
|
||||
|
||||
#include <nuttx/wdog.h>
|
||||
#include <nuttx/clock.h>
|
||||
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/ioexpander/ioexpander.h>
|
||||
#include <nuttx/ioexpander/pca9555.h>
|
||||
|
||||
@ -75,11 +77,22 @@
|
||||
* Enables support for the PCA9555 driver (Needs CONFIG_INPUT)
|
||||
* CONFIG_PCA9555_MULTIPLE
|
||||
* Can be defined to support multiple PCA9555 devices on board.
|
||||
* CONFIG_PCA9555_INT_DISABLE
|
||||
* Disable driver GPIO interrupt functionality (ignored if GPIO functionality is
|
||||
* disabled).
|
||||
* CONFIG_PCA9555_INT_NCALLBACKS
|
||||
* Maximum number of supported pin interrupt callbacks.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
# ifndef CONFIG_PCA9555_INT_NCALLBACKS
|
||||
# define CONFIG_PCA9555_INT_NCALLBACKS 4
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
# ifndef CONFIG_SCHED_WORKQUEUE
|
||||
# error Work queue support required. CONFIG_SCHED_WORKQUEUE must be selected.
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#undef CONFIG_PCA9555_REFCNT
|
||||
|
||||
/* Driver support ***************************************************************************/
|
||||
@ -113,6 +126,17 @@
|
||||
* Public Types
|
||||
********************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
/* This type represents on registered pin interrupt callback */
|
||||
|
||||
struct pca9555_callback_s
|
||||
{
|
||||
ioe_pinset_t pinset; /* Set of pin interrupts that will generate
|
||||
* the callback. */
|
||||
ioe_callback_t cbfunc; /* The saved callback function pointer */
|
||||
};
|
||||
#endif
|
||||
|
||||
/* This structure represents the state of the PCA9555 driver */
|
||||
|
||||
struct pca9555_dev_s
|
||||
@ -128,6 +152,14 @@ struct pca9555_dev_s
|
||||
FAR struct pca9555_config_s *config; /* Board configuration data */
|
||||
FAR struct i2c_master_s *i2c; /* Saved I2C driver instance */
|
||||
sem_t exclsem; /* Mutual exclusion */
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
struct work_s work; /* Supports the interrupt handling "bottom half" */
|
||||
|
||||
/* Saved callback information for each I/O expander client */
|
||||
|
||||
struct pca9555_callback_s cb[CONFIG_PCA9555_INT_NCALLBACKS];
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* CONFIG_IOEXPANDER && CONFIG_IOEXPANDER_PCA9555 */
|
||||
|
@ -41,26 +41,32 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <stdint.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
|
||||
#ifdef CONFIG_IOEXPANDER
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Configuration ************************************************************/
|
||||
|
||||
#ifndef CONFIG_IOEXPANDER_NPINS
|
||||
# define CONFIG_IOEXPANDER_NPINS 16
|
||||
#endif
|
||||
|
||||
#if CONFIG_IOEXPANDER_NPINS > 64
|
||||
# error No support for devices with more than 64 pins
|
||||
#endif
|
||||
|
||||
/* Pin definiotions *********************************************************/
|
||||
|
||||
#define IOEXPANDER_DIRECTION_IN 0
|
||||
#define IOEXPANDER_DIRECTION_OUT 1
|
||||
|
||||
/* Pin options */
|
||||
|
||||
#define IOEXPANDER_OPTION_INVERT 1 /* set the "active" level for the line */
|
||||
#define IOEXPANDER_OPTION_INVERT 1 /* Set the "active" level for the line */
|
||||
|
||||
/* Access macros ************************************************************/
|
||||
|
||||
@ -221,16 +227,59 @@
|
||||
****************************************************************************/
|
||||
|
||||
#define IOEXP_MULTIREADBUF(dev,pins,vals,count) \
|
||||
((dev)->ops->ioe_multireadbuf(dev,pin,vals,count))
|
||||
((dev)->ops->ioe_multireadbuf(dev,pins,vals,count))
|
||||
|
||||
#endif /* CONFIG_IOEXPANDER_MULTIPIN */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: IOEP_ATTACH
|
||||
*
|
||||
* Description:
|
||||
* Attach a pin interrupt callback function.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* pinset - The set of pin events that will generate the callback
|
||||
* callback - The pointer to callback function. NULL will detach the
|
||||
* callback.
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success, else a negative error code
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
#define IOEP_ATTACH(dev,pinset,callback) \
|
||||
((dev)->ops->ioe_attach(dev,pins,callback))
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
struct ioexpander_dev_s;
|
||||
/* This type represents a bitmap of pins */
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
#if CONFIG_IOEXPANDER_NPINS <= 8
|
||||
typedef uint8_t ioe_pinset_t;
|
||||
#elif CONFIG_IOEXPANDER_NPINS <= 16
|
||||
typedef uint16_t ioe_pinset_t;
|
||||
#elif CONFIG_IOEXPANDER_NPINS <= 32
|
||||
typedef uint32_t ioe_pinset_t;
|
||||
#else /* if CONFIG_IOEXPANDER_NPINS <= 64 */
|
||||
typedef uint64_t ioe_pinset_t;
|
||||
#endif
|
||||
|
||||
/* This type represents a pin interrupt callback function */
|
||||
|
||||
struct ioexpander_dev_s;
|
||||
typedef int (*ioe_callback_t)(FAR struct ioexpander_dev_s *dev,
|
||||
ioe_pinset_t pinset);
|
||||
#endif /* CONFIG_IOEXPANDER_INT_ENABLE */
|
||||
|
||||
/* I/O expander interface methods */
|
||||
|
||||
struct ioexpander_dev_s;
|
||||
struct ioexpander_ops_s
|
||||
{
|
||||
CODE int (*ioe_direction)(FAR struct ioexpander_dev_s *dev, uint8_t pin,
|
||||
@ -251,16 +300,21 @@ struct ioexpander_ops_s
|
||||
CODE int (*ioe_multireadbuf)(FAR struct ioexpander_dev_s *dev,
|
||||
uint8_t *pins, bool *values, int count);
|
||||
#endif
|
||||
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
|
||||
CODE int (*ioe_attach)(FAR struct ioexpander_dev_s *dev,
|
||||
ioe_pinset_t pinset, ioe_callback_t callback);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ioexpander_dev_s
|
||||
{
|
||||
/* "Lower half" operations provided by the I/O expander lower half */
|
||||
|
||||
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
|
||||
|
||||
/* Internal storage used by the I/O expander may (internal to the I/O
|
||||
* expander implementation).
|
||||
*/
|
||||
};
|
||||
|
||||
#endif /* CONFIG_IOEXPANDER */
|
||||
|
Loading…
x
Reference in New Issue
Block a user