diff --git a/Documentation/platforms/risc-v/esp32c3/index.rst b/Documentation/platforms/risc-v/esp32c3/index.rst index 95bb8b1a8ef2c..a6f2fb60d03eb 100644 --- a/Documentation/platforms/risc-v/esp32c3/index.rst +++ b/Documentation/platforms/risc-v/esp32c3/index.rst @@ -350,7 +350,7 @@ CAN/TWAI Yes DMA No DS No eFuse Yes Also virtual mode supported -GPIO Yes +GPIO Yes Dedicated GPIO supported HMAC No I2C Yes Master and Slave mode supported I2S Yes diff --git a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst index 6b01c4238c3e0..2a672ca23ac1e 100644 --- a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst +++ b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst @@ -183,6 +183,42 @@ We can use the interrupt pin to send a signal when the interrupt fires:: The pin is configured as a rising edge interrupt, so after issuing the above command, connect it to 3.3V. +To use dedicated gpio for controling multiple gpio pin at the same time +or having better response time, you need to enable +`CONFIG_ESPRESSIF_DEDICATED_GPIO` option. Dedicated GPIO is suitable +for faster response times required applications like simulate serial/parallel +interfaces in a bit-banging way. +After this option enabled GPIO4 and GPIO5 pins are ready to used as dedicated GPIO pins +as input/output mode. These pins are for example, you can use any pin up to 8 pins for +input and 8 pins for output for dedicated gpio. +To write and read data from dedicated gpio, you need to use +`GPIOC_BUNDLE_WR` and `GPIOC_BUNDLE_RD` commands. + +The following snippet demonstrates how to read/write to dedicated GPIO pins: + +.. code-block:: C + + int fd; = open("/dev/gpio3", O_RDWR); + int rd_val = 0; + struct gpio_bundle_wr_arg_s wr_arg; + + wr_arg.mask = 0xffff; + wr_arg.value = 0; + while(1) + { + ioctl(fd, GPIOC_BUNDLE_WR, &wr_arg); + if (toggle == 0) + { + wr_arg.value = 3; + } + else + { + wr_arg.value = 0; + } + ioctl(fd, GPIOC_BUNDLE_RD, &rd_val); + printf("rd_val: %d", rd_val); + } + i2c --- diff --git a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst index fd81264a27faf..317fef8bd4f3c 100644 --- a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst +++ b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst @@ -167,6 +167,42 @@ We can use the interrupt pin to send a signal when the interrupt fires:: The pin is configured as a rising edge interrupt, so after issuing the above command, connect it to 3.3V. +To use dedicated gpio for controling multiple gpio pin at the same time +or having better response time, you need to enable +`CONFIG_ESPRESSIF_DEDICATED_GPIO` option. Dedicated GPIO is suitable +for faster response times required applications like simulate serial/parallel +interfaces in a bit-banging way. +After this option enabled GPIO4 and GPIO5 pins are ready to used as dedicated GPIO pins +as input/output mode. These pins are for example, you can use any pin up to 8 pins for +input and 8 pins for output for dedicated gpio. +To write and read data from dedicated gpio, you need to use +`GPIOC_BUNDLE_WR` and `GPIOC_BUNDLE_RD` commands. + +The following snippet demonstrates how to read/write to dedicated GPIO pins: + +.. code-block:: C + + int fd; = open("/dev/gpio3", O_RDWR); + int rd_val = 0; + struct gpio_bundle_wr_arg_s wr_arg; + + wr_arg.mask = 0xffff; + wr_arg.value = 0; + while(1) + { + ioctl(fd, GPIOC_BUNDLE_WR, &wr_arg); + if (toggle == 0) + { + wr_arg.value = 3; + } + else + { + wr_arg.value = 0; + } + ioctl(fd, GPIOC_BUNDLE_RD, &rd_val); + printf("rd_val: %d", rd_val); + } + i2c --- diff --git a/Documentation/platforms/risc-v/esp32c6/index.rst b/Documentation/platforms/risc-v/esp32c6/index.rst index adea935252ef9..e29595d137cfa 100644 --- a/Documentation/platforms/risc-v/esp32c6/index.rst +++ b/Documentation/platforms/risc-v/esp32c6/index.rst @@ -338,7 +338,7 @@ CAN/TWAI Yes DMA Yes ECC No eFuse Yes -GPIO Yes +GPIO Yes Dedicated GPIO supported HMAC No I2C Yes Master and Slave mode supported I2S Yes diff --git a/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst b/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst index 2b2c2125ebc33..7fb4f4dc1a409 100644 --- a/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst +++ b/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst @@ -166,6 +166,42 @@ We can use the interrupt pin to send a signal when the interrupt fires:: The pin is configured as a rising edge interrupt, so after issuing the above command, connect it to 3.3V. +To use dedicated gpio for controling multiple gpio pin at the same time +or having better response time, you need to enable +`CONFIG_ESPRESSIF_DEDICATED_GPIO` option. Dedicated GPIO is suitable +for faster response times required applications like simulate serial/parallel +interfaces in a bit-banging way. +After this option enabled GPIO4 and GPIO5 pins are ready to used as dedicated GPIO pins +as input/output mode. These pins are for example, you can use any pin up to 8 pins for +input and 8 pins for output for dedicated gpio. +To write and read data from dedicated gpio, you need to use +`GPIOC_BUNDLE_WR` and `GPIOC_BUNDLE_RD` commands. + +The following snippet demonstrates how to read/write to dedicated GPIO pins: + +.. code-block:: C + + int fd; = open("/dev/gpio3", O_RDWR); + int rd_val = 0; + struct gpio_bundle_wr_arg_s wr_arg; + + wr_arg.mask = 0xffff; + wr_arg.value = 0; + while(1) + { + ioctl(fd, GPIOC_BUNDLE_WR, &wr_arg); + if (toggle == 0) + { + wr_arg.value = 3; + } + else + { + wr_arg.value = 0; + } + ioctl(fd, GPIOC_BUNDLE_RD, &rd_val); + printf("rd_val: %d", rd_val); + } + i2c --- diff --git a/Documentation/platforms/risc-v/esp32h2/index.rst b/Documentation/platforms/risc-v/esp32h2/index.rst index 06211a4897dd4..72b57bb4f593c 100644 --- a/Documentation/platforms/risc-v/esp32h2/index.rst +++ b/Documentation/platforms/risc-v/esp32h2/index.rst @@ -340,7 +340,7 @@ DMA Yes DS No ECC No eFuse Yes -GPIO Yes +GPIO Yes Dedicated GPIO supported HMAC No I2C Yes Master and Slave mode supported I2S Yes diff --git a/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-saola-1/index.rst b/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-saola-1/index.rst index 2929fc3e32982..d3caf8790ebd4 100644 --- a/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-saola-1/index.rst +++ b/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-saola-1/index.rst @@ -201,6 +201,36 @@ At the nsh, we can turn the GPIO output on and off with the following:: nsh> gpio -o 1 /dev/gpio0 nsh> gpio -o 0 /dev/gpio0 +To use dedicated gpio, you need to enable `CONFIG_ESPRESSIF_DEDICATED_GPIO` option. +After this option enabled GPIO6 and GPIO5 pins are ready to used as dedicated GPIO pins +as input/output mode. To write and read data from dedicated gpio, you need to use +`GPIOC_BUNDLE_WR` and `GPIOC_BUNDLE_RD` commands. + +The following snippet demonstrates how to read/write to dedicated GPIO pins: + +.. code-block:: C + + int fd; = open("/dev/gpio3", O_RDWR); + int rd_val = 0; + struct gpio_bundle_wr_arg_s wr_arg; + + wr_arg.mask = 0xffff; + wr_arg.value = 0; + while(1) + { + ioctl(fd, GPIOC_BUNDLE_WR, &wr_arg); + if (toggle == 0) + { + wr_arg.value = 3; + } + else + { + wr_arg.value = 0; + } + ioctl(fd, GPIOC_BUNDLE_RD, &rd_val); + printf("rd_val: %d", rd_val); + } + i2c --- diff --git a/Documentation/platforms/xtensa/esp32s2/index.rst b/Documentation/platforms/xtensa/esp32s2/index.rst index 542bee73186c8..1da97a9aea3af 100644 --- a/Documentation/platforms/xtensa/esp32s2/index.rst +++ b/Documentation/platforms/xtensa/esp32s2/index.rst @@ -382,7 +382,7 @@ CAN/TWAI Yes DAC No DMA Yes eFuse Yes -GPIO Yes +GPIO Yes Dedicated GPIO supported I2C Yes Master and Slave mode supported I2S Yes LED/PWM Yes diff --git a/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-devkit/index.rst b/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-devkit/index.rst index 0686955d36eef..f8e5516a95c88 100644 --- a/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-devkit/index.rst +++ b/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-devkit/index.rst @@ -234,6 +234,42 @@ interrupt fires:: The pin is configured to trigger an interrupt on the rising edge, so after issuing the above command, connect it to 3.3V. +To use dedicated gpio for controling multiple gpio pin at the same time +or having better response time, you need to enable +`CONFIG_ESPRESSIF_DEDICATED_GPIO` option. Dedicated GPIO is suitable +for faster response times required applications like simulate serial/parallel +interfaces in a bit-banging way. +After this option enabled GPIO4 and GPIO5 pins are ready to used as dedicated GPIO pins +as input/output mode. These pins are for example, you can use any pin up to 8 pins for +input and 8 pins for output for dedicated gpio. +To write and read data from dedicated gpio, you need to use +`GPIOC_BUNDLE_WR` and `GPIOC_BUNDLE_RD` commands. + +The following snippet demonstrates how to read/write to dedicated GPIO pins: + +.. code-block:: C + + int fd; = open("/dev/gpio3", O_RDWR); + int rd_val = 0; + struct gpio_bundle_wr_arg_s wr_arg; + + wr_arg.mask = 0xffff; + wr_arg.value = 0; + while(1) + { + ioctl(fd, GPIOC_BUNDLE_WR, &wr_arg); + if (toggle == 0) + { + wr_arg.value = 3; + } + else + { + wr_arg.value = 0; + } + ioctl(fd, GPIOC_BUNDLE_RD, &rd_val); + printf("rd_val: %d", rd_val); + } + i2c --- diff --git a/Documentation/platforms/xtensa/esp32s3/index.rst b/Documentation/platforms/xtensa/esp32s3/index.rst index 714d52f82082c..7521b9a717455 100644 --- a/Documentation/platforms/xtensa/esp32s3/index.rst +++ b/Documentation/platforms/xtensa/esp32s3/index.rst @@ -415,7 +415,7 @@ Camera No CAN/TWAI Yes DMA Yes eFuse Yes -GPIO Yes +GPIO Yes Dedicated GPIO supported I2C Yes Master and Slave mode supported I2S Yes LCD No diff --git a/arch/risc-v/src/common/espressif/Kconfig b/arch/risc-v/src/common/espressif/Kconfig index 45b94ece087cc..7e0ebce0e0a93 100644 --- a/arch/risc-v/src/common/espressif/Kconfig +++ b/arch/risc-v/src/common/espressif/Kconfig @@ -303,6 +303,12 @@ config ESPRESSIF_USBSERIAL select OTHER_UART_SERIALDRIVER select ARCH_HAVE_SERIAL_TERMIOS +config ESPRESSIF_DEDICATED_GPIO + bool "Dedicated GPIO" + default n + ---help--- + Enable dedicated GPIO support for faster response time + config ESPRESSIF_GPIO_IRQ bool "GPIO pin interrupts" default n diff --git a/arch/risc-v/src/common/espressif/Make.defs b/arch/risc-v/src/common/espressif/Make.defs index d4778c76a7761..7e5bd3c23a62e 100644 --- a/arch/risc-v/src/common/espressif/Make.defs +++ b/arch/risc-v/src/common/espressif/Make.defs @@ -103,6 +103,10 @@ ifeq ($(CONFIG_ESP_RMT),y) endif endif +ifeq ($(CONFIG_ESPRESSIF_DEDICATED_GPIO),y) + CHIP_CSRCS += esp_dedic_gpio.c +endif + ifeq ($(CONFIG_ESPRESSIF_TEMP),y) CHIP_CSRCS += esp_temperature_sensor.c endif diff --git a/arch/risc-v/src/common/espressif/esp_dedic_gpio.c b/arch/risc-v/src/common/espressif/esp_dedic_gpio.c new file mode 100644 index 0000000000000..9dc2601c16dd9 --- /dev/null +++ b/arch/risc-v/src/common/espressif/esp_dedic_gpio.c @@ -0,0 +1,428 @@ +/**************************************************************************** + * arch/risc-v/src/common/espressif/esp_dedic_gpio.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "riscv_internal.h" +#include "esp_dedic_gpio.h" +#include "esp_gpio.h" +#include "soc/dedic_gpio_periph.h" +#include "hal/dedic_gpio_cpu_ll.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct esp_dedic_gpio_common_priv_s +{ + int refs; /* Reference count */ + spinlock_t spinlock; /* Held while chip is selected for mutual exclusion */ + uint32_t out_occupied_mask; /* Mask of output channels */ + uint32_t in_occupied_mask; /* Mask of input channels */ +}; + +struct esp_dedic_gpio_bundle_priv_s +{ + struct gpio_dev_s gpio_dev; /* Externally visible part of the GPIO interface */ + uint32_t out_offset; /* Offset of output channels */ + uint32_t in_offset; /* Offset of input channels */ + uint32_t out_mask; /* Mask of output channels */ + uint32_t in_mask; /* Mask of input channels */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int esp_dedic_gpio_bundle_read(struct gpio_dev_s *dev, int *value); +static int esp_dedic_gpio_bundle_write(struct gpio_dev_s *dev, + struct gpio_bundle_wr_arg_s *value); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct gpio_operations_s dedic_gpio_ops = +{ + .go_bundle_read = esp_dedic_gpio_bundle_read, + .go_bundle_write = esp_dedic_gpio_bundle_write, + .go_read = NULL, + .go_write = NULL, + .go_attach = NULL, + .go_enable = NULL, + .go_setpintype = NULL, +}; + +static struct esp_dedic_gpio_common_priv_s dedic_gpio_common = +{ + .refs = 0, + .spinlock = SP_UNLOCKED, + .out_occupied_mask = 0, + .in_occupied_mask = 0, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_dedic_gpio_bundle_read + * + * Description: + * Read dedicated gpio bundle data. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * value - Pointer to the read data will be saved + * + * Returned Value: + * OK + * + ****************************************************************************/ + +static int esp_dedic_gpio_bundle_read(struct gpio_dev_s *dev, int *value) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t dedic_value = 0; + + DEBUGASSERT(priv != NULL && value != NULL); + + gpioinfo("Reading int pin...\n"); + + dedic_value = dedic_gpio_cpu_ll_read_in(); + *value = (dedic_value & priv->in_mask) >> (priv->in_offset); + + return OK; +} + +/**************************************************************************** + * Name: esp_dedic_gpio_bundle_write + * + * Description: + * Write data to the dedicated gpio bundle. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * value - A pointer to a gpio_bundle_wr_arg_s to set pins. + * + * Returned Value: + * OK + * + ****************************************************************************/ + +static int esp_dedic_gpio_bundle_write(struct gpio_dev_s *dev, + struct gpio_bundle_wr_arg_s *value) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t mask_value = 0; + uint32_t write_value = 0; + + DEBUGASSERT(priv != NULL); + gpioinfo("Writing %d with mask: %d\n", (int)value->value, value->mask); + + mask_value = priv->out_mask & (value->mask << priv->out_offset); + write_value = value->value << priv->out_offset; + + dedic_gpio_cpu_ll_write_mask(mask_value, write_value); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_dedic_gpio_write + * + * Description: + * Write data to the dedicated gpio bundle with given mask value. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * mask - Mask of the GPIOs to be written + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_write(struct gpio_dev_s *dev, + uint32_t mask, + uint32_t value) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t mask_value = priv->out_mask & (mask << priv->out_offset); + uint32_t write_value = value << priv->out_offset; + + dedic_gpio_cpu_ll_write_mask(mask_value, write_value); +} + +/**************************************************************************** + * Name: esp_dedic_gpio_read + * + * Description: + * Read dedicated gpio bundle data. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * value - Pointer to the read data will be saved + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_read(struct gpio_dev_s *dev, int *value) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + + *value = dedic_gpio_cpu_ll_read_in(); + *value = ((*value) & priv->in_mask) >> (priv->in_offset); +} + +/**************************************************************************** + * Name: esp_dedic_gpio_new_bundle + * + * Description: + * Request dedicated GPIO bundle and config it with given parameters. + * + * Input Parameters: + * config - Dedicated GPIO bundle configuration + * + * Returned Value: + * Valid GPIO device structure reference on success; NULL on failure. + * + ****************************************************************************/ + +struct gpio_dev_s *esp_dedic_gpio_new_bundle( + struct esp_dedic_gpio_config_s *config) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = NULL; + irqstate_t flags = 0; + uint32_t out_mask = 0; + uint32_t in_mask = 0; + uint32_t pattern = 0; + uint32_t out_offset = 0; + uint32_t in_offset = 0; + gpio_pinattr_t attr = 0; + + DEBUGASSERT(config != NULL); + DEBUGASSERT(config->gpio_array != NULL && config->array_size > 0); + DEBUGASSERT(config->flags->input_enable || + config->flags->output_enable > 0); + + if (dedic_gpio_common.refs == 0) + { + flags = spin_lock_irqsave(&dedic_gpio_common.spinlock); + + dedic_gpio_common.out_occupied_mask = + UINT32_MAX & ~((1 << SOC_DEDIC_GPIO_OUT_CHANNELS_NUM) - 1); + dedic_gpio_common.in_occupied_mask = + UINT32_MAX & ~((1 << SOC_DEDIC_GPIO_IN_CHANNELS_NUM) - 1); + + spin_unlock_irqrestore(&dedic_gpio_common.spinlock, flags); + } + + priv = kmm_zalloc(sizeof(struct esp_dedic_gpio_bundle_priv_s)); + if (priv) + { + pattern = (1 << config->array_size) - 1; + + /* configure outwards channels */ + + priv->gpio_dev.gp_pintype = GPIO_INPUT_PIN; + priv->gpio_dev.gp_ops = &dedic_gpio_ops; + + out_offset = 0; + if (config->flags->output_enable) + { + if (config->array_size > SOC_DEDIC_GPIO_OUT_CHANNELS_NUM) + { + gpioerr("ERROR: array size(%d) exceeds maximum supported out\ + channels(%d)\n", + config->array_size, SOC_DEDIC_GPIO_OUT_CHANNELS_NUM); + free(priv); + return NULL; + } + + flags = spin_lock_irqsave(&dedic_gpio_common.spinlock); + + for (int i = 0; + i <= SOC_DEDIC_GPIO_OUT_CHANNELS_NUM - config->array_size; + i++) + { + if ((dedic_gpio_common.out_occupied_mask & (pattern << i)) + == 0) + { + out_mask = pattern << i; + out_offset = i; + break; + } + } + + if (out_mask) + { + dedic_gpio_common.out_occupied_mask |= out_mask; + } + + spin_unlock_irqrestore(&dedic_gpio_common.spinlock, flags); + if (out_mask == 0) + { + gpioerr("ERROR: no free outward channels\n"); + free(priv); + return NULL; + } + + attr |= OUTPUT; + priv->gpio_dev.gp_pintype = GPIO_OUTPUT_PIN; + gpioinfo("New out bundle(%p), offset=%"PRIu32", mask(%"PRIx32")", + priv, priv->out_offset, priv->out_mask); + } + + if (config->flags->input_enable) + { + if (config->array_size > SOC_DEDIC_GPIO_IN_CHANNELS_NUM) + { + gpioerr("ERROR: array size(%d) exceeds maximum supported in\ + channels(%d)\n", + config->array_size, SOC_DEDIC_GPIO_IN_CHANNELS_NUM); + free(priv); + return NULL; + } + + flags = spin_lock_irqsave(&dedic_gpio_common.spinlock); + + for (int i = 0; + i <= SOC_DEDIC_GPIO_IN_CHANNELS_NUM - config->array_size; + i++) + { + if ((dedic_gpio_common.in_occupied_mask & (pattern << i)) == 0) + { + in_mask = pattern << i; + in_offset = i; + break; + } + } + + if (in_mask) + { + dedic_gpio_common.in_occupied_mask |= in_mask; + } + + spin_unlock_irqrestore(&dedic_gpio_common.spinlock, flags); + if (in_mask == 0) + { + gpioerr("ERROR: no free inward channels\n"); + free(priv); + return NULL; + } + + attr |= INPUT; + gpioinfo("New in bundle(%p), offset=%"PRIu32", mask(%"PRIx32")", + priv, priv->in_offset, priv->in_mask); + } + + /* Route dedicated GPIO channel signals to GPIO matrix */ + + for (int i = 0; i < config->array_size; i++) + { + esp_configgpio(config->gpio_array[i], attr); + if (config->flags->input_enable) + { + esp_gpio_matrix_in(config->gpio_array[i], + dedic_gpio_periph_signals.cores[0].in_sig_per_channel[in_offset + i], + config->flags->invert_input_enable); + } + + if (config->flags->output_enable) + { + esp_gpio_matrix_out(config->gpio_array[i], + dedic_gpio_periph_signals.cores[0].out_sig_per_channel[in_offset + i], + config->flags->invert_output_enable, 0); + } + } + + dedic_gpio_cpu_ll_enable_output(dedic_gpio_common.out_occupied_mask); + priv->out_mask = out_mask; + priv->in_mask = in_mask; + priv->out_offset = out_offset; + priv->in_offset = in_offset; + } + else + { + gpioerr("ERROR: memory allocation failed\n"); + return NULL; + } + + dedic_gpio_common.refs++; + return (struct gpio_dev_s *)priv; +} + +/**************************************************************************** + * Name: esp_dedic_gpio_del_bundle + * + * Description: + * Delete dedicated gpio bundle. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * + * Returned Value: + * OK + * + ****************************************************************************/ + +int esp_dedic_gpio_del_bundle(struct gpio_dev_s *dev) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + irqstate_t flags = spin_lock_irqsave(&dedic_gpio_common.spinlock); + + dedic_gpio_common.refs--; + + dedic_gpio_common.out_occupied_mask &= ~(priv->out_mask); + dedic_gpio_common.in_occupied_mask &= ~(priv->in_mask); + + free(priv); + priv = NULL; + spin_unlock_irqrestore(&dedic_gpio_common.spinlock, flags); + + return OK; +} diff --git a/arch/risc-v/src/common/espressif/esp_dedic_gpio.h b/arch/risc-v/src/common/espressif/esp_dedic_gpio.h new file mode 100644 index 0000000000000..74a2372d08d71 --- /dev/null +++ b/arch/risc-v/src/common/espressif/esp_dedic_gpio.h @@ -0,0 +1,153 @@ +/**************************************************************************** + * arch/risc-v/src/common/espressif/esp_dedic_gpio.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H +#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +struct esp_dedic_gpio_flags_s +{ + bool input_enable; + bool invert_input_enable; + bool output_enable; + bool invert_output_enable; +}; + +struct esp_dedic_gpio_config_s +{ + const int *gpio_array; /* Array of GPIO numbers */ + int array_size; /* Number of GPIOs in gpio_array */ + struct esp_dedic_gpio_flags_s *flags; /* Flags to control specific behaviour of GPIO bundle */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_dedic_gpio_write + * + * Description: + * Write data to the dedicated gpio bundle with given mask value. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * mask - Mask of the GPIOs to be written + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_write(struct gpio_dev_s *dev, + uint32_t mask, + uint32_t value); + +/**************************************************************************** + * Name: esp_dedic_gpio_read + * + * Description: + * Read dedicated gpio bundle data. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * value - Pointer to the read data will be saved + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_read(struct gpio_dev_s *dev, int *value); + +/**************************************************************************** + * Name: esp_dedic_gpio_new_bundle + * + * Description: + * Request dedicated GPIO bundle and config it with given parameters. + * + * Input Parameters: + * config - Dedicated GPIO bundle configuration + * + * Returned Value: + * Valid GPIO device structure reference on success; NULL on failure. + * + ****************************************************************************/ + +struct gpio_dev_s *esp_dedic_gpio_new_bundle( + struct esp_dedic_gpio_config_s *config); + +/**************************************************************************** + * Name: esp_dedic_gpio_del_bundle + * + * Description: + * Delete dedicated gpio bundle. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * + * Returned Value: + * OK on success; ERROR on failure + * + ****************************************************************************/ + +int esp_dedic_gpio_del_bundle(struct gpio_dev_s *dev); + +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H */ diff --git a/arch/risc-v/src/esp32c3/hal_esp32c3.mk b/arch/risc-v/src/esp32c3/hal_esp32c3.mk index d669703bd33fc..50f729f50f907 100644 --- a/arch/risc-v/src/esp32c3/hal_esp32c3.mk +++ b/arch/risc-v/src/esp32c3/hal_esp32c3.mk @@ -151,6 +151,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)riscv$(DELIM)interrupt.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)lldesc.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)dedic_gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gdma_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c diff --git a/arch/risc-v/src/esp32c6/hal_esp32c6.mk b/arch/risc-v/src/esp32c6/hal_esp32c6.mk index 712a15a5d37a3..c598bb2c07b5c 100644 --- a/arch/risc-v/src/esp32c6/hal_esp32c6.mk +++ b/arch/risc-v/src/esp32c6/hal_esp32c6.mk @@ -158,6 +158,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)riscv$(DELIM)interrupt.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)lldesc.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)dedic_gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gdma_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c diff --git a/arch/risc-v/src/esp32h2/hal_esp32h2.mk b/arch/risc-v/src/esp32h2/hal_esp32h2.mk index e7a393ec1c8b7..847b2496bcc4a 100644 --- a/arch/risc-v/src/esp32h2/hal_esp32h2.mk +++ b/arch/risc-v/src/esp32h2/hal_esp32h2.mk @@ -142,6 +142,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)riscv$(DELIM)interrupt.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)lldesc.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)dedic_gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gdma_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c diff --git a/arch/xtensa/src/common/espressif/Kconfig b/arch/xtensa/src/common/espressif/Kconfig index 13e3bce882553..4f611b8837b44 100644 --- a/arch/xtensa/src/common/espressif/Kconfig +++ b/arch/xtensa/src/common/espressif/Kconfig @@ -109,6 +109,20 @@ config ESPRESSIF_SPIFLASH depends on ARCH_CHIP_ESP32S2 default n +config ESPRESSIF_DEDICATED_GPIO + bool "Dedicated GPIO" + depends on !ARCH_CHIP_ESP32 + default n + ---help--- + Enable dedicated GPIO support for faster response time + +config ESPRESSIF_DEDICATED_GPIO_IRQ + bool "Dedicated GPIO IRQ" + depends on ESPRESSIF_DEDICATED_GPIO && ARCH_CHIP_ESP32S2 + default n + ---help--- + Enable dedicated GPIO IRQ support + menu "Pulse Counter (PCNT) Configuration" depends on ESP_PCNT diff --git a/arch/xtensa/src/common/espressif/Make.defs b/arch/xtensa/src/common/espressif/Make.defs index e59cee5e71e85..092958305d126 100644 --- a/arch/xtensa/src/common/espressif/Make.defs +++ b/arch/xtensa/src/common/espressif/Make.defs @@ -72,6 +72,10 @@ ifeq ($(CONFIG_ESPRESSIF_I2C_PERIPH_SLAVE_MODE),y) CHIP_CSRCS += esp_i2c_slave.c endif +ifeq ($(CONFIG_ESPRESSIF_DEDICATED_GPIO),y) +CHIP_CSRCS += esp_dedic_gpio.c +endif + ifeq ($(CONFIG_SYSTEM_NXDIAG_ESPRESSIF_CHIP_WO_TOOL),y) CHIP_CSRCS += esp_nxdiag.c endif diff --git a/arch/xtensa/src/common/espressif/esp_dedic_gpio.c b/arch/xtensa/src/common/espressif/esp_dedic_gpio.c new file mode 100644 index 0000000000000..e8c5c7a52efd4 --- /dev/null +++ b/arch/xtensa/src/common/espressif/esp_dedic_gpio.c @@ -0,0 +1,899 @@ +/**************************************************************************** + * arch/xtensa/src/common/espressif/esp_dedic_gpio.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chip.h" +#include "esp_dedic_gpio.h" +#if defined(CONFIG_ARCH_CHIP_ESP32S3) +#include "esp32s3_gpio.h" +#elif defined(CONFIG_ARCH_CHIP_ESP32S2) +#include "esp32s2_irq.h" +#include "esp32s2_gpio.h" +#endif + +#if defined(CONFIG_ARCH_CHIP_ESP32S2) +#include "soc/dedic_gpio_struct.h" +#include "hal/dedic_gpio_ll.h" +#endif +#include "soc/dedic_gpio_periph.h" +#include "hal/dedic_gpio_cpu_ll.h" +#include "soc/gpio_sig_map.h" +#include "periph_ctrl.h" +#include "soc/soc_caps.h" +#include "soc/gpio_pins.h" +#include "esp_clk.h" +#include "esp_attr.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_ARCH_CHIP_ESP32S3) +#define esp_configgpio esp32s3_configgpio +#define esp_gpio_matrix_in esp32s3_gpio_matrix_in +#define esp_gpio_matrix_out esp32s3_gpio_matrix_out +#define ESP_IRQ_PRIORITY_DEFAULT ESP32S3_INT_PRIO_DEF +#define ESP_IRQ_TRIGGER_LEVEL ESP32S3_CPUINT_LEVEL +#elif defined(CONFIG_ARCH_CHIP_ESP32S2) +#define esp_setup_irq esp32s2_setup_irq +#define esp_teardown_irq esp32s2_teardown_irq +#define esp_configgpio esp32s2_configgpio +#define esp_gpio_matrix_in esp32s2_gpio_matrix_in +#define esp_gpio_matrix_out esp32s2_gpio_matrix_out +#define ESP_IRQ_PRIORITY_DEFAULT ESP32S2_INT_PRIO_DEF +#define ESP_IRQ_TRIGGER_LEVEL ESP32S2_CPUINT_LEVEL +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ +enum esp_dedic_gpio_intr_type_t +{ + DEDIC_GPIO_INTR_NONE, /* No interrupt */ + DEDIC_GPIO_INTR_LOW_LEVEL = 2, /* Interrupt on low level */ + DEDIC_GPIO_INTR_HIGH_LEVEL, /* Interrupt on high level */ + DEDIC_GPIO_INTR_NEG_EDGE, /* Interrupt on negedge */ + DEDIC_GPIO_INTR_POS_EDGE, /* Interrupt on posedge */ + DEDIC_GPIO_INTR_BOTH_EDGE /* Interrupt on both negedge and posedge */ +}; +#endif + +struct esp_dedic_gpio_bundle_priv_s +{ + struct gpio_dev_s gpio_dev; /* Externally visible part of the GPIO interface */ + uint32_t out_offset; /* Offset of output channels */ + uint32_t in_offset; /* Offset of input channels */ + uint32_t out_mask; /* Mask of output channels */ + uint32_t in_mask; /* Mask of input channels */ +}; + +struct esp_dedic_gpio_common_priv_s +{ + int refs; /* Reference count */ + spinlock_t spinlock; /* Held while chip is selected for mutual exclusion */ + uint32_t out_occupied_mask; /* Mask of output channels */ + uint32_t in_occupied_mask; /* Mask of input channels */ +#ifdef CONFIG_ARCH_CHIP_ESP32S2 + dedic_dev_t *dev; +#endif +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ + bool isr_init; /* ISR register flag for peripheral */ + pin_interrupt_t cbs[SOC_DEDIC_GPIO_IN_CHANNELS_NUM]; + + /* Demonstrate that which bundle belongs to for input channel */ + + struct esp_dedic_gpio_bundle_priv_s * + in_bundles[SOC_DEDIC_GPIO_IN_CHANNELS_NUM]; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int esp_dedic_gpio_bundle_read(struct gpio_dev_s *dev, int *value); +static int esp_dedic_gpio_bundle_write(struct gpio_dev_s *dev, + struct gpio_bundle_wr_arg_s *value); +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ +static int esp_dedic_gpio_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback); +static int esp_dedic_gpio_int_enable(struct gpio_dev_s *dev, bool enable); +static int esp_dedic_gpio_setpintsetpintype(struct gpio_dev_s *dev, + enum gpio_pintype_e pintype); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct gpio_operations_s dedic_gpio_ops = +{ + .go_bundle_read = esp_dedic_gpio_bundle_read, + .go_bundle_write = esp_dedic_gpio_bundle_write, + .go_read = NULL, + .go_write = NULL, +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ + .go_attach = esp_dedic_gpio_attach, + .go_enable = esp_dedic_gpio_int_enable, + .go_setpintype = esp_dedic_gpio_setpintype, +#else + .go_attach = NULL, + .go_enable = NULL, + .go_setpintype = NULL, +#endif +}; + +static struct esp_dedic_gpio_common_priv_s + dedic_gpio_common[SOC_CPU_CORES_NUM] = +{ + 0 +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ + +/**************************************************************************** + * Name: esp_dedic_gpio_pin_get_pin_attr + * + * Description: + * Convert pin type to dedicated GPIO pin attr. + * + * Input Parameters: + * pintype - The pin type. See nuttx/ioexpander/gpio.h. + * + * Returned Value: + * Dedicated gpio driver pin attr if avaible, 0 otherwise. + * + ****************************************************************************/ + +static int esp_dedic_gpio_pin_get_pin_attr(enum gpio_pintype_e pintype) +{ + switch (pintype) + { + case GPIO_INTERRUPT_LOW_PIN: + return DEDIC_GPIO_INTR_LOW_LEVEL; + break; + case GPIO_INTERRUPT_HIGH_PIN: + return DEDIC_GPIO_INTR_HIGH_LEVEL; + break; + case GPIO_INTERRUPT_FALLING_PIN: + return DEDIC_GPIO_INTR_NEG_EDGE; + break; + case GPIO_INTERRUPT_RISING_PIN: + return DEDIC_GPIO_INTR_POS_EDGE; + break; + case GPIO_INTERRUPT_BOTH_PIN: + return DEDIC_GPIO_INTR_BOTH_EDGE; + break; + default: + return DEDIC_GPIO_INTR_NONE; + break; + } + + return DEDIC_GPIO_INTR_NONE; +} + +/**************************************************************************** + * Name: esp_pcnt_isr_default + * + * Description: + * Handler for the dedicated GPIO controller interrupt. + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info + * arg - PCNT controller private data + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +static int IRAM_ATTR esp_dedic_gpio_isr_default(int irq, void *context, + void *arg) +{ + struct esp_dedic_gpio_common_priv_s *platform = + (struct esp_dedic_gpio_common_priv_s *)arg; + uint32_t flags = spin_lock_irqsave(dedic_gpio_common->spinlock); + uint32_t status = dedic_gpio_ll_get_interrupt_status(platform->dev); + + dedic_gpio_ll_clear_interrupt_status(platform->dev, status); + spin_unlock_irqrestore(dedic_gpio_common->spinlock, flags); + + while (status) + { + uint32_t channel = __builtin_ffs(status) - 1; + if (platform->cbs[channel] != NULL) + { + platform->cbs[channel]((struct gpio_dev_s *) + platform->in_bundles[channel], + channel - + platform->in_bundles[channel]->in_offset); + } + + status = status & (status - 1); + } + + return 0; +} + +/**************************************************************************** + * Name: esp_pcnt_isr_register + * + * Description: + * This function registers an interrupt service routine (ISR) for the + * peripheral. It allocates a CPU interrupt, attaches the ISR to the + * interrupt, and returns the status of the operation. + * + * Input Parameters: + * None. + * + * Returned Value: + * Returns OK on successful registration of the ISR; a negated errno value + * is returned on any failure. + * + ****************************************************************************/ + +static int esp_dedic_gpio_isr_register(void) +{ + int cpuint; + int ret; + int cpu = this_cpu(); + uint32_t status; + + cpuint = esp_setup_irq(dedic_gpio_periph_signals.irq, + ESP_IRQ_PRIORITY_DEFAULT, + ESP_IRQ_TRIGGER_LEVEL); + if (cpuint < 0) + { + cperr("Failed to allocate a CPU interrupt.\n"); + return ERROR; + } + + ret = irq_attach(dedic_gpio_periph_signals.irq + XTENSA_IRQ_FIRSTPERIPH, + esp_dedic_gpio_isr_default, + &dedic_gpio_common[cpu]); + if (ret < 0) + { + cperr("Couldn't attach IRQ to handler.\n"); + esp_teardown_irq(dedic_gpio_periph_signals.irq, cpuint); + return ERROR; + } + + status = dedic_gpio_ll_get_interrupt_status(dedic_gpio_common[cpu].dev); + dedic_gpio_ll_clear_interrupt_status(dedic_gpio_common[cpu].dev, status); + up_enable_irq(dedic_gpio_periph_signals.irq + XTENSA_IRQ_FIRSTPERIPH); + return OK; +} + +/**************************************************************************** + * Name: esp_dedic_gpio_int_enable + * + * Description: + * Enable/Disable interrupt. + * + * Parameters: + * dev - A pointer to the gpio driver struct. + * enable - True to enable, false to disable. + * + * Returned Value: + * Zero (OK). + * + ****************************************************************************/ + +static int esp_dedic_gpio_int_enable(struct gpio_dev_s *dev, bool enable) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t channel_mask = priv->in_mask << priv->in_offset; + uint32_t channel = 0; + irqstate_t flags; + int cpu = this_cpu(); + uint32_t status = dedic_gpio_ll_get_interrupt_status( + dedic_gpio_common[cpu].dev); + + dedic_gpio_ll_clear_interrupt_status(dedic_gpio_common[cpu].dev, status); + while (channel_mask) + { + channel = __builtin_ffs(channel_mask) - 1; + flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock); + + dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev, + 1 << channel, + enable); + + spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags); + + channel_mask = channel_mask & (channel_mask - 1); + } + + return OK; +} + +/**************************************************************************** + * Name: esp_dedic_gpio_setpintype + * + * Description: + * Set int type to trigger. + * + * Parameters: + * dev - A pointer to the gpio driver struct. + * pintype - The pin type. See nuttx/ioexpander/gpio.h. + * + * Returned Value: + * Zero (OK) on success; -1 (ERROR) otherwise. + * + ****************************************************************************/ + +static int esp_dedic_gpio_setpintype(struct gpio_dev_s *dev, + enum gpio_pintype_e pintype) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t channel_mask = priv->in_mask << priv->in_offset; + uint32_t channel = 0; + irqstate_t flags; + int cpu = this_cpu(); + int pin_attr = esp_dedic_gpio_pin_get_pin_attr(pintype); + + while (channel_mask) + { + channel = __builtin_ffs(channel_mask) - 1; + flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock); + + dedic_gpio_ll_set_interrupt_type(dedic_gpio_common[cpu].dev, + channel, + pin_attr); + if (pin_attr != DEDIC_GPIO_INTR_NONE) + { + dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev, + 1 << channel, + true); + } + else + { + dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev, + 1 << channel, + false); + } + + spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags); + + channel_mask = channel_mask & (channel_mask - 1); + } + + return OK; +} + +/**************************************************************************** + * Name: esp_dedic_gpio_attach + * + * Description: + * Attach the ISR to IRQ and register the callback. But it still doesn't + * enable interrupt yet. + * + * Parameters: + * dev - A pointer to the gpio driver struct. + * callback - User callback function. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +static int esp_dedic_gpio_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t channel_mask = priv->in_mask << priv->in_offset; + int cpu = this_cpu(); + int ret; + int channel; + + gpioinfo("Attaching the callback\n"); + + if (dedic_gpio_common[cpu].isr_init == false) + { + ret = esp_dedic_gpio_isr_register(); + if (ret != OK) + { + gpioerr("Failed to initialize interrupt\n"); + return ERROR; + } + } + + gpioinfo("Attach %p\n", callback); + while (channel_mask) + { + channel = __builtin_ffs(channel_mask) - 1; + dedic_gpio_common[cpu].cbs[channel] = callback; + dedic_gpio_common[cpu].in_bundles[channel] = priv; + channel_mask = channel_mask & (channel_mask - 1); + } + + return OK; +} +#endif /* CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ */ + +/**************************************************************************** + * Name: esp_dedic_gpio_bundle_read + * + * Description: + * Read dedicated gpio bundle data. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * value - Pointer to the read data will be saved + * + * Returned Value: + * OK + * + ****************************************************************************/ + +static int esp_dedic_gpio_bundle_read(struct gpio_dev_s *dev, int *value) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t dedic_value = 0; + + DEBUGASSERT(priv != NULL && value != NULL); + + gpioinfo("Reading int pin...\n"); + + dedic_value = dedic_gpio_cpu_ll_read_in(); + *value = (dedic_value & priv->in_mask) >> (priv->in_offset); + + return OK; +} + +/**************************************************************************** + * Name: esp_dedic_gpio_bundle_write + * + * Description: + * Write data to the dedicated gpio bundle. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * value - A pointer to a gpio_bundle_wr_arg_s to set pins. + * + * Returned Value: + * OK + * + ****************************************************************************/ + +static int esp_dedic_gpio_bundle_write(struct gpio_dev_s *dev, + struct gpio_bundle_wr_arg_s *value) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t mask_value = 0; + uint32_t write_value = 0; + + DEBUGASSERT(priv != NULL); + gpioinfo("Writing %d with mask: %d\n", (int)value->value, value->mask); + + mask_value = priv->out_mask & (value->mask << priv->out_offset); + write_value = value->value << priv->out_offset; + + dedic_gpio_cpu_ll_write_mask(mask_value, write_value); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ +/**************************************************************************** + * Name: esp_dedic_gpio_set_cb + * + * Description: + * Set event callbacks + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * mask - Mask of the GPIOs to assign callback + * pintype - Type of interrupt to trigger + * callback - Pointer to the ISR function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_set_cb(struct gpio_dev_s *dev, + uint32_t mask, + enum gpio_pintype_e pintype, + pin_interrupt_t callback) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t channel_mask = priv->in_mask & (mask << priv->in_offset); + uint32_t channel = 0; + irqstate_t flags; + int cpu = this_cpu(); + int pin_attr = esp_dedic_gpio_pin_get_pin_attr(pintype); + + while (channel_mask) + { + channel = __builtin_ffs(channel_mask) - 1; + flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock); + + dedic_gpio_ll_set_interrupt_type(dedic_gpio_common[cpu].dev, + channel, + pin_attr); + if (pin_attr != DEDIC_GPIO_INTR_NONE) + { + dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev, + 1 << channel, + true); + } + else + { + dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev, + 1 << channel, + false); + } + + spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags); + + dedic_gpio_common[cpu].cbs[channel] = callback; + dedic_gpio_common[cpu].in_bundles[channel] = priv; + channel_mask = channel_mask & (channel_mask - 1); + } +} +#endif + +/**************************************************************************** + * Name: esp_dedic_gpio_write + * + * Description: + * Write data to the dedicated gpio bundle with given mask value. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * mask - Mask of the GPIOs to be written + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_write(struct gpio_dev_s *dev, + uint32_t mask, + uint32_t value) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + uint32_t mask_value = priv->out_mask & (mask << priv->out_offset); + uint32_t write_value = value << priv->out_offset; + + dedic_gpio_cpu_ll_write_mask(mask_value, write_value); +} + +/**************************************************************************** + * Name: esp_dedic_gpio_read + * + * Description: + * Read dedicated gpio bundle data. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * value - Pointer to the read data will be saved + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_read(struct gpio_dev_s *dev, int *value) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + + *value = dedic_gpio_cpu_ll_read_in(); + *value = ((*value) & priv->in_mask) >> (priv->in_offset); +} + +/**************************************************************************** + * Name: esp_dedic_gpio_new_bundle + * + * Description: + * Request dedicated GPIO bundle and config it with given parameters. + * + * Input Parameters: + * config - Dedicated GPIO bundle configuration + * + * Returned Value: + * Valid GPIO device structure reference on success; NULL on failure. + * + ****************************************************************************/ + +struct gpio_dev_s *esp_dedic_gpio_new_bundle( + struct esp_dedic_gpio_config_s *config) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = NULL; + irqstate_t flags = 0; + uint32_t out_mask = 0; + uint32_t in_mask = 0; + uint32_t pattern = 0; + uint32_t out_offset = 0; + uint32_t in_offset = 0; + gpio_pinattr_t attr = 0; + int cpu = this_cpu(); +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ + int ret; +#endif + + DEBUGASSERT(config != NULL); + DEBUGASSERT(config->gpio_array != NULL && config->array_size > 0); + DEBUGASSERT(config->flags->input_enable || + config->flags->output_enable > 0); + + if (dedic_gpio_common[cpu].refs == 0) + { + flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock); + +#ifdef CONFIG_ARCH_CHIP_ESP32S2 + dedic_gpio_common[cpu].dev = &DEDIC_GPIO; +#endif + periph_module_enable(dedic_gpio_periph_signals.module); + dedic_gpio_common[cpu].out_occupied_mask = + UINT32_MAX & ~((1 << SOC_DEDIC_GPIO_OUT_CHANNELS_NUM) - 1); + dedic_gpio_common[cpu].in_occupied_mask = + UINT32_MAX & ~((1 << SOC_DEDIC_GPIO_IN_CHANNELS_NUM) - 1); + + spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags); + } + + priv = kmm_zalloc(sizeof(struct esp_dedic_gpio_bundle_priv_s)); + if (priv) + { + pattern = (1 << config->array_size) - 1; + + /* configure outwards channels */ + + priv->gpio_dev.gp_pintype = GPIO_INPUT_PIN; + priv->gpio_dev.gp_ops = &dedic_gpio_ops; + + out_offset = 0; + if (config->flags->output_enable) + { + if (config->array_size > SOC_DEDIC_GPIO_OUT_CHANNELS_NUM) + { + gpioerr("ERROR: array size(%d) exceeds maximum supported out\ + channels(%d)\n", + config->array_size, SOC_DEDIC_GPIO_OUT_CHANNELS_NUM); + free(priv); + return NULL; + } + + flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock); + + for (int i = 0; + i <= SOC_DEDIC_GPIO_OUT_CHANNELS_NUM - config->array_size; + i++) + { + if ((dedic_gpio_common[cpu].out_occupied_mask & (pattern << i)) + == 0) + { + out_mask = pattern << i; + out_offset = i; + break; + } + } + + if (out_mask) + { + dedic_gpio_common[cpu].out_occupied_mask |= out_mask; + } + + spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags); + if (out_mask == 0) + { + gpioerr("ERROR: no free outward channels\n"); + free(priv); + return NULL; + } + + attr |= OUTPUT; + priv->gpio_dev.gp_pintype = GPIO_OUTPUT_PIN; + +#ifdef CONFIG_ARCH_CHIP_ESP32S2 + dedic_gpio_ll_enable_instruction_access_out( + dedic_gpio_common[cpu].dev, + out_mask, + true); +#endif + gpioinfo("New out bundle(%p), offset=%"PRIu32", mask(%"PRIx32")", + priv, priv->out_offset, priv->out_mask); + } + + if (config->flags->input_enable) + { + if (config->array_size > SOC_DEDIC_GPIO_IN_CHANNELS_NUM) + { + gpioerr("ERROR: array size(%d) exceeds maximum supported in\ + channels(%d)\n", + config->array_size, SOC_DEDIC_GPIO_IN_CHANNELS_NUM); + free(priv); + return NULL; + } + + flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock); + + for (int i = 0; + i <= SOC_DEDIC_GPIO_IN_CHANNELS_NUM - config->array_size; + i++) + { + if ((dedic_gpio_common[cpu].in_occupied_mask & + (pattern << i)) == 0) + { + in_mask = pattern << i; + in_offset = i; + break; + } + } + + if (in_mask) + { + dedic_gpio_common[cpu].in_occupied_mask |= in_mask; + } + + spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags); + if (in_mask == 0) + { + gpioerr("ERROR: no free inward channels\n"); + free(priv); + return NULL; + } + + attr |= INPUT; + gpioinfo("New in bundle(%p), offset=%"PRIu32", mask(%"PRIx32")", + priv, priv->in_offset, priv->in_mask); + } + + /* Route dedicated GPIO channel signals to GPIO matrix */ + + for (int i = 0; i < config->array_size; i++) + { + esp_configgpio(config->gpio_array[i], attr); + if (config->flags->input_enable) + { + esp_gpio_matrix_in(config->gpio_array[i], + dedic_gpio_periph_signals.cores[cpu].in_sig_per_channel[in_offset + i], + config->flags->invert_input_enable); + } + + if (config->flags->output_enable) + { + esp_gpio_matrix_out(config->gpio_array[i], + dedic_gpio_periph_signals.cores[cpu].out_sig_per_channel[in_offset + i], + config->flags->invert_output_enable, 0); + } + } + + priv->out_mask = out_mask; + priv->in_mask = in_mask; + priv->out_offset = out_offset; + priv->in_offset = in_offset; + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ + if (config->flags->input_enable && + config->flags->intr_enable && + dedic_gpio_common[cpu].isr_init == false) + { + ret = esp_dedic_gpio_isr_register(); + if (ret != OK) + { + gpioerr("Failed to initialize interrupt\n"); + free(priv); + return NULL; + } + } +#endif + } + else + { + gpioerr("ERROR: memory allocation failed\n"); + return NULL; + } + + dedic_gpio_common[cpu].refs++; + return (struct gpio_dev_s *)priv; +} + +/**************************************************************************** + * Name: esp_dedic_gpio_del_bundle + * + * Description: + * Delete dedicated gpio bundle. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * + * Returned Value: + * OK + * + ****************************************************************************/ + +int esp_dedic_gpio_del_bundle(struct gpio_dev_s *dev) +{ + struct esp_dedic_gpio_bundle_priv_s *priv = + (struct esp_dedic_gpio_bundle_priv_s *)dev; + int cpu = this_cpu(); + irqstate_t flags = spin_lock_irqsave(&dedic_gpio_common[cpu].spinlock); + + dedic_gpio_common[cpu].refs--; + + dedic_gpio_common[cpu].out_occupied_mask &= ~(priv->out_mask); + dedic_gpio_common[cpu].in_occupied_mask &= ~(priv->in_mask); + + if (dedic_gpio_common[cpu].refs == 0) + { + periph_module_disable(dedic_gpio_periph_signals.module); +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ + dedic_gpio_ll_enable_interrupt(dedic_gpio_common[cpu].dev, + ~0UL, + false); + up_disable_irq(dedic_gpio_periph_signals.irq + XTENSA_IRQ_FIRSTPERIPH); + dedic_gpio_common[cpu].isr_init = false; +#endif + } + + free(priv); + priv = NULL; + spin_unlock_irqrestore(&dedic_gpio_common[cpu].spinlock, flags); + + return OK; +} diff --git a/arch/xtensa/src/common/espressif/esp_dedic_gpio.h b/arch/xtensa/src/common/espressif/esp_dedic_gpio.h new file mode 100644 index 0000000000000..8cb93c9a67177 --- /dev/null +++ b/arch/xtensa/src/common/espressif/esp_dedic_gpio.h @@ -0,0 +1,181 @@ +/**************************************************************************** + * arch/xtensa/src/common/espressif/esp_dedic_gpio.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H +#define __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +struct esp_dedic_gpio_flags_s +{ + bool input_enable; + bool invert_input_enable; + bool output_enable; + bool invert_output_enable; +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ + bool intr_enable; +#endif +}; + +struct esp_dedic_gpio_config_s +{ + const int *gpio_array; /* Array of GPIO numbers */ + int array_size; /* Number of GPIOs in gpio_array */ + struct esp_dedic_gpio_flags_s *flags; /* Flags to control specific behaviour of GPIO bundle */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO_IRQ +/**************************************************************************** + * Name: esp_dedic_gpio_set_cb + * + * Description: + * Set event callbacks + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * mask - Mask of the GPIOs to assign callback + * pintype - Type of interrupt to trigger + * callback - Pointer to the ISR function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_set_cb(struct gpio_dev_s *dev, + uint32_t mask, + enum gpio_pintype_e pintype, + pin_interrupt_t callback); +#endif + +/**************************************************************************** + * Name: esp_dedic_gpio_write + * + * Description: + * Write data to the dedicated gpio bundle with given mask value. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * mask - Mask of the GPIOs to be written + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_write(struct gpio_dev_s *dev, + uint32_t mask, + uint32_t value); + +/**************************************************************************** + * Name: esp_dedic_gpio_read + * + * Description: + * Read dedicated gpio bundle data. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * value - Pointer to the read data will be saved + * + * Returned Value: + * None + * + ****************************************************************************/ + +void esp_dedic_gpio_read(struct gpio_dev_s *dev, int *value); + +/**************************************************************************** + * Name: esp_dedic_gpio_new_bundle + * + * Description: + * Request dedicated GPIO bundle and config it with given parameters. + * + * Input Parameters: + * config - Dedicated GPIO bundle configuration + * + * Returned Value: + * Valid GPIO device structure reference on success; NULL on failure. + * + ****************************************************************************/ + +struct gpio_dev_s *esp_dedic_gpio_new_bundle( + struct esp_dedic_gpio_config_s *config); + +/**************************************************************************** + * Name: esp_dedic_gpio_del_bundle + * + * Description: + * Delete dedicated gpio bundle. + * + * Input Parameters: + * dev - Pointer to the dedicated gpio driver struct + * + * Returned Value: + * OK on success; ERROR on failure + * + ****************************************************************************/ + +int esp_dedic_gpio_del_bundle(struct gpio_dev_s *dev); + +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_DEDIC_GPIO_H */ diff --git a/arch/xtensa/src/esp32s2/hal.mk b/arch/xtensa/src/esp32s2/hal.mk index 4d0f4524e1436..7de15e4f00a95 100644 --- a/arch/xtensa/src/esp32s2/hal.mk +++ b/arch/xtensa/src/esp32s2/hal.mk @@ -114,6 +114,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)dedic_gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)pcnt_periph.c diff --git a/arch/xtensa/src/esp32s3/Make.defs b/arch/xtensa/src/esp32s3/Make.defs index c85279e25c72d..1fb666f907bf0 100644 --- a/arch/xtensa/src/esp32s3/Make.defs +++ b/arch/xtensa/src/esp32s3/Make.defs @@ -221,7 +221,7 @@ endif ESP_HAL_3RDPARTY_REPO = esp-hal-3rdparty ifndef ESP_HAL_3RDPARTY_VERSION - ESP_HAL_3RDPARTY_VERSION = 0b15e1a642d7005ad11c3c0394c784959f478f5f + ESP_HAL_3RDPARTY_VERSION = 65d20bfeed8dc22ff6eb096cea4486f925b92f1e endif ifndef ESP_HAL_3RDPARTY_URL diff --git a/arch/xtensa/src/esp32s3/hal.mk b/arch/xtensa/src/esp32s3/hal.mk index 9d7642a9893d0..500231d750a18 100644 --- a/arch/xtensa/src/esp32s3/hal.mk +++ b/arch/xtensa/src/esp32s3/hal.mk @@ -127,6 +127,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)dedic_gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gdma_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c diff --git a/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_gpio.c b/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_gpio.c index c751699193c18..19966d853caaa 100644 --- a/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_gpio.c +++ b/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_gpio.c @@ -44,6 +44,9 @@ /* Arch */ #include "espressif/esp_gpio.h" +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +#include "espressif/esp_dedic_gpio.h" +#endif /* Board */ @@ -75,6 +78,14 @@ #define GPIO_IRQPIN 9 +/* Dedicated GPIO pins. GPIO4 and GPIO5 is used as an example, any other + * GPIOs could be used. + */ + +#define GPIO_DEDIC1 4 +#define GPIO_DEDIC2 5 +#define GPIO_DEDIC_COUNT 2 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -155,6 +166,32 @@ static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] = static struct espgpint_dev_s g_gpint[BOARD_NGPIOINT]; #endif +/* This array maps the GPIO pins used as Dedicated GPIO */ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +static const int g_gpioidedic[GPIO_DEDIC_COUNT] = +{ + GPIO_DEDIC1, GPIO_DEDIC2 +}; + +static struct esp_dedic_gpio_flags_s dedic_gpio_flags = +{ + .input_enable = 1, + .invert_input_enable = 0, + .output_enable = 1, + .invert_output_enable = 0 +}; + +struct esp_dedic_gpio_config_s dedic_gpio_conf = +{ + .gpio_array = g_gpioidedic, + .array_size = GPIO_DEDIC_COUNT, + .flags = &dedic_gpio_flags +}; + +struct gpio_dev_s *dedicated_gpio = NULL; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -509,6 +546,13 @@ int esp_gpio_init(void) } #endif +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO + dedicated_gpio = esp_dedic_gpio_new_bundle(&dedic_gpio_conf); + + gpio_pin_register(dedicated_gpio, pincount); + pincount++; +#endif + return OK; } #endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */ diff --git a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_gpio.c b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_gpio.c index c88a2217b53c9..0e66193ae65fb 100644 --- a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_gpio.c +++ b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_gpio.c @@ -44,6 +44,9 @@ /* Arch */ #include "espressif/esp_gpio.h" +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +#include "espressif/esp_dedic_gpio.h" +#endif /* Board */ @@ -75,6 +78,14 @@ #define GPIO_IRQPIN 9 +/* Dedicated GPIO pins. GPIO4 and GPIO5 is used as an example, any other + * GPIOs could be used. + */ + +#define GPIO_DEDIC1 4 +#define GPIO_DEDIC2 5 +#define GPIO_DEDIC_COUNT 2 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -155,6 +166,32 @@ static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] = static struct espgpint_dev_s g_gpint[BOARD_NGPIOINT]; #endif +/* This array maps the GPIO pins used as Dedicated GPIO */ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +static const int g_gpioidedic[GPIO_DEDIC_COUNT] = +{ + GPIO_DEDIC1, GPIO_DEDIC2 +}; + +static struct esp_dedic_gpio_flags_s dedic_gpio_flags = +{ + .input_enable = 1, + .invert_input_enable = 0, + .output_enable = 1, + .invert_output_enable = 0 +}; + +struct esp_dedic_gpio_config_s dedic_gpio_conf = +{ + .gpio_array = g_gpioidedic, + .array_size = GPIO_DEDIC_COUNT, + .flags = &dedic_gpio_flags +}; + +struct gpio_dev_s *dedicated_gpio = NULL; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -509,6 +546,13 @@ int esp_gpio_init(void) } #endif +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO + dedicated_gpio = esp_dedic_gpio_new_bundle(&dedic_gpio_conf); + + gpio_pin_register(dedicated_gpio, pincount); + pincount++; +#endif + return OK; } #endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */ diff --git a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_gpio.c b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_gpio.c index bd1ae75d01847..d2530096c6d11 100644 --- a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_gpio.c +++ b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_gpio.c @@ -44,6 +44,9 @@ /* Arch */ #include "espressif/esp_gpio.h" +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +#include "espressif/esp_dedic_gpio.h" +#endif /* Board */ @@ -75,6 +78,14 @@ #define GPIO_IRQPIN 9 +/* Dedicated GPIO pins. GPIO4 and GPIO5 is used as an example, any other + * GPIOs could be used. + */ + +#define GPIO_DEDIC1 4 +#define GPIO_DEDIC2 5 +#define GPIO_DEDIC_COUNT 2 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -155,6 +166,32 @@ static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] = static struct espgpint_dev_s g_gpint[BOARD_NGPIOINT]; #endif +/* This array maps the GPIO pins used as Dedicated GPIO */ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +static const int g_gpioidedic[GPIO_DEDIC_COUNT] = +{ + GPIO_DEDIC1, GPIO_DEDIC2 +}; + +static struct esp_dedic_gpio_flags_s dedic_gpio_flags = +{ + .input_enable = 1, + .invert_input_enable = 0, + .output_enable = 1, + .invert_output_enable = 0 +}; + +struct esp_dedic_gpio_config_s dedic_gpio_conf = +{ + .gpio_array = g_gpioidedic, + .array_size = GPIO_DEDIC_COUNT, + .flags = &dedic_gpio_flags +}; + +struct gpio_dev_s *dedicated_gpio = NULL; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -509,6 +546,13 @@ int esp_gpio_init(void) } #endif +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO + dedicated_gpio = esp_dedic_gpio_new_bundle(&dedic_gpio_conf); + + gpio_pin_register(dedicated_gpio, pincount); + pincount++; +#endif + return OK; } #endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */ 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 5278cd0cbf16f..f4b666dc163be 100644 --- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_gpio.c +++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_gpio.c @@ -42,6 +42,10 @@ #include "esp32s2_gpio.h" #include "hardware/esp32s2_gpio_sigmap.h" +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +#include "espressif/esp_dedic_gpio.h" +#endif + #if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF) /**************************************************************************** @@ -64,6 +68,14 @@ #define GPIO_IRQPIN 9 +/* Dedicated GPIO pins. GPIO4 and GPIO5 is used as an example, any other + * GPIOs could be used. + */ + +#define GPIO_DEDIC1 6 +#define GPIO_DEDIC2 5 +#define GPIO_DEDIC_COUNT 2 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -161,6 +173,32 @@ static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] = static struct esp32s2gpint_dev_s g_gpint[BOARD_NGPIOINT]; #endif +/* This array maps the GPIO pins used as Dedicated GPIO */ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +static const int g_gpioidedic[GPIO_DEDIC_COUNT] = +{ + GPIO_DEDIC1, GPIO_DEDIC2 +}; + +static struct esp_dedic_gpio_flags_s dedic_gpio_flags = +{ + .input_enable = 1, + .invert_input_enable = 0, + .output_enable = 1, + .invert_output_enable = 0 +}; + +struct esp_dedic_gpio_config_s dedic_gpio_conf = +{ + .gpio_array = g_gpioidedic, + .array_size = GPIO_DEDIC_COUNT, + .flags = &dedic_gpio_flags +}; + +struct gpio_dev_s *dedicated_gpio = NULL; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -465,6 +503,13 @@ int esp32s2_gpio_init(void) } #endif +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO + dedicated_gpio = esp_dedic_gpio_new_bundle(&dedic_gpio_conf); + + gpio_pin_register(dedicated_gpio, pincount); + pincount++; +#endif + return OK; } #endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */ diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_gpio.c b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_gpio.c index 33c3c8cd12e4c..1b1ba481970fc 100644 --- a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_gpio.c +++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_gpio.c @@ -40,6 +40,10 @@ #include "esp32s3_gpio.h" #include "hardware/esp32s3_gpio_sigmap.h" +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +#include "espressif/esp_dedic_gpio.h" +#endif + #if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF) /**************************************************************************** @@ -68,6 +72,14 @@ #define GPIO_IRQPIN1 21 +/* Dedicated GPIO pins. GPIO4 and GPIO5 is used as an example, any other + * GPIOs could be used. + */ + +#define GPIO_DEDIC1 4 +#define GPIO_DEDIC2 5 +#define GPIO_DEDIC_COUNT 2 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -165,6 +177,32 @@ static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] = static struct esp32s3gpint_dev_s g_gpint[BOARD_NGPIOINT]; #endif +/* This array maps the GPIO pins used as Dedicated GPIO */ + +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO +static const int g_gpioidedic[GPIO_DEDIC_COUNT] = +{ + GPIO_DEDIC1, GPIO_DEDIC2 +}; + +static struct esp_dedic_gpio_flags_s dedic_gpio_flags = +{ + .input_enable = 1, + .invert_input_enable = 0, + .output_enable = 1, + .invert_output_enable = 0 +}; + +struct esp_dedic_gpio_config_s dedic_gpio_conf = +{ + .gpio_array = g_gpioidedic, + .array_size = GPIO_DEDIC_COUNT, + .flags = &dedic_gpio_flags +}; + +struct gpio_dev_s *dedicated_gpio = NULL; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -385,6 +423,13 @@ int esp32s3_gpio_init(void) } #endif +#ifdef CONFIG_ESPRESSIF_DEDICATED_GPIO + dedicated_gpio = esp_dedic_gpio_new_bundle(&dedic_gpio_conf); + + gpio_pin_register(dedicated_gpio, pincount); + pincount++; +#endif + return OK; } #endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */ diff --git a/drivers/ioexpander/gpio.c b/drivers/ioexpander/gpio.c index 1549d7d4817ed..c523f976be661 100644 --- a/drivers/ioexpander/gpio.c +++ b/drivers/ioexpander/gpio.c @@ -576,6 +576,50 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + /* Command: GPIOC_BUNDLE_WR + * Description: Set the value of a bundle (a set of) output GPIO. + * This call can be used to read more than one GPIO + * at the same time which is not possible on `GPIOC_READ` + * command. + * Argument: A pointer to a gpio_bundle_wr_arg_s to set pins. + */ + + case GPIOC_BUNDLE_WR: + if (dev->gp_pintype == GPIO_OUTPUT_PIN || + dev->gp_pintype == GPIO_OUTPUT_PIN_OPENDRAIN) + { + FAR struct gpio_bundle_wr_arg_s *ptr = + (FAR struct gpio_bundle_wr_arg_s *)((uintptr_t)arg); + DEBUGASSERT(ptr != NULL); + DEBUGASSERT(dev->gp_ops->go_bundle_write != NULL); + ret = dev->gp_ops->go_bundle_write(dev, ptr); + } + else + { + ret = -EACCES; + } + break; + + /* Command: GPIOC_BUNDLE_RD + * Description: Read the value of a bundle (a set of) input GPIO. + * This call can be used to read more than one GPIO + * at the same time which is not possible on `GPIOC_READ` + * command. + * Argument: A pointer to a int value to receive the result. + */ + + case GPIOC_BUNDLE_RD: + { + FAR int *ptr = (FAR int *)((uintptr_t)arg); + DEBUGASSERT(ptr != NULL); + + filep->f_priv = (FAR void *)dev->int_count; + + DEBUGASSERT(dev->gp_ops->go_bundle_read != NULL); + ret = dev->gp_ops->go_bundle_read(dev, ptr); + } + break; + /* Unrecognized command */ default: @@ -730,15 +774,18 @@ int gpio_pin_register_byname(FAR struct gpio_dev_s *dev, case GPIO_INPUT_PIN_PULLUP: case GPIO_INPUT_PIN_PULLDOWN: { - DEBUGASSERT(dev->gp_ops->go_read != NULL); + DEBUGASSERT(dev->gp_ops->go_read != NULL || + dev->gp_ops->go_bundle_read != NULL); } break; case GPIO_OUTPUT_PIN: case GPIO_OUTPUT_PIN_OPENDRAIN: { - DEBUGASSERT(dev->gp_ops->go_read != NULL && - dev->gp_ops->go_write != NULL); + DEBUGASSERT((dev->gp_ops->go_read != NULL && + dev->gp_ops->go_write != NULL) || + (dev->gp_ops->go_bundle_read != NULL && + dev->gp_ops->go_bundle_write != NULL)); } break; diff --git a/include/nuttx/ioexpander/gpio.h b/include/nuttx/ioexpander/gpio.h index 8e27b6a07730c..ea9a260d2015a 100644 --- a/include/nuttx/ioexpander/gpio.h +++ b/include/nuttx/ioexpander/gpio.h @@ -70,6 +70,20 @@ * Description: Set the GPIO pin type. * Argument: The enum gpio_pintype_e type. * + * Command: GPIOC_BUNDLE_RD + * Description: Read the value of a bundle (a set of) input GPIO. + * This call can be used to read more than one GPIO + * at the same time which is not possible on `GPIOC_READ` + * command. + * Argument: A pointer to a int value to receive the result. + * + * Command: GPIOC_BUNDLE_WR + * Description: Set the value of a bundle (a set of) output GPIO. + * This call can be used to read more than one GPIO + * at the same time which is not possible on `GPIOC_READ` + * command. + * Argument: A pointer to a gpio_bundle_wr_arg_s to set pins. + * */ #define GPIOC_WRITE _GPIOC(1) @@ -78,6 +92,8 @@ #define GPIOC_REGISTER _GPIOC(4) #define GPIOC_UNREGISTER _GPIOC(5) #define GPIOC_SETPINTYPE _GPIOC(6) +#define GPIOC_BUNDLE_RD _GPIOC(7) +#define GPIOC_BUNDLE_WR _GPIOC(8) /**************************************************************************** * Public Types @@ -128,6 +144,7 @@ typedef CODE int (*pin_interrupt_t)(FAR struct gpio_dev_s *dev, uint8_t pin); */ struct gpio_dev_s; +struct gpio_bundle_wr_arg_s; struct gpio_operations_s { /* Interface methods */ @@ -139,6 +156,9 @@ struct gpio_operations_s 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); + CODE int (*go_bundle_read)(FAR struct gpio_dev_s *dev, FAR int *value); + CODE int (*go_bundle_write)(FAR struct gpio_dev_s *dev, + FAR struct gpio_bundle_wr_arg_s *value); }; /* Signal information */ @@ -187,6 +207,16 @@ struct gpio_dev_s /* Device specific, lower-half information may follow. */ }; +/* Structs with the parameters passed to the IOCTL + * for bundle write operation. + */ + +struct gpio_bundle_wr_arg_s +{ + uint32_t mask; /* Mask of the GPIOs to be written */ + uint32_t value; /* Value to write */ +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/