1 /*
2 * Copyright 2017, 2024 NXP
3 * Copyright (c) 2020 PHYTEC Messtechnik GmbH
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT nxp_kinetis_uart
9
10 #include <errno.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/uart.h>
13 #include <zephyr/drivers/clock_control.h>
14 #include <zephyr/irq.h>
15 #include <fsl_uart.h>
16 #include <soc.h>
17 #include <zephyr/pm/device.h>
18 #include <zephyr/drivers/pinctrl.h>
19
20 struct uart_mcux_config {
21 UART_Type *base;
22 const struct device *clock_dev;
23 clock_control_subsys_t clock_subsys;
24 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
25 void (*irq_config_func)(const struct device *dev);
26 #endif
27 const struct pinctrl_dev_config *pincfg;
28 };
29
30 struct uart_mcux_data {
31 struct uart_config uart_cfg;
32 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
33 uart_irq_callback_user_data_t callback;
34 void *cb_data;
35 #endif
36 };
37
uart_mcux_configure(const struct device * dev,const struct uart_config * cfg)38 static int uart_mcux_configure(const struct device *dev,
39 const struct uart_config *cfg)
40 {
41 const struct uart_mcux_config *config = dev->config;
42 struct uart_mcux_data *data = dev->data;
43 uart_config_t uart_config;
44 uint32_t clock_freq;
45 status_t retval;
46
47 if (!device_is_ready(config->clock_dev)) {
48 return -ENODEV;
49 }
50
51 if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
52 &clock_freq)) {
53 return -EINVAL;
54 }
55
56 UART_GetDefaultConfig(&uart_config);
57
58 uart_config.enableTx = true;
59 uart_config.enableRx = true;
60 uart_config.baudRate_Bps = cfg->baudrate;
61
62 switch (cfg->stop_bits) {
63 case UART_CFG_STOP_BITS_1:
64 #if defined(FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT) && \
65 FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT
66 uart_config.stopBitCount = kUART_OneStopBit;
67 break;
68 case UART_CFG_STOP_BITS_2:
69 uart_config.stopBitCount = kUART_TwoStopBit;
70 #endif
71 break;
72 default:
73 return -ENOTSUP;
74 }
75
76 #if defined(FSL_FEATURE_UART_HAS_MODEM_SUPPORT) && FSL_FEATURE_UART_HAS_MODEM_SUPPORT
77 switch (cfg->flow_ctrl) {
78 case UART_CFG_FLOW_CTRL_NONE:
79 uart_config.enableRxRTS = false;
80 uart_config.enableTxCTS = false;
81 break;
82 case UART_CFG_FLOW_CTRL_RTS_CTS:
83 uart_config.enableRxRTS = true;
84 uart_config.enableTxCTS = true;
85 break;
86 default:
87 return -ENOTSUP;
88 }
89 #endif
90
91 switch (cfg->parity) {
92 case UART_CFG_PARITY_NONE:
93 uart_config.parityMode = kUART_ParityDisabled;
94 break;
95 case UART_CFG_PARITY_EVEN:
96 uart_config.parityMode = kUART_ParityEven;
97 break;
98 case UART_CFG_PARITY_ODD:
99 uart_config.parityMode = kUART_ParityOdd;
100 break;
101 default:
102 return -ENOTSUP;
103 }
104
105 retval = UART_Init(config->base, &uart_config, clock_freq);
106 if (retval != kStatus_Success) {
107 return -EINVAL;
108 }
109
110 data->uart_cfg = *cfg;
111
112 return 0;
113 }
114
115 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
uart_mcux_config_get(const struct device * dev,struct uart_config * cfg)116 static int uart_mcux_config_get(const struct device *dev,
117 struct uart_config *cfg)
118 {
119 struct uart_mcux_data *data = dev->data;
120
121 *cfg = data->uart_cfg;
122
123 return 0;
124 }
125 #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
126
uart_mcux_poll_in(const struct device * dev,unsigned char * c)127 static int uart_mcux_poll_in(const struct device *dev, unsigned char *c)
128 {
129 const struct uart_mcux_config *config = dev->config;
130 uint32_t flags = UART_GetStatusFlags(config->base);
131 int ret = -1;
132
133 if (flags & kUART_RxDataRegFullFlag) {
134 *c = UART_ReadByte(config->base);
135 ret = 0;
136 }
137
138 return ret;
139 }
140
uart_mcux_poll_out(const struct device * dev,unsigned char c)141 static void uart_mcux_poll_out(const struct device *dev, unsigned char c)
142 {
143 const struct uart_mcux_config *config = dev->config;
144
145 while (!(UART_GetStatusFlags(config->base) & kUART_TxDataRegEmptyFlag)) {
146 }
147
148 UART_WriteByte(config->base, c);
149 }
150
uart_mcux_err_check(const struct device * dev)151 static int uart_mcux_err_check(const struct device *dev)
152 {
153 const struct uart_mcux_config *config = dev->config;
154 uint32_t flags = UART_GetStatusFlags(config->base);
155 int err = 0;
156
157 if (flags & kUART_RxOverrunFlag) {
158 err |= UART_ERROR_OVERRUN;
159 }
160
161 if (flags & kUART_ParityErrorFlag) {
162 err |= UART_ERROR_PARITY;
163 }
164
165 if (flags & kUART_FramingErrorFlag) {
166 err |= UART_ERROR_FRAMING;
167 }
168
169 UART_ClearStatusFlags(config->base, kUART_RxOverrunFlag |
170 kUART_ParityErrorFlag |
171 kUART_FramingErrorFlag);
172
173 return err;
174 }
175
176 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_mcux_fifo_fill(const struct device * dev,const uint8_t * tx_data,int len)177 static int uart_mcux_fifo_fill(const struct device *dev,
178 const uint8_t *tx_data,
179 int len)
180 {
181 const struct uart_mcux_config *config = dev->config;
182 int num_tx = 0U;
183
184 while ((len - num_tx > 0) &&
185 (UART_GetStatusFlags(config->base) & kUART_TxDataRegEmptyFlag)) {
186
187 UART_WriteByte(config->base, tx_data[num_tx++]);
188 }
189
190 return num_tx;
191 }
192
uart_mcux_fifo_read(const struct device * dev,uint8_t * rx_data,const int len)193 static int uart_mcux_fifo_read(const struct device *dev, uint8_t *rx_data,
194 const int len)
195 {
196 const struct uart_mcux_config *config = dev->config;
197 int num_rx = 0U;
198
199 while ((len - num_rx > 0) &&
200 (UART_GetStatusFlags(config->base) & kUART_RxDataRegFullFlag)) {
201
202 rx_data[num_rx++] = UART_ReadByte(config->base);
203 }
204
205 return num_rx;
206 }
207
uart_mcux_irq_tx_enable(const struct device * dev)208 static void uart_mcux_irq_tx_enable(const struct device *dev)
209 {
210 const struct uart_mcux_config *config = dev->config;
211 uint32_t mask = kUART_TxDataRegEmptyInterruptEnable;
212 pm_device_busy_set(dev);
213 UART_EnableInterrupts(config->base, mask);
214 }
215
uart_mcux_irq_tx_disable(const struct device * dev)216 static void uart_mcux_irq_tx_disable(const struct device *dev)
217 {
218 const struct uart_mcux_config *config = dev->config;
219 uint32_t mask = kUART_TxDataRegEmptyInterruptEnable;
220 pm_device_busy_clear(dev);
221 UART_DisableInterrupts(config->base, mask);
222 }
223
uart_mcux_irq_tx_complete(const struct device * dev)224 static int uart_mcux_irq_tx_complete(const struct device *dev)
225 {
226 const struct uart_mcux_config *config = dev->config;
227 uint32_t flags = UART_GetStatusFlags(config->base);
228
229 return (flags & kUART_TransmissionCompleteFlag) != 0U;
230 }
231
uart_mcux_irq_tx_ready(const struct device * dev)232 static int uart_mcux_irq_tx_ready(const struct device *dev)
233 {
234 const struct uart_mcux_config *config = dev->config;
235 uint32_t mask = kUART_TxDataRegEmptyInterruptEnable;
236 uint32_t flags = UART_GetStatusFlags(config->base);
237
238 return (UART_GetEnabledInterrupts(config->base) & mask)
239 && (flags & kUART_TxDataRegEmptyFlag);
240 }
241
uart_mcux_irq_rx_enable(const struct device * dev)242 static void uart_mcux_irq_rx_enable(const struct device *dev)
243 {
244 const struct uart_mcux_config *config = dev->config;
245 uint32_t mask = kUART_RxDataRegFullInterruptEnable;
246
247 UART_EnableInterrupts(config->base, mask);
248 }
249
uart_mcux_irq_rx_disable(const struct device * dev)250 static void uart_mcux_irq_rx_disable(const struct device *dev)
251 {
252 const struct uart_mcux_config *config = dev->config;
253 uint32_t mask = kUART_RxDataRegFullInterruptEnable;
254
255 UART_DisableInterrupts(config->base, mask);
256 }
257
uart_mcux_irq_rx_full(const struct device * dev)258 static int uart_mcux_irq_rx_full(const struct device *dev)
259 {
260 const struct uart_mcux_config *config = dev->config;
261 uint32_t flags = UART_GetStatusFlags(config->base);
262
263 return (flags & kUART_RxDataRegFullFlag) != 0U;
264 }
265
uart_mcux_irq_rx_pending(const struct device * dev)266 static int uart_mcux_irq_rx_pending(const struct device *dev)
267 {
268 const struct uart_mcux_config *config = dev->config;
269 uint32_t mask = kUART_RxDataRegFullInterruptEnable;
270
271 return (UART_GetEnabledInterrupts(config->base) & mask)
272 && uart_mcux_irq_rx_full(dev);
273 }
274
uart_mcux_irq_err_enable(const struct device * dev)275 static void uart_mcux_irq_err_enable(const struct device *dev)
276 {
277 const struct uart_mcux_config *config = dev->config;
278 uint32_t mask = kUART_NoiseErrorInterruptEnable |
279 kUART_FramingErrorInterruptEnable |
280 kUART_ParityErrorInterruptEnable;
281
282 UART_EnableInterrupts(config->base, mask);
283 }
284
uart_mcux_irq_err_disable(const struct device * dev)285 static void uart_mcux_irq_err_disable(const struct device *dev)
286 {
287 const struct uart_mcux_config *config = dev->config;
288 uint32_t mask = kUART_NoiseErrorInterruptEnable |
289 kUART_FramingErrorInterruptEnable |
290 kUART_ParityErrorInterruptEnable;
291
292 UART_DisableInterrupts(config->base, mask);
293 }
294
uart_mcux_irq_is_pending(const struct device * dev)295 static int uart_mcux_irq_is_pending(const struct device *dev)
296 {
297 return uart_mcux_irq_tx_ready(dev) || uart_mcux_irq_rx_pending(dev);
298 }
299
uart_mcux_irq_update(const struct device * dev)300 static int uart_mcux_irq_update(const struct device *dev)
301 {
302 return 1;
303 }
304
uart_mcux_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)305 static void uart_mcux_irq_callback_set(const struct device *dev,
306 uart_irq_callback_user_data_t cb,
307 void *cb_data)
308 {
309 struct uart_mcux_data *data = dev->data;
310
311 data->callback = cb;
312 data->cb_data = cb_data;
313 }
314
uart_mcux_isr(const struct device * dev)315 static void uart_mcux_isr(const struct device *dev)
316 {
317 struct uart_mcux_data *data = dev->data;
318 if (data->callback) {
319 data->callback(dev, data->cb_data);
320 }
321 }
322 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
323
uart_mcux_init(const struct device * dev)324 static int uart_mcux_init(const struct device *dev)
325 {
326 const struct uart_mcux_config *config = dev->config;
327 struct uart_mcux_data *data = dev->data;
328 int err;
329
330 err = uart_mcux_configure(dev, &data->uart_cfg);
331 if (err != 0) {
332 return err;
333 }
334
335 err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
336 if (err != 0) {
337 return err;
338 }
339
340 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
341 config->irq_config_func(dev);
342 #endif
343
344 return 0;
345 }
346
347 #ifdef CONFIG_PM_DEVICE
uart_mcux_pm_action(const struct device * dev,enum pm_device_action action)348 static int uart_mcux_pm_action(const struct device *dev, enum pm_device_action action)
349 {
350 const struct uart_mcux_config *config = dev->config;
351
352 switch (action) {
353 case PM_DEVICE_ACTION_RESUME:
354 clock_control_on(config->clock_dev, config->clock_subsys);
355 break;
356 case PM_DEVICE_ACTION_SUSPEND:
357 clock_control_off(config->clock_dev, config->clock_subsys);
358 break;
359 case PM_DEVICE_ACTION_TURN_OFF:
360 return 0;
361 case PM_DEVICE_ACTION_TURN_ON:
362 return 0;
363 default:
364 return -ENOTSUP;
365 }
366 return 0;
367 }
368 #endif /*CONFIG_PM_DEVICE*/
369
370 static DEVICE_API(uart, uart_mcux_driver_api) = {
371 .poll_in = uart_mcux_poll_in,
372 .poll_out = uart_mcux_poll_out,
373 .err_check = uart_mcux_err_check,
374 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
375 .configure = uart_mcux_configure,
376 .config_get = uart_mcux_config_get,
377 #endif
378 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
379 .fifo_fill = uart_mcux_fifo_fill,
380 .fifo_read = uart_mcux_fifo_read,
381 .irq_tx_enable = uart_mcux_irq_tx_enable,
382 .irq_tx_disable = uart_mcux_irq_tx_disable,
383 .irq_tx_complete = uart_mcux_irq_tx_complete,
384 .irq_tx_ready = uart_mcux_irq_tx_ready,
385 .irq_rx_enable = uart_mcux_irq_rx_enable,
386 .irq_rx_disable = uart_mcux_irq_rx_disable,
387 .irq_rx_ready = uart_mcux_irq_rx_full,
388 .irq_err_enable = uart_mcux_irq_err_enable,
389 .irq_err_disable = uart_mcux_irq_err_disable,
390 .irq_is_pending = uart_mcux_irq_is_pending,
391 .irq_update = uart_mcux_irq_update,
392 .irq_callback_set = uart_mcux_irq_callback_set,
393 #endif
394 };
395
396 #define UART_MCUX_DECLARE_CFG(n, IRQ_FUNC_INIT) \
397 static const struct uart_mcux_config uart_mcux_##n##_config = { \
398 .base = (UART_Type *)DT_INST_REG_ADDR(n), \
399 .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
400 .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),\
401 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
402 IRQ_FUNC_INIT \
403 }
404
405 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
406 #define UART_MCUX_CONFIG_FUNC(n) \
407 static void uart_mcux_config_func_##n(const struct device *dev) \
408 { \
409 UART_MCUX_IRQ(n, status); \
410 UART_MCUX_IRQ(n, error); \
411 }
412
413 #define UART_MCUX_IRQ_INIT(n, name) \
414 do { \
415 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, name, irq), \
416 DT_INST_IRQ_BY_NAME(n, name, priority), \
417 uart_mcux_isr, DEVICE_DT_INST_GET(n), 0); \
418 \
419 irq_enable(DT_INST_IRQ_BY_NAME(n, name, irq)); \
420 } while (false)
421
422 #define UART_MCUX_IRQ(n, name) \
423 COND_CODE_1(DT_INST_IRQ_HAS_NAME(n, name), \
424 (UART_MCUX_IRQ_INIT(n, name)), ())
425
426 #define UART_MCUX_IRQ_CFG_FUNC_INIT(n) \
427 .irq_config_func = uart_mcux_config_func_##n
428 #define UART_MCUX_INIT_CFG(n) \
429 UART_MCUX_DECLARE_CFG(n, UART_MCUX_IRQ_CFG_FUNC_INIT(n))
430 #else
431 #define UART_MCUX_CONFIG_FUNC(n)
432 #define UART_MCUX_IRQ_CFG_FUNC_INIT
433 #define UART_MCUX_INIT_CFG(n) \
434 UART_MCUX_DECLARE_CFG(n, UART_MCUX_IRQ_CFG_FUNC_INIT)
435 #endif
436
437 #define UART_MCUX_INIT(n) \
438 PINCTRL_DT_INST_DEFINE(n); \
439 \
440 static struct uart_mcux_data uart_mcux_##n##_data = { \
441 .uart_cfg = { \
442 .stop_bits = UART_CFG_STOP_BITS_1, \
443 .data_bits = UART_CFG_DATA_BITS_8, \
444 .baudrate = DT_INST_PROP(n, current_speed), \
445 .parity = UART_CFG_PARITY_NONE, \
446 .flow_ctrl = DT_INST_PROP(n, hw_flow_control) ? \
447 UART_CFG_FLOW_CTRL_RTS_CTS : UART_CFG_FLOW_CTRL_NONE,\
448 }, \
449 }; \
450 \
451 static const struct uart_mcux_config uart_mcux_##n##_config; \
452 PM_DEVICE_DT_INST_DEFINE(n, uart_mcux_pm_action);\
453 \
454 DEVICE_DT_INST_DEFINE(n, \
455 uart_mcux_init, \
456 PM_DEVICE_DT_INST_GET(n), \
457 &uart_mcux_##n##_data, \
458 &uart_mcux_##n##_config, \
459 PRE_KERNEL_1, \
460 CONFIG_SERIAL_INIT_PRIORITY, \
461 &uart_mcux_driver_api); \
462 \
463 UART_MCUX_CONFIG_FUNC(n) \
464 \
465 UART_MCUX_INIT_CFG(n);
466
467 DT_INST_FOREACH_STATUS_OKAY(UART_MCUX_INIT)
468