aboutsummaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/8250.c24
-rw-r--r--drivers/serial/8250_pnp.c4
-rw-r--r--drivers/serial/Kconfig15
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/apbuart.c710
-rw-r--r--drivers/serial/apbuart.h64
-rw-r--r--drivers/serial/jsm/jsm.h8
-rw-r--r--drivers/serial/jsm/jsm_driver.c48
-rw-r--r--drivers/serial/jsm/jsm_neo.c8
-rw-r--r--drivers/serial/jsm/jsm_tty.c6
-rw-r--r--drivers/serial/mcf.c2
-rw-r--r--drivers/serial/pmac_zilog.h2
-rw-r--r--drivers/serial/pxa.c13
-rw-r--r--drivers/serial/s3c2410.c2
-rw-r--r--drivers/serial/s3c2412.c2
-rw-r--r--drivers/serial/s3c2440.c2
-rw-r--r--drivers/serial/s3c24a0.c2
-rw-r--r--drivers/serial/samsung.c2
-rw-r--r--drivers/serial/samsung.h2
-rw-r--r--drivers/serial/serial_core.c33
-rw-r--r--drivers/serial/serial_cs.c143
-rw-r--r--drivers/serial/sh-sci.c59
-rw-r--r--drivers/serial/sh-sci.h2
-rw-r--r--drivers/serial/ucc_uart.c10
24 files changed, 940 insertions, 224 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 737b4c96097..c3e37c8e7e2 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1339,14 +1339,12 @@ static void serial8250_start_tx(struct uart_port *port)
serial_out(up, UART_IER, up->ier);
if (up->bugs & UART_BUG_TXEN) {
- unsigned char lsr, iir;
+ unsigned char lsr;
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
- iir = serial_in(up, UART_IIR) & 0x0f;
if ((up->port.type == PORT_RM9000) ?
- (lsr & UART_LSR_THRE &&
- (iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) :
- (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT))
+ (lsr & UART_LSR_THRE) :
+ (lsr & UART_LSR_TEMT))
transmit_chars(up);
}
}
@@ -2646,7 +2644,7 @@ static void __init serial8250_isa_init_ports(void)
{
struct uart_8250_port *up;
static int first = 1;
- int i;
+ int i, irqflag = 0;
if (!first)
return;
@@ -2670,6 +2668,9 @@ static void __init serial8250_isa_init_ports(void)
up->port.ops = &serial8250_pops;
}
+ if (share_irqs)
+ irqflag = IRQF_SHARED;
+
for (i = 0, up = serial8250_ports;
i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
i++, up++) {
@@ -2683,8 +2684,7 @@ static void __init serial8250_isa_init_ports(void)
up->port.iotype = old_serial_port[i].io_type;
up->port.regshift = old_serial_port[i].iomem_reg_shift;
set_io_from_upio(&up->port);
- if (share_irqs)
- up->port.irqflags |= IRQF_SHARED;
+ up->port.irqflags |= irqflag;
}
}
@@ -2940,10 +2940,13 @@ static int __devinit serial8250_probe(struct platform_device *dev)
{
struct plat_serial8250_port *p = dev->dev.platform_data;
struct uart_port port;
- int ret, i;
+ int ret, i, irqflag = 0;
memset(&port, 0, sizeof(struct uart_port));
+ if (share_irqs)
+ irqflag = IRQF_SHARED;
+
for (i = 0; p && p->flags != 0; p++, i++) {
port.iobase = p->iobase;
port.membase = p->membase;
@@ -2960,8 +2963,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
port.dev = &dev->dev;
- if (share_irqs)
- port.irqflags |= IRQF_SHARED;
+ port.irqflags |= irqflag;
ret = serial8250_register_port(&port);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index d71dfe39894..36ede02ceac 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -361,9 +361,9 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "LTS0001", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
- /* Unkown PnP modems */
+ /* Unknown PnP modems */
{ "PNPCXXX", UNKNOWN_DEV },
- /* More unkown PnP modems */
+ /* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
{ "", 0 }
};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index e5225725727..9ff47db0b2c 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -996,7 +996,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support"
- depends on SUPERH || H8300
+ depends on HAVE_CLK && (SUPERH || H8300)
select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS
@@ -1477,4 +1477,17 @@ config SERIAL_BCM63XX_CONSOLE
If you have enabled the serial port on the bcm63xx CPU
you can make it the console by answering Y to this option.
+config SERIAL_GRLIB_GAISLER_APBUART
+ tristate "GRLIB APBUART serial support"
+ depends on OF
+ ---help---
+ Add support for the GRLIB APBUART serial port.
+
+config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
+ bool "Console on GRLIB APBUART serial port"
+ depends on SERIAL_GRLIB_GAISLER_APBUART=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Support for running a console on the GRLIB APBUART
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index d21d5dd5d04..5548fe7df61 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -81,3 +81,4 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
+obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
new file mode 100644
index 00000000000..fe91319b5f6
--- /dev/null
+++ b/drivers/serial/apbuart.c
@@ -0,0 +1,710 @@
+/*
+ * Driver for GRLIB serial ports (APBUART)
+ *
+ * Based on linux/drivers/serial/amba.c
+ *
+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
+ * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
+ * Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
+ * Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
+ * Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
+ */
+
+#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+#include <asm/irq.h>
+
+#include "apbuart.h"
+
+#define SERIAL_APBUART_MAJOR TTY_MAJOR
+#define SERIAL_APBUART_MINOR 64
+#define UART_DUMMY_RSR_RX 0x8000 /* for ignore all read */
+
+static void apbuart_tx_chars(struct uart_port *port);
+
+static void apbuart_stop_tx(struct uart_port *port)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CTRL(port);
+ cr &= ~UART_CTRL_TI;
+ UART_PUT_CTRL(port, cr);
+}
+
+static void apbuart_start_tx(struct uart_port *port)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CTRL(port);
+ cr |= UART_CTRL_TI;
+ UART_PUT_CTRL(port, cr);
+
+ if (UART_GET_STATUS(port) & UART_STATUS_THE)
+ apbuart_tx_chars(port);
+}
+
+static void apbuart_stop_rx(struct uart_port *port)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CTRL(port);
+ cr &= ~(UART_CTRL_RI);
+ UART_PUT_CTRL(port, cr);
+}
+
+static void apbuart_enable_ms(struct uart_port *port)
+{
+ /* No modem status change interrupts for APBUART */
+}
+
+static void apbuart_rx_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = port->state->port.tty;
+ unsigned int status, ch, rsr, flag;
+ unsigned int max_chars = port->fifosize;
+
+ status = UART_GET_STATUS(port);
+
+ while (UART_RX_DATA(status) && (max_chars--)) {
+
+ ch = UART_GET_CHAR(port);
+ flag = TTY_NORMAL;
+
+ port->icount.rx++;
+
+ rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
+ UART_PUT_STATUS(port, 0);
+ if (rsr & UART_STATUS_ERR) {
+
+ if (rsr & UART_STATUS_BR) {
+ rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ goto ignore_char;
+ } else if (rsr & UART_STATUS_PE) {
+ port->icount.parity++;
+ } else if (rsr & UART_STATUS_FE) {
+ port->icount.frame++;
+ }
+ if (rsr & UART_STATUS_OE)
+ port->icount.overrun++;
+
+ rsr &= port->read_status_mask;
+
+ if (rsr & UART_STATUS_PE)
+ flag = TTY_PARITY;
+ else if (rsr & UART_STATUS_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
+
+
+ ignore_char:
+ status = UART_GET_STATUS(port);
+ }
+
+ tty_flip_buffer_push(tty);
+}
+
+static void apbuart_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ int count;
+
+ if (port->x_char) {
+ UART_PUT_CHAR(port, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ apbuart_stop_tx(port);
+ return;
+ }
+
+ /* amba: fill FIFO */
+ count = port->fifosize >> 1;
+ do {
+ UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ apbuart_stop_tx(port);
+}
+
+static irqreturn_t apbuart_int(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ unsigned int status;
+
+ spin_lock(&port->lock);
+
+ status = UART_GET_STATUS(port);
+ if (status & UART_STATUS_DR)
+ apbuart_rx_chars(port);
+ if (status & UART_STATUS_THE)
+ apbuart_tx_chars(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int apbuart_tx_empty(struct uart_port *port)
+{
+ unsigned int status = UART_GET_STATUS(port);
+ return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int apbuart_get_mctrl(struct uart_port *port)
+{
+ /* The GRLIB APBUART handles flow control in hardware */
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* The GRLIB APBUART handles flow control in hardware */
+}
+
+static void apbuart_break_ctl(struct uart_port *port, int break_state)
+{
+ /* We don't support sending break */
+}
+
+static int apbuart_startup(struct uart_port *port)
+{
+ int retval;
+ unsigned int cr;
+
+ /* Allocate the IRQ */
+ retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
+ if (retval)
+ return retval;
+
+ /* Finally, enable interrupts */
+ cr = UART_GET_CTRL(port);
+ UART_PUT_CTRL(port,
+ cr | UART_CTRL_RE | UART_CTRL_TE |
+ UART_CTRL_RI | UART_CTRL_TI);
+
+ return 0;
+}
+
+static void apbuart_shutdown(struct uart_port *port)
+{
+ unsigned int cr;
+
+ /* disable all interrupts, disable the port */
+ cr = UART_GET_CTRL(port);
+ UART_PUT_CTRL(port,
+ cr & ~(UART_CTRL_RE | UART_CTRL_TE |
+ UART_CTRL_RI | UART_CTRL_TI));
+
+ /* Free the interrupt */
+ free_irq(port->irq, port);
+}
+
+static void apbuart_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ unsigned int cr;
+ unsigned long flags;
+ unsigned int baud, quot;
+
+ /* Ask the core to calculate the divisor for us. */
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+ if (baud == 0)
+ panic("invalid baudrate %i\n", port->uartclk / 16);
+
+ /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
+ quot = (uart_get_divisor(port, baud)) * 2;
+ cr = UART_GET_CTRL(port);
+ cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
+
+ if (termios->c_cflag & PARENB) {
+ cr |= UART_CTRL_PE;
+ if ((termios->c_cflag & PARODD))
+ cr |= UART_CTRL_PS;
+ }
+
+ /* Enable flow control. */
+ if (termios->c_cflag & CRTSCTS)
+ cr |= UART_CTRL_FL;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Update the per-port timeout. */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ port->read_status_mask = UART_STATUS_OE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
+
+ /* Characters to ignore */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
+
+ /* Ignore all characters if CREAD is not set. */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_DUMMY_RSR_RX;
+
+ /* Set baud rate */
+ quot -= 1;
+ UART_PUT_SCAL(port, quot);
+ UART_PUT_CTRL(port, cr);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *apbuart_type(struct uart_port *port)
+{
+ return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
+}
+
+static void apbuart_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, 0x100);
+}
+
+static int apbuart_request_port(struct uart_port *port)
+{
+ return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
+ != NULL ? 0 : -EBUSY;
+ return 0;
+}
+
+/* Configure/autoconfigure the port */
+static void apbuart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_APBUART;
+ apbuart_request_port(port);
+ }
+}
+
+/* Verify the new serial_struct (for TIOCSSERIAL) */
+static int apbuart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
+ ret = -EINVAL;
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops grlib_apbuart_ops = {
+ .tx_empty = apbuart_tx_empty,
+ .set_mctrl = apbuart_set_mctrl,
+ .get_mctrl = apbuart_get_mctrl,
+ .stop_tx = apbuart_stop_tx,
+ .start_tx = apbuart_start_tx,
+ .stop_rx = apbuart_stop_rx,
+ .enable_ms = apbuart_enable_ms,
+ .break_ctl = apbuart_break_ctl,
+ .startup = apbuart_startup,
+ .shutdown = apbuart_shutdown,
+ .set_termios = apbuart_set_termios,
+ .type = apbuart_type,
+ .release_port = apbuart_release_port,
+ .request_port = apbuart_request_port,
+ .config_port = apbuart_config_port,
+ .verify_port = apbuart_verify_port,
+};
+
+static struct uart_port grlib_apbuart_ports[UART_NR];
+static struct device_node *grlib_apbuart_nodes[UART_NR];
+
+static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
+{
+ int ctrl, loop = 0;
+ int status;
+ int fifosize;
+ unsigned long flags;
+
+ ctrl = UART_GET_CTRL(port);
+
+ /*
+ * Enable the transceiver and wait for it to be ready to send data.
+ * Clear interrupts so that this process will not be externally
+ * interrupted in the middle (which can cause the transceiver to
+ * drain prematurely).
+ */
+
+ local_irq_save(flags);
+
+ UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
+
+ while (!UART_TX_READY(UART_GET_STATUS(port)))
+ loop++;
+
+ /*
+ * Disable the transceiver so data isn't actually sent during the
+ * actual test.
+ */
+
+ UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
+
+ fifosize = 1;
+ UART_PUT_CHAR(port, 0);
+
+ /*
+ * So long as transmitting a character increments the tranceivier FIFO
+ * length the FIFO must be at least that big. These bytes will
+ * automatically drain off of the FIFO.
+ */
+
+ status = UART_GET_STATUS(port);
+ while (((status >> 20) & 0x3F) == fifosize) {
+ fifosize++;
+ UART_PUT_CHAR(port, 0);
+ status = UART_GET_STATUS(port);
+ }
+
+ fifosize--;
+
+ UART_PUT_CTRL(port, ctrl);
+ local_irq_restore(flags);
+
+ if (fifosize == 0)
+ fifosize = 1;
+
+ return fifosize;
+}
+
+static void apbuart_flush_fifo(struct uart_port *port)
+{
+ int i;
+
+ for (i = 0; i < port->fifosize; i++)
+ UART_GET_CHAR(port);
+}
+
+
+/* ======================================================================== */
+/* Console driver, if enabled */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
+
+static void apbuart_console_putchar(struct uart_port *port, int ch)
+{
+ unsigned int status;
+ do {
+ status = UART_GET_STATUS(port);
+ } while (!UART_TX_READY(status));
+ UART_PUT_CHAR(port, ch);
+}
+
+static void
+apbuart_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = &grlib_apbuart_ports[co->index];
+ unsigned int status, old_cr, new_cr;
+
+ /* First save the CR then disable the interrupts */
+ old_cr = UART_GET_CTRL(port);
+ new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
+ UART_PUT_CTRL(port, new_cr);
+
+ uart_console_write(port, s, count, apbuart_console_putchar);
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the TCR
+ */
+ do {
+ status = UART_GET_STATUS(port);
+ } while (!UART_TX_READY(status));
+ UART_PUT_CTRL(port, old_cr);
+}
+
+static void __init
+apbuart_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
+
+ unsigned int quot, status;
+ status = UART_GET_STATUS(port);
+
+ *parity = 'n';
+ if (status & UART_CTRL_PE) {
+ if ((status & UART_CTRL_PS) == 0)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ *bits = 8;
+ quot = UART_GET_SCAL(port) / 8;
+ *baud = port->uartclk / (16 * (quot + 1));
+ }
+}
+
+static int __init apbuart_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 38400;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
+ co, co->index, options);
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index >= grlib_apbuart_port_nr)
+ co->index = 0;
+
+ port = &grlib_apbuart_ports[co->index];
+
+ spin_lock_init(&port->lock);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ apbuart_console_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver grlib_apbuart_driver;
+
+static struct console grlib_apbuart_console = {
+ .name = "ttyS",
+ .write = apbuart_console_write,
+ .device = uart_console_device,
+ .setup = apbuart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &grlib_apbuart_driver,
+};
+
+
+static void grlib_apbuart_configure(void);
+
+static int __init apbuart_console_init(void)
+{
+ grlib_apbuart_configure();
+ register_console(&grlib_apbuart_console);
+ return 0;
+}
+
+console_initcall(apbuart_console_init);
+
+#define APBUART_CONSOLE (&grlib_apbuart_console)
+#else
+#define APBUART_CONSOLE NULL
+#endif
+
+static struct uart_driver grlib_apbuart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial",
+ .dev_name = "ttyS",
+ .major = SERIAL_APBUART_MAJOR,
+ .minor = SERIAL_APBUART_MINOR,
+ .nr = UART_NR,
+ .cons = APBUART_CONSOLE,
+};
+
+
+/* ======================================================================== */
+/* OF Platform Driver */
+/* ======================================================================== */
+
+static int __devinit apbuart_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ int i = -1;
+ struct uart_port *port = NULL;
+
+ i = 0;
+ for (i = 0; i < grlib_apbuart_port_nr; i++) {
+ if (op->node == grlib_apbuart_nodes[i])
+ break;
+ }
+
+ port = &grlib_apbuart_ports[i];
+ port->dev = &op->dev;
+
+ uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
+
+ apbuart_flush_fifo((struct uart_port *) port);
+
+ printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
+ (unsigned long long) port->mapbase, port->irq);
+ return 0;
+
+}
+
+static struct of_device_id __initdata apbuart_match[] = {
+ {
+ .name = "GAISLER_APBUART",
+ },
+ {},
+};
+
+static struct of_platform_driver grlib_apbuart_of_driver = {
+ .match_table = apbuart_match,
+ .probe = apbuart_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "grlib-apbuart",
+ },
+};
+
+
+static void grlib_apbuart_configure(void)
+{
+ static int enum_done;
+ struct device_node *np, *rp;
+ struct uart_port *port = NULL;
+ const u32 *prop;
+ int freq_khz;
+ int v = 0, d = 0;
+ unsigned int addr;
+ int irq, line;
+ struct amba_prom_registers *regs;
+
+ if (enum_done)
+ return;
+
+ /* Get bus frequency */
+ rp = of_find_node_by_path("/");
+ rp = of_get_next_child(rp, NULL);
+ prop = of_get_property(rp, "clock-frequency", NULL);
+ freq_khz = *prop;
+
+ line = 0;
+ for_each_matching_node(np, apbuart_match) {
+
+ int *vendor = (int *) of_get_property(np, "vendor", NULL);
+ int *device = (int *) of_get_property(np, "device", NULL);
+ int *irqs = (int *) of_get_property(np, "interrupts", NULL);
+ regs = (struct amba_prom_registers *)
+ of_get_property(np, "reg", NULL);
+
+ if (vendor)
+ v = *vendor;
+ if (device)
+ d = *device;
+
+ if (!irqs || !regs)
+ return;
+
+ grlib_apbuart_nodes[line] = np;
+
+ addr = regs->phys_addr;
+ irq = *irqs;
+
+ port = &grlib_apbuart_ports[line];
+
+ port->mapbase = addr;
+ port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
+ port->irq = irq;
+ port->iotype = UPIO_MEM;
+ port->ops = &grlib_apbuart_ops;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->line = line;
+ port->uartclk = freq_khz * 1000;
+ port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
+ line++;
+
+ /* We support maximum UART_NR uarts ... */
+ if (line == UART_NR)
+ break;
+
+ }
+
+ enum_done = 1;
+
+ grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
+}
+
+static int __init grlib_apbuart_init(void)
+{
+ int ret;
+
+ /* Find all APBUARTS in device the tree and initialize their ports */
+ grlib_apbuart_configure();
+
+ printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
+
+ ret = uart_register_driver(&grlib_apbuart_driver);
+
+ if (ret) {
+ printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
+ __FILE__, ret);
+ return ret;
+ }
+
+ ret = of_register_platform_driver(&grlib_apbuart_of_driver);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: of_register_platform_driver failed (%i)\n",
+ __FILE__, ret);
+ uart_unregister_driver(&grlib_apbuart_driver);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void __exit grlib_apbuart_exit(void)
+{
+ int i;
+
+ for (i = 0; i < grlib_apbuart_port_nr; i++)
+ uart_remove_one_port(&grlib_apbuart_driver,
+ &grlib_apbuart_ports[i]);
+
+ uart_unregister_driver(&grlib_apbuart_driver);
+ of_unregister_platform_driver(&grlib_apbuart_of_driver);
+}
+
+module_init(grlib_apbuart_init);
+module_exit(grlib_apbuart_exit);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB");
+MODULE_DESCRIPTION("GRLIB APBUART serial driver");
+MODULE_VERSION("2.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/apbuart.h b/drivers/serial/apbuart.h
new file mode 100644
index 00000000000..5faf87c8d2b
--- /dev/null
+++ b/drivers/serial/apbuart.h
@@ -0,0 +1,64 @@
+#ifndef __GRLIB_APBUART_H__
+#define __GRLIB_APBUART_H__
+
+#include <asm/io.h>
+
+#define UART_NR 8
+static int grlib_apbuart_port_nr;
+
+struct grlib_apbuart_regs_map {
+ u32 data;
+ u32 status;
+ u32 ctrl;
+ u32 scaler;
+};
+
+struct amba_prom_registers {
+ unsigned int phys_addr;
+ unsigned int reg_size;
+};
+
+/*
+ * The following defines the bits in the APBUART Status Registers.
+ */
+#define UART_STATUS_DR 0x00000001 /* Data Ready */
+#define UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
+#define UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
+#define UART_STATUS_BR 0x00000008 /* Break Error */
+#define UART_STATUS_OE 0x00000010 /* RX Overrun Error */
+#define UART_STATUS_PE 0x00000020 /* RX Parity Error */
+#define UART_STATUS_FE 0x00000040 /* RX Framing Error */
+#define UART_STATUS_ERR 0x00000078 /* Error Mask */
+
+/*
+ * The following defines the bits in the APBUART Ctrl Registers.
+ */
+#define UART_CTRL_RE 0x00000001 /* Receiver enable */
+#define UART_CTRL_TE 0x00000002 /* Transmitter enable */
+#define UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */
+#define UART_CTRL_TI 0x00000008 /* Transmitter irq */
+#define UART_CTRL_PS 0x00000010 /* Parity select */
+#define UART_CTRL_PE 0x00000020 /* Parity enable */
+#define UART_CTRL_FL 0x00000040 /* Flow control enable */
+#define UART_CTRL_LB 0x00000080 /* Loopback enable */
+
+#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase))
+
+#define APBBASE_DATA_P(port) (&(APBBASE(port)->data))
+#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
+#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl))
+#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
+
+#define UART_GET_CHAR(port) (__raw_readl(APBBASE_DATA_P(port)))
+#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port)))
+#define UART_GET_STATUS(port) (__raw_readl(APBBASE_STATUS_P(port)))
+#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port)))
+#define UART_GET_CTRL(port) (__raw_readl(APBBASE_CTRL_P(port)))
+#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port)))
+#define UART_GET_SCAL(port) (__raw_readl(APBBASE_SCALAR_P(port)))
+#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port)))
+
+#define UART_RX_DATA(s) (((s) & UART_STATUS_DR) != 0)
+#define UART_TX_READY(s) (((s) & UART_STATUS_THE) != 0)
+
+#endif /* __GRLIB_APBUART_H__ */
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index 4e5f3bde046..38a509c684c 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -138,7 +138,6 @@ struct jsm_board
u32 nasync; /* Number of ports on card */
u32 irq; /* Interrupt request number */
- u64 intr_count; /* Count of interrupts */
u64 membase; /* Start of base memory of the card */
u64 membase_end; /* End of base memory of the card */
@@ -206,8 +205,6 @@ struct jsm_channel {
u64 ch_close_delay; /* How long we should drop RTS/DTR for */
- u64 ch_cpstime; /* Time for CPS calculations */
-
tcflag_t ch_c_iflag; /* channel iflags */
tcflag_t ch_c_cflag; /* channel cflags */
tcflag_t ch_c_oflag; /* channel oflags */
@@ -215,11 +212,6 @@ struct jsm_channel {
u8 ch_stopc; /* Stop character */
u8 ch_startc; /* Start character */
- u32 ch_old_baud; /* Cache of the current baud */
- u32 ch_custom_speed;/* Custom baud, if set */
-
- u32 ch_wopen; /* Waiting for open process cnt */
-
u8 ch_mostat; /* FEP output modem status */
u8 ch_mistat; /* FEP input modem status */
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index b3604aa322a..108c3e0471f 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -48,6 +48,17 @@ struct uart_driver jsm_uart_driver = {
.nr = NR_PORTS,
};
+static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
+static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
+static void jsm_io_resume(struct pci_dev *pdev);
+
+static struct pci_error_handlers jsm_err_handler = {
+ .error_detected = jsm_io_error_detected,
+ .slot_reset = jsm_io_slot_reset,
+ .resume = jsm_io_resume,
+};
+
int jsm_debug;
module_param(jsm_debug, int, 0);
MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
@@ -123,7 +134,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
}
rc = request_irq(brd->irq, brd->bd_ops->intr,
- IRQF_DISABLED|IRQF_SHARED, "JSM", brd);
+ IRQF_SHARED, "JSM", brd);
if (rc) {
printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
goto out_iounmap;
@@ -164,6 +175,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
}
pci_set_drvdata(pdev, brd);
+ pci_save_state(pdev);
return 0;
out_free_irq:
@@ -222,8 +234,42 @@ static struct pci_driver jsm_driver = {
.id_table = jsm_pci_tbl,
.probe = jsm_probe_one,
.remove = __devexit_p(jsm_remove_one),
+ .err_handler = &jsm_err_handler,
};
+static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct jsm_board *brd = pci_get_drvdata(pdev);
+
+ jsm_remove_uart_port(brd);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
+{
+ int rc;
+
+ rc = pci_enable_device(pdev);
+
+ if (rc)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ pci_set_master(pdev);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void jsm_io_resume(struct pci_dev *pdev)
+{
+ struct jsm_board *brd = pci_get_drvdata(pdev);
+
+ pci_restore_state(pdev);
+
+ jsm_uart_port_init(brd);
+}
+
static int __init jsm_init_module(void)
{
int rc;
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index b4b124e4828..7960d9633c1 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -954,13 +954,8 @@ static void neo_param(struct jsm_channel *ch)
ch->ch_flags |= (CH_BAUD0);
ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
neo_assert_modem_signals(ch);
- ch->ch_old_baud = 0;
return;
- } else if (ch->ch_custom_speed) {
- baud = ch->ch_custom_speed;
- if (ch->ch_flags & CH_BAUD0)
- ch->ch_flags &= ~(CH_BAUD0);
} else {
int i;
unsigned int cflag;
@@ -1045,7 +1040,6 @@ static void neo_param(struct jsm_channel *ch)
quot = ch->ch_bd->bd_dividend / baud;
if (quot != 0) {
- ch->ch_old_baud = baud;
writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
writeb((quot >> 8), &ch->ch_neo_uart->ier);
@@ -1123,8 +1117,6 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
unsigned long lock_flags2;
int outofloop_count = 0;
- brd->intr_count++;
-
/* Lock out the slow poller from running on this board. */
spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 7439c037362..cd95e215550 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -296,8 +296,6 @@ static void jsm_tty_close(struct uart_port *port)
bd->bd_ops->assert_modem_signals(channel);
}
- channel->ch_old_baud = 0;
-
/* Turn off UART interrupts for this port */
channel->ch_bd->bd_ops->uart_off(channel);
@@ -432,7 +430,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
return 0;
}
-int __devinit jsm_uart_port_init(struct jsm_board *brd)
+int jsm_uart_port_init(struct jsm_board *brd)
{
int i;
unsigned int line;
@@ -472,7 +470,7 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd)
if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
printk(KERN_INFO "jsm: add device failed\n");
else
- printk(KERN_INFO "Added device \n");
+ printk(KERN_INFO "jsm: Port %d added\n", i);
}
jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
index b44382442bf..7bb5fee639e 100644
--- a/drivers/serial/mcf.c
+++ b/drivers/serial/mcf.c
@@ -602,7 +602,7 @@ static int __devinit mcf_probe(struct platform_device *pdev)
/****************************************************************************/
-static int mcf_remove(struct platform_device *pdev)
+static int __devexit mcf_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
diff --git a/drivers/serial/pmac_zilog.h b/drivers/serial/pmac_zilog.h
index 570b0d925e8..f6e77f12acd 100644
--- a/drivers/serial/pmac_zilog.h
+++ b/drivers/serial/pmac_zilog.h
@@ -73,7 +73,7 @@ static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap)
}
/*
- * Register acessors. Note that we don't need to enforce a recovery
+ * Register accessors. Note that we don't need to enforce a recovery
* delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip,
* though if we try to use this driver on older machines, we might have
* to add it back
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index b8629d74f6a..4a821046baa 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -438,6 +438,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
+ unsigned int dll;
switch (termios->c_cflag & CSIZE) {
case CS5:
@@ -534,10 +535,18 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
else
up->mcr &= ~UART_MCR_AFE;
- serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+ serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
+
+ /*
+ * work around Errata #75 according to Intel(R) PXA27x Processor Family
+ * Specification Update (Nov 2005)
+ */
+ dll = serial_in(up, UART_DLL);
+ WARN_ON(dll != (quot & 0xff));
+
serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
- serial_out(up, UART_LCR, cval); /* reset DLAB */
+ serial_out(up, UART_LCR, cval); /* reset DLAB */
up->lcr = cval; /* Save LCR */
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
serial_out(up, UART_FCR, fcr);
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index c99f0821cae..73f089d3efd 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -2,7 +2,7 @@
*
* Driver for Samsung S3C2410 SoC onboard UARTs.
*
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c
index 6e057d8809d..ce75e28e36e 100644
--- a/drivers/serial/s3c2412.c
+++ b/drivers/serial/s3c2412.c
@@ -2,7 +2,7 @@
*
* Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs.
*
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c
index 69ff5d340f0..094cc3904b1 100644
--- a/drivers/serial/s3c2440.c
+++ b/drivers/serial/s3c2440.c
@@ -2,7 +2,7 @@
*
* Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs.
*
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c
index 26c49e18bdd..fad6083ca42 100644
--- a/drivers/serial/s3c24a0.c
+++ b/drivers/serial/s3c24a0.c
@@ -6,7 +6,7 @@
*
* Author: Sandeep Patil <sandeep.patil@azingo.com>
*
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
index 1523e8d9ae7..52e3df113ec 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/serial/samsung.c
@@ -2,7 +2,7 @@
*
* Driver core for Samsung SoC onboard UARTs.
*
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h
index d3fe315969f..1fb22343df4 100644
--- a/drivers/serial/samsung.h
+++ b/drivers/serial/samsung.h
@@ -2,7 +2,7 @@
*
* Driver for Samsung SoC onboard UARTs.
*
- * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index dcc72444e8e..047530b285b 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -342,11 +342,11 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
if (flags == UPF_SPD_HI)
altbaud = 57600;
- if (flags == UPF_SPD_VHI)
+ else if (flags == UPF_SPD_VHI)
altbaud = 115200;
- if (flags == UPF_SPD_SHI)
+ else if (flags == UPF_SPD_SHI)
altbaud = 230400;
- if (flags == UPF_SPD_WARP)
+ else if (flags == UPF_SPD_WARP)
altbaud = 460800;
for (try = 0; try < 2; try++) {
@@ -1217,9 +1217,8 @@ static void uart_set_termios(struct tty_struct *tty,
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
-
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+ else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
unsigned int mask = TIOCM_DTR;
if (!(cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags))
@@ -1234,9 +1233,8 @@ static void uart_set_termios(struct tty_struct *tty,
__uart_start(tty);
spin_unlock_irqrestore(&state->uart_port->lock, flags);
}
-
/* Handle turning on CRTSCTS */
- if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+ else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
spin_lock_irqsave(&state->uart_port->lock, flags);
if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
tty->hw_stopped = 1;
@@ -2344,7 +2342,7 @@ static const struct tty_operations uart_ops = {
*/
int uart_register_driver(struct uart_driver *drv)
{
- struct tty_driver *normal = NULL;
+ struct tty_driver *normal;
int i, retval;
BUG_ON(drv->state);
@@ -2354,13 +2352,12 @@ int uart_register_driver(struct uart_driver *drv)
* we have a large number of ports to handle.
*/
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
- retval = -ENOMEM;
if (!drv->state)
goto out;
- normal = alloc_tty_driver(drv->nr);
+ normal = alloc_tty_driver(drv->nr);
if (!normal)
- goto out;
+ goto out_kfree;
drv->tty_driver = normal;
@@ -2393,12 +2390,14 @@ int uart_register_driver(struct uart_driver *drv)
}
retval = tty_register_driver(normal);
- out:
- if (retval < 0) {
- put_tty_driver(normal);
- kfree(drv->state);
- }
- return retval;
+ if (retval >= 0)
+ return retval;
+
+ put_tty_driver(normal);
+out_kfree:
+ kfree(drv->state);
+out:
+ return -ENOMEM;
}
/**
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 7c7914f5fa0..fc413f0f8dd 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -54,14 +54,6 @@
#include "8250.h"
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-module_param(pc_debug, int, 0644);
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version = "serial_cs.c 1.134 2002/05/04 05:48:53 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
/*====================================================================*/
@@ -121,24 +113,20 @@ static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_
static int quirk_post_ibm(struct pcmcia_device *link)
{
conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
- int last_ret, last_fn;
+ int ret;
+
+ ret = pcmcia_access_configuration_register(link, &reg);
+ if (ret)
+ goto failed;
- last_ret = pcmcia_access_configuration_register(link, &reg);
- if (last_ret) {
- last_fn = AccessConfigurationRegister;
- goto cs_failed;
- }
reg.Action = CS_WRITE;
reg.Value = reg.Value | 1;
- last_ret = pcmcia_access_configuration_register(link, &reg);
- if (last_ret) {
- last_fn = AccessConfigurationRegister;
- goto cs_failed;
- }
+ ret = pcmcia_access_configuration_register(link, &reg);
+ if (ret)
+ goto failed;
return 0;
- cs_failed:
- cs_error(link, last_fn, last_ret);
+ failed:
return -ENODEV;
}
@@ -283,7 +271,7 @@ static void serial_remove(struct pcmcia_device *link)
struct serial_info *info = link->priv;
int i;
- DEBUG(0, "serial_release(0x%p)\n", link);
+ dev_dbg(&link->dev, "serial_release\n");
/*
* Recheck to see if the device is still configured.
@@ -334,7 +322,7 @@ static int serial_probe(struct pcmcia_device *link)
{
struct serial_info *info;
- DEBUG(0, "serial_attach()\n");
+ dev_dbg(&link->dev, "serial_attach()\n");
/* Create new serial device */
info = kzalloc(sizeof (*info), GFP_KERNEL);
@@ -346,7 +334,6 @@ static int serial_probe(struct pcmcia_device *link)
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 8;
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
- link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
if (do_sound) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
@@ -370,7 +357,7 @@ static void serial_detach(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
- DEBUG(0, "serial_detach(0x%p)\n", link);
+ dev_dbg(&link->dev, "serial_detach\n");
/*
* Ensure any outstanding scheduled tasks are completed.
@@ -399,7 +386,7 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
port.irq = irq;
port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
port.uartclk = 1843200;
- port.dev = &handle_to_dev(handle);
+ port.dev = &handle->dev;
if (buggy_uart)
port.flags |= UPF_BUGGY_UART;
@@ -426,21 +413,6 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
/*====================================================================*/
-static int
-first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
-{
- int i;
- i = pcmcia_get_first_tuple(handle, tuple);
- if (i != 0)
- return i;
- i = pcmcia_get_tuple_data(handle, tuple);
- if (i != 0)
- return i;
- return pcmcia_parse_tuple(tuple, parse);
-}
-
-/*====================================================================*/
-
static int simple_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
@@ -522,15 +494,13 @@ static int simple_config(struct pcmcia_device *link)
printk(KERN_NOTICE
"serial_cs: no usable port range found, giving up\n");
- cs_error(link, RequestIO, i);
return -1;
found_port:
i = pcmcia_request_irq(link, &link->irq);
- if (i != 0) {
- cs_error(link, RequestIRQ, i);
+ if (i != 0)
link->irq.AssignedIRQ = 0;
- }
+
if (info->multi && (info->manfid == MANFID_3COM))
link->conf.ConfigIndex &= ~(0x08);
@@ -541,10 +511,8 @@ found_port:
info->quirk->config(link);
i = pcmcia_request_configuration(link, &link->conf);
- if (i != 0) {
- cs_error(link, RequestConfiguration, i);
+ if (i != 0)
return -1;
- }
return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
}
@@ -613,7 +581,6 @@ static int multi_config(struct pcmcia_device *link)
/* FIXME: comment does not fit, error handling does not fit */
printk(KERN_NOTICE
"serial_cs: no usable port range found, giving up\n");
- cs_error(link, RequestIRQ, i);
link->irq.AssignedIRQ = 0;
}
@@ -624,10 +591,8 @@ static int multi_config(struct pcmcia_device *link)
info->quirk->config(link);
i = pcmcia_request_configuration(link, &link->conf);
- if (i != 0) {
- cs_error(link, RequestConfiguration, i);
+ if (i != 0)
return -ENODEV;
- }
/* The Oxford Semiconductor OXCF950 cards are in fact single-port:
* 8 registers are for the UART, the others are extra registers.
@@ -665,6 +630,25 @@ static int multi_config(struct pcmcia_device *link)
return 0;
}
+static int serial_check_for_multi(struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cf,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
+{
+ struct serial_info *info = p_dev->priv;
+
+ if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
+ info->multi = cf->io.win[0].len >> 3;
+
+ if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
+ (cf->io.win[1].len == 8))
+ info->multi = 2;
+
+ return 0; /* break */
+}
+
+
/*======================================================================
serial_config() is scheduled to run after a CARD_INSERTION event
@@ -676,46 +660,14 @@ static int multi_config(struct pcmcia_device *link)
static int serial_config(struct pcmcia_device * link)
{
struct serial_info *info = link->priv;
- struct serial_cfg_mem *cfg_mem;
- tuple_t *tuple;
- u_char *buf;
- cisparse_t *parse;
- cistpl_cftable_entry_t *cf;
- int i, last_ret, last_fn;
-
- DEBUG(0, "serial_config(0x%p)\n", link);
-
- cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
- if (!cfg_mem)
- goto failed;
+ int i;
- tuple = &cfg_mem->tuple;
- parse = &cfg_mem->parse;
- cf = &parse->cftable_entry;
- buf = cfg_mem->buf;
-
- tuple->TupleData = (cisdata_t *) buf;
- tuple->TupleOffset = 0;
- tuple->TupleDataMax = 255;
- tuple->Attributes = 0;
-
- /* Get configuration register information */
- tuple->DesiredTuple = CISTPL_CONFIG;
- last_ret = first_tuple(link, tuple, parse);
- if (last_ret != 0) {
- last_fn = ParseTuple;
- goto cs_failed;
- }
- link->conf.ConfigBase = parse->config.base;
- link->conf.Present = parse->config.rmask[0];
+ dev_dbg(&link->dev, "serial_config\n");
/* Is this a compliant multifunction card? */
- tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
- tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
- info->multi = (first_tuple(link, tuple, parse) == 0);
+ info->multi = (link->socket->functions > 1);
/* Is this a multiport card? */
- tuple->DesiredTuple = CISTPL_MANFID;
info->manfid = link->manf_id;
info->prodid = link->card_id;
@@ -730,20 +682,11 @@ static int serial_config(struct pcmcia_device * link)
/* Another check for dual-serial cards: look for either serial or
multifunction cards that ask for appropriate IO port ranges */
- tuple->DesiredTuple = CISTPL_FUNCID;
if ((info->multi == 0) &&
(link->has_func_id) &&
((link->func_id == CISTPL_FUNCID_MULTI) ||
- (link->func_id == CISTPL_FUNCID_SERIAL))) {
- tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
- if (first_tuple(link, tuple, parse) == 0) {
- if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
- info->multi = cf->io.win[0].len >> 3;
- if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
- (cf->io.win[1].len == 8))
- info->multi = 2;
- }
- }
+ (link->func_id == CISTPL_FUNCID_SERIAL)))
+ pcmcia_loop_config(link, serial_check_for_multi, info);
/*
* Apply any multi-port quirk.
@@ -768,14 +711,10 @@ static int serial_config(struct pcmcia_device * link)
goto failed;
link->dev_node = &info->node[0];
- kfree(cfg_mem);
return 0;
-cs_failed:
- cs_error(link, last_fn, last_ret);
failed:
serial_remove(link);
- kfree(cfg_mem);
return -ENODEV;
}
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 6498bd1fb6d..ff38dbdb5c6 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -50,7 +50,6 @@
#include <linux/list.h>
#ifdef CONFIG_SUPERH
-#include <asm/clock.h>
#include <asm/sh_bios.h>
#endif
@@ -79,22 +78,18 @@ struct sci_port {
struct timer_list break_timer;
int break_flag;
-#ifdef CONFIG_HAVE_CLK
/* Interface clock */
struct clk *iclk;
/* Data clock */
struct clk *dclk;
-#endif
+
struct list_head node;
};
struct sh_sci_priv {
spinlock_t lock;
struct list_head ports;
-
-#ifdef CONFIG_HAVE_CLK
struct notifier_block clk_nb;
-#endif
};
/* Function prototypes */
@@ -156,32 +151,6 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
}
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
-#if defined(__H8300S__)
-enum { sci_disable, sci_enable };
-
-static void h8300_sci_config(struct uart_port *port, unsigned int ctrl)
-{
- volatile unsigned char *mstpcrl = (volatile unsigned char *)MSTPCRL;
- int ch = (port->mapbase - SMR0) >> 3;
- unsigned char mask = 1 << (ch+1);
-
- if (ctrl == sci_disable)
- *mstpcrl |= mask;
- else
- *mstpcrl &= ~mask;
-}
-
-static void h8300_sci_enable(struct uart_port *port)
-{
- h8300_sci_config(port, sci_enable);
-}
-
-static void h8300_sci_disable(struct uart_port *port)
-{
- h8300_sci_config(port, sci_disable);
-}
-#endif
-
#if defined(__H8300H__) || defined(__H8300S__)
static void sci_init_pins(struct uart_port *port, unsigned int cflag)
{
@@ -733,7 +702,6 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
return ret;
}
-#ifdef CONFIG_HAVE_CLK
/*
* Here we define a transistion notifier so that we can update all of our
* ports' baud rate when the peripheral clock changes.
@@ -751,7 +719,6 @@ static int sci_notifier(struct notifier_block *self,
spin_lock_irqsave(&priv->lock, flags);
list_for_each_entry(sci_port, &priv->ports, node)
sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
-
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -778,7 +745,6 @@ static void sci_clk_disable(struct uart_port *port)
clk_disable(sci_port->dclk);
}
-#endif
static int sci_request_irq(struct sci_port *port)
{
@@ -833,8 +799,8 @@ static void sci_free_irq(struct sci_port *port)
static unsigned int sci_tx_empty(struct uart_port *port)
{
- /* Can't detect */
- return TIOCSER_TEMT;
+ unsigned short status = sci_in(port, SCxSR);
+ return status & SCxSR_TEND(port) ? TIOCSER_TEMT : 0;
}
static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
@@ -1077,21 +1043,10 @@ static void __devinit sci_init_single(struct platform_device *dev,
sci_port->port.iotype = UPIO_MEM;
sci_port->port.line = index;
sci_port->port.fifosize = 1;
-
-#if defined(__H8300H__) || defined(__H8300S__)
-#ifdef __H8300S__
- sci_port->enable = h8300_sci_enable;
- sci_port->disable = h8300_sci_disable;
-#endif
- sci_port->port.uartclk = CONFIG_CPU_CLOCK;
-#elif defined(CONFIG_HAVE_CLK)
sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL;
sci_port->dclk = clk_get(&dev->dev, "peripheral_clk");
sci_port->enable = sci_clk_enable;
sci_port->disable = sci_clk_disable;
-#else
-#error "Need a valid uartclk"
-#endif
sci_port->break_timer.data = (unsigned long)sci_port;
sci_port->break_timer.function = sci_break_timer;
@@ -1106,7 +1061,6 @@ static void __devinit sci_init_single(struct platform_device *dev,
sci_port->type = sci_port->port.type = p->type;
memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
-
}
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
@@ -1239,14 +1193,11 @@ static int sci_remove(struct platform_device *dev)
struct sci_port *p;
unsigned long flags;
-#ifdef CONFIG_HAVE_CLK
cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
spin_lock_irqsave(&priv->lock, flags);
list_for_each_entry(p, &priv->ports, node)
uart_remove_one_port(&sci_uart_driver, &p->port);
-
spin_unlock_irqrestore(&priv->lock, flags);
kfree(priv);
@@ -1307,10 +1258,8 @@ static int __devinit sci_probe(struct platform_device *dev)
spin_lock_init(&priv->lock);
platform_set_drvdata(dev, priv);
-#ifdef CONFIG_HAVE_CLK
priv->clk_nb.notifier_call = sci_notifier;
cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
if (dev->id != -1) {
ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
@@ -1370,7 +1319,7 @@ static struct dev_pm_ops sci_dev_pm_ops = {
static struct platform_driver sci_driver = {
.probe = sci_probe,
- .remove = __devexit_p(sci_remove),
+ .remove = sci_remove,
.driver = {
.name = "sh-sci",
.owner = THIS_MODULE,
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 3e2fcf93b42..a32094eeb42 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -1,5 +1,5 @@
#include <linux/serial_core.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/gpio.h>
#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 0c08f286a2e..465f2fae102 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -313,7 +313,7 @@ static void qe_uart_stop_tx(struct uart_port *port)
* This function will attempt to stuff of all the characters from the
* kernel's transmit buffer into TX BDs.
*
- * A return value of non-zero indicates that it sucessfully stuffed all
+ * A return value of non-zero indicates that it successfully stuffed all
* characters from the kernel buffer.
*
* A return value of zero indicates that there are still characters in the
@@ -1179,16 +1179,18 @@ static void uart_firmware_cont(const struct firmware *fw, void *context)
if (firmware->header.length != fw->size) {
dev_err(dev, "invalid firmware\n");
- return;
+ goto out;
}
ret = qe_upload_firmware(firmware);
if (ret) {
dev_err(dev, "could not load firmware\n");
- return;
+ goto out;
}
firmware_loaded = 1;
+ out:
+ release_firmware(fw);
}
static int ucc_uart_probe(struct of_device *ofdev,
@@ -1247,7 +1249,7 @@ static int ucc_uart_probe(struct of_device *ofdev,
*/
ret = request_firmware_nowait(THIS_MODULE,
FW_ACTION_HOTPLUG, filename, &ofdev->dev,
- &ofdev->dev, uart_firmware_cont);
+ GFP_KERNEL, &ofdev->dev, uart_firmware_cont);
if (ret) {
dev_err(&ofdev->dev,
"could not load firmware %s\n",