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  * 2023-09-26     1ridic       Integrate with RT-Thread driver framework.
9  */
10 
11 #include <rtdevice.h>
12 #include <drv_uart.h>
13 #include <hardware/gpio.h>
14 
15 #ifdef RT_USING_SERIAL
16 
17 #include "hardware/uart.h"
18 #include "hardware/irq.h"
19 
20 #if !defined(BSP_USING_UART0) && !defined(BSP_USING_UART1)
21     #error "Please define at least one BSP_USING_UARTx"
22     /* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
23 #endif
24 
25 #ifdef BSP_USING_UART0
26     void pico_uart0_isr(void);
27 #endif
28 #ifdef BSP_USING_UART1
29     void pico_uart1_isr(void);
30 #endif
31 
32 struct pico_uart_dev
33 {
34     rt_serial_t parent;
35     uart_inst_t *instance;
36     rt_uint32_t irqno;
37     rt_uint32_t tx_pin;
38     rt_uint32_t rx_pin;
39     void (*uart_isr)(void);
40 };
41 
42 static struct pico_uart_dev uart_dev[] =
43 {
44 #ifdef BSP_USING_UART0
45     {
46         .instance = uart0,
47         .irqno = UART0_IRQ,
48         .tx_pin = BSP_UART0_TX_PIN,
49         .rx_pin = BSP_UART0_RX_PIN,
50         .uart_isr = pico_uart0_isr,
51     },
52 #endif
53 #ifdef BSP_USING_UART1
54     {
55         .instance = uart1,
56         .irqno = UART1_IRQ,
57         .tx_pin = BSP_UART1_TX_PIN,
58         .rx_pin = BSP_UART1_RX_PIN,
59         .uart_isr = pico_uart1_isr,
60     },
61 #endif
62 };
63 
64 enum
65 {
66 #ifdef BSP_USING_UART0
67     UART0_INDEX,
68 #endif
69 #ifdef BSP_USING_UART1
70     UART1_INDEX,
71 #endif
72 };
73 
74 #ifdef BSP_USING_UART0
pico_uart0_isr(void)75 void pico_uart0_isr(void)
76 {
77     rt_interrupt_enter();
78     /* read interrupt status and clear it */
79     if (uart_is_readable(uart0)) /* rx ind */
80     {
81         rt_hw_serial_isr(&uart_dev[UART0_INDEX].parent, RT_SERIAL_EVENT_RX_IND);
82     }
83 
84     rt_interrupt_leave();
85 }
86 #endif
87 #ifdef BSP_USING_UART1
pico_uart1_isr(void)88 void pico_uart1_isr(void)
89 {
90     rt_interrupt_enter();
91     /* read interrupt status and clear it */
92     if (uart_is_readable(uart1)) /* rx ind */
93     {
94         rt_hw_serial_isr(&uart_dev[UART1_INDEX].parent, RT_SERIAL_EVENT_RX_IND);
95     }
96 
97     rt_interrupt_leave();
98 }
99 #endif
100 
101 /*
102  * UART interface
103  */
pico_uart_configure(struct rt_serial_device * serial,struct serial_configure * cfg)104 static rt_err_t pico_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
105 {
106     struct pico_uart_dev *uart = RT_NULL;
107     RT_ASSERT(serial != RT_NULL);
108     RT_ASSERT(cfg != RT_NULL);
109     uart = rt_container_of(serial, struct pico_uart_dev, parent);
110 
111     uart_init(uart->instance, cfg->baud_rate);
112 
113     // Set the TX and RX pins by using the function select on the GPIO
114     // Set datasheet for more information on function select
115     gpio_set_function(uart->rx_pin, GPIO_FUNC_UART);
116     gpio_set_function(uart->tx_pin, GPIO_FUNC_UART);
117 
118     // Set UART flow control CTS/RTS
119     if (cfg->flowcontrol == RT_SERIAL_FLOWCONTROL_CTSRTS)
120         uart_set_hw_flow(uart->instance, true, true);
121     else
122         uart_set_hw_flow(uart->instance, false, false);
123 
124     // Set our data format
125     uart_parity_t uart_parity = UART_PARITY_NONE;
126     if (cfg->parity == PARITY_ODD)
127         uart_parity = UART_PARITY_ODD;
128     else if (cfg->parity == PARITY_EVEN)
129         uart_parity = UART_PARITY_EVEN;
130     uart_set_format(uart->instance, cfg->data_bits, cfg->stop_bits, uart_parity);
131 
132     // Turn off FIFO's - we want to do this character by character
133     uart_set_fifo_enabled(uart->instance, false);
134 
135     return RT_EOK;
136 }
137 
pico_uart_control(struct rt_serial_device * serial,int cmd,void * arg)138 static rt_err_t pico_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
139 {
140     struct pico_uart_dev *uart = RT_NULL;
141     RT_ASSERT(serial != RT_NULL);
142     uart = rt_container_of(serial, struct pico_uart_dev, parent);
143 
144     switch (cmd)
145     {
146     /* enable interrupt */
147     case RT_DEVICE_CTRL_SET_INT:
148         // Set up a RX interrupt
149         // We need to set up the handler first
150         // And set up and enable the interrupt handlers
151         irq_set_exclusive_handler(uart->irqno, uart->uart_isr);
152         irq_set_enabled(uart->irqno, true);
153 
154         // Now enable the UART to send interrupts - RX only
155         uart_set_irq_enables(uart->instance, true, false);
156         break;
157     }
158     return RT_EOK;
159 }
160 
pico_uart_putc(struct rt_serial_device * serial,char c)161 static int pico_uart_putc(struct rt_serial_device *serial, char c)
162 {
163     struct pico_uart_dev *uart = RT_NULL;
164     RT_ASSERT(serial != RT_NULL);
165     uart = rt_container_of(serial, struct pico_uart_dev, parent);
166     uart_putc_raw(uart->instance, c);
167 
168     return 1;
169 }
170 
pico_uart_getc(struct rt_serial_device * serial)171 static int pico_uart_getc(struct rt_serial_device *serial)
172 {
173     struct pico_uart_dev *uart = RT_NULL;
174     RT_ASSERT(serial != RT_NULL);
175     uart = rt_container_of(serial, struct pico_uart_dev, parent);
176 
177     int ch;
178 
179     if (uart_is_readable(uart->instance))
180     {
181         ch = uart_get_hw(uart->instance)->dr;
182     }
183     else
184     {
185         ch = -1;
186     }
187 
188     return ch;
189 }
190 
191 const static struct rt_uart_ops _uart_ops =
192 {
193     pico_uart_configure,
194     pico_uart_control,
195     pico_uart_putc,
196     pico_uart_getc,
197     RT_NULL,
198 };
199 
200 /*
201  * UART Initiation
202  */
rt_hw_uart_init(void)203 int rt_hw_uart_init(void)
204 {
205     rt_err_t ret = RT_EOK;
206 
207     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
208 
209 #ifdef BSP_USING_UART0
210     uart_dev[UART0_INDEX].parent.ops = &_uart_ops;
211     uart_dev[UART0_INDEX].parent.config = config;
212 
213     ret = rt_hw_serial_register(&uart_dev[UART0_INDEX].parent,
214                                 "uart0",
215                                 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
216                                 &uart_dev[UART0_INDEX]);
217     RT_ASSERT(ret == RT_EOK);
218 #endif
219 
220 #ifdef BSP_USING_UART1
221     uart_dev[UART1_INDEX].parent.ops = &_uart_ops;
222     uart_dev[UART1_INDEX].parent.config = config;
223 
224     ret = rt_hw_serial_register(&uart_dev[UART1_INDEX].parent,
225                                 "uart1",
226                                 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
227                                 &uart_dev[UART1_INDEX]);
228     RT_ASSERT(ret == RT_EOK);
229 #endif
230 
231     return ret;
232 }
233 
234 
235 #endif /* RT_USING_SERIAL */
236