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