blob: d0c511b3b4abaa02e06ab82e70575e6fcb350dd2 [file] [log] [blame]
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001/*
2 * Copyright (c) 2016 Open-RnD Sp. z o.o.
Erwan Gouriou8c079e92016-11-14 11:53:52 +01003 * Copyright (c) 2016 Linaro Limited.
Abderrahmane Jarmounie783aaf2024-03-20 15:25:14 +01004 * Copyright (c) 2024 STMicroelectronics
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01005 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08006 * SPDX-License-Identifier: Apache-2.0
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01007 */
8
Kumar Gala989484b2020-03-24 14:28:48 -05009#define DT_DRV_COMPAT st_stm32_uart
10
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010011/**
Ilya Tagunov84cffc72018-03-20 20:44:45 +030012 * @brief Driver for UART port on STM32 family processor.
Georgij Cernysiov78eed342019-03-15 19:51:09 +010013 * @note LPUART and U(S)ART have the same base and
14 * majority of operations are performed the same way.
15 * Please validate for newly added series.
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010016 */
17
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020018#include <zephyr/kernel.h>
19#include <zephyr/arch/cpu.h>
20#include <zephyr/sys/__assert.h>
Kumar Galaaa2bdbe2018-10-31 12:44:45 -050021#include <soc.h>
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020022#include <zephyr/init.h>
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020023#include <zephyr/drivers/clock_control.h>
24#include <zephyr/pm/policy.h>
Erwan Gourioua439c042022-08-03 14:39:59 +020025#include <zephyr/pm/device.h>
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010026
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +020027#ifdef CONFIG_UART_ASYNC_API
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020028#include <zephyr/drivers/dma/dma_stm32.h>
29#include <zephyr/drivers/dma.h>
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +020030#endif
31
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020032#include <zephyr/linker/sections.h>
33#include <zephyr/drivers/clock_control/stm32_clock_control.h>
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010034#include "uart_stm32.h"
35
Gerard Marull-Paretase83fab32020-10-03 23:58:36 +020036#include <stm32_ll_usart.h>
37#include <stm32_ll_lpuart.h>
Francois Ramu9926b902022-09-16 10:41:18 +020038#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE)
39#include <stm32_ll_exti.h>
40#endif /* CONFIG_PM */
Gerard Marull-Paretase83fab32020-10-03 23:58:36 +020041
Abderrahmane Jarmounie783aaf2024-03-20 15:25:14 +010042#ifdef CONFIG_DCACHE
43#include <zephyr/linker/linker-defs.h>
44#include <zephyr/mem_mgmt/mem_attr.h>
45#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
46#endif /* CONFIG_DCACHE */
47
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020048#include <zephyr/logging/log.h>
Gerard Marull-Paretas178bdc42022-10-17 10:24:11 +020049#include <zephyr/irq.h>
Pete Dietl060e39e2022-03-04 12:56:05 -080050LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL);
Francois Ramud3ffa8d2019-11-12 16:13:03 +010051
Artur Lipowskibb857592022-05-10 12:18:28 +020052/* This symbol takes the value 1 if one of the device instances */
Erwan Gouriou1ef9e9e2022-08-04 11:08:15 +020053/* is configured in dts with a domain clock */
54#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
55#define STM32_UART_DOMAIN_CLOCK_SUPPORT 1
Artur Lipowskibb857592022-05-10 12:18:28 +020056#else
Erwan Gouriou1ef9e9e2022-08-04 11:08:15 +020057#define STM32_UART_DOMAIN_CLOCK_SUPPORT 0
Artur Lipowskibb857592022-05-10 12:18:28 +020058#endif
59
Nando Galliardb9748b52023-10-16 12:20:23 +020060#define HAS_LPUART DT_HAS_COMPAT_STATUS_OKAY(st_stm32_lpuart)
Erwan Gouriou76313f02020-04-17 12:33:29 +020061
Armin Braunsb95cdb22023-05-22 14:29:23 +000062/* Available everywhere except l1, f1, f2, f4. */
63#ifdef USART_CR3_DEM
64#define HAS_DRIVER_ENABLE 1
65#else
66#define HAS_DRIVER_ENABLE 0
67#endif
68
Mathieu Choplainb1b85fc2024-08-22 16:50:37 +020069#ifdef CONFIG_PM
70/* Placeholder value when wakeup-line DT property is not defined */
71#define STM32_WAKEUP_LINE_NONE 0xFFFFFFFF
72#endif
73
Nando Galliardb9748b52023-10-16 12:20:23 +020074#if HAS_LPUART
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +080075#ifdef USART_PRESC_PRESCALER
76uint32_t lpuartdiv_calc(const uint64_t clock_rate, const uint16_t presc_idx,
77 const uint32_t baud_rate)
78{
79 uint64_t lpuartdiv;
80
81 lpuartdiv = clock_rate / LPUART_PRESCALER_TAB[presc_idx];
82 lpuartdiv *= LPUART_LPUARTDIV_FREQ_MUL;
83 lpuartdiv += baud_rate / 2;
84 lpuartdiv /= baud_rate;
85
86 return (uint32_t)lpuartdiv;
87}
88#else
89uint32_t lpuartdiv_calc(const uint64_t clock_rate, const uint32_t baud_rate)
90{
91 uint64_t lpuartdiv;
92
93 lpuartdiv = clock_rate * LPUART_LPUARTDIV_FREQ_MUL;
94 lpuartdiv += baud_rate / 2;
95 lpuartdiv /= baud_rate;
96
97 return (uint32_t)lpuartdiv;
98}
99#endif /* USART_PRESC_PRESCALER */
Nando Galliardb9748b52023-10-16 12:20:23 +0200100#endif /* HAS_LPUART */
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +0800101
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200102#ifdef CONFIG_PM
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +0100103static void uart_stm32_pm_policy_state_lock_get(const struct device *dev)
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200104{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100105 struct uart_stm32_data *data = dev->data;
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200106
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +0100107 if (!data->pm_policy_state_on) {
108 data->pm_policy_state_on = true;
Carlo Caione69b28bf2022-04-07 13:06:12 +0200109 pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
Guillaume Gautierbe26c712024-01-17 09:02:53 +0100110 if (IS_ENABLED(CONFIG_PM_S2RAM)) {
111 pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES);
112 }
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200113 }
114}
115
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +0100116static void uart_stm32_pm_policy_state_lock_put(const struct device *dev)
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200117{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100118 struct uart_stm32_data *data = dev->data;
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200119
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +0100120 if (data->pm_policy_state_on) {
121 data->pm_policy_state_on = false;
Carlo Caione69b28bf2022-04-07 13:06:12 +0200122 pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
Guillaume Gautierbe26c712024-01-17 09:02:53 +0100123 if (IS_ENABLED(CONFIG_PM_S2RAM)) {
124 pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES);
125 }
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200126 }
127}
128#endif /* CONFIG_PM */
129
Artur Lipowskibb857592022-05-10 12:18:28 +0200130static inline void uart_stm32_set_baudrate(const struct device *dev, uint32_t baud_rate)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800131{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100132 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700133 USART_TypeDef *usart = config->usart;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100134 struct uart_stm32_data *data = dev->data;
Erwan Gouriou69a28962019-05-20 17:15:02 +0200135
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500136 uint32_t clock_rate;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800137
138 /* Get clock rate */
Erwan Gouriou1ef9e9e2022-08-04 11:08:15 +0200139 if (IS_ENABLED(STM32_UART_DOMAIN_CLOCK_SUPPORT) && (config->pclk_len > 1)) {
Artur Lipowskibb857592022-05-10 12:18:28 +0200140 if (clock_control_get_rate(data->clock,
141 (clock_control_subsys_t)&config->pclken[1],
142 &clock_rate) < 0) {
143 LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
144 return;
145 }
146 } else {
147 if (clock_control_get_rate(data->clock,
148 (clock_control_subsys_t)&config->pclken[0],
149 &clock_rate) < 0) {
150 LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
151 return;
152 }
Francois Ramud3ffa8d2019-11-12 16:13:03 +0100153 }
Erwan Gouriou69a28962019-05-20 17:15:02 +0200154
Nando Galliardb9748b52023-10-16 12:20:23 +0200155#if HAS_LPUART
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700156 if (IS_LPUART_INSTANCE(usart)) {
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +0800157 uint32_t lpuartdiv;
158#ifdef USART_PRESC_PRESCALER
159 uint8_t presc_idx;
160 uint32_t presc_val;
161
162 for (presc_idx = 0; presc_idx < ARRAY_SIZE(LPUART_PRESCALER_TAB); presc_idx++) {
163 lpuartdiv = lpuartdiv_calc(clock_rate, presc_idx, baud_rate);
164 if (lpuartdiv >= LPUART_BRR_MIN_VALUE && lpuartdiv <= LPUART_BRR_MASK) {
165 break;
166 }
167 }
168
169 if (presc_idx == ARRAY_SIZE(LPUART_PRESCALER_TAB)) {
170 LOG_ERR("Unable to set %s to %d", dev->name, baud_rate);
171 return;
172 }
173
174 presc_val = presc_idx << USART_PRESC_PRESCALER_Pos;
175
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700176 LL_LPUART_SetPrescaler(usart, presc_val);
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +0800177#else
178 lpuartdiv = lpuartdiv_calc(clock_rate, baud_rate);
179 if (lpuartdiv < LPUART_BRR_MIN_VALUE || lpuartdiv > LPUART_BRR_MASK) {
180 LOG_ERR("Unable to set %s to %d", dev->name, baud_rate);
181 return;
182 }
183#endif /* USART_PRESC_PRESCALER */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700184 LL_LPUART_SetBaudRate(usart,
Erwan Gouriou69a28962019-05-20 17:15:02 +0200185 clock_rate,
186#ifdef USART_PRESC_PRESCALER
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +0800187 presc_val,
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800188#endif
Erwan Gouriou69a28962019-05-20 17:15:02 +0200189 baud_rate);
Francois Ramu7b958032022-09-08 17:26:29 +0200190 /* Check BRR is greater than or equal to 0x300 */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700191 __ASSERT(LL_LPUART_ReadReg(usart, BRR) >= 0x300U,
Francois Ramu7b958032022-09-08 17:26:29 +0200192 "BaudRateReg >= 0x300");
193
194 /* Check BRR is lower than or equal to 0xFFFFF */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700195 __ASSERT(LL_LPUART_ReadReg(usart, BRR) < 0x000FFFFFU,
Francois Ramu7b958032022-09-08 17:26:29 +0200196 "BaudRateReg < 0xFFFF");
Erwan Gouriou69a28962019-05-20 17:15:02 +0200197 } else {
Nando Galliardb9748b52023-10-16 12:20:23 +0200198#endif /* HAS_LPUART */
Erwan Gouriou37c7b892021-01-08 10:54:46 +0100199#ifdef USART_CR1_OVER8
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700200 LL_USART_SetOverSampling(usart,
Erwan Gouriou37c7b892021-01-08 10:54:46 +0100201 LL_USART_OVERSAMPLING_16);
202#endif
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700203 LL_USART_SetBaudRate(usart,
Erwan Gouriou69a28962019-05-20 17:15:02 +0200204 clock_rate,
205#ifdef USART_PRESC_PRESCALER
206 LL_USART_PRESCALER_DIV1,
207#endif
208#ifdef USART_CR1_OVER8
209 LL_USART_OVERSAMPLING_16,
210#endif
211 baud_rate);
Francois Ramu7b958032022-09-08 17:26:29 +0200212 /* Check BRR is greater than or equal to 16d */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700213 __ASSERT(LL_USART_ReadReg(usart, BRR) >= 16,
Francois Ramu7b958032022-09-08 17:26:29 +0200214 "BaudRateReg >= 16");
Erwan Gouriou69a28962019-05-20 17:15:02 +0200215
Nando Galliardb9748b52023-10-16 12:20:23 +0200216#if HAS_LPUART
Erwan Gouriou69a28962019-05-20 17:15:02 +0200217 }
Nando Galliardb9748b52023-10-16 12:20:23 +0200218#endif /* HAS_LPUART */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800219}
220
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200221static inline void uart_stm32_set_parity(const struct device *dev,
222 uint32_t parity)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800223{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100224 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800225
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100226 LL_USART_SetParity(config->usart, parity);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800227}
228
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200229static inline uint32_t uart_stm32_get_parity(const struct device *dev)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800230{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100231 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800232
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100233 return LL_USART_GetParity(config->usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800234}
235
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200236static inline void uart_stm32_set_stopbits(const struct device *dev,
237 uint32_t stopbits)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800238{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100239 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800240
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100241 LL_USART_SetStopBitsLength(config->usart, stopbits);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800242}
243
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200244static inline uint32_t uart_stm32_get_stopbits(const struct device *dev)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800245{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100246 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800247
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100248 return LL_USART_GetStopBitsLength(config->usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800249}
250
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200251static inline void uart_stm32_set_databits(const struct device *dev,
252 uint32_t databits)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800253{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100254 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800255
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100256 LL_USART_SetDataWidth(config->usart, databits);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800257}
258
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200259static inline uint32_t uart_stm32_get_databits(const struct device *dev)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800260{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100261 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800262
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100263 return LL_USART_GetDataWidth(config->usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800264}
265
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200266static inline void uart_stm32_set_hwctrl(const struct device *dev,
267 uint32_t hwctrl)
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100268{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100269 const struct uart_stm32_config *config = dev->config;
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100270
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100271 LL_USART_SetHWFlowCtrl(config->usart, hwctrl);
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100272}
273
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200274static inline uint32_t uart_stm32_get_hwctrl(const struct device *dev)
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100275{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100276 const struct uart_stm32_config *config = dev->config;
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100277
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100278 return LL_USART_GetHWFlowCtrl(config->usart);
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100279}
280
Armin Braunsb95cdb22023-05-22 14:29:23 +0000281#if HAS_DRIVER_ENABLE
282static inline void uart_stm32_set_driver_enable(const struct device *dev,
283 bool driver_enable)
284{
285 const struct uart_stm32_config *config = dev->config;
286
287 if (driver_enable) {
288 LL_USART_EnableDEMode(config->usart);
289 } else {
290 LL_USART_DisableDEMode(config->usart);
291 }
292}
293
294static inline bool uart_stm32_get_driver_enable(const struct device *dev)
295{
296 const struct uart_stm32_config *config = dev->config;
297
298 return LL_USART_IsEnabledDEMode(config->usart);
299}
300#endif
301
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500302static inline uint32_t uart_stm32_cfg2ll_parity(enum uart_config_parity parity)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800303{
304 switch (parity) {
305 case UART_CFG_PARITY_ODD:
306 return LL_USART_PARITY_ODD;
307 case UART_CFG_PARITY_EVEN:
308 return LL_USART_PARITY_EVEN;
309 case UART_CFG_PARITY_NONE:
310 default:
311 return LL_USART_PARITY_NONE;
312 }
313}
314
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500315static inline enum uart_config_parity uart_stm32_ll2cfg_parity(uint32_t parity)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800316{
317 switch (parity) {
318 case LL_USART_PARITY_ODD:
319 return UART_CFG_PARITY_ODD;
320 case LL_USART_PARITY_EVEN:
321 return UART_CFG_PARITY_EVEN;
322 case LL_USART_PARITY_NONE:
323 default:
324 return UART_CFG_PARITY_NONE;
325 }
326}
327
Jeroen van Dooren250e1f92023-02-06 09:39:37 +0100328static inline uint32_t uart_stm32_cfg2ll_stopbits(const struct uart_stm32_config *config,
329 enum uart_config_stop_bits sb)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800330{
331 switch (sb) {
332/* Some MCU's don't support 0.5 stop bits */
333#ifdef LL_USART_STOPBITS_0_5
334 case UART_CFG_STOP_BITS_0_5:
Nando Galliardb9748b52023-10-16 12:20:23 +0200335#if HAS_LPUART
Jeroen van Dooren250e1f92023-02-06 09:39:37 +0100336 if (IS_LPUART_INSTANCE(config->usart)) {
337 /* return the default */
338 return LL_USART_STOPBITS_1;
339 }
Nando Galliardb9748b52023-10-16 12:20:23 +0200340#endif /* HAS_LPUART */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800341 return LL_USART_STOPBITS_0_5;
342#endif /* LL_USART_STOPBITS_0_5 */
343 case UART_CFG_STOP_BITS_1:
344 return LL_USART_STOPBITS_1;
345/* Some MCU's don't support 1.5 stop bits */
346#ifdef LL_USART_STOPBITS_1_5
347 case UART_CFG_STOP_BITS_1_5:
Nando Galliardb9748b52023-10-16 12:20:23 +0200348#if HAS_LPUART
Jeroen van Dooren250e1f92023-02-06 09:39:37 +0100349 if (IS_LPUART_INSTANCE(config->usart)) {
350 /* return the default */
351 return LL_USART_STOPBITS_2;
352 }
353#endif
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800354 return LL_USART_STOPBITS_1_5;
355#endif /* LL_USART_STOPBITS_1_5 */
356 case UART_CFG_STOP_BITS_2:
357 default:
358 return LL_USART_STOPBITS_2;
359 }
360}
361
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500362static inline enum uart_config_stop_bits uart_stm32_ll2cfg_stopbits(uint32_t sb)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800363{
364 switch (sb) {
365/* Some MCU's don't support 0.5 stop bits */
366#ifdef LL_USART_STOPBITS_0_5
367 case LL_USART_STOPBITS_0_5:
368 return UART_CFG_STOP_BITS_0_5;
369#endif /* LL_USART_STOPBITS_0_5 */
370 case LL_USART_STOPBITS_1:
371 return UART_CFG_STOP_BITS_1;
372/* Some MCU's don't support 1.5 stop bits */
373#ifdef LL_USART_STOPBITS_1_5
374 case LL_USART_STOPBITS_1_5:
375 return UART_CFG_STOP_BITS_1_5;
376#endif /* LL_USART_STOPBITS_1_5 */
377 case LL_USART_STOPBITS_2:
378 default:
379 return UART_CFG_STOP_BITS_2;
380 }
381}
382
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100383static inline uint32_t uart_stm32_cfg2ll_databits(enum uart_config_data_bits db,
384 enum uart_config_parity p)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800385{
386 switch (db) {
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100387/* Some MCU's don't support 7B or 9B datawidth */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800388#ifdef LL_USART_DATAWIDTH_7B
389 case UART_CFG_DATA_BITS_7:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100390 if (p == UART_CFG_PARITY_NONE) {
391 return LL_USART_DATAWIDTH_7B;
392 } else {
393 return LL_USART_DATAWIDTH_8B;
394 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800395#endif /* LL_USART_DATAWIDTH_7B */
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100396#ifdef LL_USART_DATAWIDTH_9B
397 case UART_CFG_DATA_BITS_9:
398 return LL_USART_DATAWIDTH_9B;
399#endif /* LL_USART_DATAWIDTH_9B */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800400 case UART_CFG_DATA_BITS_8:
401 default:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100402 if (p == UART_CFG_PARITY_NONE) {
403 return LL_USART_DATAWIDTH_8B;
404#ifdef LL_USART_DATAWIDTH_9B
405 } else {
406 return LL_USART_DATAWIDTH_9B;
407#endif
408 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800409 return LL_USART_DATAWIDTH_8B;
410 }
411}
412
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100413static inline enum uart_config_data_bits uart_stm32_ll2cfg_databits(uint32_t db,
414 uint32_t p)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800415{
416 switch (db) {
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100417/* Some MCU's don't support 7B or 9B datawidth */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800418#ifdef LL_USART_DATAWIDTH_7B
419 case LL_USART_DATAWIDTH_7B:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100420 if (p == LL_USART_PARITY_NONE) {
421 return UART_CFG_DATA_BITS_7;
422 } else {
423 return UART_CFG_DATA_BITS_6;
424 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800425#endif /* LL_USART_DATAWIDTH_7B */
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100426#ifdef LL_USART_DATAWIDTH_9B
427 case LL_USART_DATAWIDTH_9B:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100428 if (p == LL_USART_PARITY_NONE) {
429 return UART_CFG_DATA_BITS_9;
430 } else {
431 return UART_CFG_DATA_BITS_8;
432 }
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100433#endif /* LL_USART_DATAWIDTH_9B */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800434 case LL_USART_DATAWIDTH_8B:
435 default:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100436 if (p == LL_USART_PARITY_NONE) {
437 return UART_CFG_DATA_BITS_8;
438 } else {
439 return UART_CFG_DATA_BITS_7;
440 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800441 }
442}
443
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100444/**
445 * @brief Get LL hardware flow control define from
446 * Zephyr hardware flow control option.
Armin Braunsb95cdb22023-05-22 14:29:23 +0000447 * @note Supports only UART_CFG_FLOW_CTRL_RTS_CTS and UART_CFG_FLOW_CTRL_RS485.
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100448 * @param fc: Zephyr hardware flow control option.
449 * @retval LL_USART_HWCONTROL_RTS_CTS, or LL_USART_HWCONTROL_NONE.
450 */
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500451static inline uint32_t uart_stm32_cfg2ll_hwctrl(enum uart_config_flow_control fc)
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100452{
453 if (fc == UART_CFG_FLOW_CTRL_RTS_CTS) {
454 return LL_USART_HWCONTROL_RTS_CTS;
Armin Braunsb95cdb22023-05-22 14:29:23 +0000455 } else if (fc == UART_CFG_FLOW_CTRL_RS485) {
456 /* Driver Enable is handled separately */
457 return LL_USART_HWCONTROL_NONE;
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100458 }
459
460 return LL_USART_HWCONTROL_NONE;
461}
462
463/**
Yannis Damigosa4b448e2020-02-06 20:36:03 +0200464 * @brief Get Zephyr hardware flow control option from
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100465 * LL hardware flow control define.
466 * @note Supports only LL_USART_HWCONTROL_RTS_CTS.
Yannis Damigosa4b448e2020-02-06 20:36:03 +0200467 * @param fc: LL hardware flow control definition.
Kumar Gala61153462020-02-06 11:30:05 -0600468 * @retval UART_CFG_FLOW_CTRL_RTS_CTS, or UART_CFG_FLOW_CTRL_NONE.
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100469 */
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500470static inline enum uart_config_flow_control uart_stm32_ll2cfg_hwctrl(uint32_t fc)
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100471{
472 if (fc == LL_USART_HWCONTROL_RTS_CTS) {
473 return UART_CFG_FLOW_CTRL_RTS_CTS;
474 }
475
Kumar Gala61153462020-02-06 11:30:05 -0600476 return UART_CFG_FLOW_CTRL_NONE;
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100477}
478
Kenneth J. Miller5217a172023-06-20 01:39:32 +0200479static void uart_stm32_parameters_set(const struct device *dev,
480 const struct uart_config *cfg)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800481{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100482 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100483 struct uart_stm32_data *data = dev->data;
Kenneth J. Millerc8ffeb42023-06-20 01:16:42 +0200484 struct uart_config *uart_cfg = data->uart_cfg;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500485 const uint32_t parity = uart_stm32_cfg2ll_parity(cfg->parity);
Jeroen van Dooren250e1f92023-02-06 09:39:37 +0100486 const uint32_t stopbits = uart_stm32_cfg2ll_stopbits(config, cfg->stop_bits);
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100487 const uint32_t databits = uart_stm32_cfg2ll_databits(cfg->data_bits,
488 cfg->parity);
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500489 const uint32_t flowctrl = uart_stm32_cfg2ll_hwctrl(cfg->flow_ctrl);
Armin Braunsb95cdb22023-05-22 14:29:23 +0000490#if HAS_DRIVER_ENABLE
491 bool driver_enable = cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485;
492#endif
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800493
Kenneth J. Miller5217a172023-06-20 01:39:32 +0200494 if (cfg == uart_cfg) {
495 /* Called via (re-)init function, so the SoC either just booted,
496 * or is returning from a low-power state where it lost register
497 * contents
498 */
499 LL_USART_ConfigCharacter(config->usart,
500 databits,
501 parity,
502 stopbits);
503 uart_stm32_set_hwctrl(dev, flowctrl);
504 uart_stm32_set_baudrate(dev, cfg->baudrate);
505 } else {
506 /* Called from application/subsys via uart_configure syscall */
507 if (parity != uart_stm32_get_parity(dev)) {
508 uart_stm32_set_parity(dev, parity);
509 }
510
511 if (stopbits != uart_stm32_get_stopbits(dev)) {
512 uart_stm32_set_stopbits(dev, stopbits);
513 }
514
515 if (databits != uart_stm32_get_databits(dev)) {
516 uart_stm32_set_databits(dev, databits);
517 }
518
519 if (flowctrl != uart_stm32_get_hwctrl(dev)) {
520 uart_stm32_set_hwctrl(dev, flowctrl);
521 }
522
523#if HAS_DRIVER_ENABLE
524 if (driver_enable != uart_stm32_get_driver_enable(dev)) {
525 uart_stm32_set_driver_enable(dev, driver_enable);
526 }
527#endif
528
529 if (cfg->baudrate != uart_cfg->baudrate) {
530 uart_stm32_set_baudrate(dev, cfg->baudrate);
531 uart_cfg->baudrate = cfg->baudrate;
532 }
533 }
534}
535
536#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
537static int uart_stm32_configure(const struct device *dev,
538 const struct uart_config *cfg)
539{
540 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700541 USART_TypeDef *usart = config->usart;
Kenneth J. Miller5217a172023-06-20 01:39:32 +0200542 struct uart_stm32_data *data = dev->data;
543 struct uart_config *uart_cfg = data->uart_cfg;
544 const uint32_t parity = uart_stm32_cfg2ll_parity(cfg->parity);
545 const uint32_t stopbits = uart_stm32_cfg2ll_stopbits(config, cfg->stop_bits);
546 const uint32_t databits = uart_stm32_cfg2ll_databits(cfg->data_bits,
547 cfg->parity);
548
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800549 /* Hardware doesn't support mark or space parity */
Erwan Gouriou5e561702021-02-11 09:55:38 +0100550 if ((cfg->parity == UART_CFG_PARITY_MARK) ||
551 (cfg->parity == UART_CFG_PARITY_SPACE)) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800552 return -ENOTSUP;
553 }
554
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100555 /* Driver does not supports parity + 9 databits */
556 if ((cfg->parity != UART_CFG_PARITY_NONE) &&
557 (cfg->data_bits == UART_CFG_DATA_BITS_9)) {
558 return -ENOTSUP;
559 }
560
Jeroen van Dooren250e1f92023-02-06 09:39:37 +0100561 /* When the transformed ll stop bits don't match with what was requested, then it's not
562 * supported
563 */
564 if (uart_stm32_ll2cfg_stopbits(stopbits) != cfg->stop_bits) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800565 return -ENOTSUP;
566 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800567
Jeroen van Dooren250e1f92023-02-06 09:39:37 +0100568 /* When the transformed ll databits don't match with what was requested, then it's not
569 * supported
570 */
571 if (uart_stm32_ll2cfg_databits(databits, parity) != cfg->data_bits) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800572 return -ENOTSUP;
573 }
574
Armin Braunsb95cdb22023-05-22 14:29:23 +0000575 /* Driver supports only RTS/CTS and RS485 flow control */
576 if (!(cfg->flow_ctrl == UART_CFG_FLOW_CTRL_NONE
577 || (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS &&
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700578 IS_UART_HWFLOW_INSTANCE(usart))
Armin Braunsb95cdb22023-05-22 14:29:23 +0000579#if HAS_DRIVER_ENABLE
580 || (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485 &&
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700581 IS_UART_DRIVER_ENABLE_INSTANCE(usart))
Armin Braunsb95cdb22023-05-22 14:29:23 +0000582#endif
583 )) {
584 return -ENOTSUP;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800585 }
586
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700587 LL_USART_Disable(usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800588
Pisit Sawangvongananb4567fa2024-01-13 00:34:18 +0700589 /* Set basic parameters, such as data-/stop-bit, parity, and baudrate */
Kenneth J. Miller5217a172023-06-20 01:39:32 +0200590 uart_stm32_parameters_set(dev, cfg);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800591
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700592 LL_USART_Enable(usart);
Kenneth J. Miller5217a172023-06-20 01:39:32 +0200593
594 /* Upon successful configuration, persist the syscall-passed
595 * uart_config.
596 * This allows restoring it, should the device return from a low-power
597 * mode in which register contents are lost.
598 */
599 *uart_cfg = *cfg;
600
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800601 return 0;
602};
603
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200604static int uart_stm32_config_get(const struct device *dev,
605 struct uart_config *cfg)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800606{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100607 struct uart_stm32_data *data = dev->data;
Kenneth J. Millerc8ffeb42023-06-20 01:16:42 +0200608 struct uart_config *uart_cfg = data->uart_cfg;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800609
Kenneth J. Millerc8ffeb42023-06-20 01:16:42 +0200610 cfg->baudrate = uart_cfg->baudrate;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800611 cfg->parity = uart_stm32_ll2cfg_parity(uart_stm32_get_parity(dev));
612 cfg->stop_bits = uart_stm32_ll2cfg_stopbits(
613 uart_stm32_get_stopbits(dev));
614 cfg->data_bits = uart_stm32_ll2cfg_databits(
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100615 uart_stm32_get_databits(dev), uart_stm32_get_parity(dev));
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100616 cfg->flow_ctrl = uart_stm32_ll2cfg_hwctrl(
617 uart_stm32_get_hwctrl(dev));
Armin Braunsb95cdb22023-05-22 14:29:23 +0000618#if HAS_DRIVER_ENABLE
619 if (uart_stm32_get_driver_enable(dev)) {
620 cfg->flow_ctrl = UART_CFG_FLOW_CTRL_RS485;
621 }
622#endif
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800623 return 0;
624}
Daniel Leung4e1692f2021-05-26 12:33:37 -0700625#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800626
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100627typedef void (*poll_in_fn)(
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700628 USART_TypeDef *usart,
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100629 void *in);
630
631static int uart_stm32_poll_in_visitor(const struct device *dev, void *in, poll_in_fn get_fn)
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100632{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100633 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700634 USART_TypeDef *usart = config->usart;
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100635
Kiril Zyapkov7a602fc2018-11-02 15:34:56 +0200636 /* Clear overrun error flag */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700637 if (LL_USART_IsActiveFlag_ORE(usart)) {
638 LL_USART_ClearFlag_ORE(usart);
Kiril Zyapkov7a602fc2018-11-02 15:34:56 +0200639 }
640
Francois Ramu860bd872022-01-28 16:52:28 +0100641 /*
642 * On stm32 F4X, F1X, and F2X, the RXNE flag is affected (cleared) by
643 * the uart_err_check function call (on errors flags clearing)
644 */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700645 if (!LL_USART_IsActiveFlag_RXNE(usart)) {
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100646 return -1;
647 }
Erwan Gouriouda210ba2017-09-21 15:20:53 +0200648
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700649 get_fn(usart, in);
Erwan Gouriouda210ba2017-09-21 15:20:53 +0200650
651 return 0;
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100652}
653
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100654typedef void (*poll_out_fn)(
Pisit Sawangvonganan3a6e36d2024-11-10 00:03:03 +0700655 USART_TypeDef *usart, uint16_t out);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100656
Pisit Sawangvonganan3a6e36d2024-11-10 00:03:03 +0700657static void uart_stm32_poll_out_visitor(const struct device *dev, uint16_t out, poll_out_fn set_fn)
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100658{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100659 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700660 USART_TypeDef *usart = config->usart;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100661#ifdef CONFIG_PM
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100662 struct uart_stm32_data *data = dev->data;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100663#endif
Johann Fischer5e5ea9a2022-07-13 16:50:25 +0200664 unsigned int key;
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100665
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100666 /* Wait for TXE flag to be raised
667 * When TXE flag is raised, we lock interrupts to prevent interrupts (notably that of usart)
668 * or thread switch. Then, we can safely send our character. The character sent will be
669 * interlaced with the characters potentially send with interrupt transmission API
670 */
Julien D'ascenziod42cef12021-11-08 12:47:25 +0100671 while (1) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700672 if (LL_USART_IsActiveFlag_TXE(usart)) {
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100673 key = irq_lock();
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700674 if (LL_USART_IsActiveFlag_TXE(usart)) {
Julien D'ascenziod42cef12021-11-08 12:47:25 +0100675 break;
676 }
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100677 irq_unlock(key);
678 }
Anas Nashif4c322582019-06-04 10:52:23 -0400679 }
Erwan Gouriouda210ba2017-09-21 15:20:53 +0200680
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200681#ifdef CONFIG_PM
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200682
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100683 /* If an interrupt transmission is in progress, the pm constraint is already managed by the
684 * call of uart_stm32_irq_tx_[en|dis]able
685 */
686 if (!data->tx_poll_stream_on && !data->tx_int_stream_on) {
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200687 data->tx_poll_stream_on = true;
688
689 /* Don't allow system to suspend until stream
690 * transmission has completed
691 */
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +0100692 uart_stm32_pm_policy_state_lock_get(dev);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200693
694 /* Enable TC interrupt so we can release suspend
695 * constraint when done
696 */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700697 LL_USART_EnableIT_TC(usart);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200698 }
699#endif /* CONFIG_PM */
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +0200700
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700701 set_fn(usart, out);
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100702 irq_unlock(key);
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100703}
704
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700705static void poll_in_u8(USART_TypeDef *usart, void *in)
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100706{
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700707 *((unsigned char *)in) = (unsigned char)LL_USART_ReceiveData8(usart);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100708}
709
Pisit Sawangvonganan3a6e36d2024-11-10 00:03:03 +0700710static void poll_out_u8(USART_TypeDef *usart, uint16_t out)
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100711{
Pisit Sawangvonganan3a6e36d2024-11-10 00:03:03 +0700712 LL_USART_TransmitData8(usart, (uint8_t)out);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100713}
714
715static int uart_stm32_poll_in(const struct device *dev, unsigned char *c)
716{
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100717 return uart_stm32_poll_in_visitor(dev, (void *)c, poll_in_u8);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100718}
719
720static void uart_stm32_poll_out(const struct device *dev, unsigned char c)
721{
Pisit Sawangvonganan3a6e36d2024-11-10 00:03:03 +0700722 uart_stm32_poll_out_visitor(dev, c, poll_out_u8);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100723}
724
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100725#ifdef CONFIG_UART_WIDE_DATA
726
Pisit Sawangvonganan3a6e36d2024-11-10 00:03:03 +0700727static void poll_out_u9(USART_TypeDef *usart, uint16_t out)
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100728{
Pisit Sawangvonganan3a6e36d2024-11-10 00:03:03 +0700729 LL_USART_TransmitData9(usart, out);
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100730}
731
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700732static void poll_in_u9(USART_TypeDef *usart, void *in)
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100733{
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700734 *((uint16_t *)in) = LL_USART_ReceiveData9(usart);
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100735}
736
737static int uart_stm32_poll_in_u16(const struct device *dev, uint16_t *in_u16)
738{
739 return uart_stm32_poll_in_visitor(dev, (void *)in_u16, poll_in_u9);
740}
741
742static void uart_stm32_poll_out_u16(const struct device *dev, uint16_t out_u16)
743{
Pisit Sawangvonganan3a6e36d2024-11-10 00:03:03 +0700744 uart_stm32_poll_out_visitor(dev, out_u16, poll_out_u9);
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100745}
746
747#endif
748
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200749static int uart_stm32_err_check(const struct device *dev)
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100750{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100751 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700752 USART_TypeDef *usart = config->usart;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500753 uint32_t err = 0U;
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100754
Francois Ramu860bd872022-01-28 16:52:28 +0100755 /* Check for errors, then clear them.
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100756 * Some SoC clear all error flags when at least
Francois Ramu860bd872022-01-28 16:52:28 +0100757 * one is cleared. (e.g. F4X, F1X, and F2X).
758 * The stm32 F4X, F1X, and F2X also reads the usart DR when clearing Errors
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100759 */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700760 if (LL_USART_IsActiveFlag_ORE(usart)) {
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100761 err |= UART_ERROR_OVERRUN;
762 }
763
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700764 if (LL_USART_IsActiveFlag_PE(usart)) {
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100765 err |= UART_ERROR_PARITY;
766 }
767
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700768 if (LL_USART_IsActiveFlag_FE(usart)) {
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100769 err |= UART_ERROR_FRAMING;
770 }
771
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700772 if (LL_USART_IsActiveFlag_NE(usart)) {
Dawid Niedzwiecki4a2a5122023-01-03 09:38:48 +0100773 err |= UART_ERROR_NOISE;
774 }
775
Andrea Campanellab2190fd2021-12-21 16:09:15 +0000776#if !defined(CONFIG_SOC_SERIES_STM32F0X) || defined(USART_LIN_SUPPORT)
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700777 if (LL_USART_IsActiveFlag_LBD(usart)) {
Andrea Campanellab2190fd2021-12-21 16:09:15 +0000778 err |= UART_BREAK;
779 }
780
781 if (err & UART_BREAK) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700782 LL_USART_ClearFlag_LBD(usart);
Andrea Campanellab2190fd2021-12-21 16:09:15 +0000783 }
784#endif
Francois Ramu860bd872022-01-28 16:52:28 +0100785 /* Clearing error :
786 * the stm32 F4X, F1X, and F2X sw sequence is reading the usart SR
787 * then the usart DR to clear the Error flags ORE, PE, FE, NE
788 * --> so is the RXNE flag also cleared !
789 */
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100790 if (err & UART_ERROR_OVERRUN) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700791 LL_USART_ClearFlag_ORE(usart);
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100792 }
793
794 if (err & UART_ERROR_PARITY) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700795 LL_USART_ClearFlag_PE(usart);
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100796 }
797
798 if (err & UART_ERROR_FRAMING) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700799 LL_USART_ClearFlag_FE(usart);
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100800 }
Dawid Niedzwiecki4a2a5122023-01-03 09:38:48 +0100801
802 if (err & UART_ERROR_NOISE) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700803 LL_USART_ClearFlag_NE(usart);
Dawid Niedzwiecki4a2a5122023-01-03 09:38:48 +0100804 }
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100805
806 return err;
807}
808
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200809static inline void __uart_stm32_get_clock(const struct device *dev)
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100810{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100811 struct uart_stm32_data *data = dev->data;
Gerard Marull-Paretasa2023412022-08-22 10:36:10 +0200812 const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100813
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100814 data->clock = clk;
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100815}
816
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100817#ifdef CONFIG_UART_INTERRUPT_DRIVEN
818
Zheng Wuf59e2472024-10-30 19:34:45 +0800819typedef void (*fifo_fill_fn)(USART_TypeDef *usart, const void *tx_data, const int offset);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100820
821static int uart_stm32_fifo_fill_visitor(const struct device *dev, const void *tx_data, int size,
822 fifo_fill_fn fill_fn)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100823{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100824 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700825 USART_TypeDef *usart = config->usart;
Zheng Wuf59e2472024-10-30 19:34:45 +0800826 int num_tx = 0U;
Johann Fischer5e5ea9a2022-07-13 16:50:25 +0200827 unsigned int key;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100828
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700829 if (!LL_USART_IsActiveFlag_TXE(usart)) {
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100830 return num_tx;
831 }
832
833 /* Lock interrupts to prevent nested interrupts or thread switch */
834 key = irq_lock();
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100835
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700836 while ((size - num_tx > 0) && LL_USART_IsActiveFlag_TXE(usart)) {
Georgij Cernysiov3de55da2019-02-06 23:31:24 +0100837 /* TXE flag will be cleared with byte write to DR|RDR register */
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100838
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100839 /* Send a character */
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700840 fill_fn(usart, tx_data, num_tx);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100841 num_tx++;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100842 }
843
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100844 irq_unlock(key);
845
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100846 return num_tx;
847}
848
Zheng Wuf59e2472024-10-30 19:34:45 +0800849static void fifo_fill_with_u8(USART_TypeDef *usart, const void *tx_data, const int offset)
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100850{
851 const uint8_t *data = (const uint8_t *)tx_data;
852 /* Send a character (8bit) */
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700853 LL_USART_TransmitData8(usart, data[offset]);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100854}
855
856static int uart_stm32_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
857{
858 if (uart_stm32_ll2cfg_databits(uart_stm32_get_databits(dev), uart_stm32_get_parity(dev)) ==
859 UART_CFG_DATA_BITS_9) {
860 return -ENOTSUP;
861 }
862 return uart_stm32_fifo_fill_visitor(dev, (const void *)tx_data, size,
863 fifo_fill_with_u8);
864}
865
Zheng Wuf59e2472024-10-30 19:34:45 +0800866typedef void (*fifo_read_fn)(USART_TypeDef *usart, void *rx_data, const int offset);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100867
868static int uart_stm32_fifo_read_visitor(const struct device *dev, void *rx_data, const int size,
869 fifo_read_fn read_fn)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100870{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100871 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700872 USART_TypeDef *usart = config->usart;
Zheng Wuf59e2472024-10-30 19:34:45 +0800873 int num_rx = 0U;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100874
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700875 while ((size - num_rx > 0) && LL_USART_IsActiveFlag_RXNE(usart)) {
Georgij Cernysiov3de55da2019-02-06 23:31:24 +0100876 /* RXNE flag will be cleared upon read from DR|RDR register */
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100877
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700878 read_fn(usart, rx_data, num_rx);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100879 num_rx++;
Kiril Zyapkov7a602fc2018-11-02 15:34:56 +0200880
881 /* Clear overrun error flag */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +0700882 if (LL_USART_IsActiveFlag_ORE(usart)) {
883 LL_USART_ClearFlag_ORE(usart);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100884 /*
885 * On stm32 F4X, F1X, and F2X, the RXNE flag is affected (cleared) by
886 * the uart_err_check function call (on errors flags clearing)
887 */
Kiril Zyapkov7a602fc2018-11-02 15:34:56 +0200888 }
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100889 }
Georgij Cernysiov3de55da2019-02-06 23:31:24 +0100890
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100891 return num_rx;
892}
893
Zheng Wuf59e2472024-10-30 19:34:45 +0800894static void fifo_read_with_u8(USART_TypeDef *usart, void *rx_data, const int offset)
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100895{
896 uint8_t *data = (uint8_t *)rx_data;
897
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700898 data[offset] = LL_USART_ReceiveData8(usart);
Jeroen van Dooren435d5d12023-02-06 09:49:27 +0100899}
900
901static int uart_stm32_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
902{
903 if (uart_stm32_ll2cfg_databits(uart_stm32_get_databits(dev), uart_stm32_get_parity(dev)) ==
904 UART_CFG_DATA_BITS_9) {
905 return -ENOTSUP;
906 }
907 return uart_stm32_fifo_read_visitor(dev, (void *)rx_data, size,
908 fifo_read_with_u8);
909}
910
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100911#ifdef CONFIG_UART_WIDE_DATA
912
Zheng Wuf59e2472024-10-30 19:34:45 +0800913static void fifo_fill_with_u16(USART_TypeDef *usart, const void *tx_data, const int offset)
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100914{
915 const uint16_t *data = (const uint16_t *)tx_data;
916
917 /* Send a character (9bit) */
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700918 LL_USART_TransmitData9(usart, data[offset]);
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100919}
920
921static int uart_stm32_fifo_fill_u16(const struct device *dev, const uint16_t *tx_data, int size)
922{
923 if (uart_stm32_ll2cfg_databits(uart_stm32_get_databits(dev), uart_stm32_get_parity(dev)) !=
924 UART_CFG_DATA_BITS_9) {
925 return -ENOTSUP;
926 }
927 return uart_stm32_fifo_fill_visitor(dev, (const void *)tx_data, size,
928 fifo_fill_with_u16);
929}
930
Zheng Wuf59e2472024-10-30 19:34:45 +0800931static void fifo_read_with_u16(USART_TypeDef *usart, void *rx_data, const int offset)
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100932{
933 uint16_t *data = (uint16_t *)rx_data;
934
Pisit Sawangvongananf503b7a2024-05-24 13:17:38 +0700935 data[offset] = LL_USART_ReceiveData9(usart);
Jeroen van Dooren6ab70692023-02-06 09:54:20 +0100936}
937
938static int uart_stm32_fifo_read_u16(const struct device *dev, uint16_t *rx_data, const int size)
939{
940 if (uart_stm32_ll2cfg_databits(uart_stm32_get_databits(dev), uart_stm32_get_parity(dev)) !=
941 UART_CFG_DATA_BITS_9) {
942 return -ENOTSUP;
943 }
944 return uart_stm32_fifo_read_visitor(dev, (void *)rx_data, size,
945 fifo_read_with_u16);
946}
947
948#endif
949
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200950static void uart_stm32_irq_tx_enable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100951{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100952 const struct uart_stm32_config *config = dev->config;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100953#ifdef CONFIG_PM
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100954 struct uart_stm32_data *data = dev->data;
Johann Fischer5e5ea9a2022-07-13 16:50:25 +0200955 unsigned int key;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100956#endif
Julien D'ascenziod42cef12021-11-08 12:47:25 +0100957
958#ifdef CONFIG_PM
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100959 key = irq_lock();
Julien D'ascenzio7b210502021-10-26 18:03:31 +0200960 data->tx_poll_stream_on = false;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100961 data->tx_int_stream_on = true;
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +0100962 uart_stm32_pm_policy_state_lock_get(dev);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200963#endif
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100964 LL_USART_EnableIT_TC(config->usart);
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100965
966#ifdef CONFIG_PM
967 irq_unlock(key);
968#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100969}
970
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200971static void uart_stm32_irq_tx_disable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100972{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100973 const struct uart_stm32_config *config = dev->config;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100974#ifdef CONFIG_PM
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100975 struct uart_stm32_data *data = dev->data;
Johann Fischer5e5ea9a2022-07-13 16:50:25 +0200976 unsigned int key;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100977
978 key = irq_lock();
979#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100980
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100981 LL_USART_DisableIT_TC(config->usart);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200982
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100983#ifdef CONFIG_PM
984 data->tx_int_stream_on = false;
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +0100985 uart_stm32_pm_policy_state_lock_put(dev);
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100986#endif
Julien D'ascenziod42cef12021-11-08 12:47:25 +0100987
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200988#ifdef CONFIG_PM
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100989 irq_unlock(key);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200990#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100991}
992
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200993static int uart_stm32_irq_tx_ready(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100994{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100995 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100996
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100997 return LL_USART_IsActiveFlag_TXE(config->usart) &&
998 LL_USART_IsEnabledIT_TC(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100999}
1000
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001001static int uart_stm32_irq_tx_complete(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001002{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001003 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001004
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001005 return LL_USART_IsActiveFlag_TC(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001006}
1007
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001008static void uart_stm32_irq_rx_enable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001009{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001010 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001011
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001012 LL_USART_EnableIT_RXNE(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001013}
1014
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001015static void uart_stm32_irq_rx_disable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001016{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001017 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001018
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001019 LL_USART_DisableIT_RXNE(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001020}
1021
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001022static int uart_stm32_irq_rx_ready(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001023{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001024 const struct uart_stm32_config *config = dev->config;
Francois Ramu860bd872022-01-28 16:52:28 +01001025 /*
1026 * On stm32 F4X, F1X, and F2X, the RXNE flag is affected (cleared) by
1027 * the uart_err_check function call (on errors flags clearing)
1028 */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001029 return LL_USART_IsActiveFlag_RXNE(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001030}
1031
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001032static void uart_stm32_irq_err_enable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001033{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001034 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001035 USART_TypeDef *usart = config->usart;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001036
Erwan Gouriou8c079e92016-11-14 11:53:52 +01001037 /* Enable FE, ORE interruptions */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001038 LL_USART_EnableIT_ERROR(usart);
Ilya Tagunov967c31b2018-03-29 19:40:00 +03001039#if !defined(CONFIG_SOC_SERIES_STM32F0X) || defined(USART_LIN_SUPPORT)
Erwan Gouriou8c079e92016-11-14 11:53:52 +01001040 /* Enable Line break detection */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001041 if (IS_UART_LIN_INSTANCE(usart)) {
1042 LL_USART_EnableIT_LBD(usart);
Ilya Tagunov967c31b2018-03-29 19:40:00 +03001043 }
Maciej Debskieaff37e2017-08-09 11:23:04 +02001044#endif
Erwan Gouriou8c079e92016-11-14 11:53:52 +01001045 /* Enable parity error interruption */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001046 LL_USART_EnableIT_PE(usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001047}
1048
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001049static void uart_stm32_irq_err_disable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001050{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001051 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001052 USART_TypeDef *usart = config->usart;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001053
Ilya Tagunov967c31b2018-03-29 19:40:00 +03001054 /* Disable FE, ORE interruptions */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001055 LL_USART_DisableIT_ERROR(usart);
Ilya Tagunov967c31b2018-03-29 19:40:00 +03001056#if !defined(CONFIG_SOC_SERIES_STM32F0X) || defined(USART_LIN_SUPPORT)
1057 /* Disable Line break detection */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001058 if (IS_UART_LIN_INSTANCE(usart)) {
1059 LL_USART_DisableIT_LBD(usart);
Ilya Tagunov967c31b2018-03-29 19:40:00 +03001060 }
Maciej Debskieaff37e2017-08-09 11:23:04 +02001061#endif
Ilya Tagunov967c31b2018-03-29 19:40:00 +03001062 /* Disable parity error interruption */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001063 LL_USART_DisableIT_PE(usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001064}
1065
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001066static int uart_stm32_irq_is_pending(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001067{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001068 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001069 USART_TypeDef *usart = config->usart;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001070
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001071 return ((LL_USART_IsActiveFlag_RXNE(usart) &&
1072 LL_USART_IsEnabledIT_RXNE(usart)) ||
1073 (LL_USART_IsActiveFlag_TC(usart) &&
1074 LL_USART_IsEnabledIT_TC(usart)));
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001075}
1076
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001077static int uart_stm32_irq_update(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001078{
1079 return 1;
1080}
1081
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001082static void uart_stm32_irq_callback_set(const struct device *dev,
Paul Sokolovsky57286af2018-07-16 21:12:26 +03001083 uart_irq_callback_user_data_t cb,
1084 void *cb_data)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001085{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001086 struct uart_stm32_data *data = dev->data;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001087
1088 data->user_cb = cb;
Paul Sokolovsky57286af2018-07-16 21:12:26 +03001089 data->user_data = cb_data;
Daniel Leung9f02eea2022-08-18 11:19:46 -07001090
1091#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS)
1092 data->async_cb = NULL;
1093 data->async_user_data = NULL;
1094#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001095}
1096
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001097#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
1098
1099#ifdef CONFIG_UART_ASYNC_API
1100
1101static inline void async_user_callback(struct uart_stm32_data *data,
1102 struct uart_event *event)
1103{
1104 if (data->async_cb) {
1105 data->async_cb(data->uart_dev, event, data->async_user_data);
1106 }
1107}
1108
1109static inline void async_evt_rx_rdy(struct uart_stm32_data *data)
1110{
1111 LOG_DBG("rx_rdy: (%d %d)", data->dma_rx.offset, data->dma_rx.counter);
1112
1113 struct uart_event event = {
1114 .type = UART_RX_RDY,
1115 .data.rx.buf = data->dma_rx.buffer,
1116 .data.rx.len = data->dma_rx.counter - data->dma_rx.offset,
1117 .data.rx.offset = data->dma_rx.offset
1118 };
1119
Alexander Shuklin6831b8b2021-02-04 12:00:49 +03001120 /* update the current pos for new data */
1121 data->dma_rx.offset = data->dma_rx.counter;
1122
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001123 /* send event only for new data */
1124 if (event.data.rx.len > 0) {
1125 async_user_callback(data, &event);
1126 }
1127}
1128
1129static inline void async_evt_rx_err(struct uart_stm32_data *data, int err_code)
1130{
1131 LOG_DBG("rx error: %d", err_code);
1132
1133 struct uart_event event = {
1134 .type = UART_RX_STOPPED,
1135 .data.rx_stop.reason = err_code,
1136 .data.rx_stop.data.len = data->dma_rx.counter,
1137 .data.rx_stop.data.offset = 0,
1138 .data.rx_stop.data.buf = data->dma_rx.buffer
1139 };
1140
1141 async_user_callback(data, &event);
1142}
1143
1144static inline void async_evt_tx_done(struct uart_stm32_data *data)
1145{
1146 LOG_DBG("tx done: %d", data->dma_tx.counter);
1147
1148 struct uart_event event = {
1149 .type = UART_TX_DONE,
1150 .data.tx.buf = data->dma_tx.buffer,
1151 .data.tx.len = data->dma_tx.counter
1152 };
1153
1154 /* Reset tx buffer */
1155 data->dma_tx.buffer_length = 0;
1156 data->dma_tx.counter = 0;
1157
1158 async_user_callback(data, &event);
1159}
1160
1161static inline void async_evt_tx_abort(struct uart_stm32_data *data)
1162{
1163 LOG_DBG("tx abort: %d", data->dma_tx.counter);
1164
1165 struct uart_event event = {
1166 .type = UART_TX_ABORTED,
1167 .data.tx.buf = data->dma_tx.buffer,
1168 .data.tx.len = data->dma_tx.counter
1169 };
1170
1171 /* Reset tx buffer */
1172 data->dma_tx.buffer_length = 0;
1173 data->dma_tx.counter = 0;
1174
1175 async_user_callback(data, &event);
1176}
1177
1178static inline void async_evt_rx_buf_request(struct uart_stm32_data *data)
1179{
1180 struct uart_event evt = {
1181 .type = UART_RX_BUF_REQUEST,
1182 };
1183
1184 async_user_callback(data, &evt);
1185}
1186
1187static inline void async_evt_rx_buf_release(struct uart_stm32_data *data)
1188{
1189 struct uart_event evt = {
1190 .type = UART_RX_BUF_RELEASED,
1191 .data.rx_buf.buf = data->dma_rx.buffer,
1192 };
1193
1194 async_user_callback(data, &evt);
1195}
1196
Francois Ramu962d6b12021-04-08 12:09:58 +02001197static inline void async_timer_start(struct k_work_delayable *work,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001198 int32_t timeout)
1199{
Krzysztof Chruscinskic590b352021-10-01 15:47:40 +02001200 if ((timeout != SYS_FOREVER_US) && (timeout != 0)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001201 /* start timer */
Krzysztof Chruscinskic590b352021-10-01 15:47:40 +02001202 LOG_DBG("async timer started for %d us", timeout);
1203 k_work_reschedule(work, K_USEC(timeout));
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001204 }
1205}
1206
1207static void uart_stm32_dma_rx_flush(const struct device *dev)
1208{
1209 struct dma_status stat;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001210 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001211
Erwan Gouriou13c23512021-03-01 11:59:57 +01001212 if (dma_get_status(data->dma_rx.dma_dev,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001213 data->dma_rx.dma_channel, &stat) == 0) {
1214 size_t rx_rcv_len = data->dma_rx.buffer_length -
1215 stat.pending_length;
1216 if (rx_rcv_len > data->dma_rx.offset) {
1217 data->dma_rx.counter = rx_rcv_len;
1218
1219 async_evt_rx_rdy(data);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001220 }
1221 }
1222}
1223
1224#endif /* CONFIG_UART_ASYNC_API */
1225
Erwan Gouriou79ff6452021-09-21 09:34:09 +02001226#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || \
1227 defined(CONFIG_UART_ASYNC_API) || \
1228 defined(CONFIG_PM)
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001229
Tomasz Bursztyka4dcfb552020-06-17 14:58:56 +02001230static void uart_stm32_isr(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001231{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001232 struct uart_stm32_data *data = dev->data;
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001233#if defined(CONFIG_PM) || defined(CONFIG_UART_ASYNC_API)
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001234 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001235 USART_TypeDef *usart = config->usart;
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001236#endif
1237
1238#ifdef CONFIG_PM
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001239 if (LL_USART_IsEnabledIT_TC(usart) &&
1240 LL_USART_IsActiveFlag_TC(usart)) {
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001241
1242 if (data->tx_poll_stream_on) {
Yegor Yefremov1155d462022-03-07 22:53:16 +01001243 /* A poll stream transmission just completed,
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001244 * allow system to suspend
1245 */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001246 LL_USART_DisableIT_TC(usart);
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001247 data->tx_poll_stream_on = false;
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +01001248 uart_stm32_pm_policy_state_lock_put(dev);
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001249 }
Yegor Yefremov1155d462022-03-07 22:53:16 +01001250 /* Stream transmission was either async or IRQ based,
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001251 * constraint will be released at the same time TC IT
1252 * is disabled
1253 */
1254 }
1255#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001256
Shlomi Vaknin1b4f7e52021-05-17 23:06:51 +03001257#ifdef CONFIG_UART_INTERRUPT_DRIVEN
1258 if (data->user_cb) {
1259 data->user_cb(dev, data->user_data);
1260 }
1261#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
1262
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001263#ifdef CONFIG_UART_ASYNC_API
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001264 if (LL_USART_IsEnabledIT_IDLE(usart) &&
1265 LL_USART_IsActiveFlag_IDLE(usart)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001266
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001267 LL_USART_ClearFlag_IDLE(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001268
1269 LOG_DBG("idle interrupt occurred");
1270
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001271 if (data->dma_rx.timeout == 0) {
1272 uart_stm32_dma_rx_flush(dev);
Francois Ramu0300b342022-08-31 12:13:41 +02001273 } else {
1274 /* Start the RX timer not null */
1275 async_timer_start(&data->dma_rx.timeout_work,
1276 data->dma_rx.timeout);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001277 }
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001278 } else if (LL_USART_IsEnabledIT_TC(usart) &&
1279 LL_USART_IsActiveFlag_TC(usart)) {
Zisis Adamos7235b092021-03-30 12:20:46 +02001280
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001281 LL_USART_DisableIT_TC(usart);
Zisis Adamos7235b092021-03-30 12:20:46 +02001282 /* Generate TX_DONE event when transmission is done */
1283 async_evt_tx_done(data);
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001284
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001285#ifdef CONFIG_PM
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +01001286 uart_stm32_pm_policy_state_lock_put(dev);
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001287#endif
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001288 } else if (LL_USART_IsEnabledIT_RXNE(usart) &&
1289 LL_USART_IsActiveFlag_RXNE(usart)) {
Francois Ramucf606392021-11-08 11:43:53 +01001290#ifdef USART_SR_RXNE
1291 /* clear the RXNE flag, because Rx data was not read */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001292 LL_USART_ClearFlag_RXNE(usart);
Francois Ramucf606392021-11-08 11:43:53 +01001293#else
Francois Ramu95e2c392021-10-26 11:39:57 +02001294 /* clear the RXNE by flushing the fifo, because Rx data was not read */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001295 LL_USART_RequestRxDataFlush(usart);
Francois Ramucf606392021-11-08 11:43:53 +01001296#endif /* USART_SR_RXNE */
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001297 }
1298
1299 /* Clear errors */
1300 uart_stm32_err_check(dev);
1301#endif /* CONFIG_UART_ASYNC_API */
Erwan Gourioue5ab70b2023-11-16 12:17:59 +01001302
Erwan Gourioua38c8d22023-11-21 16:59:27 +01001303#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) \
1304 && defined(USART_CR3_WUFIE)
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001305 if (LL_USART_IsEnabledIT_WKUP(usart) &&
1306 LL_USART_IsActiveFlag_WKUP(usart)) {
Erwan Gourioue5ab70b2023-11-16 12:17:59 +01001307
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001308 LL_USART_ClearFlag_WKUP(usart);
Erwan Gourioue5ab70b2023-11-16 12:17:59 +01001309#ifdef USART_ISR_REACK
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001310 while (LL_USART_IsActiveFlag_REACK(usart) == 0) {
Erwan Gourioue5ab70b2023-11-16 12:17:59 +01001311 }
1312#endif
1313 }
1314#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001315}
Erwan Gouriou79ff6452021-09-21 09:34:09 +02001316#endif /* CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API || CONFIG_PM */
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001317
1318#ifdef CONFIG_UART_ASYNC_API
1319
Abderrahmane Jarmounie783aaf2024-03-20 15:25:14 +01001320#ifdef CONFIG_DCACHE
1321static bool buf_in_nocache(uintptr_t buf, size_t len_bytes)
1322{
1323 bool buf_within_nocache = false;
1324
1325#ifdef CONFIG_NOCACHE_MEMORY
1326 buf_within_nocache = (buf >= ((uintptr_t)_nocache_ram_start)) &&
1327 ((buf + len_bytes - 1) <= ((uintptr_t)_nocache_ram_end));
1328 if (buf_within_nocache) {
1329 return true;
1330 }
1331#endif /* CONFIG_NOCACHE_MEMORY */
1332
1333 buf_within_nocache = mem_attr_check_buf(
1334 (void *)buf, len_bytes, DT_MEM_ARM_MPU_RAM_NOCACHE) == 0;
1335 if (buf_within_nocache) {
1336 return true;
1337 }
1338
1339 buf_within_nocache = (buf >= ((uintptr_t)__rodata_region_start)) &&
1340 ((buf + len_bytes - 1) <= ((uintptr_t)__rodata_region_end));
1341
1342 return buf_within_nocache;
1343}
1344#endif /* CONFIG_DCACHE */
1345
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001346static int uart_stm32_async_callback_set(const struct device *dev,
1347 uart_callback_t callback,
1348 void *user_data)
1349{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001350 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001351
1352 data->async_cb = callback;
1353 data->async_user_data = user_data;
1354
Daniel Leung9f02eea2022-08-18 11:19:46 -07001355#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS)
1356 data->user_cb = NULL;
1357 data->user_data = NULL;
1358#endif
1359
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001360 return 0;
1361}
1362
1363static inline void uart_stm32_dma_tx_enable(const struct device *dev)
1364{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001365 const struct uart_stm32_config *config = dev->config;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001366
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001367 LL_USART_EnableDMAReq_TX(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001368}
1369
1370static inline void uart_stm32_dma_tx_disable(const struct device *dev)
1371{
Erwan Gourioud7513fb2023-11-14 16:49:18 +01001372#ifdef CONFIG_UART_STM32U5_ERRATA_DMAT
Francois Ramu1b2942f2023-04-05 16:09:27 +02001373 ARG_UNUSED(dev);
1374
1375 /*
1376 * Errata Sheet ES0499 : STM32U575xx and STM32U585xx device errata
1377 * USART does not generate DMA requests after setting/clearing DMAT bit
1378 * (also seen on stm32H5 serie)
1379 */
1380#else
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001381 const struct uart_stm32_config *config = dev->config;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001382
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001383 LL_USART_DisableDMAReq_TX(config->usart);
Erwan Gourioud7513fb2023-11-14 16:49:18 +01001384#endif
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001385}
1386
1387static inline void uart_stm32_dma_rx_enable(const struct device *dev)
1388{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001389 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001390 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001391
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001392 LL_USART_EnableDMAReq_RX(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001393
1394 data->dma_rx.enabled = true;
1395}
1396
1397static inline void uart_stm32_dma_rx_disable(const struct device *dev)
1398{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001399 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001400
1401 data->dma_rx.enabled = false;
1402}
1403
1404static int uart_stm32_async_rx_disable(const struct device *dev)
1405{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001406 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001407 USART_TypeDef *usart = config->usart;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001408 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001409 struct uart_event disabled_event = {
1410 .type = UART_RX_DISABLED
1411 };
1412
1413 if (!data->dma_rx.enabled) {
1414 async_user_callback(data, &disabled_event);
1415 return -EFAULT;
1416 }
1417
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001418 LL_USART_DisableIT_IDLE(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001419
1420 uart_stm32_dma_rx_flush(dev);
1421
1422 async_evt_rx_buf_release(data);
1423
1424 uart_stm32_dma_rx_disable(dev);
1425
Francois Ramu962d6b12021-04-08 12:09:58 +02001426 (void)k_work_cancel_delayable(&data->dma_rx.timeout_work);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001427
Erwan Gouriou13c23512021-03-01 11:59:57 +01001428 dma_stop(data->dma_rx.dma_dev, data->dma_rx.dma_channel);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001429
Wouter Cappelle984b6122022-10-07 14:49:16 +02001430 if (data->rx_next_buffer) {
1431 struct uart_event rx_next_buf_release_evt = {
1432 .type = UART_RX_BUF_RELEASED,
1433 .data.rx_buf.buf = data->rx_next_buffer,
1434 };
1435 async_user_callback(data, &rx_next_buf_release_evt);
1436 }
1437
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001438 data->rx_next_buffer = NULL;
1439 data->rx_next_buffer_len = 0;
1440
Yegor Yefremov1155d462022-03-07 22:53:16 +01001441 /* When async rx is disabled, enable interruptible instance of uart to function normally */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001442 LL_USART_EnableIT_RXNE(usart);
Manojkumar Subramaniamd79d26f2021-08-23 02:04:05 +08001443
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001444 LOG_DBG("rx: disabled");
1445
1446 async_user_callback(data, &disabled_event);
1447
1448 return 0;
1449}
1450
1451void uart_stm32_dma_tx_cb(const struct device *dma_dev, void *user_data,
1452 uint32_t channel, int status)
1453{
1454 const struct device *uart_dev = user_data;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001455 struct uart_stm32_data *data = uart_dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001456 struct dma_status stat;
1457 unsigned int key = irq_lock();
1458
1459 /* Disable TX */
1460 uart_stm32_dma_tx_disable(uart_dev);
1461
Francois Ramu962d6b12021-04-08 12:09:58 +02001462 (void)k_work_cancel_delayable(&data->dma_tx.timeout_work);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001463
Erwan Gouriou13c23512021-03-01 11:59:57 +01001464 if (!dma_get_status(data->dma_tx.dma_dev,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001465 data->dma_tx.dma_channel, &stat)) {
1466 data->dma_tx.counter = data->dma_tx.buffer_length -
1467 stat.pending_length;
1468 }
1469
Prema Jonathan van Win76dee392021-05-03 11:24:38 +03001470 data->dma_tx.buffer_length = 0;
1471
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001472 irq_unlock(key);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001473}
1474
1475static void uart_stm32_dma_replace_buffer(const struct device *dev)
1476{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001477 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001478 USART_TypeDef *usart = config->usart;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001479 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001480
Yegor Yefremov1155d462022-03-07 22:53:16 +01001481 /* Replace the buffer and reload the DMA */
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001482 LOG_DBG("Replacing RX buffer: %d", data->rx_next_buffer_len);
1483
1484 /* reload DMA */
1485 data->dma_rx.offset = 0;
1486 data->dma_rx.counter = 0;
1487 data->dma_rx.buffer = data->rx_next_buffer;
1488 data->dma_rx.buffer_length = data->rx_next_buffer_len;
1489 data->dma_rx.blk_cfg.block_size = data->dma_rx.buffer_length;
1490 data->dma_rx.blk_cfg.dest_address = (uint32_t)data->dma_rx.buffer;
1491 data->rx_next_buffer = NULL;
1492 data->rx_next_buffer_len = 0;
1493
Erwan Gouriou13c23512021-03-01 11:59:57 +01001494 dma_reload(data->dma_rx.dma_dev, data->dma_rx.dma_channel,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001495 data->dma_rx.blk_cfg.source_address,
1496 data->dma_rx.blk_cfg.dest_address,
1497 data->dma_rx.blk_cfg.block_size);
1498
Erwan Gouriou13c23512021-03-01 11:59:57 +01001499 dma_start(data->dma_rx.dma_dev, data->dma_rx.dma_channel);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001500
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001501 LL_USART_ClearFlag_IDLE(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001502
1503 /* Request next buffer */
1504 async_evt_rx_buf_request(data);
1505}
1506
1507void uart_stm32_dma_rx_cb(const struct device *dma_dev, void *user_data,
1508 uint32_t channel, int status)
1509{
1510 const struct device *uart_dev = user_data;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001511 struct uart_stm32_data *data = uart_dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001512
Cyril Fougeray1be72d92023-03-26 17:26:23 +02001513 if (status < 0) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001514 async_evt_rx_err(data, status);
1515 return;
1516 }
1517
Francois Ramu962d6b12021-04-08 12:09:58 +02001518 (void)k_work_cancel_delayable(&data->dma_rx.timeout_work);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001519
1520 /* true since this functions occurs when buffer if full */
1521 data->dma_rx.counter = data->dma_rx.buffer_length;
1522
1523 async_evt_rx_rdy(data);
1524
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001525 if (data->rx_next_buffer != NULL) {
1526 async_evt_rx_buf_release(data);
1527
1528 /* replace the buffer when the current
1529 * is full and not the same as the next
1530 * one.
1531 */
1532 uart_stm32_dma_replace_buffer(uart_dev);
1533 } else {
1534 /* Buffer full without valid next buffer,
1535 * an UART_RX_DISABLED event must be generated,
1536 * but uart_stm32_async_rx_disable() cannot be
1537 * called in ISR context. So force the RX timeout
1538 * to minimum value and let the RX timeout to do the job.
1539 */
Francois Ramu962d6b12021-04-08 12:09:58 +02001540 k_work_reschedule(&data->dma_rx.timeout_work, K_TICKS(1));
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001541 }
1542}
1543
1544static int uart_stm32_async_tx(const struct device *dev,
1545 const uint8_t *tx_data, size_t buf_size, int32_t timeout)
1546{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001547 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001548 USART_TypeDef *usart = config->usart;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001549 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001550 int ret;
1551
Erwan Gouriou13c23512021-03-01 11:59:57 +01001552 if (data->dma_tx.dma_dev == NULL) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001553 return -ENODEV;
1554 }
1555
1556 if (data->dma_tx.buffer_length != 0) {
1557 return -EBUSY;
1558 }
1559
Abderrahmane Jarmounie783aaf2024-03-20 15:25:14 +01001560#ifdef CONFIG_DCACHE
1561 if (!buf_in_nocache((uintptr_t)tx_data, buf_size)) {
1562 LOG_ERR("Tx buffer should be placed in a nocache memory region");
1563 return -EFAULT;
1564 }
1565#endif /* CONFIG_DCACHE */
1566
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001567 data->dma_tx.buffer = (uint8_t *)tx_data;
1568 data->dma_tx.buffer_length = buf_size;
1569 data->dma_tx.timeout = timeout;
1570
1571 LOG_DBG("tx: l=%d", data->dma_tx.buffer_length);
1572
Zisis Adamos7235b092021-03-30 12:20:46 +02001573 /* Clear TC flag */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001574 LL_USART_ClearFlag_TC(usart);
Zisis Adamos7235b092021-03-30 12:20:46 +02001575
1576 /* Enable TC interrupt so we can signal correct TX done */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001577 LL_USART_EnableIT_TC(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001578
1579 /* set source address */
1580 data->dma_tx.blk_cfg.source_address = (uint32_t)data->dma_tx.buffer;
1581 data->dma_tx.blk_cfg.block_size = data->dma_tx.buffer_length;
1582
Erwan Gouriou13c23512021-03-01 11:59:57 +01001583 ret = dma_config(data->dma_tx.dma_dev, data->dma_tx.dma_channel,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001584 &data->dma_tx.dma_cfg);
1585
1586 if (ret != 0) {
1587 LOG_ERR("dma tx config error!");
1588 return -EINVAL;
1589 }
1590
Erwan Gouriou13c23512021-03-01 11:59:57 +01001591 if (dma_start(data->dma_tx.dma_dev, data->dma_tx.dma_channel)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001592 LOG_ERR("UART err: TX DMA start failed!");
1593 return -EFAULT;
1594 }
1595
1596 /* Start TX timer */
1597 async_timer_start(&data->dma_tx.timeout_work, data->dma_tx.timeout);
1598
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001599#ifdef CONFIG_PM
Erwan Gouriou79ff6452021-09-21 09:34:09 +02001600
1601 /* Do not allow system to suspend until transmission has completed */
Gerard Marull-Paretas5a71eeb2022-01-20 16:06:28 +01001602 uart_stm32_pm_policy_state_lock_get(dev);
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001603#endif
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001604
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001605 /* Enable TX DMA requests */
1606 uart_stm32_dma_tx_enable(dev);
1607
1608 return 0;
1609}
1610
1611static int uart_stm32_async_rx_enable(const struct device *dev,
1612 uint8_t *rx_buf, size_t buf_size, int32_t timeout)
1613{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001614 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001615 USART_TypeDef *usart = config->usart;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001616 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001617 int ret;
1618
Erwan Gouriou13c23512021-03-01 11:59:57 +01001619 if (data->dma_rx.dma_dev == NULL) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001620 return -ENODEV;
1621 }
1622
1623 if (data->dma_rx.enabled) {
1624 LOG_WRN("RX was already enabled");
1625 return -EBUSY;
1626 }
1627
Abderrahmane Jarmounie783aaf2024-03-20 15:25:14 +01001628#ifdef CONFIG_DCACHE
1629 if (!buf_in_nocache((uintptr_t)rx_buf, buf_size)) {
1630 LOG_ERR("Rx buffer should be placed in a nocache memory region");
1631 return -EFAULT;
1632 }
1633#endif /* CONFIG_DCACHE */
1634
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001635 data->dma_rx.offset = 0;
1636 data->dma_rx.buffer = rx_buf;
1637 data->dma_rx.buffer_length = buf_size;
1638 data->dma_rx.counter = 0;
1639 data->dma_rx.timeout = timeout;
1640
1641 /* Disable RX interrupts to let DMA to handle it */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001642 LL_USART_DisableIT_RXNE(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001643
1644 data->dma_rx.blk_cfg.block_size = buf_size;
1645 data->dma_rx.blk_cfg.dest_address = (uint32_t)data->dma_rx.buffer;
1646
Erwan Gouriou13c23512021-03-01 11:59:57 +01001647 ret = dma_config(data->dma_rx.dma_dev, data->dma_rx.dma_channel,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001648 &data->dma_rx.dma_cfg);
1649
1650 if (ret != 0) {
1651 LOG_ERR("UART ERR: RX DMA config failed!");
1652 return -EINVAL;
1653 }
1654
Erwan Gouriou13c23512021-03-01 11:59:57 +01001655 if (dma_start(data->dma_rx.dma_dev, data->dma_rx.dma_channel)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001656 LOG_ERR("UART ERR: RX DMA start failed!");
1657 return -EFAULT;
1658 }
1659
Bjarki Arge Andreasenf9b42bc2023-11-16 20:39:39 +01001660 /* Flush RX data buffer */
1661#ifdef USART_SR_RXNE
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001662 LL_USART_ClearFlag_RXNE(usart);
Bjarki Arge Andreasenf9b42bc2023-11-16 20:39:39 +01001663#else
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001664 LL_USART_RequestRxDataFlush(usart);
Bjarki Arge Andreasenf9b42bc2023-11-16 20:39:39 +01001665#endif /* USART_SR_RXNE */
1666
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001667 /* Enable RX DMA requests */
1668 uart_stm32_dma_rx_enable(dev);
1669
1670 /* Enable IRQ IDLE to define the end of a
1671 * RX DMA transaction.
1672 */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001673 LL_USART_ClearFlag_IDLE(usart);
1674 LL_USART_EnableIT_IDLE(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001675
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001676 LL_USART_EnableIT_ERROR(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001677
1678 /* Request next buffer */
1679 async_evt_rx_buf_request(data);
1680
1681 LOG_DBG("async rx enabled");
1682
1683 return ret;
1684}
1685
1686static int uart_stm32_async_tx_abort(const struct device *dev)
1687{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001688 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001689 size_t tx_buffer_length = data->dma_tx.buffer_length;
1690 struct dma_status stat;
1691
1692 if (tx_buffer_length == 0) {
1693 return -EFAULT;
1694 }
1695
Francois Ramu962d6b12021-04-08 12:09:58 +02001696 (void)k_work_cancel_delayable(&data->dma_tx.timeout_work);
Erwan Gouriou13c23512021-03-01 11:59:57 +01001697 if (!dma_get_status(data->dma_tx.dma_dev,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001698 data->dma_tx.dma_channel, &stat)) {
1699 data->dma_tx.counter = tx_buffer_length - stat.pending_length;
1700 }
1701
Erwan Gourioud2ea9e42023-11-30 11:35:11 +01001702#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma)
Francois Ramue00f91d2022-10-04 17:18:42 +02001703 dma_suspend(data->dma_tx.dma_dev, data->dma_tx.dma_channel);
Erwan Gourioud7513fb2023-11-14 16:49:18 +01001704#endif
Erwan Gouriou13c23512021-03-01 11:59:57 +01001705 dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001706 async_evt_tx_abort(data);
1707
1708 return 0;
1709}
1710
1711static void uart_stm32_async_rx_timeout(struct k_work *work)
1712{
Yong Cong Sin731241f2022-01-19 12:07:51 +08001713 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
1714 struct uart_dma_stream *rx_stream = CONTAINER_OF(dwork,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001715 struct uart_dma_stream, timeout_work);
1716 struct uart_stm32_data *data = CONTAINER_OF(rx_stream,
1717 struct uart_stm32_data, dma_rx);
1718 const struct device *dev = data->uart_dev;
1719
1720 LOG_DBG("rx timeout");
1721
1722 if (data->dma_rx.counter == data->dma_rx.buffer_length) {
1723 uart_stm32_async_rx_disable(dev);
1724 } else {
1725 uart_stm32_dma_rx_flush(dev);
1726 }
1727}
1728
1729static void uart_stm32_async_tx_timeout(struct k_work *work)
1730{
Yong Cong Sin731241f2022-01-19 12:07:51 +08001731 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
1732 struct uart_dma_stream *tx_stream = CONTAINER_OF(dwork,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001733 struct uart_dma_stream, timeout_work);
1734 struct uart_stm32_data *data = CONTAINER_OF(tx_stream,
1735 struct uart_stm32_data, dma_tx);
1736 const struct device *dev = data->uart_dev;
1737
1738 uart_stm32_async_tx_abort(dev);
1739
1740 LOG_DBG("tx: async timeout");
1741}
1742
1743static int uart_stm32_async_rx_buf_rsp(const struct device *dev, uint8_t *buf,
1744 size_t len)
1745{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001746 struct uart_stm32_data *data = dev->data;
Abderrahmane Jarmouni4affeaa2024-02-15 16:59:47 +01001747 unsigned int key;
1748 int err = 0;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001749
1750 LOG_DBG("replace buffer (%d)", len);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001751
Abderrahmane Jarmouni4affeaa2024-02-15 16:59:47 +01001752 key = irq_lock();
1753
1754 if (data->rx_next_buffer != NULL) {
1755 err = -EBUSY;
1756 } else if (!data->dma_rx.enabled) {
1757 err = -EACCES;
1758 } else {
Abderrahmane Jarmounie783aaf2024-03-20 15:25:14 +01001759#ifdef CONFIG_DCACHE
1760 if (!buf_in_nocache((uintptr_t)buf, len)) {
1761 LOG_ERR("Rx buffer should be placed in a nocache memory region");
1762 return -EFAULT;
1763 }
1764#endif /* CONFIG_DCACHE */
Abderrahmane Jarmouni4affeaa2024-02-15 16:59:47 +01001765 data->rx_next_buffer = buf;
1766 data->rx_next_buffer_len = len;
1767 }
1768
1769 irq_unlock(key);
1770
1771 return err;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001772}
1773
1774static int uart_stm32_async_init(const struct device *dev)
1775{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001776 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001777 USART_TypeDef *usart = config->usart;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001778 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001779
1780 data->uart_dev = dev;
1781
Erwan Gouriou13c23512021-03-01 11:59:57 +01001782 if (data->dma_rx.dma_dev != NULL) {
1783 if (!device_is_ready(data->dma_rx.dma_dev)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001784 return -ENODEV;
1785 }
1786 }
1787
Erwan Gouriou13c23512021-03-01 11:59:57 +01001788 if (data->dma_tx.dma_dev != NULL) {
Georgij Cernysiov64c804a2022-05-06 08:47:03 +02001789 if (!device_is_ready(data->dma_tx.dma_dev)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001790 return -ENODEV;
1791 }
1792 }
1793
1794 /* Disable both TX and RX DMA requests */
1795 uart_stm32_dma_rx_disable(dev);
1796 uart_stm32_dma_tx_disable(dev);
1797
Francois Ramu962d6b12021-04-08 12:09:58 +02001798 k_work_init_delayable(&data->dma_rx.timeout_work,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001799 uart_stm32_async_rx_timeout);
Francois Ramu962d6b12021-04-08 12:09:58 +02001800 k_work_init_delayable(&data->dma_tx.timeout_work,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001801 uart_stm32_async_tx_timeout);
1802
1803 /* Configure dma rx config */
1804 memset(&data->dma_rx.blk_cfg, 0, sizeof(data->dma_rx.blk_cfg));
1805
1806#if defined(CONFIG_SOC_SERIES_STM32F1X) || \
1807 defined(CONFIG_SOC_SERIES_STM32F2X) || \
1808 defined(CONFIG_SOC_SERIES_STM32F4X) || \
1809 defined(CONFIG_SOC_SERIES_STM32L1X)
1810 data->dma_rx.blk_cfg.source_address =
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001811 LL_USART_DMA_GetRegAddr(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001812#else
1813 data->dma_rx.blk_cfg.source_address =
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001814 LL_USART_DMA_GetRegAddr(usart,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001815 LL_USART_DMA_REG_DATA_RECEIVE);
1816#endif
1817
1818 data->dma_rx.blk_cfg.dest_address = 0; /* dest not ready */
1819
1820 if (data->dma_rx.src_addr_increment) {
1821 data->dma_rx.blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT;
1822 } else {
1823 data->dma_rx.blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
1824 }
1825
1826 if (data->dma_rx.dst_addr_increment) {
1827 data->dma_rx.blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
1828 } else {
1829 data->dma_rx.blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
1830 }
1831
1832 /* RX disable circular buffer */
1833 data->dma_rx.blk_cfg.source_reload_en = 0;
1834 data->dma_rx.blk_cfg.dest_reload_en = 0;
1835 data->dma_rx.blk_cfg.fifo_mode_control = data->dma_rx.fifo_threshold;
1836
1837 data->dma_rx.dma_cfg.head_block = &data->dma_rx.blk_cfg;
1838 data->dma_rx.dma_cfg.user_data = (void *)dev;
1839 data->rx_next_buffer = NULL;
1840 data->rx_next_buffer_len = 0;
1841
1842 /* Configure dma tx config */
1843 memset(&data->dma_tx.blk_cfg, 0, sizeof(data->dma_tx.blk_cfg));
1844
1845#if defined(CONFIG_SOC_SERIES_STM32F1X) || \
1846 defined(CONFIG_SOC_SERIES_STM32F2X) || \
1847 defined(CONFIG_SOC_SERIES_STM32F4X) || \
1848 defined(CONFIG_SOC_SERIES_STM32L1X)
1849 data->dma_tx.blk_cfg.dest_address =
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001850 LL_USART_DMA_GetRegAddr(usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001851#else
1852 data->dma_tx.blk_cfg.dest_address =
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001853 LL_USART_DMA_GetRegAddr(usart,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001854 LL_USART_DMA_REG_DATA_TRANSMIT);
1855#endif
1856
1857 data->dma_tx.blk_cfg.source_address = 0; /* not ready */
1858
1859 if (data->dma_tx.src_addr_increment) {
1860 data->dma_tx.blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT;
1861 } else {
1862 data->dma_tx.blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
1863 }
1864
1865 if (data->dma_tx.dst_addr_increment) {
1866 data->dma_tx.blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
1867 } else {
1868 data->dma_tx.blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
1869 }
1870
1871 data->dma_tx.blk_cfg.fifo_mode_control = data->dma_tx.fifo_threshold;
1872
1873 data->dma_tx.dma_cfg.head_block = &data->dma_tx.blk_cfg;
1874 data->dma_tx.dma_cfg.user_data = (void *)dev;
1875
1876 return 0;
1877}
1878
Jeroen van Dooren6ab70692023-02-06 09:54:20 +01001879#ifdef CONFIG_UART_WIDE_DATA
1880
1881static int uart_stm32_async_tx_u16(const struct device *dev, const uint16_t *tx_data,
1882 size_t buf_size, int32_t timeout)
1883{
1884 return uart_stm32_async_tx(dev, (const uint8_t *)tx_data, buf_size * 2, timeout);
1885}
1886
1887static int uart_stm32_async_rx_enable_u16(const struct device *dev, uint16_t *buf, size_t len,
1888 int32_t timeout)
1889{
1890 return uart_stm32_async_rx_enable(dev, (uint8_t *)buf, len * 2, timeout);
1891}
1892
1893static int uart_stm32_async_rx_buf_rsp_u16(const struct device *dev, uint16_t *buf, size_t len)
1894{
1895 return uart_stm32_async_rx_buf_rsp(dev, (uint8_t *)buf, len * 2);
1896}
1897
1898#endif
1899
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001900#endif /* CONFIG_UART_ASYNC_API */
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001901
Pieter De Gendt29c9b912024-11-28 21:21:48 +01001902static DEVICE_API(uart, uart_stm32_driver_api) = {
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001903 .poll_in = uart_stm32_poll_in,
1904 .poll_out = uart_stm32_poll_out,
Jeroen van Dooren6ab70692023-02-06 09:54:20 +01001905#ifdef CONFIG_UART_WIDE_DATA
1906 .poll_in_u16 = uart_stm32_poll_in_u16,
1907 .poll_out_u16 = uart_stm32_poll_out_u16,
1908#endif
Georgij Cernysiovc74c1312019-02-14 10:50:19 +01001909 .err_check = uart_stm32_err_check,
Daniel Leung4e1692f2021-05-26 12:33:37 -07001910#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
Pushpal Sidhuacd0e252019-01-07 13:52:24 -08001911 .configure = uart_stm32_configure,
1912 .config_get = uart_stm32_config_get,
Daniel Leung4e1692f2021-05-26 12:33:37 -07001913#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001914#ifdef CONFIG_UART_INTERRUPT_DRIVEN
1915 .fifo_fill = uart_stm32_fifo_fill,
1916 .fifo_read = uart_stm32_fifo_read,
Jeroen van Dooren6ab70692023-02-06 09:54:20 +01001917#ifdef CONFIG_UART_WIDE_DATA
1918 .fifo_fill_u16 = uart_stm32_fifo_fill_u16,
1919 .fifo_read_u16 = uart_stm32_fifo_read_u16,
1920#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001921 .irq_tx_enable = uart_stm32_irq_tx_enable,
1922 .irq_tx_disable = uart_stm32_irq_tx_disable,
1923 .irq_tx_ready = uart_stm32_irq_tx_ready,
Paul Sokolovsky0fdc9b52017-05-11 17:57:29 +03001924 .irq_tx_complete = uart_stm32_irq_tx_complete,
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001925 .irq_rx_enable = uart_stm32_irq_rx_enable,
1926 .irq_rx_disable = uart_stm32_irq_rx_disable,
1927 .irq_rx_ready = uart_stm32_irq_rx_ready,
1928 .irq_err_enable = uart_stm32_irq_err_enable,
1929 .irq_err_disable = uart_stm32_irq_err_disable,
1930 .irq_is_pending = uart_stm32_irq_is_pending,
1931 .irq_update = uart_stm32_irq_update,
1932 .irq_callback_set = uart_stm32_irq_callback_set,
Jeroen van Dooren6ab70692023-02-06 09:54:20 +01001933#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001934#ifdef CONFIG_UART_ASYNC_API
1935 .callback_set = uart_stm32_async_callback_set,
1936 .tx = uart_stm32_async_tx,
1937 .tx_abort = uart_stm32_async_tx_abort,
1938 .rx_enable = uart_stm32_async_rx_enable,
1939 .rx_disable = uart_stm32_async_rx_disable,
1940 .rx_buf_rsp = uart_stm32_async_rx_buf_rsp,
Jeroen van Dooren6ab70692023-02-06 09:54:20 +01001941#ifdef CONFIG_UART_WIDE_DATA
1942 .tx_u16 = uart_stm32_async_tx_u16,
1943 .rx_enable_u16 = uart_stm32_async_rx_enable_u16,
1944 .rx_buf_rsp_u16 = uart_stm32_async_rx_buf_rsp_u16,
1945#endif
1946#endif /* CONFIG_UART_ASYNC_API */
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001947};
1948
Kenneth J. Miller31a6e312023-06-20 01:28:09 +02001949static int uart_stm32_clocks_enable(const struct device *dev)
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001950{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001951 const struct uart_stm32_config *config = dev->config;
1952 struct uart_stm32_data *data = dev->data;
Erwan Gouriou0b9c5842020-10-16 17:20:00 +02001953 int err;
Erwan Gouriouda210ba2017-09-21 15:20:53 +02001954
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001955 __uart_stm32_get_clock(dev);
Henrik Brix Andersen9456eca2022-08-08 16:05:16 +02001956
1957 if (!device_is_ready(data->clock)) {
1958 LOG_ERR("clock control device not ready");
1959 return -ENODEV;
1960 }
1961
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001962 /* enable clock */
Artur Lipowskibb857592022-05-10 12:18:28 +02001963 err = clock_control_on(data->clock, (clock_control_subsys_t)&config->pclken[0]);
1964 if (err != 0) {
1965 LOG_ERR("Could not enable (LP)UART clock");
1966 return err;
1967 }
1968
Erwan Gouriou1ef9e9e2022-08-04 11:08:15 +02001969 if (IS_ENABLED(STM32_UART_DOMAIN_CLOCK_SUPPORT) && (config->pclk_len > 1)) {
Artur Lipowskibb857592022-05-10 12:18:28 +02001970 err = clock_control_configure(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE),
1971 (clock_control_subsys_t) &config->pclken[1],
1972 NULL);
1973 if (err != 0) {
Erwan Gouriou1ef9e9e2022-08-04 11:08:15 +02001974 LOG_ERR("Could not select UART domain clock");
Artur Lipowskibb857592022-05-10 12:18:28 +02001975 return err;
1976 }
Erwan Gouriou9062e972018-12-07 11:09:28 +01001977 }
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001978
Kenneth J. Miller31a6e312023-06-20 01:28:09 +02001979 return 0;
1980}
1981
1982static int uart_stm32_registers_configure(const struct device *dev)
1983{
1984 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001985 USART_TypeDef *usart = config->usart;
Kenneth J. Miller31a6e312023-06-20 01:28:09 +02001986 struct uart_stm32_data *data = dev->data;
1987 struct uart_config *uart_cfg = data->uart_cfg;
Erwan Gouriou252a6232020-06-05 10:57:52 +02001988
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07001989 LL_USART_Disable(usart);
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001990
Kenneth J. Millerbde1cd82023-06-23 04:24:49 +02001991 if (!device_is_ready(config->reset.dev)) {
Patryk Duda1aebcec2022-10-28 14:25:13 +02001992 LOG_ERR("reset controller not ready");
1993 return -ENODEV;
1994 }
1995
1996 /* Reset UART to default state using RCC */
Kenneth J. Millerbde1cd82023-06-23 04:24:49 +02001997 (void)reset_line_toggle_dt(&config->reset);
Patryk Duda1aebcec2022-10-28 14:25:13 +02001998
Erwan Gouriouda210ba2017-09-21 15:20:53 +02001999 /* TX/RX direction */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002000 LL_USART_SetTransferDirection(usart, LL_USART_DIRECTION_TX_RX);
Erwan Gouriouda210ba2017-09-21 15:20:53 +02002001
Pisit Sawangvongananb4567fa2024-01-13 00:34:18 +07002002 /* Set basic parameters, such as data-/stop-bit, parity, and baudrate */
Kenneth J. Miller5217a172023-06-20 01:39:32 +02002003 uart_stm32_parameters_set(dev, uart_cfg);
Erwan Gouriouda210ba2017-09-21 15:20:53 +02002004
Jonathan Hahn32f9dcf2022-01-01 23:41:19 +01002005 /* Enable the single wire / half-duplex mode */
2006 if (config->single_wire) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002007 LL_USART_EnableHalfDuplex(usart);
Jonathan Hahn32f9dcf2022-01-01 23:41:19 +01002008 }
2009
Peter Maxwell Warasila3c09c212022-05-09 16:28:51 -04002010#ifdef LL_USART_TXRX_SWAPPED
2011 if (config->tx_rx_swap) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002012 LL_USART_SetTXRXSwap(usart, LL_USART_TXRX_SWAPPED);
Peter Maxwell Warasila3c09c212022-05-09 16:28:51 -04002013 }
2014#endif
2015
Jonathan Hahn05cc2e12022-04-25 20:12:25 +02002016#ifdef LL_USART_RXPIN_LEVEL_INVERTED
2017 if (config->rx_invert) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002018 LL_USART_SetRXPinLevel(usart, LL_USART_RXPIN_LEVEL_INVERTED);
Jonathan Hahn05cc2e12022-04-25 20:12:25 +02002019 }
2020#endif
2021
2022#ifdef LL_USART_TXPIN_LEVEL_INVERTED
2023 if (config->tx_invert) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002024 LL_USART_SetTXPinLevel(usart, LL_USART_TXPIN_LEVEL_INVERTED);
Jonathan Hahn05cc2e12022-04-25 20:12:25 +02002025 }
2026#endif
2027
Armin Braunsb95cdb22023-05-22 14:29:23 +00002028#if HAS_DRIVER_ENABLE
Abram Earlya59c9482023-05-03 10:10:21 -06002029 if (config->de_enable) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002030 if (!IS_UART_DRIVER_ENABLE_INSTANCE(usart)) {
Abram Earlya59c9482023-05-03 10:10:21 -06002031 LOG_ERR("%s does not support driver enable", dev->name);
2032 return -EINVAL;
2033 }
2034
Armin Braunsb95cdb22023-05-22 14:29:23 +00002035 uart_stm32_set_driver_enable(dev, true);
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002036 LL_USART_SetDEAssertionTime(usart, config->de_assert_time);
2037 LL_USART_SetDEDeassertionTime(usart, config->de_deassert_time);
Abram Earlya59c9482023-05-03 10:10:21 -06002038
2039 if (config->de_invert) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002040 LL_USART_SetDESignalPolarity(usart, LL_USART_DE_POLARITY_LOW);
Abram Earlya59c9482023-05-03 10:10:21 -06002041 }
2042 }
2043#endif
2044
Erwan Gouriou0c541d72023-11-27 11:34:29 +01002045#ifdef USART_CR1_FIFOEN
2046 if (config->fifo_enable) {
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002047 LL_USART_EnableFIFO(usart);
Erwan Gouriou0c541d72023-11-27 11:34:29 +01002048 }
2049#endif
2050
Erwan Gouriouad1594e2023-11-28 14:38:54 +01002051#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE)
2052 if (config->wakeup_source) {
2053 /* Enable ability to wakeup device in Stop mode
2054 * Effect depends on CONFIG_PM_DEVICE status:
2055 * CONFIG_PM_DEVICE=n : Always active
2056 * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable()
2057 */
2058#ifdef USART_CR3_WUFIE
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002059 LL_USART_SetWKUPType(usart, LL_USART_WAKEUP_ON_RXNE);
2060 LL_USART_EnableIT_WKUP(usart);
2061 LL_USART_ClearFlag_WKUP(usart);
Erwan Gouriouad1594e2023-11-28 14:38:54 +01002062#endif
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002063 LL_USART_EnableInStopMode(usart);
Erwan Gouriouad1594e2023-11-28 14:38:54 +01002064
Mathieu Choplainb1b85fc2024-08-22 16:50:37 +02002065 if (config->wakeup_line != STM32_WAKEUP_LINE_NONE) {
Erwan Gouriouad1594e2023-11-28 14:38:54 +01002066 /* Prepare the WAKEUP with the expected EXTI line */
2067 LL_EXTI_EnableIT_0_31(BIT(config->wakeup_line));
2068 }
2069 }
2070#endif /* CONFIG_PM */
2071
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002072 LL_USART_Enable(usart);
Erwan Gouriouda210ba2017-09-21 15:20:53 +02002073
Erwan Gouriou80b8c502018-06-13 11:32:38 +02002074#ifdef USART_ISR_TEACK
2075 /* Wait until TEACK flag is set */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002076 while (!(LL_USART_IsActiveFlag_TEACK(usart))) {
Anas Nashif4c322582019-06-04 10:52:23 -04002077 }
Erwan Gouriou80b8c502018-06-13 11:32:38 +02002078#endif /* !USART_ISR_TEACK */
2079
2080#ifdef USART_ISR_REACK
Erwan Gouriou13a96572018-06-18 18:01:06 +02002081 /* Wait until REACK flag is set */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002082 while (!(LL_USART_IsActiveFlag_REACK(usart))) {
Anas Nashif4c322582019-06-04 10:52:23 -04002083 }
Erwan Gouriou80b8c502018-06-13 11:32:38 +02002084#endif /* !USART_ISR_REACK */
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01002085
Kenneth J. Miller31a6e312023-06-20 01:28:09 +02002086 return 0;
2087}
2088
2089/**
2090 * @brief Initialize UART channel
2091 *
2092 * This routine is called to reset the chip in a quiescent state.
2093 * It is assumed that this function is called only once per UART.
2094 *
2095 * @param dev UART device struct
2096 *
2097 * @return 0
2098 */
2099static int uart_stm32_init(const struct device *dev)
2100{
2101 const struct uart_stm32_config *config = dev->config;
2102 int err;
2103
2104 err = uart_stm32_clocks_enable(dev);
2105 if (err < 0) {
2106 return err;
2107 }
2108
2109 /* Configure dt provided device signals when available */
2110 err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
2111 if (err < 0) {
2112 return err;
2113 }
2114
2115 err = uart_stm32_registers_configure(dev);
2116 if (err < 0) {
2117 return err;
2118 }
2119
Gerard Marull-Paretase101cc72022-01-25 16:21:36 +01002120#if defined(CONFIG_PM) || \
2121 defined(CONFIG_UART_INTERRUPT_DRIVEN) || \
2122 defined(CONFIG_UART_ASYNC_API)
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02002123 config->irq_config_func(dev);
Gerard Marull-Paretase101cc72022-01-25 16:21:36 +01002124#endif /* CONFIG_PM || CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API */
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02002125
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002126#ifdef CONFIG_UART_ASYNC_API
2127 return uart_stm32_async_init(dev);
2128#else
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01002129 return 0;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002130#endif
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01002131}
2132
Erwan Gourioua439c042022-08-03 14:39:59 +02002133#ifdef CONFIG_PM_DEVICE
2134static void uart_stm32_suspend_setup(const struct device *dev)
2135{
2136 const struct uart_stm32_config *config = dev->config;
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002137 USART_TypeDef *usart = config->usart;
Erwan Gourioua439c042022-08-03 14:39:59 +02002138
2139#ifdef USART_ISR_BUSY
2140 /* Make sure that no USART transfer is on-going */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002141 while (LL_USART_IsActiveFlag_BUSY(usart) == 1) {
Erwan Gourioua439c042022-08-03 14:39:59 +02002142 }
2143#endif
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002144 while (LL_USART_IsActiveFlag_TC(usart) == 0) {
Erwan Gourioua439c042022-08-03 14:39:59 +02002145 }
2146#ifdef USART_ISR_REACK
2147 /* Make sure that USART is ready for reception */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002148 while (LL_USART_IsActiveFlag_REACK(usart) == 0) {
Erwan Gourioua439c042022-08-03 14:39:59 +02002149 }
2150#endif
2151 /* Clear OVERRUN flag */
Pisit Sawangvonganan86e0fe12024-05-24 13:09:35 +07002152 LL_USART_ClearFlag_ORE(usart);
Erwan Gourioua439c042022-08-03 14:39:59 +02002153}
2154
2155static int uart_stm32_pm_action(const struct device *dev,
2156 enum pm_device_action action)
2157{
2158 const struct uart_stm32_config *config = dev->config;
2159 struct uart_stm32_data *data = dev->data;
2160 int err;
2161
2162
2163 switch (action) {
2164 case PM_DEVICE_ACTION_RESUME:
Guillaume Gautierc1327db2024-01-29 16:56:02 +01002165 /* Set pins to active state */
2166 err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
2167 if (err < 0) {
2168 return err;
2169 }
Erwan Gourioua439c042022-08-03 14:39:59 +02002170
Guillaume Gautierc1327db2024-01-29 16:56:02 +01002171 /* Enable clock */
2172 err = clock_control_on(data->clock,
2173 (clock_control_subsys_t)&config->pclken[0]);
2174 if (err < 0) {
2175 LOG_ERR("Could not enable (LP)UART clock");
2176 return err;
2177 }
2178
2179 if ((IS_ENABLED(CONFIG_PM_S2RAM)) &&
2180 (!LL_USART_IsEnabled(config->usart))) {
2181 /* When exiting low power mode, check whether UART is enabled.
2182 * If not, it means we are exiting Suspend to RAM mode (STM32
2183 * Standby), and the driver needs to be reinitialized.
2184 */
Guillaume Gautier0792a852023-12-08 14:11:53 +01002185 uart_stm32_init(dev);
Erwan Gourioua439c042022-08-03 14:39:59 +02002186 }
2187 break;
2188 case PM_DEVICE_ACTION_SUSPEND:
2189 uart_stm32_suspend_setup(dev);
Erwan Gourioue89e4b52022-08-03 10:47:34 +02002190 /* Stop device clock. Note: fixed clocks are not handled yet. */
Erwan Gourioua439c042022-08-03 14:39:59 +02002191 err = clock_control_off(data->clock, (clock_control_subsys_t)&config->pclken[0]);
Guillaume Gautierc1327db2024-01-29 16:56:02 +01002192 if (err < 0) {
Erwan Gourioua439c042022-08-03 14:39:59 +02002193 LOG_ERR("Could not enable (LP)UART clock");
2194 return err;
2195 }
2196
2197 /* Move pins to sleep state */
2198 err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
Francois Ramu7dff1722023-02-03 15:10:56 +01002199 if ((err < 0) && (err != -ENOENT)) {
2200 /*
2201 * If returning -ENOENT, no pins where defined for sleep mode :
2202 * Do not output on console (might sleep already) when going to sleep,
2203 * "(LP)UART pinctrl sleep state not available"
2204 * and don't block PM suspend.
2205 * Else return the error.
2206 */
Erwan Gourioua439c042022-08-03 14:39:59 +02002207 return err;
2208 }
2209 break;
2210 default:
2211 return -ENOTSUP;
2212 }
2213
2214 return 0;
2215}
2216#endif /* CONFIG_PM_DEVICE */
2217
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002218#ifdef CONFIG_UART_ASYNC_API
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002219
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002220/* src_dev and dest_dev should be 'MEMORY' or 'PERIPHERAL'. */
2221#define UART_DMA_CHANNEL_INIT(index, dir, dir_cap, src_dev, dest_dev) \
Francois Ramu30fd0222021-06-18 15:52:30 +02002222 .dma_dev = DEVICE_DT_GET(STM32_DMA_CTLR(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002223 .dma_channel = DT_INST_DMAS_CELL_BY_NAME(index, dir, channel), \
2224 .dma_cfg = { \
Francois Ramu744e1dc2021-08-09 16:32:57 +02002225 .dma_slot = STM32_DMA_SLOT(index, dir, slot),\
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002226 .channel_direction = STM32_DMA_CONFIG_DIRECTION( \
Francois Ramu30fd0222021-06-18 15:52:30 +02002227 STM32_DMA_CHANNEL_CONFIG(index, dir)),\
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002228 .channel_priority = STM32_DMA_CONFIG_PRIORITY( \
Francois Ramu30fd0222021-06-18 15:52:30 +02002229 STM32_DMA_CHANNEL_CONFIG(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002230 .source_data_size = STM32_DMA_CONFIG_##src_dev##_DATA_SIZE(\
Francois Ramu30fd0222021-06-18 15:52:30 +02002231 STM32_DMA_CHANNEL_CONFIG(index, dir)),\
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002232 .dest_data_size = STM32_DMA_CONFIG_##dest_dev##_DATA_SIZE(\
Francois Ramu30fd0222021-06-18 15:52:30 +02002233 STM32_DMA_CHANNEL_CONFIG(index, dir)),\
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002234 .source_burst_length = 1, /* SINGLE transfer */ \
2235 .dest_burst_length = 1, \
2236 .block_count = 1, \
2237 .dma_callback = uart_stm32_dma_##dir##_cb, \
2238 }, \
2239 .src_addr_increment = STM32_DMA_CONFIG_##src_dev##_ADDR_INC( \
Francois Ramu30fd0222021-06-18 15:52:30 +02002240 STM32_DMA_CHANNEL_CONFIG(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002241 .dst_addr_increment = STM32_DMA_CONFIG_##dest_dev##_ADDR_INC( \
Francois Ramu30fd0222021-06-18 15:52:30 +02002242 STM32_DMA_CHANNEL_CONFIG(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002243 .fifo_threshold = STM32_DMA_FEATURES_FIFO_THRESHOLD( \
Francois Ramu30fd0222021-06-18 15:52:30 +02002244 STM32_DMA_FEATURES(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002245
2246#endif
2247
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02002248#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) || \
2249 defined(CONFIG_PM)
Erwan Gouriou62755132020-02-28 14:54:37 +01002250#define STM32_UART_IRQ_HANDLER_DECL(index) \
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02002251 static void uart_stm32_irq_config_func_##index(const struct device *dev);
Erwan Gouriou62755132020-02-28 14:54:37 +01002252#define STM32_UART_IRQ_HANDLER(index) \
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02002253static void uart_stm32_irq_config_func_##index(const struct device *dev) \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002254{ \
Erwan Gouriouccd6b722020-06-05 09:48:29 +02002255 IRQ_CONNECT(DT_INST_IRQN(index), \
2256 DT_INST_IRQ(index, priority), \
Kumar Galac49b1622020-12-11 10:12:30 -06002257 uart_stm32_isr, DEVICE_DT_INST_GET(index), \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002258 0); \
Erwan Gouriouccd6b722020-06-05 09:48:29 +02002259 irq_enable(DT_INST_IRQN(index)); \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002260}
2261#else
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02002262#define STM32_UART_IRQ_HANDLER_DECL(index) /* Not used */
2263#define STM32_UART_IRQ_HANDLER(index) /* Not used */
2264#endif
2265
Gerard Marull-Paretase101cc72022-01-25 16:21:36 +01002266#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) || \
2267 defined(CONFIG_PM)
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02002268#define STM32_UART_IRQ_HANDLER_FUNC(index) \
2269 .irq_config_func = uart_stm32_irq_config_func_##index,
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02002270#else
2271#define STM32_UART_IRQ_HANDLER_FUNC(index) /* Not used */
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002272#endif
2273
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002274#ifdef CONFIG_UART_ASYNC_API
2275#define UART_DMA_CHANNEL(index, dir, DIR, src, dest) \
Artur Lipowskibb857592022-05-10 12:18:28 +02002276.dma_##dir = { \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002277 COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir), \
2278 (UART_DMA_CHANNEL_INIT(index, dir, DIR, src, dest)), \
Artur Lipowskibb857592022-05-10 12:18:28 +02002279 (NULL)) \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002280 },
2281
2282#else
2283#define UART_DMA_CHANNEL(index, dir, DIR, src, dest)
2284#endif
2285
Erwan Gouriou4422de52022-08-03 14:39:48 +02002286#ifdef CONFIG_PM
Francois Ramu0e119b52022-09-12 16:22:54 +02002287#define STM32_UART_PM_WAKEUP(index) \
2288 .wakeup_source = DT_INST_PROP(index, wakeup_source), \
2289 .wakeup_line = COND_CODE_1(DT_INST_NODE_HAS_PROP(index, wakeup_line), \
2290 (DT_INST_PROP(index, wakeup_line)), \
Mathieu Choplainb1b85fc2024-08-22 16:50:37 +02002291 (STM32_WAKEUP_LINE_NONE)),
Erwan Gouriou4422de52022-08-03 14:39:48 +02002292#else
2293#define STM32_UART_PM_WAKEUP(index) /* Not used */
2294#endif
2295
Kenneth J. Miller044de032023-06-20 01:45:32 +02002296/* Ensure DTS doesn't present an incompatible parity configuration.
2297 * Mark/space parity isn't supported on the STM32 family.
2298 * If 9 data bits are configured, ensure that a parity bit isn't set.
2299 */
2300#define STM32_UART_CHECK_DT_PARITY(index) \
2301BUILD_ASSERT( \
2302 !(DT_INST_ENUM_IDX_OR(index, parity, STM32_UART_DEFAULT_PARITY) \
2303 == UART_CFG_PARITY_MARK || \
2304 DT_INST_ENUM_IDX_OR(index, parity, STM32_UART_DEFAULT_PARITY) \
2305 == UART_CFG_PARITY_SPACE), \
2306 "Node " DT_NODE_PATH(DT_DRV_INST(index)) \
2307 " has unsupported parity configuration"); \
2308BUILD_ASSERT( \
2309 !(DT_INST_ENUM_IDX_OR(index, parity, STM32_UART_DEFAULT_PARITY) \
2310 != UART_CFG_PARITY_NONE && \
2311 DT_INST_ENUM_IDX_OR(index, data_bits, \
2312 STM32_UART_DEFAULT_DATA_BITS) \
2313 == UART_CFG_DATA_BITS_9), \
2314 "Node " DT_NODE_PATH(DT_DRV_INST(index)) \
2315 " has unsupported parity + data bits combination");
2316
2317/* Ensure DTS doesn't present an incompatible data bits configuration
2318 * The STM32 family doesn't support 5 data bits, or 6 data bits without parity.
2319 * Only some series support 7 data bits.
2320 */
2321#ifdef LL_USART_DATAWIDTH_7B
2322#define STM32_UART_CHECK_DT_DATA_BITS(index) \
2323BUILD_ASSERT( \
2324 !(DT_INST_ENUM_IDX_OR(index, data_bits, \
2325 STM32_UART_DEFAULT_DATA_BITS) \
2326 == UART_CFG_DATA_BITS_5 || \
2327 (DT_INST_ENUM_IDX_OR(index, data_bits, \
2328 STM32_UART_DEFAULT_DATA_BITS) \
2329 == UART_CFG_DATA_BITS_6 && \
2330 DT_INST_ENUM_IDX_OR(index, parity, \
2331 STM32_UART_DEFAULT_PARITY) \
2332 == UART_CFG_PARITY_NONE)), \
2333 "Node " DT_NODE_PATH(DT_DRV_INST(index)) \
2334 " has unsupported data bits configuration");
2335#else
2336#define STM32_UART_CHECK_DT_DATA_BITS(index) \
2337BUILD_ASSERT( \
2338 !(DT_INST_ENUM_IDX_OR(index, data_bits, \
2339 STM32_UART_DEFAULT_DATA_BITS) \
2340 == UART_CFG_DATA_BITS_5 || \
2341 DT_INST_ENUM_IDX_OR(index, data_bits, \
2342 STM32_UART_DEFAULT_DATA_BITS) \
2343 == UART_CFG_DATA_BITS_6 || \
2344 (DT_INST_ENUM_IDX_OR(index, data_bits, \
2345 STM32_UART_DEFAULT_DATA_BITS) \
2346 == UART_CFG_DATA_BITS_7 && \
2347 DT_INST_ENUM_IDX_OR(index, parity, \
2348 STM32_UART_DEFAULT_PARITY) \
2349 == UART_CFG_PARITY_NONE)), \
2350 "Node " DT_NODE_PATH(DT_DRV_INST(index)) \
2351 " has unsupported data bits configuration");
2352#endif
2353
2354/* Ensure DTS doesn't present an incompatible stop bits configuration.
2355 * Some STM32 series USARTs don't support 0.5 stop bits, and it generally isn't
2356 * supported for LPUART.
2357 */
2358#ifndef LL_USART_STOPBITS_0_5
2359#define STM32_UART_CHECK_DT_STOP_BITS_0_5(index) \
2360BUILD_ASSERT( \
2361 !(DT_INST_ENUM_IDX_OR(index, stop_bits, \
2362 STM32_UART_DEFAULT_STOP_BITS) \
2363 == UART_CFG_STOP_BITS_0_5), \
2364 "Node " DT_NODE_PATH(DT_DRV_INST(index)) \
2365 " has unsupported stop bits configuration");
2366/* LPUARTs don't support 0.5 stop bits configurations */
2367#else
2368#define STM32_UART_CHECK_DT_STOP_BITS_0_5(index) \
2369BUILD_ASSERT( \
2370 !(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_lpuart) && \
2371 DT_INST_ENUM_IDX_OR(index, stop_bits, \
2372 STM32_UART_DEFAULT_STOP_BITS) \
2373 == UART_CFG_STOP_BITS_0_5), \
2374 "Node " DT_NODE_PATH(DT_DRV_INST(index)) \
2375 " has unsupported stop bits configuration");
2376#endif
2377
2378/* Ensure DTS doesn't present an incompatible stop bits configuration.
2379 * Some STM32 series USARTs don't support 1.5 stop bits, and it generally isn't
2380 * supported for LPUART.
2381 */
2382#ifndef LL_USART_STOPBITS_1_5
2383#define STM32_UART_CHECK_DT_STOP_BITS_1_5(index) \
2384BUILD_ASSERT( \
2385 DT_INST_ENUM_IDX_OR(index, stop_bits, \
2386 STM32_UART_DEFAULT_STOP_BITS) \
2387 != UART_CFG_STOP_BITS_1_5, \
2388 "Node " DT_NODE_PATH(DT_DRV_INST(index)) \
2389 " has unsupported stop bits configuration");
2390/* LPUARTs don't support 1.5 stop bits configurations */
2391#else
2392#define STM32_UART_CHECK_DT_STOP_BITS_1_5(index) \
2393BUILD_ASSERT( \
2394 !(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_lpuart) && \
2395 DT_INST_ENUM_IDX_OR(index, stop_bits, \
2396 STM32_UART_DEFAULT_STOP_BITS) \
2397 == UART_CFG_STOP_BITS_1_5), \
2398 "Node " DT_NODE_PATH(DT_DRV_INST(index)) \
2399 " has unsupported stop bits configuration");
2400#endif
2401
Erwan Gouriou62755132020-02-28 14:54:37 +01002402#define STM32_UART_INIT(index) \
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02002403STM32_UART_IRQ_HANDLER_DECL(index) \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002404 \
Gerard Marull-Paretas5dc6ed32021-12-23 12:33:03 +01002405PINCTRL_DT_INST_DEFINE(index); \
Erwan Gouriou252a6232020-06-05 10:57:52 +02002406 \
Artur Lipowskibb857592022-05-10 12:18:28 +02002407static const struct stm32_pclken pclken_##index[] = \
2408 STM32_DT_INST_CLOCKS(index);\
2409 \
Kenneth J. Millerc8ffeb42023-06-20 01:16:42 +02002410static struct uart_config uart_cfg_##index = { \
2411 .baudrate = DT_INST_PROP_OR(index, current_speed, \
2412 STM32_UART_DEFAULT_BAUDRATE), \
2413 .parity = DT_INST_ENUM_IDX_OR(index, parity, \
2414 STM32_UART_DEFAULT_PARITY), \
2415 .stop_bits = DT_INST_ENUM_IDX_OR(index, stop_bits, \
2416 STM32_UART_DEFAULT_STOP_BITS), \
2417 .data_bits = DT_INST_ENUM_IDX_OR(index, data_bits, \
2418 STM32_UART_DEFAULT_DATA_BITS), \
2419 .flow_ctrl = DT_INST_PROP(index, hw_flow_control) \
2420 ? UART_CFG_FLOW_CTRL_RTS_CTS \
2421 : UART_CFG_FLOW_CTRL_NONE, \
2422}; \
2423 \
Erwan Gouriou62755132020-02-28 14:54:37 +01002424static const struct uart_stm32_config uart_stm32_cfg_##index = { \
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01002425 .usart = (USART_TypeDef *)DT_INST_REG_ADDR(index), \
Kenneth J. Millerbde1cd82023-06-23 04:24:49 +02002426 .reset = RESET_DT_SPEC_GET(DT_DRV_INST(index)), \
Artur Lipowskibb857592022-05-10 12:18:28 +02002427 .pclken = pclken_##index, \
2428 .pclk_len = DT_INST_NUM_CLOCKS(index), \
Gerard Marull-Paretas21a27192021-09-07 16:39:45 +02002429 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \
Roman Studenikin260fc892024-01-24 16:06:47 +00002430 .single_wire = DT_INST_PROP(index, single_wire), \
2431 .tx_rx_swap = DT_INST_PROP(index, tx_rx_swap), \
Erwan Gouriou4422de52022-08-03 14:39:48 +02002432 .rx_invert = DT_INST_PROP(index, rx_invert), \
2433 .tx_invert = DT_INST_PROP(index, tx_invert), \
Abram Earlya59c9482023-05-03 10:10:21 -06002434 .de_enable = DT_INST_PROP(index, de_enable), \
2435 .de_assert_time = DT_INST_PROP(index, de_assert_time), \
2436 .de_deassert_time = DT_INST_PROP(index, de_deassert_time), \
2437 .de_invert = DT_INST_PROP(index, de_invert), \
Erwan Gouriou0c541d72023-11-27 11:34:29 +01002438 .fifo_enable = DT_INST_PROP(index, fifo_enable), \
Gerard Marull-Paretase101cc72022-01-25 16:21:36 +01002439 STM32_UART_IRQ_HANDLER_FUNC(index) \
Erwan Gouriou4422de52022-08-03 14:39:48 +02002440 STM32_UART_PM_WAKEUP(index) \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002441}; \
2442 \
Erwan Gouriou62755132020-02-28 14:54:37 +01002443static struct uart_stm32_data uart_stm32_data_##index = { \
Kenneth J. Millerc8ffeb42023-06-20 01:16:42 +02002444 .uart_cfg = &uart_cfg_##index, \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02002445 UART_DMA_CHANNEL(index, rx, RX, PERIPHERAL, MEMORY) \
2446 UART_DMA_CHANNEL(index, tx, TX, MEMORY, PERIPHERAL) \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002447}; \
2448 \
Pisit Sawangvonganana2e0b1d2024-07-06 18:43:11 +07002449PM_DEVICE_DT_INST_DEFINE(index, uart_stm32_pm_action); \
Erwan Gourioua439c042022-08-03 14:39:59 +02002450 \
Kumar Galac49b1622020-12-11 10:12:30 -06002451DEVICE_DT_INST_DEFINE(index, \
Pisit Sawangvonganana2e0b1d2024-07-06 18:43:11 +07002452 uart_stm32_init, \
Erwan Gourioua439c042022-08-03 14:39:59 +02002453 PM_DEVICE_DT_INST_GET(index), \
Erwan Gouriou62755132020-02-28 14:54:37 +01002454 &uart_stm32_data_##index, &uart_stm32_cfg_##index, \
Maureen Helmad145052021-10-14 09:38:10 -05002455 PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02002456 &uart_stm32_driver_api); \
2457 \
Kenneth J. Miller044de032023-06-20 01:45:32 +02002458STM32_UART_IRQ_HANDLER(index) \
2459 \
2460STM32_UART_CHECK_DT_PARITY(index) \
2461STM32_UART_CHECK_DT_DATA_BITS(index) \
2462STM32_UART_CHECK_DT_STOP_BITS_0_5(index) \
2463STM32_UART_CHECK_DT_STOP_BITS_1_5(index)
Erwan Gouriou8c079e92016-11-14 11:53:52 +01002464
Martí Bolívar7e0eed92020-05-06 11:23:07 -07002465DT_INST_FOREACH_STATUS_OKAY(STM32_UART_INIT)