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 * 2024-02-06 yandld The first version for MCX
9 * 2024-11-11 hywing add more UART channels
10 */
11 #include <rtdevice.h>
12 #include "drv_uart.h"
13 #include "fsl_lpuart.h"
14
15 #ifdef RT_USING_SERIAL
16
17 #define DBG_TAG "drv.uart"
18 #define DBG_LVL DBG_INFO
19 #include <rtdbg.h>
20
21 struct mcx_uart
22 {
23 struct rt_serial_device *serial;
24 LPUART_Type *uart_base;
25 IRQn_Type irqn;
26 clock_name_t clock_src;
27 clock_attach_id_t clock_attach_id;
28 clock_ip_name_t clock_ip_name;
29 clock_div_name_t clock_div_name;
30 char *device_name;
31 };
32
33 static void uart_isr(struct rt_serial_device *serial);
34
35 #if defined(BSP_USING_UART0)
36 struct rt_serial_device serial0;
37
LPUART0_IRQHandler(void)38 void LPUART0_IRQHandler(void)
39 {
40 uart_isr(&serial0);
41 }
42 #endif
43 #if defined(BSP_USING_UART1)
44 struct rt_serial_device serial1;
45
LPUART1_IRQHandler(void)46 void LPUART1_IRQHandler(void)
47 {
48 uart_isr(&serial1);
49 }
50 #endif
51 #if defined(BSP_USING_UART2)
52 struct rt_serial_device serial2;
53
LPUART2_IRQHandler(void)54 void LPUART2_IRQHandler(void)
55 {
56 uart_isr(&serial2);
57 }
58 #endif
59
60 static const struct mcx_uart uarts[] =
61 {
62 #ifdef BSP_USING_UART0
63 {
64 &serial0,
65 LPUART0,
66 LPUART0_IRQn,
67 #if (defined(CPU_MCXA346VLH) || defined(CPU_MCXA346VLL) || defined(CPU_MCXA346VLQ) || defined(CPU_MCXA346VPN))
68 kFRO_LF_DIV_to_LPUART0,
69 #else
70 kFRO12M_to_LPUART0,
71 #endif
72 kFRO12M_to_LPUART0,
73 kCLOCK_GateLPUART0,
74 kCLOCK_DivLPUART0,
75 "uart0",
76 },
77 #endif
78 #ifdef BSP_USING_UART1
79 {
80 &serial1,
81 LPUART1,
82 LPUART1_IRQn,
83 #if (defined(CPU_MCXA346VLH) || defined(CPU_MCXA346VLL) || defined(CPU_MCXA346VLQ) || defined(CPU_MCXA346VPN))
84 kFRO_LF_DIV_to_LPUART1,
85 #else
86 kFRO12M_to_LPUART1,
87 #endif
88 kFRO12M_to_LPUART1,
89 kCLOCK_GateLPUART1,
90 kCLOCK_DivLPUART1,
91 "uart1",
92 },
93 #endif
94 #ifdef BSP_USING_UART2
95 {
96 &serial2,
97 LPUART2,
98 LPUART2_IRQn,
99 kCLOCK_Fro12M,
100 #if (defined(CPU_MCXA346VLH) || defined(CPU_MCXA346VLL) || defined(CPU_MCXA346VLQ) || defined(CPU_MCXA346VPN))
101 kFRO_LF_DIV_to_LPUART2,
102 #else
103 kFRO12M_to_LPUART2,
104 #endif
105 kCLOCK_GateLPUART2,
106 kCLOCK_DivLPUART2,
107 "uart2",
108 },
109 #endif
110 };
111
mcx_configure(struct rt_serial_device * serial,struct serial_configure * cfg)112 static rt_err_t mcx_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
113 {
114 struct mcx_uart *uart;
115 lpuart_config_t config;
116
117 RT_ASSERT(serial != RT_NULL);
118 RT_ASSERT(cfg != RT_NULL);
119
120 uart = (struct mcx_uart *)serial->parent.user_data;
121
122 CLOCK_SetClockDiv(uart->clock_div_name, 1u);
123 CLOCK_AttachClk(uart->clock_attach_id);
124 CLOCK_EnableClock(uart->clock_ip_name);
125
126 LPUART_GetDefaultConfig(&config);
127 config.baudRate_Bps = cfg->baud_rate;
128
129 switch (cfg->data_bits)
130 {
131 case DATA_BITS_7:
132 config.dataBitsCount = kLPUART_SevenDataBits;
133 break;
134
135 default:
136 config.dataBitsCount = kLPUART_EightDataBits;
137 break;
138 }
139
140 config.enableTx = true;
141 config.enableRx = true;
142
143 LPUART_Init(uart->uart_base, &config, CLOCK_GetFreq(uart->clock_src));
144
145 return RT_EOK;
146 }
147
mcx_control(struct rt_serial_device * serial,int cmd,void * arg)148 static rt_err_t mcx_control(struct rt_serial_device *serial, int cmd, void *arg)
149 {
150 struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data;
151
152 RT_ASSERT(uart != RT_NULL);
153
154 switch (cmd)
155 {
156 case RT_DEVICE_CTRL_CLR_INT:
157 /* disable rx irq */
158 LPUART_DisableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable);
159 DisableIRQ(uart->irqn);
160 break;
161 case RT_DEVICE_CTRL_SET_INT:
162 /* enable rx irq */
163 LPUART_EnableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable);
164 EnableIRQ(uart->irqn);
165 break;
166 }
167
168 return RT_EOK;
169 }
170
mcx_putc(struct rt_serial_device * serial,char ch)171 static int mcx_putc(struct rt_serial_device *serial, char ch)
172 {
173 struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data;
174
175 while(!(kLPUART_TxDataRegEmptyFlag & LPUART_GetStatusFlags(uart->uart_base)));
176 LPUART_WriteByte(uart->uart_base, ch);
177
178 return 1;
179 }
180
mcx_getc(struct rt_serial_device * serial)181 static int mcx_getc(struct rt_serial_device *serial)
182 {
183 struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data;
184
185 if (kLPUART_RxDataRegFullInterruptEnable & LPUART_GetStatusFlags(uart->uart_base))
186 {
187 return LPUART_ReadByte(uart->uart_base);
188 }
189 else
190 {
191 return -1;
192 }
193 }
194
195 /**
196 * Uart common interrupt process. This need add to uart ISR.
197 *
198 * @param serial serial device
199 */
uart_isr(struct rt_serial_device * serial)200 static void uart_isr(struct rt_serial_device *serial)
201 {
202 struct mcx_uart *uart;
203
204 RT_ASSERT(serial != RT_NULL);
205
206 uart = (struct mcx_uart *) serial->parent.user_data;
207 RT_ASSERT(uart != RT_NULL);
208
209 /* enter interrupt */
210 rt_interrupt_enter();
211
212 /* UART in mode Receiver -------------------------------------------------*/
213 rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
214
215 /* leave interrupt */
216 rt_interrupt_leave();
217 }
218
219 static const struct rt_uart_ops mcx_uart_ops =
220 {
221 mcx_configure,
222 mcx_control,
223 mcx_putc,
224 mcx_getc,
225 };
226
rt_hw_uart_init(void)227 int rt_hw_uart_init(void)
228 {
229 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
230 int i;
231
232 for (i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++)
233 {
234 uarts[i].serial->ops = &mcx_uart_ops;
235 uarts[i].serial->config = config;
236
237 /* register UART device */
238 rt_hw_serial_register(uarts[i].serial, uarts[i].device_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, (void *)&uarts[i]);
239 }
240
241 return 0;
242 }
243 INIT_BOARD_EXPORT(rt_hw_uart_init);
244 #endif /*BSP_USING_SERIAL */
245