/* * Copyright (c) 2016 Open-RnD Sp. z o.o. * Copyright (c) 2021 Linaro Limited * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include /** * @brief Array containing pointers to each GPIO port. * * Entries will be NULL if the GPIO port is not enabled. */ static const struct device * const gpio_ports[] = { DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpioa)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpiob)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpioc)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpiod)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpioe)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpiof)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpiog)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpioh)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpioi)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpioj)), DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpiok)), }; /** Number of GPIO ports. */ static const size_t gpio_ports_cnt = ARRAY_SIZE(gpio_ports); #if DT_NODE_HAS_PROP(DT_NODELABEL(pinctrl), remap_pa11) #define REMAP_PA11 DT_PROP(DT_NODELABEL(pinctrl), remap_pa11) #endif #if DT_NODE_HAS_PROP(DT_NODELABEL(pinctrl), remap_pa12) #define REMAP_PA12 DT_PROP(DT_NODELABEL(pinctrl), remap_pa12) #endif #if DT_NODE_HAS_PROP(DT_NODELABEL(pinctrl), remap_pa11_pa12) #define REMAP_PA11_PA12 DT_PROP(DT_NODELABEL(pinctrl), remap_pa11_pa12) #endif #if REMAP_PA11 || REMAP_PA12 || REMAP_PA11_PA12 int stm32_pinmux_init_remap(const struct device *dev) { ARG_UNUSED(dev); #if REMAP_PA11 || REMAP_PA12 #if !defined(CONFIG_SOC_SERIES_STM32G0X) #error "Pin remap property available only on STM32G0 SoC series" #endif LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG); #if REMAP_PA11 LL_SYSCFG_EnablePinRemap(LL_SYSCFG_PIN_RMP_PA11); #endif #if REMAP_PA12 LL_SYSCFG_EnablePinRemap(LL_SYSCFG_PIN_RMP_PA12); #endif #elif REMAP_PA11_PA12 #if !defined(SYSCFG_CFGR1_PA11_PA12_RMP) #error "Pin remap property available only on STM32F070x SoC series" #endif LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_SYSCFG); LL_SYSCFG_EnablePinRemap(); #endif /* (REMAP_PA11 || REMAP_PA12) || REMAP_PA11_PA12 */ return 0; } SYS_INIT(stm32_pinmux_init_remap, PRE_KERNEL_1, CONFIG_PINCTRL_STM32_REMAP_INIT_PRIORITY); #endif /* REMAP_PA11 || REMAP_PA12 || REMAP_PA11_PA12 */ #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_pinctrl) /** * @brief Helper function to check and apply provided pinctrl remap * configuration. * * Check operation verifies that pin remapping configuration is the same on all * pins. If configuration is valid AFIO clock is enabled and remap is applied * * @param pins List of pins to be configured. * @param pin_cnt Number of pins. * * @retval 0 If successful * @retval -EINVAL If pins have an incompatible set of remaps. */ static int stm32_pins_remap(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt) { uint8_t pos; uint32_t reg_val; volatile uint32_t *reg; uint16_t remap; remap = (uint8_t)STM32_DT_PINMUX_REMAP(pins[0].pinmux); /* not remappable */ if (remap == NO_REMAP) { return 0; } for (size_t i = 1U; i < pin_cnt; i++) { if (STM32_DT_PINMUX_REMAP(pins[i].pinmux) != remap) { return -EINVAL; } } /* A valid remapping configuration is available */ /* Apply remapping before proceeding with pin configuration */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO); if (STM32_REMAP_REG_GET(remap) == 0U) { reg = &AFIO->MAPR; } else { reg = &AFIO->MAPR2; } pos = STM32_REMAP_SHIFT_GET(remap); reg_val = *reg; reg_val &= ~(STM32_REMAP_MASK_GET(remap) << pos); reg_val |= STM32_REMAP_VAL_GET(remap) << pos; *reg = reg_val; return 0; } #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_pinctrl) */ static int stm32_pin_configure(uint32_t pin, uint32_t func, uint32_t altf) { const struct device *port_device; int ret = 0; if (STM32_PORT(pin) >= gpio_ports_cnt) { return -EINVAL; } port_device = gpio_ports[STM32_PORT(pin)]; if ((port_device == NULL) || (!device_is_ready(port_device))) { return -ENODEV; } #ifdef CONFIG_PM_DEVICE_RUNTIME ret = pm_device_runtime_get(port_device); if (ret < 0) { return ret; } #endif gpio_stm32_configure(port_device, STM32_PIN(pin), func, altf); #ifdef CONFIG_PM_DEVICE_RUNTIME ret = pm_device_runtime_put(port_device); #endif return ret; } int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) { uint32_t pin, mux; uint32_t func = 0; int ret = 0; ARG_UNUSED(reg); #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_pinctrl) ret = stm32_pins_remap(pins, pin_cnt); if (ret < 0) { return ret; } #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_pinctrl) */ for (uint8_t i = 0U; i < pin_cnt; i++) { mux = pins[i].pinmux; #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_pinctrl) uint32_t pupd; if (STM32_DT_PINMUX_FUNC(mux) == ALTERNATE) { func = pins[i].pincfg | STM32_MODE_OUTPUT | STM32_CNF_ALT_FUNC; } else if (STM32_DT_PINMUX_FUNC(mux) == ANALOG) { func = pins[i].pincfg | STM32_MODE_INPUT | STM32_CNF_IN_ANALOG; } else if (STM32_DT_PINMUX_FUNC(mux) == GPIO_IN) { func = pins[i].pincfg | STM32_MODE_INPUT; pupd = func & (STM32_PUPD_MASK << STM32_PUPD_SHIFT); if (pupd == STM32_PUPD_NO_PULL) { func = func | STM32_CNF_IN_FLOAT; } else { func = func | STM32_CNF_IN_PUPD; } } else { /* Not supported */ __ASSERT_NO_MSG(STM32_DT_PINMUX_FUNC(mux)); } #else if (STM32_DT_PINMUX_FUNC(mux) < STM32_ANALOG) { func = pins[i].pincfg | STM32_MODER_ALT_MODE; } else if (STM32_DT_PINMUX_FUNC(mux) == STM32_ANALOG) { func = STM32_MODER_ANALOG_MODE; } else { /* Not supported */ __ASSERT_NO_MSG(STM32_DT_PINMUX_FUNC(mux)); } #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_pinctrl) */ pin = STM32PIN(STM32_DT_PINMUX_PORT(mux), STM32_DT_PINMUX_LINE(mux)); ret = stm32_pin_configure(pin, func, STM32_DT_PINMUX_FUNC(mux)); if (ret < 0) { return ret; } } return 0; }