linux/drivers/tty/serial/meson_uart.c
<<
>>
Prefs
   1/*
   2 *  Based on meson_uart.c, by AMLOGIC, INC.
   3 *
   4 * Copyright (C) 2014 Carlo Caione <carlo@caione.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License version 2 as published
   8 * by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 */
  16
  17#include <linux/clk.h>
  18#include <linux/console.h>
  19#include <linux/delay.h>
  20#include <linux/init.h>
  21#include <linux/io.h>
  22#include <linux/module.h>
  23#include <linux/kernel.h>
  24#include <linux/of.h>
  25#include <linux/platform_device.h>
  26#include <linux/serial.h>
  27#include <linux/serial_core.h>
  28#include <linux/tty.h>
  29#include <linux/tty_flip.h>
  30
  31/* Register offsets */
  32#define AML_UART_WFIFO                  0x00
  33#define AML_UART_RFIFO                  0x04
  34#define AML_UART_CONTROL                0x08
  35#define AML_UART_STATUS                 0x0c
  36#define AML_UART_MISC                   0x10
  37#define AML_UART_REG5                   0x14
  38
  39/* AML_UART_CONTROL bits */
  40#define AML_UART_TX_EN                  BIT(12)
  41#define AML_UART_RX_EN                  BIT(13)
  42#define AML_UART_TX_RST                 BIT(22)
  43#define AML_UART_RX_RST                 BIT(23)
  44#define AML_UART_CLR_ERR                BIT(24)
  45#define AML_UART_RX_INT_EN              BIT(27)
  46#define AML_UART_TX_INT_EN              BIT(28)
  47#define AML_UART_DATA_LEN_MASK          (0x03 << 20)
  48#define AML_UART_DATA_LEN_8BIT          (0x00 << 20)
  49#define AML_UART_DATA_LEN_7BIT          (0x01 << 20)
  50#define AML_UART_DATA_LEN_6BIT          (0x02 << 20)
  51#define AML_UART_DATA_LEN_5BIT          (0x03 << 20)
  52
  53/* AML_UART_STATUS bits */
  54#define AML_UART_PARITY_ERR             BIT(16)
  55#define AML_UART_FRAME_ERR              BIT(17)
  56#define AML_UART_TX_FIFO_WERR           BIT(18)
  57#define AML_UART_RX_EMPTY               BIT(20)
  58#define AML_UART_TX_FULL                BIT(21)
  59#define AML_UART_TX_EMPTY               BIT(22)
  60#define AML_UART_XMIT_BUSY              BIT(25)
  61#define AML_UART_ERR                    (AML_UART_PARITY_ERR | \
  62                                         AML_UART_FRAME_ERR  | \
  63                                         AML_UART_TX_FIFO_WERR)
  64
  65/* AML_UART_CONTROL bits */
  66#define AML_UART_TWO_WIRE_EN            BIT(15)
  67#define AML_UART_PARITY_TYPE            BIT(18)
  68#define AML_UART_PARITY_EN              BIT(19)
  69#define AML_UART_CLEAR_ERR              BIT(24)
  70#define AML_UART_STOP_BIN_LEN_MASK      (0x03 << 16)
  71#define AML_UART_STOP_BIN_1SB           (0x00 << 16)
  72#define AML_UART_STOP_BIN_2SB           (0x01 << 16)
  73
  74/* AML_UART_MISC bits */
  75#define AML_UART_XMIT_IRQ(c)            (((c) & 0xff) << 8)
  76#define AML_UART_RECV_IRQ(c)            ((c) & 0xff)
  77
  78/* AML_UART_REG5 bits */
  79#define AML_UART_BAUD_MASK              0x7fffff
  80#define AML_UART_BAUD_USE               BIT(23)
  81#define AML_UART_BAUD_XTAL              BIT(24)
  82
  83#define AML_UART_PORT_NUM               6
  84#define AML_UART_DEV_NAME               "ttyAML"
  85
  86
  87static struct uart_driver meson_uart_driver;
  88
  89static struct uart_port *meson_ports[AML_UART_PORT_NUM];
  90
  91static void meson_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
  92{
  93}
  94
  95static unsigned int meson_uart_get_mctrl(struct uart_port *port)
  96{
  97        return TIOCM_CTS;
  98}
  99
 100static unsigned int meson_uart_tx_empty(struct uart_port *port)
 101{
 102        u32 val;
 103
 104        val = readl(port->membase + AML_UART_STATUS);
 105        val &= (AML_UART_TX_EMPTY | AML_UART_XMIT_BUSY);
 106        return (val == AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0;
 107}
 108
 109static void meson_uart_stop_tx(struct uart_port *port)
 110{
 111        u32 val;
 112
 113        val = readl(port->membase + AML_UART_CONTROL);
 114        val &= ~AML_UART_TX_INT_EN;
 115        writel(val, port->membase + AML_UART_CONTROL);
 116}
 117
 118static void meson_uart_stop_rx(struct uart_port *port)
 119{
 120        u32 val;
 121
 122        val = readl(port->membase + AML_UART_CONTROL);
 123        val &= ~AML_UART_RX_EN;
 124        writel(val, port->membase + AML_UART_CONTROL);
 125}
 126
 127static void meson_uart_shutdown(struct uart_port *port)
 128{
 129        unsigned long flags;
 130        u32 val;
 131
 132        free_irq(port->irq, port);
 133
 134        spin_lock_irqsave(&port->lock, flags);
 135
 136        val = readl(port->membase + AML_UART_CONTROL);
 137        val &= ~AML_UART_RX_EN;
 138        val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
 139        writel(val, port->membase + AML_UART_CONTROL);
 140
 141        spin_unlock_irqrestore(&port->lock, flags);
 142}
 143
 144static void meson_uart_start_tx(struct uart_port *port)
 145{
 146        struct circ_buf *xmit = &port->state->xmit;
 147        unsigned int ch;
 148        u32 val;
 149
 150        if (uart_tx_stopped(port)) {
 151                meson_uart_stop_tx(port);
 152                return;
 153        }
 154
 155        while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) {
 156                if (port->x_char) {
 157                        writel(port->x_char, port->membase + AML_UART_WFIFO);
 158                        port->icount.tx++;
 159                        port->x_char = 0;
 160                        continue;
 161                }
 162
 163                if (uart_circ_empty(xmit))
 164                        break;
 165
 166                ch = xmit->buf[xmit->tail];
 167                writel(ch, port->membase + AML_UART_WFIFO);
 168                xmit->tail = (xmit->tail+1) & (SERIAL_XMIT_SIZE - 1);
 169                port->icount.tx++;
 170        }
 171
 172        if (!uart_circ_empty(xmit)) {
 173                val = readl(port->membase + AML_UART_CONTROL);
 174                val |= AML_UART_TX_INT_EN;
 175                writel(val, port->membase + AML_UART_CONTROL);
 176        }
 177
 178        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 179                uart_write_wakeup(port);
 180}
 181
 182static void meson_receive_chars(struct uart_port *port)
 183{
 184        struct tty_port *tport = &port->state->port;
 185        char flag;
 186        u32 status, ch, mode;
 187
 188        do {
 189                flag = TTY_NORMAL;
 190                port->icount.rx++;
 191                status = readl(port->membase + AML_UART_STATUS);
 192
 193                if (status & AML_UART_ERR) {
 194                        if (status & AML_UART_TX_FIFO_WERR)
 195                                port->icount.overrun++;
 196                        else if (status & AML_UART_FRAME_ERR)
 197                                port->icount.frame++;
 198                        else if (status & AML_UART_PARITY_ERR)
 199                                port->icount.frame++;
 200
 201                        mode = readl(port->membase + AML_UART_CONTROL);
 202                        mode |= AML_UART_CLEAR_ERR;
 203                        writel(mode, port->membase + AML_UART_CONTROL);
 204
 205                        /* It doesn't clear to 0 automatically */
 206                        mode &= ~AML_UART_CLEAR_ERR;
 207                        writel(mode, port->membase + AML_UART_CONTROL);
 208
 209                        status &= port->read_status_mask;
 210                        if (status & AML_UART_FRAME_ERR)
 211                                flag = TTY_FRAME;
 212                        else if (status & AML_UART_PARITY_ERR)
 213                                flag = TTY_PARITY;
 214                }
 215
 216                ch = readl(port->membase + AML_UART_RFIFO);
 217                ch &= 0xff;
 218
 219                if ((status & port->ignore_status_mask) == 0)
 220                        tty_insert_flip_char(tport, ch, flag);
 221
 222                if (status & AML_UART_TX_FIFO_WERR)
 223                        tty_insert_flip_char(tport, 0, TTY_OVERRUN);
 224
 225        } while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY));
 226
 227        spin_unlock(&port->lock);
 228        tty_flip_buffer_push(tport);
 229        spin_lock(&port->lock);
 230}
 231
 232static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
 233{
 234        struct uart_port *port = (struct uart_port *)dev_id;
 235
 236        spin_lock(&port->lock);
 237
 238        if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY))
 239                meson_receive_chars(port);
 240
 241        if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) {
 242                if (readl(port->membase + AML_UART_CONTROL) & AML_UART_TX_INT_EN)
 243                        meson_uart_start_tx(port);
 244        }
 245
 246        spin_unlock(&port->lock);
 247
 248        return IRQ_HANDLED;
 249}
 250
 251static const char *meson_uart_type(struct uart_port *port)
 252{
 253        return (port->type == PORT_MESON) ? "meson_uart" : NULL;
 254}
 255
 256static void meson_uart_reset(struct uart_port *port)
 257{
 258        u32 val;
 259
 260        val = readl(port->membase + AML_UART_CONTROL);
 261        val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
 262        writel(val, port->membase + AML_UART_CONTROL);
 263
 264        val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
 265        writel(val, port->membase + AML_UART_CONTROL);
 266}
 267
 268static int meson_uart_startup(struct uart_port *port)
 269{
 270        u32 val;
 271        int ret = 0;
 272
 273        val = readl(port->membase + AML_UART_CONTROL);
 274        val |= AML_UART_CLR_ERR;
 275        writel(val, port->membase + AML_UART_CONTROL);
 276        val &= ~AML_UART_CLR_ERR;
 277        writel(val, port->membase + AML_UART_CONTROL);
 278
 279        val |= (AML_UART_RX_EN | AML_UART_TX_EN);
 280        writel(val, port->membase + AML_UART_CONTROL);
 281
 282        val |= (AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
 283        writel(val, port->membase + AML_UART_CONTROL);
 284
 285        val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2));
 286        writel(val, port->membase + AML_UART_MISC);
 287
 288        ret = request_irq(port->irq, meson_uart_interrupt, 0,
 289                          meson_uart_type(port), port);
 290
 291        return ret;
 292}
 293
 294static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
 295{
 296        u32 val;
 297
 298        while (!meson_uart_tx_empty(port))
 299                cpu_relax();
 300
 301        val = readl(port->membase + AML_UART_REG5);
 302        val &= ~AML_UART_BAUD_MASK;
 303        if (port->uartclk == 24000000) {
 304                val = ((port->uartclk / 3) / baud) - 1;
 305                val |= AML_UART_BAUD_XTAL;
 306        } else {
 307                val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
 308        }
 309        val |= AML_UART_BAUD_USE;
 310        writel(val, port->membase + AML_UART_REG5);
 311}
 312
 313static void meson_uart_set_termios(struct uart_port *port,
 314                                   struct ktermios *termios,
 315                                   struct ktermios *old)
 316{
 317        unsigned int cflags, iflags, baud;
 318        unsigned long flags;
 319        u32 val;
 320
 321        spin_lock_irqsave(&port->lock, flags);
 322
 323        cflags = termios->c_cflag;
 324        iflags = termios->c_iflag;
 325
 326        val = readl(port->membase + AML_UART_CONTROL);
 327
 328        val &= ~AML_UART_DATA_LEN_MASK;
 329        switch (cflags & CSIZE) {
 330        case CS8:
 331                val |= AML_UART_DATA_LEN_8BIT;
 332                break;
 333        case CS7:
 334                val |= AML_UART_DATA_LEN_7BIT;
 335                break;
 336        case CS6:
 337                val |= AML_UART_DATA_LEN_6BIT;
 338                break;
 339        case CS5:
 340                val |= AML_UART_DATA_LEN_5BIT;
 341                break;
 342        }
 343
 344        if (cflags & PARENB)
 345                val |= AML_UART_PARITY_EN;
 346        else
 347                val &= ~AML_UART_PARITY_EN;
 348
 349        if (cflags & PARODD)
 350                val |= AML_UART_PARITY_TYPE;
 351        else
 352                val &= ~AML_UART_PARITY_TYPE;
 353
 354        val &= ~AML_UART_STOP_BIN_LEN_MASK;
 355        if (cflags & CSTOPB)
 356                val |= AML_UART_STOP_BIN_2SB;
 357        else
 358                val &= ~AML_UART_STOP_BIN_1SB;
 359
 360        if (cflags & CRTSCTS)
 361                val &= ~AML_UART_TWO_WIRE_EN;
 362        else
 363                val |= AML_UART_TWO_WIRE_EN;
 364
 365        writel(val, port->membase + AML_UART_CONTROL);
 366
 367        baud = uart_get_baud_rate(port, termios, old, 9600, 115200);
 368        meson_uart_change_speed(port, baud);
 369
 370        port->read_status_mask = AML_UART_TX_FIFO_WERR;
 371        if (iflags & INPCK)
 372                port->read_status_mask |= AML_UART_PARITY_ERR |
 373                                          AML_UART_FRAME_ERR;
 374
 375        port->ignore_status_mask = 0;
 376        if (iflags & IGNPAR)
 377                port->ignore_status_mask |= AML_UART_PARITY_ERR |
 378                                            AML_UART_FRAME_ERR;
 379
 380        uart_update_timeout(port, termios->c_cflag, baud);
 381        spin_unlock_irqrestore(&port->lock, flags);
 382}
 383
 384static int meson_uart_verify_port(struct uart_port *port,
 385                                  struct serial_struct *ser)
 386{
 387        int ret = 0;
 388
 389        if (port->type != PORT_MESON)
 390                ret = -EINVAL;
 391        if (port->irq != ser->irq)
 392                ret = -EINVAL;
 393        if (ser->baud_base < 9600)
 394                ret = -EINVAL;
 395        return ret;
 396}
 397
 398static int meson_uart_res_size(struct uart_port *port)
 399{
 400        struct platform_device *pdev = to_platform_device(port->dev);
 401        struct resource *res;
 402
 403        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 404        if (!res) {
 405                dev_err(port->dev, "cannot obtain I/O memory region");
 406                return -ENODEV;
 407        }
 408
 409        return resource_size(res);
 410}
 411
 412static void meson_uart_release_port(struct uart_port *port)
 413{
 414        int size = meson_uart_res_size(port);
 415
 416        if (port->flags & UPF_IOREMAP) {
 417                devm_release_mem_region(port->dev, port->mapbase, size);
 418                devm_iounmap(port->dev, port->membase);
 419                port->membase = NULL;
 420        }
 421}
 422
 423static int meson_uart_request_port(struct uart_port *port)
 424{
 425        int size = meson_uart_res_size(port);
 426
 427        if (size < 0)
 428                return size;
 429
 430        if (!devm_request_mem_region(port->dev, port->mapbase, size,
 431                                     dev_name(port->dev))) {
 432                dev_err(port->dev, "Memory region busy\n");
 433                return -EBUSY;
 434        }
 435
 436        if (port->flags & UPF_IOREMAP) {
 437                port->membase = devm_ioremap_nocache(port->dev,
 438                                                     port->mapbase,
 439                                                     size);
 440                if (port->membase == NULL)
 441                        return -ENOMEM;
 442        }
 443
 444        return 0;
 445}
 446
 447static void meson_uart_config_port(struct uart_port *port, int flags)
 448{
 449        if (flags & UART_CONFIG_TYPE) {
 450                port->type = PORT_MESON;
 451                meson_uart_request_port(port);
 452        }
 453}
 454
 455static struct uart_ops meson_uart_ops = {
 456        .set_mctrl      = meson_uart_set_mctrl,
 457        .get_mctrl      = meson_uart_get_mctrl,
 458        .tx_empty       = meson_uart_tx_empty,
 459        .start_tx       = meson_uart_start_tx,
 460        .stop_tx        = meson_uart_stop_tx,
 461        .stop_rx        = meson_uart_stop_rx,
 462        .startup        = meson_uart_startup,
 463        .shutdown       = meson_uart_shutdown,
 464        .set_termios    = meson_uart_set_termios,
 465        .type           = meson_uart_type,
 466        .config_port    = meson_uart_config_port,
 467        .request_port   = meson_uart_request_port,
 468        .release_port   = meson_uart_release_port,
 469        .verify_port    = meson_uart_verify_port,
 470};
 471
 472#ifdef CONFIG_SERIAL_MESON_CONSOLE
 473
 474static void meson_console_putchar(struct uart_port *port, int ch)
 475{
 476        if (!port->membase)
 477                return;
 478
 479        while (readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)
 480                cpu_relax();
 481        writel(ch, port->membase + AML_UART_WFIFO);
 482}
 483
 484static void meson_serial_console_write(struct console *co, const char *s,
 485                                       u_int count)
 486{
 487        struct uart_port *port;
 488        unsigned long flags;
 489        int locked;
 490        u32 val, tmp;
 491
 492        port = meson_ports[co->index];
 493        if (!port)
 494                return;
 495
 496        local_irq_save(flags);
 497        if (port->sysrq) {
 498                locked = 0;
 499        } else if (oops_in_progress) {
 500                locked = spin_trylock(&port->lock);
 501        } else {
 502                spin_lock(&port->lock);
 503                locked = 1;
 504        }
 505
 506        val = readl(port->membase + AML_UART_CONTROL);
 507        val |= AML_UART_TX_EN;
 508        tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
 509        writel(tmp, port->membase + AML_UART_CONTROL);
 510
 511        uart_console_write(port, s, count, meson_console_putchar);
 512        writel(val, port->membase + AML_UART_CONTROL);
 513
 514        if (locked)
 515                spin_unlock(&port->lock);
 516        local_irq_restore(flags);
 517}
 518
 519static int meson_serial_console_setup(struct console *co, char *options)
 520{
 521        struct uart_port *port;
 522        int baud = 115200;
 523        int bits = 8;
 524        int parity = 'n';
 525        int flow = 'n';
 526
 527        if (co->index < 0 || co->index >= AML_UART_PORT_NUM)
 528                return -EINVAL;
 529
 530        port = meson_ports[co->index];
 531        if (!port || !port->membase)
 532                return -ENODEV;
 533
 534        if (options)
 535                uart_parse_options(options, &baud, &parity, &bits, &flow);
 536
 537        return uart_set_options(port, co, baud, parity, bits, flow);
 538}
 539
 540static struct console meson_serial_console = {
 541        .name           = AML_UART_DEV_NAME,
 542        .write          = meson_serial_console_write,
 543        .device         = uart_console_device,
 544        .setup          = meson_serial_console_setup,
 545        .flags          = CON_PRINTBUFFER,
 546        .index          = -1,
 547        .data           = &meson_uart_driver,
 548};
 549
 550static int __init meson_serial_console_init(void)
 551{
 552        register_console(&meson_serial_console);
 553        return 0;
 554}
 555console_initcall(meson_serial_console_init);
 556
 557#define MESON_SERIAL_CONSOLE    (&meson_serial_console)
 558#else
 559#define MESON_SERIAL_CONSOLE    NULL
 560#endif
 561
 562static struct uart_driver meson_uart_driver = {
 563        .owner          = THIS_MODULE,
 564        .driver_name    = "meson_uart",
 565        .dev_name       = AML_UART_DEV_NAME,
 566        .nr             = AML_UART_PORT_NUM,
 567        .cons           = MESON_SERIAL_CONSOLE,
 568};
 569
 570static int meson_uart_probe(struct platform_device *pdev)
 571{
 572        struct resource *res_mem, *res_irq;
 573        struct uart_port *port;
 574        struct clk *clk;
 575        int ret = 0;
 576
 577        if (pdev->dev.of_node)
 578                pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
 579
 580        if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM)
 581                return -EINVAL;
 582
 583        res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 584        if (!res_mem)
 585                return -ENODEV;
 586
 587        res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 588        if (!res_irq)
 589                return -ENODEV;
 590
 591        if (meson_ports[pdev->id]) {
 592                dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
 593                return -EBUSY;
 594        }
 595
 596        port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL);
 597        if (!port)
 598                return -ENOMEM;
 599
 600        clk = clk_get(&pdev->dev, NULL);
 601        if (IS_ERR(clk))
 602                return PTR_ERR(clk);
 603
 604        port->uartclk = clk_get_rate(clk);
 605        port->iotype = UPIO_MEM;
 606        port->mapbase = res_mem->start;
 607        port->irq = res_irq->start;
 608        port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
 609        port->dev = &pdev->dev;
 610        port->line = pdev->id;
 611        port->type = PORT_MESON;
 612        port->x_char = 0;
 613        port->ops = &meson_uart_ops;
 614        port->fifosize = 64;
 615
 616        meson_ports[pdev->id] = port;
 617        platform_set_drvdata(pdev, port);
 618
 619        /* reset port before registering (and possibly registering console) */
 620        if (meson_uart_request_port(port) >= 0) {
 621                meson_uart_reset(port);
 622                meson_uart_release_port(port);
 623        }
 624
 625        ret = uart_add_one_port(&meson_uart_driver, port);
 626        if (ret)
 627                meson_ports[pdev->id] = NULL;
 628
 629        return ret;
 630}
 631
 632static int meson_uart_remove(struct platform_device *pdev)
 633{
 634        struct uart_port *port;
 635
 636        port = platform_get_drvdata(pdev);
 637        uart_remove_one_port(&meson_uart_driver, port);
 638        meson_ports[pdev->id] = NULL;
 639
 640        return 0;
 641}
 642
 643
 644static const struct of_device_id meson_uart_dt_match[] = {
 645        { .compatible = "amlogic,meson-uart" },
 646        { /* sentinel */ },
 647};
 648MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
 649
 650static  struct platform_driver meson_uart_platform_driver = {
 651        .probe          = meson_uart_probe,
 652        .remove         = meson_uart_remove,
 653        .driver         = {
 654                .name           = "meson_uart",
 655                .of_match_table = meson_uart_dt_match,
 656        },
 657};
 658
 659static int __init meson_uart_init(void)
 660{
 661        int ret;
 662
 663        ret = uart_register_driver(&meson_uart_driver);
 664        if (ret)
 665                return ret;
 666
 667        ret = platform_driver_register(&meson_uart_platform_driver);
 668        if (ret)
 669                uart_unregister_driver(&meson_uart_driver);
 670
 671        return ret;
 672}
 673
 674static void __exit meson_uart_exit(void)
 675{
 676        platform_driver_unregister(&meson_uart_platform_driver);
 677        uart_unregister_driver(&meson_uart_driver);
 678}
 679
 680module_init(meson_uart_init);
 681module_exit(meson_uart_exit);
 682
 683MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
 684MODULE_DESCRIPTION("Amlogic Meson serial port driver");
 685MODULE_LICENSE("GPL v2");
 686