From 41a6764c9f29bf35ed6f84a8520d6f17d3caa257 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 7 Oct 2019 10:49:17 +0200 Subject: [PATCH 1/5] drivers/gpio: stm32: Rework configure function exit for dual core With dual core handling introduction, we now need to take care to always release lock before exiting function. Rework gpio_stm32_config to take this into account. Additionally, since ENOSYS usage is resevred to system calls handling, replace with EIO. Signed-off-by: Erwan Gouriou --- drivers/gpio/gpio_stm32.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index 94676d687e2be..d292092b36a42 100644 --- a/drivers/gpio/gpio_stm32.c +++ b/drivers/gpio/gpio_stm32.c @@ -260,6 +260,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 +283,21 @@ 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 (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 +317,23 @@ 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; } } +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; } /** From 7a98feeaa472dcfebf70c4684249623aed809472 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Wed, 18 Sep 2019 18:38:35 +0200 Subject: [PATCH 2/5] gpio: stm32: statify gpio_stm32_enable_int() This allows compiler to inline function body and reduce overall code size. Signed-off-by: Marcin Niestroj --- drivers/gpio/gpio_stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index d292092b36a42..57335775d1385 100644 --- a/drivers/gpio/gpio_stm32.c +++ b/drivers/gpio/gpio_stm32.c @@ -188,7 +188,7 @@ int gpio_stm32_configure(u32_t *base_addr, int pin, int conf, int altf) /** * @brief Enable EXTI of the specific line */ -const int gpio_stm32_enable_int(int port, int pin) +static int gpio_stm32_enable_int(int port, int pin) { #if defined(CONFIG_SOC_SERIES_STM32F2X) || \ defined(CONFIG_SOC_SERIES_STM32F3X) || \ From a71b411271367adb6a60f13f26656b9d880faa37 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 14 Oct 2019 18:13:39 +0200 Subject: [PATCH 3/5] gpio: stm32: cleanup preprocessor macros Check if CONFIG_SOC_SERIES_STM32MP1X is defined instead of its value. While at it convert CONFIG_SOC_SERIES_STM32F1X check to be consistent with others. Signed-off-by: Marcin Niestroj --- drivers/gpio/gpio_stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index 57335775d1385..0b3cf7d4ee78e 100644 --- a/drivers/gpio/gpio_stm32.c +++ b/drivers/gpio/gpio_stm32.c @@ -240,9 +240,9 @@ static 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); From ae50222399971b4e0cf2ce758acee46ffff26bb4 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Wed, 18 Sep 2019 17:44:47 +0200 Subject: [PATCH 4/5] gpio: stm32: split helper functions from gpio_stm32_enable_int() This patch doesn't change functionality, but is only related to improved readability and reusability. Signed-off-by: Marcin Niestroj --- drivers/gpio/gpio_stm32.c | 79 +++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index 0b3cf7d4ee78e..214def702612c 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 - */ -static 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) /* @@ -253,6 +236,36 @@ static int gpio_stm32_enable_int(int port, int pin) return 0; } +/** + * @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 */ From 3ef472d16121d8753c8ea7d875ba8946657ccd2e Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Wed, 18 Sep 2019 23:38:02 +0200 Subject: [PATCH 5/5] gpio: stm32: support disabling and reenabling interrupts on gpio pin Up to now interrupts could be only configured once, with no way to disable them in runtime. Allow interrupts to be disabled in runtime and then properly reenabled on user request. This allows to ignore interrupts when software is not expecting them. The improvement over previously reverted patch [1] is that we disable interrupts only when we configure port for which interrupt line was previously selected. This for example prevents to disable interrupts line 2 in case PA2 was previously configured as interrupt source, but we are currently configuring PB2 as output. [1] 0951ce2d34b6 ("gpio: stm32: support disabling and reenabling interrupts on pin") Signed-off-by: Marcin Niestroj --- drivers/gpio/gpio_stm32.c | 49 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index 214def702612c..26aa5c825109a 100644 --- a/drivers/gpio/gpio_stm32.c +++ b/drivers/gpio/gpio_stm32.c @@ -236,6 +236,44 @@ static int gpio_stm32_set_exti_source(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 */ @@ -305,8 +343,11 @@ static int gpio_stm32_config(struct device *dev, int access_op, 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) { err = -EBUSY; @@ -338,7 +379,11 @@ static int gpio_stm32_config(struct device *dev, int access_op, 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: