linux/drivers/tty/serial/milbeaut_usio.c
<<
>>
Prefs
   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, int 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");
 612