1 /*
2 * Copyright (c) 2017 Intel Corporation
3 * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT espressif_esp32_gpio
9
10 /* Include esp-idf headers first to avoid redefining BIT() macro */
11 #include <soc/gpio_reg.h>
12 #include <soc/io_mux_reg.h>
13 #include <soc/soc.h>
14 #include <hal/gpio_ll.h>
15 #include <esp_attr.h>
16 #include <hal/rtc_io_hal.h>
17
18 #include <soc.h>
19 #include <errno.h>
20 #include <zephyr/device.h>
21 #include <zephyr/drivers/gpio.h>
22 #include <zephyr/dt-bindings/gpio/espressif-esp32-gpio.h>
23 #if defined(CONFIG_SOC_SERIES_ESP32C2) || \
24 defined(CONFIG_SOC_SERIES_ESP32C3) || \
25 defined(CONFIG_SOC_SERIES_ESP32C6)
26 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
27 #else
28 #include <zephyr/drivers/interrupt_controller/intc_esp32.h>
29 #endif
30 #include <zephyr/kernel.h>
31 #include <zephyr/sys/util.h>
32
33 #include <zephyr/drivers/gpio/gpio_utils.h>
34
35 #include <zephyr/logging/log.h>
36 LOG_MODULE_REGISTER(gpio_esp32, CONFIG_LOG_DEFAULT_LEVEL);
37
38 #ifdef CONFIG_SOC_SERIES_ESP32C2
39 #define out out.val
40 #define in in.val
41 #define out_w1ts out_w1ts.val
42 #define out_w1tc out_w1tc.val
43 /* arch_curr_cpu() is not available for riscv based chips */
44 #define CPU_ID() 0
45 #define ISR_HANDLER isr_handler_t
46 #elif CONFIG_SOC_SERIES_ESP32C3
47 /* gpio structs in esp32c3 series are different from xtensa ones */
48 #define out out.data
49 #define in in.data
50 #define out_w1ts out_w1ts.val
51 #define out_w1tc out_w1tc.val
52 /* arch_curr_cpu() is not available for riscv based chips */
53 #define CPU_ID() 0
54 #define ISR_HANDLER isr_handler_t
55 #elif defined(CONFIG_SOC_SERIES_ESP32C6)
56 /* gpio structs in esp32c6 are also different */
57 #define out out.out_data_orig
58 #define in in.in_data_next
59 #define out_w1ts out_w1ts.val
60 #define out_w1tc out_w1tc.val
61 /* arch_curr_cpu() is not available for riscv based chips */
62 #define CPU_ID() 0
63 #define ISR_HANDLER isr_handler_t
64 #else
65 #define CPU_ID() arch_curr_cpu()->id
66 #define ISR_HANDLER intr_handler_t
67 #endif
68
69 #ifndef SOC_GPIO_SUPPORT_RTC_INDEPENDENT
70 #define SOC_GPIO_SUPPORT_RTC_INDEPENDENT 0
71 #endif
72
73 struct gpio_esp32_config {
74 /* gpio_driver_config needs to be first */
75 struct gpio_driver_config drv_cfg;
76 gpio_dev_t *const gpio_base;
77 gpio_dev_t *const gpio_dev;
78 const int gpio_port;
79 };
80
81 struct gpio_esp32_data {
82 /* gpio_driver_data needs to be first */
83 struct gpio_driver_data common;
84 sys_slist_t cb;
85 };
86
rtc_gpio_is_valid_gpio(uint32_t gpio_num)87 static inline bool rtc_gpio_is_valid_gpio(uint32_t gpio_num)
88 {
89 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
90 return (gpio_num < SOC_GPIO_PIN_COUNT && rtc_io_num_map[gpio_num] >= 0);
91 #else
92 return false;
93 #endif
94 }
95
gpio_pin_is_valid(uint32_t pin)96 static inline bool gpio_pin_is_valid(uint32_t pin)
97 {
98 return ((BIT(pin) & SOC_GPIO_VALID_GPIO_MASK) != 0);
99 }
100
gpio_pin_is_output_capable(uint32_t pin)101 static inline bool gpio_pin_is_output_capable(uint32_t pin)
102 {
103 return ((BIT(pin) & SOC_GPIO_VALID_OUTPUT_GPIO_MASK) != 0);
104 }
105
gpio_esp32_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)106 static int gpio_esp32_config(const struct device *dev,
107 gpio_pin_t pin,
108 gpio_flags_t flags)
109 {
110 const struct gpio_esp32_config *const cfg = dev->config;
111 uint32_t io_pin = (uint32_t) pin + ((cfg->gpio_port == 1 && pin < 32) ? 32 : 0);
112 uint32_t key;
113 int ret = 0;
114
115 if (!gpio_pin_is_valid(io_pin)) {
116 LOG_ERR("Selected IO pin is not valid.");
117 return -EINVAL;
118 }
119
120 key = irq_lock();
121
122 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
123 if (rtc_gpio_is_valid_gpio(io_pin)) {
124 rtcio_hal_function_select(rtc_io_num_map[io_pin], RTCIO_FUNC_DIGITAL);
125 }
126 #endif
127
128 if (io_pin >= GPIO_NUM_MAX) {
129 LOG_ERR("Invalid pin.");
130 ret = -EINVAL;
131 goto end;
132 }
133
134 /* Set pin function as GPIO */
135 gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[io_pin], PIN_FUNC_GPIO);
136
137 if (flags & GPIO_PULL_UP) {
138 if (!rtc_gpio_is_valid_gpio(io_pin) || SOC_GPIO_SUPPORT_RTC_INDEPENDENT) {
139 gpio_ll_pullup_en(&GPIO, io_pin);
140 } else {
141 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
142 int rtcio_num = rtc_io_num_map[io_pin];
143
144 if (rtc_io_desc[rtcio_num].pullup) {
145 rtcio_hal_pullup_enable(rtcio_num);
146 } else {
147 ret = -ENOTSUP;
148 goto end;
149 }
150 #endif
151 }
152 } else {
153 if (!rtc_gpio_is_valid_gpio(io_pin) || SOC_GPIO_SUPPORT_RTC_INDEPENDENT) {
154 gpio_ll_pullup_dis(&GPIO, io_pin);
155 } else {
156 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
157 int rtcio_num = rtc_io_num_map[io_pin];
158
159 if (rtc_io_desc[rtcio_num].pullup) {
160 rtcio_hal_pullup_disable(rtcio_num);
161 }
162 #else
163 ret = -ENOTSUP;
164 goto end;
165 #endif
166 }
167 }
168
169 if (flags & GPIO_SINGLE_ENDED) {
170 if (flags & GPIO_LINE_OPEN_DRAIN) {
171 gpio_ll_od_enable(cfg->gpio_base, io_pin);
172 } else {
173 LOG_ERR("GPIO configuration not supported");
174 ret = -ENOTSUP;
175 goto end;
176 }
177 } else {
178 gpio_ll_od_disable(cfg->gpio_base, io_pin);
179 }
180
181 if (flags & GPIO_PULL_DOWN) {
182 if (!rtc_gpio_is_valid_gpio(io_pin) || SOC_GPIO_SUPPORT_RTC_INDEPENDENT) {
183 gpio_ll_pulldown_en(&GPIO, io_pin);
184 } else {
185 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
186 int rtcio_num = rtc_io_num_map[io_pin];
187
188 if (rtc_io_desc[rtcio_num].pulldown) {
189 rtcio_hal_pulldown_enable(rtcio_num);
190 } else {
191 ret = -ENOTSUP;
192 goto end;
193 }
194 #endif
195 }
196 } else {
197 if (!rtc_gpio_is_valid_gpio(io_pin) || SOC_GPIO_SUPPORT_RTC_INDEPENDENT) {
198 gpio_ll_pulldown_dis(&GPIO, io_pin);
199 } else {
200 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
201 int rtcio_num = rtc_io_num_map[io_pin];
202
203 if (rtc_io_desc[rtcio_num].pulldown) {
204 rtcio_hal_pulldown_disable(rtcio_num);
205 }
206 #else
207 ret = -ENOTSUP;
208 goto end;
209 #endif
210 }
211 }
212
213 if (flags & GPIO_OUTPUT) {
214
215 if (!gpio_pin_is_output_capable(pin)) {
216 LOG_ERR("GPIO can only be used as input");
217 ret = -EINVAL;
218 goto end;
219 }
220
221 /*
222 * By default, drive strength is set to its maximum value when the pin is set
223 * to either low or high states. Alternative drive strength is weak-only,
224 * while any other intermediary combination is considered invalid.
225 */
226 switch (flags & ESP32_GPIO_DS_MASK) {
227 case ESP32_GPIO_DS_DFLT:
228 if (!rtc_gpio_is_valid_gpio(io_pin) || SOC_GPIO_SUPPORT_RTC_INDEPENDENT) {
229 gpio_ll_set_drive_capability(cfg->gpio_base,
230 io_pin,
231 GPIO_DRIVE_CAP_3);
232 } else {
233 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
234 rtcio_hal_set_drive_capability(rtc_io_num_map[io_pin],
235 GPIO_DRIVE_CAP_3);
236 #endif
237 }
238 break;
239 case ESP32_GPIO_DS_ALT:
240 if (!rtc_gpio_is_valid_gpio(io_pin) || SOC_GPIO_SUPPORT_RTC_INDEPENDENT) {
241 gpio_ll_set_drive_capability(cfg->gpio_base,
242 io_pin,
243 GPIO_DRIVE_CAP_0);
244 } else {
245 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
246 rtcio_hal_set_drive_capability(rtc_io_num_map[io_pin],
247 GPIO_DRIVE_CAP_0);
248 #endif
249 }
250 break;
251 default:
252 ret = -EINVAL;
253 goto end;
254 }
255
256 gpio_ll_output_enable(&GPIO, io_pin);
257 esp_rom_gpio_matrix_out(io_pin, SIG_GPIO_OUT_IDX, false, false);
258
259 /* Set output pin initial value */
260 if (flags & GPIO_OUTPUT_INIT_HIGH) {
261 gpio_ll_set_level(cfg->gpio_base, io_pin, 1);
262 } else if (flags & GPIO_OUTPUT_INIT_LOW) {
263 gpio_ll_set_level(cfg->gpio_base, io_pin, 0);
264 }
265 } else {
266 if (!(flags & ESP32_GPIO_PIN_OUT_EN)) {
267 gpio_ll_output_disable(&GPIO, io_pin);
268 }
269 }
270
271 if (flags & GPIO_INPUT) {
272 gpio_ll_input_enable(&GPIO, io_pin);
273 } else {
274 if (!(flags & ESP32_GPIO_PIN_IN_EN)) {
275 gpio_ll_input_disable(&GPIO, io_pin);
276 }
277 }
278
279 end:
280 irq_unlock(key);
281
282 return ret;
283 }
284
gpio_esp32_port_get_raw(const struct device * port,uint32_t * value)285 static int gpio_esp32_port_get_raw(const struct device *port, uint32_t *value)
286 {
287 const struct gpio_esp32_config *const cfg = port->config;
288
289 if (cfg->gpio_port == 0) {
290 *value = cfg->gpio_dev->in;
291 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1))
292 } else {
293 *value = cfg->gpio_dev->in1.data;
294 #endif
295 }
296
297 return 0;
298 }
299
gpio_esp32_port_set_masked_raw(const struct device * port,uint32_t mask,uint32_t value)300 static int gpio_esp32_port_set_masked_raw(const struct device *port,
301 uint32_t mask, uint32_t value)
302 {
303 const struct gpio_esp32_config *const cfg = port->config;
304
305 uint32_t key = irq_lock();
306
307 if (cfg->gpio_port == 0) {
308 cfg->gpio_dev->out = (cfg->gpio_dev->out & ~mask) | (mask & value);
309 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1))
310 } else {
311 cfg->gpio_dev->out1.data = (cfg->gpio_dev->out1.data & ~mask) | (mask & value);
312 #endif
313 }
314
315 irq_unlock(key);
316
317 return 0;
318 }
319
gpio_esp32_port_set_bits_raw(const struct device * port,uint32_t pins)320 static int gpio_esp32_port_set_bits_raw(const struct device *port,
321 uint32_t pins)
322 {
323 const struct gpio_esp32_config *const cfg = port->config;
324
325 if (cfg->gpio_port == 0) {
326 cfg->gpio_dev->out_w1ts = pins;
327 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1))
328 } else {
329 cfg->gpio_dev->out1_w1ts.data = pins;
330 #endif
331 }
332
333 return 0;
334 }
335
gpio_esp32_port_clear_bits_raw(const struct device * port,uint32_t pins)336 static int gpio_esp32_port_clear_bits_raw(const struct device *port,
337 uint32_t pins)
338 {
339 const struct gpio_esp32_config *const cfg = port->config;
340
341 if (cfg->gpio_port == 0) {
342 cfg->gpio_dev->out_w1tc = pins;
343 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1))
344 } else {
345 cfg->gpio_dev->out1_w1tc.data = pins;
346 #endif
347 }
348
349 return 0;
350 }
351
gpio_esp32_port_toggle_bits(const struct device * port,uint32_t pins)352 static int gpio_esp32_port_toggle_bits(const struct device *port,
353 uint32_t pins)
354 {
355 const struct gpio_esp32_config *const cfg = port->config;
356 uint32_t key = irq_lock();
357
358 if (cfg->gpio_port == 0) {
359 cfg->gpio_dev->out ^= pins;
360 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1))
361 } else {
362 cfg->gpio_dev->out1.data ^= pins;
363 #endif
364 }
365
366 irq_unlock(key);
367
368 return 0;
369 }
370
convert_int_type(enum gpio_int_mode mode,enum gpio_int_trig trig)371 static int convert_int_type(enum gpio_int_mode mode,
372 enum gpio_int_trig trig)
373 {
374 if (mode == GPIO_INT_MODE_DISABLED) {
375 return GPIO_INTR_DISABLE;
376 }
377
378 if (mode == GPIO_INT_MODE_LEVEL) {
379 switch (trig) {
380 case GPIO_INT_TRIG_LOW:
381 return GPIO_INTR_LOW_LEVEL;
382 case GPIO_INT_TRIG_HIGH:
383 return GPIO_INTR_HIGH_LEVEL;
384 default:
385 return -EINVAL;
386 }
387 } else { /* edge interrupts */
388 switch (trig) {
389 case GPIO_INT_TRIG_HIGH:
390 return GPIO_INTR_POSEDGE;
391 case GPIO_INT_TRIG_LOW:
392 return GPIO_INTR_NEGEDGE;
393 case GPIO_INT_TRIG_BOTH:
394 return GPIO_INTR_ANYEDGE;
395 default:
396 return -EINVAL;
397 }
398 }
399
400 /* Any other type of interrupt triggering is invalid. */
401 return -EINVAL;
402 }
403
gpio_esp32_pin_interrupt_configure(const struct device * port,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)404 static int gpio_esp32_pin_interrupt_configure(const struct device *port,
405 gpio_pin_t pin,
406 enum gpio_int_mode mode,
407 enum gpio_int_trig trig)
408 {
409 const struct gpio_esp32_config *const cfg = port->config;
410 uint32_t io_pin = (uint32_t) pin + ((cfg->gpio_port == 1 && pin < 32) ? 32 : 0);
411 int intr_trig_mode = convert_int_type(mode, trig);
412 uint32_t key;
413
414 if (intr_trig_mode < 0) {
415 return intr_trig_mode;
416 }
417
418 key = irq_lock();
419 if (cfg->gpio_port == 0) {
420 gpio_ll_clear_intr_status(cfg->gpio_base, BIT(pin));
421 } else {
422 gpio_ll_clear_intr_status_high(cfg->gpio_base, BIT(pin));
423 }
424
425 gpio_ll_set_intr_type(cfg->gpio_base, io_pin, intr_trig_mode);
426 gpio_ll_intr_enable_on_core(cfg->gpio_base, CPU_ID(), io_pin);
427 irq_unlock(key);
428
429 return 0;
430 }
431
gpio_esp32_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)432 static int gpio_esp32_manage_callback(const struct device *dev,
433 struct gpio_callback *callback,
434 bool set)
435 {
436 struct gpio_esp32_data *data = dev->data;
437
438 return gpio_manage_callback(&data->cb, callback, set);
439 }
440
gpio_esp32_get_pending_int(const struct device * dev)441 static uint32_t gpio_esp32_get_pending_int(const struct device *dev)
442 {
443 const struct gpio_esp32_config *const cfg = dev->config;
444 uint32_t irq_status;
445 uint32_t const core_id = CPU_ID();
446
447 if (cfg->gpio_port == 0) {
448 gpio_ll_get_intr_status(cfg->gpio_base, core_id, &irq_status);
449 } else {
450 gpio_ll_get_intr_status_high(cfg->gpio_base, core_id, &irq_status);
451 }
452
453 return irq_status;
454 }
455
gpio_esp32_fire_callbacks(const struct device * dev)456 static void IRAM_ATTR gpio_esp32_fire_callbacks(const struct device *dev)
457 {
458 const struct gpio_esp32_config *const cfg = dev->config;
459 struct gpio_esp32_data *data = dev->data;
460 uint32_t irq_status;
461 uint32_t const core_id = CPU_ID();
462
463 if (cfg->gpio_port == 0) {
464 gpio_ll_get_intr_status(cfg->gpio_base, core_id, &irq_status);
465 gpio_ll_clear_intr_status(cfg->gpio_base, irq_status);
466 } else {
467 gpio_ll_get_intr_status_high(cfg->gpio_base, core_id, &irq_status);
468 gpio_ll_clear_intr_status_high(cfg->gpio_base, irq_status);
469 }
470
471 if (irq_status != 0) {
472 gpio_fire_callbacks(&data->cb, dev, irq_status);
473 }
474 }
475
476 static void gpio_esp32_isr(void *param);
477
gpio_esp32_init(const struct device * dev)478 static int gpio_esp32_init(const struct device *dev)
479 {
480 static bool isr_connected;
481
482 if (!isr_connected) {
483 int ret = esp_intr_alloc(DT_IRQ_BY_IDX(DT_NODELABEL(gpio0), 0, irq),
484 ESP_PRIO_TO_FLAGS(DT_IRQ_BY_IDX(DT_NODELABEL(gpio0), 0, priority)) |
485 ESP_INT_FLAGS_CHECK(DT_IRQ_BY_IDX(DT_NODELABEL(gpio0), 0, flags)),
486 (ISR_HANDLER)gpio_esp32_isr,
487 (void *)dev,
488 NULL);
489
490 if (ret != 0) {
491 LOG_ERR("could not allocate interrupt (err %d)", ret);
492 return ret;
493 }
494
495 isr_connected = true;
496 }
497
498 return 0;
499 }
500
501 static DEVICE_API(gpio, gpio_esp32_driver_api) = {
502 .pin_configure = gpio_esp32_config,
503 .port_get_raw = gpio_esp32_port_get_raw,
504 .port_set_masked_raw = gpio_esp32_port_set_masked_raw,
505 .port_set_bits_raw = gpio_esp32_port_set_bits_raw,
506 .port_clear_bits_raw = gpio_esp32_port_clear_bits_raw,
507 .port_toggle_bits = gpio_esp32_port_toggle_bits,
508 .pin_interrupt_configure = gpio_esp32_pin_interrupt_configure,
509 .manage_callback = gpio_esp32_manage_callback,
510 .get_pending_int = gpio_esp32_get_pending_int
511 };
512
513 #define ESP_SOC_GPIO_INIT(_id) \
514 static struct gpio_esp32_data gpio_data_##_id; \
515 static struct gpio_esp32_config gpio_config_##_id = { \
516 .drv_cfg = { \
517 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(_id), \
518 }, \
519 .gpio_base = (gpio_dev_t *)DT_REG_ADDR(DT_NODELABEL(gpio0)), \
520 .gpio_dev = (gpio_dev_t *)DT_REG_ADDR(DT_NODELABEL(gpio##_id)), \
521 .gpio_port = _id \
522 }; \
523 DEVICE_DT_DEFINE(DT_NODELABEL(gpio##_id), \
524 &gpio_esp32_init, \
525 NULL, \
526 &gpio_data_##_id, \
527 &gpio_config_##_id, \
528 PRE_KERNEL_1, \
529 CONFIG_GPIO_INIT_PRIORITY, \
530 &gpio_esp32_driver_api);
531
532 DT_INST_FOREACH_STATUS_OKAY(ESP_SOC_GPIO_INIT);
533
gpio_esp32_isr(void * param)534 static void IRAM_ATTR gpio_esp32_isr(void *param)
535 {
536 ARG_UNUSED(param);
537
538 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio0))
539 gpio_esp32_fire_callbacks(DEVICE_DT_INST_GET(0));
540 #endif
541
542 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1))
543 gpio_esp32_fire_callbacks(DEVICE_DT_INST_GET(1));
544 #endif
545 }
546