1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2013-05-18     Bernard      The first version for LPC40xx
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "board.h"
14 
15 #ifdef RT_USING_SERIAL
16 
17 struct lpc_uart
18 {
19     LPC_UART_TypeDef *UART;
20     IRQn_Type UART_IRQn;
21 };
22 
lpc_configure(struct rt_serial_device * serial,struct serial_configure * cfg)23 static rt_err_t lpc_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
24 {
25     struct lpc_uart *uart;
26     uint32_t Fdiv = 0;
27 
28     RT_ASSERT(serial != RT_NULL);
29     uart = (struct lpc_uart *)serial->parent.user_data;
30 
31     /* Initialize UART Configuration parameter structure to default state:
32      * Baudrate = 115200 bps
33      * 8 data bit
34      * 1 Stop bit
35      * None parity
36      */
37     /* set DLAB=1 */
38     uart->UART->LCR |= 0x80;
39     /* config uart baudrate */
40     Fdiv = (PeripheralClock / 16) / cfg->baud_rate;
41     uart->UART->DLM = Fdiv / 256;
42     uart->UART->DLL = Fdiv % 256;
43     /* set DLAB=0 */
44     uart->UART->LCR &= ~0x80;
45     /* config to 8 data bit,1 Stop bit,None parity */
46     uart->UART->LCR |= 0x03;
47 
48     /*enable and reset FIFO*/
49     uart->UART->FCR = 0x07;
50 
51     return RT_EOK;
52 }
53 
lpc_control(struct rt_serial_device * serial,int cmd,void * arg)54 static rt_err_t lpc_control(struct rt_serial_device *serial, int cmd, void *arg)
55 {
56     struct lpc_uart *uart;
57 
58     RT_ASSERT(serial != RT_NULL);
59     uart = (struct lpc_uart *)serial->parent.user_data;
60 
61     switch (cmd)
62     {
63     case RT_DEVICE_CTRL_CLR_INT:
64         /* disable rx irq */
65         uart->UART->IER &= ~0x01;
66         break;
67     case RT_DEVICE_CTRL_SET_INT:
68         /* enable rx irq */
69         uart->UART->IER |= 0x01;
70         break;
71     }
72 
73     return RT_EOK;
74 }
75 
lpc_putc(struct rt_serial_device * serial,char c)76 static int lpc_putc(struct rt_serial_device *serial, char c)
77 {
78     struct lpc_uart *uart;
79 
80     uart = (struct lpc_uart *)serial->parent.user_data;
81     while (!(uart->UART->LSR & 0x20));
82     uart->UART->THR = c;
83 
84     return 1;
85 }
86 
lpc_getc(struct rt_serial_device * serial)87 static int lpc_getc(struct rt_serial_device *serial)
88 {
89     struct lpc_uart *uart;
90 
91     uart = (struct lpc_uart *)serial->parent.user_data;
92     if (uart->UART->LSR & 0x01)
93         return (uart->UART->RBR);
94     else
95         return -1;
96 }
97 
98 static const struct rt_uart_ops lpc_uart_ops =
99 {
100     lpc_configure,
101     lpc_control,
102     lpc_putc,
103     lpc_getc,
104 };
105 
106 #ifdef BSP_USING_UART0
107 
108 struct lpc_uart uart0 =
109 {
110     LPC_UART0,
111     UART0_IRQn,
112 };
113 struct rt_serial_device serial0;
114 
UART0_IRQHandler(void)115 void UART0_IRQHandler(void)
116 {
117     volatile  uint32_t IIR, tmp;
118 
119     /* enter interrupt */
120     rt_interrupt_enter();
121 
122     IIR = LPC_UART0->IIR;
123     IIR &= 0x0e;
124     switch (IIR)
125     {
126     case 0x04:
127     case 0x0C:
128         rt_hw_serial_isr(&serial0, RT_SERIAL_EVENT_RX_IND);
129         break;
130     case 0x06:
131         tmp = LPC_UART0->LSR;
132         break;
133     default :
134         tmp = LPC_UART0->LSR;
135         break;
136     }
137     /* leave interrupt */
138     rt_interrupt_leave();
139 }
140 #endif
141 
142 #ifdef BSP_USING_UART2
143 
144 struct lpc_uart uart2 =
145 {
146     LPC_UART2,
147     UART2_IRQn,
148 };
149 struct rt_serial_device serial2;
150 
UART2_IRQHandler(void)151 void UART2_IRQHandler(void)
152 {
153     volatile  uint32_t IIR, tmp;
154 
155     /* enter interrupt */
156     rt_interrupt_enter();
157 
158     IIR = LPC_UART2->IIR;
159     IIR &= 0x0e;
160     switch (IIR)
161     {
162     case 0x04:
163     case 0x0C:
164         rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND);
165         break;
166     case 0x06:
167         tmp = LPC_UART2->LSR;
168         break;
169     default :
170         tmp = LPC_UART2->LSR;
171         break;
172     }
173 
174     /* leave interrupt */
175     rt_interrupt_leave();
176 }
177 #endif
178 
rt_hw_uart_init(void)179 int rt_hw_uart_init(void)
180 {
181     rt_err_t ret = RT_EOK;
182     struct lpc_uart *uart;
183     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
184 
185 #ifdef BSP_USING_UART0
186     uart = &uart0;
187 
188     serial0.ops    = &lpc_uart_ops;
189     serial0.config = config;
190     serial0.parent.user_data = uart;
191 
192     /*
193      * Initialize UART0 pin connect
194      * P0.2: U0_TXD
195      * P0.3: U0_RXD
196      */
197     LPC_IOCON->P0_2 &= ~0x07;
198     LPC_IOCON->P0_2 |= 0x01;
199     LPC_IOCON->P0_3 &= ~0x07;
200     LPC_IOCON->P0_3 |= 0x01;
201 
202     /* enable the uart0 power and clock */
203     LPC_SC->PCONP |= 0x01 << 3;
204 
205     /* preemption = 1, sub-priority = 1 */
206     NVIC_SetPriority(uart->UART_IRQn, ((0x01 << 3) | 0x01));
207 
208     /* Enable Interrupt for UART channel */
209     NVIC_EnableIRQ(uart->UART_IRQn);
210 
211     /* register UART0 device */
212     ret = rt_hw_serial_register(&serial0, "uart0",
213                                 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
214                                 uart);
215 #endif
216 
217 #ifdef BSP_USING_UART2
218     uart = &uart2;
219 
220     serial2.ops    = &lpc_uart_ops;
221     serial2.config = config;
222     serial2.parent.user_data = uart;
223 
224     /*
225      * Initialize UART2 pin connect
226      * P2.8: U2_TXD
227      * P0.11: U2_RXD
228      */
229     LPC_IOCON->P2_8 &= ~0x07;
230     LPC_IOCON->P0_11 &= ~0x07;
231     LPC_IOCON->P2_8 |= 0x02;
232     LPC_IOCON->P0_11 |= 0x01;
233 
234     /* enable the uart2 power and clock */
235     LPC_SC->PCONP |= 0x01 << 24;
236     /* preemption = 1, sub-priority = 1 */
237     NVIC_SetPriority(uart->UART_IRQn, ((0x01 << 3) | 0x01));
238 
239     /* Enable Interrupt for UART channel */
240     NVIC_EnableIRQ(uart->UART_IRQn);
241 
242     /* register UART2 device */
243     ret = rt_hw_serial_register(&serial2, "uart2",
244                                 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
245                                 uart);
246 #endif
247 
248     return ret;
249 }
250 INIT_BOARD_EXPORT(rt_hw_uart_init);
251 
252 #endif /* RT_USING_SERIAL */
253