1 /*
2  * Copyright (c) 2024 Google LLC.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT wch_usart
7 
8 #include <errno.h>
9 
10 #include <zephyr/drivers/uart.h>
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/irq.h>
14 
15 #include <ch32fun.h>
16 
17 struct usart_wch_config {
18 	USART_TypeDef *regs;
19 	const struct device *clock_dev;
20 	uint32_t current_speed;
21 	uint8_t parity;
22 	uint8_t clock_id;
23 	const struct pinctrl_dev_config *pin_cfg;
24 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
25 	void (*irq_config_func)(const struct device *dev);
26 #endif
27 };
28 
29 struct usart_wch_data {
30 	uart_irq_callback_user_data_t cb;
31 	void *user_data;
32 };
33 
usart_wch_init(const struct device * dev)34 static int usart_wch_init(const struct device *dev)
35 {
36 	const struct usart_wch_config *config = dev->config;
37 	USART_TypeDef *regs = config->regs;
38 	uint32_t ctlr1 = USART_CTLR1_TE | USART_CTLR1_RE | USART_CTLR1_UE;
39 	uint32_t clock_rate;
40 	clock_control_subsys_t clock_sys = (clock_control_subsys_t *)(uintptr_t)config->clock_id;
41 	uint32_t divn;
42 	int err;
43 
44 	clock_control_on(config->clock_dev, clock_sys);
45 
46 	err = clock_control_get_rate(config->clock_dev, clock_sys, &clock_rate);
47 	if (err != 0) {
48 		return err;
49 	}
50 	divn = (clock_rate + config->current_speed / 2) / config->current_speed;
51 
52 	switch (config->parity) {
53 	case UART_CFG_PARITY_NONE:
54 		break;
55 	case UART_CFG_PARITY_ODD:
56 		ctlr1 |= USART_CTLR1_PCE | USART_CTLR1_PS;
57 		break;
58 	case UART_CFG_PARITY_EVEN:
59 		ctlr1 |= USART_CTLR1_PCE;
60 		break;
61 	default:
62 		return -EINVAL;
63 	}
64 
65 	regs->BRR = divn;
66 	regs->CTLR1 = ctlr1;
67 	regs->CTLR2 = 0;
68 	regs->CTLR3 = 0;
69 
70 	err = pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT);
71 	if (err != 0) {
72 		return err;
73 	}
74 
75 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
76 	config->irq_config_func(dev);
77 #endif
78 
79 	return 0;
80 }
81 
usart_wch_poll_in(const struct device * dev,unsigned char * ch)82 static int usart_wch_poll_in(const struct device *dev, unsigned char *ch)
83 {
84 	const struct usart_wch_config *config = dev->config;
85 	USART_TypeDef *regs = config->regs;
86 
87 	if ((regs->STATR & USART_STATR_RXNE) == 0) {
88 		return -1;
89 	}
90 
91 	*ch = regs->DATAR;
92 	return 0;
93 }
94 
usart_wch_poll_out(const struct device * dev,unsigned char ch)95 static void usart_wch_poll_out(const struct device *dev, unsigned char ch)
96 {
97 	const struct usart_wch_config *config = dev->config;
98 	USART_TypeDef *regs = config->regs;
99 
100 	while ((regs->STATR & USART_STATR_TXE) == 0) {
101 	}
102 
103 	regs->DATAR = ch;
104 }
105 
usart_wch_err_check(const struct device * dev)106 static int usart_wch_err_check(const struct device *dev)
107 {
108 	const struct usart_wch_config *config = dev->config;
109 	USART_TypeDef *regs = config->regs;
110 	uint32_t statr = regs->STATR;
111 	enum uart_rx_stop_reason errors = 0;
112 
113 	if ((statr & USART_STATR_PE) != 0) {
114 		errors |= UART_ERROR_PARITY;
115 	}
116 	if ((statr & USART_STATR_LBD) != 0) {
117 		errors |= UART_BREAK;
118 	}
119 	if ((statr & USART_STATR_FE) != 0) {
120 		errors |= UART_ERROR_FRAMING;
121 	}
122 	if ((statr & USART_STATR_NE) != 0) {
123 		errors |= UART_ERROR_NOISE;
124 	}
125 	if ((statr & USART_STATR_ORE) != 0) {
126 		errors |= UART_ERROR_OVERRUN;
127 	}
128 
129 	return errors;
130 }
131 
132 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
133 
usart_wch_isr(const struct device * dev)134 static void usart_wch_isr(const struct device *dev)
135 {
136 	struct usart_wch_data *data = dev->data;
137 
138 	if (data->cb) {
139 		data->cb(dev, data->user_data);
140 	}
141 }
142 
usart_wch_fifo_fill(const struct device * dev,const uint8_t * tx_data,int len)143 static int usart_wch_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len)
144 {
145 	const struct usart_wch_config *config = dev->config;
146 	USART_TypeDef *regs = config->regs;
147 
148 	if (!len || !(regs->STATR & USART_STATR_TXE)) {
149 		return 0;
150 	}
151 
152 	regs->DATAR = tx_data[0];
153 	return 1;
154 }
155 
usart_wch_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)156 static int usart_wch_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
157 {
158 	const struct usart_wch_config *config = dev->config;
159 	USART_TypeDef *regs = config->regs;
160 
161 	if (!size || !(regs->STATR & USART_STATR_RXNE)) {
162 		return 0;
163 	}
164 
165 	rx_data[0] = regs->DATAR;
166 	return 1;
167 }
168 
usart_wch_irq_tx_enable(const struct device * dev)169 static void usart_wch_irq_tx_enable(const struct device *dev)
170 {
171 	const struct usart_wch_config *config = dev->config;
172 	USART_TypeDef *regs = config->regs;
173 
174 	regs->CTLR1 |= (USART_CTLR1_TXEIE | USART_CTLR1_TCIE);
175 }
176 
usart_wch_irq_tx_disable(const struct device * dev)177 static void usart_wch_irq_tx_disable(const struct device *dev)
178 {
179 	const struct usart_wch_config *config = dev->config;
180 	USART_TypeDef *regs = config->regs;
181 
182 	regs->CTLR1 &= ~(USART_CTLR1_TXEIE | USART_CTLR1_TCIE);
183 }
184 
usart_wch_irq_tx_ready(const struct device * dev)185 static int usart_wch_irq_tx_ready(const struct device *dev)
186 {
187 	const struct usart_wch_config *config = dev->config;
188 	USART_TypeDef *regs = config->regs;
189 
190 	return (regs->STATR & USART_STATR_TXE) > 0;
191 }
192 
usart_wch_irq_rx_enable(const struct device * dev)193 static void usart_wch_irq_rx_enable(const struct device *dev)
194 {
195 	const struct usart_wch_config *config = dev->config;
196 	USART_TypeDef *regs = config->regs;
197 
198 	regs->CTLR1 |= USART_CTLR1_RXNEIE;
199 }
200 
usart_wch_irq_rx_disable(const struct device * dev)201 static void usart_wch_irq_rx_disable(const struct device *dev)
202 {
203 	const struct usart_wch_config *config = dev->config;
204 	USART_TypeDef *regs = config->regs;
205 
206 	regs->CTLR1 &= ~USART_CTLR1_RXNEIE;
207 }
208 
usart_wch_irq_tx_complete(const struct device * dev)209 static int usart_wch_irq_tx_complete(const struct device *dev)
210 {
211 	const struct usart_wch_config *config = dev->config;
212 	USART_TypeDef *regs = config->regs;
213 
214 	return (regs->STATR & USART_STATR_TC) > 0;
215 }
216 
usart_wch_irq_rx_ready(const struct device * dev)217 static int usart_wch_irq_rx_ready(const struct device *dev)
218 {
219 	const struct usart_wch_config *config = dev->config;
220 	USART_TypeDef *regs = config->regs;
221 
222 	return (regs->STATR & USART_STATR_RXNE) > 0;
223 }
224 
usart_wch_irq_err_enable(const struct device * dev)225 static void usart_wch_irq_err_enable(const struct device *dev)
226 {
227 	const struct usart_wch_config *config = dev->config;
228 	USART_TypeDef *regs = config->regs;
229 
230 	regs->CTLR1 |= USART_CTLR1_PEIE;
231 	regs->CTLR2 |= USART_CTLR2_LBDIE;
232 	regs->CTLR3 |= USART_CTLR3_EIE;
233 }
234 
usart_wch_irq_err_disable(const struct device * dev)235 static void usart_wch_irq_err_disable(const struct device *dev)
236 {
237 	const struct usart_wch_config *config = dev->config;
238 	USART_TypeDef *regs = config->regs;
239 
240 	regs->CTLR1 &= ~USART_CTLR1_PEIE;
241 	regs->CTLR2 &= ~USART_CTLR2_LBDIE;
242 	regs->CTLR3 &= ~USART_CTLR3_EIE;
243 }
244 
usart_wch_irq_is_pending(const struct device * dev)245 static int usart_wch_irq_is_pending(const struct device *dev)
246 {
247 	const struct usart_wch_config *config = dev->config;
248 	USART_TypeDef *regs = config->regs;
249 	uint16_t ctlr1 = regs->CTLR1;
250 	uint16_t ctlr2 = regs->CTLR2;
251 	uint16_t ctlr3 = regs->CTLR3;
252 	uint16_t statr = regs->STATR;
253 	uint16_t stat_mask = 0;
254 
255 	stat_mask |= (ctlr1 & USART_CTLR1_TXEIE) ? USART_STATR_TXE : 0;
256 	stat_mask |= (ctlr1 & USART_CTLR1_TCIE) ? USART_STATR_TC : 0;
257 	stat_mask |= (ctlr1 & USART_CTLR1_RXNEIE) ? USART_STATR_RXNE | USART_STATR_ORE : 0;
258 	stat_mask |= (ctlr1 & USART_CTLR1_IDLEIE) ? USART_STATR_IDLE : 0;
259 	stat_mask |= (ctlr1 & USART_CTLR1_PEIE) ? USART_STATR_PE : 0;
260 
261 	stat_mask |= (ctlr2 & USART_CTLR2_LBDIE) ? USART_STATR_LBD : 0;
262 	stat_mask |=
263 		(ctlr3 & USART_CTLR3_EIE) ? USART_STATR_NE | USART_STATR_ORE | USART_STATR_FE : 0;
264 	stat_mask |= (ctlr3 & USART_CTLR3_CTSIE) ? USART_STATR_CTS : 0;
265 
266 	return (statr & stat_mask) > 0;
267 }
268 
usart_wch_irq_update(const struct device * dev)269 static int usart_wch_irq_update(const struct device *dev)
270 {
271 	return 1;
272 }
273 
usart_wch_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * user_data)274 static void usart_wch_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
275 				       void *user_data)
276 {
277 	struct usart_wch_data *data = dev->data;
278 
279 	data->cb = cb;
280 	data->user_data = user_data;
281 }
282 #endif /*CONFIG_UART_INTERRUPT_DRIVEN*/
283 
284 static DEVICE_API(uart, usart_wch_driver_api) = {
285 	.poll_in = usart_wch_poll_in,
286 	.poll_out = usart_wch_poll_out,
287 	.err_check = usart_wch_err_check,
288 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
289 	.fifo_fill = usart_wch_fifo_fill,
290 	.fifo_read = usart_wch_fifo_read,
291 	.irq_tx_enable = usart_wch_irq_tx_enable,
292 	.irq_tx_disable = usart_wch_irq_tx_disable,
293 	.irq_tx_ready = usart_wch_irq_tx_ready,
294 	.irq_rx_enable = usart_wch_irq_rx_enable,
295 	.irq_rx_disable = usart_wch_irq_rx_disable,
296 	.irq_tx_complete = usart_wch_irq_tx_complete,
297 	.irq_rx_ready = usart_wch_irq_rx_ready,
298 	.irq_err_enable = usart_wch_irq_err_enable,
299 	.irq_err_disable = usart_wch_irq_err_disable,
300 	.irq_is_pending = usart_wch_irq_is_pending,
301 	.irq_update = usart_wch_irq_update,
302 	.irq_callback_set = usart_wch_irq_callback_set,
303 #endif
304 };
305 
306 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
307 #define USART_WCH_IRQ_HANDLER_DECL(idx)                                                            \
308 	static void usart_wch_irq_config_func_##idx(const struct device *dev);
309 
310 #define USART_WCH_IRQ_HANDLER_FUNC(idx) .irq_config_func = usart_wch_irq_config_func_##idx,
311 
312 #define USART_WCH_IRQ_HANDLER(idx)                                                                 \
313 	static void usart_wch_irq_config_func_##idx(const struct device *dev)                      \
314 	{                                                                                          \
315 		IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), usart_wch_isr,        \
316 			    DEVICE_DT_INST_GET(idx), 0);                                           \
317 		irq_enable(DT_INST_IRQN(idx));                                                     \
318 	}
319 #else
320 #define USART_WCH_IRQ_HANDLER_DECL(idx)
321 #define USART_WCH_IRQ_HANDLER_FUNC(idx)
322 #define USART_WCH_IRQ_HANDLER(idx)
323 #endif
324 
325 #define USART_WCH_INIT(idx)                                                                        \
326 	PINCTRL_DT_INST_DEFINE(idx);                                                               \
327 	USART_WCH_IRQ_HANDLER_DECL(idx)                                                            \
328 	static struct usart_wch_data usart_wch_##idx##_data;                                       \
329 	static const struct usart_wch_config usart_wch_##idx##_config = {                          \
330 		.regs = (USART_TypeDef *)DT_INST_REG_ADDR(idx),                                    \
331 		.current_speed = DT_INST_PROP(idx, current_speed),                                 \
332 		.parity = DT_INST_ENUM_IDX(idx, parity),                                           \
333 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)),                              \
334 		.clock_id = DT_INST_CLOCKS_CELL(idx, id),                                          \
335 		.pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx),                                    \
336 		USART_WCH_IRQ_HANDLER_FUNC(idx)};                                                  \
337 	DEVICE_DT_INST_DEFINE(idx, &usart_wch_init, NULL, &usart_wch_##idx##_data,                 \
338 			      &usart_wch_##idx##_config, PRE_KERNEL_1,                             \
339 			      CONFIG_SERIAL_INIT_PRIORITY, &usart_wch_driver_api);                 \
340 	USART_WCH_IRQ_HANDLER(idx)
341 
342 DT_INST_FOREACH_STATUS_OKAY(USART_WCH_INIT)
343