Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 22static struct uart_port mlb_usio_ports[CONFIG_SERIAL_MILBEAUT_USIO_PORTS];
 23
 24#define RX	0
 25#define TX	1
 26static 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
 69static 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
 77static 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
125static 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
140static 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
146static 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
153static 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
212static 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
223static 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
235static 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
241static void mlb_usio_set_mctrl(struct uart_port *port, unsigned int mctrl)
242{
243}
244
245static unsigned int mlb_usio_get_mctrl(struct uart_port *port)
246{
247	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
248
249}
250
251static void mlb_usio_break_ctl(struct uart_port *port, int break_state)
252{
253}
254
255static 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
296static 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
304static 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
378static const char *mlb_usio_type(struct uart_port *port)
379{
380	return ((port->type == PORT_MLB_USIO) ? USIO_NAME : NULL);
381}
382
383static 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
389static 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
407static 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
415static 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
423static 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
449static struct uart_driver mlb_usio_uart_driver;
450static 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
460static int __init mlb_usio_console_init(void)
461{
462	register_console(&mlb_usio_console);
463	return 0;
464}
465console_initcall(mlb_usio_console_init);
466
467
468static 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
476static 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
485OF_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
493static 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
501static 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
553failed:
554	clk_disable_unprepare(clk);
555
556	return ret;
557}
558
559static 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
570static const struct of_device_id mlb_usio_dt_ids[] = {
571	{ .compatible = "socionext,milbeaut-usio-uart" },
572	{ /* sentinel */ }
573};
574MODULE_DEVICE_TABLE(of, mlb_usio_dt_ids);
575
576static 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
585static 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
603static void __exit mlb_usio_exit(void)
604{
605	platform_driver_unregister(&mlb_usio_driver);
606	uart_unregister_driver(&mlb_usio_uart_driver);
607}
608
609module_init(mlb_usio_init);
610module_exit(mlb_usio_exit);
611
612MODULE_AUTHOR("SOCIONEXT");
613MODULE_DESCRIPTION("MILBEAUT_USIO/UART Driver");
614MODULE_LICENSE("GPL");