Merge tag 'amlogic-dt64-2.1' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman...
[linux-2.6-microblaze.git] / drivers / tty / serial / milbeaut_usio.c
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");