1 /*
2 * Copyright (c) 2018 Diego Sueiro <diego.sueiro@gmail.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_imx_uart
8
9 /**
10 * @brief Driver for UART on NXP IMX family processor.
11 *
12 * For full serial function, use the USART controller.
13 *
14 */
15
16 #include <zephyr/kernel.h>
17 #include <zephyr/arch/cpu.h>
18 #include <zephyr/sys/__assert.h>
19 #include <soc.h>
20 #include <zephyr/init.h>
21 #include <zephyr/drivers/uart.h>
22 #include <uart_imx.h>
23 #include <zephyr/drivers/pinctrl.h>
24 #include <zephyr/irq.h>
25
26 #define UART_STRUCT(dev) \
27 ((UART_Type *)((const struct imx_uart_config *const)(dev)->config)->base)
28
29 struct imx_uart_config {
30 UART_Type *base;
31 uint32_t baud_rate;
32 uint8_t modem_mode;
33 const struct pinctrl_dev_config *pincfg;
34 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
35 void (*irq_config_func)(const struct device *dev);
36 #endif
37 };
38
39 struct imx_uart_data {
40 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
41 uart_irq_callback_user_data_t callback;
42 void *cb_data;
43 #endif
44 };
45
46 /**
47 * @brief Initialize UART channel
48 *
49 * This routine is called to reset the chip in a quiescent state.
50 * It is assumed that this function is called only once per UART.
51 *
52 * @param dev UART device struct
53 *
54 * @return 0
55 */
uart_imx_init(const struct device * dev)56 static int uart_imx_init(const struct device *dev)
57 {
58 UART_Type *uart = UART_STRUCT(dev);
59 const struct imx_uart_config *config = dev->config;
60 unsigned int old_level;
61 int err;
62
63 /* disable interrupts */
64 old_level = irq_lock();
65
66 /* Setup UART init structure */
67 uart_init_config_t initConfig = {
68 .baudRate = config->baud_rate,
69 .wordLength = uartWordLength8Bits,
70 .stopBitNum = uartStopBitNumOne,
71 .parity = uartParityDisable,
72 .direction = uartDirectionTxRx
73 };
74
75 err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
76 if (err) {
77 return err;
78 }
79
80 /* Get current module clock frequency */
81 initConfig.clockRate = get_uart_clock_freq(uart);
82
83 UART_Init(uart, &initConfig);
84
85 /* Set UART built-in hardware FIFO Watermark. */
86 UART_SetTxFifoWatermark(uart, 2);
87 UART_SetRxFifoWatermark(uart, 1);
88
89 /* restore interrupt state */
90 irq_unlock(old_level);
91
92 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
93 config->irq_config_func(dev);
94 #endif
95
96 /* Set UART modem mode */
97 UART_SetModemMode(uart, config->modem_mode);
98
99 /* Finally, enable the UART module */
100 UART_Enable(uart);
101
102 return 0;
103 }
104
uart_imx_poll_out(const struct device * dev,unsigned char c)105 static void uart_imx_poll_out(const struct device *dev, unsigned char c)
106 {
107 UART_Type *uart = UART_STRUCT(dev);
108
109 while (!UART_GetStatusFlag(uart, uartStatusTxReady)) {
110 }
111 UART_Putchar(uart, c);
112 }
113
uart_imx_poll_in(const struct device * dev,unsigned char * c)114 static int uart_imx_poll_in(const struct device *dev, unsigned char *c)
115 {
116 UART_Type *uart = UART_STRUCT(dev);
117 int ret = -1;
118
119 if (UART_GetStatusFlag(uart, uartStatusRxDataReady)) {
120 *c = UART_Getchar(uart);
121
122 if (UART_GetStatusFlag(uart, uartStatusRxOverrun)) {
123 UART_ClearStatusFlag(uart, uartStatusRxOverrun);
124 }
125 ret = 0;
126 }
127
128 return ret;
129 }
130
131 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
132
uart_imx_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)133 static int uart_imx_fifo_fill(const struct device *dev,
134 const uint8_t *tx_data,
135 int size)
136 {
137 UART_Type *uart = UART_STRUCT(dev);
138 unsigned int num_tx = 0U;
139
140 while (((size - num_tx) > 0) &&
141 UART_GetStatusFlag(uart, uartStatusTxReady)) {
142 /* Send a character */
143 UART_Putchar(uart, tx_data[num_tx]);
144 num_tx++;
145 }
146
147 return (int)num_tx;
148 }
149
uart_imx_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)150 static int uart_imx_fifo_read(const struct device *dev, uint8_t *rx_data,
151 const int size)
152 {
153 UART_Type *uart = UART_STRUCT(dev);
154 unsigned int num_rx = 0U;
155
156 while (((size - num_rx) > 0) &&
157 UART_GetStatusFlag(uart, uartStatusRxReady)) {
158 /* Receive a character */
159 rx_data[num_rx++] = UART_Getchar(uart);
160 }
161
162 if (UART_GetStatusFlag(uart, uartStatusRxOverrun)) {
163 UART_ClearStatusFlag(uart, uartStatusRxOverrun);
164 }
165
166 return num_rx;
167 }
168
uart_imx_irq_tx_enable(const struct device * dev)169 static void uart_imx_irq_tx_enable(const struct device *dev)
170 {
171 UART_Type *uart = UART_STRUCT(dev);
172
173 UART_SetIntCmd(uart, uartIntTxReady, true);
174 }
175
uart_imx_irq_tx_disable(const struct device * dev)176 static void uart_imx_irq_tx_disable(const struct device *dev)
177 {
178 UART_Type *uart = UART_STRUCT(dev);
179
180 UART_SetIntCmd(uart, uartIntTxReady, false);
181 }
182
uart_imx_irq_tx_ready(const struct device * dev)183 static int uart_imx_irq_tx_ready(const struct device *dev)
184 {
185 UART_Type *uart = UART_STRUCT(dev);
186
187 return UART_GetStatusFlag(uart, uartStatusTxReady);
188 }
189
uart_imx_irq_rx_enable(const struct device * dev)190 static void uart_imx_irq_rx_enable(const struct device *dev)
191 {
192 UART_Type *uart = UART_STRUCT(dev);
193
194 UART_SetIntCmd(uart, uartIntRxReady, true);
195 }
196
uart_imx_irq_rx_disable(const struct device * dev)197 static void uart_imx_irq_rx_disable(const struct device *dev)
198 {
199 UART_Type *uart = UART_STRUCT(dev);
200
201 UART_SetIntCmd(uart, uartIntRxReady, false);
202 }
203
uart_imx_irq_rx_ready(const struct device * dev)204 static int uart_imx_irq_rx_ready(const struct device *dev)
205 {
206 UART_Type *uart = UART_STRUCT(dev);
207
208 return UART_GetStatusFlag(uart, uartStatusRxReady);
209 }
210
uart_imx_irq_err_enable(const struct device * dev)211 static void uart_imx_irq_err_enable(const struct device *dev)
212 {
213 UART_Type *uart = UART_STRUCT(dev);
214
215 UART_SetIntCmd(uart, uartIntParityError, true);
216 UART_SetIntCmd(uart, uartIntFrameError, true);
217 }
218
uart_imx_irq_err_disable(const struct device * dev)219 static void uart_imx_irq_err_disable(const struct device *dev)
220 {
221 UART_Type *uart = UART_STRUCT(dev);
222
223 UART_SetIntCmd(uart, uartIntParityError, false);
224 UART_SetIntCmd(uart, uartIntFrameError, false);
225 }
226
uart_imx_irq_is_pending(const struct device * dev)227 static int uart_imx_irq_is_pending(const struct device *dev)
228 {
229 UART_Type *uart = UART_STRUCT(dev);
230
231 return UART_GetStatusFlag(uart, uartStatusRxReady) ||
232 UART_GetStatusFlag(uart, uartStatusTxReady);
233 }
234
uart_imx_irq_update(const struct device * dev)235 static int uart_imx_irq_update(const struct device *dev)
236 {
237 return 1;
238 }
239
uart_imx_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)240 static void uart_imx_irq_callback_set(const struct device *dev,
241 uart_irq_callback_user_data_t cb,
242 void *cb_data)
243 {
244 struct imx_uart_data *data = dev->data;
245
246 data->callback = cb;
247 data->cb_data = cb_data;
248 }
249
250 /**
251 * @brief Interrupt service routine.
252 *
253 * This simply calls the callback function, if one exists.
254 *
255 * Note: imx UART Tx interrupts when ready to send; Rx interrupts when char
256 * received.
257 *
258 * @param arg Argument to ISR.
259 */
uart_imx_isr(const struct device * dev)260 void uart_imx_isr(const struct device *dev)
261 {
262 struct imx_uart_data *data = dev->data;
263
264 if (data->callback) {
265 data->callback(dev, data->cb_data);
266 }
267 }
268 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
269
270 static const struct uart_driver_api uart_imx_driver_api = {
271 .poll_in = uart_imx_poll_in,
272 .poll_out = uart_imx_poll_out,
273
274 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
275 .fifo_fill = uart_imx_fifo_fill,
276 .fifo_read = uart_imx_fifo_read,
277 .irq_tx_enable = uart_imx_irq_tx_enable,
278 .irq_tx_disable = uart_imx_irq_tx_disable,
279 .irq_tx_ready = uart_imx_irq_tx_ready,
280 .irq_rx_enable = uart_imx_irq_rx_enable,
281 .irq_rx_disable = uart_imx_irq_rx_disable,
282 .irq_rx_ready = uart_imx_irq_rx_ready,
283 .irq_err_enable = uart_imx_irq_err_enable,
284 .irq_err_disable = uart_imx_irq_err_disable,
285 .irq_is_pending = uart_imx_irq_is_pending,
286 .irq_update = uart_imx_irq_update,
287 .irq_callback_set = uart_imx_irq_callback_set,
288 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
289
290 };
291
292 #define UART_IMX_DECLARE_CFG(n, IRQ_FUNC_INIT) \
293 static const struct imx_uart_config imx_uart_##n##_config = { \
294 .base = (UART_Type *) DT_INST_REG_ADDR(n), \
295 .baud_rate = DT_INST_PROP(n, current_speed), \
296 .modem_mode = DT_INST_PROP(n, modem_mode), \
297 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
298 IRQ_FUNC_INIT \
299 }
300
301 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
302 #define UART_IMX_CONFIG_FUNC(n) \
303 static void irq_config_func_##n(const struct device *dev) \
304 { \
305 IRQ_CONNECT(DT_INST_IRQN(n), \
306 DT_INST_IRQ(n, priority), \
307 uart_imx_isr, \
308 DEVICE_DT_INST_GET(n), 0); \
309 irq_enable(DT_INST_IRQN(n)); \
310 }
311 #define UART_IMX_IRQ_CFG_FUNC_INIT(n) \
312 .irq_config_func = irq_config_func_##n
313 #define UART_IMX_INIT_CFG(n) \
314 UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT(n))
315 #else
316 #define UART_IMX_CONFIG_FUNC(n)
317 #define UART_IMX_IRQ_CFG_FUNC_INIT
318 #define UART_IMX_INIT_CFG(n) \
319 UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT)
320 #endif
321
322 #define UART_IMX_INIT(n) \
323 static struct imx_uart_data imx_uart_##n##_data; \
324 \
325 static const struct imx_uart_config imx_uart_##n##_config; \
326 \
327 PINCTRL_DT_INST_DEFINE(n); \
328 \
329 DEVICE_DT_INST_DEFINE(n, &uart_imx_init, NULL, \
330 &imx_uart_##n##_data, &imx_uart_##n##_config, \
331 PRE_KERNEL_1, \
332 CONFIG_SERIAL_INIT_PRIORITY, \
333 &uart_imx_driver_api); \
334 \
335 UART_IMX_CONFIG_FUNC(n) \
336 \
337 UART_IMX_INIT_CFG(n);
338
339 DT_INST_FOREACH_STATUS_OKAY(UART_IMX_INIT)
340