1 /*
2 * Copyright (c) 2016 Open-RnD Sp. z o.o.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT st_stm32_gpio
8
9 #include <errno.h>
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <soc.h>
14 #include <stm32_ll_bus.h>
15 #include <stm32_ll_exti.h>
16 #include <stm32_ll_gpio.h>
17 #include <stm32_ll_pwr.h>
18 #include <stm32_ll_system.h>
19 #include <zephyr/drivers/gpio.h>
20 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
21 #include <zephyr/sys/util.h>
22 #include <zephyr/drivers/interrupt_controller/exti_stm32.h>
23 #include <zephyr/pm/device.h>
24 #include <zephyr/pm/device_runtime.h>
25 #include <zephyr/drivers/misc/stm32_wkup_pins/stm32_wkup_pins.h>
26 #include <zephyr/dt-bindings/gpio/stm32-gpio.h>
27
28 #include "stm32_hsem.h"
29 #include "gpio_stm32.h"
30 #include <zephyr/drivers/gpio/gpio_utils.h>
31
32 #include <zephyr/logging/log.h>
33
34 LOG_MODULE_REGISTER(stm32, CONFIG_GPIO_LOG_LEVEL);
35
36 /**
37 * @brief Common GPIO driver for STM32 MCUs.
38 */
39
40 /**
41 * @brief EXTI interrupt callback
42 */
gpio_stm32_isr(int line,void * arg)43 static void gpio_stm32_isr(int line, void *arg)
44 {
45 struct gpio_stm32_data *data = arg;
46
47 gpio_fire_callbacks(&data->cb, data->dev, BIT(line));
48 }
49
50 /**
51 * @brief Common gpio flags to custom flags
52 */
gpio_stm32_flags_to_conf(gpio_flags_t flags,int * pincfg)53 static int gpio_stm32_flags_to_conf(gpio_flags_t flags, int *pincfg)
54 {
55
56 if ((flags & GPIO_OUTPUT) != 0) {
57 /* Output only or Output/Input */
58
59 *pincfg = STM32_PINCFG_MODE_OUTPUT;
60
61 if ((flags & GPIO_SINGLE_ENDED) != 0) {
62 if (flags & GPIO_LINE_OPEN_DRAIN) {
63 *pincfg |= STM32_PINCFG_OPEN_DRAIN;
64 } else {
65 /* Output can't be open source */
66 return -ENOTSUP;
67 }
68 } else {
69 *pincfg |= STM32_PINCFG_PUSH_PULL;
70 }
71
72 if ((flags & GPIO_PULL_UP) != 0) {
73 *pincfg |= STM32_PINCFG_PULL_UP;
74 } else if ((flags & GPIO_PULL_DOWN) != 0) {
75 *pincfg |= STM32_PINCFG_PULL_DOWN;
76 }
77
78 } else if ((flags & GPIO_INPUT) != 0) {
79 /* Input */
80
81 *pincfg = STM32_PINCFG_MODE_INPUT;
82
83 if ((flags & GPIO_PULL_UP) != 0) {
84 *pincfg |= STM32_PINCFG_PULL_UP;
85 } else if ((flags & GPIO_PULL_DOWN) != 0) {
86 *pincfg |= STM32_PINCFG_PULL_DOWN;
87 } else {
88 *pincfg |= STM32_PINCFG_FLOATING;
89 }
90 } else {
91 /* Deactivated: Analog */
92 *pincfg = STM32_PINCFG_MODE_ANALOG;
93 }
94
95 return 0;
96 }
97
98 #if defined(CONFIG_GPIO_GET_CONFIG) && !defined(CONFIG_SOC_SERIES_STM32F1X)
99 /**
100 * @brief Custom stm32 flags to zephyr
101 */
gpio_stm32_pincfg_to_flags(struct gpio_stm32_pin pin_cfg,gpio_flags_t * out_flags)102 static int gpio_stm32_pincfg_to_flags(struct gpio_stm32_pin pin_cfg,
103 gpio_flags_t *out_flags)
104 {
105 gpio_flags_t flags = 0;
106
107 if (pin_cfg.mode == LL_GPIO_MODE_OUTPUT) {
108 flags |= GPIO_OUTPUT;
109 if (pin_cfg.type == LL_GPIO_OUTPUT_OPENDRAIN) {
110 flags |= GPIO_OPEN_DRAIN;
111 }
112 } else if (pin_cfg.mode == LL_GPIO_MODE_INPUT) {
113 flags |= GPIO_INPUT;
114 #ifdef CONFIG_SOC_SERIES_STM32F1X
115 } else if (pin_cfg.mode == LL_GPIO_MODE_FLOATING) {
116 flags |= GPIO_INPUT;
117 #endif
118 } else {
119 flags |= GPIO_DISCONNECTED;
120 }
121
122 if (pin_cfg.pupd == LL_GPIO_PULL_UP) {
123 flags |= GPIO_PULL_UP;
124 } else if (pin_cfg.pupd == LL_GPIO_PULL_DOWN) {
125 flags |= GPIO_PULL_DOWN;
126 }
127
128 if (pin_cfg.out_state != 0) {
129 flags |= GPIO_OUTPUT_HIGH;
130 } else {
131 flags |= GPIO_OUTPUT_LOW;
132 }
133
134 *out_flags = flags;
135
136 return 0;
137 }
138 #endif /* CONFIG_GPIO_GET_CONFIG */
139
140 /**
141 * @brief Translate pin to pinval that the LL library needs
142 */
stm32_pinval_get(int pin)143 static inline uint32_t stm32_pinval_get(int pin)
144 {
145 uint32_t pinval;
146
147 #ifdef CONFIG_SOC_SERIES_STM32F1X
148 pinval = (1 << pin) << GPIO_PIN_MASK_POS;
149 if (pin < 8) {
150 pinval |= 1 << pin;
151 } else {
152 pinval |= (1 << (pin % 8)) | 0x04000000;
153 }
154 #else
155 pinval = 1 << pin;
156 #endif
157 return pinval;
158 }
159
160 /**
161 * @brief Configure the hardware.
162 */
gpio_stm32_configure_raw(const struct device * dev,int pin,int conf,int func)163 static void gpio_stm32_configure_raw(const struct device *dev, int pin,
164 int conf, int func)
165 {
166 const struct gpio_stm32_config *cfg = dev->config;
167 GPIO_TypeDef *gpio = (GPIO_TypeDef *)cfg->base;
168
169 int pin_ll = stm32_pinval_get(pin);
170
171 #ifdef CONFIG_SOC_SERIES_STM32F1X
172 ARG_UNUSED(func);
173
174 uint32_t temp = conf &
175 (STM32_MODE_INOUT_MASK << STM32_MODE_INOUT_SHIFT);
176
177 if (temp == STM32_MODE_INPUT) {
178 temp = conf & (STM32_CNF_IN_MASK << STM32_CNF_IN_SHIFT);
179
180 if (temp == STM32_CNF_IN_ANALOG) {
181 LL_GPIO_SetPinMode(gpio, pin_ll, LL_GPIO_MODE_ANALOG);
182 } else if (temp == STM32_CNF_IN_FLOAT) {
183 LL_GPIO_SetPinMode(gpio, pin_ll, LL_GPIO_MODE_FLOATING);
184 } else {
185 temp = conf & (STM32_PUPD_MASK << STM32_PUPD_SHIFT);
186
187 if (temp == STM32_PUPD_PULL_UP) {
188 LL_GPIO_SetPinPull(gpio, pin_ll,
189 LL_GPIO_PULL_UP);
190 } else {
191 LL_GPIO_SetPinPull(gpio, pin_ll,
192 LL_GPIO_PULL_DOWN);
193 }
194
195 LL_GPIO_SetPinMode(gpio, pin_ll, LL_GPIO_MODE_INPUT);
196 }
197
198 } else {
199 temp = conf & (STM32_CNF_OUT_1_MASK << STM32_CNF_OUT_1_SHIFT);
200
201 if (temp == STM32_CNF_GP_OUTPUT) {
202 LL_GPIO_SetPinMode(gpio, pin_ll, LL_GPIO_MODE_OUTPUT);
203 } else {
204 LL_GPIO_SetPinMode(gpio, pin_ll,
205 LL_GPIO_MODE_ALTERNATE);
206 }
207
208 temp = conf & (STM32_CNF_OUT_0_MASK << STM32_CNF_OUT_0_SHIFT);
209
210 if (temp == STM32_CNF_PUSH_PULL) {
211 LL_GPIO_SetPinOutputType(gpio, pin_ll,
212 LL_GPIO_OUTPUT_PUSHPULL);
213 } else {
214 LL_GPIO_SetPinOutputType(gpio, pin_ll,
215 LL_GPIO_OUTPUT_OPENDRAIN);
216 }
217
218 temp = conf &
219 (STM32_MODE_OSPEED_MASK << STM32_MODE_OSPEED_SHIFT);
220
221 if (temp == STM32_MODE_OUTPUT_MAX_2) {
222 LL_GPIO_SetPinSpeed(gpio, pin_ll,
223 LL_GPIO_SPEED_FREQ_LOW);
224 } else if (temp == STM32_MODE_OUTPUT_MAX_10) {
225 LL_GPIO_SetPinSpeed(gpio, pin_ll,
226 LL_GPIO_SPEED_FREQ_MEDIUM);
227 } else {
228 LL_GPIO_SetPinSpeed(gpio, pin_ll,
229 LL_GPIO_SPEED_FREQ_HIGH);
230 }
231 }
232 #else
233 unsigned int mode, otype, ospeed, pupd;
234
235 mode = conf & (STM32_MODER_MASK << STM32_MODER_SHIFT);
236 otype = conf & (STM32_OTYPER_MASK << STM32_OTYPER_SHIFT);
237 ospeed = conf & (STM32_OSPEEDR_MASK << STM32_OSPEEDR_SHIFT);
238 pupd = conf & (STM32_PUPDR_MASK << STM32_PUPDR_SHIFT);
239
240 z_stm32_hsem_lock(CFG_HW_GPIO_SEMID, HSEM_LOCK_DEFAULT_RETRY);
241
242 #if defined(CONFIG_SOC_SERIES_STM32L4X) && defined(GPIO_ASCR_ASC0)
243 /*
244 * For STM32L47xx/48xx, register ASCR should be configured to connect
245 * analog switch of gpio lines to the ADC.
246 */
247 if (mode == STM32_MODER_ANALOG_MODE) {
248 LL_GPIO_EnablePinAnalogControl(gpio, pin_ll);
249 }
250 #endif
251
252 LL_GPIO_SetPinOutputType(gpio, pin_ll, otype >> STM32_OTYPER_SHIFT);
253
254 LL_GPIO_SetPinSpeed(gpio, pin_ll, ospeed >> STM32_OSPEEDR_SHIFT);
255
256 LL_GPIO_SetPinPull(gpio, pin_ll, pupd >> STM32_PUPDR_SHIFT);
257
258 if (mode == STM32_MODER_ALT_MODE) {
259 if (pin < 8) {
260 LL_GPIO_SetAFPin_0_7(gpio, pin_ll, func);
261 } else {
262 LL_GPIO_SetAFPin_8_15(gpio, pin_ll, func);
263 }
264 }
265
266 LL_GPIO_SetPinMode(gpio, pin_ll, mode >> STM32_MODER_SHIFT);
267
268 z_stm32_hsem_unlock(CFG_HW_GPIO_SEMID);
269 #endif /* CONFIG_SOC_SERIES_STM32F1X */
270
271 }
272
273 /**
274 * @brief GPIO port clock handling
275 */
gpio_stm32_clock_request(const struct device * dev,bool on)276 static int gpio_stm32_clock_request(const struct device *dev, bool on)
277 {
278 const struct gpio_stm32_config *cfg = dev->config;
279 int ret;
280
281 __ASSERT_NO_MSG(dev != NULL);
282
283 /* enable clock for subsystem */
284 const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
285
286 if (on) {
287 ret = clock_control_on(clk,
288 (clock_control_subsys_t)&cfg->pclken);
289 } else {
290 ret = clock_control_off(clk,
291 (clock_control_subsys_t)&cfg->pclken);
292 }
293
294 return ret;
295 }
296
gpio_stm32_pin_to_exti_line(int pin)297 static inline uint32_t gpio_stm32_pin_to_exti_line(int pin)
298 {
299 #if defined(CONFIG_SOC_SERIES_STM32L0X) || \
300 defined(CONFIG_SOC_SERIES_STM32F0X)
301 return ((pin % 4 * 4) << 16) | (pin / 4);
302 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32g0_exti)
303 return ((pin & 0x3) << (16 + 3)) | (pin >> 2);
304 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7rs_exti)
305 /* Gives the LL_SBS_EXTI_LINEn corresponding to the pin */
306 return (((pin % 4 * 4) << LL_SBS_REGISTER_PINPOS_SHFT) | (pin / 4));
307 #else
308 return (0xF << ((pin % 4 * 4) + 16)) | (pin / 4);
309 #endif
310 }
311
312
313 /* Set the EXTI line corresponding to the PORT [STM32_PORTA .. ] and pin [0..15] */
gpio_stm32_set_exti_source(int port,int pin)314 static void gpio_stm32_set_exti_source(int port, int pin)
315 {
316 uint32_t line = gpio_stm32_pin_to_exti_line(pin);
317
318 #if defined(CONFIG_SOC_SERIES_STM32L0X) && defined(LL_SYSCFG_EXTI_PORTH)
319 /*
320 * Ports F and G are not present on some STM32L0 parts, so
321 * for these parts port H external interrupt should be enabled
322 * by writing value 0x5 instead of 0x7.
323 */
324 if (port == STM32_PORTH) {
325 port = LL_SYSCFG_EXTI_PORTH;
326 }
327 #endif
328
329 z_stm32_hsem_lock(CFG_HW_EXTI_SEMID, HSEM_LOCK_DEFAULT_RETRY);
330
331 #ifdef CONFIG_SOC_SERIES_STM32F1X
332 LL_GPIO_AF_SetEXTISource(port, line);
333
334 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32g0_exti)
335 LL_EXTI_SetEXTISource(port, line);
336 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7rs_exti)
337 LL_SBS_SetEXTISource(port, line);
338 #else
339 LL_SYSCFG_SetEXTISource(port, line);
340 #endif
341 z_stm32_hsem_unlock(CFG_HW_EXTI_SEMID);
342 }
343
344 /* Gives the PORT [STM32_PORTA .. ] corresponding to the EXTI line of the pin [0..15] */
gpio_stm32_get_exti_source(int pin)345 static int gpio_stm32_get_exti_source(int pin)
346 {
347 uint32_t line = gpio_stm32_pin_to_exti_line(pin);
348 int port;
349
350 #ifdef CONFIG_SOC_SERIES_STM32F1X
351 port = LL_GPIO_AF_GetEXTISource(line);
352 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32g0_exti)
353 port = LL_EXTI_GetEXTISource(line);
354 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7rs_exti)
355 port = LL_SBS_GetEXTISource(line);
356 #else
357 port = LL_SYSCFG_GetEXTISource(line);
358 #endif
359
360 #if defined(CONFIG_SOC_SERIES_STM32L0X) && defined(LL_SYSCFG_EXTI_PORTH)
361 /*
362 * Ports F and G are not present on some STM32L0 parts, so
363 * for these parts port H external interrupt is enabled
364 * by writing value 0x5 instead of 0x7.
365 */
366 if (port == LL_SYSCFG_EXTI_PORTH) {
367 port = STM32_PORTH;
368 }
369 #endif
370
371 return port;
372 }
373
374 /**
375 * @brief Enable EXTI of the specific line
376 */
gpio_stm32_enable_int(int port,int pin)377 static int gpio_stm32_enable_int(int port, int pin)
378 {
379 #if defined(CONFIG_SOC_SERIES_STM32F2X) || \
380 defined(CONFIG_SOC_SERIES_STM32F3X) || \
381 defined(CONFIG_SOC_SERIES_STM32F4X) || \
382 defined(CONFIG_SOC_SERIES_STM32F7X) || \
383 defined(CONFIG_SOC_SERIES_STM32H7X) || \
384 defined(CONFIG_SOC_SERIES_STM32H7RSX) || \
385 defined(CONFIG_SOC_SERIES_STM32L1X) || \
386 defined(CONFIG_SOC_SERIES_STM32L4X) || \
387 defined(CONFIG_SOC_SERIES_STM32G4X)
388 const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
389 struct stm32_pclken pclken = {
390 #if defined(CONFIG_SOC_SERIES_STM32H7X)
391 .bus = STM32_CLOCK_BUS_APB4,
392 .enr = LL_APB4_GRP1_PERIPH_SYSCFG
393 #elif defined(CONFIG_SOC_SERIES_STM32H7RSX)
394 .bus = STM32_CLOCK_BUS_APB4,
395 .enr = LL_APB4_GRP1_PERIPH_SBS
396 #else
397 .bus = STM32_CLOCK_BUS_APB2,
398 .enr = LL_APB2_GRP1_PERIPH_SYSCFG
399 #endif /* CONFIG_SOC_SERIES_STM32H7X */
400 };
401 int ret;
402
403 /* Enable SYSCFG clock */
404 ret = clock_control_on(clk, (clock_control_subsys_t) &pclken);
405 if (ret != 0) {
406 return ret;
407 }
408 #endif
409
410 gpio_stm32_set_exti_source(port, pin);
411
412 return 0;
413 }
414
gpio_stm32_port_get_raw(const struct device * dev,uint32_t * value)415 static int gpio_stm32_port_get_raw(const struct device *dev, uint32_t *value)
416 {
417 const struct gpio_stm32_config *cfg = dev->config;
418 GPIO_TypeDef *gpio = (GPIO_TypeDef *)cfg->base;
419
420 *value = LL_GPIO_ReadInputPort(gpio);
421
422 return 0;
423 }
424
gpio_stm32_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)425 static int gpio_stm32_port_set_masked_raw(const struct device *dev,
426 gpio_port_pins_t mask,
427 gpio_port_value_t value)
428 {
429 const struct gpio_stm32_config *cfg = dev->config;
430 GPIO_TypeDef *gpio = (GPIO_TypeDef *)cfg->base;
431 uint32_t port_value;
432
433 z_stm32_hsem_lock(CFG_HW_GPIO_SEMID, HSEM_LOCK_DEFAULT_RETRY);
434
435 port_value = LL_GPIO_ReadOutputPort(gpio);
436 LL_GPIO_WriteOutputPort(gpio, (port_value & ~mask) | (mask & value));
437
438 z_stm32_hsem_unlock(CFG_HW_GPIO_SEMID);
439
440 return 0;
441 }
442
gpio_stm32_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)443 static int gpio_stm32_port_set_bits_raw(const struct device *dev,
444 gpio_port_pins_t pins)
445 {
446 const struct gpio_stm32_config *cfg = dev->config;
447 GPIO_TypeDef *gpio = (GPIO_TypeDef *)cfg->base;
448
449 /*
450 * On F1 series, using LL API requires a costly pin mask translation.
451 * Skip it and use CMSIS API directly. Valid also on other series.
452 */
453 WRITE_REG(gpio->BSRR, pins);
454
455 return 0;
456 }
457
gpio_stm32_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)458 static int gpio_stm32_port_clear_bits_raw(const struct device *dev,
459 gpio_port_pins_t pins)
460 {
461 const struct gpio_stm32_config *cfg = dev->config;
462 GPIO_TypeDef *gpio = (GPIO_TypeDef *)cfg->base;
463
464 #ifdef CONFIG_SOC_SERIES_STM32F1X
465 /*
466 * On F1 series, using LL API requires a costly pin mask translation.
467 * Skip it and use CMSIS API directly.
468 */
469 WRITE_REG(gpio->BRR, pins);
470 #else
471 /* On other series, LL abstraction is needed */
472 LL_GPIO_ResetOutputPin(gpio, pins);
473 #endif
474
475 return 0;
476 }
477
gpio_stm32_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)478 static int gpio_stm32_port_toggle_bits(const struct device *dev,
479 gpio_port_pins_t pins)
480 {
481 const struct gpio_stm32_config *cfg = dev->config;
482 GPIO_TypeDef *gpio = (GPIO_TypeDef *)cfg->base;
483
484 /*
485 * On F1 series, using LL API requires a costly pin mask translation.
486 * Skip it and use CMSIS API directly. Valid also on other series.
487 */
488 z_stm32_hsem_lock(CFG_HW_GPIO_SEMID, HSEM_LOCK_DEFAULT_RETRY);
489 WRITE_REG(gpio->ODR, READ_REG(gpio->ODR) ^ pins);
490 z_stm32_hsem_unlock(CFG_HW_GPIO_SEMID);
491
492 return 0;
493 }
494
495 #ifdef CONFIG_SOC_SERIES_STM32F1X
496 #define IS_GPIO_OUT GPIO_OUT
497 #else
498 #define IS_GPIO_OUT STM32_GPIO
499 #endif
500
gpio_stm32_configure(const struct device * dev,int pin,int conf,int func)501 int gpio_stm32_configure(const struct device *dev, int pin, int conf, int func)
502 {
503 int ret;
504
505 ret = pm_device_runtime_get(dev);
506 if (ret < 0) {
507 return ret;
508 }
509
510 gpio_stm32_configure_raw(dev, pin, conf, func);
511
512 if (func == IS_GPIO_OUT) {
513 uint32_t gpio_out = conf & (STM32_ODR_MASK << STM32_ODR_SHIFT);
514
515 if (gpio_out == STM32_ODR_1) {
516 gpio_stm32_port_set_bits_raw(dev, BIT(pin));
517 } else if (gpio_out == STM32_ODR_0) {
518 gpio_stm32_port_clear_bits_raw(dev, BIT(pin));
519 }
520 }
521
522 return pm_device_runtime_put(dev);
523 }
524
525 /**
526 * @brief Configure pin or port
527 */
gpio_stm32_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)528 static int gpio_stm32_config(const struct device *dev,
529 gpio_pin_t pin, gpio_flags_t flags)
530 {
531 int err;
532 int pincfg;
533
534 /* figure out if we can map the requested GPIO
535 * configuration
536 */
537 err = gpio_stm32_flags_to_conf(flags, &pincfg);
538 if (err != 0) {
539 return err;
540 }
541
542 /* Enable device clock before configuration (requires bank writes) */
543 if (((flags & GPIO_OUTPUT) != 0) || ((flags & GPIO_INPUT) != 0)) {
544 err = pm_device_runtime_get(dev);
545 if (err < 0) {
546 return err;
547 }
548 }
549
550 if ((flags & GPIO_OUTPUT) != 0) {
551 if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
552 gpio_stm32_port_set_bits_raw(dev, BIT(pin));
553 } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
554 gpio_stm32_port_clear_bits_raw(dev, BIT(pin));
555 }
556 }
557
558 gpio_stm32_configure_raw(dev, pin, pincfg, 0);
559
560 #ifdef CONFIG_STM32_WKUP_PINS
561 if (flags & STM32_GPIO_WKUP) {
562 #ifdef CONFIG_POWEROFF
563 struct gpio_dt_spec gpio_dt_cfg = {
564 .port = dev,
565 .pin = pin,
566 .dt_flags = (gpio_dt_flags_t)flags,
567 };
568
569 if (stm32_pwr_wkup_pin_cfg_gpio((const struct gpio_dt_spec *)&gpio_dt_cfg)) {
570 LOG_ERR("Could not configure GPIO %s pin %d as a wake-up source",
571 gpio_dt_cfg.port->name, gpio_dt_cfg.pin);
572 }
573 #else
574 LOG_DBG("STM32_GPIO_WKUP flag has no effect when CONFIG_POWEROFF=n");
575 #endif /* CONFIG_POWEROFF */
576 }
577 #endif /* CONFIG_STM32_WKUP_PINS */
578
579 /* Release clock only if pin is disconnected */
580 if (((flags & GPIO_OUTPUT) == 0) && ((flags & GPIO_INPUT) == 0)) {
581 err = pm_device_runtime_put(dev);
582 if (err < 0) {
583 return err;
584 }
585 }
586
587 return 0;
588 }
589
590 #if defined(CONFIG_GPIO_GET_CONFIG) && !defined(CONFIG_SOC_SERIES_STM32F1X)
591 /**
592 * @brief Get configuration of pin
593 */
gpio_stm32_get_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t * flags)594 static int gpio_stm32_get_config(const struct device *dev,
595 gpio_pin_t pin, gpio_flags_t *flags)
596 {
597 const struct gpio_stm32_config *cfg = dev->config;
598 GPIO_TypeDef *gpio = (GPIO_TypeDef *)cfg->base;
599 struct gpio_stm32_pin pin_config;
600 int pin_ll;
601 int err;
602
603 err = pm_device_runtime_get(dev);
604 if (err < 0) {
605 return err;
606 }
607
608 pin_ll = stm32_pinval_get(pin);
609 pin_config.type = LL_GPIO_GetPinOutputType(gpio, pin_ll);
610 pin_config.pupd = LL_GPIO_GetPinPull(gpio, pin_ll);
611 pin_config.mode = LL_GPIO_GetPinMode(gpio, pin_ll);
612 pin_config.out_state = LL_GPIO_IsOutputPinSet(gpio, pin_ll);
613
614 gpio_stm32_pincfg_to_flags(pin_config, flags);
615
616 return pm_device_runtime_put(dev);
617 }
618 #endif /* CONFIG_GPIO_GET_CONFIG */
619
gpio_stm32_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)620 static int gpio_stm32_pin_interrupt_configure(const struct device *dev,
621 gpio_pin_t pin,
622 enum gpio_int_mode mode,
623 enum gpio_int_trig trig)
624 {
625 const struct gpio_stm32_config *cfg = dev->config;
626 struct gpio_stm32_data *data = dev->data;
627 int edge = 0;
628 int err = 0;
629
630 #ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT
631 if (mode == GPIO_INT_MODE_DISABLE_ONLY) {
632 stm32_exti_disable(pin);
633 goto exit;
634 } else if (mode == GPIO_INT_MODE_ENABLE_ONLY) {
635 stm32_exti_enable(pin);
636 goto exit;
637 }
638 #endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */
639
640 if (mode == GPIO_INT_MODE_DISABLED) {
641 if (gpio_stm32_get_exti_source(pin) == cfg->port) {
642 stm32_exti_disable(pin);
643 stm32_exti_unset_callback(pin);
644 stm32_exti_trigger(pin, STM32_EXTI_TRIG_NONE);
645 }
646 /* else: No irq source configured for pin. Nothing to disable */
647 goto exit;
648 }
649
650 /* Level trigger interrupts not supported */
651 if (mode == GPIO_INT_MODE_LEVEL) {
652 err = -ENOTSUP;
653 goto exit;
654 }
655
656 if (stm32_exti_set_callback(pin, gpio_stm32_isr, data) != 0) {
657 err = -EBUSY;
658 goto exit;
659 }
660
661 switch (trig) {
662 case GPIO_INT_TRIG_LOW:
663 edge = STM32_EXTI_TRIG_FALLING;
664 break;
665 case GPIO_INT_TRIG_HIGH:
666 edge = STM32_EXTI_TRIG_RISING;
667 break;
668 case GPIO_INT_TRIG_BOTH:
669 edge = STM32_EXTI_TRIG_BOTH;
670 break;
671 default:
672 err = -EINVAL;
673 goto exit;
674 }
675
676 gpio_stm32_enable_int(cfg->port, pin);
677
678 stm32_exti_trigger(pin, edge);
679
680 stm32_exti_enable(pin);
681
682 exit:
683 return err;
684 }
685
gpio_stm32_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)686 static int gpio_stm32_manage_callback(const struct device *dev,
687 struct gpio_callback *callback,
688 bool set)
689 {
690 struct gpio_stm32_data *data = dev->data;
691
692 return gpio_manage_callback(&data->cb, callback, set);
693 }
694
695 static const struct gpio_driver_api gpio_stm32_driver = {
696 .pin_configure = gpio_stm32_config,
697 #if defined(CONFIG_GPIO_GET_CONFIG) && !defined(CONFIG_SOC_SERIES_STM32F1X)
698 .pin_get_config = gpio_stm32_get_config,
699 #endif /* CONFIG_GPIO_GET_CONFIG */
700 .port_get_raw = gpio_stm32_port_get_raw,
701 .port_set_masked_raw = gpio_stm32_port_set_masked_raw,
702 .port_set_bits_raw = gpio_stm32_port_set_bits_raw,
703 .port_clear_bits_raw = gpio_stm32_port_clear_bits_raw,
704 .port_toggle_bits = gpio_stm32_port_toggle_bits,
705 .pin_interrupt_configure = gpio_stm32_pin_interrupt_configure,
706 .manage_callback = gpio_stm32_manage_callback,
707 };
708
709 #ifdef CONFIG_PM_DEVICE
gpio_stm32_pm_action(const struct device * dev,enum pm_device_action action)710 static int gpio_stm32_pm_action(const struct device *dev,
711 enum pm_device_action action)
712 {
713 switch (action) {
714 case PM_DEVICE_ACTION_RESUME:
715 return gpio_stm32_clock_request(dev, true);
716 case PM_DEVICE_ACTION_SUSPEND:
717 return gpio_stm32_clock_request(dev, false);
718 default:
719 return -ENOTSUP;
720 }
721
722 return 0;
723 }
724 #endif /* CONFIG_PM_DEVICE */
725
726
727 /**
728 * @brief Initialize GPIO port
729 *
730 * Perform basic initialization of a GPIO port. The code will
731 * enable the clock for corresponding peripheral.
732 *
733 * @param dev GPIO device struct
734 *
735 * @return 0
736 */
gpio_stm32_init(const struct device * dev)737 static int gpio_stm32_init(const struct device *dev)
738 {
739 struct gpio_stm32_data *data = dev->data;
740 int ret;
741
742 data->dev = dev;
743
744 if (!device_is_ready(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE))) {
745 return -ENODEV;
746 }
747
748 #if (defined(PWR_CR2_IOSV) || defined(PWR_SVMCR_IO2SV)) && \
749 DT_NODE_HAS_STATUS(DT_NODELABEL(gpiog), okay)
750 z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY);
751 /* Port G[15:2] requires external power supply */
752 /* Cf: L4/L5 RM, Chapter "Independent I/O supply rail" */
753 LL_PWR_EnableVddIO2();
754 z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
755 #endif
756 /* enable port clock (if runtime PM is not enabled) */
757 ret = gpio_stm32_clock_request(dev, !IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME));
758 if (ret < 0) {
759 return ret;
760 }
761
762 if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
763 pm_device_init_suspended(dev);
764 }
765 (void)pm_device_runtime_enable(dev);
766
767 return 0;
768 }
769
770 #define GPIO_DEVICE_INIT(__node, __suffix, __base_addr, __port, __cenr, __bus) \
771 static const struct gpio_stm32_config gpio_stm32_cfg_## __suffix = { \
772 .common = { \
773 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_NGPIOS(16U), \
774 }, \
775 .base = (uint32_t *)__base_addr, \
776 .port = __port, \
777 .pclken = { .bus = __bus, .enr = __cenr } \
778 }; \
779 static struct gpio_stm32_data gpio_stm32_data_## __suffix; \
780 PM_DEVICE_DT_DEFINE(__node, gpio_stm32_pm_action); \
781 DEVICE_DT_DEFINE(__node, \
782 gpio_stm32_init, \
783 PM_DEVICE_DT_GET(__node), \
784 &gpio_stm32_data_## __suffix, \
785 &gpio_stm32_cfg_## __suffix, \
786 PRE_KERNEL_1, \
787 CONFIG_GPIO_INIT_PRIORITY, \
788 &gpio_stm32_driver)
789
790 #define GPIO_DEVICE_INIT_STM32(__suffix, __SUFFIX) \
791 GPIO_DEVICE_INIT(DT_NODELABEL(gpio##__suffix), \
792 __suffix, \
793 DT_REG_ADDR(DT_NODELABEL(gpio##__suffix)), \
794 STM32_PORT##__SUFFIX, \
795 DT_CLOCKS_CELL(DT_NODELABEL(gpio##__suffix), bits),\
796 DT_CLOCKS_CELL(DT_NODELABEL(gpio##__suffix), bus))
797
798 #define GPIO_DEVICE_INIT_STM32_IF_OKAY(__suffix, __SUFFIX) \
799 COND_CODE_1(DT_NODE_HAS_STATUS(DT_NODELABEL(gpio##__suffix), okay), \
800 (GPIO_DEVICE_INIT_STM32(__suffix, __SUFFIX)), \
801 ())
802
803 GPIO_DEVICE_INIT_STM32_IF_OKAY(a, A);
804 GPIO_DEVICE_INIT_STM32_IF_OKAY(b, B);
805 GPIO_DEVICE_INIT_STM32_IF_OKAY(c, C);
806 GPIO_DEVICE_INIT_STM32_IF_OKAY(d, D);
807 GPIO_DEVICE_INIT_STM32_IF_OKAY(e, E);
808 GPIO_DEVICE_INIT_STM32_IF_OKAY(f, F);
809 GPIO_DEVICE_INIT_STM32_IF_OKAY(g, G);
810 GPIO_DEVICE_INIT_STM32_IF_OKAY(h, H);
811 GPIO_DEVICE_INIT_STM32_IF_OKAY(i, I);
812 GPIO_DEVICE_INIT_STM32_IF_OKAY(j, J);
813 GPIO_DEVICE_INIT_STM32_IF_OKAY(k, K);
814
815 GPIO_DEVICE_INIT_STM32_IF_OKAY(m, M);
816 GPIO_DEVICE_INIT_STM32_IF_OKAY(n, N);
817 GPIO_DEVICE_INIT_STM32_IF_OKAY(o, O);
818 GPIO_DEVICE_INIT_STM32_IF_OKAY(p, P);
819