stm32: Allow UARTs to use alternate clocks.

Add support for an alternate clock. If available,
alternate clock is enabled and used to get the
device clock rate.
Based on: #45053.

Signed-off-by: Artur Lipowski <Artur.Lipowski@hidglobal.com>
This commit is contained in:
Artur Lipowski 2022-05-10 12:18:28 +02:00 committed by Maureen Helm
commit bb8575962d
2 changed files with 48 additions and 17 deletions

View file

@ -38,6 +38,14 @@
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL); 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), \ #define HAS_LPUART_1 (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart1), \
st_stm32_lpuart, okay)) st_stm32_lpuart, okay))
@ -93,8 +101,7 @@ static void uart_stm32_pm_policy_state_lock_put(const struct device *dev)
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static inline void uart_stm32_set_baudrate(const struct device *dev, static inline void uart_stm32_set_baudrate(const struct device *dev, uint32_t baud_rate)
uint32_t baud_rate)
{ {
const struct uart_stm32_config *config = dev->config; const struct uart_stm32_config *config = dev->config;
struct uart_stm32_data *data = dev->data; 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; uint32_t clock_rate;
/* Get clock rate */ /* Get clock rate */
if (clock_control_get_rate(data->clock, if (IS_ENABLED(STM32_UART_OPT_CLOCK_SUPPORT) && (config->pclk_len > 1)) {
(clock_control_subsys_t *)&config->pclken, if (clock_control_get_rate(data->clock,
&clock_rate) < 0) { (clock_control_subsys_t)&config->pclken[1],
LOG_ERR("Failed call clock_control_get_rate"); &clock_rate) < 0) {
return; 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 #if HAS_LPUART_1
@ -1550,9 +1566,20 @@ static int uart_stm32_init(const struct device *dev)
__uart_stm32_get_clock(dev); __uart_stm32_get_clock(dev);
/* enable clock */ /* enable clock */
if (clock_control_on(data->clock, err = clock_control_on(data->clock, (clock_control_subsys_t)&config->pclken[0]);
(clock_control_subsys_t *)&config->pclken) != 0) { if (err != 0) {
return -EIO; 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 */ /* 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 #ifdef CONFIG_UART_ASYNC_API
#define UART_DMA_CHANNEL(index, dir, DIR, src, dest) \ #define UART_DMA_CHANNEL(index, dir, DIR, src, dest) \
.dma_##dir = { \ .dma_##dir = { \
COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir), \ COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir), \
(UART_DMA_CHANNEL_INIT(index, dir, DIR, src, dest)), \ (UART_DMA_CHANNEL_INIT(index, dir, DIR, src, dest)), \
(NULL)) \ (NULL)) \
}, },
#else #else
@ -1712,15 +1739,17 @@ STM32_UART_IRQ_HANDLER_DECL(index) \
\ \
PINCTRL_DT_INST_DEFINE(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 = { \ static const struct uart_stm32_config uart_stm32_cfg_##index = { \
.usart = (USART_TypeDef *)DT_INST_REG_ADDR(index), \ .usart = (USART_TypeDef *)DT_INST_REG_ADDR(index), \
.pclken = { .bus = DT_INST_CLOCKS_CELL(index, bus), \ .pclken = pclken_##index, \
.enr = DT_INST_CLOCKS_CELL(index, bits) \ .pclk_len = DT_INST_NUM_CLOCKS(index), \
}, \
.hw_flow_control = DT_INST_PROP(index, hw_flow_control), \ .hw_flow_control = DT_INST_PROP(index, hw_flow_control), \
.parity = DT_INST_ENUM_IDX_OR(index, parity, UART_CFG_PARITY_NONE), \ .parity = DT_INST_ENUM_IDX_OR(index, parity, UART_CFG_PARITY_NONE), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ .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), \ .tx_rx_swap = DT_INST_PROP_OR(index, tx_rx_swap, false), \
STM32_UART_IRQ_HANDLER_FUNC(index) \ STM32_UART_IRQ_HANDLER_FUNC(index) \
}; \ }; \

View file

@ -21,7 +21,9 @@ struct uart_stm32_config {
/* USART instance */ /* USART instance */
USART_TypeDef *usart; USART_TypeDef *usart;
/* clock subsystem driving this peripheral */ /* 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 */ /* initial hardware flow control, 1 for RTS/CTS */
bool hw_flow_control; bool hw_flow_control;
/* initial parity, 0 for none, 1 for odd, 2 for even */ /* initial parity, 0 for none, 1 for odd, 2 for even */