Skip to content

Commit 5d74f78

Browse files
LucasTamborkartben
authored andcommitted
drivers: gpio: Add LP GPIO
Add LP GPIO support for LP Core Signed-off-by: Lucas Tamborrino <lucas.tamborrino@espressif.com>
1 parent 9a6f116 commit 5d74f78

File tree

7 files changed

+245
-2
lines changed

7 files changed

+245
-2
lines changed

boards/espressif/esp32c6_devkitc/esp32c6_devkitc_lpcore_defconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ CONFIG_CBPRINTF_NANO=y
1717

1818
# Build
1919
CONFIG_SIZE_OPTIMIZATIONS=y
20+
CONFIG_BUSYWAIT_CPU_LOOPS_PER_USEC=4

drivers/gpio/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_XEC_V2 gpio_mchp_xec_v2.c)
117117
zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_AXI gpio_xlnx_axi.c)
118118
zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_PS gpio_xlnx_ps.c gpio_xlnx_ps_bank.c)
119119
zephyr_library_sources_ifdef(CONFIG_GPIO_XMC4XXX gpio_xmc4xxx.c)
120+
zephyr_library_sources_ifdef(CONFIG_LPGPIO_ESP32 gpio_esp32_lp.c)
120121
# zephyr-keep-sorted-stop
121122

122123
# zephyr-keep-sorted-start

drivers/gpio/Kconfig.esp32

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
config GPIO_ESP32
77
bool "ESP32 GPIO"
88
default y
9-
depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED
9+
depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED && !SOC_ESP32C6_LPCORE
10+
help
11+
Enables the ESP32 GPIO driver
12+
13+
config LPGPIO_ESP32
14+
bool "ESP32 Low Power GPIO"
15+
default y
16+
depends on DT_HAS_ESPRESSIF_ESP32_GPIO_ENABLED && SOC_ESP32C6_LPCORE
1017
help
1118
Enables the ESP32 GPIO driver

drivers/gpio/gpio_esp32_lp.c

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
* Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT espressif_esp32_lpgpio
8+
9+
#include <soc.h>
10+
#include <errno.h>
11+
#include <zephyr/device.h>
12+
#include <zephyr/drivers/gpio.h>
13+
#include <zephyr/dt-bindings/gpio/espressif-esp32-gpio.h>
14+
#include <zephyr/kernel.h>
15+
#include <zephyr/sys/util.h>
16+
17+
#include <zephyr/drivers/gpio/gpio_utils.h>
18+
19+
#include <hal/rtc_io_hal.h>
20+
#include <soc/rtc_io_periph.h>
21+
#include <ulp_lp_core_interrupts.h>
22+
23+
#include <zephyr/logging/log.h>
24+
LOG_MODULE_REGISTER(gpio_esp32, CONFIG_LOG_DEFAULT_LEVEL);
25+
26+
struct gpio_esp32_lp_config {
27+
struct gpio_driver_config drv_cfg;
28+
lp_io_dev_t *const lp_io_dev;
29+
};
30+
31+
struct gpio_esp32_lp_data {
32+
struct gpio_driver_data common;
33+
sys_slist_t cb;
34+
};
35+
36+
void ulp_lp_core_lp_io_intr_handler(void)
37+
{
38+
uint32_t intr_status = rtcio_ll_get_interrupt_status();
39+
const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(lp_gpio));
40+
struct gpio_esp32_lp_data *data = dev->data;
41+
42+
rtcio_ll_clear_interrupt_status();
43+
gpio_fire_callbacks(&data->cb, dev, intr_status);
44+
}
45+
46+
bool lp_gpio_is_valid(uint32_t pin)
47+
{
48+
return rtc_io_num_map[pin] >= 0;
49+
}
50+
51+
static int gpio_esp32_lp_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
52+
{
53+
if (!lp_gpio_is_valid(pin)) {
54+
LOG_ERR("Selected LP IO pin is not valid.");
55+
return -EINVAL;
56+
}
57+
58+
rtcio_hal_function_select(pin, RTCIO_FUNC_RTC);
59+
60+
if (flags & GPIO_OUTPUT) {
61+
rtcio_hal_set_direction(pin, RTC_GPIO_MODE_OUTPUT_ONLY);
62+
if (flags & GPIO_OUTPUT_INIT_HIGH) {
63+
rtcio_hal_set_level(pin, 1);
64+
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
65+
rtcio_hal_set_level(pin, 0);
66+
}
67+
} else if (flags & GPIO_INPUT) {
68+
rtcio_hal_set_direction(pin, RTC_GPIO_MODE_INPUT_ONLY);
69+
}
70+
71+
return 0;
72+
}
73+
74+
static int gpio_esp32_lp_port_get_raw(const struct device *port, uint32_t *value)
75+
{
76+
const struct gpio_esp32_lp_config *const cfg = port->config;
77+
78+
*value = cfg->lp_io_dev->in.val;
79+
80+
return 0;
81+
}
82+
83+
static int gpio_esp32_lp_port_set_masked_raw(const struct device *port, uint32_t mask,
84+
uint32_t value)
85+
{
86+
const struct gpio_esp32_lp_config *const cfg = port->config;
87+
88+
cfg->lp_io_dev->out_data.val = (cfg->lp_io_dev->out_data.val & ~mask) | (mask & value);
89+
return 0;
90+
}
91+
92+
static int gpio_esp32_lp_port_set_bits_raw(const struct device *port, uint32_t pins)
93+
{
94+
const struct gpio_esp32_lp_config *const cfg = port->config;
95+
96+
cfg->lp_io_dev->out_data_w1ts.val = pins;
97+
return 0;
98+
}
99+
100+
static int gpio_esp32_lp_port_clear_bits_raw(const struct device *port, uint32_t pins)
101+
{
102+
const struct gpio_esp32_lp_config *const cfg = port->config;
103+
104+
cfg->lp_io_dev->out_data_w1tc.val = pins;
105+
return 0;
106+
}
107+
108+
static int gpio_esp32_lp_port_toggle_bits(const struct device *port, uint32_t pins)
109+
{
110+
const struct gpio_esp32_lp_config *const cfg = port->config;
111+
112+
cfg->lp_io_dev->out_data.val ^= pins;
113+
return 0;
114+
}
115+
116+
static int lp_gpio_convert_int_type(enum gpio_int_mode mode, enum gpio_int_trig trig)
117+
{
118+
if (mode == GPIO_INT_MODE_DISABLED) {
119+
return RTCIO_INTR_DISABLE;
120+
}
121+
122+
if (mode == GPIO_INT_MODE_LEVEL) {
123+
switch (trig) {
124+
case GPIO_INT_TRIG_LOW:
125+
return RTCIO_INTR_LOW_LEVEL;
126+
case GPIO_INT_TRIG_HIGH:
127+
return RTCIO_INTR_HIGH_LEVEL;
128+
default:
129+
return -EINVAL;
130+
}
131+
} else { /* edge interrupts */
132+
switch (trig) {
133+
case GPIO_INT_TRIG_HIGH:
134+
return RTCIO_INTR_POSEDGE;
135+
case GPIO_INT_TRIG_LOW:
136+
return RTCIO_INTR_NEGEDGE;
137+
case GPIO_INT_TRIG_BOTH:
138+
return RTCIO_INTR_ANYEDGE;
139+
default:
140+
return -EINVAL;
141+
}
142+
}
143+
144+
/* Any other type of interrupt triggering is invalid. */
145+
return -EINVAL;
146+
}
147+
148+
static int gpio_esp32_lp_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
149+
enum gpio_int_mode mode, enum gpio_int_trig trig)
150+
{
151+
int intr_trig_mode = lp_gpio_convert_int_type(mode, trig);
152+
153+
if (!lp_gpio_is_valid(pin)) {
154+
LOG_ERR("Selected LP IO pin is not valid.");
155+
return -EINVAL;
156+
}
157+
158+
rtcio_ll_clear_interrupt_status();
159+
ulp_lp_core_intr_enable();
160+
161+
rtcio_ll_intr_enable(pin, intr_trig_mode);
162+
163+
return 0;
164+
}
165+
166+
static int gpio_esp32_lp_manage_callback(const struct device *dev, struct gpio_callback *callback,
167+
bool set)
168+
{
169+
struct gpio_esp32_lp_data *data = dev->data;
170+
171+
return gpio_manage_callback(&data->cb, callback, set);
172+
}
173+
174+
static uint32_t gpio_esp32_lp_get_pending_int(const struct device *dev)
175+
{
176+
ARG_UNUSED(dev);
177+
178+
return rtcio_ll_get_interrupt_status();
179+
}
180+
181+
static int gpio_esp32_lp_init(const struct device *dev)
182+
{
183+
return 0;
184+
}
185+
186+
static DEVICE_API(gpio, gpio_esp32_lp_driver_api) = {
187+
.pin_configure = gpio_esp32_lp_configure,
188+
.port_get_raw = gpio_esp32_lp_port_get_raw,
189+
.port_set_masked_raw = gpio_esp32_lp_port_set_masked_raw,
190+
.port_set_bits_raw = gpio_esp32_lp_port_set_bits_raw,
191+
.port_clear_bits_raw = gpio_esp32_lp_port_clear_bits_raw,
192+
.port_toggle_bits = gpio_esp32_lp_port_toggle_bits,
193+
.pin_interrupt_configure = gpio_esp32_lp_pin_interrupt_configure,
194+
.manage_callback = gpio_esp32_lp_manage_callback,
195+
.get_pending_int = gpio_esp32_lp_get_pending_int
196+
};
197+
198+
static struct gpio_esp32_lp_data gpio_esp32_lp_data_0;
199+
static struct gpio_esp32_lp_config gpio_esp32_lp_cfg = {
200+
.drv_cfg = {
201+
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(DT_NODELABEL(lp_gpio)),
202+
},
203+
.lp_io_dev = (lp_io_dev_t *)DT_REG_ADDR(DT_NODELABEL(lp_gpio)),
204+
};
205+
206+
DEVICE_DT_DEFINE(DT_NODELABEL(lp_gpio), gpio_esp32_lp_init, NULL, &gpio_esp32_lp_data_0,
207+
&gpio_esp32_lp_cfg, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY,
208+
&gpio_esp32_lp_driver_api);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ESP32 Low Power GPIO controller for LP Core
5+
6+
compatible: "espressif,esp32-lpgpio"
7+
8+
include: [gpio-controller.yaml, base.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
"#gpio-cells":
15+
const: 2
16+
17+
gpio-cells:
18+
- pin
19+
- flags

dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,12 @@
6666
status = "disabled";
6767
};
6868

69+
lp_gpio: gpio@600b2000 {
70+
compatible = "espressif,esp32-gpio";
71+
gpio-controller;
72+
#gpio-cells = <2>;
73+
reg = <0x600b2000 DT_SIZE_K(4)>;
74+
ngpios = <8>;
75+
};
6976
};
7077
};

west.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ manifest:
167167
groups:
168168
- hal
169169
- name: hal_espressif
170-
revision: dbc28ad4c1bdcdb25e79ca225cb5528a75d8dc91
170+
revision: c811e7e58ecb2574a4ae6a1c777015185cdaf199
171171
path: modules/hal/espressif
172172
west-commands: west/west-commands.yml
173173
groups:

0 commit comments

Comments
 (0)