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