cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

milbeaut_usio.c (16193B)


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