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