xref: /linux/drivers/tty/serial/milbeaut_usio.c (revision 44f57d78)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 Socionext Inc.
4  */
5 
6 #if defined(CONFIG_SERIAL_MILBEAUT_USIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
7 #define SUPPORT_SYSRQ
8 #endif
9 
10 #include <linux/clk.h>
11 #include <linux/console.h>
12 #include <linux/module.h>
13 #include <linux/of_irq.h>
14 #include <linux/platform_device.h>
15 #include <linux/serial_core.h>
16 #include <linux/tty.h>
17 #include <linux/tty_flip.h>
18 
19 #define USIO_NAME		"mlb-usio-uart"
20 #define USIO_UART_DEV_NAME	"ttyUSI"
21 
22 static struct uart_port mlb_usio_ports[CONFIG_SERIAL_MILBEAUT_USIO_PORTS];
23 
24 #define RX	0
25 #define TX	1
26 static int mlb_usio_irq[CONFIG_SERIAL_MILBEAUT_USIO_PORTS][2];
27 
28 #define MLB_USIO_REG_SMR		0
29 #define MLB_USIO_REG_SCR		1
30 #define MLB_USIO_REG_ESCR		2
31 #define MLB_USIO_REG_SSR		3
32 #define MLB_USIO_REG_DR			4
33 #define MLB_USIO_REG_BGR		6
34 #define MLB_USIO_REG_FCR		12
35 #define MLB_USIO_REG_FBYTE		14
36 
37 #define MLB_USIO_SMR_SOE		BIT(0)
38 #define MLB_USIO_SMR_SBL		BIT(3)
39 #define MLB_USIO_SCR_TXE		BIT(0)
40 #define MLB_USIO_SCR_RXE		BIT(1)
41 #define MLB_USIO_SCR_TBIE		BIT(2)
42 #define MLB_USIO_SCR_TIE		BIT(3)
43 #define MLB_USIO_SCR_RIE		BIT(4)
44 #define MLB_USIO_SCR_UPCL		BIT(7)
45 #define MLB_USIO_ESCR_L_8BIT		0
46 #define MLB_USIO_ESCR_L_5BIT		1
47 #define MLB_USIO_ESCR_L_6BIT		2
48 #define MLB_USIO_ESCR_L_7BIT		3
49 #define MLB_USIO_ESCR_P			BIT(3)
50 #define MLB_USIO_ESCR_PEN		BIT(4)
51 #define MLB_USIO_ESCR_FLWEN		BIT(7)
52 #define MLB_USIO_SSR_TBI		BIT(0)
53 #define MLB_USIO_SSR_TDRE		BIT(1)
54 #define MLB_USIO_SSR_RDRF		BIT(2)
55 #define MLB_USIO_SSR_ORE		BIT(3)
56 #define MLB_USIO_SSR_FRE		BIT(4)
57 #define MLB_USIO_SSR_PE			BIT(5)
58 #define MLB_USIO_SSR_REC		BIT(7)
59 #define MLB_USIO_SSR_BRK		BIT(8)
60 #define MLB_USIO_FCR_FE1		BIT(0)
61 #define MLB_USIO_FCR_FE2		BIT(1)
62 #define MLB_USIO_FCR_FCL1		BIT(2)
63 #define MLB_USIO_FCR_FCL2		BIT(3)
64 #define MLB_USIO_FCR_FSET		BIT(4)
65 #define MLB_USIO_FCR_FTIE		BIT(9)
66 #define MLB_USIO_FCR_FDRQ		BIT(10)
67 #define MLB_USIO_FCR_FRIIE		BIT(11)
68 
69 static void mlb_usio_stop_tx(struct uart_port *port)
70 {
71 	writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FTIE,
72 	       port->membase + MLB_USIO_REG_FCR);
73 	writeb(readb(port->membase + MLB_USIO_REG_SCR) & ~MLB_USIO_SCR_TBIE,
74 	       port->membase + MLB_USIO_REG_SCR);
75 }
76 
77 static void mlb_usio_tx_chars(struct uart_port *port)
78 {
79 	struct circ_buf *xmit = &port->state->xmit;
80 	int count;
81 
82 	writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FTIE,
83 	       port->membase + MLB_USIO_REG_FCR);
84 	writeb(readb(port->membase + MLB_USIO_REG_SCR) &
85 	       ~(MLB_USIO_SCR_TIE | MLB_USIO_SCR_TBIE),
86 	       port->membase + MLB_USIO_REG_SCR);
87 
88 	if (port->x_char) {
89 		writew(port->x_char, port->membase + MLB_USIO_REG_DR);
90 		port->icount.tx++;
91 		port->x_char = 0;
92 		return;
93 	}
94 	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
95 		mlb_usio_stop_tx(port);
96 		return;
97 	}
98 
99 	count = port->fifosize -
100 		(readw(port->membase + MLB_USIO_REG_FBYTE) & 0xff);
101 
102 	do {
103 		writew(xmit->buf[xmit->tail], port->membase + MLB_USIO_REG_DR);
104 
105 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
106 		port->icount.tx++;
107 		if (uart_circ_empty(xmit))
108 			break;
109 
110 	} while (--count > 0);
111 
112 	writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FDRQ,
113 	       port->membase + MLB_USIO_REG_FCR);
114 
115 	writeb(readb(port->membase + MLB_USIO_REG_SCR) | MLB_USIO_SCR_TBIE,
116 	       port->membase + MLB_USIO_REG_SCR);
117 
118 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
119 		uart_write_wakeup(port);
120 
121 	if (uart_circ_empty(xmit))
122 		mlb_usio_stop_tx(port);
123 }
124 
125 static void mlb_usio_start_tx(struct uart_port *port)
126 {
127 	u16 fcr = readw(port->membase + MLB_USIO_REG_FCR);
128 
129 	writew(fcr | MLB_USIO_FCR_FTIE, port->membase + MLB_USIO_REG_FCR);
130 	if (!(fcr & MLB_USIO_FCR_FDRQ))
131 		return;
132 
133 	writeb(readb(port->membase + MLB_USIO_REG_SCR) | MLB_USIO_SCR_TBIE,
134 	       port->membase + MLB_USIO_REG_SCR);
135 
136 	if (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI)
137 		mlb_usio_tx_chars(port);
138 }
139 
140 static void mlb_usio_stop_rx(struct uart_port *port)
141 {
142 	writeb(readb(port->membase + MLB_USIO_REG_SCR) & ~MLB_USIO_SCR_RIE,
143 	       port->membase + MLB_USIO_REG_SCR);
144 }
145 
146 static void mlb_usio_enable_ms(struct uart_port *port)
147 {
148 	writeb(readb(port->membase + MLB_USIO_REG_SCR) |
149 	       MLB_USIO_SCR_RIE | MLB_USIO_SCR_RXE,
150 	       port->membase + MLB_USIO_REG_SCR);
151 }
152 
153 static void mlb_usio_rx_chars(struct uart_port *port)
154 {
155 	struct tty_port *ttyport = &port->state->port;
156 	unsigned long flag = 0;
157 	char ch = 0;
158 	u8 status;
159 	int max_count = 2;
160 
161 	while (max_count--) {
162 		status = readb(port->membase + MLB_USIO_REG_SSR);
163 
164 		if (!(status & MLB_USIO_SSR_RDRF))
165 			break;
166 
167 		if (!(status & (MLB_USIO_SSR_ORE | MLB_USIO_SSR_FRE |
168 				MLB_USIO_SSR_PE))) {
169 			ch = readw(port->membase + MLB_USIO_REG_DR);
170 			flag = TTY_NORMAL;
171 			port->icount.rx++;
172 			if (uart_handle_sysrq_char(port, ch))
173 				continue;
174 			uart_insert_char(port, status, MLB_USIO_SSR_ORE,
175 					 ch, flag);
176 			continue;
177 		}
178 		if (status & MLB_USIO_SSR_PE)
179 			port->icount.parity++;
180 		if (status & MLB_USIO_SSR_ORE)
181 			port->icount.overrun++;
182 		status &= port->read_status_mask;
183 		if (status & MLB_USIO_SSR_BRK) {
184 			flag = TTY_BREAK;
185 			ch = 0;
186 		} else
187 			if (status & MLB_USIO_SSR_PE) {
188 				flag = TTY_PARITY;
189 				ch = 0;
190 			} else
191 				if (status & MLB_USIO_SSR_FRE) {
192 					flag = TTY_FRAME;
193 					ch = 0;
194 				}
195 		if (flag)
196 			uart_insert_char(port, status, MLB_USIO_SSR_ORE,
197 					 ch, flag);
198 
199 		writeb(readb(port->membase + MLB_USIO_REG_SSR) |
200 				MLB_USIO_SSR_REC,
201 				port->membase + MLB_USIO_REG_SSR);
202 
203 		max_count = readw(port->membase + MLB_USIO_REG_FBYTE) >> 8;
204 		writew(readw(port->membase + MLB_USIO_REG_FCR) |
205 		       MLB_USIO_FCR_FE2 | MLB_USIO_FCR_FRIIE,
206 		port->membase + MLB_USIO_REG_FCR);
207 	}
208 
209 	tty_flip_buffer_push(ttyport);
210 }
211 
212 static irqreturn_t mlb_usio_rx_irq(int irq, void *dev_id)
213 {
214 	struct uart_port *port = dev_id;
215 
216 	spin_lock(&port->lock);
217 	mlb_usio_rx_chars(port);
218 	spin_unlock(&port->lock);
219 
220 	return IRQ_HANDLED;
221 }
222 
223 static irqreturn_t mlb_usio_tx_irq(int irq, void *dev_id)
224 {
225 	struct uart_port *port = dev_id;
226 
227 	spin_lock(&port->lock);
228 	if (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI)
229 		mlb_usio_tx_chars(port);
230 	spin_unlock(&port->lock);
231 
232 	return IRQ_HANDLED;
233 }
234 
235 static unsigned int mlb_usio_tx_empty(struct uart_port *port)
236 {
237 	return (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI) ?
238 		TIOCSER_TEMT : 0;
239 }
240 
241 static void mlb_usio_set_mctrl(struct uart_port *port, unsigned int mctrl)
242 {
243 }
244 
245 static unsigned int mlb_usio_get_mctrl(struct uart_port *port)
246 {
247 	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
248 
249 }
250 
251 static void mlb_usio_break_ctl(struct uart_port *port, int break_state)
252 {
253 }
254 
255 static int mlb_usio_startup(struct uart_port *port)
256 {
257 	const char *portname = to_platform_device(port->dev)->name;
258 	unsigned long flags;
259 	int ret, index = port->line;
260 	unsigned char  escr;
261 
262 	ret = request_irq(mlb_usio_irq[index][RX], mlb_usio_rx_irq,
263 				0, portname, port);
264 	if (ret)
265 		return ret;
266 	ret = request_irq(mlb_usio_irq[index][TX], mlb_usio_tx_irq,
267 				0, portname, port);
268 	if (ret) {
269 		free_irq(mlb_usio_irq[index][RX], port);
270 		return ret;
271 	}
272 
273 	escr = readb(port->membase + MLB_USIO_REG_ESCR);
274 	if (of_property_read_bool(port->dev->of_node, "auto-flow-control"))
275 		escr |= MLB_USIO_ESCR_FLWEN;
276 	spin_lock_irqsave(&port->lock, flags);
277 	writeb(0, port->membase + MLB_USIO_REG_SCR);
278 	writeb(escr, port->membase + MLB_USIO_REG_ESCR);
279 	writeb(MLB_USIO_SCR_UPCL, port->membase + MLB_USIO_REG_SCR);
280 	writeb(MLB_USIO_SSR_REC, port->membase + MLB_USIO_REG_SSR);
281 	writew(0, port->membase + MLB_USIO_REG_FCR);
282 	writew(MLB_USIO_FCR_FCL1 | MLB_USIO_FCR_FCL2,
283 	       port->membase + MLB_USIO_REG_FCR);
284 	writew(MLB_USIO_FCR_FE1 | MLB_USIO_FCR_FE2 | MLB_USIO_FCR_FRIIE,
285 	       port->membase + MLB_USIO_REG_FCR);
286 	writew(0, port->membase + MLB_USIO_REG_FBYTE);
287 	writew(BIT(12), port->membase + MLB_USIO_REG_FBYTE);
288 
289 	writeb(MLB_USIO_SCR_TXE  | MLB_USIO_SCR_RIE | MLB_USIO_SCR_TBIE |
290 	       MLB_USIO_SCR_RXE, port->membase + MLB_USIO_REG_SCR);
291 	spin_unlock_irqrestore(&port->lock, flags);
292 
293 	return 0;
294 }
295 
296 static void mlb_usio_shutdown(struct uart_port *port)
297 {
298 	int index = port->line;
299 
300 	free_irq(mlb_usio_irq[index][RX], port);
301 	free_irq(mlb_usio_irq[index][TX], port);
302 }
303 
304 static void mlb_usio_set_termios(struct uart_port *port,
305 			struct ktermios *termios, struct ktermios *old)
306 {
307 	unsigned int escr, smr = MLB_USIO_SMR_SOE;
308 	unsigned long flags, baud, quot;
309 
310 	switch (termios->c_cflag & CSIZE) {
311 	case CS5:
312 		escr = MLB_USIO_ESCR_L_5BIT;
313 		break;
314 	case CS6:
315 		escr = MLB_USIO_ESCR_L_6BIT;
316 		break;
317 	case CS7:
318 		escr = MLB_USIO_ESCR_L_7BIT;
319 		break;
320 	case CS8:
321 	default:
322 		escr = MLB_USIO_ESCR_L_8BIT;
323 		break;
324 	}
325 
326 	if (termios->c_cflag & CSTOPB)
327 		smr |= MLB_USIO_SMR_SBL;
328 
329 	if (termios->c_cflag & PARENB) {
330 		escr |= MLB_USIO_ESCR_PEN;
331 		if (termios->c_cflag & PARODD)
332 			escr |= MLB_USIO_ESCR_P;
333 	}
334 	/* Set hard flow control */
335 	if (of_property_read_bool(port->dev->of_node, "auto-flow-control") ||
336 			(termios->c_cflag & CRTSCTS))
337 		escr |= MLB_USIO_ESCR_FLWEN;
338 
339 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
340 	if (baud > 1)
341 		quot = port->uartclk / baud - 1;
342 	else
343 		quot = 0;
344 
345 	spin_lock_irqsave(&port->lock, flags);
346 	uart_update_timeout(port, termios->c_cflag, baud);
347 	port->read_status_mask = MLB_USIO_SSR_ORE | MLB_USIO_SSR_RDRF |
348 				 MLB_USIO_SSR_TDRE;
349 	if (termios->c_iflag & INPCK)
350 		port->read_status_mask |= MLB_USIO_SSR_FRE | MLB_USIO_SSR_PE;
351 
352 	port->ignore_status_mask = 0;
353 	if (termios->c_iflag & IGNPAR)
354 		port->ignore_status_mask |= MLB_USIO_SSR_FRE | MLB_USIO_SSR_PE;
355 	if ((termios->c_iflag & IGNBRK) && (termios->c_iflag & IGNPAR))
356 		port->ignore_status_mask |= MLB_USIO_SSR_ORE;
357 	if ((termios->c_cflag & CREAD) == 0)
358 		port->ignore_status_mask |= MLB_USIO_SSR_RDRF;
359 
360 	writeb(0, port->membase + MLB_USIO_REG_SCR);
361 	writeb(MLB_USIO_SCR_UPCL, port->membase + MLB_USIO_REG_SCR);
362 	writeb(MLB_USIO_SSR_REC, port->membase + MLB_USIO_REG_SSR);
363 	writew(0, port->membase + MLB_USIO_REG_FCR);
364 	writeb(smr, port->membase + MLB_USIO_REG_SMR);
365 	writeb(escr, port->membase + MLB_USIO_REG_ESCR);
366 	writew(quot, port->membase + MLB_USIO_REG_BGR);
367 	writew(0, port->membase + MLB_USIO_REG_FCR);
368 	writew(MLB_USIO_FCR_FCL1 | MLB_USIO_FCR_FCL2 | MLB_USIO_FCR_FE1 |
369 	       MLB_USIO_FCR_FE2 | MLB_USIO_FCR_FRIIE,
370 	       port->membase + MLB_USIO_REG_FCR);
371 	writew(0, port->membase + MLB_USIO_REG_FBYTE);
372 	writew(BIT(12), port->membase + MLB_USIO_REG_FBYTE);
373 	writeb(MLB_USIO_SCR_RIE | MLB_USIO_SCR_RXE | MLB_USIO_SCR_TBIE |
374 	       MLB_USIO_SCR_TXE, port->membase + MLB_USIO_REG_SCR);
375 	spin_unlock_irqrestore(&port->lock, flags);
376 }
377 
378 static const char *mlb_usio_type(struct uart_port *port)
379 {
380 	return ((port->type == PORT_MLB_USIO) ? USIO_NAME : NULL);
381 }
382 
383 static void mlb_usio_config_port(struct uart_port *port, int flags)
384 {
385 	if (flags & UART_CONFIG_TYPE)
386 		port->type = PORT_MLB_USIO;
387 }
388 
389 static const struct uart_ops mlb_usio_ops = {
390 	.tx_empty	= mlb_usio_tx_empty,
391 	.set_mctrl	= mlb_usio_set_mctrl,
392 	.get_mctrl	= mlb_usio_get_mctrl,
393 	.stop_tx	= mlb_usio_stop_tx,
394 	.start_tx	= mlb_usio_start_tx,
395 	.stop_rx	= mlb_usio_stop_rx,
396 	.enable_ms	= mlb_usio_enable_ms,
397 	.break_ctl	= mlb_usio_break_ctl,
398 	.startup	= mlb_usio_startup,
399 	.shutdown	= mlb_usio_shutdown,
400 	.set_termios	= mlb_usio_set_termios,
401 	.type		= mlb_usio_type,
402 	.config_port	= mlb_usio_config_port,
403 };
404 
405 #ifdef CONFIG_SERIAL_MILBEAUT_USIO_CONSOLE
406 
407 static void mlb_usio_console_putchar(struct uart_port *port, int c)
408 {
409 	while (!(readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TDRE))
410 		cpu_relax();
411 
412 	writew(c, port->membase + MLB_USIO_REG_DR);
413 }
414 
415 static void mlb_usio_console_write(struct console *co, const char *s,
416 			       unsigned int count)
417 {
418 	struct uart_port *port = &mlb_usio_ports[co->index];
419 
420 	uart_console_write(port, s, count, mlb_usio_console_putchar);
421 }
422 
423 static int __init mlb_usio_console_setup(struct console *co, char *options)
424 {
425 	struct uart_port *port;
426 	int baud = 115200;
427 	int parity = 'n';
428 	int flow = 'n';
429 	int bits = 8;
430 
431 	if (co->index >= CONFIG_SERIAL_MILBEAUT_USIO_PORTS)
432 		return -ENODEV;
433 
434 	port = &mlb_usio_ports[co->index];
435 	if (!port->membase)
436 		return -ENODEV;
437 
438 
439 	if (options)
440 		uart_parse_options(options, &baud, &parity, &bits, &flow);
441 
442 	if (of_property_read_bool(port->dev->of_node, "auto-flow-control"))
443 		flow = 'r';
444 
445 	return uart_set_options(port, co, baud, parity, bits, flow);
446 }
447 
448 
449 static struct uart_driver mlb_usio_uart_driver;
450 static struct console mlb_usio_console = {
451 	.name   = USIO_UART_DEV_NAME,
452 	.write  = mlb_usio_console_write,
453 	.device = uart_console_device,
454 	.setup  = mlb_usio_console_setup,
455 	.flags  = CON_PRINTBUFFER,
456 	.index  = -1,
457 	.data   = &mlb_usio_uart_driver,
458 };
459 
460 static int __init mlb_usio_console_init(void)
461 {
462 	register_console(&mlb_usio_console);
463 	return 0;
464 }
465 console_initcall(mlb_usio_console_init);
466 
467 
468 static void mlb_usio_early_console_write(struct console *co, const char *s,
469 					u_int count)
470 {
471 	struct earlycon_device *dev = co->data;
472 
473 	uart_console_write(&dev->port, s, count, mlb_usio_console_putchar);
474 }
475 
476 static int __init mlb_usio_early_console_setup(struct earlycon_device *device,
477 						const char *opt)
478 {
479 	if (!device->port.membase)
480 		return -ENODEV;
481 	device->con->write = mlb_usio_early_console_write;
482 	return 0;
483 }
484 
485 OF_EARLYCON_DECLARE(mlb_usio, "socionext,milbeaut-usio-uart",
486 			mlb_usio_early_console_setup);
487 
488 #define USIO_CONSOLE	(&mlb_usio_console)
489 #else
490 #define USIO_CONSOLE	NULL
491 #endif
492 
493 static struct  uart_driver mlb_usio_uart_driver = {
494 	.owner		= THIS_MODULE,
495 	.driver_name	= USIO_NAME,
496 	.dev_name	= USIO_UART_DEV_NAME,
497 	.cons           = USIO_CONSOLE,
498 	.nr		= CONFIG_SERIAL_MILBEAUT_USIO_PORTS,
499 };
500 
501 static int mlb_usio_probe(struct platform_device *pdev)
502 {
503 	struct clk *clk = devm_clk_get(&pdev->dev, NULL);
504 	struct uart_port *port;
505 	struct resource *res;
506 	int index = 0;
507 	int ret;
508 
509 	if (IS_ERR(clk)) {
510 		dev_err(&pdev->dev, "Missing clock\n");
511 		return PTR_ERR(clk);
512 	}
513 	ret = clk_prepare_enable(clk);
514 	if (ret) {
515 		dev_err(&pdev->dev, "Clock enable failed: %d\n", ret);
516 		return ret;
517 	}
518 	of_property_read_u32(pdev->dev.of_node, "index", &index);
519 	port = &mlb_usio_ports[index];
520 
521 	port->private_data = (void *)clk;
522 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
523 	if (res == NULL) {
524 		dev_err(&pdev->dev, "Missing regs\n");
525 		ret = -ENODEV;
526 		goto failed;
527 	}
528 	port->membase = devm_ioremap(&pdev->dev, res->start,
529 				resource_size(res));
530 
531 	ret = platform_get_irq_byname(pdev, "rx");
532 	mlb_usio_irq[index][RX] = ret;
533 
534 	ret = platform_get_irq_byname(pdev, "tx");
535 	mlb_usio_irq[index][TX] = ret;
536 
537 	port->irq = mlb_usio_irq[index][RX];
538 	port->uartclk = clk_get_rate(clk);
539 	port->fifosize = 128;
540 	port->iotype = UPIO_MEM32;
541 	port->flags = UPF_BOOT_AUTOCONF | UPF_SPD_VHI;
542 	port->line = index;
543 	port->ops = &mlb_usio_ops;
544 	port->dev = &pdev->dev;
545 
546 	ret = uart_add_one_port(&mlb_usio_uart_driver, port);
547 	if (ret) {
548 		dev_err(&pdev->dev, "Adding port failed: %d\n", ret);
549 		goto failed;
550 	}
551 	return 0;
552 
553 failed:
554 	clk_disable_unprepare(clk);
555 
556 	return ret;
557 }
558 
559 static int mlb_usio_remove(struct platform_device *pdev)
560 {
561 	struct uart_port *port = &mlb_usio_ports[pdev->id];
562 	struct clk *clk = port->private_data;
563 
564 	uart_remove_one_port(&mlb_usio_uart_driver, port);
565 	clk_disable_unprepare(clk);
566 
567 	return 0;
568 }
569 
570 static const struct of_device_id mlb_usio_dt_ids[] = {
571 	{ .compatible = "socionext,milbeaut-usio-uart" },
572 	{ /* sentinel */ }
573 };
574 MODULE_DEVICE_TABLE(of, mlb_usio_dt_ids);
575 
576 static struct platform_driver mlb_usio_driver = {
577 	.probe          = mlb_usio_probe,
578 	.remove         = mlb_usio_remove,
579 	.driver         = {
580 		.name   = USIO_NAME,
581 		.of_match_table = mlb_usio_dt_ids,
582 	},
583 };
584 
585 static int __init mlb_usio_init(void)
586 {
587 	int ret = uart_register_driver(&mlb_usio_uart_driver);
588 
589 	if (ret) {
590 		pr_err("%s: uart registration failed: %d\n", __func__, ret);
591 		return ret;
592 	}
593 	ret = platform_driver_register(&mlb_usio_driver);
594 	if (ret) {
595 		uart_unregister_driver(&mlb_usio_uart_driver);
596 		pr_err("%s: drv registration failed: %d\n", __func__, ret);
597 		return ret;
598 	}
599 
600 	return 0;
601 }
602 
603 static void __exit mlb_usio_exit(void)
604 {
605 	platform_driver_unregister(&mlb_usio_driver);
606 	uart_unregister_driver(&mlb_usio_uart_driver);
607 }
608 
609 module_init(mlb_usio_init);
610 module_exit(mlb_usio_exit);
611 
612 MODULE_AUTHOR("SOCIONEXT");
613 MODULE_DESCRIPTION("MILBEAUT_USIO/UART Driver");
614 MODULE_LICENSE("GPL");
615