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  * 2019-05-05     jg1uaa       port to LPC1114
10  */
11 #include <stddef.h>
12 #include <rtthread.h>
13 #include <rtdevice.h>
14 #include <rthw.h>
15 #include "board.h"      // CPU_CLOCK
16 #include "drv_uart.h"
17 
18 #ifdef BSP_USING_SERIAL
19 
20 #define UART_BASE       0x40008000              // UART (only one)
21 #define UART_IRQ        21
22 #define UART_CLOCK      (CPU_CLOCK / 1)         // Hz
23 
24 #define URBR            HWREG32(UART_BASE + 0x00)       // R-
25 #define UTHR            HWREG32(UART_BASE + 0x00)       // -W
26 #define UIER            HWREG32(UART_BASE + 0x04)       // RW
27 #define UIIR            HWREG32(UART_BASE + 0x08)       // R-
28 #define UFCR            HWREG32(UART_BASE + 0x08)       // -W
29 #define ULCR            HWREG32(UART_BASE + 0x0c)       // RW
30 #define UMCR            HWREG32(UART_BASE + 0x10)       // RW
31 #define ULSR            HWREG32(UART_BASE + 0x14)       // R-
32 #define UMSR            HWREG32(UART_BASE + 0x18)       // R-
33 
34 #define UDLL            HWREG32(UART_BASE + 0x00)       // RW
35 #define UDLM            HWREG32(UART_BASE + 0x04)       // RW
36 
37 #define IOCONFIG_BASE   0x40044000
38 #define IOCON_PIO1_6    HWREG32(IOCONFIG_BASE + 0xa4)
39 #define IOCON_PIO1_7    HWREG32(IOCONFIG_BASE + 0xa8)
40 
41 #define SYSCON_BASE     0x40048000
42 #define AHBCLKCTRL      HWREG32(SYSCON_BASE + 0x80)
43 #define UARTCLKDIV      HWREG32(SYSCON_BASE + 0x98)
44 
lpc_configure(struct rt_serial_device * serial,struct serial_configure * cfg)45 static rt_err_t lpc_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
46 {
47     rt_uint32_t Fdiv = 0;
48 
49     RT_ASSERT(serial != RT_NULL);
50 
51     /* Initialize UART Configuration parameter structure to default state:
52      * Baudrate = 115200 bps
53      * 8 data bit
54      * 1 Stop bit
55      * None parity
56      */
57     /* set DLAB=1 */
58     ULCR |= 0x80;
59     /* config uart baudrate */
60     Fdiv = UART_CLOCK / (cfg->baud_rate * 16);
61     UDLM = Fdiv / 256;
62     UDLL = Fdiv % 256;
63     /* set DLAB=0 */
64     ULCR &= ~0x80;
65     /* config to 8 data bit,1 Stop bit,None parity */
66     ULCR |= 0x03;
67 
68     /*enable and reset FIFO*/
69     UFCR = 0x07;
70 
71     return RT_EOK;
72 }
73 
lpc_control(struct rt_serial_device * serial,int cmd,void * arg)74 static rt_err_t lpc_control(struct rt_serial_device *serial, int cmd, void *arg)
75 {
76     RT_ASSERT(serial != RT_NULL);
77 
78     switch (cmd)
79     {
80     case RT_DEVICE_CTRL_CLR_INT:
81         /* disable rx irq */
82         UIER &= ~0x01;
83         break;
84     case RT_DEVICE_CTRL_SET_INT:
85         /* enable rx irq */
86         UIER |= 0x01;
87         break;
88     }
89 
90     return RT_EOK;
91 }
92 
lpc_putc(struct rt_serial_device * serial,char c)93 static int lpc_putc(struct rt_serial_device *serial, char c)
94 {
95     while (!(ULSR & 0x20));
96     UTHR = c;
97 
98     return 1;
99 }
100 
lpc_getc(struct rt_serial_device * serial)101 static int lpc_getc(struct rt_serial_device *serial)
102 {
103     if (ULSR & 0x01)
104         return URBR;
105     else
106         return -1;
107 }
108 
109 static const struct rt_uart_ops lpc_uart_ops =
110 {
111     lpc_configure,
112     lpc_control,
113     lpc_putc,
114     lpc_getc,
115 };
116 
117 struct rt_serial_device serial;
118 
UART_IRQHandler(void)119 void UART_IRQHandler(void)
120 {
121     /* enter interrupt */
122     rt_interrupt_enter();
123 
124     switch (UIIR & 0x0e)
125     {
126     case 0x04:
127     case 0x0C:
128         rt_hw_serial_isr(&serial, RT_SERIAL_EVENT_RX_IND);
129         break;
130     case 0x06:
131         (void)ULSR;
132         break;
133     default:
134         (void)ULSR;
135         break;
136     }
137     /* leave interrupt */
138     rt_interrupt_leave();
139 }
140 
rt_hw_uart_init(void)141 int rt_hw_uart_init(void)
142 {
143     rt_err_t ret = RT_EOK;
144     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
145 
146     serial.ops    = &lpc_uart_ops;
147     serial.config = config;
148     serial.parent.user_data = NULL;
149 
150     /*
151      * Initialize UART pin connect
152      * P1.6: U0_RXD
153      * P1.7: U0_TXD
154      */
155     IOCON_PIO1_6 = 0xc1;
156     IOCON_PIO1_7 = 0xc1;
157 
158     /* setup the uart power and clock */
159     UARTCLKDIV = 0x01;          // UART PCLK = system clock / 1
160     AHBCLKCTRL |= (1 << 12);    // UART power-up
161 
162     /* priority = 1 */
163     NVIC_SetPriority(UART_IRQ, 0x01 << 6);
164 
165     /* Enable Interrupt for UART channel */
166     NVIC_EnableIRQ(UART_IRQ);
167 
168     /* register UART device */
169     ret = rt_hw_serial_register(&serial, "uart",
170                                 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
171                                 NULL);
172 
173     return ret;
174 }
175 INIT_BOARD_EXPORT(rt_hw_uart_init);
176 
177 #endif /* BSP_USING_SERIAL */
178