1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  * Copyright (c) 2024 sensry.io
4  */
5 
6 #define DT_DRV_COMPAT sensry_sy1xx_uart
7 
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/uart.h>
10 #include <soc.h>
11 #include <zephyr/sys/printk.h>
12 #include <udma.h>
13 #include <pad_ctrl.h>
14 
15 struct sy1xx_uart_config {
16 	uint32_t base;
17 	uint32_t inst;
18 };
19 
20 typedef struct {
21 	uint16_t data_len;
22 	uint8_t *data;
23 } sy1xx_uartTransfer_t;
24 
25 typedef enum {
26 	DRIVERS_UART_STOP_1,
27 	DRIVERS_UART_STOP_1_5,
28 	DRIVERS_UART_STOP_2
29 } sy1xx_uart_stop_t;
30 
31 typedef enum {
32 	DRIVERS_UART_PAR_NONE,
33 	DRIVERS_UART_PAR_EVEN,
34 	DRIVERS_UART_PAR_ODD,
35 	DRIVERS_UART_PAR_MARK,
36 	DRIVERS_UART_PAR_SPACE
37 } sy1xx_uart_parity_t;
38 
39 typedef struct {
40 	uint32_t baudrate;
41 	sy1xx_uart_stop_t stopbits;
42 	sy1xx_uart_parity_t parity;
43 } sy1xx_uartConfig_t;
44 
45 #define DEVICE_MAX_BUFFER_SIZE (512)
46 
47 struct sy1xx_uart_data {
48 	uint8_t write[DEVICE_MAX_BUFFER_SIZE];
49 	uint8_t read[DEVICE_MAX_BUFFER_SIZE];
50 };
51 
52 /* prototypes */
53 static int32_t sy1xx_uart_read(const struct device *dev, sy1xx_uartTransfer_t *request);
54 static int32_t sy1xx_uart_write(const struct device *dev, sy1xx_uartTransfer_t *request);
55 
sy1xx_uart_configure(const struct device * dev,sy1xx_uartConfig_t * uart_cfg)56 static int32_t sy1xx_uart_configure(const struct device *dev, sy1xx_uartConfig_t *uart_cfg)
57 {
58 	struct sy1xx_uart_config *config = (struct sy1xx_uart_config *)dev->config;
59 
60 	if (uart_cfg->baudrate == 0) {
61 		return -1;
62 	}
63 
64 	/*
65 	 * The counter in the UDMA will count from 0 to div included
66 	 * and then will restart from 0, so we must give div - 1 as
67 	 * divider
68 	 */
69 	uint32_t divider = sy1xx_soc_get_peripheral_clock() / uart_cfg->baudrate - 1;
70 
71 	/*
72 	 * [31:16]: clock divider (from SoC clock)
73 	 * [9]: RX enable
74 	 * [8]: TX enable
75 	 * [3]: stop bits  0 = 1 stop bit
76 	 *                 1 = 2 stop bits
77 	 * [2:1]: bits     00 = 5 bits
78 	 *                 01 = 6 bits
79 	 *                 10 = 7 bits
80 	 *                 11 = 8 bits
81 	 * [0]: parity
82 	 */
83 
84 	/* default: both tx and rx enabled; 8N1 configuration; 1 stop bits */
85 	volatile uint32_t setup = 0x0306 | uart_cfg->parity;
86 
87 	setup |= ((divider) << 16);
88 	SY1XX_UDMA_WRITE_REG(config->base, SY1XX_UDMA_SETUP_REG, setup);
89 
90 	/* start initial reading request to get the dma running */
91 	uint8_t dummy_data[10];
92 
93 	sy1xx_uartTransfer_t dummy_request = {
94 		.data_len = 10,
95 		.data = (uint8_t *)dummy_data,
96 	};
97 
98 	sy1xx_uart_read(dev, &dummy_request);
99 	return 0;
100 }
101 
102 /**
103  * @return
104  *  - < 0: Error
105  *  -   0: OK
106  *  - > 0: Busy
107  */
sy1xx_uart_read(const struct device * dev,sy1xx_uartTransfer_t * request)108 int32_t sy1xx_uart_read(const struct device *dev, sy1xx_uartTransfer_t *request)
109 {
110 	struct sy1xx_uart_config *config = (struct sy1xx_uart_config *)dev->config;
111 	struct sy1xx_uart_data *data = (struct sy1xx_uart_data *)dev->data;
112 
113 	if (request == 0) {
114 		return -1;
115 	}
116 
117 	uint32_t max_read_size = request->data_len;
118 
119 	request->data_len = 0;
120 
121 	if (max_read_size > DEVICE_MAX_BUFFER_SIZE) {
122 		return -3;
123 	}
124 
125 	int32_t ret = 0;
126 
127 	/* rx is ready */
128 	int32_t remaining_bytes = SY1XX_UDMA_READ_REG(config->base, SY1XX_UDMA_RX_SIZE_REG);
129 	int32_t bytes_transferred = (DEVICE_MAX_BUFFER_SIZE - remaining_bytes);
130 
131 	if (bytes_transferred > 0) {
132 		/* copy data to the user buffer */
133 		uint32_t copy_len =
134 			bytes_transferred > max_read_size ? max_read_size : bytes_transferred;
135 		for (uint32_t i = 0; i < copy_len; i++) {
136 			request->data[i] = data->read[i];
137 		}
138 
139 		/* update actual read length */
140 		request->data_len = bytes_transferred;
141 
142 		/* stop and restart receiving */
143 		SY1XX_UDMA_CANCEL_RX(config->base);
144 
145 		/* start another read request, with maximum buffer size */
146 		SY1XX_UDMA_START_RX(config->base, (int32_t)data->read, DEVICE_MAX_BUFFER_SIZE, 0);
147 
148 		/* return: some data received */
149 		ret = 0;
150 
151 	} else {
152 		/* return: (busy) stay in receiving mode */
153 		ret = 1;
154 	}
155 
156 	return ret;
157 }
158 
159 /**
160  * @return
161  *  - < 0: Error
162  *  -   0: OK
163  *  - > 0: Busy
164  */
sy1xx_uart_write(const struct device * dev,sy1xx_uartTransfer_t * request)165 int32_t sy1xx_uart_write(const struct device *dev, sy1xx_uartTransfer_t *request)
166 {
167 	struct sy1xx_uart_config *config = (struct sy1xx_uart_config *)dev->config;
168 	struct sy1xx_uart_data *data = (struct sy1xx_uart_data *)dev->data;
169 
170 	if (request == 0) {
171 		return -1;
172 	}
173 
174 	if (request->data_len == 0) {
175 		return -1;
176 	}
177 
178 	if (request->data_len > DEVICE_MAX_BUFFER_SIZE) {
179 		/* more data than possible requested */
180 		return -2;
181 	}
182 
183 	if (0 == SY1XX_UDMA_IS_FINISHED_TX(config->base)) {
184 		/* writing not finished => busy */
185 		return 1;
186 	}
187 
188 	uint32_t remaining_bytes = SY1XX_UDMA_GET_REMAINING_TX(config->base);
189 
190 	if (remaining_bytes != 0) {
191 		SY1XX_UDMA_CANCEL_TX(config->base);
192 		return -3;
193 	}
194 
195 	/* copy the data to transmission buffer */
196 	for (uint32_t i = 0; i < request->data_len; i++) {
197 		data->write[i] = request->data[i];
198 	}
199 
200 	/* start new transmission */
201 	SY1XX_UDMA_START_TX(config->base, (uint32_t)data->write, request->data_len, 0);
202 
203 	/* success */
204 	return 0;
205 }
206 
207 /*
208  * it should be avoided to read single characters only
209  */
sy1xx_uart_poll_in(const struct device * dev,unsigned char * c)210 static int sy1xx_uart_poll_in(const struct device *dev, unsigned char *c)
211 {
212 	sy1xx_uartTransfer_t request = {
213 		.data_len = 1,
214 		.data = c,
215 	};
216 
217 	if (0 == sy1xx_uart_read(dev, &request)) {
218 		return 0;
219 	}
220 
221 	return -1;
222 }
223 
224 /*
225  * it should be avoided to write single characters only
226  */
sy1xx_uart_poll_out(const struct device * dev,unsigned char c)227 static void sy1xx_uart_poll_out(const struct device *dev, unsigned char c)
228 {
229 	sy1xx_uartTransfer_t request = {
230 		.data_len = 1,
231 		.data = &c,
232 	};
233 
234 	while (1) {
235 		if (0 == sy1xx_uart_write(dev, &request)) {
236 			break;
237 		}
238 	}
239 }
240 
sy1xx_uart_err_check(const struct device * dev)241 static int sy1xx_uart_err_check(const struct device *dev)
242 {
243 	int err = 0;
244 
245 	return err;
246 }
247 
sy1xx_uart_init(const struct device * dev)248 static int sy1xx_uart_init(const struct device *dev)
249 {
250 	struct sy1xx_uart_config *config = (struct sy1xx_uart_config *)dev->config;
251 	struct sy1xx_uart_data *data = (struct sy1xx_uart_data *)dev->data;
252 
253 	for (uint32_t i = 0; i < DEVICE_MAX_BUFFER_SIZE; i++) {
254 		data->write[i] = 0xa5;
255 		data->read[i] = 0xb4;
256 	}
257 
258 	/* UDMA clock enable */
259 	sy1xx_udma_enable_clock(SY1XX_UDMA_MODULE_UART, config->inst);
260 
261 	/* PAD config */
262 	uint32_t pad_config_tx =
263 		SY1XX_PAD_CONFIG(0, SY1XX_PAD_SMT_DISABLE, SY1XX_PAD_SLEW_LOW, SY1XX_PAD_PULLUP_DIS,
264 				 SY1XX_PAD_PULLDOWN_DIS, SY1XX_PAD_DRIVE_2PF, SY1XX_PAD_PMOD_NORMAL,
265 				 SY1XX_PAD_DIR_OUTPUT);
266 
267 	uint32_t pad_config_rx =
268 		SY1XX_PAD_CONFIG(8, SY1XX_PAD_SMT_DISABLE, SY1XX_PAD_SLEW_LOW, SY1XX_PAD_PULLUP_DIS,
269 				 SY1XX_PAD_PULLDOWN_DIS, SY1XX_PAD_DRIVE_2PF, SY1XX_PAD_PMOD_NORMAL,
270 				 SY1XX_PAD_DIR_INPUT);
271 
272 	uint32_t pad_config_cts =
273 		SY1XX_PAD_CONFIG(16, SY1XX_PAD_SMT_DISABLE, SY1XX_PAD_SLEW_LOW, SY1XX_PAD_PULLUP_EN,
274 				 SY1XX_PAD_PULLDOWN_DIS, SY1XX_PAD_DRIVE_2PF, SY1XX_PAD_PMOD_NORMAL,
275 				 SY1XX_PAD_DIR_INPUT);
276 
277 	uint32_t pad_config_rts =
278 		SY1XX_PAD_CONFIG(24, SY1XX_PAD_SMT_DISABLE, SY1XX_PAD_SLEW_LOW,
279 				 SY1XX_PAD_PULLUP_DIS, SY1XX_PAD_PULLDOWN_DIS, SY1XX_PAD_DRIVE_2PF,
280 				 SY1XX_PAD_PMOD_NORMAL, SY1XX_PAD_DIR_OUTPUT);
281 
282 	sys_write32((pad_config_tx | pad_config_rx | pad_config_cts | pad_config_rts),
283 		    SY1XX_PAD_CONFIG_ADDR_UART + (config->inst * 4 + 0));
284 
285 	sy1xx_uartConfig_t default_config = {
286 		.baudrate = 1000000,
287 		.parity = DRIVERS_UART_PAR_NONE,
288 		.stopbits = DRIVERS_UART_STOP_1,
289 	};
290 
291 	SY1XX_UDMA_CANCEL_RX(config->base);
292 	SY1XX_UDMA_CANCEL_TX(config->base);
293 
294 	sy1xx_uart_configure(dev, &default_config);
295 
296 	return 0;
297 }
298 
299 static DEVICE_API(uart, sy1xx_uart_driver_api) = {
300 
301 	.poll_in = sy1xx_uart_poll_in,
302 	.poll_out = sy1xx_uart_poll_out,
303 	.err_check = sy1xx_uart_err_check,
304 
305 };
306 
307 #define SYS1XX_UART_INIT(n)                                                                        \
308                                                                                                    \
309 	static const struct sy1xx_uart_config sy1xx_uart_##n##_cfg = {                             \
310 		.base = (uint32_t)DT_INST_REG_ADDR(n),                                             \
311 		.inst = (uint32_t)DT_INST_PROP(n, instance),                                       \
312 	};                                                                                         \
313                                                                                                    \
314 	static struct sy1xx_uart_data __attribute__((section(".udma_access")))                     \
315 	__aligned(4) sy1xx_uart_##n##_data = {                                                     \
316                                                                                                    \
317 	};                                                                                         \
318                                                                                                    \
319 	DEVICE_DT_INST_DEFINE(n, &sy1xx_uart_init, NULL, &sy1xx_uart_##n##_data,                   \
320 			      &sy1xx_uart_##n##_cfg, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY,    \
321 			      &sy1xx_uart_driver_api);
322 
323 DT_INST_FOREACH_STATUS_OKAY(SYS1XX_UART_INIT)
324