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_port_write(struct uart_port *port, const char *s,
 485                                    u_int count)
 486{
 487        unsigned long flags;
 488        int locked;
 489        u32 val, tmp;
 490
 491        local_irq_save(flags);
 492        if (port->sysrq) {
 493                locked = 0;
 494        } else if (oops_in_progress) {
 495                locked = spin_trylock(&port->lock);
 496        } else {
 497                spin_lock(&port->lock);
 498                locked = 1;
 499        }
 500
 501        val = readl(port->membase + AML_UART_CONTROL);
 502        val |= AML_UART_TX_EN;
 503        tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
 504        writel(tmp, port->membase + AML_UART_CONTROL);
 505
 506        uart_console_write(port, s, count, meson_console_putchar);
 507        writel(val, port->membase + AML_UART_CONTROL);
 508
 509        if (locked)
 510                spin_unlock(&port->lock);
 511        local_irq_restore(flags);
 512}
 513
 514static void meson_serial_console_write(struct console *co, const char *s,
 515                                       u_int count)
 516{
 517        struct uart_port *port;
 518
 519        port = meson_ports[co->index];
 520        if (!port)
 521                return;
 522
 523        meson_serial_port_write(port, s, count);
 524}
 525
 526static int meson_serial_console_setup(struct console *co, char *options)
 527{
 528        struct uart_port *port;
 529        int baud = 115200;
 530        int bits = 8;
 531        int parity = 'n';
 532        int flow = 'n';
 533
 534        if (co->index < 0 || co->index >= AML_UART_PORT_NUM)
 535                return -EINVAL;
 536
 537        port = meson_ports[co->index];
 538        if (!port || !port->membase)
 539                return -ENODEV;
 540
 541        if (options)
 542                uart_parse_options(options, &baud, &parity, &bits, &flow);
 543
 544        return uart_set_options(port, co, baud, parity, bits, flow);
 545}
 546
 547static struct console meson_serial_console = {
 548        .name           = AML_UART_DEV_NAME,
 549        .write          = meson_serial_console_write,
 550        .device         = uart_console_device,
 551        .setup          = meson_serial_console_setup,
 552        .flags          = CON_PRINTBUFFER,
 553        .index          = -1,
 554        .data           = &meson_uart_driver,
 555};
 556
 557static int __init meson_serial_console_init(void)
 558{
 559        register_console(&meson_serial_console);
 560        return 0;
 561}
 562console_initcall(meson_serial_console_init);
 563
 564static void meson_serial_early_console_write(struct console *co,
 565                                             const char *s,
 566                                             u_int count)
 567{
 568        struct earlycon_device *dev = co->data;
 569
 570        meson_serial_port_write(&dev->port, s, count);
 571}
 572
 573static int __init
 574meson_serial_early_console_setup(struct earlycon_device *device, const char *opt)
 575{
 576        if (!device->port.membase)
 577                return -ENODEV;
 578
 579        device->con->write = meson_serial_early_console_write;
 580        return 0;
 581}
 582OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart",
 583                    meson_serial_early_console_setup);
 584
 585#define MESON_SERIAL_CONSOLE    (&meson_serial_console)
 586#else
 587#define MESON_SERIAL_CONSOLE    NULL
 588#endif
 589
 590static struct uart_driver meson_uart_driver = {
 591        .owner          = THIS_MODULE,
 592        .driver_name    = "meson_uart",
 593        .dev_name       = AML_UART_DEV_NAME,
 594        .nr             = AML_UART_PORT_NUM,
 595        .cons           = MESON_SERIAL_CONSOLE,
 596};
 597
 598static int meson_uart_probe(struct platform_device *pdev)
 599{
 600        struct resource *res_mem, *res_irq;
 601        struct uart_port *port;
 602        struct clk *clk;
 603        int ret = 0;
 604
 605        if (pdev->dev.of_node)
 606                pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
 607
 608        if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM)
 609                return -EINVAL;
 610
 611        res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 612        if (!res_mem)
 613                return -ENODEV;
 614
 615        res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 616        if (!res_irq)
 617                return -ENODEV;
 618
 619        if (meson_ports[pdev->id]) {
 620                dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
 621                return -EBUSY;
 622        }
 623
 624        port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL);
 625        if (!port)
 626                return -ENOMEM;
 627
 628        clk = clk_get(&pdev->dev, NULL);
 629        if (IS_ERR(clk))
 630                return PTR_ERR(clk);
 631
 632        port->uartclk = clk_get_rate(clk);
 633        port->iotype = UPIO_MEM;
 634        port->mapbase = res_mem->start;
 635        port->irq = res_irq->start;
 636        port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
 637        port->dev = &pdev->dev;
 638        port->line = pdev->id;
 639        port->type = PORT_MESON;
 640        port->x_char = 0;
 641        port->ops = &meson_uart_ops;
 642        port->fifosize = 64;
 643
 644        meson_ports[pdev->id] = port;
 645        platform_set_drvdata(pdev, port);
 646
 647        /* reset port before registering (and possibly registering console) */
 648        if (meson_uart_request_port(port) >= 0) {
 649                meson_uart_reset(port);
 650                meson_uart_release_port(port);
 651        }
 652
 653        ret = uart_add_one_port(&meson_uart_driver, port);
 654        if (ret)
 655                meson_ports[pdev->id] = NULL;
 656
 657        return ret;
 658}
 659
 660static int meson_uart_remove(struct platform_device *pdev)
 661{
 662        struct uart_port *port;
 663
 664        port = platform_get_drvdata(pdev);
 665        uart_remove_one_port(&meson_uart_driver, port);
 666        meson_ports[pdev->id] = NULL;
 667
 668        return 0;
 669}
 670
 671
 672static const struct of_device_id meson_uart_dt_match[] = {
 673        { .compatible = "amlogic,meson-uart" },
 674        { /* sentinel */ },
 675};
 676MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
 677
 678static  struct platform_driver meson_uart_platform_driver = {
 679        .probe          = meson_uart_probe,
 680        .remove         = meson_uart_remove,
 681        .driver         = {
 682                .name           = "meson_uart",
 683                .of_match_table = meson_uart_dt_match,
 684        },
 685};
 686
 687static int __init meson_uart_init(void)
 688{
 689        int ret;
 690
 691        ret = uart_register_driver(&meson_uart_driver);
 692        if (ret)
 693                return ret;
 694
 695        ret = platform_driver_register(&meson_uart_platform_driver);
 696        if (ret)
 697                uart_unregister_driver(&meson_uart_driver);
 698
 699        return ret;
 700}
 701
 702static void __exit meson_uart_exit(void)
 703{
 704        platform_driver_unregister(&meson_uart_platform_driver);
 705        uart_unregister_driver(&meson_uart_driver);
 706}
 707
 708module_init(meson_uart_init);
 709module_exit(meson_uart_exit);
 710
 711MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
 712MODULE_DESCRIPTION("Amlogic Meson serial port driver");
 713MODULE_LICENSE("GPL v2");
 714