diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index a5807563636..c7c5898e4e6 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -38,6 +38,14 @@ #include LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL); +/* This symbol takes the value 1 if one of the device instances */ +/* is configured in dts with an optional clock */ +#if STM32_DT_INST_DEV_OPT_CLOCK_SUPPORT +#define STM32_UART_OPT_CLOCK_SUPPORT 1 +#else +#define STM32_UART_OPT_CLOCK_SUPPORT 0 +#endif + #define HAS_LPUART_1 (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart1), \ st_stm32_lpuart, okay)) @@ -93,8 +101,7 @@ static void uart_stm32_pm_policy_state_lock_put(const struct device *dev) } #endif /* CONFIG_PM */ -static inline void uart_stm32_set_baudrate(const struct device *dev, - uint32_t baud_rate) +static inline void uart_stm32_set_baudrate(const struct device *dev, uint32_t baud_rate) { const struct uart_stm32_config *config = dev->config; struct uart_stm32_data *data = dev->data; @@ -102,11 +109,20 @@ static inline void uart_stm32_set_baudrate(const struct device *dev, uint32_t clock_rate; /* Get clock rate */ - if (clock_control_get_rate(data->clock, - (clock_control_subsys_t *)&config->pclken, - &clock_rate) < 0) { - LOG_ERR("Failed call clock_control_get_rate"); - return; + if (IS_ENABLED(STM32_UART_OPT_CLOCK_SUPPORT) && (config->pclk_len > 1)) { + if (clock_control_get_rate(data->clock, + (clock_control_subsys_t)&config->pclken[1], + &clock_rate) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclken[1])"); + return; + } + } else { + if (clock_control_get_rate(data->clock, + (clock_control_subsys_t)&config->pclken[0], + &clock_rate) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclken[0])"); + return; + } } #if HAS_LPUART_1 @@ -1550,9 +1566,20 @@ static int uart_stm32_init(const struct device *dev) __uart_stm32_get_clock(dev); /* enable clock */ - if (clock_control_on(data->clock, - (clock_control_subsys_t *)&config->pclken) != 0) { - return -EIO; + err = clock_control_on(data->clock, (clock_control_subsys_t)&config->pclken[0]); + if (err != 0) { + LOG_ERR("Could not enable (LP)UART clock"); + return err; + } + + if (IS_ENABLED(STM32_UART_OPT_CLOCK_SUPPORT) && (config->pclk_len > 1)) { + err = clock_control_configure(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &config->pclken[1], + NULL); + if (err != 0) { + LOG_ERR("Could not select UART source clock"); + return err; + } } /* Configure dt provided device signals when available */ @@ -1697,10 +1724,10 @@ static void uart_stm32_irq_config_func_##index(const struct device *dev) \ #ifdef CONFIG_UART_ASYNC_API #define UART_DMA_CHANNEL(index, dir, DIR, src, dest) \ -.dma_##dir = { \ +.dma_##dir = { \ COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir), \ (UART_DMA_CHANNEL_INIT(index, dir, DIR, src, dest)), \ - (NULL)) \ + (NULL)) \ }, #else @@ -1712,15 +1739,17 @@ STM32_UART_IRQ_HANDLER_DECL(index) \ \ PINCTRL_DT_INST_DEFINE(index); \ \ +static const struct stm32_pclken pclken_##index[] = \ + STM32_DT_INST_CLOCKS(index);\ + \ static const struct uart_stm32_config uart_stm32_cfg_##index = { \ .usart = (USART_TypeDef *)DT_INST_REG_ADDR(index), \ - .pclken = { .bus = DT_INST_CLOCKS_CELL(index, bus), \ - .enr = DT_INST_CLOCKS_CELL(index, bits) \ - }, \ + .pclken = pclken_##index, \ + .pclk_len = DT_INST_NUM_CLOCKS(index), \ .hw_flow_control = DT_INST_PROP(index, hw_flow_control), \ .parity = DT_INST_ENUM_IDX_OR(index, parity, UART_CFG_PARITY_NONE), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ - .single_wire = DT_INST_PROP_OR(index, single_wire, false), \ + .single_wire = DT_INST_PROP_OR(index, single_wire, false), \ .tx_rx_swap = DT_INST_PROP_OR(index, tx_rx_swap, false), \ STM32_UART_IRQ_HANDLER_FUNC(index) \ }; \ diff --git a/drivers/serial/uart_stm32.h b/drivers/serial/uart_stm32.h index 31a5b8b917a..f8432ba7144 100644 --- a/drivers/serial/uart_stm32.h +++ b/drivers/serial/uart_stm32.h @@ -21,7 +21,9 @@ struct uart_stm32_config { /* USART instance */ USART_TypeDef *usart; /* clock subsystem driving this peripheral */ - struct stm32_pclken pclken; + const struct stm32_pclken *pclken; + /* number of clock subsystems */ + size_t pclk_len; /* initial hardware flow control, 1 for RTS/CTS */ bool hw_flow_control; /* initial parity, 0 for none, 1 for odd, 2 for even */