diff --git a/drivers/ioexpander/Kconfig b/drivers/ioexpander/Kconfig index 0e9e0503a5..619e9105b7 100644 --- a/drivers/ioexpander/Kconfig +++ b/drivers/ioexpander/Kconfig @@ -189,4 +189,15 @@ config GPIO_LOWER_HALF Enable support for a lower half driver that provides GPIO driver support for I/O expander pins. +if GPIO_LOWER_HALF + +config GPIO_LOWER_HALF_INTTYPE + int "default interrupt type for GPIO_INTERRUPT_PIN pintype" + default 14 + ---help--- + This is the default interrupt type (IOEXPANDER_VAL_BOTH) for + GPIO_INTERRUPT_PIN pintype in gplf driver register. + +endif + endmenu # IO Expander/GPIO Support diff --git a/drivers/ioexpander/gpio.c b/drivers/ioexpander/gpio.c index 69ebd8d3b5..f534a7160e 100644 --- a/drivers/ioexpander/gpio.c +++ b/drivers/ioexpander/gpio.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/ioexpander/gpio.c * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -55,7 +55,7 @@ * Private Function Prototypes ****************************************************************************/ -static int gpio_handler(FAR struct gpio_dev_s *dev); +static int gpio_handler(FAR struct gpio_dev_s *dev, uint8_t pin); static int gpio_open(FAR struct file *filep); static int gpio_close(FAR struct file *filep); static ssize_t gpio_read(FAR struct file *filep, FAR char *buffer, @@ -97,7 +97,7 @@ static const struct file_operations g_gpio_drvrops = * ****************************************************************************/ -static int gpio_handler(FAR struct gpio_dev_s *dev) +static int gpio_handler(FAR struct gpio_dev_s *dev, uint8_t pin) { DEBUGASSERT(dev != NULL); (void)nxsig_kill(dev->gp_pid, dev->gp_signo); @@ -296,6 +296,17 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + /* Command: GPIOC_SETPINTYPE + * Description: Set the GPIO pin type. + * Argument: The enum gpio_pintype_e type. + */ + + case GPIOC_SETPINTYPE: + { + ret = dev->gp_ops->go_setpintype(dev, arg); + } + break; + /* Unrecognized command */ default: @@ -378,4 +389,54 @@ int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor) return register_driver(devname, &g_gpio_drvrops, 0666, dev); } +/**************************************************************************** + * Name: gpio_pin_unregister + * + * Description: + * Unregister GPIO pin device driver. + * + * - Input pin types will be registered at /dev/gpinN + * - Output pin types will be registered at /dev/gpoutN + * - Interrupt pin types will be registered at /dev/gpintN + * + * Where N is the provided minor number in the range of 0-99. + * + * + ****************************************************************************/ + +void gpio_pin_unregister(FAR struct gpio_dev_s *dev, int minor) +{ + FAR const char *fmt; + char devname[16]; + + switch (dev->gp_pintype) + { + case GPIO_INPUT_PIN: + { + fmt = "/dev/gpin%u"; + } + break; + + case GPIO_OUTPUT_PIN: + { + fmt = "/dev/gpout%u"; + } + break; + + case GPIO_INTERRUPT_PIN: + { + fmt = "/dev/gpint%u"; + } + break; + + default: + return; + } + + snprintf(devname, 16, fmt, (unsigned int)minor); + gpioinfo("Unregistering %s\n", devname); + + (void)unregister_driver(devname); +} + #endif /* CONFIG_DEV_GPIO */ diff --git a/drivers/ioexpander/gpio_lower_half.c b/drivers/ioexpander/gpio_lower_half.c index 86d26e9e62..dec00c46f6 100644 --- a/drivers/ioexpander/gpio_lower_half.c +++ b/drivers/ioexpander/gpio_lower_half.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/ioexpander/gpio_lower_half.c * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -88,6 +88,8 @@ 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); #endif +static int gplh_setpintype(FAR struct gpio_dev_s *gpio, + enum gpio_pintype_e pintype); /**************************************************************************** * Private Data @@ -106,6 +108,22 @@ static const struct gpio_operations_s g_gplh_ops = NULL, /* attach */ NULL, /* enable */ #endif + gplh_setpintype, +}; + +/* REVISIT: The following violates the NuttX coding standard requirement + * for C89 compatibility. + */ + +static const uint32_t g_gplh_inttype[] = +{ + [GPIO_INPUT_PIN] = IOEXPANDER_VAL_DISABLE, + [GPIO_INTERRUPT_PIN] = CONFIG_GPIO_LOWER_HALF_INTTYPE, + [GPIO_INTERRUPT_HIGH_PIN] = IOEXPANDER_VAL_HIGH, + [GPIO_INTERRUPT_LOW_PIN] = IOEXPANDER_VAL_LOW, + [GPIO_INTERRUPT_RISING_PIN] = IOEXPANDER_VAL_RISING, + [GPIO_INTERRUPT_FALLING_PIN] = IOEXPANDER_VAL_FALLING, + [GPIO_INTERRUPT_BOTH_PIN] = IOEXPANDER_VAL_BOTH, }; /**************************************************************************** @@ -135,7 +153,7 @@ static int gplh_handler(FAR struct ioexpander_dev_s *ioe, * upper half GPIO driver via its callback. */ - return priv->callback(&priv->gpio); + return priv->callback(&priv->gpio, priv->pin); } #endif @@ -258,7 +276,11 @@ static int gplh_enable(FAR struct gpio_dev_s *gpio, bool enable) else if (priv->handle == NULL) { +#if CONFIG_IOEXPANDER_NPINS <= 64 ioe_pinset_t pinset = ((ioe_pinset_t)1 << priv->pin); +#else + ioe_pinset_t pinset = ((ioe_pinset_t)priv->pin); +#endif /* We have a callback and the callback is not yet attached. * do it now. @@ -302,6 +324,39 @@ static int gplh_enable(FAR struct gpio_dev_s *gpio, bool enable) } #endif +/**************************************************************************** + * Name: gplh_setpintype + * + * Description: + * Set I/O expander pin to an appointed gpiopintype + * + ****************************************************************************/ + +static int gplh_setpintype(FAR struct gpio_dev_s *gpio, enum gpio_pintype_e pintype) +{ + FAR struct gplh_dev_s *priv = (FAR struct gplh_dev_s *)gpio; + FAR struct ioexpander_dev_s *ioe = priv->ioe; + uint8_t pin = priv->pin; + + if (pintype >= GPIO_NPINTYPES) + { + return -EINVAL; + } + else if (pintype == GPIO_OUTPUT_PIN) + { + IOEXP_SETDIRECTION(ioe, pin, IOEXPANDER_DIRECTION_OUT); + } + else + { + IOEXP_SETDIRECTION(ioe, pin, IOEXPANDER_DIRECTION_IN); + IOEXP_SETOPTION(ioe, pin, IOEXPANDER_OPTION_INTCFG, + (FAR void *)g_gplh_inttype[pintype]); + } + + gpio->gp_pintype = pintype; + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -360,6 +415,17 @@ int gpio_lower_half(FAR struct ioexpander_dev_s *ioe, unsigned int pin, gpio->gp_pintype = (uint8_t)pintype; gpio->gp_ops = &g_gplh_ops; + if (pintype == GPIO_OUTPUT_PIN) + { + IOEXP_SETDIRECTION(ioe, pin, IOEXPANDER_DIRECTION_OUT); + } + else + { + IOEXP_SETDIRECTION(ioe, pin, IOEXPANDER_DIRECTION_IN); + IOEXP_SETOPTION(ioe, pin, IOEXPANDER_OPTION_INTCFG, + (FAR void *)g_gplh_inttype[pintype]); + } + /* Register the GPIO driver */ ret = gpio_pin_register(gpio, minor); diff --git a/include/nuttx/ioexpander/gpio.h b/include/nuttx/ioexpander/gpio.h index e8a0c44a4d..13f06ad772 100644 --- a/include/nuttx/ioexpander/gpio.h +++ b/include/nuttx/ioexpander/gpio.h @@ -75,6 +75,11 @@ * Command: GPIOC_UNREGISTER * Description: Stop receiving signals for pin interrupts. * Argument: None. + * + * Command: GPIOC_SETPINTYPE + * Description: Set the GPIO pin type. + * Argument: The enum gpio_pintype_e type. + * */ #define GPIOC_WRITE _GPIOC(1) @@ -82,6 +87,7 @@ #define GPIOC_PINTYPE _GPIOC(3) #define GPIOC_REGISTER _GPIOC(4) #define GPIOC_UNREGISTER _GPIOC(5) +#define GPIOC_SETPINTYPE _GPIOC(6) /**************************************************************************** * Public Types @@ -94,6 +100,11 @@ enum gpio_pintype_e GPIO_INPUT_PIN = 0, GPIO_OUTPUT_PIN, GPIO_INTERRUPT_PIN, + GPIO_INTERRUPT_HIGH_PIN, + GPIO_INTERRUPT_LOW_PIN, + GPIO_INTERRUPT_RISING_PIN, + GPIO_INTERRUPT_FALLING_PIN, + GPIO_INTERRUPT_BOTH_PIN, GPIO_NPINTYPES }; @@ -110,6 +121,7 @@ typedef CODE int (*pin_interrupt_t)(FAR struct gpio_dev_s *dev); * for other pin types may be NULL. * - go_attach and gp_eanble. Required only the GPIO_INTERRUPT_PIN pin * type. Unused for other pin types may be NULL. + * - go_setpinytype. Required for all all pin types. */ struct gpio_dev_s; @@ -122,6 +134,8 @@ struct gpio_operations_s 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); + CODE int (*go_setpintype)(FAR struct gpio_dev_s *dev, + enum gpio_pintype_e pintype); }; /* Pin interface definition. Must lie in writable memory. */ @@ -177,6 +191,23 @@ extern "C" int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor); +/**************************************************************************** + * Name: gpio_pin_unregister + * + * Description: + * Unregister GPIO pin device driver. + * + * - Input pin types will be registered at /dev/gpinN + * - Output pin types will be registered at /dev/gpoutN + * - Interrupt pin types will be registered at /dev/gpintN + * + * Where N is the provided minor number in the range of 0-99. + * + * + ****************************************************************************/ + +void gpio_pin_unregister(FAR struct gpio_dev_s *dev, int minor); + /**************************************************************************** * Name: gpio_lower_half * diff --git a/include/nuttx/ioexpander/ioexpander.h b/include/nuttx/ioexpander/ioexpander.h index f149b7dfa7..079b839ff6 100644 --- a/include/nuttx/ioexpander/ioexpander.h +++ b/include/nuttx/ioexpander/ioexpander.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/ioexpander/ioexpander.h * - * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2015-2016, 2018 Gregory Nutt. All rights reserved. * Author: Sebastien Lorquet * * Redistribution and use in source and binary forms, with or without @@ -41,6 +41,7 @@ ****************************************************************************/ #include +#include #include #ifdef CONFIG_IOEXPANDER @@ -55,10 +56,6 @@ # 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 @@ -101,7 +98,7 @@ * ****************************************************************************/ -#define IOEXP_SETDIRECTION(dev,pin,dir) ((dev)->ops->ioe_direction(dev,pin,dir)) +#define IOEXP_SETDIRECTION(dev,pin,dir) ((dev)->ops->ioe_direction(dev,pin,dir)) /**************************************************************************** * Name: IOEXP_SETOPTION @@ -293,7 +290,11 @@ * Public Types ****************************************************************************/ -/* This type represents a bitmap of pins */ +/* This type represents a bitmap of pins + * + * For IOE NPINS greater than 64, ioe_pinset_t represent one interrupt pin + * number instead of a bitmap of pins. + */ #if CONFIG_IOEXPANDER_NPINS <= 8 typedef uint8_t ioe_pinset_t; @@ -301,8 +302,10 @@ typedef uint8_t ioe_pinset_t; typedef uint16_t ioe_pinset_t; #elif CONFIG_IOEXPANDER_NPINS <= 32 typedef uint32_t ioe_pinset_t; -#else /* if CONFIG_IOEXPANDER_NPINS <= 64 */ +#elif CONFIG_IOEXPANDER_NPINS <= 64 typedef uint64_t ioe_pinset_t; +#else +typedef uint8_t ioe_pinset_t; #endif #ifdef CONFIG_IOEXPANDER_INT_ENABLE