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