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>
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) \
}; \

View file

@ -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 */