1 /*
2 * Copyright (c) 2019, Manivannan Sadhasivam <mani@kernel.org>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_imx_iuart
8
9 #include <device.h>
10 #include <drivers/uart.h>
11 #include <drivers/clock_control.h>
12 #include <errno.h>
13 #include <fsl_uart.h>
14 #include <soc.h>
15
16 struct mcux_iuart_config {
17 UART_Type *base;
18 const struct device *clock_dev;
19 clock_control_subsys_t clock_subsys;
20 uint32_t baud_rate;
21 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
22 void (*irq_config_func)(const struct device *dev);
23 #endif
24 };
25
26 struct mcux_iuart_data {
27 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
28 uart_irq_callback_user_data_t callback;
29 void *cb_data;
30 #endif
31 };
32
33 #define DEV_CFG(dev) \
34 ((const struct mcux_iuart_config * const)(dev)->config)
35
mcux_iuart_poll_in(const struct device * dev,unsigned char * c)36 static int mcux_iuart_poll_in(const struct device *dev, unsigned char *c)
37 {
38 const struct mcux_iuart_config *config = DEV_CFG(dev);
39 int ret = -1;
40
41 if (UART_GetStatusFlag(config->base, kUART_RxDataReadyFlag)) {
42 *c = UART_ReadByte(config->base);
43 ret = 0;
44 }
45
46 return ret;
47 }
48
mcux_iuart_poll_out(const struct device * dev,unsigned char c)49 static void mcux_iuart_poll_out(const struct device *dev, unsigned char c)
50 {
51 const struct mcux_iuart_config *config = DEV_CFG(dev);
52
53 while (!(UART_GetStatusFlag(config->base, kUART_TxReadyFlag))) {
54 }
55
56 UART_WriteByte(config->base, c);
57 }
58
mcux_iuart_err_check(const struct device * dev)59 static int mcux_iuart_err_check(const struct device *dev)
60 {
61 const struct mcux_iuart_config *config = DEV_CFG(dev);
62 int err = 0;
63
64 if (UART_GetStatusFlag(config->base, kUART_RxOverrunFlag)) {
65 err |= UART_ERROR_OVERRUN;
66 UART_ClearStatusFlag(config->base, kUART_RxOverrunFlag);
67 }
68
69 if (UART_GetStatusFlag(config->base, kUART_ParityErrorFlag)) {
70 err |= UART_ERROR_PARITY;
71 UART_ClearStatusFlag(config->base, kUART_ParityErrorFlag);
72 }
73
74 if (UART_GetStatusFlag(config->base, kUART_FrameErrorFlag)) {
75 err |= UART_ERROR_FRAMING;
76 UART_ClearStatusFlag(config->base, kUART_FrameErrorFlag);
77 }
78
79 return err;
80 }
81
82 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
mcux_iuart_fifo_fill(const struct device * dev,const uint8_t * tx_data,int len)83 static int mcux_iuart_fifo_fill(const struct device *dev,
84 const uint8_t *tx_data,
85 int len)
86 {
87 const struct mcux_iuart_config *config = DEV_CFG(dev);
88 uint8_t num_tx = 0U;
89
90 while ((len - num_tx > 0) &&
91 (UART_GetStatusFlag(config->base, kUART_TxEmptyFlag))) {
92
93 UART_WriteByte(config->base, tx_data[num_tx++]);
94 }
95
96 return num_tx;
97 }
98
mcux_iuart_fifo_read(const struct device * dev,uint8_t * rx_data,const int len)99 static int mcux_iuart_fifo_read(const struct device *dev, uint8_t *rx_data,
100 const int len)
101 {
102 const struct mcux_iuart_config *config = DEV_CFG(dev);
103 uint8_t num_rx = 0U;
104
105 while ((len - num_rx > 0) &&
106 (UART_GetStatusFlag(config->base, kUART_RxDataReadyFlag))) {
107
108 rx_data[num_rx++] = UART_ReadByte(config->base);
109 }
110
111 return num_rx;
112 }
113
mcux_iuart_irq_tx_enable(const struct device * dev)114 static void mcux_iuart_irq_tx_enable(const struct device *dev)
115 {
116 const struct mcux_iuart_config *config = DEV_CFG(dev);
117
118 UART_EnableInterrupts(config->base, kUART_TxEmptyEnable);
119 }
120
mcux_iuart_irq_tx_disable(const struct device * dev)121 static void mcux_iuart_irq_tx_disable(const struct device *dev)
122 {
123 const struct mcux_iuart_config *config = DEV_CFG(dev);
124
125 UART_DisableInterrupts(config->base, kUART_TxEmptyEnable);
126 }
127
mcux_iuart_irq_tx_complete(const struct device * dev)128 static int mcux_iuart_irq_tx_complete(const struct device *dev)
129 {
130 const struct mcux_iuart_config *config = DEV_CFG(dev);
131
132 return (UART_GetStatusFlag(config->base, kUART_TxEmptyFlag)) != 0U;
133 }
134
mcux_iuart_irq_tx_ready(const struct device * dev)135 static int mcux_iuart_irq_tx_ready(const struct device *dev)
136 {
137 const struct mcux_iuart_config *config = DEV_CFG(dev);
138 uint32_t mask = kUART_TxEmptyEnable;
139
140 return (UART_GetEnabledInterrupts(config->base) & mask)
141 && mcux_iuart_irq_tx_complete(dev);
142 }
143
mcux_iuart_irq_rx_enable(const struct device * dev)144 static void mcux_iuart_irq_rx_enable(const struct device *dev)
145 {
146 const struct mcux_iuart_config *config = DEV_CFG(dev);
147 uint32_t mask = kUART_RxDataReadyEnable;
148
149 UART_EnableInterrupts(config->base, mask);
150 }
151
mcux_iuart_irq_rx_disable(const struct device * dev)152 static void mcux_iuart_irq_rx_disable(const struct device *dev)
153 {
154 const struct mcux_iuart_config *config = DEV_CFG(dev);
155 uint32_t mask = kUART_RxDataReadyEnable;
156
157 UART_DisableInterrupts(config->base, mask);
158 }
159
mcux_iuart_irq_rx_full(const struct device * dev)160 static int mcux_iuart_irq_rx_full(const struct device *dev)
161 {
162 const struct mcux_iuart_config *config = DEV_CFG(dev);
163
164 return (UART_GetStatusFlag(config->base, kUART_RxDataReadyFlag)) != 0U;
165 }
166
mcux_iuart_irq_rx_pending(const struct device * dev)167 static int mcux_iuart_irq_rx_pending(const struct device *dev)
168 {
169 const struct mcux_iuart_config *config = DEV_CFG(dev);
170 uint32_t mask = kUART_RxDataReadyEnable;
171
172 return (UART_GetEnabledInterrupts(config->base) & mask)
173 && mcux_iuart_irq_rx_full(dev);
174 }
175
mcux_iuart_irq_err_enable(const struct device * dev)176 static void mcux_iuart_irq_err_enable(const struct device *dev)
177 {
178 const struct mcux_iuart_config *config = DEV_CFG(dev);
179 uint32_t mask = kUART_RxOverrunEnable | kUART_ParityErrorEnable |
180 kUART_FrameErrorEnable;
181
182 UART_EnableInterrupts(config->base, mask);
183 }
184
mcux_iuart_irq_err_disable(const struct device * dev)185 static void mcux_iuart_irq_err_disable(const struct device *dev)
186 {
187 const struct mcux_iuart_config *config = DEV_CFG(dev);
188 uint32_t mask = kUART_RxOverrunEnable | kUART_ParityErrorEnable |
189 kUART_FrameErrorEnable;
190
191 UART_DisableInterrupts(config->base, mask);
192 }
193
mcux_iuart_irq_is_pending(const struct device * dev)194 static int mcux_iuart_irq_is_pending(const struct device *dev)
195 {
196 return mcux_iuart_irq_tx_ready(dev) || mcux_iuart_irq_rx_pending(dev);
197 }
198
mcux_iuart_irq_update(const struct device * dev)199 static int mcux_iuart_irq_update(const struct device *dev)
200 {
201 return 1;
202 }
203
mcux_iuart_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)204 static void mcux_iuart_irq_callback_set(const struct device *dev,
205 uart_irq_callback_user_data_t cb,
206 void *cb_data)
207 {
208 struct mcux_iuart_data *data = dev->data;
209
210 data->callback = cb;
211 data->cb_data = cb_data;
212 }
213
mcux_iuart_isr(const struct device * dev)214 static void mcux_iuart_isr(const struct device *dev)
215 {
216 struct mcux_iuart_data *data = dev->data;
217
218 if (data->callback) {
219 data->callback(dev, data->cb_data);
220 }
221 }
222 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
223
mcux_iuart_init(const struct device * dev)224 static int mcux_iuart_init(const struct device *dev)
225 {
226 const struct mcux_iuart_config *config = DEV_CFG(dev);
227 uart_config_t uart_config;
228 uint32_t clock_freq;
229
230 if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
231 &clock_freq)) {
232 return -EINVAL;
233 }
234
235 UART_GetDefaultConfig(&uart_config);
236 uart_config.enableTx = true;
237 uart_config.enableRx = true;
238 uart_config.baudRate_Bps = config->baud_rate;
239
240 UART_Init(config->base, &uart_config, clock_freq);
241
242 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
243 config->irq_config_func(dev);
244 #endif
245
246 return 0;
247 }
248
249 static const struct uart_driver_api mcux_iuart_driver_api = {
250 .poll_in = mcux_iuart_poll_in,
251 .poll_out = mcux_iuart_poll_out,
252 .err_check = mcux_iuart_err_check,
253 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
254 .fifo_fill = mcux_iuart_fifo_fill,
255 .fifo_read = mcux_iuart_fifo_read,
256 .irq_tx_enable = mcux_iuart_irq_tx_enable,
257 .irq_tx_disable = mcux_iuart_irq_tx_disable,
258 .irq_tx_complete = mcux_iuart_irq_tx_complete,
259 .irq_tx_ready = mcux_iuart_irq_tx_ready,
260 .irq_rx_enable = mcux_iuart_irq_rx_enable,
261 .irq_rx_disable = mcux_iuart_irq_rx_disable,
262 .irq_rx_ready = mcux_iuart_irq_rx_full,
263 .irq_err_enable = mcux_iuart_irq_err_enable,
264 .irq_err_disable = mcux_iuart_irq_err_disable,
265 .irq_is_pending = mcux_iuart_irq_is_pending,
266 .irq_update = mcux_iuart_irq_update,
267 .irq_callback_set = mcux_iuart_irq_callback_set,
268 #endif
269 };
270
271 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
272 #define MCUX_IUART_IRQ_INIT(n, i) \
273 do { \
274 IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, i, irq), \
275 DT_INST_IRQ_BY_IDX(n, i, priority), \
276 mcux_iuart_isr, DEVICE_DT_INST_GET(n), 0); \
277 \
278 irq_enable(DT_INST_IRQ_BY_IDX(n, i, irq)); \
279 } while (0)
280 #define IUART_MCUX_CONFIG_FUNC(n) \
281 static void mcux_iuart_config_func_##n(const struct device *dev) \
282 { \
283 MCUX_IUART_IRQ_INIT(n, 0); \
284 \
285 IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 1), \
286 (MCUX_IUART_IRQ_INIT(n, 1);)) \
287 }
288 #define IUART_MCUX_IRQ_CFG_FUNC_INIT(n) \
289 .irq_config_func = mcux_iuart_config_func_##n
290 #define IUART_MCUX_INIT_CFG(n) \
291 IUART_MCUX_DECLARE_CFG(n, IUART_MCUX_IRQ_CFG_FUNC_INIT(n))
292 #else
293 #define IUART_MCUX_CONFIG_FUNC(n)
294 #define IUART_MCUX_IRQ_CFG_FUNC_INIT
295 #define IUART_MCUX_INIT_CFG(n) \
296 IUART_MCUX_DECLARE_CFG(n, IUART_MCUX_IRQ_CFG_FUNC_INIT)
297 #endif
298
299 #define IUART_MCUX_DECLARE_CFG(n, IRQ_FUNC_INIT) \
300 static const struct mcux_iuart_config mcux_iuart_##n##_config = { \
301 .base = (UART_Type *) DT_INST_REG_ADDR(n), \
302 .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
303 .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),\
304 .baud_rate = DT_INST_PROP(n, current_speed), \
305 IRQ_FUNC_INIT \
306 }
307
308 #define IUART_MCUX_INIT(n) \
309 \
310 static struct mcux_iuart_data mcux_iuart_##n##_data; \
311 \
312 static const struct mcux_iuart_config mcux_iuart_##n##_config;\
313 \
314 DEVICE_DT_INST_DEFINE(n, \
315 &mcux_iuart_init, \
316 NULL, \
317 &mcux_iuart_##n##_data, \
318 &mcux_iuart_##n##_config, \
319 PRE_KERNEL_1, \
320 CONFIG_SERIAL_INIT_PRIORITY, \
321 &mcux_iuart_driver_api); \
322 \
323 IUART_MCUX_CONFIG_FUNC(n) \
324 \
325 IUART_MCUX_INIT_CFG(n);
326
327 DT_INST_FOREACH_STATUS_OKAY(IUART_MCUX_INIT)
328