root/drivers/tty/serial/apbuart.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. apbuart_stop_tx
  2. apbuart_start_tx
  3. apbuart_stop_rx
  4. apbuart_rx_chars
  5. apbuart_tx_chars
  6. apbuart_int
  7. apbuart_tx_empty
  8. apbuart_get_mctrl
  9. apbuart_set_mctrl
  10. apbuart_break_ctl
  11. apbuart_startup
  12. apbuart_shutdown
  13. apbuart_set_termios
  14. apbuart_type
  15. apbuart_release_port
  16. apbuart_request_port
  17. apbuart_config_port
  18. apbuart_verify_port
  19. apbuart_scan_fifo_size
  20. apbuart_flush_fifo
  21. apbuart_console_putchar
  22. apbuart_console_write
  23. apbuart_console_get_options
  24. apbuart_console_setup
  25. apbuart_console_init
  26. apbuart_probe
  27. grlib_apbuart_configure
  28. grlib_apbuart_init
  29. grlib_apbuart_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *  Driver for GRLIB serial ports (APBUART)
   4  *
   5  *  Based on linux/drivers/serial/amba.c
   6  *
   7  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
   8  *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
   9  *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
  10  *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
  11  *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
  12  */
  13 
  14 #if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
  15 #define SUPPORT_SYSRQ
  16 #endif
  17 
  18 #include <linux/module.h>
  19 #include <linux/tty.h>
  20 #include <linux/tty_flip.h>
  21 #include <linux/ioport.h>
  22 #include <linux/init.h>
  23 #include <linux/serial.h>
  24 #include <linux/console.h>
  25 #include <linux/sysrq.h>
  26 #include <linux/kthread.h>
  27 #include <linux/device.h>
  28 #include <linux/of.h>
  29 #include <linux/of_device.h>
  30 #include <linux/of_platform.h>
  31 #include <linux/of_irq.h>
  32 #include <linux/platform_device.h>
  33 #include <linux/io.h>
  34 #include <linux/serial_core.h>
  35 #include <asm/irq.h>
  36 
  37 #include "apbuart.h"
  38 
  39 #define SERIAL_APBUART_MAJOR    TTY_MAJOR
  40 #define SERIAL_APBUART_MINOR    64
  41 #define UART_DUMMY_RSR_RX       0x8000  /* for ignore all read */
  42 
  43 static void apbuart_tx_chars(struct uart_port *port);
  44 
  45 static void apbuart_stop_tx(struct uart_port *port)
  46 {
  47         unsigned int cr;
  48 
  49         cr = UART_GET_CTRL(port);
  50         cr &= ~UART_CTRL_TI;
  51         UART_PUT_CTRL(port, cr);
  52 }
  53 
  54 static void apbuart_start_tx(struct uart_port *port)
  55 {
  56         unsigned int cr;
  57 
  58         cr = UART_GET_CTRL(port);
  59         cr |= UART_CTRL_TI;
  60         UART_PUT_CTRL(port, cr);
  61 
  62         if (UART_GET_STATUS(port) & UART_STATUS_THE)
  63                 apbuart_tx_chars(port);
  64 }
  65 
  66 static void apbuart_stop_rx(struct uart_port *port)
  67 {
  68         unsigned int cr;
  69 
  70         cr = UART_GET_CTRL(port);
  71         cr &= ~(UART_CTRL_RI);
  72         UART_PUT_CTRL(port, cr);
  73 }
  74 
  75 static void apbuart_rx_chars(struct uart_port *port)
  76 {
  77         unsigned int status, ch, rsr, flag;
  78         unsigned int max_chars = port->fifosize;
  79 
  80         status = UART_GET_STATUS(port);
  81 
  82         while (UART_RX_DATA(status) && (max_chars--)) {
  83 
  84                 ch = UART_GET_CHAR(port);
  85                 flag = TTY_NORMAL;
  86 
  87                 port->icount.rx++;
  88 
  89                 rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
  90                 UART_PUT_STATUS(port, 0);
  91                 if (rsr & UART_STATUS_ERR) {
  92 
  93                         if (rsr & UART_STATUS_BR) {
  94                                 rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
  95                                 port->icount.brk++;
  96                                 if (uart_handle_break(port))
  97                                         goto ignore_char;
  98                         } else if (rsr & UART_STATUS_PE) {
  99                                 port->icount.parity++;
 100                         } else if (rsr & UART_STATUS_FE) {
 101                                 port->icount.frame++;
 102                         }
 103                         if (rsr & UART_STATUS_OE)
 104                                 port->icount.overrun++;
 105 
 106                         rsr &= port->read_status_mask;
 107 
 108                         if (rsr & UART_STATUS_PE)
 109                                 flag = TTY_PARITY;
 110                         else if (rsr & UART_STATUS_FE)
 111                                 flag = TTY_FRAME;
 112                 }
 113 
 114                 if (uart_handle_sysrq_char(port, ch))
 115                         goto ignore_char;
 116 
 117                 uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
 118 
 119 
 120               ignore_char:
 121                 status = UART_GET_STATUS(port);
 122         }
 123 
 124         spin_unlock(&port->lock);
 125         tty_flip_buffer_push(&port->state->port);
 126         spin_lock(&port->lock);
 127 }
 128 
 129 static void apbuart_tx_chars(struct uart_port *port)
 130 {
 131         struct circ_buf *xmit = &port->state->xmit;
 132         int count;
 133 
 134         if (port->x_char) {
 135                 UART_PUT_CHAR(port, port->x_char);
 136                 port->icount.tx++;
 137                 port->x_char = 0;
 138                 return;
 139         }
 140 
 141         if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
 142                 apbuart_stop_tx(port);
 143                 return;
 144         }
 145 
 146         /* amba: fill FIFO */
 147         count = port->fifosize >> 1;
 148         do {
 149                 UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
 150                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 151                 port->icount.tx++;
 152                 if (uart_circ_empty(xmit))
 153                         break;
 154         } while (--count > 0);
 155 
 156         if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 157                 uart_write_wakeup(port);
 158 
 159         if (uart_circ_empty(xmit))
 160                 apbuart_stop_tx(port);
 161 }
 162 
 163 static irqreturn_t apbuart_int(int irq, void *dev_id)
 164 {
 165         struct uart_port *port = dev_id;
 166         unsigned int status;
 167 
 168         spin_lock(&port->lock);
 169 
 170         status = UART_GET_STATUS(port);
 171         if (status & UART_STATUS_DR)
 172                 apbuart_rx_chars(port);
 173         if (status & UART_STATUS_THE)
 174                 apbuart_tx_chars(port);
 175 
 176         spin_unlock(&port->lock);
 177 
 178         return IRQ_HANDLED;
 179 }
 180 
 181 static unsigned int apbuart_tx_empty(struct uart_port *port)
 182 {
 183         unsigned int status = UART_GET_STATUS(port);
 184         return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
 185 }
 186 
 187 static unsigned int apbuart_get_mctrl(struct uart_port *port)
 188 {
 189         /* The GRLIB APBUART handles flow control in hardware */
 190         return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
 191 }
 192 
 193 static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
 194 {
 195         /* The GRLIB APBUART handles flow control in hardware */
 196 }
 197 
 198 static void apbuart_break_ctl(struct uart_port *port, int break_state)
 199 {
 200         /* We don't support sending break */
 201 }
 202 
 203 static int apbuart_startup(struct uart_port *port)
 204 {
 205         int retval;
 206         unsigned int cr;
 207 
 208         /* Allocate the IRQ */
 209         retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
 210         if (retval)
 211                 return retval;
 212 
 213         /* Finally, enable interrupts */
 214         cr = UART_GET_CTRL(port);
 215         UART_PUT_CTRL(port,
 216                       cr | UART_CTRL_RE | UART_CTRL_TE |
 217                       UART_CTRL_RI | UART_CTRL_TI);
 218 
 219         return 0;
 220 }
 221 
 222 static void apbuart_shutdown(struct uart_port *port)
 223 {
 224         unsigned int cr;
 225 
 226         /* disable all interrupts, disable the port */
 227         cr = UART_GET_CTRL(port);
 228         UART_PUT_CTRL(port,
 229                       cr & ~(UART_CTRL_RE | UART_CTRL_TE |
 230                              UART_CTRL_RI | UART_CTRL_TI));
 231 
 232         /* Free the interrupt */
 233         free_irq(port->irq, port);
 234 }
 235 
 236 static void apbuart_set_termios(struct uart_port *port,
 237                                 struct ktermios *termios, struct ktermios *old)
 238 {
 239         unsigned int cr;
 240         unsigned long flags;
 241         unsigned int baud, quot;
 242 
 243         /* Ask the core to calculate the divisor for us. */
 244         baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
 245         if (baud == 0)
 246                 panic("invalid baudrate %i\n", port->uartclk / 16);
 247 
 248         /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
 249         quot = (uart_get_divisor(port, baud)) * 2;
 250         cr = UART_GET_CTRL(port);
 251         cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
 252 
 253         if (termios->c_cflag & PARENB) {
 254                 cr |= UART_CTRL_PE;
 255                 if ((termios->c_cflag & PARODD))
 256                         cr |= UART_CTRL_PS;
 257         }
 258 
 259         /* Enable flow control. */
 260         if (termios->c_cflag & CRTSCTS)
 261                 cr |= UART_CTRL_FL;
 262 
 263         spin_lock_irqsave(&port->lock, flags);
 264 
 265         /* Update the per-port timeout. */
 266         uart_update_timeout(port, termios->c_cflag, baud);
 267 
 268         port->read_status_mask = UART_STATUS_OE;
 269         if (termios->c_iflag & INPCK)
 270                 port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
 271 
 272         /* Characters to ignore */
 273         port->ignore_status_mask = 0;
 274         if (termios->c_iflag & IGNPAR)
 275                 port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
 276 
 277         /* Ignore all characters if CREAD is not set. */
 278         if ((termios->c_cflag & CREAD) == 0)
 279                 port->ignore_status_mask |= UART_DUMMY_RSR_RX;
 280 
 281         /* Set baud rate */
 282         quot -= 1;
 283         UART_PUT_SCAL(port, quot);
 284         UART_PUT_CTRL(port, cr);
 285 
 286         spin_unlock_irqrestore(&port->lock, flags);
 287 }
 288 
 289 static const char *apbuart_type(struct uart_port *port)
 290 {
 291         return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
 292 }
 293 
 294 static void apbuart_release_port(struct uart_port *port)
 295 {
 296         release_mem_region(port->mapbase, 0x100);
 297 }
 298 
 299 static int apbuart_request_port(struct uart_port *port)
 300 {
 301         return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
 302             != NULL ? 0 : -EBUSY;
 303         return 0;
 304 }
 305 
 306 /* Configure/autoconfigure the port */
 307 static void apbuart_config_port(struct uart_port *port, int flags)
 308 {
 309         if (flags & UART_CONFIG_TYPE) {
 310                 port->type = PORT_APBUART;
 311                 apbuart_request_port(port);
 312         }
 313 }
 314 
 315 /* Verify the new serial_struct (for TIOCSSERIAL) */
 316 static int apbuart_verify_port(struct uart_port *port,
 317                                struct serial_struct *ser)
 318 {
 319         int ret = 0;
 320         if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
 321                 ret = -EINVAL;
 322         if (ser->irq < 0 || ser->irq >= NR_IRQS)
 323                 ret = -EINVAL;
 324         if (ser->baud_base < 9600)
 325                 ret = -EINVAL;
 326         return ret;
 327 }
 328 
 329 static const struct uart_ops grlib_apbuart_ops = {
 330         .tx_empty = apbuart_tx_empty,
 331         .set_mctrl = apbuart_set_mctrl,
 332         .get_mctrl = apbuart_get_mctrl,
 333         .stop_tx = apbuart_stop_tx,
 334         .start_tx = apbuart_start_tx,
 335         .stop_rx = apbuart_stop_rx,
 336         .break_ctl = apbuart_break_ctl,
 337         .startup = apbuart_startup,
 338         .shutdown = apbuart_shutdown,
 339         .set_termios = apbuart_set_termios,
 340         .type = apbuart_type,
 341         .release_port = apbuart_release_port,
 342         .request_port = apbuart_request_port,
 343         .config_port = apbuart_config_port,
 344         .verify_port = apbuart_verify_port,
 345 };
 346 
 347 static struct uart_port grlib_apbuart_ports[UART_NR];
 348 static struct device_node *grlib_apbuart_nodes[UART_NR];
 349 
 350 static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
 351 {
 352         int ctrl, loop = 0;
 353         int status;
 354         int fifosize;
 355         unsigned long flags;
 356 
 357         ctrl = UART_GET_CTRL(port);
 358 
 359         /*
 360          * Enable the transceiver and wait for it to be ready to send data.
 361          * Clear interrupts so that this process will not be externally
 362          * interrupted in the middle (which can cause the transceiver to
 363          * drain prematurely).
 364          */
 365 
 366         local_irq_save(flags);
 367 
 368         UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
 369 
 370         while (!UART_TX_READY(UART_GET_STATUS(port)))
 371                 loop++;
 372 
 373         /*
 374          * Disable the transceiver so data isn't actually sent during the
 375          * actual test.
 376          */
 377 
 378         UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
 379 
 380         fifosize = 1;
 381         UART_PUT_CHAR(port, 0);
 382 
 383         /*
 384          * So long as transmitting a character increments the tranceivier FIFO
 385          * length the FIFO must be at least that big. These bytes will
 386          * automatically drain off of the FIFO.
 387          */
 388 
 389         status = UART_GET_STATUS(port);
 390         while (((status >> 20) & 0x3F) == fifosize) {
 391                 fifosize++;
 392                 UART_PUT_CHAR(port, 0);
 393                 status = UART_GET_STATUS(port);
 394         }
 395 
 396         fifosize--;
 397 
 398         UART_PUT_CTRL(port, ctrl);
 399         local_irq_restore(flags);
 400 
 401         if (fifosize == 0)
 402                 fifosize = 1;
 403 
 404         return fifosize;
 405 }
 406 
 407 static void apbuart_flush_fifo(struct uart_port *port)
 408 {
 409         int i;
 410 
 411         for (i = 0; i < port->fifosize; i++)
 412                 UART_GET_CHAR(port);
 413 }
 414 
 415 
 416 /* ======================================================================== */
 417 /* Console driver, if enabled                                               */
 418 /* ======================================================================== */
 419 
 420 #ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
 421 
 422 static void apbuart_console_putchar(struct uart_port *port, int ch)
 423 {
 424         unsigned int status;
 425         do {
 426                 status = UART_GET_STATUS(port);
 427         } while (!UART_TX_READY(status));
 428         UART_PUT_CHAR(port, ch);
 429 }
 430 
 431 static void
 432 apbuart_console_write(struct console *co, const char *s, unsigned int count)
 433 {
 434         struct uart_port *port = &grlib_apbuart_ports[co->index];
 435         unsigned int status, old_cr, new_cr;
 436 
 437         /* First save the CR then disable the interrupts */
 438         old_cr = UART_GET_CTRL(port);
 439         new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
 440         UART_PUT_CTRL(port, new_cr);
 441 
 442         uart_console_write(port, s, count, apbuart_console_putchar);
 443 
 444         /*
 445          *      Finally, wait for transmitter to become empty
 446          *      and restore the TCR
 447          */
 448         do {
 449                 status = UART_GET_STATUS(port);
 450         } while (!UART_TX_READY(status));
 451         UART_PUT_CTRL(port, old_cr);
 452 }
 453 
 454 static void __init
 455 apbuart_console_get_options(struct uart_port *port, int *baud,
 456                             int *parity, int *bits)
 457 {
 458         if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
 459 
 460                 unsigned int quot, status;
 461                 status = UART_GET_STATUS(port);
 462 
 463                 *parity = 'n';
 464                 if (status & UART_CTRL_PE) {
 465                         if ((status & UART_CTRL_PS) == 0)
 466                                 *parity = 'e';
 467                         else
 468                                 *parity = 'o';
 469                 }
 470 
 471                 *bits = 8;
 472                 quot = UART_GET_SCAL(port) / 8;
 473                 *baud = port->uartclk / (16 * (quot + 1));
 474         }
 475 }
 476 
 477 static int __init apbuart_console_setup(struct console *co, char *options)
 478 {
 479         struct uart_port *port;
 480         int baud = 38400;
 481         int bits = 8;
 482         int parity = 'n';
 483         int flow = 'n';
 484 
 485         pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
 486                  co, co->index, options);
 487 
 488         /*
 489          * Check whether an invalid uart number has been specified, and
 490          * if so, search for the first available port that does have
 491          * console support.
 492          */
 493         if (co->index >= grlib_apbuart_port_nr)
 494                 co->index = 0;
 495 
 496         port = &grlib_apbuart_ports[co->index];
 497 
 498         spin_lock_init(&port->lock);
 499 
 500         if (options)
 501                 uart_parse_options(options, &baud, &parity, &bits, &flow);
 502         else
 503                 apbuart_console_get_options(port, &baud, &parity, &bits);
 504 
 505         return uart_set_options(port, co, baud, parity, bits, flow);
 506 }
 507 
 508 static struct uart_driver grlib_apbuart_driver;
 509 
 510 static struct console grlib_apbuart_console = {
 511         .name = "ttyS",
 512         .write = apbuart_console_write,
 513         .device = uart_console_device,
 514         .setup = apbuart_console_setup,
 515         .flags = CON_PRINTBUFFER,
 516         .index = -1,
 517         .data = &grlib_apbuart_driver,
 518 };
 519 
 520 
 521 static int grlib_apbuart_configure(void);
 522 
 523 static int __init apbuart_console_init(void)
 524 {
 525         if (grlib_apbuart_configure())
 526                 return -ENODEV;
 527         register_console(&grlib_apbuart_console);
 528         return 0;
 529 }
 530 
 531 console_initcall(apbuart_console_init);
 532 
 533 #define APBUART_CONSOLE (&grlib_apbuart_console)
 534 #else
 535 #define APBUART_CONSOLE NULL
 536 #endif
 537 
 538 static struct uart_driver grlib_apbuart_driver = {
 539         .owner = THIS_MODULE,
 540         .driver_name = "serial",
 541         .dev_name = "ttyS",
 542         .major = SERIAL_APBUART_MAJOR,
 543         .minor = SERIAL_APBUART_MINOR,
 544         .nr = UART_NR,
 545         .cons = APBUART_CONSOLE,
 546 };
 547 
 548 
 549 /* ======================================================================== */
 550 /* OF Platform Driver                                                       */
 551 /* ======================================================================== */
 552 
 553 static int apbuart_probe(struct platform_device *op)
 554 {
 555         int i;
 556         struct uart_port *port = NULL;
 557 
 558         for (i = 0; i < grlib_apbuart_port_nr; i++) {
 559                 if (op->dev.of_node == grlib_apbuart_nodes[i])
 560                         break;
 561         }
 562 
 563         port = &grlib_apbuart_ports[i];
 564         port->dev = &op->dev;
 565         port->irq = op->archdata.irqs[0];
 566 
 567         uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
 568 
 569         apbuart_flush_fifo((struct uart_port *) port);
 570 
 571         printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
 572                (unsigned long long) port->mapbase, port->irq);
 573         return 0;
 574 }
 575 
 576 static const struct of_device_id apbuart_match[] = {
 577         {
 578          .name = "GAISLER_APBUART",
 579          },
 580         {
 581          .name = "01_00c",
 582          },
 583         {},
 584 };
 585 MODULE_DEVICE_TABLE(of, apbuart_match);
 586 
 587 static struct platform_driver grlib_apbuart_of_driver = {
 588         .probe = apbuart_probe,
 589         .driver = {
 590                 .name = "grlib-apbuart",
 591                 .of_match_table = apbuart_match,
 592         },
 593 };
 594 
 595 
 596 static int __init grlib_apbuart_configure(void)
 597 {
 598         struct device_node *np;
 599         int line = 0;
 600 
 601         for_each_matching_node(np, apbuart_match) {
 602                 const int *ampopts;
 603                 const u32 *freq_hz;
 604                 const struct amba_prom_registers *regs;
 605                 struct uart_port *port;
 606                 unsigned long addr;
 607 
 608                 ampopts = of_get_property(np, "ampopts", NULL);
 609                 if (ampopts && (*ampopts == 0))
 610                         continue; /* Ignore if used by another OS instance */
 611                 regs = of_get_property(np, "reg", NULL);
 612                 /* Frequency of APB Bus is frequency of UART */
 613                 freq_hz = of_get_property(np, "freq", NULL);
 614 
 615                 if (!regs || !freq_hz || (*freq_hz == 0))
 616                         continue;
 617 
 618                 grlib_apbuart_nodes[line] = np;
 619 
 620                 addr = regs->phys_addr;
 621 
 622                 port = &grlib_apbuart_ports[line];
 623 
 624                 port->mapbase = addr;
 625                 port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
 626                 port->irq = 0;
 627                 port->iotype = UPIO_MEM;
 628                 port->ops = &grlib_apbuart_ops;
 629                 port->flags = UPF_BOOT_AUTOCONF;
 630                 port->line = line;
 631                 port->uartclk = *freq_hz;
 632                 port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
 633                 line++;
 634 
 635                 /* We support maximum UART_NR uarts ... */
 636                 if (line == UART_NR)
 637                         break;
 638         }
 639 
 640         grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
 641         return line ? 0 : -ENODEV;
 642 }
 643 
 644 static int __init grlib_apbuart_init(void)
 645 {
 646         int ret;
 647 
 648         /* Find all APBUARTS in device the tree and initialize their ports */
 649         ret = grlib_apbuart_configure();
 650         if (ret)
 651                 return ret;
 652 
 653         printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
 654 
 655         ret = uart_register_driver(&grlib_apbuart_driver);
 656 
 657         if (ret) {
 658                 printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
 659                        __FILE__, ret);
 660                 return ret;
 661         }
 662 
 663         ret = platform_driver_register(&grlib_apbuart_of_driver);
 664         if (ret) {
 665                 printk(KERN_ERR
 666                        "%s: platform_driver_register failed (%i)\n",
 667                        __FILE__, ret);
 668                 uart_unregister_driver(&grlib_apbuart_driver);
 669                 return ret;
 670         }
 671 
 672         return ret;
 673 }
 674 
 675 static void __exit grlib_apbuart_exit(void)
 676 {
 677         int i;
 678 
 679         for (i = 0; i < grlib_apbuart_port_nr; i++)
 680                 uart_remove_one_port(&grlib_apbuart_driver,
 681                                      &grlib_apbuart_ports[i]);
 682 
 683         uart_unregister_driver(&grlib_apbuart_driver);
 684         platform_driver_unregister(&grlib_apbuart_of_driver);
 685 }
 686 
 687 module_init(grlib_apbuart_init);
 688 module_exit(grlib_apbuart_exit);
 689 
 690 MODULE_AUTHOR("Aeroflex Gaisler AB");
 691 MODULE_DESCRIPTION("GRLIB APBUART serial driver");
 692 MODULE_VERSION("2.1");
 693 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */