1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2018/10/28     Bernard           Unify UART driver for FSL library.
9  * 2019/09/07     niannianyouyu     Add the driver of UART1
10  */
11 
12 #include <rthw.h>
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 
16 #include "board.h"
17 #include "drv_uart.h"
18 
19 #include "fsl_lpuart.h"
20 
21 struct fsl_uart
22 {
23     LPUART_Type *uart_base;
24     IRQn_Type irqn;
25 
26     struct rt_serial_device *serial;
27     char *device_name;
28 };
29 
30 static rt_err_t  uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
31 static rt_err_t  uart_control(struct rt_serial_device *serial, int cmd, void *arg);
32 static int       uart_putc(struct rt_serial_device *serial, char c);
33 static int       uart_getc(struct rt_serial_device *serial);
34 static rt_ssize_t uart_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
35 
36 static void     uart_irq_handler(int irqno, void *param);
37 
38 const struct rt_uart_ops _uart_ops =
39 {
40     uart_configure,
41     uart_control,
42     uart_putc,
43     uart_getc,
44     uart_dma_transmit
45 };
46 
47 static void uart_isr(struct rt_serial_device *serial);
48 
49 #if defined(BSP_USING_UART0)
50 struct rt_serial_device serial0;
51 
LPUART0_IRQHandler(void)52 void LPUART0_IRQHandler(void)
53 {
54     uart_isr(&serial0);
55 }
56 #endif
57 
58 #if defined(BSP_USING_UART1)
59 struct rt_serial_device serial1;
60 
LPUART1_IRQHandler(void)61 void LPUART1_IRQHandler(void)
62 {
63     uart_isr(&serial1);
64 }
65 #endif
66 
67 static const struct fsl_uart uarts[] =
68 {
69 #ifdef BSP_USING_UART0
70     {
71         LPUART0,
72         LPUART0_IRQn,
73         &serial0,
74         "uart0",
75     },
76     #ifdef BSP_USING_UART1
77     {
78         LPUART1,
79         LPUART1_IRQn,
80         &serial1,
81         "uart1",
82     },
83 #endif
84 #endif
85 };
86 
87 
88 /*
89  * UART Initiation
90  */
rt_hw_uart_init(void)91 int rt_hw_uart_init(void)
92 {
93     int i;
94     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
95 
96     for (i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++)
97     {
98         uarts[i].serial->ops    = &_uart_ops;
99         uarts[i].serial->config = config;
100 
101         /* register UART device */
102         rt_hw_serial_register(uarts[i].serial,
103                               uarts[i].device_name,
104                               RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
105                               (void *)&uarts[i]);
106     }
107 
108     return 0;
109 }
110 
111 /*
112  * UART interface
113  */
uart_configure(struct rt_serial_device * serial,struct serial_configure * cfg)114 static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
115 {
116     struct fsl_uart *uart;
117     lpuart_config_t config;
118 
119     RT_ASSERT(serial != RT_NULL);
120     RT_ASSERT(cfg != RT_NULL);
121 
122     uart = (struct fsl_uart *)serial->parent.user_data;
123 
124     LPUART_GetDefaultConfig(&config);
125     config.baudRate_Bps = cfg->baud_rate;
126 
127     switch (cfg->data_bits)
128     {
129 #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
130     case DATA_BITS_7:
131         config.dataBitsCount = kLPUART_SevenDataBits;
132         break;
133 #endif
134 
135     default:
136         config.dataBitsCount = kLPUART_EightDataBits;
137         break;
138     }
139 
140     switch (cfg->stop_bits)
141     {
142     case STOP_BITS_2:
143         config.stopBitCount = kLPUART_TwoStopBit;
144         break;
145     default:
146         config.stopBitCount = kLPUART_OneStopBit;
147         break;
148     }
149 
150     switch (cfg->parity)
151     {
152     case PARITY_ODD:
153         config.parityMode = kLPUART_ParityOdd;
154         break;
155     case PARITY_EVEN:
156         config.parityMode = kLPUART_ParityEven;
157         break;
158     default:
159         config.parityMode = kLPUART_ParityDisabled;
160         break;
161     }
162 
163     config.enableTx = true;
164     config.enableRx = true;
165 
166     CLOCK_SetIpSrc(kCLOCK_Lpuart0, kCLOCK_IpSrcFircAsync);
167 
168     uint32_t uartClkSrcFreq0 = CLOCK_GetIpFreq(kCLOCK_Lpuart0);
169     LPUART_Init(uart->uart_base, &config, uartClkSrcFreq0);
170     LPUART_EnableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable);
171 
172     CLOCK_SetIpSrc(kCLOCK_Lpuart1, kCLOCK_IpSrcFircAsync);
173 
174     uint32_t uartClkSrcFreq1 = CLOCK_GetIpFreq(kCLOCK_Lpuart1);
175     LPUART_Init(uart->uart_base, &config, uartClkSrcFreq1);
176     LPUART_EnableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable);
177 
178     return RT_EOK;
179 }
180 
uart_control(struct rt_serial_device * serial,int cmd,void * arg)181 static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
182 {
183     struct fsl_uart *uart;
184 
185     RT_ASSERT(serial != RT_NULL);
186     uart = (struct fsl_uart *)serial->parent.user_data;
187 
188     switch (cmd)
189     {
190     case RT_DEVICE_CTRL_CLR_INT:
191         /* disable rx irq */
192         DisableIRQ(uart->irqn);
193 
194         break;
195     case RT_DEVICE_CTRL_SET_INT:
196         /* enable rx irq */
197         EnableIRQ(uart->irqn);
198         break;
199     }
200 
201     return RT_EOK;
202 }
203 
uart_putc(struct rt_serial_device * serial,char c)204 static int uart_putc(struct rt_serial_device *serial, char c)
205 {
206     struct fsl_uart *uart;
207 
208     RT_ASSERT(serial != RT_NULL);
209     uart = (struct fsl_uart *)serial->parent.user_data;
210 
211     LPUART_WriteByte(uart->uart_base, c);
212     while (!(LPUART_GetStatusFlags(uart->uart_base) & kLPUART_TxDataRegEmptyFlag));
213 
214     return (1);
215 }
216 
uart_getc(struct rt_serial_device * serial)217 static int uart_getc(struct rt_serial_device *serial)
218 {
219     int ch;
220     struct fsl_uart *uart;
221 
222     RT_ASSERT(serial != RT_NULL);
223     uart = (struct fsl_uart *)serial->parent.user_data;
224 
225     ch = -1;
226     if (LPUART_GetStatusFlags(uart->uart_base) & kLPUART_RxDataRegFullFlag)
227         ch = LPUART_ReadByte(uart->uart_base);
228     return ch;
229 }
230 
uart_dma_transmit(struct rt_serial_device * serial,rt_uint8_t * buf,rt_size_t size,int direction)231 static rt_ssize_t uart_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
232 {
233     return (0);
234 }
235 
236 /* UART ISR */
237 /**
238  * Uart common interrupt process. This need add to uart ISR.
239  *
240  * @param serial serial device
241  */
uart_isr(struct rt_serial_device * serial)242 static void uart_isr(struct rt_serial_device *serial)
243 {
244     struct fsl_uart *uart;
245 
246     RT_ASSERT(serial != RT_NULL);
247 
248     uart = (struct fsl_uart *) serial->parent.user_data;
249     RT_ASSERT(uart != RT_NULL);
250 
251     /* UART in mode Receiver */
252     if (LPUART_GetStatusFlags(uart->uart_base) & kLPUART_RxDataRegFullFlag)
253     {
254         rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
255     }
256 
257     /* If RX overrun. */
258     if (LPUART_STAT_OR_MASK & uart->uart_base->STAT)
259     {
260         /* Clear overrun flag, otherwise the RX does not work. */
261         uart->uart_base->STAT = ((uart->uart_base->STAT & 0x3FE00000U) | LPUART_STAT_OR_MASK);
262     }
263 }
264