diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 24 | ||||
-rw-r--r-- | drivers/serial/8250_pnp.c | 4 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 15 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/apbuart.c | 710 | ||||
-rw-r--r-- | drivers/serial/apbuart.h | 64 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm.h | 8 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_driver.c | 48 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_neo.c | 8 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_tty.c | 6 | ||||
-rw-r--r-- | drivers/serial/mcf.c | 2 | ||||
-rw-r--r-- | drivers/serial/pmac_zilog.h | 2 | ||||
-rw-r--r-- | drivers/serial/pxa.c | 13 | ||||
-rw-r--r-- | drivers/serial/s3c2410.c | 2 | ||||
-rw-r--r-- | drivers/serial/s3c2412.c | 2 | ||||
-rw-r--r-- | drivers/serial/s3c2440.c | 2 | ||||
-rw-r--r-- | drivers/serial/s3c24a0.c | 2 | ||||
-rw-r--r-- | drivers/serial/samsung.c | 2 | ||||
-rw-r--r-- | drivers/serial/samsung.h | 2 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 33 | ||||
-rw-r--r-- | drivers/serial/serial_cs.c | 143 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 59 | ||||
-rw-r--r-- | drivers/serial/sh-sci.h | 2 | ||||
-rw-r--r-- | drivers/serial/ucc_uart.c | 10 |
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, ®); + if (ret) + goto failed; - last_ret = pcmcia_access_configuration_register(link, ®); - 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, ®); - if (last_ret) { - last_fn = AccessConfigurationRegister; - goto cs_failed; - } + ret = pcmcia_access_configuration_register(link, ®); + 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", |