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