blob: 297e6e4abd37c22f232a9e89516eec7932c98083 [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.
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01004 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08005 * SPDX-License-Identifier: Apache-2.0
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01006 */
7
Kumar Gala989484b2020-03-24 14:28:48 -05008#define DT_DRV_COMPAT st_stm32_uart
9
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010010/**
Ilya Tagunov84cffc72018-03-20 20:44:45 +030011 * @brief Driver for UART port on STM32 family processor.
Georgij Cernysiov78eed342019-03-15 19:51:09 +010012 * @note LPUART and U(S)ART have the same base and
13 * majority of operations are performed the same way.
14 * Please validate for newly added series.
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010015 */
16
Flavio Santesb04cdcd2016-12-04 14:59:37 -060017#include <kernel.h>
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010018#include <arch/cpu.h>
Anas Nashif5eb90ec2019-06-26 10:33:39 -040019#include <sys/__assert.h>
Kumar Galaaa2bdbe2018-10-31 12:44:45 -050020#include <soc.h>
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010021#include <init.h>
Anas Nashifd1b27182019-06-25 15:54:01 -040022#include <drivers/uart.h>
Anas Nashif17ddd172019-06-25 15:53:47 -040023#include <drivers/clock_control.h>
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +020024#include <pm/pm.h>
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010025
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +020026#ifdef CONFIG_UART_ASYNC_API
Francois Ramu30fd0222021-06-18 15:52:30 +020027#include <drivers/dma/dma_stm32.h>
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +020028#include <drivers/dma.h>
29#endif
30
Anas Nashif397d29d2017-06-17 11:30:47 -040031#include <linker/sections.h>
Peter Bigot0b0d2e642020-01-25 05:34:53 -060032#include <drivers/clock_control/stm32_clock_control.h>
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010033#include "uart_stm32.h"
34
Gerard Marull-Paretase83fab32020-10-03 23:58:36 +020035#include <stm32_ll_usart.h>
36#include <stm32_ll_lpuart.h>
37
Francois Ramud3ffa8d2019-11-12 16:13:03 +010038#include <logging/log.h>
Pete Dietl060e39e2022-03-04 12:56:05 -080039LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL);
Francois Ramud3ffa8d2019-11-12 16:13:03 +010040
Kumar Galac2135f82020-05-07 12:22:26 -050041#define HAS_LPUART_1 (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart1), \
42 st_stm32_lpuart, okay))
Erwan Gouriou76313f02020-04-17 12:33:29 +020043
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +080044#if HAS_LPUART_1
45#ifdef USART_PRESC_PRESCALER
46uint32_t lpuartdiv_calc(const uint64_t clock_rate, const uint16_t presc_idx,
47 const uint32_t baud_rate)
48{
49 uint64_t lpuartdiv;
50
51 lpuartdiv = clock_rate / LPUART_PRESCALER_TAB[presc_idx];
52 lpuartdiv *= LPUART_LPUARTDIV_FREQ_MUL;
53 lpuartdiv += baud_rate / 2;
54 lpuartdiv /= baud_rate;
55
56 return (uint32_t)lpuartdiv;
57}
58#else
59uint32_t lpuartdiv_calc(const uint64_t clock_rate, const uint32_t baud_rate)
60{
61 uint64_t lpuartdiv;
62
63 lpuartdiv = clock_rate * LPUART_LPUARTDIV_FREQ_MUL;
64 lpuartdiv += baud_rate / 2;
65 lpuartdiv /= baud_rate;
66
67 return (uint32_t)lpuartdiv;
68}
69#endif /* USART_PRESC_PRESCALER */
70#endif /* HAS_LPUART_1 */
71
Erwan Gouriou8c079e92016-11-14 11:53:52 +010072#define TIMEOUT 1000
Maciek Borzecki5a73ca62016-03-03 15:33:20 +010073
Erwan Gourioua3de3df2021-09-14 09:27:56 +020074#ifdef CONFIG_PM
75static void uart_stm32_pm_constraint_set(const struct device *dev)
76{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +010077 struct uart_stm32_data *data = dev->data;
Erwan Gourioua3de3df2021-09-14 09:27:56 +020078
79 if (!data->pm_constraint_on) {
80 data->pm_constraint_on = true;
81 pm_constraint_set(PM_STATE_SUSPEND_TO_IDLE);
82 }
83}
84
85static void uart_stm32_pm_constraint_release(const struct device *dev)
86{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +010087 struct uart_stm32_data *data = dev->data;
Erwan Gourioua3de3df2021-09-14 09:27:56 +020088
89 if (data->pm_constraint_on) {
90 data->pm_constraint_on = false;
91 pm_constraint_release(PM_STATE_SUSPEND_TO_IDLE);
92 }
93}
94#endif /* CONFIG_PM */
95
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020096static inline void uart_stm32_set_baudrate(const struct device *dev,
97 uint32_t baud_rate)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -080098{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +010099 const struct uart_stm32_config *config = dev->config;
100 struct uart_stm32_data *data = dev->data;
Erwan Gouriou69a28962019-05-20 17:15:02 +0200101
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500102 uint32_t clock_rate;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800103
104 /* Get clock rate */
Francois Ramud3ffa8d2019-11-12 16:13:03 +0100105 if (clock_control_get_rate(data->clock,
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800106 (clock_control_subsys_t *)&config->pclken,
Francois Ramud3ffa8d2019-11-12 16:13:03 +0100107 &clock_rate) < 0) {
108 LOG_ERR("Failed call clock_control_get_rate");
109 return;
110 }
Erwan Gouriou69a28962019-05-20 17:15:02 +0200111
Erwan Gouriou76313f02020-04-17 12:33:29 +0200112#if HAS_LPUART_1
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100113 if (IS_LPUART_INSTANCE(config->usart)) {
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +0800114 uint32_t lpuartdiv;
115#ifdef USART_PRESC_PRESCALER
116 uint8_t presc_idx;
117 uint32_t presc_val;
118
119 for (presc_idx = 0; presc_idx < ARRAY_SIZE(LPUART_PRESCALER_TAB); presc_idx++) {
120 lpuartdiv = lpuartdiv_calc(clock_rate, presc_idx, baud_rate);
121 if (lpuartdiv >= LPUART_BRR_MIN_VALUE && lpuartdiv <= LPUART_BRR_MASK) {
122 break;
123 }
124 }
125
126 if (presc_idx == ARRAY_SIZE(LPUART_PRESCALER_TAB)) {
127 LOG_ERR("Unable to set %s to %d", dev->name, baud_rate);
128 return;
129 }
130
131 presc_val = presc_idx << USART_PRESC_PRESCALER_Pos;
132
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100133 LL_LPUART_SetPrescaler(config->usart, presc_val);
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +0800134#else
135 lpuartdiv = lpuartdiv_calc(clock_rate, baud_rate);
136 if (lpuartdiv < LPUART_BRR_MIN_VALUE || lpuartdiv > LPUART_BRR_MASK) {
137 LOG_ERR("Unable to set %s to %d", dev->name, baud_rate);
138 return;
139 }
140#endif /* USART_PRESC_PRESCALER */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100141 LL_LPUART_SetBaudRate(config->usart,
Erwan Gouriou69a28962019-05-20 17:15:02 +0200142 clock_rate,
143#ifdef USART_PRESC_PRESCALER
Yong Cong Sina6ebcdd2021-10-22 00:02:29 +0800144 presc_val,
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800145#endif
Erwan Gouriou69a28962019-05-20 17:15:02 +0200146 baud_rate);
147 } else {
Erwan Gouriou76313f02020-04-17 12:33:29 +0200148#endif /* HAS_LPUART_1 */
Erwan Gouriou37c7b892021-01-08 10:54:46 +0100149#ifdef USART_CR1_OVER8
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100150 LL_USART_SetOverSampling(config->usart,
Erwan Gouriou37c7b892021-01-08 10:54:46 +0100151 LL_USART_OVERSAMPLING_16);
152#endif
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100153 LL_USART_SetBaudRate(config->usart,
Erwan Gouriou69a28962019-05-20 17:15:02 +0200154 clock_rate,
155#ifdef USART_PRESC_PRESCALER
156 LL_USART_PRESCALER_DIV1,
157#endif
158#ifdef USART_CR1_OVER8
159 LL_USART_OVERSAMPLING_16,
160#endif
161 baud_rate);
162
Erwan Gouriou76313f02020-04-17 12:33:29 +0200163#if HAS_LPUART_1
Erwan Gouriou69a28962019-05-20 17:15:02 +0200164 }
Erwan Gouriou76313f02020-04-17 12:33:29 +0200165#endif /* HAS_LPUART_1 */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800166}
167
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200168static inline void uart_stm32_set_parity(const struct device *dev,
169 uint32_t parity)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800170{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100171 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800172
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100173 LL_USART_SetParity(config->usart, parity);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800174}
175
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200176static inline uint32_t uart_stm32_get_parity(const struct device *dev)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800177{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100178 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800179
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100180 return LL_USART_GetParity(config->usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800181}
182
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200183static inline void uart_stm32_set_stopbits(const struct device *dev,
184 uint32_t stopbits)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800185{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100186 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800187
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100188 LL_USART_SetStopBitsLength(config->usart, stopbits);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800189}
190
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200191static inline uint32_t uart_stm32_get_stopbits(const struct device *dev)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800192{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100193 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800194
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100195 return LL_USART_GetStopBitsLength(config->usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800196}
197
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200198static inline void uart_stm32_set_databits(const struct device *dev,
199 uint32_t databits)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800200{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100201 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800202
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100203 LL_USART_SetDataWidth(config->usart, databits);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800204}
205
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200206static inline uint32_t uart_stm32_get_databits(const struct device *dev)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800207{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100208 const struct uart_stm32_config *config = dev->config;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800209
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100210 return LL_USART_GetDataWidth(config->usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800211}
212
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200213static inline void uart_stm32_set_hwctrl(const struct device *dev,
214 uint32_t hwctrl)
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100215{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100216 const struct uart_stm32_config *config = dev->config;
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100217
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100218 LL_USART_SetHWFlowCtrl(config->usart, hwctrl);
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100219}
220
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200221static inline uint32_t uart_stm32_get_hwctrl(const struct device *dev)
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100222{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100223 const struct uart_stm32_config *config = dev->config;
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100224
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100225 return LL_USART_GetHWFlowCtrl(config->usart);
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100226}
227
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500228static inline uint32_t uart_stm32_cfg2ll_parity(enum uart_config_parity parity)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800229{
230 switch (parity) {
231 case UART_CFG_PARITY_ODD:
232 return LL_USART_PARITY_ODD;
233 case UART_CFG_PARITY_EVEN:
234 return LL_USART_PARITY_EVEN;
235 case UART_CFG_PARITY_NONE:
236 default:
237 return LL_USART_PARITY_NONE;
238 }
239}
240
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500241static inline enum uart_config_parity uart_stm32_ll2cfg_parity(uint32_t parity)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800242{
243 switch (parity) {
244 case LL_USART_PARITY_ODD:
245 return UART_CFG_PARITY_ODD;
246 case LL_USART_PARITY_EVEN:
247 return UART_CFG_PARITY_EVEN;
248 case LL_USART_PARITY_NONE:
249 default:
250 return UART_CFG_PARITY_NONE;
251 }
252}
253
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500254static inline uint32_t uart_stm32_cfg2ll_stopbits(enum uart_config_stop_bits sb)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800255{
256 switch (sb) {
257/* Some MCU's don't support 0.5 stop bits */
258#ifdef LL_USART_STOPBITS_0_5
259 case UART_CFG_STOP_BITS_0_5:
260 return LL_USART_STOPBITS_0_5;
261#endif /* LL_USART_STOPBITS_0_5 */
262 case UART_CFG_STOP_BITS_1:
263 return LL_USART_STOPBITS_1;
264/* Some MCU's don't support 1.5 stop bits */
265#ifdef LL_USART_STOPBITS_1_5
266 case UART_CFG_STOP_BITS_1_5:
267 return LL_USART_STOPBITS_1_5;
268#endif /* LL_USART_STOPBITS_1_5 */
269 case UART_CFG_STOP_BITS_2:
270 default:
271 return LL_USART_STOPBITS_2;
272 }
273}
274
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500275static inline enum uart_config_stop_bits uart_stm32_ll2cfg_stopbits(uint32_t sb)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800276{
277 switch (sb) {
278/* Some MCU's don't support 0.5 stop bits */
279#ifdef LL_USART_STOPBITS_0_5
280 case LL_USART_STOPBITS_0_5:
281 return UART_CFG_STOP_BITS_0_5;
282#endif /* LL_USART_STOPBITS_0_5 */
283 case LL_USART_STOPBITS_1:
284 return UART_CFG_STOP_BITS_1;
285/* Some MCU's don't support 1.5 stop bits */
286#ifdef LL_USART_STOPBITS_1_5
287 case LL_USART_STOPBITS_1_5:
288 return UART_CFG_STOP_BITS_1_5;
289#endif /* LL_USART_STOPBITS_1_5 */
290 case LL_USART_STOPBITS_2:
291 default:
292 return UART_CFG_STOP_BITS_2;
293 }
294}
295
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100296static inline uint32_t uart_stm32_cfg2ll_databits(enum uart_config_data_bits db,
297 enum uart_config_parity p)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800298{
299 switch (db) {
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100300/* Some MCU's don't support 7B or 9B datawidth */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800301#ifdef LL_USART_DATAWIDTH_7B
302 case UART_CFG_DATA_BITS_7:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100303 if (p == UART_CFG_PARITY_NONE) {
304 return LL_USART_DATAWIDTH_7B;
305 } else {
306 return LL_USART_DATAWIDTH_8B;
307 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800308#endif /* LL_USART_DATAWIDTH_7B */
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100309#ifdef LL_USART_DATAWIDTH_9B
310 case UART_CFG_DATA_BITS_9:
311 return LL_USART_DATAWIDTH_9B;
312#endif /* LL_USART_DATAWIDTH_9B */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800313 case UART_CFG_DATA_BITS_8:
314 default:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100315 if (p == UART_CFG_PARITY_NONE) {
316 return LL_USART_DATAWIDTH_8B;
317#ifdef LL_USART_DATAWIDTH_9B
318 } else {
319 return LL_USART_DATAWIDTH_9B;
320#endif
321 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800322 return LL_USART_DATAWIDTH_8B;
323 }
324}
325
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100326static inline enum uart_config_data_bits uart_stm32_ll2cfg_databits(uint32_t db,
327 uint32_t p)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800328{
329 switch (db) {
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100330/* Some MCU's don't support 7B or 9B datawidth */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800331#ifdef LL_USART_DATAWIDTH_7B
332 case LL_USART_DATAWIDTH_7B:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100333 if (p == LL_USART_PARITY_NONE) {
334 return UART_CFG_DATA_BITS_7;
335 } else {
336 return UART_CFG_DATA_BITS_6;
337 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800338#endif /* LL_USART_DATAWIDTH_7B */
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100339#ifdef LL_USART_DATAWIDTH_9B
340 case LL_USART_DATAWIDTH_9B:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100341 if (p == LL_USART_PARITY_NONE) {
342 return UART_CFG_DATA_BITS_9;
343 } else {
344 return UART_CFG_DATA_BITS_8;
345 }
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100346#endif /* LL_USART_DATAWIDTH_9B */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800347 case LL_USART_DATAWIDTH_8B:
348 default:
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100349 if (p == LL_USART_PARITY_NONE) {
350 return UART_CFG_DATA_BITS_8;
351 } else {
352 return UART_CFG_DATA_BITS_7;
353 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800354 }
355}
356
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100357/**
358 * @brief Get LL hardware flow control define from
359 * Zephyr hardware flow control option.
360 * @note Supports only UART_CFG_FLOW_CTRL_RTS_CTS.
361 * @param fc: Zephyr hardware flow control option.
362 * @retval LL_USART_HWCONTROL_RTS_CTS, or LL_USART_HWCONTROL_NONE.
363 */
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500364static inline uint32_t uart_stm32_cfg2ll_hwctrl(enum uart_config_flow_control fc)
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100365{
366 if (fc == UART_CFG_FLOW_CTRL_RTS_CTS) {
367 return LL_USART_HWCONTROL_RTS_CTS;
368 }
369
370 return LL_USART_HWCONTROL_NONE;
371}
372
373/**
Yannis Damigosa4b448e2020-02-06 20:36:03 +0200374 * @brief Get Zephyr hardware flow control option from
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100375 * LL hardware flow control define.
376 * @note Supports only LL_USART_HWCONTROL_RTS_CTS.
Yannis Damigosa4b448e2020-02-06 20:36:03 +0200377 * @param fc: LL hardware flow control definition.
Kumar Gala61153462020-02-06 11:30:05 -0600378 * @retval UART_CFG_FLOW_CTRL_RTS_CTS, or UART_CFG_FLOW_CTRL_NONE.
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100379 */
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500380static inline enum uart_config_flow_control uart_stm32_ll2cfg_hwctrl(uint32_t fc)
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100381{
382 if (fc == LL_USART_HWCONTROL_RTS_CTS) {
383 return UART_CFG_FLOW_CTRL_RTS_CTS;
384 }
385
Kumar Gala61153462020-02-06 11:30:05 -0600386 return UART_CFG_FLOW_CTRL_NONE;
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100387}
388
Daniel Leung4e1692f2021-05-26 12:33:37 -0700389#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200390static int uart_stm32_configure(const struct device *dev,
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800391 const struct uart_config *cfg)
392{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100393 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100394 struct uart_stm32_data *data = dev->data;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500395 const uint32_t parity = uart_stm32_cfg2ll_parity(cfg->parity);
396 const uint32_t stopbits = uart_stm32_cfg2ll_stopbits(cfg->stop_bits);
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100397 const uint32_t databits = uart_stm32_cfg2ll_databits(cfg->data_bits,
398 cfg->parity);
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500399 const uint32_t flowctrl = uart_stm32_cfg2ll_hwctrl(cfg->flow_ctrl);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800400
401 /* Hardware doesn't support mark or space parity */
Erwan Gouriou5e561702021-02-11 09:55:38 +0100402 if ((cfg->parity == UART_CFG_PARITY_MARK) ||
403 (cfg->parity == UART_CFG_PARITY_SPACE)) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800404 return -ENOTSUP;
405 }
406
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100407 /* Driver does not supports parity + 9 databits */
408 if ((cfg->parity != UART_CFG_PARITY_NONE) &&
409 (cfg->data_bits == UART_CFG_DATA_BITS_9)) {
410 return -ENOTSUP;
411 }
412
Erwan Gouriou76313f02020-04-17 12:33:29 +0200413#if defined(LL_USART_STOPBITS_0_5) && HAS_LPUART_1
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100414 if (IS_LPUART_INSTANCE(config->usart) &&
Erwan Gouriou5e561702021-02-11 09:55:38 +0100415 (cfg->stop_bits == UART_CFG_STOP_BITS_0_5)) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800416 return -ENOTSUP;
417 }
418#else
Erwan Gouriou5e561702021-02-11 09:55:38 +0100419 if (cfg->stop_bits == UART_CFG_STOP_BITS_0_5) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800420 return -ENOTSUP;
421 }
422#endif
423
Erwan Gouriou76313f02020-04-17 12:33:29 +0200424#if defined(LL_USART_STOPBITS_1_5) && HAS_LPUART_1
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100425 if (IS_LPUART_INSTANCE(config->usart) &&
Erwan Gouriou5e561702021-02-11 09:55:38 +0100426 (cfg->stop_bits == UART_CFG_STOP_BITS_1_5)) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800427 return -ENOTSUP;
428 }
429#else
Erwan Gouriou5e561702021-02-11 09:55:38 +0100430 if (cfg->stop_bits == UART_CFG_STOP_BITS_1_5) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800431 return -ENOTSUP;
432 }
433#endif
434
Benoit Leforestier9fee67d2019-03-22 14:19:57 +0100435 /* Driver doesn't support 5 or 6 databits and potentially 7 or 9 */
Erwan Gouriou5e561702021-02-11 09:55:38 +0100436 if ((cfg->data_bits == UART_CFG_DATA_BITS_5) ||
437 (cfg->data_bits == UART_CFG_DATA_BITS_6)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800438#ifndef LL_USART_DATAWIDTH_7B
Erwan Gouriou5e561702021-02-11 09:55:38 +0100439 || (cfg->data_bits == UART_CFG_DATA_BITS_7)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800440#endif /* LL_USART_DATAWIDTH_7B */
Erwan Gouriou5e561702021-02-11 09:55:38 +0100441 || (cfg->data_bits == UART_CFG_DATA_BITS_9)) {
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800442 return -ENOTSUP;
443 }
444
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100445 /* Driver supports only RTS CTS flow control */
Erwan Gouriou5e561702021-02-11 09:55:38 +0100446 if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) {
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100447 if (!IS_UART_HWFLOW_INSTANCE(config->usart) ||
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100448 UART_CFG_FLOW_CTRL_RTS_CTS != cfg->flow_ctrl) {
449 return -ENOTSUP;
450 }
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800451 }
452
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100453 LL_USART_Disable(config->usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800454
455 if (parity != uart_stm32_get_parity(dev)) {
456 uart_stm32_set_parity(dev, parity);
457 }
458
459 if (stopbits != uart_stm32_get_stopbits(dev)) {
460 uart_stm32_set_stopbits(dev, stopbits);
461 }
462
463 if (databits != uart_stm32_get_databits(dev)) {
464 uart_stm32_set_databits(dev, databits);
465 }
466
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100467 if (flowctrl != uart_stm32_get_hwctrl(dev)) {
468 uart_stm32_set_hwctrl(dev, flowctrl);
469 }
470
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800471 if (cfg->baudrate != data->baud_rate) {
472 uart_stm32_set_baudrate(dev, cfg->baudrate);
473 data->baud_rate = cfg->baudrate;
474 }
475
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100476 LL_USART_Enable(config->usart);
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800477 return 0;
478};
479
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200480static int uart_stm32_config_get(const struct device *dev,
481 struct uart_config *cfg)
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800482{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100483 struct uart_stm32_data *data = dev->data;
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800484
485 cfg->baudrate = data->baud_rate;
486 cfg->parity = uart_stm32_ll2cfg_parity(uart_stm32_get_parity(dev));
487 cfg->stop_bits = uart_stm32_ll2cfg_stopbits(
488 uart_stm32_get_stopbits(dev));
489 cfg->data_bits = uart_stm32_ll2cfg_databits(
Nicolas VINCENT573eec12021-03-10 13:23:00 +0100490 uart_stm32_get_databits(dev), uart_stm32_get_parity(dev));
Georgij Cernysiov78eed342019-03-15 19:51:09 +0100491 cfg->flow_ctrl = uart_stm32_ll2cfg_hwctrl(
492 uart_stm32_get_hwctrl(dev));
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800493 return 0;
494}
Daniel Leung4e1692f2021-05-26 12:33:37 -0700495#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
Pushpal Sidhuacd0e252019-01-07 13:52:24 -0800496
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200497static int uart_stm32_poll_in(const struct device *dev, unsigned char *c)
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100498{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100499 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100500
Kiril Zyapkov7a602fc2018-11-02 15:34:56 +0200501 /* Clear overrun error flag */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100502 if (LL_USART_IsActiveFlag_ORE(config->usart)) {
503 LL_USART_ClearFlag_ORE(config->usart);
Kiril Zyapkov7a602fc2018-11-02 15:34:56 +0200504 }
505
Francois Ramu860bd872022-01-28 16:52:28 +0100506 /*
507 * On stm32 F4X, F1X, and F2X, the RXNE flag is affected (cleared) by
508 * the uart_err_check function call (on errors flags clearing)
509 */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100510 if (!LL_USART_IsActiveFlag_RXNE(config->usart)) {
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100511 return -1;
512 }
Erwan Gouriouda210ba2017-09-21 15:20:53 +0200513
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100514 *c = (unsigned char)LL_USART_ReceiveData8(config->usart);
Erwan Gouriouda210ba2017-09-21 15:20:53 +0200515
516 return 0;
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100517}
518
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200519static void uart_stm32_poll_out(const struct device *dev,
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100520 unsigned char c)
521{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100522 const struct uart_stm32_config *config = dev->config;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100523#ifdef CONFIG_PM
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100524 struct uart_stm32_data *data = dev->data;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100525#endif
526 int key;
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100527
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100528 /* Wait for TXE flag to be raised
529 * When TXE flag is raised, we lock interrupts to prevent interrupts (notably that of usart)
530 * or thread switch. Then, we can safely send our character. The character sent will be
531 * interlaced with the characters potentially send with interrupt transmission API
532 */
Julien D'ascenziod42cef12021-11-08 12:47:25 +0100533 while (1) {
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100534 if (LL_USART_IsActiveFlag_TXE(config->usart)) {
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100535 key = irq_lock();
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100536 if (LL_USART_IsActiveFlag_TXE(config->usart)) {
Julien D'ascenziod42cef12021-11-08 12:47:25 +0100537 break;
538 }
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100539 irq_unlock(key);
540 }
Anas Nashif4c322582019-06-04 10:52:23 -0400541 }
Erwan Gouriouda210ba2017-09-21 15:20:53 +0200542
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200543#ifdef CONFIG_PM
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200544
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100545 /* If an interrupt transmission is in progress, the pm constraint is already managed by the
546 * call of uart_stm32_irq_tx_[en|dis]able
547 */
548 if (!data->tx_poll_stream_on && !data->tx_int_stream_on) {
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200549 data->tx_poll_stream_on = true;
550
551 /* Don't allow system to suspend until stream
552 * transmission has completed
553 */
554 uart_stm32_pm_constraint_set(dev);
555
556 /* Enable TC interrupt so we can release suspend
557 * constraint when done
558 */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100559 LL_USART_EnableIT_TC(config->usart);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200560 }
561#endif /* CONFIG_PM */
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +0200562
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100563 LL_USART_TransmitData8(config->usart, (uint8_t)c);
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100564 irq_unlock(key);
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100565}
566
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200567static int uart_stm32_err_check(const struct device *dev)
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100568{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100569 const struct uart_stm32_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500570 uint32_t err = 0U;
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100571
Francois Ramu860bd872022-01-28 16:52:28 +0100572 /* Check for errors, then clear them.
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100573 * Some SoC clear all error flags when at least
Francois Ramu860bd872022-01-28 16:52:28 +0100574 * one is cleared. (e.g. F4X, F1X, and F2X).
575 * The stm32 F4X, F1X, and F2X also reads the usart DR when clearing Errors
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100576 */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100577 if (LL_USART_IsActiveFlag_ORE(config->usart)) {
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100578 err |= UART_ERROR_OVERRUN;
579 }
580
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100581 if (LL_USART_IsActiveFlag_PE(config->usart)) {
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100582 err |= UART_ERROR_PARITY;
583 }
584
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100585 if (LL_USART_IsActiveFlag_FE(config->usart)) {
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100586 err |= UART_ERROR_FRAMING;
587 }
588
Andrea Campanellab2190fd2021-12-21 16:09:15 +0000589#if !defined(CONFIG_SOC_SERIES_STM32F0X) || defined(USART_LIN_SUPPORT)
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100590 if (LL_USART_IsActiveFlag_LBD(config->usart)) {
Andrea Campanellab2190fd2021-12-21 16:09:15 +0000591 err |= UART_BREAK;
592 }
593
594 if (err & UART_BREAK) {
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100595 LL_USART_ClearFlag_LBD(config->usart);
Andrea Campanellab2190fd2021-12-21 16:09:15 +0000596 }
597#endif
Francois Ramu860bd872022-01-28 16:52:28 +0100598 /* Clearing error :
599 * the stm32 F4X, F1X, and F2X sw sequence is reading the usart SR
600 * then the usart DR to clear the Error flags ORE, PE, FE, NE
601 * --> so is the RXNE flag also cleared !
602 */
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100603 if (err & UART_ERROR_OVERRUN) {
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100604 LL_USART_ClearFlag_ORE(config->usart);
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100605 }
606
607 if (err & UART_ERROR_PARITY) {
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100608 LL_USART_ClearFlag_PE(config->usart);
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100609 }
610
611 if (err & UART_ERROR_FRAMING) {
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100612 LL_USART_ClearFlag_FE(config->usart);
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100613 }
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100614 /* Clear noise error as well,
615 * it is not represented by the errors enum
616 */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100617 LL_USART_ClearFlag_NE(config->usart);
Georgij Cernysiovc74c1312019-02-14 10:50:19 +0100618
619 return err;
620}
621
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200622static inline void __uart_stm32_get_clock(const struct device *dev)
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100623{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100624 struct uart_stm32_data *data = dev->data;
Kumar Galab275fec2021-02-11 11:49:24 -0600625 const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100626
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100627 data->clock = clk;
Maciek Borzecki5a73ca62016-03-03 15:33:20 +0100628}
629
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100630#ifdef CONFIG_UART_INTERRUPT_DRIVEN
631
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200632static int uart_stm32_fifo_fill(const struct device *dev,
633 const uint8_t *tx_data,
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100634 int size)
635{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100636 const struct uart_stm32_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500637 uint8_t num_tx = 0U;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100638 int key;
639
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100640 if (!LL_USART_IsActiveFlag_TXE(config->usart)) {
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100641 return num_tx;
642 }
643
644 /* Lock interrupts to prevent nested interrupts or thread switch */
645 key = irq_lock();
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100646
Erwan Gouriouda210ba2017-09-21 15:20:53 +0200647 while ((size - num_tx > 0) &&
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100648 LL_USART_IsActiveFlag_TXE(config->usart)) {
Georgij Cernysiov3de55da2019-02-06 23:31:24 +0100649 /* TXE flag will be cleared with byte write to DR|RDR register */
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100650
651 /* Send a character (8bit , parity none) */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100652 LL_USART_TransmitData8(config->usart, tx_data[num_tx++]);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100653 }
654
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100655 irq_unlock(key);
656
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100657 return num_tx;
658}
659
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200660static int uart_stm32_fifo_read(const struct device *dev, uint8_t *rx_data,
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100661 const int size)
662{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100663 const struct uart_stm32_config *config = dev->config;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500664 uint8_t num_rx = 0U;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100665
Erwan Gouriouda210ba2017-09-21 15:20:53 +0200666 while ((size - num_rx > 0) &&
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100667 LL_USART_IsActiveFlag_RXNE(config->usart)) {
Georgij Cernysiov3de55da2019-02-06 23:31:24 +0100668 /* RXNE flag will be cleared upon read from DR|RDR register */
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100669
670 /* Receive a character (8bit , parity none) */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100671 rx_data[num_rx++] = LL_USART_ReceiveData8(config->usart);
Kiril Zyapkov7a602fc2018-11-02 15:34:56 +0200672
673 /* Clear overrun error flag */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100674 if (LL_USART_IsActiveFlag_ORE(config->usart)) {
675 LL_USART_ClearFlag_ORE(config->usart);
Francois Ramu860bd872022-01-28 16:52:28 +0100676 /*
677 * On stm32 F4X, F1X, and F2X, the RXNE flag is affected (cleared) by
678 * the uart_err_check function call (on errors flags clearing)
679 */
Kiril Zyapkov7a602fc2018-11-02 15:34:56 +0200680 }
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100681 }
Georgij Cernysiov3de55da2019-02-06 23:31:24 +0100682
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100683 return num_rx;
684}
685
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200686static void uart_stm32_irq_tx_enable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100687{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100688 const struct uart_stm32_config *config = dev->config;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100689#ifdef CONFIG_PM
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100690 struct uart_stm32_data *data = dev->data;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100691 int key;
692#endif
Julien D'ascenziod42cef12021-11-08 12:47:25 +0100693
694#ifdef CONFIG_PM
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100695 key = irq_lock();
Julien D'ascenzio7b210502021-10-26 18:03:31 +0200696 data->tx_poll_stream_on = false;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100697 data->tx_int_stream_on = true;
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200698 uart_stm32_pm_constraint_set(dev);
699#endif
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100700 LL_USART_EnableIT_TC(config->usart);
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100701
702#ifdef CONFIG_PM
703 irq_unlock(key);
704#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100705}
706
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200707static void uart_stm32_irq_tx_disable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100708{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100709 const struct uart_stm32_config *config = dev->config;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100710#ifdef CONFIG_PM
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100711 struct uart_stm32_data *data = dev->data;
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100712 int key;
713
714 key = irq_lock();
715#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100716
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100717 LL_USART_DisableIT_TC(config->usart);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200718
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100719#ifdef CONFIG_PM
720 data->tx_int_stream_on = false;
721 uart_stm32_pm_constraint_release(dev);
722#endif
Julien D'ascenziod42cef12021-11-08 12:47:25 +0100723
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200724#ifdef CONFIG_PM
Julien D'ascenzioe4234ae2021-12-01 10:19:44 +0100725 irq_unlock(key);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200726#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100727}
728
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200729static int uart_stm32_irq_tx_ready(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100730{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100731 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100732
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100733 return LL_USART_IsActiveFlag_TXE(config->usart) &&
734 LL_USART_IsEnabledIT_TC(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100735}
736
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200737static int uart_stm32_irq_tx_complete(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100738{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100739 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100740
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100741 return LL_USART_IsActiveFlag_TC(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100742}
743
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200744static void uart_stm32_irq_rx_enable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100745{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100746 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100747
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100748 LL_USART_EnableIT_RXNE(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100749}
750
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200751static void uart_stm32_irq_rx_disable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100752{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100753 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100754
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100755 LL_USART_DisableIT_RXNE(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100756}
757
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200758static int uart_stm32_irq_rx_ready(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100759{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100760 const struct uart_stm32_config *config = dev->config;
Francois Ramu860bd872022-01-28 16:52:28 +0100761 /*
762 * On stm32 F4X, F1X, and F2X, the RXNE flag is affected (cleared) by
763 * the uart_err_check function call (on errors flags clearing)
764 */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100765 return LL_USART_IsActiveFlag_RXNE(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100766}
767
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200768static void uart_stm32_irq_err_enable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100769{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100770 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100771
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100772 /* Enable FE, ORE interruptions */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100773 LL_USART_EnableIT_ERROR(config->usart);
Ilya Tagunov967c31b2018-03-29 19:40:00 +0300774#if !defined(CONFIG_SOC_SERIES_STM32F0X) || defined(USART_LIN_SUPPORT)
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100775 /* Enable Line break detection */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100776 if (IS_UART_LIN_INSTANCE(config->usart)) {
777 LL_USART_EnableIT_LBD(config->usart);
Ilya Tagunov967c31b2018-03-29 19:40:00 +0300778 }
Maciej Debskieaff37e2017-08-09 11:23:04 +0200779#endif
Erwan Gouriou8c079e92016-11-14 11:53:52 +0100780 /* Enable parity error interruption */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100781 LL_USART_EnableIT_PE(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100782}
783
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200784static void uart_stm32_irq_err_disable(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100785{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100786 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100787
Ilya Tagunov967c31b2018-03-29 19:40:00 +0300788 /* Disable FE, ORE interruptions */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100789 LL_USART_DisableIT_ERROR(config->usart);
Ilya Tagunov967c31b2018-03-29 19:40:00 +0300790#if !defined(CONFIG_SOC_SERIES_STM32F0X) || defined(USART_LIN_SUPPORT)
791 /* Disable Line break detection */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100792 if (IS_UART_LIN_INSTANCE(config->usart)) {
793 LL_USART_DisableIT_LBD(config->usart);
Ilya Tagunov967c31b2018-03-29 19:40:00 +0300794 }
Maciej Debskieaff37e2017-08-09 11:23:04 +0200795#endif
Ilya Tagunov967c31b2018-03-29 19:40:00 +0300796 /* Disable parity error interruption */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100797 LL_USART_DisableIT_PE(config->usart);
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100798}
799
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200800static int uart_stm32_irq_is_pending(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100801{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100802 const struct uart_stm32_config *config = dev->config;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100803
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100804 return ((LL_USART_IsActiveFlag_RXNE(config->usart) &&
805 LL_USART_IsEnabledIT_RXNE(config->usart)) ||
806 (LL_USART_IsActiveFlag_TC(config->usart) &&
807 LL_USART_IsEnabledIT_TC(config->usart)));
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100808}
809
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200810static int uart_stm32_irq_update(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100811{
812 return 1;
813}
814
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200815static void uart_stm32_irq_callback_set(const struct device *dev,
Paul Sokolovsky57286af2018-07-16 21:12:26 +0300816 uart_irq_callback_user_data_t cb,
817 void *cb_data)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100818{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100819 struct uart_stm32_data *data = dev->data;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100820
821 data->user_cb = cb;
Paul Sokolovsky57286af2018-07-16 21:12:26 +0300822 data->user_data = cb_data;
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100823}
824
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200825#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
826
827#ifdef CONFIG_UART_ASYNC_API
828
829static inline void async_user_callback(struct uart_stm32_data *data,
830 struct uart_event *event)
831{
832 if (data->async_cb) {
833 data->async_cb(data->uart_dev, event, data->async_user_data);
834 }
835}
836
837static inline void async_evt_rx_rdy(struct uart_stm32_data *data)
838{
839 LOG_DBG("rx_rdy: (%d %d)", data->dma_rx.offset, data->dma_rx.counter);
840
841 struct uart_event event = {
842 .type = UART_RX_RDY,
843 .data.rx.buf = data->dma_rx.buffer,
844 .data.rx.len = data->dma_rx.counter - data->dma_rx.offset,
845 .data.rx.offset = data->dma_rx.offset
846 };
847
Alexander Shuklin6831b8b2021-02-04 12:00:49 +0300848 /* update the current pos for new data */
849 data->dma_rx.offset = data->dma_rx.counter;
850
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200851 /* send event only for new data */
852 if (event.data.rx.len > 0) {
853 async_user_callback(data, &event);
854 }
855}
856
857static inline void async_evt_rx_err(struct uart_stm32_data *data, int err_code)
858{
859 LOG_DBG("rx error: %d", err_code);
860
861 struct uart_event event = {
862 .type = UART_RX_STOPPED,
863 .data.rx_stop.reason = err_code,
864 .data.rx_stop.data.len = data->dma_rx.counter,
865 .data.rx_stop.data.offset = 0,
866 .data.rx_stop.data.buf = data->dma_rx.buffer
867 };
868
869 async_user_callback(data, &event);
870}
871
872static inline void async_evt_tx_done(struct uart_stm32_data *data)
873{
874 LOG_DBG("tx done: %d", data->dma_tx.counter);
875
876 struct uart_event event = {
877 .type = UART_TX_DONE,
878 .data.tx.buf = data->dma_tx.buffer,
879 .data.tx.len = data->dma_tx.counter
880 };
881
882 /* Reset tx buffer */
883 data->dma_tx.buffer_length = 0;
884 data->dma_tx.counter = 0;
885
886 async_user_callback(data, &event);
887}
888
889static inline void async_evt_tx_abort(struct uart_stm32_data *data)
890{
891 LOG_DBG("tx abort: %d", data->dma_tx.counter);
892
893 struct uart_event event = {
894 .type = UART_TX_ABORTED,
895 .data.tx.buf = data->dma_tx.buffer,
896 .data.tx.len = data->dma_tx.counter
897 };
898
899 /* Reset tx buffer */
900 data->dma_tx.buffer_length = 0;
901 data->dma_tx.counter = 0;
902
903 async_user_callback(data, &event);
904}
905
906static inline void async_evt_rx_buf_request(struct uart_stm32_data *data)
907{
908 struct uart_event evt = {
909 .type = UART_RX_BUF_REQUEST,
910 };
911
912 async_user_callback(data, &evt);
913}
914
915static inline void async_evt_rx_buf_release(struct uart_stm32_data *data)
916{
917 struct uart_event evt = {
918 .type = UART_RX_BUF_RELEASED,
919 .data.rx_buf.buf = data->dma_rx.buffer,
920 };
921
922 async_user_callback(data, &evt);
923}
924
Francois Ramu962d6b12021-04-08 12:09:58 +0200925static inline void async_timer_start(struct k_work_delayable *work,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200926 int32_t timeout)
927{
Krzysztof Chruscinskic590b352021-10-01 15:47:40 +0200928 if ((timeout != SYS_FOREVER_US) && (timeout != 0)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200929 /* start timer */
Krzysztof Chruscinskic590b352021-10-01 15:47:40 +0200930 LOG_DBG("async timer started for %d us", timeout);
931 k_work_reschedule(work, K_USEC(timeout));
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200932 }
933}
934
935static void uart_stm32_dma_rx_flush(const struct device *dev)
936{
937 struct dma_status stat;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100938 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200939
Erwan Gouriou13c23512021-03-01 11:59:57 +0100940 if (dma_get_status(data->dma_rx.dma_dev,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200941 data->dma_rx.dma_channel, &stat) == 0) {
942 size_t rx_rcv_len = data->dma_rx.buffer_length -
943 stat.pending_length;
944 if (rx_rcv_len > data->dma_rx.offset) {
945 data->dma_rx.counter = rx_rcv_len;
946
947 async_evt_rx_rdy(data);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200948 }
949 }
950}
951
952#endif /* CONFIG_UART_ASYNC_API */
953
Erwan Gouriou79ff6452021-09-21 09:34:09 +0200954#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || \
955 defined(CONFIG_UART_ASYNC_API) || \
956 defined(CONFIG_PM)
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200957
Tomasz Bursztyka4dcfb552020-06-17 14:58:56 +0200958static void uart_stm32_isr(const struct device *dev)
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100959{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +0100960 struct uart_stm32_data *data = dev->data;
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200961#if defined(CONFIG_PM) || defined(CONFIG_UART_ASYNC_API)
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100962 const struct uart_stm32_config *config = dev->config;
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200963#endif
964
965#ifdef CONFIG_PM
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100966 if (LL_USART_IsEnabledIT_TC(config->usart) &&
967 LL_USART_IsActiveFlag_TC(config->usart)) {
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200968
969 if (data->tx_poll_stream_on) {
Yegor Yefremov1155d462022-03-07 22:53:16 +0100970 /* A poll stream transmission just completed,
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200971 * allow system to suspend
972 */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100973 LL_USART_DisableIT_TC(config->usart);
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200974 data->tx_poll_stream_on = false;
975 uart_stm32_pm_constraint_release(dev);
976 }
Yegor Yefremov1155d462022-03-07 22:53:16 +0100977 /* Stream transmission was either async or IRQ based,
Erwan Gourioua3de3df2021-09-14 09:27:56 +0200978 * constraint will be released at the same time TC IT
979 * is disabled
980 */
981 }
982#endif
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +0100983
Shlomi Vaknin1b4f7e52021-05-17 23:06:51 +0300984#ifdef CONFIG_UART_INTERRUPT_DRIVEN
985 if (data->user_cb) {
986 data->user_cb(dev, data->user_data);
987 }
988#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
989
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200990#ifdef CONFIG_UART_ASYNC_API
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100991 if (LL_USART_IsEnabledIT_IDLE(config->usart) &&
992 LL_USART_IsActiveFlag_IDLE(config->usart)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200993
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +0100994 LL_USART_ClearFlag_IDLE(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +0200995
996 LOG_DBG("idle interrupt occurred");
997
998 /* Start the RX timer */
999 async_timer_start(&data->dma_rx.timeout_work,
1000 data->dma_rx.timeout);
1001
1002 if (data->dma_rx.timeout == 0) {
1003 uart_stm32_dma_rx_flush(dev);
1004 }
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001005 } else if (LL_USART_IsEnabledIT_TC(config->usart) &&
1006 LL_USART_IsActiveFlag_TC(config->usart)) {
Zisis Adamos7235b092021-03-30 12:20:46 +02001007
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001008 LL_USART_DisableIT_TC(config->usart);
1009 LL_USART_ClearFlag_TC(config->usart);
Zisis Adamos7235b092021-03-30 12:20:46 +02001010 /* Generate TX_DONE event when transmission is done */
1011 async_evt_tx_done(data);
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001012
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001013#ifdef CONFIG_PM
1014 uart_stm32_pm_constraint_release(dev);
1015#endif
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001016 } else if (LL_USART_IsEnabledIT_RXNE(config->usart) &&
1017 LL_USART_IsActiveFlag_RXNE(config->usart)) {
Francois Ramucf606392021-11-08 11:43:53 +01001018#ifdef USART_SR_RXNE
1019 /* clear the RXNE flag, because Rx data was not read */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001020 LL_USART_ClearFlag_RXNE(config->usart);
Francois Ramucf606392021-11-08 11:43:53 +01001021#else
Francois Ramu95e2c392021-10-26 11:39:57 +02001022 /* clear the RXNE by flushing the fifo, because Rx data was not read */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001023 LL_USART_RequestRxDataFlush(config->usart);
Francois Ramucf606392021-11-08 11:43:53 +01001024#endif /* USART_SR_RXNE */
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001025 }
1026
1027 /* Clear errors */
1028 uart_stm32_err_check(dev);
1029#endif /* CONFIG_UART_ASYNC_API */
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001030}
Erwan Gouriou79ff6452021-09-21 09:34:09 +02001031#endif /* CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API || CONFIG_PM */
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001032
1033#ifdef CONFIG_UART_ASYNC_API
1034
1035static int uart_stm32_async_callback_set(const struct device *dev,
1036 uart_callback_t callback,
1037 void *user_data)
1038{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001039 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001040
1041 data->async_cb = callback;
1042 data->async_user_data = user_data;
1043
1044 return 0;
1045}
1046
1047static inline void uart_stm32_dma_tx_enable(const struct device *dev)
1048{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001049 const struct uart_stm32_config *config = dev->config;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001050
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001051 LL_USART_EnableDMAReq_TX(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001052}
1053
1054static inline void uart_stm32_dma_tx_disable(const struct device *dev)
1055{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001056 const struct uart_stm32_config *config = dev->config;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001057
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001058 LL_USART_DisableDMAReq_TX(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001059}
1060
1061static inline void uart_stm32_dma_rx_enable(const struct device *dev)
1062{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001063 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001064 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001065
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001066 LL_USART_EnableDMAReq_RX(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001067
1068 data->dma_rx.enabled = true;
1069}
1070
1071static inline void uart_stm32_dma_rx_disable(const struct device *dev)
1072{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001073 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001074
1075 data->dma_rx.enabled = false;
1076}
1077
1078static int uart_stm32_async_rx_disable(const struct device *dev)
1079{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001080 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001081 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001082 struct uart_event disabled_event = {
1083 .type = UART_RX_DISABLED
1084 };
1085
1086 if (!data->dma_rx.enabled) {
1087 async_user_callback(data, &disabled_event);
1088 return -EFAULT;
1089 }
1090
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001091 LL_USART_DisableIT_IDLE(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001092
1093 uart_stm32_dma_rx_flush(dev);
1094
1095 async_evt_rx_buf_release(data);
1096
1097 uart_stm32_dma_rx_disable(dev);
1098
Francois Ramu962d6b12021-04-08 12:09:58 +02001099 (void)k_work_cancel_delayable(&data->dma_rx.timeout_work);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001100
Erwan Gouriou13c23512021-03-01 11:59:57 +01001101 dma_stop(data->dma_rx.dma_dev, data->dma_rx.dma_channel);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001102
1103 data->rx_next_buffer = NULL;
1104 data->rx_next_buffer_len = 0;
1105
Yegor Yefremov1155d462022-03-07 22:53:16 +01001106 /* When async rx is disabled, enable interruptible instance of uart to function normally */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001107 LL_USART_EnableIT_RXNE(config->usart);
Manojkumar Subramaniamd79d26f2021-08-23 02:04:05 +08001108
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001109 LOG_DBG("rx: disabled");
1110
1111 async_user_callback(data, &disabled_event);
1112
1113 return 0;
1114}
1115
1116void uart_stm32_dma_tx_cb(const struct device *dma_dev, void *user_data,
1117 uint32_t channel, int status)
1118{
1119 const struct device *uart_dev = user_data;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001120 struct uart_stm32_data *data = uart_dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001121 struct dma_status stat;
1122 unsigned int key = irq_lock();
1123
1124 /* Disable TX */
1125 uart_stm32_dma_tx_disable(uart_dev);
1126
Francois Ramu962d6b12021-04-08 12:09:58 +02001127 (void)k_work_cancel_delayable(&data->dma_tx.timeout_work);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001128
Erwan Gouriou13c23512021-03-01 11:59:57 +01001129 if (!dma_get_status(data->dma_tx.dma_dev,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001130 data->dma_tx.dma_channel, &stat)) {
1131 data->dma_tx.counter = data->dma_tx.buffer_length -
1132 stat.pending_length;
1133 }
1134
Prema Jonathan van Win76dee392021-05-03 11:24:38 +03001135 data->dma_tx.buffer_length = 0;
1136
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001137 irq_unlock(key);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001138}
1139
1140static void uart_stm32_dma_replace_buffer(const struct device *dev)
1141{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001142 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001143 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001144
Yegor Yefremov1155d462022-03-07 22:53:16 +01001145 /* Replace the buffer and reload the DMA */
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001146 LOG_DBG("Replacing RX buffer: %d", data->rx_next_buffer_len);
1147
1148 /* reload DMA */
1149 data->dma_rx.offset = 0;
1150 data->dma_rx.counter = 0;
1151 data->dma_rx.buffer = data->rx_next_buffer;
1152 data->dma_rx.buffer_length = data->rx_next_buffer_len;
1153 data->dma_rx.blk_cfg.block_size = data->dma_rx.buffer_length;
1154 data->dma_rx.blk_cfg.dest_address = (uint32_t)data->dma_rx.buffer;
1155 data->rx_next_buffer = NULL;
1156 data->rx_next_buffer_len = 0;
1157
Erwan Gouriou13c23512021-03-01 11:59:57 +01001158 dma_reload(data->dma_rx.dma_dev, data->dma_rx.dma_channel,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001159 data->dma_rx.blk_cfg.source_address,
1160 data->dma_rx.blk_cfg.dest_address,
1161 data->dma_rx.blk_cfg.block_size);
1162
Erwan Gouriou13c23512021-03-01 11:59:57 +01001163 dma_start(data->dma_rx.dma_dev, data->dma_rx.dma_channel);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001164
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001165 LL_USART_ClearFlag_IDLE(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001166
1167 /* Request next buffer */
1168 async_evt_rx_buf_request(data);
1169}
1170
1171void uart_stm32_dma_rx_cb(const struct device *dma_dev, void *user_data,
1172 uint32_t channel, int status)
1173{
1174 const struct device *uart_dev = user_data;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001175 struct uart_stm32_data *data = uart_dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001176
1177 if (status != 0) {
1178 async_evt_rx_err(data, status);
1179 return;
1180 }
1181
Francois Ramu962d6b12021-04-08 12:09:58 +02001182 (void)k_work_cancel_delayable(&data->dma_rx.timeout_work);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001183
1184 /* true since this functions occurs when buffer if full */
1185 data->dma_rx.counter = data->dma_rx.buffer_length;
1186
1187 async_evt_rx_rdy(data);
1188
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001189 if (data->rx_next_buffer != NULL) {
1190 async_evt_rx_buf_release(data);
1191
1192 /* replace the buffer when the current
1193 * is full and not the same as the next
1194 * one.
1195 */
1196 uart_stm32_dma_replace_buffer(uart_dev);
1197 } else {
1198 /* Buffer full without valid next buffer,
1199 * an UART_RX_DISABLED event must be generated,
1200 * but uart_stm32_async_rx_disable() cannot be
1201 * called in ISR context. So force the RX timeout
1202 * to minimum value and let the RX timeout to do the job.
1203 */
Francois Ramu962d6b12021-04-08 12:09:58 +02001204 k_work_reschedule(&data->dma_rx.timeout_work, K_TICKS(1));
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001205 }
1206}
1207
1208static int uart_stm32_async_tx(const struct device *dev,
1209 const uint8_t *tx_data, size_t buf_size, int32_t timeout)
1210{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001211 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001212 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001213 int ret;
1214
Erwan Gouriou13c23512021-03-01 11:59:57 +01001215 if (data->dma_tx.dma_dev == NULL) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001216 return -ENODEV;
1217 }
1218
1219 if (data->dma_tx.buffer_length != 0) {
1220 return -EBUSY;
1221 }
1222
1223 data->dma_tx.buffer = (uint8_t *)tx_data;
1224 data->dma_tx.buffer_length = buf_size;
1225 data->dma_tx.timeout = timeout;
1226
1227 LOG_DBG("tx: l=%d", data->dma_tx.buffer_length);
1228
Zisis Adamos7235b092021-03-30 12:20:46 +02001229 /* Clear TC flag */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001230 LL_USART_ClearFlag_TC(config->usart);
Zisis Adamos7235b092021-03-30 12:20:46 +02001231
1232 /* Enable TC interrupt so we can signal correct TX done */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001233 LL_USART_EnableIT_TC(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001234
1235 /* set source address */
1236 data->dma_tx.blk_cfg.source_address = (uint32_t)data->dma_tx.buffer;
1237 data->dma_tx.blk_cfg.block_size = data->dma_tx.buffer_length;
1238
Erwan Gouriou13c23512021-03-01 11:59:57 +01001239 ret = dma_config(data->dma_tx.dma_dev, data->dma_tx.dma_channel,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001240 &data->dma_tx.dma_cfg);
1241
1242 if (ret != 0) {
1243 LOG_ERR("dma tx config error!");
1244 return -EINVAL;
1245 }
1246
Erwan Gouriou13c23512021-03-01 11:59:57 +01001247 if (dma_start(data->dma_tx.dma_dev, data->dma_tx.dma_channel)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001248 LOG_ERR("UART err: TX DMA start failed!");
1249 return -EFAULT;
1250 }
1251
1252 /* Start TX timer */
1253 async_timer_start(&data->dma_tx.timeout_work, data->dma_tx.timeout);
1254
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001255#ifdef CONFIG_PM
Erwan Gouriou79ff6452021-09-21 09:34:09 +02001256
1257 /* Do not allow system to suspend until transmission has completed */
Erwan Gourioua3de3df2021-09-14 09:27:56 +02001258 uart_stm32_pm_constraint_set(dev);
1259#endif
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001260
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001261 /* Enable TX DMA requests */
1262 uart_stm32_dma_tx_enable(dev);
1263
1264 return 0;
1265}
1266
1267static int uart_stm32_async_rx_enable(const struct device *dev,
1268 uint8_t *rx_buf, size_t buf_size, int32_t timeout)
1269{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001270 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001271 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001272 int ret;
1273
Erwan Gouriou13c23512021-03-01 11:59:57 +01001274 if (data->dma_rx.dma_dev == NULL) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001275 return -ENODEV;
1276 }
1277
1278 if (data->dma_rx.enabled) {
1279 LOG_WRN("RX was already enabled");
1280 return -EBUSY;
1281 }
1282
1283 data->dma_rx.offset = 0;
1284 data->dma_rx.buffer = rx_buf;
1285 data->dma_rx.buffer_length = buf_size;
1286 data->dma_rx.counter = 0;
1287 data->dma_rx.timeout = timeout;
1288
1289 /* Disable RX interrupts to let DMA to handle it */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001290 LL_USART_DisableIT_RXNE(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001291
1292 data->dma_rx.blk_cfg.block_size = buf_size;
1293 data->dma_rx.blk_cfg.dest_address = (uint32_t)data->dma_rx.buffer;
1294
Erwan Gouriou13c23512021-03-01 11:59:57 +01001295 ret = dma_config(data->dma_rx.dma_dev, data->dma_rx.dma_channel,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001296 &data->dma_rx.dma_cfg);
1297
1298 if (ret != 0) {
1299 LOG_ERR("UART ERR: RX DMA config failed!");
1300 return -EINVAL;
1301 }
1302
Erwan Gouriou13c23512021-03-01 11:59:57 +01001303 if (dma_start(data->dma_rx.dma_dev, data->dma_rx.dma_channel)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001304 LOG_ERR("UART ERR: RX DMA start failed!");
1305 return -EFAULT;
1306 }
1307
1308 /* Enable RX DMA requests */
1309 uart_stm32_dma_rx_enable(dev);
1310
1311 /* Enable IRQ IDLE to define the end of a
1312 * RX DMA transaction.
1313 */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001314 LL_USART_ClearFlag_IDLE(config->usart);
1315 LL_USART_EnableIT_IDLE(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001316
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001317 LL_USART_EnableIT_ERROR(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001318
1319 /* Request next buffer */
1320 async_evt_rx_buf_request(data);
1321
1322 LOG_DBG("async rx enabled");
1323
1324 return ret;
1325}
1326
1327static int uart_stm32_async_tx_abort(const struct device *dev)
1328{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001329 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001330 size_t tx_buffer_length = data->dma_tx.buffer_length;
1331 struct dma_status stat;
1332
1333 if (tx_buffer_length == 0) {
1334 return -EFAULT;
1335 }
1336
Francois Ramu962d6b12021-04-08 12:09:58 +02001337 (void)k_work_cancel_delayable(&data->dma_tx.timeout_work);
Erwan Gouriou13c23512021-03-01 11:59:57 +01001338 if (!dma_get_status(data->dma_tx.dma_dev,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001339 data->dma_tx.dma_channel, &stat)) {
1340 data->dma_tx.counter = tx_buffer_length - stat.pending_length;
1341 }
1342
Erwan Gouriou13c23512021-03-01 11:59:57 +01001343 dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001344 async_evt_tx_abort(data);
1345
1346 return 0;
1347}
1348
1349static void uart_stm32_async_rx_timeout(struct k_work *work)
1350{
Yong Cong Sin731241f2022-01-19 12:07:51 +08001351 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
1352 struct uart_dma_stream *rx_stream = CONTAINER_OF(dwork,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001353 struct uart_dma_stream, timeout_work);
1354 struct uart_stm32_data *data = CONTAINER_OF(rx_stream,
1355 struct uart_stm32_data, dma_rx);
1356 const struct device *dev = data->uart_dev;
1357
1358 LOG_DBG("rx timeout");
1359
1360 if (data->dma_rx.counter == data->dma_rx.buffer_length) {
1361 uart_stm32_async_rx_disable(dev);
1362 } else {
1363 uart_stm32_dma_rx_flush(dev);
1364 }
1365}
1366
1367static void uart_stm32_async_tx_timeout(struct k_work *work)
1368{
Yong Cong Sin731241f2022-01-19 12:07:51 +08001369 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
1370 struct uart_dma_stream *tx_stream = CONTAINER_OF(dwork,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001371 struct uart_dma_stream, timeout_work);
1372 struct uart_stm32_data *data = CONTAINER_OF(tx_stream,
1373 struct uart_stm32_data, dma_tx);
1374 const struct device *dev = data->uart_dev;
1375
1376 uart_stm32_async_tx_abort(dev);
1377
1378 LOG_DBG("tx: async timeout");
1379}
1380
1381static int uart_stm32_async_rx_buf_rsp(const struct device *dev, uint8_t *buf,
1382 size_t len)
1383{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001384 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001385
1386 LOG_DBG("replace buffer (%d)", len);
1387 data->rx_next_buffer = buf;
1388 data->rx_next_buffer_len = len;
1389
1390 return 0;
1391}
1392
1393static int uart_stm32_async_init(const struct device *dev)
1394{
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001395 const struct uart_stm32_config *config = dev->config;
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001396 struct uart_stm32_data *data = dev->data;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001397
1398 data->uart_dev = dev;
1399
Erwan Gouriou13c23512021-03-01 11:59:57 +01001400 if (data->dma_rx.dma_dev != NULL) {
1401 if (!device_is_ready(data->dma_rx.dma_dev)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001402 return -ENODEV;
1403 }
1404 }
1405
Erwan Gouriou13c23512021-03-01 11:59:57 +01001406 if (data->dma_tx.dma_dev != NULL) {
1407 if (!device_is_ready(data->dma_rx.dma_dev)) {
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001408 return -ENODEV;
1409 }
1410 }
1411
1412 /* Disable both TX and RX DMA requests */
1413 uart_stm32_dma_rx_disable(dev);
1414 uart_stm32_dma_tx_disable(dev);
1415
Francois Ramu962d6b12021-04-08 12:09:58 +02001416 k_work_init_delayable(&data->dma_rx.timeout_work,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001417 uart_stm32_async_rx_timeout);
Francois Ramu962d6b12021-04-08 12:09:58 +02001418 k_work_init_delayable(&data->dma_tx.timeout_work,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001419 uart_stm32_async_tx_timeout);
1420
1421 /* Configure dma rx config */
1422 memset(&data->dma_rx.blk_cfg, 0, sizeof(data->dma_rx.blk_cfg));
1423
1424#if defined(CONFIG_SOC_SERIES_STM32F1X) || \
1425 defined(CONFIG_SOC_SERIES_STM32F2X) || \
1426 defined(CONFIG_SOC_SERIES_STM32F4X) || \
1427 defined(CONFIG_SOC_SERIES_STM32L1X)
1428 data->dma_rx.blk_cfg.source_address =
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001429 LL_USART_DMA_GetRegAddr(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001430#else
1431 data->dma_rx.blk_cfg.source_address =
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001432 LL_USART_DMA_GetRegAddr(config->usart,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001433 LL_USART_DMA_REG_DATA_RECEIVE);
1434#endif
1435
1436 data->dma_rx.blk_cfg.dest_address = 0; /* dest not ready */
1437
1438 if (data->dma_rx.src_addr_increment) {
1439 data->dma_rx.blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT;
1440 } else {
1441 data->dma_rx.blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
1442 }
1443
1444 if (data->dma_rx.dst_addr_increment) {
1445 data->dma_rx.blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
1446 } else {
1447 data->dma_rx.blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
1448 }
1449
1450 /* RX disable circular buffer */
1451 data->dma_rx.blk_cfg.source_reload_en = 0;
1452 data->dma_rx.blk_cfg.dest_reload_en = 0;
1453 data->dma_rx.blk_cfg.fifo_mode_control = data->dma_rx.fifo_threshold;
1454
1455 data->dma_rx.dma_cfg.head_block = &data->dma_rx.blk_cfg;
1456 data->dma_rx.dma_cfg.user_data = (void *)dev;
1457 data->rx_next_buffer = NULL;
1458 data->rx_next_buffer_len = 0;
1459
1460 /* Configure dma tx config */
1461 memset(&data->dma_tx.blk_cfg, 0, sizeof(data->dma_tx.blk_cfg));
1462
1463#if defined(CONFIG_SOC_SERIES_STM32F1X) || \
1464 defined(CONFIG_SOC_SERIES_STM32F2X) || \
1465 defined(CONFIG_SOC_SERIES_STM32F4X) || \
1466 defined(CONFIG_SOC_SERIES_STM32L1X)
1467 data->dma_tx.blk_cfg.dest_address =
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001468 LL_USART_DMA_GetRegAddr(config->usart);
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001469#else
1470 data->dma_tx.blk_cfg.dest_address =
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001471 LL_USART_DMA_GetRegAddr(config->usart,
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001472 LL_USART_DMA_REG_DATA_TRANSMIT);
1473#endif
1474
1475 data->dma_tx.blk_cfg.source_address = 0; /* not ready */
1476
1477 if (data->dma_tx.src_addr_increment) {
1478 data->dma_tx.blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT;
1479 } else {
1480 data->dma_tx.blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
1481 }
1482
1483 if (data->dma_tx.dst_addr_increment) {
1484 data->dma_tx.blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
1485 } else {
1486 data->dma_tx.blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
1487 }
1488
1489 data->dma_tx.blk_cfg.fifo_mode_control = data->dma_tx.fifo_threshold;
1490
1491 data->dma_tx.dma_cfg.head_block = &data->dma_tx.blk_cfg;
1492 data->dma_tx.dma_cfg.user_data = (void *)dev;
1493
1494 return 0;
1495}
1496
1497#endif /* CONFIG_UART_ASYNC_API */
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001498
Marcus Shawcroftd3ea5392016-10-24 08:38:49 +01001499static const struct uart_driver_api uart_stm32_driver_api = {
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001500 .poll_in = uart_stm32_poll_in,
1501 .poll_out = uart_stm32_poll_out,
Georgij Cernysiovc74c1312019-02-14 10:50:19 +01001502 .err_check = uart_stm32_err_check,
Daniel Leung4e1692f2021-05-26 12:33:37 -07001503#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
Pushpal Sidhuacd0e252019-01-07 13:52:24 -08001504 .configure = uart_stm32_configure,
1505 .config_get = uart_stm32_config_get,
Daniel Leung4e1692f2021-05-26 12:33:37 -07001506#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001507#ifdef CONFIG_UART_INTERRUPT_DRIVEN
1508 .fifo_fill = uart_stm32_fifo_fill,
1509 .fifo_read = uart_stm32_fifo_read,
1510 .irq_tx_enable = uart_stm32_irq_tx_enable,
1511 .irq_tx_disable = uart_stm32_irq_tx_disable,
1512 .irq_tx_ready = uart_stm32_irq_tx_ready,
Paul Sokolovsky0fdc9b52017-05-11 17:57:29 +03001513 .irq_tx_complete = uart_stm32_irq_tx_complete,
Maciek Borzecki0cd7ff82016-03-13 19:37:25 +01001514 .irq_rx_enable = uart_stm32_irq_rx_enable,
1515 .irq_rx_disable = uart_stm32_irq_rx_disable,
1516 .irq_rx_ready = uart_stm32_irq_rx_ready,
1517 .irq_err_enable = uart_stm32_irq_err_enable,
1518 .irq_err_disable = uart_stm32_irq_err_disable,
1519 .irq_is_pending = uart_stm32_irq_is_pending,
1520 .irq_update = uart_stm32_irq_update,
1521 .irq_callback_set = uart_stm32_irq_callback_set,
1522#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001523#ifdef CONFIG_UART_ASYNC_API
1524 .callback_set = uart_stm32_async_callback_set,
1525 .tx = uart_stm32_async_tx,
1526 .tx_abort = uart_stm32_async_tx_abort,
1527 .rx_enable = uart_stm32_async_rx_enable,
1528 .rx_disable = uart_stm32_async_rx_disable,
1529 .rx_buf_rsp = uart_stm32_async_rx_buf_rsp,
1530#endif /* CONFIG_UART_ASYNC_API */
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001531};
1532
1533/**
1534 * @brief Initialize UART channel
1535 *
1536 * This routine is called to reset the chip in a quiescent state.
1537 * It is assumed that this function is called only once per UART.
1538 *
1539 * @param dev UART device struct
1540 *
1541 * @return 0
1542 */
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001543static int uart_stm32_init(const struct device *dev)
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001544{
Gerard Marull-Paretas1674fec2022-01-18 16:58:32 +01001545 const struct uart_stm32_config *config = dev->config;
1546 struct uart_stm32_data *data = dev->data;
Kumar Galaa1b77fd2020-05-27 11:26:57 -05001547 uint32_t ll_parity;
1548 uint32_t ll_datawidth;
Erwan Gouriou0b9c5842020-10-16 17:20:00 +02001549 int err;
Erwan Gouriouda210ba2017-09-21 15:20:53 +02001550
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001551 __uart_stm32_get_clock(dev);
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001552 /* enable clock */
Erwan Gouriou9062e972018-12-07 11:09:28 +01001553 if (clock_control_on(data->clock,
1554 (clock_control_subsys_t *)&config->pclken) != 0) {
1555 return -EIO;
1556 }
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001557
Erwan Gouriou252a6232020-06-05 10:57:52 +02001558 /* Configure dt provided device signals when available */
Gerard Marull-Paretas21a27192021-09-07 16:39:45 +02001559 err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
Erwan Gouriou0b9c5842020-10-16 17:20:00 +02001560 if (err < 0) {
1561 return err;
Erwan Gouriou252a6232020-06-05 10:57:52 +02001562 }
1563
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001564 LL_USART_Disable(config->usart);
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001565
Erwan Gouriouda210ba2017-09-21 15:20:53 +02001566 /* TX/RX direction */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001567 LL_USART_SetTransferDirection(config->usart,
Erwan Gouriouda210ba2017-09-21 15:20:53 +02001568 LL_USART_DIRECTION_TX_RX);
1569
Pauli Salmenrinne30003ff2020-03-18 13:40:21 +02001570 /* Determine the datawidth and parity. If we use other parity than
1571 * 'none' we must use datawidth = 9 (to get 8 databit + 1 parity bit).
1572 */
1573 if (config->parity == 2) {
1574 /* 8 databit, 1 parity bit, parity even */
1575 ll_parity = LL_USART_PARITY_EVEN;
1576 ll_datawidth = LL_USART_DATAWIDTH_9B;
1577 } else if (config->parity == 1) {
1578 /* 8 databit, 1 parity bit, parity odd */
1579 ll_parity = LL_USART_PARITY_ODD;
1580 ll_datawidth = LL_USART_DATAWIDTH_9B;
1581 } else { /* Default to 8N0, but show warning if invalid value */
1582 if (config->parity != 0) {
1583 LOG_WRN("Invalid parity setting '%d'."
1584 "Defaulting to 'none'.", config->parity);
1585 }
1586 /* 8 databit, parity none */
1587 ll_parity = LL_USART_PARITY_NONE;
1588 ll_datawidth = LL_USART_DATAWIDTH_8B;
1589 }
1590
1591 /* Set datawidth and parity, 1 start bit, 1 stop bit */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001592 LL_USART_ConfigCharacter(config->usart,
Pauli Salmenrinne30003ff2020-03-18 13:40:21 +02001593 ll_datawidth,
1594 ll_parity,
Erwan Gouriouda210ba2017-09-21 15:20:53 +02001595 LL_USART_STOPBITS_1);
1596
Georgij Cernysiov04da64d2019-02-08 18:39:35 +01001597 if (config->hw_flow_control) {
1598 uart_stm32_set_hwctrl(dev, LL_USART_HWCONTROL_RTS_CTS);
1599 }
1600
Pushpal Sidhuacd0e252019-01-07 13:52:24 -08001601 /* Set the default baudrate */
1602 uart_stm32_set_baudrate(dev, data->baud_rate);
Erwan Gouriouda210ba2017-09-21 15:20:53 +02001603
Jonathan Hahn32f9dcf2022-01-01 23:41:19 +01001604 /* Enable the single wire / half-duplex mode */
1605 if (config->single_wire) {
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001606 LL_USART_EnableHalfDuplex(config->usart);
Jonathan Hahn32f9dcf2022-01-01 23:41:19 +01001607 }
1608
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001609 LL_USART_Enable(config->usart);
Erwan Gouriouda210ba2017-09-21 15:20:53 +02001610
Erwan Gouriou80b8c502018-06-13 11:32:38 +02001611#ifdef USART_ISR_TEACK
1612 /* Wait until TEACK flag is set */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001613 while (!(LL_USART_IsActiveFlag_TEACK(config->usart))) {
Anas Nashif4c322582019-06-04 10:52:23 -04001614 }
Erwan Gouriou80b8c502018-06-13 11:32:38 +02001615#endif /* !USART_ISR_TEACK */
1616
1617#ifdef USART_ISR_REACK
Erwan Gouriou13a96572018-06-18 18:01:06 +02001618 /* Wait until REACK flag is set */
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001619 while (!(LL_USART_IsActiveFlag_REACK(config->usart))) {
Anas Nashif4c322582019-06-04 10:52:23 -04001620 }
Erwan Gouriou80b8c502018-06-13 11:32:38 +02001621#endif /* !USART_ISR_REACK */
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001622
Gerard Marull-Paretase101cc72022-01-25 16:21:36 +01001623#if defined(CONFIG_PM) || \
1624 defined(CONFIG_UART_INTERRUPT_DRIVEN) || \
1625 defined(CONFIG_UART_ASYNC_API)
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001626 config->irq_config_func(dev);
Gerard Marull-Paretase101cc72022-01-25 16:21:36 +01001627#endif /* CONFIG_PM || CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API */
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001628
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001629#ifdef CONFIG_UART_ASYNC_API
1630 return uart_stm32_async_init(dev);
1631#else
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001632 return 0;
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001633#endif
Maciek Borzecki5a73ca62016-03-03 15:33:20 +01001634}
1635
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001636#ifdef CONFIG_UART_ASYNC_API
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001637
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001638/* src_dev and dest_dev should be 'MEMORY' or 'PERIPHERAL'. */
1639#define UART_DMA_CHANNEL_INIT(index, dir, dir_cap, src_dev, dest_dev) \
Francois Ramu30fd0222021-06-18 15:52:30 +02001640 .dma_dev = DEVICE_DT_GET(STM32_DMA_CTLR(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001641 .dma_channel = DT_INST_DMAS_CELL_BY_NAME(index, dir, channel), \
1642 .dma_cfg = { \
Francois Ramu744e1dc2021-08-09 16:32:57 +02001643 .dma_slot = STM32_DMA_SLOT(index, dir, slot),\
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001644 .channel_direction = STM32_DMA_CONFIG_DIRECTION( \
Francois Ramu30fd0222021-06-18 15:52:30 +02001645 STM32_DMA_CHANNEL_CONFIG(index, dir)),\
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001646 .channel_priority = STM32_DMA_CONFIG_PRIORITY( \
Francois Ramu30fd0222021-06-18 15:52:30 +02001647 STM32_DMA_CHANNEL_CONFIG(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001648 .source_data_size = STM32_DMA_CONFIG_##src_dev##_DATA_SIZE(\
Francois Ramu30fd0222021-06-18 15:52:30 +02001649 STM32_DMA_CHANNEL_CONFIG(index, dir)),\
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001650 .dest_data_size = STM32_DMA_CONFIG_##dest_dev##_DATA_SIZE(\
Francois Ramu30fd0222021-06-18 15:52:30 +02001651 STM32_DMA_CHANNEL_CONFIG(index, dir)),\
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001652 .source_burst_length = 1, /* SINGLE transfer */ \
1653 .dest_burst_length = 1, \
1654 .block_count = 1, \
1655 .dma_callback = uart_stm32_dma_##dir##_cb, \
1656 }, \
1657 .src_addr_increment = STM32_DMA_CONFIG_##src_dev##_ADDR_INC( \
Francois Ramu30fd0222021-06-18 15:52:30 +02001658 STM32_DMA_CHANNEL_CONFIG(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001659 .dst_addr_increment = STM32_DMA_CONFIG_##dest_dev##_ADDR_INC( \
Francois Ramu30fd0222021-06-18 15:52:30 +02001660 STM32_DMA_CHANNEL_CONFIG(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001661 .fifo_threshold = STM32_DMA_FEATURES_FIFO_THRESHOLD( \
Francois Ramu30fd0222021-06-18 15:52:30 +02001662 STM32_DMA_FEATURES(index, dir)), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001663
1664#endif
1665
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001666#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) || \
1667 defined(CONFIG_PM)
Erwan Gouriou62755132020-02-28 14:54:37 +01001668#define STM32_UART_IRQ_HANDLER_DECL(index) \
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001669 static void uart_stm32_irq_config_func_##index(const struct device *dev);
Erwan Gouriou62755132020-02-28 14:54:37 +01001670#define STM32_UART_IRQ_HANDLER(index) \
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +02001671static void uart_stm32_irq_config_func_##index(const struct device *dev) \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001672{ \
Erwan Gouriouccd6b722020-06-05 09:48:29 +02001673 IRQ_CONNECT(DT_INST_IRQN(index), \
1674 DT_INST_IRQ(index, priority), \
Kumar Galac49b1622020-12-11 10:12:30 -06001675 uart_stm32_isr, DEVICE_DT_INST_GET(index), \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001676 0); \
Erwan Gouriouccd6b722020-06-05 09:48:29 +02001677 irq_enable(DT_INST_IRQN(index)); \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001678}
1679#else
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001680#define STM32_UART_IRQ_HANDLER_DECL(index) /* Not used */
1681#define STM32_UART_IRQ_HANDLER(index) /* Not used */
1682#endif
1683
Gerard Marull-Paretase101cc72022-01-25 16:21:36 +01001684#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) || \
1685 defined(CONFIG_PM)
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001686#define STM32_UART_IRQ_HANDLER_FUNC(index) \
1687 .irq_config_func = uart_stm32_irq_config_func_##index,
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001688#else
1689#define STM32_UART_IRQ_HANDLER_FUNC(index) /* Not used */
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001690#endif
1691
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001692#ifdef CONFIG_UART_ASYNC_API
1693#define UART_DMA_CHANNEL(index, dir, DIR, src, dest) \
1694.dma_##dir = { \
1695 COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir), \
1696 (UART_DMA_CHANNEL_INIT(index, dir, DIR, src, dest)), \
1697 (NULL)) \
1698 },
1699
1700#else
1701#define UART_DMA_CHANNEL(index, dir, DIR, src, dest)
1702#endif
1703
Erwan Gouriou62755132020-02-28 14:54:37 +01001704#define STM32_UART_INIT(index) \
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001705STM32_UART_IRQ_HANDLER_DECL(index) \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001706 \
Gerard Marull-Paretas5dc6ed32021-12-23 12:33:03 +01001707PINCTRL_DT_INST_DEFINE(index); \
Erwan Gouriou252a6232020-06-05 10:57:52 +02001708 \
Erwan Gouriou62755132020-02-28 14:54:37 +01001709static const struct uart_stm32_config uart_stm32_cfg_##index = { \
Gerard Marull-Paretas32a3a022022-01-25 16:14:12 +01001710 .usart = (USART_TypeDef *)DT_INST_REG_ADDR(index), \
Erwan Gouriouccd6b722020-06-05 09:48:29 +02001711 .pclken = { .bus = DT_INST_CLOCKS_CELL(index, bus), \
1712 .enr = DT_INST_CLOCKS_CELL(index, bits) \
Erwan Gourioud76a5592018-11-08 14:38:48 +01001713 }, \
Erwan Gouriouccd6b722020-06-05 09:48:29 +02001714 .hw_flow_control = DT_INST_PROP(index, hw_flow_control), \
Gerard Marull-Paretasc759a352021-11-17 14:01:42 +01001715 .parity = DT_INST_ENUM_IDX_OR(index, parity, UART_CFG_PARITY_NONE), \
Gerard Marull-Paretas21a27192021-09-07 16:39:45 +02001716 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \
Jonathan Hahn32f9dcf2022-01-01 23:41:19 +01001717 .single_wire = DT_INST_PROP_OR(index, single_wire, false), \
Gerard Marull-Paretase101cc72022-01-25 16:21:36 +01001718 STM32_UART_IRQ_HANDLER_FUNC(index) \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001719}; \
1720 \
Erwan Gouriou62755132020-02-28 14:54:37 +01001721static struct uart_stm32_data uart_stm32_data_##index = { \
Erwan Gouriouccd6b722020-06-05 09:48:29 +02001722 .baud_rate = DT_INST_PROP(index, current_speed), \
Shlomi Vakninb4afd1a2021-01-16 18:44:24 +02001723 UART_DMA_CHANNEL(index, rx, RX, PERIPHERAL, MEMORY) \
1724 UART_DMA_CHANNEL(index, tx, TX, MEMORY, PERIPHERAL) \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001725}; \
1726 \
Kumar Galac49b1622020-12-11 10:12:30 -06001727DEVICE_DT_INST_DEFINE(index, \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001728 &uart_stm32_init, \
Gerard Marull-Paretase3f49072021-09-09 22:41:35 +02001729 NULL, \
Erwan Gouriou62755132020-02-28 14:54:37 +01001730 &uart_stm32_data_##index, &uart_stm32_cfg_##index, \
Maureen Helmad145052021-10-14 09:38:10 -05001731 PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
Florian Vaussardf27a5a32017-05-01 15:21:52 +02001732 &uart_stm32_driver_api); \
1733 \
Erwan Gouriou62755132020-02-28 14:54:37 +01001734STM32_UART_IRQ_HANDLER(index)
Erwan Gouriou8c079e92016-11-14 11:53:52 +01001735
Martí Bolívar7e0eed92020-05-06 11:23:07 -07001736DT_INST_FOREACH_STATUS_OKAY(STM32_UART_INIT)