diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index 94676d687e2be..26aa5c825109a 100644 --- a/drivers/gpio/gpio_stm32.c +++ b/drivers/gpio/gpio_stm32.c @@ -185,49 +185,32 @@ int gpio_stm32_configure(u32_t *base_addr, int pin, int conf, int altf) return 0; } -/** - * @brief Enable EXTI of the specific line - */ -const int gpio_stm32_enable_int(int port, int pin) +static inline uint32_t gpio_stm32_pin_to_exti_line(int pin) { -#if defined(CONFIG_SOC_SERIES_STM32F2X) || \ - defined(CONFIG_SOC_SERIES_STM32F3X) || \ - defined(CONFIG_SOC_SERIES_STM32F4X) || \ - defined(CONFIG_SOC_SERIES_STM32F7X) || \ - defined(CONFIG_SOC_SERIES_STM32H7X) || \ - defined(CONFIG_SOC_SERIES_STM32L1X) || \ - defined(CONFIG_SOC_SERIES_STM32L4X) || \ - defined(CONFIG_SOC_SERIES_STM32G4X) - struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME); - struct stm32_pclken pclken = { -#ifdef CONFIG_SOC_SERIES_STM32H7X - .bus = STM32_CLOCK_BUS_APB4, - .enr = LL_APB4_GRP1_PERIPH_SYSCFG +#if defined(CONFIG_SOC_SERIES_STM32L0X) || \ + defined(CONFIG_SOC_SERIES_STM32F0X) + return ((pin % 4 * 4) << 16) | (pin / 4); +#elif defined(CONFIG_SOC_SERIES_STM32MP1X) + return (((pin * 8) % 32) << 16) | (pin / 4); +#elif defined(CONFIG_SOC_SERIES_STM32G0X) + return ((pin & 0x3) << (16 + 3)) | (pin >> 2); #else - .bus = STM32_CLOCK_BUS_APB2, - .enr = LL_APB2_GRP1_PERIPH_SYSCFG -#endif /* CONFIG_SOC_SERIES_STM32H7X */ - }; - /* Enable SYSCFG clock */ - clock_control_on(clk, (clock_control_subsys_t *) &pclken); + return (0xF << ((pin % 4 * 4) + 16)) | (pin / 4); #endif +} +/** + * @brief Set GPIO port as EXTI source for the specific pin number + */ +static int gpio_stm32_set_exti_source(int port, int pin) +{ uint32_t line; if (pin > 15) { return -EINVAL; } -#if defined(CONFIG_SOC_SERIES_STM32L0X) || \ - defined(CONFIG_SOC_SERIES_STM32F0X) - line = ((pin % 4 * 4) << 16) | (pin / 4); -#elif defined(CONFIG_SOC_SERIES_STM32MP1X) - line = (((pin * 8) % 32) << 16) | (pin / 4); -#elif defined(CONFIG_SOC_SERIES_STM32G0X) - line = ((pin & 0x3) << (16 + 3)) | (pin >> 2); -#else - line = (0xF << ((pin % 4 * 4) + 16)) | (pin / 4); -#endif + line = gpio_stm32_pin_to_exti_line(pin); #if defined(CONFIG_SOC_SERIES_STM32L0X) && defined(LL_SYSCFG_EXTI_PORTH) /* @@ -240,9 +223,9 @@ const int gpio_stm32_enable_int(int port, int pin) } #endif -#ifdef CONFIG_SOC_SERIES_STM32F1X +#if defined(CONFIG_SOC_SERIES_STM32F1X) LL_GPIO_AF_SetEXTISource(port, line); -#elif CONFIG_SOC_SERIES_STM32MP1X +#elif defined(CONFIG_SOC_SERIES_STM32MP1X) LL_EXTI_SetEXTISource(port, line); #elif defined(CONFIG_SOC_SERIES_STM32G0X) LL_EXTI_SetEXTISource(port, line); @@ -253,6 +236,74 @@ const int gpio_stm32_enable_int(int port, int pin) return 0; } +/** + * @brief Get enabled GPIO port for EXTI of the specific pin number + */ +static int gpio_stm32_get_exti_source(int pin) +{ + uint32_t line; + int port; + + if (pin > 15) { + return -EINVAL; + } + + line = gpio_stm32_pin_to_exti_line(pin); + +#if defined(CONFIG_SOC_SERIES_STM32F1X) + port = LL_GPIO_AF_GetEXTISource(line); +#elif defined(CONFIG_SOC_SERIES_STM32MP1X) + port = LL_EXTI_GetEXTISource(line); +#elif defined(CONFIG_SOC_SERIES_STM32G0X) + port = LL_EXTI_GetEXTISource(line); +#else + port = LL_SYSCFG_GetEXTISource(line); +#endif + +#if defined(CONFIG_SOC_SERIES_STM32L0X) && defined(LL_SYSCFG_EXTI_PORTH) + /* + * Ports F and G are not present on some STM32L0 parts, so + * for these parts port H external interrupt is enabled + * by writing value 0x5 instead of 0x7. + */ + if (port == LL_SYSCFG_EXTI_PORTH) { + port = STM32_PORTH; + } +#endif + + return port; +} + +/** + * @brief Enable EXTI of the specific line + */ +static int gpio_stm32_enable_int(int port, int pin) +{ +#if defined(CONFIG_SOC_SERIES_STM32F2X) || \ + defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32F4X) || \ + defined(CONFIG_SOC_SERIES_STM32F7X) || \ + defined(CONFIG_SOC_SERIES_STM32H7X) || \ + defined(CONFIG_SOC_SERIES_STM32L1X) || \ + defined(CONFIG_SOC_SERIES_STM32L4X) || \ + defined(CONFIG_SOC_SERIES_STM32G4X) + struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME); + struct stm32_pclken pclken = { +#ifdef CONFIG_SOC_SERIES_STM32H7X + .bus = STM32_CLOCK_BUS_APB4, + .enr = LL_APB4_GRP1_PERIPH_SYSCFG +#else + .bus = STM32_CLOCK_BUS_APB2, + .enr = LL_APB2_GRP1_PERIPH_SYSCFG +#endif /* CONFIG_SOC_SERIES_STM32H7X */ + }; + /* Enable SYSCFG clock */ + clock_control_on(clk, (clock_control_subsys_t *) &pclken); +#endif + + return gpio_stm32_set_exti_source(port, pin); +} + /** * @brief Configure pin or port */ @@ -260,6 +311,7 @@ static int gpio_stm32_config(struct device *dev, int access_op, u32_t pin, int flags) { const struct gpio_stm32_config *cfg = dev->config->config_info; + int err = 0; int pincfg; int map_res; @@ -282,18 +334,24 @@ static int gpio_stm32_config(struct device *dev, int access_op, */ map_res = gpio_stm32_flags_to_conf(flags, &pincfg); if (map_res != 0) { - return map_res; + err = map_res; + goto release_lock; } if (gpio_stm32_configure(cfg->base, pin, pincfg, 0) != 0) { - return -EIO; + err = -EIO; + goto release_lock; } - if (IS_ENABLED(CONFIG_EXTI_STM32) && (flags & GPIO_INT) != 0) { + if (!IS_ENABLED(CONFIG_EXTI_STM32)) { + goto release_lock; + } + if (flags & GPIO_INT) { if (stm32_exti_set_callback(pin, cfg->port, gpio_stm32_isr, dev) != 0) { - return -EBUSY; + err = -EBUSY; + goto release_lock; } gpio_stm32_enable_int(cfg->port, pin); @@ -313,20 +371,27 @@ static int gpio_stm32_config(struct device *dev, int access_op, stm32_exti_trigger(pin, edge); } else { /* Level trigger interrupts not supported */ - return -ENOTSUP; + err = -ENOTSUP; + goto release_lock; } if (stm32_exti_enable(pin) != 0) { - return -ENOSYS; + err = -EIO; + goto release_lock; + } + } else { + if (gpio_stm32_get_exti_source(pin) == cfg->port) { + stm32_exti_disable(pin); + stm32_exti_unset_callback(pin); } - } +release_lock: #if defined(CONFIG_STM32H7_DUAL_CORE) LL_HSEM_ReleaseLock(HSEM, LL_HSEM_ID_1, 0); #endif /* CONFIG_STM32H7_DUAL_CORE */ - return 0; + return err; } /**