diff --git a/drivers/ioexpander/Kconfig b/drivers/ioexpander/Kconfig index feb5e942b36..470782d61e0 100644 --- a/drivers/ioexpander/Kconfig +++ b/drivers/ioexpander/Kconfig @@ -139,4 +139,12 @@ config DEV_GPIO Enables a simple GPIO input/output driver to support application- space testing of hardware. +config GPIO_LOWER_HALF + bool "GPIO Lower Half" + default n + depends on DEV_GPIO && IOEXPANDER + ---help--- + Enable support for a lower half driver that provides GPIO driver + support for I/O expander pins. + endmenu # IO Expander/GPIO Support diff --git a/drivers/ioexpander/Make.defs b/drivers/ioexpander/Make.defs index 87114f6e5b0..0a985e5df8a 100644 --- a/drivers/ioexpander/Make.defs +++ b/drivers/ioexpander/Make.defs @@ -1,8 +1,9 @@ ############################################################################ # drivers/ioexpander/Make.defs # -# Copyright (C) 2015 Gregory Nutt. All rights reserved. +# Copyright (C) 2015-2016 Gregory Nutt. All rights reserved. # Author: Sebastien Lorquet +# Gregory Nutt # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -53,6 +54,9 @@ endif # CONFIG_IOEXPANDER ifeq ($(CONFIG_DEV_GPIO),y) CSRCS += gpio.c +ifeq ($(CONFIG_GPIO_LOWER_HALF),y) + CSRCS += gpio_lower_half.c +endif endif # The folling implements an awkward OR diff --git a/drivers/ioexpander/gpio.c b/drivers/ioexpander/gpio.c index b4563e0476d..c19539baccc 100644 --- a/drivers/ioexpander/gpio.c +++ b/drivers/ioexpander/gpio.c @@ -187,7 +187,7 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) if (dev->gp_pintype == GPIO_OUTPUT_PIN) { DEBUGASSERT(arg == 0ul || arg == 1ul); - ret = dev->gp_ops->go_write(dev, (int)arg); + ret = dev->gp_ops->go_write(dev, (bool)arg); } else { @@ -197,13 +197,13 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) /* Command: GPIOC_READ * Description: Read the value of an input or output GPIO - * Argument: A pointer to an integer value to receive the result: - * 0=low value; 1=high value. + * Argument: A pointer to an bool value to receive the result: + * false=low value; true=high value. */ case GPIOC_READ: { - FAR int *ptr = (FAR int *)((uintptr_t)arg); + FAR bool *ptr = (FAR bool *)((uintptr_t)arg); DEBUGASSERT(ptr != NULL); ret = dev->gp_ops->go_read(dev, ptr); diff --git a/drivers/ioexpander/gpio_lower_half.c b/drivers/ioexpander/gpio_lower_half.c new file mode 100644 index 00000000000..a9082834ec2 --- /dev/null +++ b/drivers/ioexpander/gpio_lower_half.c @@ -0,0 +1,344 @@ +/**************************************************************************** + * drivers/ioexpander/gpio_lower_half.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_GPIO_LOWER_HALF + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* GPIO lower half driver state */ + +struct gplh_dev_s +{ + /* Publically visiable lower-half state */ + + struct gpio_dev_s gpio; + + /* Private driver data follows */ + + uint8_t pin; /* I/O expander pin ID */ + FAR struct ioexpander_dev_s *ioe; /* Contain I/O expander interface */ + FAR void *handle; /* Interrupt attach handle */ + pin_interrupt_t callback; /* Interrupt callback */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int gplh_handler(FAR struct ioexpander_dev_s *ioe, + ioe_pinset_t pinset, FAR void *arg); + +/* GPIO Lower Half Interface methods */ + +static int gplh_read(FAR struct gpio_dev_s *gpio, FAR bool *value); +static int gplh_write(FAR struct gpio_dev_s *gpio, bool value); +static int gplh_attach(FAR struct gpio_dev_s *gpio, pin_interrupt_t callback); +static int gplh_enable(FAR struct gpio_dev_s *gpio, bool enable); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct gpio_operations_s g_gplh_ops = +{ + gplh_read, /* read */ + gplh_write, /* write */ + gplh_attach, /* attach */ + gplh_enable, /* enable */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: gplh_handler + * + * Description: + * I/O expander interrupt callback function. + * + ****************************************************************************/ + +static int gplh_handler(FAR struct ioexpander_dev_s *ioe, + ioe_pinset_t pinset, FAR void *arg) +{ + FAR struct gplh_dev_s *priv = (FAR struct gplh_dev_s *)arg; + + DEBUGASSERT(priv != NULL && priv->callback != NULL); + + gpioinfo("pin%u: pinset: %lx\n", priv->pin, (unsigned long)pinset); + + /* We received the callback from the I/O expander, forward this to the + * upper half GPIO driver via its callback. + */ + + return priv->callback(&priv->gpio); +} + +/**************************************************************************** + * Name: gplh_read + * + * Description: + * Read the value of the I/O expander pin. + * + ****************************************************************************/ + +static int gplh_read(FAR struct gpio_dev_s *gpio, FAR bool *value) +{ + FAR struct gplh_dev_s *priv = (FAR struct gplh_dev_s *)gpio; + + DEBUGASSERT(priv != NULL && priv->ioe != NULL); + + gpioinfo("pin%u: value=%p\n", priv->pin, value); + + /* Get the value from the I/O expander */ + + return IOEXP_READPIN(priv->ioe, priv->pin, value); +} + +/**************************************************************************** + * Name: gplh_write + * + * Description: + * Set the value of an I/O expander output pin + * + ****************************************************************************/ + +static int gplh_write(FAR struct gpio_dev_s *gpio, bool value) +{ + FAR struct gplh_dev_s *priv = (FAR struct gplh_dev_s *)gpio; + + DEBUGASSERT(priv != NULL && priv->ioe != NULL); + + gpioinfo("pin%u: value=%u\n", priv->pin, value); + + /* Write the value using the I/O expander */ + + return IOEXP_WRITEPIN(priv->ioe, priv->pin, value); +} + +/**************************************************************************** + * Name: gplh_attach + * + * Description: + * Detach and disable any current interrupt on the pin. Save the callback + * information for use when the pin interrupt is enabled. + * + ****************************************************************************/ + +static int gplh_attach(FAR struct gpio_dev_s *gpio, pin_interrupt_t callback) +{ + FAR struct gplh_dev_s *priv = (FAR struct gplh_dev_s *)gpio; + + DEBUGASSERT(priv != NULL && priv->ioe != NULL); + + gpioinfo("pin%u: callback=%p\n", priv->pin, callback); + + /* Detach and disable any current interrupt on the pin. */ + + if (priv->handle != NULL) + { + gpioinfo("pin%u: Detaching...\n", priv->pin); + (void)IOEP_DETACH(priv->ioe, priv->handle); + priv->handle = NULL; + } + + /* Save the callback function pointer for use when the pin interrupt + * is enabled. + */ + + priv->callback = callback; + return OK; +} + +/**************************************************************************** + * Name: gplh_enable + * + * Description: + * Enable or disable the I/O expander pin interrupt + * + ****************************************************************************/ + +static int gplh_enable(FAR struct gpio_dev_s *gpio, bool enable) +{ + FAR struct gplh_dev_s *priv = (FAR struct gplh_dev_s *)gpio; + int ret = OK; + + DEBUGASSERT(priv != NULL && priv->ioe != NULL); + + gpioinfo("pin%u: %s\n", priv->pin, enable ? "Enabling" : "Disabling"); + + /* Are we enabling or disabling the pin interrupt? */ + + if (enable) + { + /* We are enabling the pin interrupt. Make certain that there is + * an interrupt handler already attached. + */ + + if (priv->callback == NULL) + { + /* No callback has been attached */ + + gpiowarn("WARNING: pin%u: Attempt to enable before attaching\n", + priv->pin); + ret = -EPERM; + } + + /* Check if the interrupt is already attached and enabled */ + + else if (priv->handle == NULL) + { + ioe_pinset_t pinset = ((ioe_pinset_t)1 << priv->pin); + + /* We have a callback and the callback is not yet attached. + * do it now. + */ + + gpioinfo("pin%u: Attaching %p\n", priv->pin, priv->callback); + + priv->handle = IOEP_ATTACH(priv->ioe, pinset, gplh_handler, priv); + if (priv->handle == NULL) + { + gpioerr("ERROR: pin%u: IOEP_ATTACH() failed\n", priv->pin); + ret = -EIO; + } + } + } + else + { + /* Check if we are already detached */ + + if (priv->handle == NULL) + { + gpiowarn("WARNING: pin%u: Already detached\n", priv->pin); + } + else + { + gpioinfo("pin%u: Detaching handle=%p\n", priv->pin, priv->handle); + ret = IOEP_DETACH(priv->ioe, priv->handle); + if (ret < 0) + { + gpioerr("ERROR: pin%u: IOEP_DETACH() failed\n", + priv->pin, ret); + } + + /* We are no longer attached */ + + priv->handle = NULL; + } + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: gpio_lower_half + * + * Description: + * Create a GPIO pin device driver instance for an I/O expander pin. + * + * Input Parameters: + * ioe - An instance of the I/O expander interface + * pin - The I/O expander pin number for the driver + * pintype - See enum gpio_pintype_e + * minor - The minor device number to use when registering the device + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int gpio_lower_half(FAR struct ioexpander_dev_s *ioe, unsigned int pin, + enum gpio_pintype_e pintype, int minor) +{ + FAR struct gplh_dev_s *priv; + FAR struct gpio_dev_s *gpio; + int ret; + + DEBUGASSERT(ioe != NULL && pin < CONFIG_IOEXPANDER_NPINS && + (unsigned int)pintype < GPIO_NPINTYPES); + + /* Allocate an new instance of the GPIO lower half driver */ + + priv = (FAR struct gplh_dev_s *)kmm_zalloc(sizeof(struct gplh_dev_s)); + if (priv == NULL) + { + gpioerr("ERROR: Failed to allocate driver state\n"); + return -ENOMEM; + } + + /* Initialize the non-zero elements of the newly allocated instance */ + + priv->pin = (uint8_t)pin; + gpio = &priv->gpio; + gpio->gp_pintype = (uint8_t)pintype; + gpio->gp_ops = &g_gplh_ops; + + /* Register the GPIO driver */ + + ret = gpio_pin_register(gpio, minor); + if (ret < 0) + { + gpioerr("ERROR: gpio_pin_register() failed: %d\n", ret); + kmm_free(priv); + } + + return ret; +} + +#endif /* CONFIG_GPIO_LOWER_HALF */ diff --git a/include/nuttx/ioexpander/gpio.h b/include/nuttx/ioexpander/gpio.h index c4c044e6a89..21c08b786e3 100644 --- a/include/nuttx/ioexpander/gpio.h +++ b/include/nuttx/ioexpander/gpio.h @@ -41,6 +41,10 @@ ****************************************************************************/ #include + +#include +#include + #include /**************************************************************************** @@ -49,12 +53,12 @@ /* Command: GPIOC_WRITE * Description: Set the value of an output GPIO - * Argument: 0=output a low value; 1=outut a high value + * Argument: T0=output a low value; 1=outut a high value * * Command: GPIOC_READ * Description: Read the value of an input or output GPIO - * Argument: A pointer to an integer value to receive the result: - * 0=low value; 1=high value. + * Argument: A pointer to an bool value to receive the result: + * false=low value; true=high value. * * Command: GPIOC_REGISTER * Description: Register to receive a signal whenever there an interrupt @@ -78,11 +82,13 @@ enum gpio_pintype_e { GPIO_INPUT_PIN = 0, GPIO_OUTPUT_PIN, - GPIO_INTERRUPT_PIN + GPIO_INTERRUPT_PIN, + GPIO_NPINTYPES }; /* Interrupt callback */ +struct gpio_dev_s; typedef CODE int (*pin_interrupt_t)(FAR struct gpio_dev_s *dev); /* Pin interface vtable definition. Instances of this vtable are read-only @@ -100,8 +106,8 @@ struct gpio_operations_s { /* Interface methods */ - CODE int (*go_read)(FAR struct gpio_dev_s *dev, FAR int *value); - CODE int (*go_write)(FAR struct gpio_dev_s *dev, int value); + CODE int (*go_read)(FAR struct gpio_dev_s *dev, FAR bool *value); + CODE int (*go_write)(FAR struct gpio_dev_s *dev, bool value); CODE int (*go_attach)(FAR struct gpio_dev_s *dev, pin_interrupt_t callback); CODE int (*go_enable)(FAR struct gpio_dev_s *dev, bool enable); @@ -160,6 +166,29 @@ extern "C" int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor); +/**************************************************************************** + * Name: gpio_lower_half + * + * Description: + * Create a GPIO pin device driver instance for an I/O expander pin. + * + * Input Parameters: + * ioe - An instance of the I/O expander interface + * pin - The I/O expander pin number for the driver + * pintype - See enum gpio_pintype_e + * minor - The minor device number to use when registering the device + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_GPIO_LOWER_HALF +struct ioexpander_dev_s; +int gpio_lower_half(FAR struct ioexpander_dev_s *ioe, unsigned int pin, + enum gpio_pintype_e pintype, int minor); +#endif + #ifdef __cplusplus } #endif diff --git a/include/nuttx/ioexpander€ioexpander.h b/include/nuttx/ioexpander€ioexpander.h new file mode 100644 index 00000000000..691d34385fa --- /dev/null +++ b/include/nuttx/ioexpander€ioexpander.h @@ -0,0 +1,357 @@ +/**************************************************************************** + * include/nuttx/ioexpander/ioexpander.h + * + * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved. + * Author: Sebastien Lorquet + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_IOEXPANDER_IOEXPANDER_H +#define __INCLUDE_NUTTX_IOEXPANDER_IOEXPANDER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#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 definitions **********************************************************/ + +#define IOEXPANDER_DIRECTION_IN 0 +#define IOEXPANDER_DIRECTION_OUT 1 + +/* Pin options */ + +#define IOEXPANDER_OPTION_INVERT 1 /* Set the "active" level for a pin */ +# define IOEXPANDER_VAL_NORMAL 0 /* Normal, no inversion */ +# define IOEXPANDER_VAL_INVERT 1 /* Inverted */ + +#define IOEXPANDER_OPTION_INTCFG 2 /* Configure interrupt for a pin */ +# define IOEXPANDER_VAL_LEVEL 1 /* xx1 Interrupt on level (vs. edge) */ +# define IOEXPANDER_VAL_HIGH 1 /* 001 Interrupt on high level */ +# define IOEXPANDER_VAL_LOW 3 /* 011 Interrupt on low level */ +# define IOEXPANDER_VAL_RISING 2 /* 010 Interrupt on rising edge */ +# define IOEXPANDER_VAL_FALLING 4 /* 100 Interrupt on falling edge */ +# define IOEXPANDER_VAL_BOTH 6 /* 110 Interrupt on both edges */ + +#define PINSET_ALL (~((ioe_pinset_t)0)) + +/* Access macros ************************************************************/ + +/**************************************************************************** + * Name: IOEXP_SETDIRECTION + * + * Description: + * Set the direction of an ioexpander pin. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * dir - One of the IOEXPANDER_DIRECTION_ macros + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#define IOEXP_SETDIRECTION(dev,pin,dir) ((dev)->ops->ioe_direction(dev,pin,dir)) + +/**************************************************************************** + * Name: IOEXP_SETOPTION + * + * Description: + * Set pin options. Required. + * Since all IO expanders have various pin options, this API allows setting + * pin options in a flexible way. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * opt - One of the IOEXPANDER_OPTION_ macros + * val - The option's value + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#define IOEXP_SETOPTION(dev,pin,opt,val) ((dev)->ops->ioe_option(dev,pin,opt,val)) + +/**************************************************************************** + * Name: IOEXP_WRITEPIN + * + * Description: + * Set the pin level. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * val - The pin level. Usually TRUE will set the pin high, + * except if OPTION_INVERT has been set on this pin. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#define IOEXP_WRITEPIN(dev,pin,val) ((dev)->ops->ioe_writepin(dev,pin,val)) + +/**************************************************************************** + * Name: IOEXP_READPIN + * + * Description: + * Read the actual PIN level. This can be different from the last value written + * to this pin. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin + * valptr - Pointer to a buffer where the pin level is stored. Usually TRUE + * if the pin is high, except if OPTION_INVERT has been set on this pin. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#define IOEXP_READPIN(dev,pin,valptr) ((dev)->ops->ioe_readpin(dev,pin,valptr)) + +/**************************************************************************** + * Name: IOEXP_READBUF + * + * Description: + * Read the buffered pin level. + * This can be different from the actual pin state. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin + * valptr - Pointer to a buffer where the level is stored. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#define IOEXP_READBUF(dev,pin,valptr) ((dev)->ops->ioe_readbuf(dev,pin,valptr)) + +#ifdef CONFIG_IOEXPANDER_MULTIPIN + +/**************************************************************************** + * Name: IOEXP_MULTIWRITEPIN + * + * Description: + * Set the pin level for multiple pins. This routine may be faster than + * individual pin accesses. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * pins - The list of pin indexes to alter in this call + * val - The list of pin levels. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#define IOEXP_MULTIWRITEPIN(dev,pins,vals,count) \ + ((dev)->ops->ioe_multiwritepin(dev,pins,vals,count)) + +/**************************************************************************** + * Name: IOEXP_MULTIREADPIN + * + * Description: + * Read the actual level for multiple pins. This routine may be faster than + * individual pin accesses. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The list of pin indexes to read + * valptr - Pointer to a buffer where the pin levels are stored. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#define IOEXP_MULTIREADPIN(dev,pins,vals,count) \ + ((dev)->ops->ioe_multireadpin(dev,pins,vals,count)) + +/**************************************************************************** + * Name: IOEXP_MULTIREADBUF + * + * Description: + * Read the buffered level of multiple pins. This routine may be faster than + * individual pin accesses. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin + * valptr - Pointer to a buffer where the buffered levels are stored. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#define IOEXP_MULTIREADBUF(dev,pins,vals,count) \ + ((dev)->ops->ioe_multireadbuf(dev,pins,vals,count)) + +#endif /* CONFIG_IOEXPANDER_MULTIPIN */ + +/**************************************************************************** + * Name: IOEP_ATTACH + * + * Description: + * Attach and enable 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. + * arg - User-provided callback argument + * + * Returned Value: + * A non-NULL handle value is returned on success. This handle may be + * used later to detach and disable the pin interrupt. + * + ****************************************************************************/ + +#ifdef CONFIG_IOEXPANDER_INT_ENABLE +#define IOEP_ATTACH(dev,pinset,callback,arg) \ + ((dev)->ops->ioe_attach(dev,pinset,callback,arg)) +#endif + +/**************************************************************************** + * Name: IOEP_DETACH + * + * Description: + * Detach and disable a pin interrupt callback function. + * + * Input Parameters: + * dev - Device-specific state data + * handle - The non-NULL opaque value return by IOEP_ATTACH + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#ifdef CONFIG_IOEXPANDER_INT_ENABLE +#define IOEP_DETACH(dev,handle) ((dev)->ops->ioe_detach(dev,handle)) +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This type represents a bitmap of pins */ + +#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 + +#ifdef CONFIG_IOEXPANDER_INT_ENABLE +/* 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, FAR void *arg); +#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, + int direction); + CODE int (*ioe_option)(FAR struct ioexpander_dev_s *dev, uint8_t pin, + int opt, void *val); + CODE int (*ioe_writepin)(FAR struct ioexpander_dev_s *dev, uint8_t pin, + bool value); + CODE int (*ioe_readpin)(FAR struct ioexpander_dev_s *dev, uint8_t pin, + bool *value); + CODE int (*ioe_readbuf)(FAR struct ioexpander_dev_s *dev, uint8_t pin, + bool *value); +#ifdef CONFIG_IOEXPANDER_MULTIPIN + CODE int (*ioe_multiwritepin)(FAR struct ioexpander_dev_s *dev, + uint8_t *pins, bool *values, int count); + CODE int (*ioe_multireadpin)(FAR struct ioexpander_dev_s *dev, + uint8_t *pins, bool *values, int count); + CODE int (*ioe_multireadbuf)(FAR struct ioexpander_dev_s *dev, + uint8_t *pins, bool *values, int count); +#endif +#ifdef CONFIG_IOEXPANDER_INT_ENABLE + CODE FAR void *(*ioe_attach)(FAR struct ioexpander_dev_s *dev, + ioe_pinset_t pinset, + ioe_callback_t callback, FAR void *arg); + CODE int (*ioe_detach)(FAR struct ioexpander_dev_s *dev, + FAR void *handle); +#endif +}; + +struct ioexpander_dev_s +{ + /* "Lower half" operations provided by the I/O expander lower half */ + + FAR const struct ioexpander_ops_s *ops; + + /* Internal storage used by the I/O expander may (internal to the I/O + * expander implementation). + */ +}; + +#endif /* CONFIG_IOEXPANDER */ +#endif /* __INCLUDE_NUTTX_IOEXPANDER_IOEXPANDER_H */