diff --git a/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-devkit/index.rst b/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-devkit/index.rst index f68af97df0..209021cdc8 100644 --- a/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-devkit/index.rst +++ b/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-devkit/index.rst @@ -57,15 +57,15 @@ GPIO9 as an interrupt pin. At the nsh, we can turn the outputs on and off with the following:: - nsh> gpio -o 1 /dev/gpout0 - nsh> gpio -o 1 /dev/gpout1 + nsh> gpio -o 1 /dev/gpio0 + nsh> gpio -o 1 /dev/gpio1 - nsh> gpio -o 0 /dev/gpout0 - nsh> gpio -o 0 /dev/gpout1 + nsh> gpio -o 0 /dev/gpio0 + nsh> gpio -o 0 /dev/gpio1 We can use the interrupt pin to send a signal when the interrupt fires:: - nsh> gpio -w 14 /dev/gpint2 + nsh> gpio -w 14 /dev/gpio2 The pin is configured as a rising edge interrupt, so after issuing the above command, connect it to 3.3V. diff --git a/Documentation/platforms/xtensa/esp32/boards/esp32-wrover-kit/index.rst b/Documentation/platforms/xtensa/esp32/boards/esp32-wrover-kit/index.rst index 1f1fca8b6d..f25aa4093d 100644 --- a/Documentation/platforms/xtensa/esp32/boards/esp32-wrover-kit/index.rst +++ b/Documentation/platforms/xtensa/esp32/boards/esp32-wrover-kit/index.rst @@ -102,12 +102,12 @@ This is a test for the GPIO driver. It includes the 3 LEDs and one, arbitrary, G For this example, GPIO22 was used. At the nsh, we can turn LEDs on and off with the following:: - nsh> gpio -o 1 /dev/gpout0 - nsh> gpio -o 0 /dev/gpout1 + nsh> gpio -o 1 /dev/gpio0 + nsh> gpio -o 0 /dev/gpio0 We can use the interrupt pin to send a signal when the interrupt fires:: - nsh> gpio -w 14 /dev/gpint0 + nsh> gpio -w 14 /dev/gpio2 The pin is configured to as a rising edge interrupt, so after issuing the above command, connect it to 3.3V. diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_gpio.c b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_gpio.c index c5af014b43..2fdb5cb063 100644 --- a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_gpio.c +++ b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_gpio.c @@ -282,6 +282,7 @@ static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable) int esp32c3_gpio_init(void) { + int pincount = 0; int i; #if BOARD_NGPIOOUT > 0 @@ -292,7 +293,7 @@ int esp32c3_gpio_init(void) g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN; g_gpout[i].gpio.gp_ops = &gpout_ops; g_gpout[i].id = i; - gpio_pin_register(&g_gpout[i].gpio, i); + gpio_pin_register(&g_gpout[i].gpio, pincount); /* Configure the pins that will be used as output */ @@ -300,6 +301,8 @@ int esp32c3_gpio_init(void) esp32c3_configgpio(g_gpiooutputs[i], OUTPUT_FUNCTION_1 | INPUT_FUNCTION_1); esp32c3_gpiowrite(g_gpiooutputs[i], 0); + + pincount++; } #endif @@ -311,11 +314,13 @@ int esp32c3_gpio_init(void) g_gpint[i].esp32c3gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN; g_gpint[i].esp32c3gpio.gpio.gp_ops = &gpint_ops; g_gpint[i].esp32c3gpio.id = i; - gpio_pin_register(&g_gpint[i].esp32c3gpio.gpio, i); + gpio_pin_register(&g_gpint[i].esp32c3gpio.gpio, pincount); /* Configure the pins that will be used as interrupt input */ esp32c3_configgpio(g_gpiointinputs[i], INPUT_FUNCTION_1 | PULLDOWN); + + pincount++; } #endif diff --git a/boards/xtensa/esp32/esp32-devkitc/src/esp32_gpio.c b/boards/xtensa/esp32/esp32-devkitc/src/esp32_gpio.c index e5c8d9bed0..e1fd26c976 100644 --- a/boards/xtensa/esp32/esp32-devkitc/src/esp32_gpio.c +++ b/boards/xtensa/esp32/esp32-devkitc/src/esp32_gpio.c @@ -326,6 +326,7 @@ static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable) int esp32_gpio_init(void) { + int pincount = 0; int i; #if BOARD_NGPIOOUT > 0 @@ -336,7 +337,7 @@ int esp32_gpio_init(void) g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN; g_gpout[i].gpio.gp_ops = &gpout_ops; g_gpout[i].id = i; - gpio_pin_register(&g_gpout[i].gpio, i); + gpio_pin_register(&g_gpout[i].gpio, pincount); /* Configure the pins that will be used as output */ @@ -344,6 +345,8 @@ int esp32_gpio_init(void) esp32_configgpio(g_gpiooutputs[i], OUTPUT_FUNCTION_3 | INPUT_FUNCTION_3); esp32_gpiowrite(g_gpiooutputs[i], 0); + + pincount++; } #endif @@ -355,11 +358,13 @@ int esp32_gpio_init(void) g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN; g_gpin[i].gpio.gp_ops = &gpin_ops; g_gpin[i].id = i; - gpio_pin_register(&g_gpin[i].gpio, i); + gpio_pin_register(&g_gpin[i].gpio, pincount); /* Configure the pins that will be used as INPUT */ esp32_configgpio(g_gpioinputs[i], INPUT_FUNCTION_3); + + pincount++; } #endif @@ -371,11 +376,13 @@ int esp32_gpio_init(void) g_gpint[i].esp32gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN; g_gpint[i].esp32gpio.gpio.gp_ops = &gpint_ops; g_gpint[i].esp32gpio.id = i; - gpio_pin_register(&g_gpint[i].esp32gpio.gpio, i); + gpio_pin_register(&g_gpint[i].esp32gpio.gpio, pincount); /* Configure the pins that will be used as interrupt input */ esp32_configgpio(g_gpiointinputs[i], INPUT_FUNCTION_3 | PULLDOWN); + + pincount++; } #endif diff --git a/boards/xtensa/esp32/esp32-wrover-kit/src/esp32_gpio.c b/boards/xtensa/esp32/esp32-wrover-kit/src/esp32_gpio.c index cb500100d3..5bbb7b4cf9 100644 --- a/boards/xtensa/esp32/esp32-wrover-kit/src/esp32_gpio.c +++ b/boards/xtensa/esp32/esp32-wrover-kit/src/esp32_gpio.c @@ -326,6 +326,7 @@ static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable) int esp32_gpio_init(void) { + int pincount = 0; int i; #if BOARD_NGPIOOUT > 0 @@ -336,7 +337,7 @@ int esp32_gpio_init(void) g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN; g_gpout[i].gpio.gp_ops = &gpout_ops; g_gpout[i].id = i; - gpio_pin_register(&g_gpout[i].gpio, i); + gpio_pin_register(&g_gpout[i].gpio, pincount); /* Configure the pins that will be used as output */ @@ -344,6 +345,8 @@ int esp32_gpio_init(void) esp32_configgpio(g_gpiooutputs[i], OUTPUT_FUNCTION_3 | INPUT_FUNCTION_3); esp32_gpiowrite(g_gpiooutputs[i], 0); + + pincount++; } #endif @@ -355,11 +358,13 @@ int esp32_gpio_init(void) g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN; g_gpin[i].gpio.gp_ops = &gpin_ops; g_gpin[i].id = i; - gpio_pin_register(&g_gpin[i].gpio, i); + gpio_pin_register(&g_gpin[i].gpio, pincount); /* Configure the pins that will be used as INPUT */ esp32_configgpio(g_gpioinputs[i], INPUT_FUNCTION_3); + + pincount++; } #endif @@ -371,11 +376,13 @@ int esp32_gpio_init(void) g_gpint[i].esp32gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN; g_gpint[i].esp32gpio.gpio.gp_ops = &gpint_ops; g_gpint[i].esp32gpio.id = i; - gpio_pin_register(&g_gpint[i].esp32gpio.gpio, i); + gpio_pin_register(&g_gpint[i].esp32gpio.gpio, pincount); /* Configure the pins that will be used as interrupt input */ esp32_configgpio(g_gpiointinputs[i], INPUT_FUNCTION_3 | PULLDOWN); + + pincount++; } #endif diff --git a/boards/xtensa/esp32/ttgo_lora_esp32/src/esp32_gpio.c b/boards/xtensa/esp32/ttgo_lora_esp32/src/esp32_gpio.c index a1d3f03046..572de73fed 100644 --- a/boards/xtensa/esp32/ttgo_lora_esp32/src/esp32_gpio.c +++ b/boards/xtensa/esp32/ttgo_lora_esp32/src/esp32_gpio.c @@ -326,6 +326,7 @@ static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable) int esp32_gpio_init(void) { + int pincount = 0; int i; #if BOARD_NGPIOOUT > 0 @@ -336,7 +337,7 @@ int esp32_gpio_init(void) g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN; g_gpout[i].gpio.gp_ops = &gpout_ops; g_gpout[i].id = i; - gpio_pin_register(&g_gpout[i].gpio, i); + gpio_pin_register(&g_gpout[i].gpio, pincount); /* Configure the pins that will be used as output */ @@ -344,6 +345,8 @@ int esp32_gpio_init(void) esp32_configgpio(g_gpiooutputs[i], OUTPUT_FUNCTION_3 | INPUT_FUNCTION_3); esp32_gpiowrite(g_gpiooutputs[i], 0); + + pincount++; } #endif @@ -355,11 +358,13 @@ int esp32_gpio_init(void) g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN; g_gpin[i].gpio.gp_ops = &gpin_ops; g_gpin[i].id = i; - gpio_pin_register(&g_gpin[i].gpio, i); + gpio_pin_register(&g_gpin[i].gpio, pincount); /* Configure the pins that will be used as INPUT */ esp32_configgpio(g_gpioinputs[i], INPUT_FUNCTION_3); + + pincount++; } #endif @@ -371,11 +376,13 @@ int esp32_gpio_init(void) g_gpint[i].esp32gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN; g_gpint[i].esp32gpio.gpio.gp_ops = &gpint_ops; g_gpint[i].esp32gpio.id = i; - gpio_pin_register(&g_gpint[i].esp32gpio.gpio, i); + gpio_pin_register(&g_gpint[i].esp32gpio.gpio, pincount); /* Configure the pins that will be used as interrupt input */ esp32_configgpio(g_gpiointinputs[i], INPUT_FUNCTION_3 | PULLDOWN); + + pincount++; } #endif diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_gpio.c b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_gpio.c index 0017404196..69423f5ed2 100644 --- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_gpio.c +++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_gpio.c @@ -404,6 +404,8 @@ static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable) int esp32s2_gpio_init(void) { + int pincount = 0; + #if BOARD_NGPIOOUT > 0 for (int i = 0; i < BOARD_NGPIOOUT; i++) { @@ -412,7 +414,7 @@ int esp32s2_gpio_init(void) g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN; g_gpout[i].gpio.gp_ops = &gpout_ops; g_gpout[i].id = i; - gpio_pin_register(&g_gpout[i].gpio, i); + gpio_pin_register(&g_gpout[i].gpio, pincount); /* Configure the pins that will be used as output */ @@ -420,6 +422,8 @@ int esp32s2_gpio_init(void) esp32s2_configgpio(g_gpiooutputs[i], OUTPUT_FUNCTION_1 | INPUT_FUNCTION_1); esp32s2_gpiowrite(g_gpiooutputs[i], 0); + + pincount++; } #endif @@ -431,11 +435,13 @@ int esp32s2_gpio_init(void) g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN_PULLDOWN; g_gpin[i].gpio.gp_ops = &gpin_ops; g_gpin[i].id = i; - gpio_pin_register(&g_gpin[i].gpio, i); + gpio_pin_register(&g_gpin[i].gpio, pincount); /* Configure the pins that will be used as interrupt input */ esp32s2_configgpio(g_gpioinputs[i], INPUT_FUNCTION_1 | PULLDOWN); + + pincount++; } #endif @@ -447,11 +453,13 @@ int esp32s2_gpio_init(void) g_gpint[i].esp32s2gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN; g_gpint[i].esp32s2gpio.gpio.gp_ops = &gpint_ops; g_gpint[i].esp32s2gpio.id = i; - gpio_pin_register(&g_gpint[i].esp32s2gpio.gpio, i); + gpio_pin_register(&g_gpint[i].esp32s2gpio.gpio, pincount); /* Configure the pins that will be used as interrupt input */ esp32s2_configgpio(g_gpiointinputs[i], INPUT_FUNCTION_1 | PULLDOWN); + + pincount++; } #endif diff --git a/drivers/ioexpander/gpio.c b/drivers/ioexpander/gpio.c index 9f2d014c2b..f7252ad77e 100644 --- a/drivers/ioexpander/gpio.c +++ b/drivers/ioexpander/gpio.c @@ -315,6 +315,7 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) inode = filep->f_inode; DEBUGASSERT(inode->i_private != NULL); dev = inode->i_private; + DEBUGASSERT(dev->gp_ops != NULL); switch (cmd) { @@ -328,6 +329,7 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) dev->gp_pintype == GPIO_OUTPUT_PIN_OPENDRAIN) { DEBUGASSERT(arg == 0ul || arg == 1ul); + DEBUGASSERT(dev->gp_ops->go_write != NULL); ret = dev->gp_ops->go_write(dev, (bool)arg); } else @@ -347,6 +349,7 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) FAR bool *ptr = (FAR bool *)((uintptr_t)arg); DEBUGASSERT(ptr != NULL); + DEBUGASSERT(dev->gp_ops->go_read != NULL); ret = dev->gp_ops->go_read(dev, ptr); DEBUGASSERT(ret < 0 || *ptr == 0 || *ptr == 1); } @@ -402,12 +405,14 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { /* Register our handler */ + DEBUGASSERT(dev->gp_ops->go_attach != NULL); ret = dev->gp_ops->go_attach(dev, (pin_interrupt_t)gpio_handler); if (ret >= 0) { /* Enable pin interrupts */ + DEBUGASSERT(dev->gp_ops->go_enable != NULL); ret = dev->gp_ops->go_enable(dev, true); } } @@ -463,11 +468,13 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { /* Make sure that the pin interrupt is disabled */ + DEBUGASSERT(dev->gp_ops->go_enable != NULL); ret = dev->gp_ops->go_enable(dev, false); if (ret >= 0) { /* Detach the handler */ + DEBUGASSERT(dev->gp_ops->go_attach != NULL); ret = dev->gp_ops->go_attach(dev, NULL); } } @@ -489,7 +496,65 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) case GPIOC_SETPINTYPE: { - ret = dev->gp_ops->go_setpintype(dev, arg); + enum gpio_pintype_e pintype = (enum gpio_pintype_e)arg; + + /* Check if the argument is a valid pintype */ + + if (pintype < GPIO_INPUT_PIN || pintype >= GPIO_NPINTYPES) + { + ret = -EINVAL; + break; + } + + /* Check if the pintype actually needs to be changed */ + + if (dev->gp_pintype == pintype) + { + /* Pintype remains the same, no need to change anything */ + + ret = OK; + break; + } + + /* Disable interrupt if pin had an interrupt pintype previously */ + + if (dev->gp_pintype >= GPIO_INTERRUPT_PIN) + { + DEBUGASSERT(dev->gp_ops->go_enable != NULL); + ret = dev->gp_ops->go_enable(dev, false); + if (ret < 0) + { + break; + } + } + + /* Change pintype */ + + DEBUGASSERT(dev->gp_ops->go_setpintype != NULL); + ret = dev->gp_ops->go_setpintype(dev, pintype); + if (ret < 0) + { + break; + } + + /* Additional DEBUGASSERTs to make sure the right operations are + * available after the pintype has been changed. + */ + + DEBUGASSERT(dev->gp_pintype == pintype); + DEBUGASSERT(dev->gp_ops != NULL); + DEBUGASSERT(dev->gp_ops->go_read != NULL); + DEBUGASSERT(dev->gp_ops->go_setpintype != NULL); + + if (pintype >= GPIO_OUTPUT_PIN && pintype < GPIO_INTERRUPT_PIN) + { + DEBUGASSERT(dev->gp_ops->go_write != NULL); + } + else if (pintype >= GPIO_INTERRUPT_PIN) + { + DEBUGASSERT(dev->gp_ops->go_attach != NULL); + DEBUGASSERT(dev->gp_ops->go_enable != NULL); + } } break; @@ -511,19 +576,13 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) * Name: gpio_pin_register * * Description: - * Register 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. + * Register GPIO pin device driver at /dev/gpioN, where N is the provided + * minor number. * ****************************************************************************/ int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor) { - FAR const char *fmt; char devname[32]; int ret; @@ -536,7 +595,6 @@ int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor) case GPIO_INPUT_PIN_PULLDOWN: { DEBUGASSERT(dev->gp_ops->go_read != NULL); - fmt = "/dev/gpin%u"; } break; @@ -544,8 +602,7 @@ int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor) case GPIO_OUTPUT_PIN_OPENDRAIN: { DEBUGASSERT(dev->gp_ops->go_read != NULL && - dev->gp_ops->go_write != NULL); - fmt = "/dev/gpout%u"; + dev->gp_ops->go_write != NULL); } break; @@ -562,13 +619,11 @@ int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor) { return ret; } - - fmt = "/dev/gpint%u"; } break; } - snprintf(devname, 16, fmt, (unsigned int)minor); + snprintf(devname, sizeof(devname), "/dev/gpio%u", (unsigned int)minor); gpioinfo("Registering %s\n", devname); return register_driver(devname, &g_gpio_drvrops, 0666, dev); @@ -578,50 +633,19 @@ 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. - * + * Unregister GPIO pin device driver at /dev/gpioN, where N is the provided + * minor number. * ****************************************************************************/ -void gpio_pin_unregister(FAR struct gpio_dev_s *dev, int minor) +int gpio_pin_unregister(FAR struct gpio_dev_s *dev, int minor) { - FAR const char *fmt; - char devname[16]; + char devname[32]; - switch (dev->gp_pintype) - { - case GPIO_INPUT_PIN: - case GPIO_INPUT_PIN_PULLUP: - case GPIO_INPUT_PIN_PULLDOWN: - { - fmt = "/dev/gpin%u"; - } - break; - - case GPIO_OUTPUT_PIN: - case GPIO_OUTPUT_PIN_OPENDRAIN: - { - fmt = "/dev/gpout%u"; - } - break; - - default: - { - fmt = "/dev/gpint%u"; - } - break; - } - - snprintf(devname, sizeof(devname), fmt, (unsigned int)minor); + snprintf(devname, sizeof(devname), "/dev/gpio%u", (unsigned int)minor); gpioinfo("Unregistering %s\n", devname); - unregister_driver(devname); + return unregister_driver(devname); } #endif /* CONFIG_DEV_GPIO */ diff --git a/include/nuttx/ioexpander/gpio.h b/include/nuttx/ioexpander/gpio.h index 5fec524485..f51df4eae6 100644 --- a/include/nuttx/ioexpander/gpio.h +++ b/include/nuttx/ioexpander/gpio.h @@ -107,12 +107,12 @@ typedef CODE int (*pin_interrupt_t)(FAR struct gpio_dev_s *dev, uint8_t pin); /* Pin interface vtable definition. Instances of this vtable are read-only * and may reside in FLASH. * - * - go_read. Required for all all pin types. + * - go_read. Required for all pin types. * - go_write. Required only for the GPIO_OUTPUT_PIN pin type. Unused - * 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. + * for other pin types, may be NULL. + * - go_attach and gp_enable. Required only for the GPIO_INTERRUPT_PIN pin + * type. Unused for other pin types, may be NULL. + * - go_setpinytype. Required for all pin types. */ struct gpio_dev_s; @@ -177,14 +177,8 @@ extern "C" * Name: gpio_pin_register * * Description: - * Register 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. - * + * Register GPIO pin device driver at /dev/gpioN, where N is the provided + * minor number. * ****************************************************************************/ @@ -194,18 +188,12 @@ 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. - * + * Unregister GPIO pin device driver at /dev/gpioN, where N is the provided + * minor number. * ****************************************************************************/ -void gpio_pin_unregister(FAR struct gpio_dev_s *dev, int minor); +int gpio_pin_unregister(FAR struct gpio_dev_s *dev, int minor); /**************************************************************************** * Name: gpio_lower_half