From 5d74f783326042a6b34356e7fb0d2e05d6fecbc0 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Thu, 30 Jan 2025 08:50:07 -0300 Subject: [PATCH] drivers: gpio: Add LP GPIO Add LP GPIO support for LP Core Signed-off-by: Lucas Tamborrino --- .../esp32c6_devkitc_lpcore_defconfig | 1 + drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig.esp32 | 9 +- drivers/gpio/gpio_esp32_lp.c | 208 ++++++++++++++++++ dts/bindings/gpio/espressif,esp32-lpgpio.yaml | 19 ++ .../espressif/esp32c6/esp32c6_lpcore.dtsi | 7 + west.yml | 2 +- 7 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 drivers/gpio/gpio_esp32_lp.c create mode 100644 dts/bindings/gpio/espressif,esp32-lpgpio.yaml diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore_defconfig b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore_defconfig index 42ee26028f9..04974098f6c 100644 --- a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore_defconfig +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore_defconfig @@ -17,3 +17,4 @@ CONFIG_CBPRINTF_NANO=y # Build CONFIG_SIZE_OPTIMIZATIONS=y +CONFIG_BUSYWAIT_CPU_LOOPS_PER_USEC=4 diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 1eaae60d621..195ce116e82 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -117,6 +117,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_XEC_V2 gpio_mchp_xec_v2.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_AXI gpio_xlnx_axi.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_PS gpio_xlnx_ps.c gpio_xlnx_ps_bank.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XMC4XXX gpio_xmc4xxx.c) +zephyr_library_sources_ifdef(CONFIG_LPGPIO_ESP32 gpio_esp32_lp.c) # zephyr-keep-sorted-stop # zephyr-keep-sorted-start diff --git a/drivers/gpio/Kconfig.esp32 b/drivers/gpio/Kconfig.esp32 index b04f6cd5e0a..3ed9039bd50 100644 --- a/drivers/gpio/Kconfig.esp32 +++ b/drivers/gpio/Kconfig.esp32 @@ -6,6 +6,13 @@ config GPIO_ESP32 bool "ESP32 GPIO" default y - depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED + depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED && !SOC_ESP32C6_LPCORE + help + Enables the ESP32 GPIO driver + +config LPGPIO_ESP32 + bool "ESP32 Low Power GPIO" + default y + depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED && SOC_ESP32C6_LPCORE help Enables the ESP32 GPIO driver diff --git a/drivers/gpio/gpio_esp32_lp.c b/drivers/gpio/gpio_esp32_lp.c new file mode 100644 index 00000000000..188471c9e6b --- /dev/null +++ b/drivers/gpio/gpio_esp32_lp.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_lpgpio + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(gpio_esp32, CONFIG_LOG_DEFAULT_LEVEL); + +struct gpio_esp32_lp_config { + struct gpio_driver_config drv_cfg; + lp_io_dev_t *const lp_io_dev; +}; + +struct gpio_esp32_lp_data { + struct gpio_driver_data common; + sys_slist_t cb; +}; + +void ulp_lp_core_lp_io_intr_handler(void) +{ + uint32_t intr_status = rtcio_ll_get_interrupt_status(); + const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(lp_gpio)); + struct gpio_esp32_lp_data *data = dev->data; + + rtcio_ll_clear_interrupt_status(); + gpio_fire_callbacks(&data->cb, dev, intr_status); +} + +bool lp_gpio_is_valid(uint32_t pin) +{ + return rtc_io_num_map[pin] >= 0; +} + +static int gpio_esp32_lp_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + if (!lp_gpio_is_valid(pin)) { + LOG_ERR("Selected LP IO pin is not valid."); + return -EINVAL; + } + + rtcio_hal_function_select(pin, RTCIO_FUNC_RTC); + + if (flags & GPIO_OUTPUT) { + rtcio_hal_set_direction(pin, RTC_GPIO_MODE_OUTPUT_ONLY); + if (flags & GPIO_OUTPUT_INIT_HIGH) { + rtcio_hal_set_level(pin, 1); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + rtcio_hal_set_level(pin, 0); + } + } else if (flags & GPIO_INPUT) { + rtcio_hal_set_direction(pin, RTC_GPIO_MODE_INPUT_ONLY); + } + + return 0; +} + +static int gpio_esp32_lp_port_get_raw(const struct device *port, uint32_t *value) +{ + const struct gpio_esp32_lp_config *const cfg = port->config; + + *value = cfg->lp_io_dev->in.val; + + return 0; +} + +static int gpio_esp32_lp_port_set_masked_raw(const struct device *port, uint32_t mask, + uint32_t value) +{ + const struct gpio_esp32_lp_config *const cfg = port->config; + + cfg->lp_io_dev->out_data.val = (cfg->lp_io_dev->out_data.val & ~mask) | (mask & value); + return 0; +} + +static int gpio_esp32_lp_port_set_bits_raw(const struct device *port, uint32_t pins) +{ + const struct gpio_esp32_lp_config *const cfg = port->config; + + cfg->lp_io_dev->out_data_w1ts.val = pins; + return 0; +} + +static int gpio_esp32_lp_port_clear_bits_raw(const struct device *port, uint32_t pins) +{ + const struct gpio_esp32_lp_config *const cfg = port->config; + + cfg->lp_io_dev->out_data_w1tc.val = pins; + return 0; +} + +static int gpio_esp32_lp_port_toggle_bits(const struct device *port, uint32_t pins) +{ + const struct gpio_esp32_lp_config *const cfg = port->config; + + cfg->lp_io_dev->out_data.val ^= pins; + return 0; +} + +static int lp_gpio_convert_int_type(enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + if (mode == GPIO_INT_MODE_DISABLED) { + return RTCIO_INTR_DISABLE; + } + + if (mode == GPIO_INT_MODE_LEVEL) { + switch (trig) { + case GPIO_INT_TRIG_LOW: + return RTCIO_INTR_LOW_LEVEL; + case GPIO_INT_TRIG_HIGH: + return RTCIO_INTR_HIGH_LEVEL; + default: + return -EINVAL; + } + } else { /* edge interrupts */ + switch (trig) { + case GPIO_INT_TRIG_HIGH: + return RTCIO_INTR_POSEDGE; + case GPIO_INT_TRIG_LOW: + return RTCIO_INTR_NEGEDGE; + case GPIO_INT_TRIG_BOTH: + return RTCIO_INTR_ANYEDGE; + default: + return -EINVAL; + } + } + + /* Any other type of interrupt triggering is invalid. */ + return -EINVAL; +} + +static int gpio_esp32_lp_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + int intr_trig_mode = lp_gpio_convert_int_type(mode, trig); + + if (!lp_gpio_is_valid(pin)) { + LOG_ERR("Selected LP IO pin is not valid."); + return -EINVAL; + } + + rtcio_ll_clear_interrupt_status(); + ulp_lp_core_intr_enable(); + + rtcio_ll_intr_enable(pin, intr_trig_mode); + + return 0; +} + +static int gpio_esp32_lp_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct gpio_esp32_lp_data *data = dev->data; + + return gpio_manage_callback(&data->cb, callback, set); +} + +static uint32_t gpio_esp32_lp_get_pending_int(const struct device *dev) +{ + ARG_UNUSED(dev); + + return rtcio_ll_get_interrupt_status(); +} + +static int gpio_esp32_lp_init(const struct device *dev) +{ + return 0; +} + +static DEVICE_API(gpio, gpio_esp32_lp_driver_api) = { + .pin_configure = gpio_esp32_lp_configure, + .port_get_raw = gpio_esp32_lp_port_get_raw, + .port_set_masked_raw = gpio_esp32_lp_port_set_masked_raw, + .port_set_bits_raw = gpio_esp32_lp_port_set_bits_raw, + .port_clear_bits_raw = gpio_esp32_lp_port_clear_bits_raw, + .port_toggle_bits = gpio_esp32_lp_port_toggle_bits, + .pin_interrupt_configure = gpio_esp32_lp_pin_interrupt_configure, + .manage_callback = gpio_esp32_lp_manage_callback, + .get_pending_int = gpio_esp32_lp_get_pending_int +}; + +static struct gpio_esp32_lp_data gpio_esp32_lp_data_0; +static struct gpio_esp32_lp_config gpio_esp32_lp_cfg = { + .drv_cfg = { + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(DT_NODELABEL(lp_gpio)), + }, + .lp_io_dev = (lp_io_dev_t *)DT_REG_ADDR(DT_NODELABEL(lp_gpio)), +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(lp_gpio), gpio_esp32_lp_init, NULL, &gpio_esp32_lp_data_0, + &gpio_esp32_lp_cfg, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, + &gpio_esp32_lp_driver_api); diff --git a/dts/bindings/gpio/espressif,esp32-lpgpio.yaml b/dts/bindings/gpio/espressif,esp32-lpgpio.yaml new file mode 100644 index 00000000000..70c00023e2d --- /dev/null +++ b/dts/bindings/gpio/espressif,esp32-lpgpio.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: ESP32 Low Power GPIO controller for LP Core + +compatible: "espressif,esp32-lpgpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi index 319bc571805..ed33ded7837 100644 --- a/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi +++ b/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi @@ -66,5 +66,12 @@ status = "disabled"; }; + lp_gpio: gpio@600b2000 { + compatible = "espressif,esp32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x600b2000 DT_SIZE_K(4)>; + ngpios = <8>; + }; }; }; diff --git a/west.yml b/west.yml index 47512a0b5b8..10ab107abb6 100644 --- a/west.yml +++ b/west.yml @@ -167,7 +167,7 @@ manifest: groups: - hal - name: hal_espressif - revision: dbc28ad4c1bdcdb25e79ca225cb5528a75d8dc91 + revision: c811e7e58ecb2574a4ae6a1c777015185cdaf199 path: modules/hal/espressif west-commands: west/west-commands.yml groups: