1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-07-15 yandld The first version for MCXN
9 */
10
11 #include <rtthread.h>
12 #include "drv_uart.h"
13
14 #include "fsl_lpuart.h"
15 #include "fsl_common.h"
16
17 #ifdef RT_USING_SERIAL
18
19
20
21 #include <rtdevice.h>
22
23 /* lpc uart driver */
24 struct mcx_uart
25 {
26 struct rt_serial_device *serial; /* Select serial device */
27 LPUART_Type *uart_base; /* serial base */
28 IRQn_Type irqn; /* serial interrupt */
29 clock_name_t clock_src; /* serial RTC */
30 clock_attach_id_t clock_attach_id; /* RTC ID */
31 clock_ip_name_t clock_ip_name; /* serial clock name */
32 clock_div_name_t clock_div_name; /* serial clock div */
33 char *device_name; /* serial device name */
34 };
35
36 static void uart_isr(struct rt_serial_device *serial);
37
38 #if defined(BSP_USING_UART2)
39 struct rt_serial_device serial2;
40
LP_FLEXCOMM2_IRQHandler(void)41 void LP_FLEXCOMM2_IRQHandler(void)
42 {
43 uart_isr(&serial2); /* Serial interrupt handling function */
44 }
45 #endif /* BSP_USING_UART2 */
46
47 #if defined(BSP_USING_UART4)
48 struct rt_serial_device serial4;
49
LP_FLEXCOMM4_IRQHandler(void)50 void LP_FLEXCOMM4_IRQHandler(void)
51 {
52 uart_isr(&serial4); /* Serial interrupt handling function */
53 }
54 #endif /* BSP_USING_UART4 */
55
56 #if defined(BSP_USING_UART5)
57 struct rt_serial_device serial5;
58
LP_FLEXCOMM5_IRQHandler(void)59 void LP_FLEXCOMM5_IRQHandler(void)
60 {
61 uart_isr(&serial5); /* Serial interrupt handling function */
62 }
63 #endif /* BSP_USING_UART5 */
64
65 #if defined(BSP_USING_UART6) /* same UART4 */
66 struct rt_serial_device serial6;
67
LP_FLEXCOMM6_IRQHandler(void)68 void LP_FLEXCOMM6_IRQHandler(void)
69 {
70 uart_isr(&serial6);
71 }
72 #endif /* BSP_USING_UART6 */
73
74 static const struct mcx_uart uarts[] = /* Initializes the above structure */
75 {
76 #ifdef BSP_USING_UART2
77 {
78 &serial2,
79 LPUART2,
80 LP_FLEXCOMM2_IRQn,
81 kCLOCK_Fro12M,
82 kFRO12M_to_FLEXCOMM2,
83 kCLOCK_LPFlexComm2,
84 kCLOCK_DivFlexcom2Clk,
85 "uart2",
86 },
87 #endif
88 #ifdef BSP_USING_UART4
89 {
90 &serial4,
91 LPUART4,
92 LP_FLEXCOMM4_IRQn,
93 kCLOCK_Fro12M,
94 kFRO12M_to_FLEXCOMM4,
95 kCLOCK_LPFlexComm4,
96 kCLOCK_DivFlexcom4Clk,
97 "uart4",
98 },
99 #endif
100 #ifdef BSP_USING_UART5
101 {
102 &serial5,
103 LPUART5,
104 LP_FLEXCOMM5_IRQn,
105 kCLOCK_Fro12M,
106 kFRO12M_to_FLEXCOMM5,
107 kCLOCK_LPFlexComm5,
108 kCLOCK_DivFlexcom5Clk,
109 "uart5",
110 },
111 #endif
112 #ifdef BSP_USING_UART6
113 {
114 &serial6,
115 LPUART6,
116 LP_FLEXCOMM6_IRQn,
117 kCLOCK_Fro12M,
118 kFRO12M_to_FLEXCOMM6,
119 kCLOCK_LPFlexComm6,
120 kCLOCK_DivFlexcom6Clk,
121 "uart6",
122 },
123 #endif
124 };
125
126 /**
127 * Configuring the serial port Module.
128 *
129 * @param serial device
130 * @param Configure the serial port configuration structure to set the TX RX features
131 */
mcx_configure(struct rt_serial_device * serial,struct serial_configure * cfg)132 static rt_err_t mcx_configure(struct rt_serial_device *serial, struct serial_configure *cfg) /* Configuring the serial port Module */
133 {
134 struct mcx_uart *uart; /* Serial port hardware structure, calling the structure initialized above */
135 lpuart_config_t config;/* It contains basic configuration parameters of the serial port, such as baud rate, data bit, stop bit, and parity check */
136
137 RT_ASSERT(serial != RT_NULL); /* assert */
138 RT_ASSERT(cfg != RT_NULL);
139
140 uart = (struct mcx_uart *)serial->parent.user_data;
141
142 CLOCK_SetClkDiv(uart->clock_div_name, 1u);
143 CLOCK_AttachClk(uart->clock_attach_id);
144 CLOCK_EnableClock(uart->clock_ip_name);
145
146 LPUART_GetDefaultConfig(&config);
147 config.baudRate_Bps = cfg->baud_rate;
148
149 switch (cfg->data_bits)
150 {
151 case DATA_BITS_7:
152 config.dataBitsCount = kLPUART_SevenDataBits;
153 break;
154
155 default:
156 config.dataBitsCount = kLPUART_EightDataBits;
157 break;
158 }
159
160 config.enableTx = true;
161 config.enableRx = true;
162
163 LPUART_Init(uart->uart_base, &config, CLOCK_GetFreq(uart->clock_src));
164
165 return RT_EOK;
166 }
167
168 /**
169 * Serial Control Function.
170 *
171 * @param serial device struct
172 * @param control Cmd
173 * @param Parameters passed to the control command
174 */
mcx_control(struct rt_serial_device * serial,int cmd,void * arg)175 static rt_err_t mcx_control(struct rt_serial_device *serial, int cmd, void *arg)/* serial control */
176 {
177 struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data; /* Convert the type to struct mcx_uart */
178
179 RT_ASSERT(uart != RT_NULL); /* Assert */
180
181 switch (cmd)
182 {
183 case RT_DEVICE_CTRL_CLR_INT:
184 /* disable rx irq */
185 LPUART_DisableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable);
186 DisableIRQ(uart->irqn);
187 break;
188 case RT_DEVICE_CTRL_SET_INT:
189 /* enable rx irq */
190 LPUART_EnableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable);
191 EnableIRQ(uart->irqn);
192 break;
193 }
194
195
196 return RT_EOK;
197 }
198
199 /**
200 * Sends a single character function to a serial device.
201 *
202 * @param serial device struct
203 * @param The serial port character you want to send
204 */
mcx_putc(struct rt_serial_device * serial,char ch)205 static int mcx_putc(struct rt_serial_device *serial, char ch)
206 {
207 struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data;
208
209 while(!(kLPUART_TxDataRegEmptyFlag & LPUART_GetStatusFlags(uart->uart_base)));
210 LPUART_WriteByte(uart->uart_base, ch);
211
212 return 1;
213 }
214
mcx_getc(struct rt_serial_device * serial)215 static int mcx_getc(struct rt_serial_device *serial)
216 {
217 struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data;
218
219 if (kLPUART_RxDataRegFullInterruptEnable & LPUART_GetStatusFlags(uart->uart_base))
220 /* Check whether the receive cache is full and read the status flag bit of the status register
221 This flag is read, indicating that there is data in the cache and can be read */
222 {
223 return LPUART_ReadByte(uart->uart_base);
224 }
225 else
226 {
227 return -1;
228 }
229 }
230
231 /**
232 * Uart common interrupt process. This need add to uart ISR.
233 *
234 * @param serial serial device
235 */
uart_isr(struct rt_serial_device * serial)236 static void uart_isr(struct rt_serial_device *serial)
237 {
238 struct mcx_uart *uart; /* Create a serial port hardware structure variable */
239
240 RT_ASSERT(serial != RT_NULL);
241
242 uart = (struct mcx_uart *) serial->parent.user_data;
243 RT_ASSERT(uart != RT_NULL);
244
245 /* enter interrupt */
246 rt_interrupt_enter();
247
248 /* UART in mode Receiver -------------------------------------------------*/
249 rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
250
251 /* leave interrupt */
252 rt_interrupt_leave();
253 }
254
255 static const struct rt_uart_ops mcx_uart_ops =
256 {
257 mcx_configure,
258 mcx_control,
259 mcx_putc,
260 mcx_getc,
261 };
262
rt_hw_uart_init(void)263 int rt_hw_uart_init(void)
264 {
265 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* initial struct [115200,8,1,NONE] */
266 int i;
267 /* Registers loops for multiple serial devices */
268 for (i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++) /* sizeof(uarts) / sizeof(uarts[0] : Calculate the number of struct mcx_uart serial ports */
269 {
270 uarts[i].serial->ops = &mcx_uart_ops;
271 uarts[i].serial->config = config;
272
273 /**
274 * register UART device.
275 *
276 * @param Indicates the structure of the serial port device to be registered
277 * @param device name
278 * @param Flag bit mask
279 * @param A pointer to the current device that is used as user private data at registration
280 */
281 rt_hw_serial_register(uarts[i].serial, uarts[i].device_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, (void *)&uarts[i]);
282 }
283
284 return 0;
285 }
286
287 INIT_BOARD_EXPORT(rt_hw_uart_init); /* RT-Thread Automatic initialization mechanism */
288
289 #endif /*BSP_USING_SERIAL */
290