1 /*
2  * Copyright (c) 2024 GARDENA GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT silabs_si32_usart
8 
9 #include <zephyr/drivers/clock_control.h>
10 #include <zephyr/drivers/uart.h>
11 #include <zephyr/init.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/sys_clock.h>
14 
15 #include <SI32_CLKCTRL_A_Type.h>
16 #include <SI32_USART_A_Type.h>
17 #include <si32_device.h>
18 
19 struct usart_si32_config {
20 	SI32_USART_A_Type *usart;
21 	bool hw_flow_control;
22 	uint8_t parity;
23 #if defined(CONFIG_UART_INTERRUPT_DRIVEN)
24 	uart_irq_config_func_t irq_config_func;
25 #endif
26 	const struct device *clock_dev;
27 };
28 
29 struct usart_si32_data {
30 	uint32_t baud_rate;
31 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
32 	uart_irq_callback_user_data_t callback;
33 	void *cb_data;
34 #endif
35 };
36 
usart_si32_poll_in(const struct device * dev,unsigned char * c)37 static int usart_si32_poll_in(const struct device *dev, unsigned char *c)
38 {
39 	const struct usart_si32_config *config = dev->config;
40 	int ret = -1;
41 
42 	if (SI32_USART_A_read_rx_fifo_count(config->usart) != 0) {
43 		*c = SI32_USART_A_read_data_u8(config->usart);
44 		ret = 0;
45 	}
46 
47 	return ret;
48 }
49 
usart_si32_poll_out(const struct device * dev,unsigned char c)50 static void usart_si32_poll_out(const struct device *dev, unsigned char c)
51 {
52 	const struct usart_si32_config *config = dev->config;
53 
54 	while (SI32_USART_A_read_tx_fifo_count(config->usart) ||
55 	       SI32_USART_A_is_tx_busy(config->usart)) {
56 		/* busy wait */
57 	}
58 
59 	SI32_USART_A_write_data_u8(config->usart, c);
60 }
61 
usart_si32_err_check(const struct device * dev)62 static int usart_si32_err_check(const struct device *dev)
63 {
64 	const struct usart_si32_config *config = dev->config;
65 	int ret = 0;
66 
67 	if (SI32_USART_A_is_tx_fifo_error_interrupt_pending(config->usart)) {
68 		SI32_USART_A_clear_tx_fifo_error_interrupt(config->usart);
69 	}
70 
71 	if (SI32_USART_A_is_rx_overrun_interrupt_pending(config->usart)) {
72 		SI32_USART_A_clear_rx_overrun_error_interrupt(config->usart);
73 		ret |= UART_ERROR_OVERRUN;
74 	}
75 
76 	if (SI32_USART_A_is_rx_parity_error_interrupt_pending(config->usart)) {
77 		SI32_USART_A_clear_rx_parity_error_interrupt(config->usart);
78 		ret |= UART_ERROR_PARITY;
79 	}
80 
81 	if (SI32_USART_A_is_rx_frame_error_interrupt_pending(config->usart)) {
82 		SI32_USART_A_clear_rx_frame_error_interrupt(config->usart);
83 		ret |= UART_ERROR_FRAMING;
84 	}
85 
86 	return ret;
87 }
88 
89 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
usart_si32_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)90 static int usart_si32_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
91 {
92 	const struct usart_si32_config *config = dev->config;
93 	int i;
94 
95 	/* NOTE: Checking `SI32_USART_A_is_tx_busy` is a workaround.
96 	 *       For some reason data gets corrupted when writing to the FIFO
97 	 *       while a write is happening.
98 	 */
99 	for (i = 0; i < size && SI32_USART_A_read_tx_fifo_count(config->usart) == 0 &&
100 		    !SI32_USART_A_is_tx_busy(config->usart);
101 	     i++) {
102 		SI32_USART_A_write_data_u8(config->usart, tx_data[i]);
103 	}
104 
105 	return i;
106 }
107 
usart_si32_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)108 static int usart_si32_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
109 {
110 	const struct usart_si32_config *config = dev->config;
111 	int i;
112 
113 	for (i = 0; i < size; i++) {
114 		if (!SI32_USART_A_read_rx_fifo_count(config->usart)) {
115 			break;
116 		}
117 
118 		rx_data[i] = SI32_USART_A_read_data_u8(config->usart);
119 	}
120 
121 	return i;
122 }
123 
usart_si32_irq_tx_enable(const struct device * dev)124 static void usart_si32_irq_tx_enable(const struct device *dev)
125 {
126 	const struct usart_si32_config *config = dev->config;
127 
128 	SI32_USART_A_enable_tx_data_request_interrupt(config->usart);
129 }
130 
usart_si32_irq_tx_disable(const struct device * dev)131 static void usart_si32_irq_tx_disable(const struct device *dev)
132 {
133 	const struct usart_si32_config *config = dev->config;
134 
135 	SI32_USART_A_disable_tx_data_request_interrupt(config->usart);
136 }
137 
usart_si32_irq_tx_ready(const struct device * dev)138 static int usart_si32_irq_tx_ready(const struct device *dev)
139 {
140 	const struct usart_si32_config *config = dev->config;
141 
142 	return SI32_USART_A_is_tx_data_request_interrupt_pending(config->usart);
143 }
144 
usart_si32_irq_tx_complete(const struct device * dev)145 static int usart_si32_irq_tx_complete(const struct device *dev)
146 {
147 	const struct usart_si32_config *config = dev->config;
148 
149 	return SI32_USART_A_is_tx_complete(config->usart);
150 }
151 
usart_si32_irq_rx_enable(const struct device * dev)152 static void usart_si32_irq_rx_enable(const struct device *dev)
153 {
154 	const struct usart_si32_config *config = dev->config;
155 
156 	SI32_USART_A_enable_rx_data_request_interrupt(config->usart);
157 }
158 
usart_si32_irq_rx_disable(const struct device * dev)159 static void usart_si32_irq_rx_disable(const struct device *dev)
160 {
161 	const struct usart_si32_config *config = dev->config;
162 
163 	SI32_USART_A_disable_rx_data_request_interrupt(config->usart);
164 }
165 
usart_si32_irq_rx_ready(const struct device * dev)166 static int usart_si32_irq_rx_ready(const struct device *dev)
167 {
168 	const struct usart_si32_config *config = dev->config;
169 
170 	return SI32_USART_A_is_rx_data_request_interrupt_pending(config->usart);
171 }
172 
usart_si32_irq_err_enable(const struct device * dev)173 static void usart_si32_irq_err_enable(const struct device *dev)
174 {
175 	const struct usart_si32_config *config = dev->config;
176 
177 	SI32_USART_A_enable_rx_error_interrupts(config->usart);
178 	SI32_USART_A_enable_tx_error_interrupts(config->usart);
179 }
180 
usart_si32_irq_err_disable(const struct device * dev)181 static void usart_si32_irq_err_disable(const struct device *dev)
182 {
183 	const struct usart_si32_config *config = dev->config;
184 
185 	SI32_USART_A_disable_rx_error_interrupts(config->usart);
186 	SI32_USART_A_disable_tx_error_interrupts(config->usart);
187 }
188 
usart_si32_irq_is_pending(const struct device * dev)189 static int usart_si32_irq_is_pending(const struct device *dev)
190 {
191 	return usart_si32_irq_rx_ready(dev) || usart_si32_irq_tx_ready(dev);
192 }
193 
usart_si32_irq_update(const struct device * dev)194 static int usart_si32_irq_update(const struct device *dev)
195 {
196 	ARG_UNUSED(dev);
197 
198 	return 1;
199 }
200 
usart_si32_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)201 static void usart_si32_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
202 					void *cb_data)
203 {
204 	struct usart_si32_data *data = dev->data;
205 
206 	data->callback = cb;
207 	data->cb_data = cb_data;
208 }
209 
usart_si32_irq_handler(const struct device * dev)210 static void usart_si32_irq_handler(const struct device *dev)
211 {
212 	struct usart_si32_data *data = dev->data;
213 
214 	if (data->callback) {
215 		data->callback(dev, data->cb_data);
216 	}
217 
218 	usart_si32_err_check(dev);
219 }
220 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
221 
222 static DEVICE_API(uart, usart_si32_driver_api) = {
223 	.poll_in = usart_si32_poll_in,
224 	.poll_out = usart_si32_poll_out,
225 	.err_check = usart_si32_err_check,
226 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
227 	.fifo_fill = usart_si32_fifo_fill,
228 	.fifo_read = usart_si32_fifo_read,
229 	.irq_tx_enable = usart_si32_irq_tx_enable,
230 	.irq_tx_disable = usart_si32_irq_tx_disable,
231 	.irq_tx_ready = usart_si32_irq_tx_ready,
232 	.irq_tx_complete = usart_si32_irq_tx_complete,
233 	.irq_rx_enable = usart_si32_irq_rx_enable,
234 	.irq_rx_disable = usart_si32_irq_rx_disable,
235 	.irq_rx_ready = usart_si32_irq_rx_ready,
236 	.irq_err_enable = usart_si32_irq_err_enable,
237 	.irq_err_disable = usart_si32_irq_err_disable,
238 	.irq_is_pending = usart_si32_irq_is_pending,
239 	.irq_update = usart_si32_irq_update,
240 	.irq_callback_set = usart_si32_irq_callback_set,
241 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
242 };
243 
usart_si32_init(const struct device * dev)244 static int usart_si32_init(const struct device *dev)
245 {
246 	const struct usart_si32_config *config = dev->config;
247 	struct usart_si32_data *data = dev->data;
248 	uint32_t apb_freq;
249 	uint32_t baud_register_value;
250 	int ret;
251 	enum SI32_USART_A_PARITY_Enum parity = SI32_USART_A_PARITY_ODD;
252 	bool parity_enabled;
253 
254 	if (!device_is_ready(config->clock_dev)) {
255 		return -ENODEV;
256 	}
257 
258 	ret = clock_control_get_rate(config->clock_dev, NULL, &apb_freq);
259 	if (ret) {
260 		return ret;
261 	}
262 
263 	switch (config->parity) {
264 	case UART_CFG_PARITY_NONE:
265 		parity_enabled = false;
266 		break;
267 	case UART_CFG_PARITY_ODD:
268 		parity = SI32_USART_A_PARITY_ODD;
269 		parity_enabled = true;
270 		break;
271 	case UART_CFG_PARITY_EVEN:
272 		parity = SI32_USART_A_PARITY_EVEN;
273 		parity_enabled = true;
274 		break;
275 	case UART_CFG_PARITY_MARK:
276 		parity = SI32_USART_A_PARITY_SET;
277 		parity_enabled = true;
278 		break;
279 	case UART_CFG_PARITY_SPACE:
280 		parity = SI32_USART_A_PARITY_CLEAR;
281 		parity_enabled = true;
282 		break;
283 	default:
284 		return -ENOTSUP;
285 	}
286 
287 	if (config->usart == SI32_USART_0) {
288 		SI32_CLKCTRL_A_enable_apb_to_modules_0(SI32_CLKCTRL_0,
289 						       SI32_CLKCTRL_A_APBCLKG0_USART0);
290 	} else if (config->usart == SI32_USART_1) {
291 		SI32_CLKCTRL_A_enable_apb_to_modules_0(SI32_CLKCTRL_0,
292 						       SI32_CLKCTRL_A_APBCLKG0_USART1);
293 	} else {
294 		return -ENOTSUP;
295 	}
296 
297 	baud_register_value = (apb_freq / (2 * data->baud_rate)) - 1;
298 
299 	SI32_USART_A_exit_loopback_mode(config->usart);
300 
301 	if (config->hw_flow_control) {
302 		SI32_USART_A_enable_rts(config->usart);
303 		SI32_USART_A_select_rts_deassert_on_byte_free(config->usart);
304 		SI32_USART_A_disable_rts_inversion(config->usart);
305 
306 		SI32_USART_A_enable_cts(config->usart);
307 		SI32_USART_A_disable_cts_inversion(config->usart);
308 	}
309 
310 	/* Transmitter */
311 	if (parity_enabled) {
312 		SI32_USART_A_select_tx_parity(config->usart, parity);
313 		SI32_USART_A_enable_tx_parity_bit(config->usart);
314 	} else {
315 		SI32_USART_A_disable_tx_parity_bit(config->usart);
316 	}
317 	SI32_USART_A_select_tx_data_length(config->usart, SI32_USART_A_DATA_LENGTH_8_BITS);
318 	SI32_USART_A_enable_tx_start_bit(config->usart);
319 	SI32_USART_A_enable_tx_stop_bit(config->usart);
320 	SI32_USART_A_select_tx_stop_bits(config->usart, SI32_USART_A_STOP_BITS_1_BIT);
321 	SI32_USART_A_set_tx_baudrate(config->usart, (uint16_t)baud_register_value);
322 	SI32_USART_A_select_tx_asynchronous_mode(config->usart);
323 	SI32_USART_A_disable_tx_signal_inversion(config->usart);
324 	SI32_USART_A_select_tx_fifo_threshold_for_request_to_1(config->usart);
325 	SI32_USART_A_enable_tx(config->usart);
326 
327 	/* Receiver */
328 	if (parity_enabled) {
329 		SI32_USART_A_select_rx_parity(config->usart, parity);
330 		SI32_USART_A_enable_rx_parity_bit(config->usart);
331 	} else {
332 		SI32_USART_A_disable_rx_parity_bit(config->usart);
333 	}
334 	SI32_USART_A_select_rx_data_length(config->usart, SI32_USART_A_DATA_LENGTH_8_BITS);
335 	SI32_USART_A_enable_rx_start_bit(config->usart);
336 	SI32_USART_A_enable_rx_stop_bit(config->usart);
337 	SI32_USART_A_select_rx_stop_bits(config->usart, SI32_USART_A_STOP_BITS_1_BIT);
338 	SI32_USART_A_set_rx_baudrate(config->usart, (uint16_t)baud_register_value);
339 	SI32_USART_A_select_rx_asynchronous_mode(config->usart);
340 	SI32_USART_A_disable_rx_signal_inversion(config->usart);
341 	SI32_USART_A_select_rx_fifo_threshold_1(config->usart);
342 	SI32_USART_A_enable_rx(config->usart);
343 
344 	SI32_USART_A_flush_tx_fifo(config->usart);
345 	SI32_USART_A_flush_rx_fifo(config->usart);
346 
347 #if defined(CONFIG_UART_INTERRUPT_DRIVEN)
348 	config->irq_config_func(dev);
349 #endif
350 
351 	return 0;
352 }
353 
354 #if defined(CONFIG_UART_INTERRUPT_DRIVEN)
355 #define SI32_USART_IRQ_HANDLER_DECL(index)                                                         \
356 	static void usart_si32_irq_config_func_##index(const struct device *dev);
357 #define SI32_USART_IRQ_HANDLER(index)                                                              \
358 	static void usart_si32_irq_config_func_##index(const struct device *dev)                   \
359 	{                                                                                          \
360 		IRQ_CONNECT(DT_INST_IRQN(index), DT_INST_IRQ(index, priority),                     \
361 			    usart_si32_irq_handler, DEVICE_DT_INST_GET(index), 0);                 \
362 		irq_enable(DT_INST_IRQN(index));                                                   \
363 	}
364 #else
365 #define SI32_USART_IRQ_HANDLER_DECL(index) /* Not used */
366 #define SI32_USART_IRQ_HANDLER(index)      /* Not used */
367 #endif
368 
369 #if defined(CONFIG_UART_INTERRUPT_DRIVEN)
370 #define SI32_USART_IRQ_HANDLER_FUNC(index) .irq_config_func = usart_si32_irq_config_func_##index,
371 #else
372 #define SI32_USART_IRQ_HANDLER_FUNC(index) /* Not used */
373 #endif
374 
375 #define SI32_USART_INIT(index)                                                                     \
376 	SI32_USART_IRQ_HANDLER_DECL(index)                                                         \
377                                                                                                    \
378 	static const struct usart_si32_config usart_si32_cfg_##index = {                           \
379 		.usart = (SI32_USART_A_Type *)DT_INST_REG_ADDR(index),                             \
380 		.hw_flow_control = DT_INST_PROP(index, hw_flow_control),                           \
381 		.parity = DT_INST_ENUM_IDX_OR(index, parity, UART_CFG_PARITY_NONE),                \
382 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(index)),                            \
383 		SI32_USART_IRQ_HANDLER_FUNC(index)};                                               \
384                                                                                                    \
385 	static struct usart_si32_data usart_si32_data_##index = {                                  \
386 		.baud_rate = DT_INST_PROP(index, current_speed),                                   \
387 	};                                                                                         \
388                                                                                                    \
389 	DEVICE_DT_INST_DEFINE(index, &usart_si32_init, NULL, &usart_si32_data_##index,             \
390 			      &usart_si32_cfg_##index, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY,  \
391 			      &usart_si32_driver_api);                                             \
392                                                                                                    \
393 	SI32_USART_IRQ_HANDLER(index)
394 
395 DT_INST_FOREACH_STATUS_OKAY(SI32_USART_INIT)
396