Commit 6b7d8f8b5c43f7bedda750d8a9dab0658da1d2ba

Authored by Tobias Klauser
Committed by Greg Kroah-Hartman
1 parent 5bcd601049

serial: Add driver for the Altera UART

Add an UART driver for the UART component available as a SOPC (System on
Programmable Chip) component for Altera FPGAs.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Showing 5 changed files with 617 additions and 0 deletions Side-by-side Diff

drivers/serial/Kconfig
... ... @@ -1544,5 +1544,36 @@
1544 1544 Bypass console output and keep going even if there is no
1545 1545 JTAG terminal connection with the host.
1546 1546  
  1547 +config SERIAL_ALTERA_UART
  1548 + tristate "Altera UART support"
  1549 + select SERIAL_CORE
  1550 + help
  1551 + This driver supports the Altera softcore UART port.
  1552 +
  1553 +config SERIAL_ALTERA_UART_MAXPORTS
  1554 + int "Maximum number of Altera UART ports"
  1555 + depends on SERIAL_ALTERA_UART
  1556 + default 4
  1557 + help
  1558 + This setting lets you define the maximum number of the Altera
  1559 + UART ports. The usual default varies from board to board, and
  1560 + this setting is a way of catering for that.
  1561 +
  1562 +config SERIAL_ALTERA_UART_BAUDRATE
  1563 + int "Default baudrate for Altera UART ports"
  1564 + depends on SERIAL_ALTERA_UART
  1565 + default 115200
  1566 + help
  1567 + This setting lets you define what the default baudrate is for the
  1568 + Altera UART ports. The usual default varies from board to board,
  1569 + and this setting is a way of catering for that.
  1570 +
  1571 +config SERIAL_ALTERA_UART_CONSOLE
  1572 + bool "Altera UART console support"
  1573 + depends on SERIAL_ALTERA_UART=y
  1574 + select SERIAL_CORE_CONSOLE
  1575 + help
  1576 + Enable a Altera UART port to be the system console.
  1577 +
1547 1578 endmenu
drivers/serial/Makefile
... ... @@ -83,4 +83,5 @@
83 83 obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
84 84 obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
85 85 obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
  86 +obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
drivers/serial/altera_uart.c
  1 +/*
  2 + * altera_uart.c -- Altera UART driver
  3 + *
  4 + * Based on mcf.c -- Freescale ColdFire UART driver
  5 + *
  6 + * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
  7 + * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
  8 + * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify
  11 + * it under the terms of the GNU General Public License as published by
  12 + * the Free Software Foundation; either version 2 of the License, or
  13 + * (at your option) any later version.
  14 + */
  15 +
  16 +#include <linux/kernel.h>
  17 +#include <linux/init.h>
  18 +#include <linux/interrupt.h>
  19 +#include <linux/module.h>
  20 +#include <linux/console.h>
  21 +#include <linux/tty.h>
  22 +#include <linux/tty_flip.h>
  23 +#include <linux/serial.h>
  24 +#include <linux/serial_core.h>
  25 +#include <linux/platform_device.h>
  26 +#include <linux/io.h>
  27 +#include <linux/altera_uart.h>
  28 +
  29 +#define DRV_NAME "altera_uart"
  30 +
  31 +/*
  32 + * Altera UART register definitions according to the Nios UART datasheet:
  33 + * http://www.altera.com/literature/ds/ds_nios_uart.pdf
  34 + */
  35 +
  36 +#define ALTERA_UART_SIZE 32
  37 +
  38 +#define ALTERA_UART_RXDATA_REG 0
  39 +#define ALTERA_UART_TXDATA_REG 4
  40 +#define ALTERA_UART_STATUS_REG 8
  41 +#define ALTERA_UART_CONTROL_REG 12
  42 +#define ALTERA_UART_DIVISOR_REG 16
  43 +#define ALTERA_UART_EOP_REG 20
  44 +
  45 +#define ALTERA_UART_STATUS_PE_MSK 0x0001 /* parity error */
  46 +#define ALTERA_UART_STATUS_FE_MSK 0x0002 /* framing error */
  47 +#define ALTERA_UART_STATUS_BRK_MSK 0x0004 /* break */
  48 +#define ALTERA_UART_STATUS_ROE_MSK 0x0008 /* RX overrun error */
  49 +#define ALTERA_UART_STATUS_TOE_MSK 0x0010 /* TX overrun error */
  50 +#define ALTERA_UART_STATUS_TMT_MSK 0x0020 /* TX shift register state */
  51 +#define ALTERA_UART_STATUS_TRDY_MSK 0x0040 /* TX ready */
  52 +#define ALTERA_UART_STATUS_RRDY_MSK 0x0080 /* RX ready */
  53 +#define ALTERA_UART_STATUS_E_MSK 0x0100 /* exception condition */
  54 +#define ALTERA_UART_STATUS_DCTS_MSK 0x0400 /* CTS logic-level change */
  55 +#define ALTERA_UART_STATUS_CTS_MSK 0x0800 /* CTS logic state */
  56 +#define ALTERA_UART_STATUS_EOP_MSK 0x1000 /* EOP written/read */
  57 +
  58 + /* Enable interrupt on... */
  59 +#define ALTERA_UART_CONTROL_PE_MSK 0x0001 /* ...parity error */
  60 +#define ALTERA_UART_CONTROL_FE_MSK 0x0002 /* ...framing error */
  61 +#define ALTERA_UART_CONTROL_BRK_MSK 0x0004 /* ...break */
  62 +#define ALTERA_UART_CONTROL_ROE_MSK 0x0008 /* ...RX overrun */
  63 +#define ALTERA_UART_CONTROL_TOE_MSK 0x0010 /* ...TX overrun */
  64 +#define ALTERA_UART_CONTROL_TMT_MSK 0x0020 /* ...TX shift register empty */
  65 +#define ALTERA_UART_CONTROL_TRDY_MSK 0x0040 /* ...TX ready */
  66 +#define ALTERA_UART_CONTROL_RRDY_MSK 0x0080 /* ...RX ready */
  67 +#define ALTERA_UART_CONTROL_E_MSK 0x0100 /* ...exception*/
  68 +
  69 +#define ALTERA_UART_CONTROL_TRBK_MSK 0x0200 /* TX break */
  70 +#define ALTERA_UART_CONTROL_DCTS_MSK 0x0400 /* Interrupt on CTS change */
  71 +#define ALTERA_UART_CONTROL_RTS_MSK 0x0800 /* RTS signal */
  72 +#define ALTERA_UART_CONTROL_EOP_MSK 0x1000 /* Interrupt on EOP */
  73 +
  74 +/*
  75 + * Local per-uart structure.
  76 + */
  77 +struct altera_uart {
  78 + struct uart_port port;
  79 + unsigned int sigs; /* Local copy of line sigs */
  80 + unsigned short imr; /* Local IMR mirror */
  81 +};
  82 +
  83 +static unsigned int altera_uart_tx_empty(struct uart_port *port)
  84 +{
  85 + return (readl(port->membase + ALTERA_UART_STATUS_REG) &
  86 + ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
  87 +}
  88 +
  89 +static unsigned int altera_uart_get_mctrl(struct uart_port *port)
  90 +{
  91 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  92 + unsigned long flags;
  93 + unsigned int sigs;
  94 +
  95 + spin_lock_irqsave(&port->lock, flags);
  96 + sigs =
  97 + (readl(port->membase + ALTERA_UART_STATUS_REG) &
  98 + ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
  99 + sigs |= (pp->sigs & TIOCM_RTS);
  100 + spin_unlock_irqrestore(&port->lock, flags);
  101 +
  102 + return sigs;
  103 +}
  104 +
  105 +static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
  106 +{
  107 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  108 + unsigned long flags;
  109 +
  110 + spin_lock_irqsave(&port->lock, flags);
  111 + pp->sigs = sigs;
  112 + if (sigs & TIOCM_RTS)
  113 + pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
  114 + else
  115 + pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
  116 + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
  117 + spin_unlock_irqrestore(&port->lock, flags);
  118 +}
  119 +
  120 +static void altera_uart_start_tx(struct uart_port *port)
  121 +{
  122 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  123 + unsigned long flags;
  124 +
  125 + spin_lock_irqsave(&port->lock, flags);
  126 + pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
  127 + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
  128 + spin_unlock_irqrestore(&port->lock, flags);
  129 +}
  130 +
  131 +static void altera_uart_stop_tx(struct uart_port *port)
  132 +{
  133 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  134 + unsigned long flags;
  135 +
  136 + spin_lock_irqsave(&port->lock, flags);
  137 + pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
  138 + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
  139 + spin_unlock_irqrestore(&port->lock, flags);
  140 +}
  141 +
  142 +static void altera_uart_stop_rx(struct uart_port *port)
  143 +{
  144 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  145 + unsigned long flags;
  146 +
  147 + spin_lock_irqsave(&port->lock, flags);
  148 + pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
  149 + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
  150 + spin_unlock_irqrestore(&port->lock, flags);
  151 +}
  152 +
  153 +static void altera_uart_break_ctl(struct uart_port *port, int break_state)
  154 +{
  155 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  156 + unsigned long flags;
  157 +
  158 + spin_lock_irqsave(&port->lock, flags);
  159 + if (break_state == -1)
  160 + pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
  161 + else
  162 + pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
  163 + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
  164 + spin_unlock_irqrestore(&port->lock, flags);
  165 +}
  166 +
  167 +static void altera_uart_enable_ms(struct uart_port *port)
  168 +{
  169 +}
  170 +
  171 +static void altera_uart_set_termios(struct uart_port *port,
  172 + struct ktermios *termios,
  173 + struct ktermios *old)
  174 +{
  175 + unsigned long flags;
  176 + unsigned int baud, baudclk;
  177 +
  178 + baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
  179 + baudclk = port->uartclk / baud;
  180 +
  181 + if (old)
  182 + tty_termios_copy_hw(termios, old);
  183 + tty_termios_encode_baud_rate(termios, baud, baud);
  184 +
  185 + spin_lock_irqsave(&port->lock, flags);
  186 + writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG);
  187 + spin_unlock_irqrestore(&port->lock, flags);
  188 +}
  189 +
  190 +static void altera_uart_rx_chars(struct altera_uart *pp)
  191 +{
  192 + struct uart_port *port = &pp->port;
  193 + unsigned char ch, flag;
  194 + unsigned short status;
  195 +
  196 + while ((status = readl(port->membase + ALTERA_UART_STATUS_REG)) &
  197 + ALTERA_UART_STATUS_RRDY_MSK) {
  198 + ch = readl(port->membase + ALTERA_UART_RXDATA_REG);
  199 + flag = TTY_NORMAL;
  200 + port->icount.rx++;
  201 +
  202 + if (status & ALTERA_UART_STATUS_E_MSK) {
  203 + writel(status, port->membase + ALTERA_UART_STATUS_REG);
  204 +
  205 + if (status & ALTERA_UART_STATUS_BRK_MSK) {
  206 + port->icount.brk++;
  207 + if (uart_handle_break(port))
  208 + continue;
  209 + } else if (status & ALTERA_UART_STATUS_PE_MSK) {
  210 + port->icount.parity++;
  211 + } else if (status & ALTERA_UART_STATUS_ROE_MSK) {
  212 + port->icount.overrun++;
  213 + } else if (status & ALTERA_UART_STATUS_FE_MSK) {
  214 + port->icount.frame++;
  215 + }
  216 +
  217 + status &= port->read_status_mask;
  218 +
  219 + if (status & ALTERA_UART_STATUS_BRK_MSK)
  220 + flag = TTY_BREAK;
  221 + else if (status & ALTERA_UART_STATUS_PE_MSK)
  222 + flag = TTY_PARITY;
  223 + else if (status & ALTERA_UART_STATUS_FE_MSK)
  224 + flag = TTY_FRAME;
  225 + }
  226 +
  227 + if (uart_handle_sysrq_char(port, ch))
  228 + continue;
  229 + uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
  230 + flag);
  231 + }
  232 +
  233 + tty_flip_buffer_push(port->state->port.tty);
  234 +}
  235 +
  236 +static void altera_uart_tx_chars(struct altera_uart *pp)
  237 +{
  238 + struct uart_port *port = &pp->port;
  239 + struct circ_buf *xmit = &port->state->xmit;
  240 +
  241 + if (port->x_char) {
  242 + /* Send special char - probably flow control */
  243 + writel(port->x_char, port->membase + ALTERA_UART_TXDATA_REG);
  244 + port->x_char = 0;
  245 + port->icount.tx++;
  246 + return;
  247 + }
  248 +
  249 + while (readl(port->membase + ALTERA_UART_STATUS_REG) &
  250 + ALTERA_UART_STATUS_TRDY_MSK) {
  251 + if (xmit->head == xmit->tail)
  252 + break;
  253 + writel(xmit->buf[xmit->tail],
  254 + port->membase + ALTERA_UART_TXDATA_REG);
  255 + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
  256 + port->icount.tx++;
  257 + }
  258 +
  259 + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
  260 + uart_write_wakeup(port);
  261 +
  262 + if (xmit->head == xmit->tail) {
  263 + pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
  264 + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
  265 + }
  266 +}
  267 +
  268 +static irqreturn_t altera_uart_interrupt(int irq, void *data)
  269 +{
  270 + struct uart_port *port = data;
  271 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  272 + unsigned int isr;
  273 +
  274 + isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr;
  275 + if (isr & ALTERA_UART_STATUS_RRDY_MSK)
  276 + altera_uart_rx_chars(pp);
  277 + if (isr & ALTERA_UART_STATUS_TRDY_MSK)
  278 + altera_uart_tx_chars(pp);
  279 + return IRQ_RETVAL(isr);
  280 +}
  281 +
  282 +static void altera_uart_config_port(struct uart_port *port, int flags)
  283 +{
  284 + port->type = PORT_ALTERA_UART;
  285 +
  286 + /* Clear mask, so no surprise interrupts. */
  287 + writel(0, port->membase + ALTERA_UART_CONTROL_REG);
  288 + /* Clear status register */
  289 + writel(0, port->membase + ALTERA_UART_STATUS_REG);
  290 +}
  291 +
  292 +static int altera_uart_startup(struct uart_port *port)
  293 +{
  294 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  295 + unsigned long flags;
  296 + int ret;
  297 +
  298 + ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
  299 + DRV_NAME, port);
  300 + if (ret) {
  301 + pr_err(DRV_NAME ": unable to attach Altera UART %d "
  302 + "interrupt vector=%d\n", port->line, port->irq);
  303 + return ret;
  304 + }
  305 +
  306 + spin_lock_irqsave(&port->lock, flags);
  307 +
  308 + /* Enable RX interrupts now */
  309 + pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
  310 + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
  311 +
  312 + spin_unlock_irqrestore(&port->lock, flags);
  313 +
  314 + return 0;
  315 +}
  316 +
  317 +static void altera_uart_shutdown(struct uart_port *port)
  318 +{
  319 + struct altera_uart *pp = container_of(port, struct altera_uart, port);
  320 + unsigned long flags;
  321 +
  322 + spin_lock_irqsave(&port->lock, flags);
  323 +
  324 + /* Disable all interrupts now */
  325 + pp->imr = 0;
  326 + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
  327 +
  328 + spin_unlock_irqrestore(&port->lock, flags);
  329 +
  330 + free_irq(port->irq, port);
  331 +}
  332 +
  333 +static const char *altera_uart_type(struct uart_port *port)
  334 +{
  335 + return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
  336 +}
  337 +
  338 +static int altera_uart_request_port(struct uart_port *port)
  339 +{
  340 + /* UARTs always present */
  341 + return 0;
  342 +}
  343 +
  344 +static void altera_uart_release_port(struct uart_port *port)
  345 +{
  346 + /* Nothing to release... */
  347 +}
  348 +
  349 +static int altera_uart_verify_port(struct uart_port *port,
  350 + struct serial_struct *ser)
  351 +{
  352 + if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
  353 + return -EINVAL;
  354 + return 0;
  355 +}
  356 +
  357 +/*
  358 + * Define the basic serial functions we support.
  359 + */
  360 +static struct uart_ops altera_uart_ops = {
  361 + .tx_empty = altera_uart_tx_empty,
  362 + .get_mctrl = altera_uart_get_mctrl,
  363 + .set_mctrl = altera_uart_set_mctrl,
  364 + .start_tx = altera_uart_start_tx,
  365 + .stop_tx = altera_uart_stop_tx,
  366 + .stop_rx = altera_uart_stop_rx,
  367 + .enable_ms = altera_uart_enable_ms,
  368 + .break_ctl = altera_uart_break_ctl,
  369 + .startup = altera_uart_startup,
  370 + .shutdown = altera_uart_shutdown,
  371 + .set_termios = altera_uart_set_termios,
  372 + .type = altera_uart_type,
  373 + .request_port = altera_uart_request_port,
  374 + .release_port = altera_uart_release_port,
  375 + .config_port = altera_uart_config_port,
  376 + .verify_port = altera_uart_verify_port,
  377 +};
  378 +
  379 +static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
  380 +
  381 +#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
  382 +
  383 +int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
  384 +{
  385 + struct uart_port *port;
  386 + int i;
  387 +
  388 + for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
  389 + port = &altera_uart_ports[i].port;
  390 +
  391 + port->line = i;
  392 + port->type = PORT_ALTERA_UART;
  393 + port->mapbase = platp[i].mapbase;
  394 + port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
  395 + port->iotype = SERIAL_IO_MEM;
  396 + port->irq = platp[i].irq;
  397 + port->uartclk = platp[i].uartclk;
  398 + port->flags = ASYNC_BOOT_AUTOCONF;
  399 + port->ops = &altera_uart_ops;
  400 + }
  401 +
  402 + return 0;
  403 +}
  404 +
  405 +static void altera_uart_console_putc(struct console *co, const char c)
  406 +{
  407 + struct uart_port *port = &(altera_uart_ports + co->index)->port;
  408 + int i;
  409 +
  410 + for (i = 0; i < 0x10000; i++) {
  411 + if (readl(port->membase + ALTERA_UART_STATUS_REG) &
  412 + ALTERA_UART_STATUS_TRDY_MSK)
  413 + break;
  414 + }
  415 + writel(c, port->membase + ALTERA_UART_TXDATA_REG);
  416 + for (i = 0; i < 0x10000; i++) {
  417 + if (readl(port->membase + ALTERA_UART_STATUS_REG) &
  418 + ALTERA_UART_STATUS_TRDY_MSK)
  419 + break;
  420 + }
  421 +}
  422 +
  423 +static void altera_uart_console_write(struct console *co, const char *s,
  424 + unsigned int count)
  425 +{
  426 + for (; count; count--, s++) {
  427 + altera_uart_console_putc(co, *s);
  428 + if (*s == '\n')
  429 + altera_uart_console_putc(co, '\r');
  430 + }
  431 +}
  432 +
  433 +static int __init altera_uart_console_setup(struct console *co, char *options)
  434 +{
  435 + struct uart_port *port;
  436 + int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
  437 + int bits = 8;
  438 + int parity = 'n';
  439 + int flow = 'n';
  440 +
  441 + if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
  442 + return -EINVAL;
  443 + port = &altera_uart_ports[co->index].port;
  444 + if (port->membase == 0)
  445 + return -ENODEV;
  446 +
  447 + if (options)
  448 + uart_parse_options(options, &baud, &parity, &bits, &flow);
  449 +
  450 + return uart_set_options(port, co, baud, parity, bits, flow);
  451 +}
  452 +
  453 +static struct uart_driver altera_uart_driver;
  454 +
  455 +static struct console altera_uart_console = {
  456 + .name = "ttyS",
  457 + .write = altera_uart_console_write,
  458 + .device = uart_console_device,
  459 + .setup = altera_uart_console_setup,
  460 + .flags = CON_PRINTBUFFER,
  461 + .index = -1,
  462 + .data = &altera_uart_driver,
  463 +};
  464 +
  465 +static int __init altera_uart_console_init(void)
  466 +{
  467 + register_console(&altera_uart_console);
  468 + return 0;
  469 +}
  470 +
  471 +console_initcall(altera_uart_console_init);
  472 +
  473 +#define ALTERA_UART_CONSOLE (&altera_uart_console)
  474 +
  475 +#else
  476 +
  477 +#define ALTERA_UART_CONSOLE NULL
  478 +
  479 +#endif /* CONFIG_ALTERA_UART_CONSOLE */
  480 +
  481 +/*
  482 + * Define the altera_uart UART driver structure.
  483 + */
  484 +static struct uart_driver altera_uart_driver = {
  485 + .owner = THIS_MODULE,
  486 + .driver_name = DRV_NAME,
  487 + .dev_name = "ttyS",
  488 + .major = TTY_MAJOR,
  489 + .minor = 64,
  490 + .nr = CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
  491 + .cons = ALTERA_UART_CONSOLE,
  492 +};
  493 +
  494 +static int __devinit altera_uart_probe(struct platform_device *pdev)
  495 +{
  496 + struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
  497 + struct uart_port *port;
  498 + int i;
  499 +
  500 + for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
  501 + port = &altera_uart_ports[i].port;
  502 +
  503 + port->line = i;
  504 + port->type = PORT_ALTERA_UART;
  505 + port->mapbase = platp[i].mapbase;
  506 + port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
  507 + port->iotype = SERIAL_IO_MEM;
  508 + port->irq = platp[i].irq;
  509 + port->uartclk = platp[i].uartclk;
  510 + port->ops = &altera_uart_ops;
  511 + port->flags = ASYNC_BOOT_AUTOCONF;
  512 +
  513 + uart_add_one_port(&altera_uart_driver, port);
  514 + }
  515 +
  516 + return 0;
  517 +}
  518 +
  519 +static int altera_uart_remove(struct platform_device *pdev)
  520 +{
  521 + struct uart_port *port;
  522 + int i;
  523 +
  524 + for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS; i++) {
  525 + port = &altera_uart_ports[i].port;
  526 + if (port)
  527 + uart_remove_one_port(&altera_uart_driver, port);
  528 + }
  529 +
  530 + return 0;
  531 +}
  532 +
  533 +static struct platform_driver altera_uart_platform_driver = {
  534 + .probe = altera_uart_probe,
  535 + .remove = __devexit_p(altera_uart_remove),
  536 + .driver = {
  537 + .name = DRV_NAME,
  538 + .owner = THIS_MODULE,
  539 + .pm = NULL,
  540 + },
  541 +};
  542 +
  543 +static int __init altera_uart_init(void)
  544 +{
  545 + int rc;
  546 +
  547 + rc = uart_register_driver(&altera_uart_driver);
  548 + if (rc)
  549 + return rc;
  550 + rc = platform_driver_register(&altera_uart_platform_driver);
  551 + if (rc) {
  552 + uart_unregister_driver(&altera_uart_driver);
  553 + return rc;
  554 + }
  555 + return 0;
  556 +}
  557 +
  558 +static void __exit altera_uart_exit(void)
  559 +{
  560 + platform_driver_unregister(&altera_uart_platform_driver);
  561 + uart_unregister_driver(&altera_uart_driver);
  562 +}
  563 +
  564 +module_init(altera_uart_init);
  565 +module_exit(altera_uart_exit);
  566 +
  567 +MODULE_DESCRIPTION("Altera UART driver");
  568 +MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
  569 +MODULE_LICENSE("GPL");
  570 +MODULE_ALIAS("platform:" DRV_NAME);
include/linux/altera_uart.h
  1 +/*
  2 + * altera_uart.h -- Altera UART driver defines.
  3 + */
  4 +
  5 +#ifndef __ALTUART_H
  6 +#define __ALTUART_H
  7 +
  8 +struct altera_uart_platform_uart {
  9 + unsigned long mapbase; /* Physical address base */
  10 + unsigned int irq; /* Interrupt vector */
  11 + unsigned int uartclk; /* UART clock rate */
  12 +};
  13 +
  14 +#endif /* __ALTUART_H */
include/linux/serial_core.h
... ... @@ -184,6 +184,7 @@
184 184  
185 185 /* Altera UARTs */
186 186 #define PORT_ALTERA_JTAGUART 91
  187 +#define PORT_ALTERA_UART 92
187 188  
188 189 #ifdef __KERNEL__
189 190