diff options
Diffstat (limited to 'drivers/tty/serial')
92 files changed, 7399 insertions, 2069 deletions
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index a44345a2dbb4..c7e8b60b6177 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -85,7 +85,6 @@ static void serial21285_enable_ms(struct uart_port *port) static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; unsigned int status, ch, flag, rxs, max_count = 256; status = *CSR_UARTFLG; @@ -115,7 +114,7 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) status = *CSR_UARTFLG; } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); return IRQ_HANDLED; } diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 66c38a3f74ce..49399470794d 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -262,8 +262,7 @@ static void rs_start(struct tty_struct *tty) local_irq_restore(flags); } -static void receive_chars(struct m68k_serial *info, struct tty_struct *tty, - unsigned short rx) +static void receive_chars(struct m68k_serial *info, unsigned short rx) { m68328_uart *uart = &uart_addr[info->line]; unsigned char ch, flag; @@ -293,9 +292,6 @@ static void receive_chars(struct m68k_serial *info, struct tty_struct *tty, } } - if(!tty) - goto clear_and_exit; - flag = TTY_NORMAL; if (rx & URX_PARITY_ERROR) @@ -305,15 +301,12 @@ static void receive_chars(struct m68k_serial *info, struct tty_struct *tty, else if (rx & URX_FRAME_ERROR) flag = TTY_FRAME; - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(&info->tport, ch, flag); #ifndef CONFIG_XCOPILOT_BUGS } while((rx = uart->urx.w) & URX_DATA_READY); #endif - tty_schedule_flip(tty); - -clear_and_exit: - return; + tty_schedule_flip(&info->tport); } static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty) @@ -367,11 +360,11 @@ irqreturn_t rs_interrupt(int irq, void *dev_id) tx = uart->utx.w; if (rx & URX_DATA_READY) - receive_chars(info, tty, rx); + receive_chars(info, rx); if (tx & UTX_TX_AVAIL) transmit_chars(info, tty); #else - receive_chars(info, tty, rx); + receive_chars(info, rx); #endif tty_kref_put(tty); @@ -1009,7 +1002,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; - if (!info || serial_paranoia_check(info, tty->name, "rs_close")) + if (serial_paranoia_check(info, tty->name, "rs_close")) return; local_irq_save(flags); @@ -1225,6 +1218,8 @@ rs68328_init(void) if (tty_register_driver(serial_driver)) { put_tty_driver(serial_driver); + for (i = 0; i < NR_PORTS; i++) + tty_port_destroy(&m68k_soft[i].tport); printk(KERN_ERR "Couldn't register serial driver\n"); return -ENOMEM; } diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 3ba4234592bc..cf6a5383748a 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -239,13 +239,6 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, }, - [PORT_RM9000] = { - .name = "RM9000", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, [PORT_OCTEON] = { .name = "OCTEON", .fifo_size = 64, @@ -280,7 +273,17 @@ static const struct serial8250_config uart_config[] = { .fifo_size = 64, .tx_loadsz = 64, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP, + }, + [PORT_XR17V35X] = { + .name = "XR17V35X", + .fifo_size = 256, + .tx_loadsz = 256, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | + UART_FCR_T_TRIG_11, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP, }, [PORT_LPC3220] = { .name = "LPC3220", @@ -290,9 +293,36 @@ static const struct serial8250_config uart_config[] = { UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, .flags = UART_CAP_FIFO, }, + [PORT_BRCM_TRUMANAGE] = { + .name = "TruManage", + .fifo_size = 1, + .tx_loadsz = 1024, + .flags = UART_CAP_HFIFO, + }, [PORT_8250_CIR] = { .name = "CIR port" - } + }, + [PORT_ALTR_16550_F32] = { + .name = "Altera 16550 FIFO32", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_ALTR_16550_F64] = { + .name = "Altera 16550 FIFO64", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_ALTR_16550_F128] = { + .name = "Altera 16550 FIFO128", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, }; /* Uart divisor latch read */ @@ -308,9 +338,9 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value) serial_out(up, UART_DLM, value >> 8 & 0xff); } -#ifdef CONFIG_MIPS_ALCHEMY +#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) -/* Au1x00 UART hardware has a weird register layout */ +/* Au1x00/RT288x UART hardware has a weird register layout */ static const u8 au_io_in_map[] = { [UART_RX] = 0, [UART_IER] = 2, @@ -354,56 +384,6 @@ static void au_serial_dl_write(struct uart_8250_port *up, int value) #endif -#ifdef CONFIG_SERIAL_8250_RM9K - -static const u8 - regmap_in[8] = { - [UART_RX] = 0x00, - [UART_IER] = 0x0c, - [UART_IIR] = 0x14, - [UART_LCR] = 0x1c, - [UART_MCR] = 0x20, - [UART_LSR] = 0x24, - [UART_MSR] = 0x28, - [UART_SCR] = 0x2c - }, - regmap_out[8] = { - [UART_TX] = 0x04, - [UART_IER] = 0x0c, - [UART_FCR] = 0x18, - [UART_LCR] = 0x1c, - [UART_MCR] = 0x20, - [UART_LSR] = 0x24, - [UART_MSR] = 0x28, - [UART_SCR] = 0x2c - }; - -static unsigned int rm9k_serial_in(struct uart_port *p, int offset) -{ - offset = regmap_in[offset] << p->regshift; - return readl(p->membase + offset); -} - -static void rm9k_serial_out(struct uart_port *p, int offset, int value) -{ - offset = regmap_out[offset] << p->regshift; - writel(value, p->membase + offset); -} - -static int rm9k_serial_dl_read(struct uart_8250_port *up) -{ - return ((__raw_readl(up->port.membase + 0x10) << 8) | - (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff; -} - -static void rm9k_serial_dl_write(struct uart_8250_port *up, int value) -{ - __raw_writel(value, up->port.membase + 0x08); - __raw_writel(value >> 8, up->port.membase + 0x10); -} - -#endif - static unsigned int hub6_serial_in(struct uart_port *p, int offset) { offset = offset << p->regshift; @@ -455,6 +435,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value) } static int serial8250_default_handle_irq(struct uart_port *port); +static int exar_handle_irq(struct uart_port *port); static void set_io_from_upio(struct uart_port *p) { @@ -480,16 +461,7 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = mem32_serial_out; break; -#ifdef CONFIG_SERIAL_8250_RM9K - case UPIO_RM9000: - p->serial_in = rm9k_serial_in; - p->serial_out = rm9k_serial_out; - up->dl_read = rm9k_serial_dl_read; - up->dl_write = rm9k_serial_dl_write; - break; -#endif - -#ifdef CONFIG_MIPS_ALCHEMY +#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) case UPIO_AU: p->serial_in = au_serial_in; p->serial_out = au_serial_out; @@ -574,6 +546,19 @@ EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); */ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { + /* + * Exar UARTs have a SLEEP register that enables or disables + * each UART to enter sleep mode separately. On the XR17V35x the + * register is accessible to each UART at the UART_EXAR_SLEEP + * offset but the UART channel may only write to the corresponding + * bit. + */ + if ((p->port.type == PORT_XR17V35X) || + (p->port.type == PORT_XR17D15X)) { + serial_out(p, UART_EXAR_SLEEP, 0xff); + return; + } + if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); @@ -882,6 +867,27 @@ static void autoconfig_16550a(struct uart_8250_port *up) up->capabilities |= UART_CAP_FIFO; /* + * XR17V35x UARTs have an extra divisor register, DLD + * that gets enabled with when DLAB is set which will + * cause the device to incorrectly match and assign + * port type to PORT_16650. The EFR for this UART is + * found at offset 0x09. Instead check the Deice ID (DVID) + * register for a 2, 4 or 8 port UART. + */ + if (up->port.flags & UPF_EXAR_EFR) { + status1 = serial_in(up, UART_EXAR_DVID); + if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { + DEBUG_AUTOCONF("Exar XR17V35x "); + up->port.type = PORT_XR17V35X; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP; + + return; + } + + } + + /* * Check for presence of the EFR when DLAB is set. * Only ST16C650V1 UARTs pass this test. */ @@ -1013,8 +1019,12 @@ static void autoconfig_16550a(struct uart_8250_port *up) * Exar uarts have EFR in a weird location */ if (up->port.flags & UPF_EXAR_EFR) { + DEBUG_AUTOCONF("Exar XR17D15x "); up->port.type = PORT_XR17D15X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP; + + return; } /* @@ -1286,7 +1296,9 @@ static void serial8250_start_tx(struct uart_port *port) struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); - if (!(up->ier & UART_IER_THRI)) { + if (up->dma && !serial8250_tx_dma(up)) { + return; + } else if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; serial_port_out(port, UART_IER, up->ier); @@ -1294,9 +1306,7 @@ static void serial8250_start_tx(struct uart_port *port) unsigned char lsr; lsr = serial_in(up, UART_LSR); up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if ((port->type == PORT_RM9000) ? - (lsr & UART_LSR_THRE) : - (lsr & UART_LSR_TEMT)) + if (lsr & UART_LSR_TEMT) serial8250_tx_chars(up); } } @@ -1342,7 +1352,6 @@ unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) { struct uart_port *port = &up->port; - struct tty_struct *tty = port->state->port.tty; unsigned char ch; int max_count = 256; char flag; @@ -1407,7 +1416,7 @@ ignore_char: lsr = serial_in(up, UART_LSR); } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); spin_unlock(&port->lock); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); spin_lock(&port->lock); return lsr; } @@ -1441,6 +1450,11 @@ void serial8250_tx_chars(struct uart_8250_port *up) port->icount.tx++; if (uart_circ_empty(xmit)) break; + if (up->capabilities & UART_CAP_HFIFO) { + if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != + BOTH_EMPTY) + break; + } } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -1487,6 +1501,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) unsigned long flags; struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); + int dma_err = 0; if (iir & UART_IIR_NO_INT) return 0; @@ -1497,8 +1512,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) DEBUG_INTR("status = %x...", status); - if (status & (UART_LSR_DR | UART_LSR_BI)) - status = serial8250_rx_chars(up, status); + if (status & (UART_LSR_DR | UART_LSR_BI)) { + if (up->dma) + dma_err = serial8250_rx_dma(up, iir); + + if (!up->dma || dma_err) + status = serial8250_rx_chars(up, status); + } serial8250_modem_status(up); if (status & UART_LSR_THRE) serial8250_tx_chars(up); @@ -1516,6 +1536,31 @@ static int serial8250_default_handle_irq(struct uart_port *port) } /* + * These Exar UARTs have an extra interrupt indicator that could + * fire for a few unimplemented interrupts. One of which is a + * wakeup event when coming out of sleep. Put this here just + * to be on the safe side that these interrupts don't go unhandled. + */ +static int exar_handle_irq(struct uart_port *port) +{ + unsigned char int0, int1, int2, int3; + unsigned int iir = serial_port_in(port, UART_IIR); + int ret; + + ret = serial8250_handle_irq(port, iir); + + if ((port->type == PORT_XR17V35X) || + (port->type == PORT_XR17D15X)) { + int0 = serial_port_in(port, 0x80); + int1 = serial_port_in(port, 0x81); + int2 = serial_port_in(port, 0x82); + int3 = serial_port_in(port, 0x83); + } + + return ret; +} + +/* * This is the serial driver's interrupt routine. * * Arjan thinks the old way was overly complex, so it got simplified. @@ -1906,9 +1951,12 @@ static int serial8250_startup(struct uart_port *port) if (port->type == PORT_8250_CIR) return -ENODEV; - port->fifosize = uart_config[up->port.type].fifo_size; - up->tx_loadsz = uart_config[up->port.type].tx_loadsz; - up->capabilities = uart_config[up->port.type].flags; + if (!port->fifosize) + port->fifosize = uart_config[port->type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[port->type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[port->type].flags; up->mcr = 0; if (port->iotype != up->cur_iotype) @@ -2113,6 +2161,18 @@ dont_test_tx_en: up->msr_saved_flags = 0; /* + * Request DMA channels for both RX and TX. + */ + if (up->dma) { + retval = serial8250_request_dma(up); + if (retval) { + pr_warn_ratelimited("ttyS%d - failed to request DMA\n", + serial_index(port)); + up->dma = NULL; + } + } + + /* * Finally, enable interrupts. Note: Modem status interrupts * are set via set_termios(), which will be occurring imminently * anyway, so we don't enable them here. @@ -2145,6 +2205,9 @@ static void serial8250_shutdown(struct uart_port *port) up->ier = 0; serial_port_out(port, UART_IER, 0); + if (up->dma) + serial8250_release_dma(up); + spin_lock_irqsave(&port->lock, flags); if (port->flags & UPF_FOURPORT) { /* reset interrupts on the AST Fourport board */ @@ -2349,16 +2412,14 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, serial_port_out(port, UART_EFR, efr); } -#ifdef CONFIG_ARCH_OMAP1 /* Workaround to enable 115200 baud on OMAP1510 internal ports */ - if (cpu_is_omap1510() && is_omap_port(up)) { + if (is_omap1510_8250(up)) { if (baud == 115200) { quot = 1; serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); } else serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); } -#endif /* * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, @@ -2439,10 +2500,9 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt) { if (pt->port.iotype == UPIO_AU) return 0x1000; -#ifdef CONFIG_ARCH_OMAP1 - if (is_omap_port(pt)) + if (is_omap1_8250(pt)) return 0x16 << pt->port.regshift; -#endif + return 8 << pt->port.regshift; } @@ -2617,6 +2677,11 @@ static void serial8250_config_port(struct uart_port *port, int flags) serial8250_release_rsa_resource(up); if (port->type == PORT_UNKNOWN) serial8250_release_std_resource(up); + + /* Fixme: probably not the best place for this */ + if ((port->type == PORT_XR17V35X) || + (port->type == PORT_XR17D15X)) + port->handle_irq = exar_handle_irq; } static int @@ -2739,9 +2804,12 @@ static void serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) { up->port.type = type; - up->port.fifosize = uart_config[type].fifo_size; - up->capabilities = uart_config[type].flags; - up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->port.fifosize) + up->port.fifosize = uart_config[type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[type].flags; } static void __init @@ -2992,7 +3060,7 @@ void serial8250_resume_port(int line) * list is terminated with a zero flags entry, which means we expect * all entries to have at least UPF_BOOT_AUTOCONF set. */ -static int __devinit serial8250_probe(struct platform_device *dev) +static int serial8250_probe(struct platform_device *dev) { struct plat_serial8250_port *p = dev->dev.platform_data; struct uart_8250_port uart; @@ -3038,7 +3106,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) /* * Remove serial ports registered against a platform device. */ -static int __devexit serial8250_remove(struct platform_device *dev) +static int serial8250_remove(struct platform_device *dev) { int i; @@ -3081,7 +3149,7 @@ static int serial8250_resume(struct platform_device *dev) static struct platform_driver serial8250_isa_driver = { .probe = serial8250_probe, - .remove = __devexit_p(serial8250_remove), + .remove = serial8250_remove, .suspend = serial8250_suspend, .resume = serial8250_resume, .driver = { @@ -3175,6 +3243,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->bugs = up->bugs; uart->port.mapbase = up->port.mapbase; uart->port.private_data = up->port.private_data; + uart->port.fifosize = up->port.fifosize; + uart->tx_loadsz = up->tx_loadsz; + uart->capabilities = up->capabilities; + if (up->port.dev) uart->port.dev = up->port.dev; @@ -3200,6 +3272,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->dl_read = up->dl_read; if (up->dl_write) uart->dl_write = up->dl_write; + if (up->dma) + uart->dma = up->dma; if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, @@ -3343,3 +3417,32 @@ module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444); MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); #endif MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); + +#ifndef MODULE +/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name + * working as well for the module options so we don't break people. We + * need to keep the names identical and the convenient macros will happily + * refuse to let us do that by failing the build with redefinition errors + * of global variables. So we stick them inside a dummy function to avoid + * those conflicts. The options still get parsed, and the redefined + * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive. + * + * This is hacky. I'm sorry. + */ +static void __used s8250_options(void) +{ +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "8250." + + module_param_cb(share_irqs, ¶m_ops_uint, &share_irqs, 0644); + module_param_cb(nr_uarts, ¶m_ops_uint, &nr_uarts, 0644); + module_param_cb(skip_txen_test, ¶m_ops_uint, &skip_txen_test, 0644); +#ifdef CONFIG_SERIAL_8250_RSA + __module_param_call(MODULE_PARAM_PREFIX, probe_rsa, + ¶m_array_ops, .arr = &__param_arr_probe_rsa, + 0444, -1); +#endif +} +#else +MODULE_ALIAS("8250"); +#endif diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 5a76f9c8d36b..34eb676916fe 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -12,6 +12,35 @@ */ #include <linux/serial_8250.h> +#include <linux/dmaengine.h> + +struct uart_8250_dma { + dma_filter_fn fn; + void *rx_param; + void *tx_param; + + int rx_chan_id; + int tx_chan_id; + + struct dma_slave_config rxconf; + struct dma_slave_config txconf; + + struct dma_chan *rxchan; + struct dma_chan *txchan; + + dma_addr_t rx_addr; + dma_addr_t tx_addr; + + dma_cookie_t rx_cookie; + dma_cookie_t tx_cookie; + + void *rx_buf; + + size_t rx_size; + size_t tx_size; + + unsigned char tx_running:1; +}; struct old_serial_port { unsigned int uart; @@ -40,6 +69,7 @@ struct serial8250_config { #define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */ #define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */ #define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */ +#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */ #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ @@ -106,3 +136,60 @@ static inline int serial8250_pnp_init(void) { return 0; } static inline void serial8250_pnp_exit(void) { } #endif +#ifdef CONFIG_ARCH_OMAP1 +static inline int is_omap1_8250(struct uart_8250_port *pt) +{ + int res; + + switch (pt->port.mapbase) { + case OMAP1_UART1_BASE: + case OMAP1_UART2_BASE: + case OMAP1_UART3_BASE: + res = 1; + break; + default: + res = 0; + break; + } + + return res; +} + +static inline int is_omap1510_8250(struct uart_8250_port *pt) +{ + if (!cpu_is_omap1510()) + return 0; + + return is_omap1_8250(pt); +} +#else +static inline int is_omap1_8250(struct uart_8250_port *pt) +{ + return 0; +} +static inline int is_omap1510_8250(struct uart_8250_port *pt) +{ + return 0; +} +#endif + +#ifdef CONFIG_SERIAL_8250_DMA +extern int serial8250_tx_dma(struct uart_8250_port *); +extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir); +extern int serial8250_request_dma(struct uart_8250_port *); +extern void serial8250_release_dma(struct uart_8250_port *); +#else +static inline int serial8250_tx_dma(struct uart_8250_port *p) +{ + return -1; +} +static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +{ + return -1; +} +static inline int serial8250_request_dma(struct uart_8250_port *p) +{ + return -1; +} +static inline void serial8250_release_dma(struct uart_8250_port *p) { } +#endif diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c index 857498312a9a..549aa07c0d27 100644 --- a/drivers/tty/serial/8250/8250_acorn.c +++ b/drivers/tty/serial/8250/8250_acorn.c @@ -38,7 +38,7 @@ struct serial_card_info { void __iomem *vaddr; }; -static int __devinit +static int serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) { struct serial_card_info *info; @@ -80,7 +80,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) return 0; } -static void __devexit serial_card_remove(struct expansion_card *ec) +static void serial_card_remove(struct expansion_card *ec) { struct serial_card_info *info = ecard_get_drvdata(ec); int i; @@ -116,7 +116,7 @@ static const struct ecard_id serial_cids[] = { static struct ecard_driver serial_card_driver = { .probe = serial_card_probe, - .remove = __devexit_p(serial_card_remove), + .remove = serial_card_remove, .id_table = serial_cids, .drv = { .name = "8250_acorn", diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c new file mode 100644 index 000000000000..b9f7fd28112e --- /dev/null +++ b/drivers/tty/serial/8250/8250_dma.c @@ -0,0 +1,216 @@ +/* + * 8250_dma.c - DMA Engine API support for 8250.c + * + * Copyright (C) 2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_reg.h> +#include <linux/dma-mapping.h> + +#include "8250.h" + +static void __dma_tx_complete(void *param) +{ + struct uart_8250_port *p = param; + struct uart_8250_dma *dma = p->dma; + struct circ_buf *xmit = &p->port.state->xmit; + + dma->tx_running = 0; + + dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + xmit->tail += dma->tx_size; + xmit->tail &= UART_XMIT_SIZE - 1; + p->port.icount.tx += dma->tx_size; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&p->port); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) { + serial8250_tx_dma(p); + uart_write_wakeup(&p->port); + } +} + +static void __dma_rx_complete(void *param) +{ + struct uart_8250_port *p = param; + struct uart_8250_dma *dma = p->dma; + struct tty_port *tty_port = &p->port.state->port; + struct dma_tx_state state; + int count; + + dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + dmaengine_terminate_all(dma->rxchan); + + count = dma->rx_size - state.residue; + + tty_insert_flip_string(tty_port, dma->rx_buf, count); + p->port.icount.rx += count; + + tty_flip_buffer_push(tty_port); +} + +int serial8250_tx_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + struct circ_buf *xmit = &p->port.state->xmit; + struct dma_async_tx_descriptor *desc; + + if (dma->tx_running) + return -EBUSY; + + dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (!dma->tx_size) + return -EINVAL; + + desc = dmaengine_prep_slave_single(dma->txchan, + dma->tx_addr + xmit->tail, + dma->tx_size, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EBUSY; + + dma->tx_running = 1; + + desc->callback = __dma_tx_complete; + desc->callback_param = p; + + dma->tx_cookie = dmaengine_submit(desc); + + dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + dma_async_issue_pending(dma->txchan); + + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_tx_dma); + +int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +{ + struct uart_8250_dma *dma = p->dma; + struct dma_async_tx_descriptor *desc; + struct dma_tx_state state; + int dma_status; + + /* + * If RCVR FIFO trigger level was not reached, complete the transfer and + * let 8250.c copy the remaining data. + */ + if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { + dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, + &state); + if (dma_status == DMA_IN_PROGRESS) { + dmaengine_pause(dma->rxchan); + __dma_rx_complete(p); + } + return -ETIMEDOUT; + } + + desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, + dma->rx_size, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EBUSY; + + desc->callback = __dma_rx_complete; + desc->callback_param = p; + + dma->rx_cookie = dmaengine_submit(desc); + + dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dma_async_issue_pending(dma->rxchan); + + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_rx_dma); + +int serial8250_request_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + dma_cap_mask_t mask; + + dma->rxconf.src_addr = p->port.mapbase + UART_RX; + dma->txconf.dst_addr = p->port.mapbase + UART_TX; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* Get a channel for RX */ + dma->rxchan = dma_request_channel(mask, dma->fn, dma->rx_param); + if (!dma->rxchan) + return -ENODEV; + + dmaengine_slave_config(dma->rxchan, &dma->rxconf); + + /* Get a channel for TX */ + dma->txchan = dma_request_channel(mask, dma->fn, dma->tx_param); + if (!dma->txchan) { + dma_release_channel(dma->rxchan); + return -ENODEV; + } + + dmaengine_slave_config(dma->txchan, &dma->txconf); + + /* RX buffer */ + if (!dma->rx_size) + dma->rx_size = PAGE_SIZE; + + dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size, + &dma->rx_addr, GFP_KERNEL); + if (!dma->rx_buf) { + dma_release_channel(dma->rxchan); + dma_release_channel(dma->txchan); + return -ENOMEM; + } + + /* TX buffer */ + dma->tx_addr = dma_map_single(dma->txchan->device->dev, + p->port.state->xmit.buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + + dev_dbg_ratelimited(p->port.dev, "got both dma channels\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_request_dma); + +void serial8250_release_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + if (!dma) + return; + + /* Release RX resources */ + dmaengine_terminate_all(dma->rxchan); + dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf, + dma->rx_addr); + dma_release_channel(dma->rxchan); + dma->rxchan = NULL; + + /* Release TX resources */ + dmaengine_terminate_all(dma->txchan); + dma_unmap_single(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + dma_release_channel(dma->txchan); + dma->txchan = NULL; + dma->tx_running = 0; + + dev_dbg_ratelimited(p->port.dev, "dma channels released\n"); +} +EXPORT_SYMBOL_GPL(serial8250_release_dma); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index c3b2ec0c8c0b..db0e66f6dd0e 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -2,6 +2,7 @@ * Synopsys DesignWare 8250 driver. * * Copyright 2011 Picochip, Jamie Iles. + * Copyright 2013 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +25,34 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/acpi.h> + +#include "8250.h" + +/* Offsets for the DesignWare specific registers */ +#define DW_UART_USR 0x1f /* UART Status Register */ +#define DW_UART_CPR 0xf4 /* Component Parameter Register */ +#define DW_UART_UCV 0xf8 /* UART Component Version */ + +/* Intel Low Power Subsystem specific */ +#define LPSS_PRV_CLOCK_PARAMS 0x800 + +/* Component Parameter Register bits */ +#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) +#define DW_UART_CPR_AFCE_MODE (1 << 4) +#define DW_UART_CPR_THRE_MODE (1 << 5) +#define DW_UART_CPR_SIR_MODE (1 << 6) +#define DW_UART_CPR_SIR_LP_MODE (1 << 7) +#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) +#define DW_UART_CPR_FIFO_ACCESS (1 << 9) +#define DW_UART_CPR_FIFO_STAT (1 << 10) +#define DW_UART_CPR_SHADOW (1 << 11) +#define DW_UART_CPR_ENCODED_PARMS (1 << 12) +#define DW_UART_CPR_DMA_EXTRA (1 << 13) +#define DW_UART_CPR_FIFO_MODE (0xff << 16) +/* Helper for fifo size calculation */ +#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) + struct dw8250_data { int last_lcr; @@ -66,9 +95,6 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) return readl(p->membase + offset); } -/* Offset for the DesignWare's UART Status Register. */ -#define UART_USR 0x1f - static int dw8250_handle_irq(struct uart_port *p) { struct dw8250_data *d = p->private_data; @@ -78,8 +104,8 @@ static int dw8250_handle_irq(struct uart_port *p) return 1; } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { /* Clear the USR and write the LCR again. */ - (void)p->serial_in(p, UART_USR); - p->serial_out(p, d->last_lcr, UART_LCR); + (void)p->serial_in(p, DW_UART_USR); + p->serial_out(p, UART_LCR, d->last_lcr); return 1; } @@ -87,61 +113,210 @@ static int dw8250_handle_irq(struct uart_port *p) return 0; } -static int __devinit dw8250_probe(struct platform_device *pdev) +static int dw8250_probe_of(struct uart_port *p) +{ + struct device_node *np = p->dev->of_node; + u32 val; + + if (!of_property_read_u32(np, "reg-io-width", &val)) { + switch (val) { + case 1: + break; + case 4: + p->iotype = UPIO_MEM32; + p->serial_in = dw8250_serial_in32; + p->serial_out = dw8250_serial_out32; + break; + default: + dev_err(p->dev, "unsupported reg-io-width (%u)\n", val); + return -EINVAL; + } + } + + if (!of_property_read_u32(np, "reg-shift", &val)) + p->regshift = val; + + if (of_property_read_u32(np, "clock-frequency", &val)) { + dev_err(p->dev, "no clock-frequency property set\n"); + return -EINVAL; + } + p->uartclk = val; + + return 0; +} + +#ifdef CONFIG_ACPI +static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm) +{ + return chan->chan_id == *(int *)parm; +} + +static acpi_status +dw8250_acpi_walk_resource(struct acpi_resource *res, void *data) +{ + struct uart_port *p = data; + struct uart_8250_port *port; + struct uart_8250_dma *dma; + struct acpi_resource_fixed_dma *fixed_dma; + struct dma_slave_config *slave; + + port = container_of(p, struct uart_8250_port, port); + + switch (res->type) { + case ACPI_RESOURCE_TYPE_FIXED_DMA: + fixed_dma = &res->data.fixed_dma; + + /* TX comes first */ + if (!port->dma) { + dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return AE_NO_MEMORY; + + port->dma = dma; + slave = &dma->txconf; + + slave->direction = DMA_MEM_TO_DEV; + slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave->slave_id = fixed_dma->request_lines; + slave->dst_maxburst = port->tx_loadsz / 4; + + dma->tx_chan_id = fixed_dma->channels; + dma->tx_param = &dma->tx_chan_id; + dma->fn = dw8250_acpi_dma_filter; + } else { + dma = port->dma; + slave = &dma->rxconf; + + slave->direction = DMA_DEV_TO_MEM; + slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave->slave_id = fixed_dma->request_lines; + slave->src_maxburst = p->fifosize / 4; + + dma->rx_chan_id = fixed_dma->channels; + dma->rx_param = &dma->rx_chan_id; + } + + break; + } + + return AE_OK; +} + +static int dw8250_probe_acpi(struct uart_port *p) +{ + const struct acpi_device_id *id; + acpi_status status; + u32 reg; + + id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); + if (!id) + return -ENODEV; + + p->iotype = UPIO_MEM32; + p->serial_in = dw8250_serial_in32; + p->serial_out = dw8250_serial_out32; + p->regshift = 2; + p->uartclk = (unsigned int)id->driver_data; + + status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS, + dw8250_acpi_walk_resource, p); + if (ACPI_FAILURE(status)) { + dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__, + acpi_format_exception(status)); + return -ENODEV; + } + + /* Fix Haswell issue where the clocks do not get enabled */ + if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) { + reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS); + writel(reg | 1, p->membase + LPSS_PRV_CLOCK_PARAMS); + } + + return 0; +} +#else +static inline int dw8250_probe_acpi(struct uart_port *p) +{ + return -ENODEV; +} +#endif /* CONFIG_ACPI */ + +static void dw8250_setup_port(struct uart_8250_port *up) +{ + struct uart_port *p = &up->port; + u32 reg = readl(p->membase + DW_UART_UCV); + + /* + * If the Component Version Register returns zero, we know that + * ADDITIONAL_FEATURES are not enabled. No need to go any further. + */ + if (!reg) + return; + + dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n", + (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); + + reg = readl(p->membase + DW_UART_CPR); + if (!reg) + return; + + /* Select the type based on fifo */ + if (reg & DW_UART_CPR_FIFO_MODE) { + p->type = PORT_16550A; + p->flags |= UPF_FIXED_TYPE; + p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); + up->tx_loadsz = p->fifosize; + } +} + +static int dw8250_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - struct device_node *np = pdev->dev.of_node; - u32 val; struct dw8250_data *data; + int err; if (!regs || !irq) { dev_err(&pdev->dev, "no registers/irq defined\n"); return -EINVAL; } - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - uart.port.private_data = data; - spin_lock_init(&uart.port.lock); uart.port.mapbase = regs->start; uart.port.irq = irq->start; uart.port.handle_irq = dw8250_handle_irq; uart.port.type = PORT_8250; - uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | - UPF_FIXED_PORT | UPF_FIXED_TYPE; + uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; uart.port.dev = &pdev->dev; + uart.port.membase = ioremap(regs->start, resource_size(regs)); + if (!uart.port.membase) + return -ENOMEM; + uart.port.iotype = UPIO_MEM; uart.port.serial_in = dw8250_serial_in; uart.port.serial_out = dw8250_serial_out; - if (!of_property_read_u32(np, "reg-io-width", &val)) { - switch (val) { - case 1: - break; - case 4: - uart.port.iotype = UPIO_MEM32; - uart.port.serial_in = dw8250_serial_in32; - uart.port.serial_out = dw8250_serial_out32; - break; - default: - dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n", - val); - return -EINVAL; - } + + dw8250_setup_port(&uart); + + if (pdev->dev.of_node) { + err = dw8250_probe_of(&uart.port); + if (err) + return err; + } else if (ACPI_HANDLE(&pdev->dev)) { + err = dw8250_probe_acpi(&uart.port); + if (err) + return err; + } else { + return -ENODEV; } - if (!of_property_read_u32(np, "reg-shift", &val)) - uart.port.regshift = val; + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; - if (of_property_read_u32(np, "clock-frequency", &val)) { - dev_err(&pdev->dev, "no clock-frequency property set\n"); - return -EINVAL; - } - uart.port.uartclk = val; + uart.port.private_data = data; data->line = serial8250_register_8250_port(&uart); if (data->line < 0) @@ -152,7 +327,7 @@ static int __devinit dw8250_probe(struct platform_device *pdev) return 0; } -static int __devexit dw8250_remove(struct platform_device *pdev) +static int dw8250_remove(struct platform_device *pdev) { struct dw8250_data *data = platform_get_drvdata(pdev); @@ -161,20 +336,53 @@ static int __devexit dw8250_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id dw8250_match[] = { +#ifdef CONFIG_PM +static int dw8250_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct dw8250_data *data = platform_get_drvdata(pdev); + + serial8250_suspend_port(data->line); + + return 0; +} + +static int dw8250_resume(struct platform_device *pdev) +{ + struct dw8250_data *data = platform_get_drvdata(pdev); + + serial8250_resume_port(data->line); + + return 0; +} +#else +#define dw8250_suspend NULL +#define dw8250_resume NULL +#endif /* CONFIG_PM */ + +static const struct of_device_id dw8250_of_match[] = { { .compatible = "snps,dw-apb-uart" }, { /* Sentinel */ } }; -MODULE_DEVICE_TABLE(of, dw8250_match); +MODULE_DEVICE_TABLE(of, dw8250_of_match); + +static const struct acpi_device_id dw8250_acpi_match[] = { + { "INT33C4", 100000000 }, + { "INT33C5", 100000000 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); static struct platform_driver dw8250_platform_driver = { .driver = { .name = "dw-apb-uart", .owner = THIS_MODULE, - .of_match_table = dw8250_match, + .of_match_table = dw8250_of_match, + .acpi_match_table = ACPI_PTR(dw8250_acpi_match), }, .probe = dw8250_probe, - .remove = __devexit_p(dw8250_remove), + .remove = dw8250_remove, + .suspend = dw8250_suspend, + .resume = dw8250_resume, }; module_platform_driver(dw8250_platform_driver); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index eaafb98debed..721904f8efa9 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -48,7 +48,7 @@ struct early_serial8250_device { static struct early_serial8250_device early_device; -static unsigned int __init serial_in(struct uart_port *port, int offset) +unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) { switch (port->iotype) { case UPIO_MEM: @@ -62,7 +62,7 @@ static unsigned int __init serial_in(struct uart_port *port, int offset) } } -static void __init serial_out(struct uart_port *port, int offset, int value) +void __weak __init serial8250_early_out(struct uart_port *port, int offset, int value) { switch (port->iotype) { case UPIO_MEM: @@ -84,7 +84,7 @@ static void __init wait_for_xmitr(struct uart_port *port) unsigned int status; for (;;) { - status = serial_in(port, UART_LSR); + status = serial8250_early_in(port, UART_LSR); if ((status & BOTH_EMPTY) == BOTH_EMPTY) return; cpu_relax(); @@ -94,7 +94,7 @@ static void __init wait_for_xmitr(struct uart_port *port) static void __init serial_putc(struct uart_port *port, int c) { wait_for_xmitr(port); - serial_out(port, UART_TX, c); + serial8250_early_out(port, UART_TX, c); } static void __init early_serial8250_write(struct console *console, @@ -104,14 +104,14 @@ static void __init early_serial8250_write(struct console *console, unsigned int ier; /* Save the IER and disable interrupts */ - ier = serial_in(port, UART_IER); - serial_out(port, UART_IER, 0); + ier = serial8250_early_in(port, UART_IER); + serial8250_early_out(port, UART_IER, 0); uart_console_write(port, s, count, serial_putc); /* Wait for transmitter to become empty and restore the IER */ wait_for_xmitr(port); - serial_out(port, UART_IER, ier); + serial8250_early_out(port, UART_IER, ier); } static unsigned int __init probe_baud(struct uart_port *port) @@ -119,11 +119,11 @@ static unsigned int __init probe_baud(struct uart_port *port) unsigned char lcr, dll, dlm; unsigned int quot; - lcr = serial_in(port, UART_LCR); - serial_out(port, UART_LCR, lcr | UART_LCR_DLAB); - dll = serial_in(port, UART_DLL); - dlm = serial_in(port, UART_DLM); - serial_out(port, UART_LCR, lcr); + lcr = serial8250_early_in(port, UART_LCR); + serial8250_early_out(port, UART_LCR, lcr | UART_LCR_DLAB); + dll = serial8250_early_in(port, UART_DLL); + dlm = serial8250_early_in(port, UART_DLM); + serial8250_early_out(port, UART_LCR, lcr); quot = (dlm << 8) | dll; return (port->uartclk / 16) / quot; @@ -135,17 +135,17 @@ static void __init init_port(struct early_serial8250_device *device) unsigned int divisor; unsigned char c; - serial_out(port, UART_LCR, 0x3); /* 8n1 */ - serial_out(port, UART_IER, 0); /* no interrupt */ - serial_out(port, UART_FCR, 0); /* no fifo */ - serial_out(port, UART_MCR, 0x3); /* DTR + RTS */ - - divisor = port->uartclk / (16 * device->baud); - c = serial_in(port, UART_LCR); - serial_out(port, UART_LCR, c | UART_LCR_DLAB); - serial_out(port, UART_DLL, divisor & 0xff); - serial_out(port, UART_DLM, (divisor >> 8) & 0xff); - serial_out(port, UART_LCR, c & ~UART_LCR_DLAB); + serial8250_early_out(port, UART_LCR, 0x3); /* 8n1 */ + serial8250_early_out(port, UART_IER, 0); /* no interrupt */ + serial8250_early_out(port, UART_FCR, 0); /* no fifo */ + serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */ + + divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); + c = serial8250_early_in(port, UART_LCR); + serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB); + serial8250_early_out(port, UART_DLL, divisor & 0xff); + serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff); + serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); } static int __init parse_options(struct early_serial8250_device *device, @@ -194,7 +194,7 @@ static int __init parse_options(struct early_serial8250_device *device, options++; device->baud = simple_strtoul(options, NULL, 0); length = min(strcspn(options, " "), sizeof(device->options)); - strncpy(device->options, options, length); + strlcpy(device->options, options, length); } else { device->baud = probe_baud(port); snprintf(device->options, sizeof(device->options), "%u", diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index 3a0363e7f3a7..916cc19fbbda 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -89,7 +89,7 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value) serial_out(up, UART_DLM_EM, value >> 8 & 0xff); } -static int __devinit serial8250_em_probe(struct platform_device *pdev) +static int serial8250_em_probe(struct platform_device *pdev) { struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -152,7 +152,7 @@ static int __devinit serial8250_em_probe(struct platform_device *pdev) return ret; } -static int __devexit serial8250_em_remove(struct platform_device *pdev) +static int serial8250_em_remove(struct platform_device *pdev) { struct serial8250_em_priv *priv = platform_get_drvdata(pdev); @@ -163,7 +163,7 @@ static int __devexit serial8250_em_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = { +static const struct of_device_id serial8250_em_dt_ids[] = { { .compatible = "renesas,em-uart", }, {}, }; @@ -176,7 +176,7 @@ static struct platform_driver serial8250_em_platform_driver = { .owner = THIS_MODULE, }, .probe = serial8250_em_probe, - .remove = __devexit_p(serial8250_em_remove), + .remove = serial8250_em_remove, }; module_platform_driver(serial8250_em_platform_driver); diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c index f3d0edf46644..5bdaf271d395 100644 --- a/drivers/tty/serial/8250/8250_hp300.c +++ b/drivers/tty/serial/8250/8250_hp300.c @@ -36,9 +36,9 @@ static struct hp300_port *hp300_ports; #ifdef CONFIG_HPDCA -static int __devinit hpdca_init_one(struct dio_dev *d, +static int hpdca_init_one(struct dio_dev *d, const struct dio_device_id *ent); -static void __devexit hpdca_remove_one(struct dio_dev *d); +static void hpdca_remove_one(struct dio_dev *d); static struct dio_device_id hpdca_dio_tbl[] = { { DIO_ID_DCA0 }, @@ -52,7 +52,7 @@ static struct dio_driver hpdca_driver = { .name = "hpdca", .id_table = hpdca_dio_tbl, .probe = hpdca_init_one, - .remove = __devexit_p(hpdca_remove_one), + .remove = hpdca_remove_one, }; #endif @@ -159,7 +159,7 @@ int __init hp300_setup_serial_console(void) #endif /* CONFIG_SERIAL_8250_CONSOLE */ #ifdef CONFIG_HPDCA -static int __devinit hpdca_init_one(struct dio_dev *d, +static int hpdca_init_one(struct dio_dev *d, const struct dio_device_id *ent) { struct uart_8250_port uart; @@ -288,7 +288,7 @@ static int __init hp300_8250_init(void) } #ifdef CONFIG_HPDCA -static void __devexit hpdca_remove_one(struct dio_dev *d) +static void hpdca_remove_one(struct dio_dev *d) { int line; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 17b7d26abf41..aa76825229dc 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -288,7 +288,7 @@ static int pci_plx9050_init(struct pci_dev *dev) return 0; } -static void __devexit pci_plx9050_exit(struct pci_dev *dev) +static void pci_plx9050_exit(struct pci_dev *dev) { u8 __iomem *p; @@ -313,7 +313,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev) #define NI8420_INT_ENABLE_REG 0x38 #define NI8420_INT_ENABLE_BIT 0x2000 -static void __devexit pci_ni8420_exit(struct pci_dev *dev) +static void pci_ni8420_exit(struct pci_dev *dev) { void __iomem *p; unsigned long base, len; @@ -345,7 +345,7 @@ static void __devexit pci_ni8420_exit(struct pci_dev *dev) #define MITE_LCIMR2_CLR_CPU_IE (1 << 30) -static void __devexit pci_ni8430_exit(struct pci_dev *dev) +static void pci_ni8430_exit(struct pci_dev *dev) { void __iomem *p; unsigned long base, len; @@ -422,7 +422,7 @@ static int sbs_init(struct pci_dev *dev) * Disables the global interrupt of PMC-OctalPro */ -static void __devexit sbs_exit(struct pci_dev *dev) +static void sbs_exit(struct pci_dev *dev) { u8 __iomem *p; @@ -991,7 +991,7 @@ static int pci_ite887x_init(struct pci_dev *dev) return ret; } -static void __devexit pci_ite887x_exit(struct pci_dev *dev) +static void pci_ite887x_exit(struct pci_dev *dev) { u32 ioport; /* the ioport is bit 0-15 in POSIO0R */ @@ -1040,6 +1040,253 @@ static int pci_asix_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +/* Quatech devices have their own extra interface features */ + +struct quatech_feature { + u16 devid; + bool amcc; +}; + +#define QPCR_TEST_FOR1 0x3F +#define QPCR_TEST_GET1 0x00 +#define QPCR_TEST_FOR2 0x40 +#define QPCR_TEST_GET2 0x40 +#define QPCR_TEST_FOR3 0x80 +#define QPCR_TEST_GET3 0x40 +#define QPCR_TEST_FOR4 0xC0 +#define QPCR_TEST_GET4 0x80 + +#define QOPR_CLOCK_X1 0x0000 +#define QOPR_CLOCK_X2 0x0001 +#define QOPR_CLOCK_X4 0x0002 +#define QOPR_CLOCK_X8 0x0003 +#define QOPR_CLOCK_RATE_MASK 0x0003 + + +static struct quatech_feature quatech_cards[] = { + { PCI_DEVICE_ID_QUATECH_QSC100, 1 }, + { PCI_DEVICE_ID_QUATECH_DSC100, 1 }, + { PCI_DEVICE_ID_QUATECH_DSC100E, 0 }, + { PCI_DEVICE_ID_QUATECH_DSC200, 1 }, + { PCI_DEVICE_ID_QUATECH_DSC200E, 0 }, + { PCI_DEVICE_ID_QUATECH_ESC100D, 1 }, + { PCI_DEVICE_ID_QUATECH_ESC100M, 1 }, + { PCI_DEVICE_ID_QUATECH_QSCP100, 1 }, + { PCI_DEVICE_ID_QUATECH_DSCP100, 1 }, + { PCI_DEVICE_ID_QUATECH_QSCP200, 1 }, + { PCI_DEVICE_ID_QUATECH_DSCP200, 1 }, + { PCI_DEVICE_ID_QUATECH_ESCLP100, 0 }, + { PCI_DEVICE_ID_QUATECH_QSCLP100, 0 }, + { PCI_DEVICE_ID_QUATECH_DSCLP100, 0 }, + { PCI_DEVICE_ID_QUATECH_SSCLP100, 0 }, + { PCI_DEVICE_ID_QUATECH_QSCLP200, 0 }, + { PCI_DEVICE_ID_QUATECH_DSCLP200, 0 }, + { PCI_DEVICE_ID_QUATECH_SSCLP200, 0 }, + { PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 }, + { 0, } +}; + +static int pci_quatech_amcc(u16 devid) +{ + struct quatech_feature *qf = &quatech_cards[0]; + while (qf->devid) { + if (qf->devid == devid) + return qf->amcc; + qf++; + } + pr_err("quatech: unknown port type '0x%04X'.\n", devid); + return 0; +}; + +static int pci_quatech_rqopr(struct uart_8250_port *port) +{ + unsigned long base = port->port.iobase; + u8 LCR, val; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + outb(LCR, base + UART_LCR); + return val; +} + +static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr) +{ + unsigned long base = port->port.iobase; + u8 LCR, val; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + outb(qopr, base + UART_SCR); + outb(LCR, base + UART_LCR); +} + +static int pci_quatech_rqmcr(struct uart_8250_port *port) +{ + unsigned long base = port->port.iobase; + u8 LCR, val, qmcr; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + outb(val | 0x10, base + UART_SCR); + qmcr = inb(base + UART_MCR); + outb(val, base + UART_SCR); + outb(LCR, base + UART_LCR); + + return qmcr; +} + +static void pci_quatech_wqmcr(struct uart_8250_port *port, u8 qmcr) +{ + unsigned long base = port->port.iobase; + u8 LCR, val; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + outb(val | 0x10, base + UART_SCR); + outb(qmcr, base + UART_MCR); + outb(val, base + UART_SCR); + outb(LCR, base + UART_LCR); +} + +static int pci_quatech_has_qmcr(struct uart_8250_port *port) +{ + unsigned long base = port->port.iobase; + u8 LCR, val; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + if (val & 0x20) { + outb(0x80, UART_LCR); + if (!(inb(UART_SCR) & 0x20)) { + outb(LCR, base + UART_LCR); + return 1; + } + } + return 0; +} + +static int pci_quatech_test(struct uart_8250_port *port) +{ + u8 reg; + u8 qopr = pci_quatech_rqopr(port); + pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1); + reg = pci_quatech_rqopr(port) & 0xC0; + if (reg != QPCR_TEST_GET1) + return -EINVAL; + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR2); + reg = pci_quatech_rqopr(port) & 0xC0; + if (reg != QPCR_TEST_GET2) + return -EINVAL; + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR3); + reg = pci_quatech_rqopr(port) & 0xC0; + if (reg != QPCR_TEST_GET3) + return -EINVAL; + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR4); + reg = pci_quatech_rqopr(port) & 0xC0; + if (reg != QPCR_TEST_GET4) + return -EINVAL; + + pci_quatech_wqopr(port, qopr); + return 0; +} + +static int pci_quatech_clock(struct uart_8250_port *port) +{ + u8 qopr, reg, set; + unsigned long clock; + + if (pci_quatech_test(port) < 0) + return 1843200; + + qopr = pci_quatech_rqopr(port); + + pci_quatech_wqopr(port, qopr & ~QOPR_CLOCK_X8); + reg = pci_quatech_rqopr(port); + if (reg & QOPR_CLOCK_X8) { + clock = 1843200; + goto out; + } + pci_quatech_wqopr(port, qopr | QOPR_CLOCK_X8); + reg = pci_quatech_rqopr(port); + if (!(reg & QOPR_CLOCK_X8)) { + clock = 1843200; + goto out; + } + reg &= QOPR_CLOCK_X8; + if (reg == QOPR_CLOCK_X2) { + clock = 3685400; + set = QOPR_CLOCK_X2; + } else if (reg == QOPR_CLOCK_X4) { + clock = 7372800; + set = QOPR_CLOCK_X4; + } else if (reg == QOPR_CLOCK_X8) { + clock = 14745600; + set = QOPR_CLOCK_X8; + } else { + clock = 1843200; + set = QOPR_CLOCK_X1; + } + qopr &= ~QOPR_CLOCK_RATE_MASK; + qopr |= set; + +out: + pci_quatech_wqopr(port, qopr); + return clock; +} + +static int pci_quatech_rs422(struct uart_8250_port *port) +{ + u8 qmcr; + int rs422 = 0; + + if (!pci_quatech_has_qmcr(port)) + return 0; + qmcr = pci_quatech_rqmcr(port); + pci_quatech_wqmcr(port, 0xFF); + if (pci_quatech_rqmcr(port)) + rs422 = 1; + pci_quatech_wqmcr(port, qmcr); + return rs422; +} + +static int pci_quatech_init(struct pci_dev *dev) +{ + if (pci_quatech_amcc(dev->device)) { + unsigned long base = pci_resource_start(dev, 0); + if (base) { + u32 tmp; + outl(inl(base + 0x38), base + 0x38); + tmp = inl(base + 0x3c); + outl(tmp | 0x01000000, base + 0x3c); + outl(tmp, base + 0x3c); + } + } + return 0; +} + +static int pci_quatech_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + /* Needed by pci_quatech calls below */ + port->port.iobase = pci_resource_start(priv->dev, FL_GET_BASE(board->flags)); + /* Set up the clocking */ + port->port.uartclk = pci_quatech_clock(port); + /* For now just warn about RS422 */ + if (pci_quatech_rs422(port)) + pr_warn("quatech: software control of RS422 features not currently supported.\n"); + return pci_default_setup(priv, board, port, idx); +} + +static void pci_quatech_exit(struct pci_dev *dev) +{ +} + static int pci_default_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1068,7 +1315,7 @@ ce4100_serial_setup(struct serial_private *priv, { int ret; - ret = setup_port(priv, port, 0, 0, board->reg_shift); + ret = setup_port(priv, port, idx, 0, board->reg_shift); port->port.iotype = UPIO_MEM32; port->port.type = PORT_XSCALE; port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); @@ -1085,6 +1332,18 @@ pci_omegapci_setup(struct serial_private *priv, return setup_port(priv, port, 2, idx * 8, 0); } +static int +pci_brcm_trumanage_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + int ret = pci_default_setup(priv, board, port, idx); + + port->port.type = PORT_BRCM_TRUMANAGE; + port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); + return ret; +} + static int skip_tx_en_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1165,6 +1424,94 @@ pci_xr17c154_setup(struct serial_private *priv, } static int +pci_xr17v35x_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + u8 __iomem *p; + + p = pci_ioremap_bar(priv->dev, 0); + if (p == NULL) + return -ENOMEM; + + port->port.flags |= UPF_EXAR_EFR; + + /* + * Setup Multipurpose Input/Output pins. + */ + if (idx == 0) { + writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/ + writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/ + writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/ + writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/ + writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/ + writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/ + writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/ + writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/ + writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/ + writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/ + writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/ + writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/ + } + writeb(0x00, p + UART_EXAR_8XMODE); + writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR); + writeb(128, p + UART_EXAR_TXTRG); + writeb(128, p + UART_EXAR_RXTRG); + iounmap(p); + + return pci_default_setup(priv, board, port, idx); +} + +#define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004 +#define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002 +#define PCI_DEVICE_ID_COMMTECH_2324PCI335 0x000a +#define PCI_DEVICE_ID_COMMTECH_2328PCI335 0x000b + +static int +pci_fastcom335_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + u8 __iomem *p; + + p = pci_ioremap_bar(priv->dev, 0); + if (p == NULL) + return -ENOMEM; + + port->port.flags |= UPF_EXAR_EFR; + + /* + * Setup Multipurpose Input/Output pins. + */ + if (idx == 0) { + switch (priv->dev->device) { + case PCI_DEVICE_ID_COMMTECH_4222PCI335: + case PCI_DEVICE_ID_COMMTECH_4224PCI335: + writeb(0x78, p + 0x90); /* MPIOLVL[7:0] */ + writeb(0x00, p + 0x92); /* MPIOINV[7:0] */ + writeb(0x00, p + 0x93); /* MPIOSEL[7:0] */ + break; + case PCI_DEVICE_ID_COMMTECH_2324PCI335: + case PCI_DEVICE_ID_COMMTECH_2328PCI335: + writeb(0x00, p + 0x90); /* MPIOLVL[7:0] */ + writeb(0xc0, p + 0x92); /* MPIOINV[7:0] */ + writeb(0xc0, p + 0x93); /* MPIOSEL[7:0] */ + break; + } + writeb(0x00, p + 0x8f); /* MPIOINT[7:0] */ + writeb(0x00, p + 0x91); /* MPIO3T[7:0] */ + writeb(0x00, p + 0x94); /* MPIOOD[7:0] */ + } + writeb(0x00, p + UART_EXAR_8XMODE); + writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR); + writeb(32, p + UART_EXAR_TXTRG); + writeb(32, p + UART_EXAR_RXTRG); + iounmap(p); + + return pci_default_setup(priv, board, port, idx); +} + +static int pci_wch_ch353_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1213,9 +1560,18 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_VENDOR_ID_AGESTAR 0x5372 #define PCI_DEVICE_ID_AGESTAR_9375 0x6872 #define PCI_VENDOR_ID_ASIX 0x9710 +#define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020 +#define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021 +#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 +#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a + +#define PCI_VENDOR_ID_SUNIX 0x1fd4 +#define PCI_DEVICE_ID_SUNIX_1999 0x1999 + /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 +#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588 /* * Master list of serial port init/setup/exit quirks. @@ -1314,7 +1670,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ite887x_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ite887x_exit), + .exit = pci_ite887x_exit, }, /* * National Instruments @@ -1326,7 +1682,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1335,7 +1691,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1344,7 +1700,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1353,7 +1709,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1362,7 +1718,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1371,7 +1727,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1380,7 +1736,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1389,7 +1745,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1398,7 +1754,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1407,7 +1763,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1416,7 +1772,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1425,7 +1781,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8420_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), + .exit = pci_ni8420_exit, }, { .vendor = PCI_VENDOR_ID_NI, @@ -1434,7 +1790,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_ni8430_init, .setup = pci_ni8430_setup, - .exit = __devexit_p(pci_ni8430_exit), + .exit = pci_ni8430_exit, + }, + /* Quatech */ + { + .vendor = PCI_VENDOR_ID_QUATECH, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_quatech_init, + .setup = pci_quatech_setup, + .exit = pci_quatech_exit, }, /* * Panacom @@ -1446,7 +1812,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_plx9050_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), + .exit = pci_plx9050_exit, }, { .vendor = PCI_VENDOR_ID_PANACOM, @@ -1455,7 +1821,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_plx9050_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), + .exit = pci_plx9050_exit, }, /* * PLX @@ -1474,7 +1840,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_SUBDEVICE_ID_EXSYS_4055, .init = pci_plx9050_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), + .exit = pci_plx9050_exit, }, { .vendor = PCI_VENDOR_ID_PLX, @@ -1483,16 +1849,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_SUBDEVICE_ID_KEYSPAN_SX2, .init = pci_plx9050_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), - }, - { - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_PLX_9050, - .subvendor = PCI_VENDOR_ID_PLX, - .subdevice = PCI_SUBDEVICE_ID_UNKNOWN_0x1584, - .init = pci_plx9050_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), + .exit = pci_plx9050_exit, }, { .vendor = PCI_VENDOR_ID_PLX, @@ -1501,7 +1858,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_DEVICE_ID_PLX_ROMULUS, .init = pci_plx9050_init, .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), + .exit = pci_plx9050_exit, }, /* * SBS Technologies, Inc., PMC-OCTALPRO 232 @@ -1513,7 +1870,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_SUBDEVICE_ID_OCTPRO232, .init = sbs_init, .setup = sbs_setup, - .exit = __devexit_p(sbs_exit), + .exit = sbs_exit, }, /* * SBS Technologies, Inc., PMC-OCTALPRO 422 @@ -1525,7 +1882,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_SUBDEVICE_ID_OCTPRO422, .init = sbs_init, .setup = sbs_setup, - .exit = __devexit_p(sbs_exit), + .exit = sbs_exit, }, /* * SBS Technologies, Inc., P-Octal 232 @@ -1537,7 +1894,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_SUBDEVICE_ID_POCTAL232, .init = sbs_init, .setup = sbs_setup, - .exit = __devexit_p(sbs_exit), + .exit = sbs_exit, }, /* * SBS Technologies, Inc., P-Octal 422 @@ -1549,7 +1906,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_SUBDEVICE_ID_POCTAL422, .init = sbs_init, .setup = sbs_setup, - .exit = __devexit_p(sbs_exit), + .exit = sbs_exit, }, /* * SIIG cards - these may be called via parport_serial @@ -1599,6 +1956,23 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_timedia_setup, }, /* + * SUNIX (Timedia) cards + * Do not "probe" for these cards as there is at least one combination + * card that should be handled by parport_pc that doesn't match the + * rule in pci_timedia_probe. + * It is part number is MIO5079A but its subdevice ID is 0x0102. + * There are some boards with part number SER5037AL that report + * subdevice ID 0x0002. + */ + { + .vendor = PCI_VENDOR_ID_SUNIX, + .device = PCI_DEVICE_ID_SUNIX_1999, + .subvendor = PCI_VENDOR_ID_SUNIX, + .subdevice = PCI_ANY_ID, + .init = pci_timedia_init, + .setup = pci_timedia_setup, + }, + /* * Exar cards */ { @@ -1622,6 +1996,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_xr17c154_setup, }, + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17V352, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17V354, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17V358, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, /* * Xircom cards */ @@ -1788,6 +2183,70 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_asix_setup, }, /* + * Commtech, Inc. Fastcom adapters + * + */ + { + .vendor = PCI_VENDOR_ID_COMMTECH, + .device = PCI_DEVICE_ID_COMMTECH_4222PCI335, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fastcom335_setup, + }, + { + .vendor = PCI_VENDOR_ID_COMMTECH, + .device = PCI_DEVICE_ID_COMMTECH_4224PCI335, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fastcom335_setup, + }, + { + .vendor = PCI_VENDOR_ID_COMMTECH, + .device = PCI_DEVICE_ID_COMMTECH_2324PCI335, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fastcom335_setup, + }, + { + .vendor = PCI_VENDOR_ID_COMMTECH, + .device = PCI_DEVICE_ID_COMMTECH_2328PCI335, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fastcom335_setup, + }, + { + .vendor = PCI_VENDOR_ID_COMMTECH, + .device = PCI_DEVICE_ID_COMMTECH_4222PCIE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, + { + .vendor = PCI_VENDOR_ID_COMMTECH, + .device = PCI_DEVICE_ID_COMMTECH_4224PCIE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, + { + .vendor = PCI_VENDOR_ID_COMMTECH, + .device = PCI_DEVICE_ID_COMMTECH_4228PCIE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, + /* + * Broadcom TruManage (NetXtreme) + */ + { + .vendor = PCI_VENDOR_ID_BROADCOM, + .device = PCI_DEVICE_ID_BROADCOM_TRUMANAGE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_brcm_trumanage_setup, + }, + + /* * Default "match everything" terminator entry */ { @@ -1863,6 +2322,10 @@ enum pci_board_num_t { pbn_b0_4_1152000, + pbn_b0_2_1152000_200, + pbn_b0_4_1152000_200, + pbn_b0_8_1152000_200, + pbn_b0_2_1843200, pbn_b0_4_1843200, @@ -1962,6 +2425,9 @@ enum pci_board_num_t { pbn_exar_XR17C152, pbn_exar_XR17C154, pbn_exar_XR17C158, + pbn_exar_XR17V352, + pbn_exar_XR17V354, + pbn_exar_XR17V358, pbn_exar_ibm_saturn, pbn_pasemi_1682M, pbn_ni8430_2, @@ -1975,6 +2441,7 @@ enum pci_board_num_t { pbn_ce4100_1_115200, pbn_omegapci, pbn_NETMOS9900_2s_115200, + pbn_brcm_trumanage, }; /* @@ -1987,7 +2454,7 @@ enum pci_board_num_t { * see first lines of serial_in() and serial_out() in 8250.c */ -static struct pciserial_board pci_boards[] __devinitdata = { +static struct pciserial_board pci_boards[] = { [pbn_default] = { .flags = FL_BASE0, .num_ports = 1, @@ -2057,6 +2524,27 @@ static struct pciserial_board pci_boards[] __devinitdata = { .uart_offset = 8, }, + [pbn_b0_2_1152000_200] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 1152000, + .uart_offset = 0x200, + }, + + [pbn_b0_4_1152000_200] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 1152000, + .uart_offset = 0x200, + }, + + [pbn_b0_8_1152000_200] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 1152000, + .uart_offset = 0x200, + }, + [pbn_b0_2_1843200] = { .flags = FL_BASE0, .num_ports = 2, @@ -2580,6 +3068,30 @@ static struct pciserial_board pci_boards[] __devinitdata = { .base_baud = 921600, .uart_offset = 0x200, }, + [pbn_exar_XR17V352] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 7812500, + .uart_offset = 0x400, + .reg_shift = 0, + .first_offset = 0, + }, + [pbn_exar_XR17V354] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 7812500, + .uart_offset = 0x400, + .reg_shift = 0, + .first_offset = 0, + }, + [pbn_exar_XR17V358] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 7812500, + .uart_offset = 0x400, + .reg_shift = 0, + .first_offset = 0, + }, [pbn_exar_ibm_saturn] = { .flags = FL_BASE0, .num_ports = 1, @@ -2658,8 +3170,8 @@ static struct pciserial_board pci_boards[] __devinitdata = { .first_offset = 0x1000, }, [pbn_ce4100_1_115200] = { - .flags = FL_BASE0, - .num_ports = 1, + .flags = FL_BASE_BARS, + .num_ports = 2, .base_baud = 921600, .reg_shift = 2, }, @@ -2674,6 +3186,12 @@ static struct pciserial_board pci_boards[] __devinitdata = { .num_ports = 2, .base_baud = 115200, }, + [pbn_brcm_trumanage] = { + .flags = FL_BASE0, + .num_ports = 1, + .reg_shift = 2, + .base_baud = 115200, + }, }; static const struct pci_device_id blacklist[] = { @@ -2691,7 +3209,7 @@ static const struct pci_device_id blacklist[] = { * guess what the configuration might be, based on the pitiful PCI * serial specs. Returns 0 on success, 1 on failure. */ -static int __devinit +static int serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) { const struct pci_device_id *bldev; @@ -2917,7 +3435,7 @@ EXPORT_SYMBOL_GPL(pciserial_resume_ports); * Probe one serial board. Unfortunately, there is no rhyme nor reason * to the arrangement of serial ports on a PCI card. */ -static int __devinit +static int pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { struct pci_serial_quirk *quirk; @@ -2988,7 +3506,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) return rc; } -static void __devexit pciserial_remove_one(struct pci_dev *dev) +static void pciserial_remove_one(struct pci_dev *dev) { struct serial_private *priv = pci_get_drvdata(dev); @@ -3207,7 +3725,12 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0, - pbn_b0_4_115200 }, + pbn_b2_4_115200 }, + /* Unknown card - subdevice 0x1588 */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_VENDOR_ID_PLX, + PCI_SUBDEVICE_ID_UNKNOWN_0x1588, 0, 0, + pbn_b2_8_115200 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_KEYSPAN, PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0, @@ -3257,18 +3780,70 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, 0x10b5, 0x106a, 0, 0, pbn_plx_romulus }, + /* + * Quatech cards. These actually have configurable clocks but for + * now we just use the default. + * + * 100 series are RS232, 200 series RS422, + */ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_4_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_8_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_8_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_8_115200 }, + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, @@ -3653,6 +4228,19 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_b0_bt_1_921600 }, /* + * SUNIX (TIMEDIA) + */ + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, + pbn_b0_bt_1_921600 }, + + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b0_bt_1_921600 }, + + /* * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org> */ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, @@ -3826,6 +4414,21 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_exar_XR17C158 }, + /* + * Exar Corp. XR17V35[248] Dual/Quad/Octal PCIe UARTs + */ + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V352 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V354, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V354 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V358, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V358 }, /* * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) @@ -4185,6 +4788,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_VENDOR_ID_IBM, 0x0299, 0, 0, pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, + 0x1000, 0x0012, + 0, 0, pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, 0xA000, 0x1000, 0, 0, pbn_b0_1_115200 }, @@ -4238,6 +4845,13 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_omegapci }, /* + * Broadcom TruManage + */ + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_brcm_trumanage }, + + /* * AgeStar as-prs2-009 */ { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375, @@ -4257,6 +4871,38 @@ static struct pci_device_id serial_pci_tbl[] = { 0, 0, pbn_b0_bt_2_115200 }, /* + * Commtech, Inc. Fastcom adapters + */ + { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4222PCI335, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_b0_2_1152000_200 }, + { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4224PCI335, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_b0_4_1152000_200 }, + { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_2324PCI335, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_b0_4_1152000_200 }, + { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_2328PCI335, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_b0_8_1152000_200 }, + { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4222PCIE, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V352 }, + { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4224PCIE, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V354 }, + { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4228PCIE, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V358 }, + + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL */ @@ -4323,7 +4969,7 @@ static const struct pci_error_handlers serial8250_err_handler = { static struct pci_driver serial_pci_driver = { .name = "serial", .probe = pciserial_init_one, - .remove = __devexit_p(pciserial_remove_one), + .remove = pciserial_remove_one, #ifdef CONFIG_PM .suspend = pciserial_suspend_one, .resume = pciserial_resume_one, @@ -4332,18 +4978,7 @@ static struct pci_driver serial_pci_driver = { .err_handler = &serial8250_err_handler, }; -static int __init serial8250_pci_init(void) -{ - return pci_register_driver(&serial_pci_driver); -} - -static void __exit serial8250_pci_exit(void) -{ - pci_unregister_driver(&serial_pci_driver); -} - -module_init(serial8250_pci_init); -module_exit(serial8250_pci_exit); +module_pci_driver(serial_pci_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module"); diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index f8ee25001dd0..b3455a970a1d 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -370,14 +370,14 @@ static const struct pnp_device_id pnp_dev_table[] = { MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -static char *modem_names[] __devinitdata = { +static char *modem_names[] = { "MODEM", "Modem", "modem", "FAX", "Fax", "fax", "56K", "56k", "K56", "33.6", "28.8", "14.4", "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", "33600", "28800", "14400", "V.90", "V.34", "V.32", NULL }; -static int __devinit check_name(char *name) +static int check_name(char *name) { char **tmp; @@ -388,7 +388,7 @@ static int __devinit check_name(char *name) return 0; } -static int __devinit check_resources(struct pnp_dev *dev) +static int check_resources(struct pnp_dev *dev) { resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8}; int i; @@ -412,7 +412,7 @@ static int __devinit check_resources(struct pnp_dev *dev) * PnP modems, alternatively we must hardcode all modems in pnp_devices[] * table. */ -static int __devinit serial_pnp_guess_board(struct pnp_dev *dev) +static int serial_pnp_guess_board(struct pnp_dev *dev) { if (!(check_name(pnp_dev_name(dev)) || (dev->card && check_name(dev->card->name)))) @@ -424,11 +424,12 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev) return -ENODEV; } -static int __devinit +static int serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { struct uart_8250_port uart; int ret, line, flags = dev_id->driver_data; + struct resource *res = NULL; if (flags & UNKNOWN_DEV) { ret = serial_pnp_guess_board(dev); @@ -439,11 +440,12 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) memset(&uart, 0, sizeof(uart)); if (pnp_irq_valid(dev, 0)) uart.port.irq = pnp_irq(dev, 0); - if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) { - uart.port.iobase = pnp_port_start(dev, 2); - uart.port.iotype = UPIO_PORT; - } else if (pnp_port_valid(dev, 0)) { - uart.port.iobase = pnp_port_start(dev, 0); + if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) + res = pnp_get_resource(dev, IORESOURCE_IO, 2); + else if (pnp_port_valid(dev, 0)) + res = pnp_get_resource(dev, IORESOURCE_IO, 0); + if (pnp_resource_enabled(res)) { + uart.port.iobase = res->start; uart.port.iotype = UPIO_PORT; } else if (pnp_mem_valid(dev, 0)) { uart.port.mapbase = pnp_mem_start(dev, 0); @@ -476,7 +478,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) return 0; } -static void __devexit serial_pnp_remove(struct pnp_dev *dev) +static void serial_pnp_remove(struct pnp_dev *dev) { long line = (long)pnp_get_drvdata(dev); if (line) @@ -511,7 +513,7 @@ static int serial_pnp_resume(struct pnp_dev *dev) static struct pnp_driver serial_pnp_driver = { .name = "serial", .probe = serial_pnp_probe, - .remove = __devexit_p(serial_pnp_remove), + .remove = serial_pnp_remove, .suspend = serial_pnp_suspend, .resume = serial_pnp_resume, .id_table = pnp_dev_table, diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index f3d283f2e3aa..2ef9537bcb2c 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -84,6 +84,14 @@ config SERIAL_8250_GSC depends on SERIAL_8250 && GSC default SERIAL_8250 +config SERIAL_8250_DMA + bool "DMA support for 16550 compatible UART controllers" if EXPERT + depends on SERIAL_8250 && DMADEVICES=y + default SERIAL_8250 + help + This builds DMA support that can be used with 8250/16650 + compatible UART controllers that support DMA signaling. + config SERIAL_8250_PCI tristate "8250/16550 PCI device support" if EXPERT depends on SERIAL_8250 && PCI @@ -249,15 +257,6 @@ config SERIAL_8250_ACORN system, say Y to this option. The driver can handle 1, 2, or 3 port cards. If unsure, say N. -config SERIAL_8250_RM9K - bool "Support for MIPS RM9xxx integrated serial port" - depends on SERIAL_8250 != n && SERIAL_RM9000 - select SERIAL_8250_SHARE_IRQ - help - Selecting this option will add support for the integrated serial - port hardware found on MIPS RM9122 and similar processors. - If unsure, say N. - config SERIAL_8250_FSL bool depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550 @@ -265,15 +264,23 @@ config SERIAL_8250_FSL config SERIAL_8250_DW tristate "Support for Synopsys DesignWare 8250 quirks" - depends on SERIAL_8250 && OF + depends on SERIAL_8250 help Selecting this option will enable handling of the extra features present in the Synopsys DesignWare APB UART. config SERIAL_8250_EM - tristate "Support for Emma Mobile intergrated serial port" + tristate "Support for Emma Mobile integrated serial port" depends on SERIAL_8250 && ARM && HAVE_CLK help Selecting this option will add support for the integrated serial port hardware found on the Emma Mobile line of processors. If unsure, say N. + +config SERIAL_8250_RT288X + bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" + depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883) + help + If you have a Ralink RT288x/RT305x SoC based board and want to use the + serial port, say Y to this option. The driver can handle up to 2 serial + ports. If unsure, say N. diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 108fe7fe13e2..a23838a4d535 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250_core.o 8250_core-y := 8250.o 8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o +8250_core-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 2a53be5f010d..7e7006fd404e 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -2,8 +2,10 @@ # Serial device configuration # +if TTY + menu "Serial drivers" - depends on HAS_IOMEM + depends on HAS_IOMEM && GENERIC_HARDIRQS source "drivers/tty/serial/8250/Kconfig" @@ -93,7 +95,7 @@ config SERIAL_SB1250_DUART_CONSOLE config SERIAL_ATMEL bool "AT91 / AT32 on-chip serial port support" - depends on (ARM && ARCH_AT91) || AVR32 + depends on ARCH_AT91 || AVR32 select SERIAL_CORE help This enables the driver for the on-chip UARTs of the Atmel @@ -198,7 +200,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" - depends on ARM && PLAT_SAMSUNG + depends on PLAT_SAMSUNG select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, @@ -208,15 +210,15 @@ config SERIAL_SAMSUNG config SERIAL_SAMSUNG_UARTS_4 bool - depends on ARM && PLAT_SAMSUNG - default y if !(CPU_S3C2410 || SERIAL_S3C2412 || CPU_S3C2440 || CPU_S3C2442) + depends on PLAT_SAMSUNG + default y if !(CPU_S3C2410 || CPU_S3C2412 || CPU_S3C2440 || CPU_S3C2442) help Internal node for the common case of 4 Samsung compatible UARTs config SERIAL_SAMSUNG_UARTS int - depends on ARM && PLAT_SAMSUNG - default 6 if ARCH_S5P6450 + depends on PLAT_SAMSUNG + default 6 if CPU_S5P6450 default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416 default 3 help @@ -249,7 +251,7 @@ config SERIAL_SAMSUNG_CONSOLE config SERIAL_SIRFSOC tristate "SiRF SoC Platform Serial port support" - depends on ARM && ARCH_PRIMA2 + depends on ARCH_PRIMA2 select SERIAL_CORE help Support for the on-chip UART on the CSR SiRFprimaII series, @@ -269,6 +271,17 @@ config SERIAL_SIRFSOC_CONSOLE your boot loader about how to pass options to the kernel at boot time.) +config SERIAL_TEGRA + tristate "NVIDIA Tegra20/30 SoC serial controller" + depends on ARCH_TEGRA && TEGRA20_APB_DMA + select SERIAL_CORE + help + Support for the on-chip UARTs on the NVIDIA Tegra series SOCs + providing /dev/ttyHS0, 1, 2, 3 and 4 (note, some machines may not + provide all of these ports, depending on how the serial port + are enabled). This driver uses the APB DMA to achieve higher baudrate + and better performance. + config SERIAL_MAX3100 tristate "MAX3100 support" depends on SPI @@ -347,7 +360,7 @@ config SERIAL_ZS_CONSOLE config SERIAL_21285 tristate "DC21285 serial port support" - depends on ARM && FOOTBRIDGE + depends on FOOTBRIDGE select SERIAL_CORE help If you have a machine based on a 21285 (Footbridge) StrongARM(R)/ @@ -371,7 +384,7 @@ config SERIAL_21285_CONSOLE config SERIAL_MPSC bool "Marvell MPSC serial port support" - depends on PPC32 && MV64X60 + depends on MV64X60 select SERIAL_CORE help Say Y here if you want to use the Marvell MPSC serial controller. @@ -408,7 +421,7 @@ config SERIAL_PXA_CONSOLE config SERIAL_SA1100 bool "SA1100 serial port support" - depends on ARM && ARCH_SA1100 + depends on ARCH_SA1100 select SERIAL_CORE help If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you @@ -716,19 +729,19 @@ config SERIAL_SH_SCI_DMA config SERIAL_PNX8XXX bool "Enable PNX8XXX SoCs' UART Support" - depends on MIPS && (SOC_PNX8550 || SOC_PNX833X) + depends on SOC_PNX833X select SERIAL_CORE help - If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 - and you want to use serial ports, say Y. Otherwise, say N. + If you have a MIPS-based Philips SoC such as PNX8330 and you want + to use serial ports, say Y. Otherwise, say N. config SERIAL_PNX8XXX_CONSOLE bool "Enable PNX8XX0 serial console" depends on SERIAL_PNX8XXX select SERIAL_CORE_CONSOLE help - If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 - and you want to use serial console, say Y. Otherwise, say N. + If you have a MIPS-based Philips SoC such as PNX8330 and you want + to use serial console, say Y. Otherwise, say N. config SERIAL_HS_LPC32XX tristate "LPC32XX high speed serial port support" @@ -1013,7 +1026,7 @@ config SERIAL_SGI_IOC3 config SERIAL_MSM bool "MSM on-chip serial port support" - depends on ARM && ARCH_MSM + depends on ARCH_MSM select SERIAL_CORE config SERIAL_MSM_CONSOLE @@ -1035,7 +1048,7 @@ config SERIAL_MSM_HS config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" - depends on ARM && ARCH_VT8500 + depends on ARCH_VT8500 select SERIAL_CORE config SERIAL_VT8500_CONSOLE @@ -1045,7 +1058,7 @@ config SERIAL_VT8500_CONSOLE config SERIAL_NETX tristate "NetX serial port support" - depends on ARM && ARCH_NETX + depends on ARCH_NETX select SERIAL_CORE help If you have a machine based on a Hilscher NetX SoC you @@ -1376,6 +1389,7 @@ config SERIAL_MXS_AUART_CONSOLE config SERIAL_XILINX_PS_UART tristate "Xilinx PS UART support" + depends on OF select SERIAL_CORE help This driver supports the Xilinx PS UART port. @@ -1423,4 +1437,53 @@ config SERIAL_EFM32_UART_CONSOLE depends on SERIAL_EFM32_UART=y select SERIAL_CORE_CONSOLE +config SERIAL_ARC + tristate "ARC UART driver support" + select SERIAL_CORE + help + Driver for on-chip UART for ARC(Synopsys) for the legacy + FPGA Boards (ML50x/ARCAngel4) + +config SERIAL_ARC_CONSOLE + bool "Console on ARC UART" + depends on SERIAL_ARC=y + select SERIAL_CORE_CONSOLE + help + Enable system Console on ARC UART + +config SERIAL_ARC_NR_PORTS + int "Number of ARC UART ports" + depends on SERIAL_ARC + range 1 3 + default "1" + help + Set this to the number of serial ports you want the driver + to support. + +config SERIAL_RP2 + tristate "Comtrol RocketPort EXPRESS/INFINITY support" + depends on PCI + select SERIAL_CORE + help + This driver supports the Comtrol RocketPort EXPRESS and + RocketPort INFINITY families of PCI/PCIe multiport serial adapters. + These adapters use a "RocketPort 2" ASIC that is not compatible + with the original RocketPort driver (CONFIG_ROCKETPORT). + + To compile this driver as a module, choose M here: the + module will be called rp2. + + If you want to compile this driver into the kernel, say Y here. If + you don't have a suitable RocketPort card installed, say N. + +config SERIAL_RP2_NR_UARTS + int "Maximum number of RocketPort EXPRESS/INFINITY ports" + depends on SERIAL_RP2 + default "32" + help + If multiple cards are present, the default limit of 32 ports may + need to be increased. + endmenu + +endif # TTY diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 4f694dafa719..eedfec40e3dd 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -80,5 +80,8 @@ obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o +obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o +obj-$(CONFIG_SERIAL_ARC) += arc_uart.o +obj-$(CONFIG_SERIAL_RP2) += rp2.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 530181e49f6b..c6bdb943726b 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -139,7 +139,7 @@ static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp) uart_insert_char(port, 0, 0, ch, flag); } - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(&port->state->port); } static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp) @@ -406,7 +406,7 @@ static struct uart_driver altera_jtaguart_driver = { .cons = ALTERA_JTAGUART_CONSOLE, }; -static int __devinit altera_jtaguart_probe(struct platform_device *pdev) +static int altera_jtaguart_probe(struct platform_device *pdev) { struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data; struct uart_port *port; @@ -453,7 +453,7 @@ static int __devinit altera_jtaguart_probe(struct platform_device *pdev) return 0; } -static int __devexit altera_jtaguart_remove(struct platform_device *pdev) +static int altera_jtaguart_remove(struct platform_device *pdev) { struct uart_port *port; int i = pdev->id; @@ -477,7 +477,7 @@ MODULE_DEVICE_TABLE(of, altera_jtaguart_match); static struct platform_driver altera_jtaguart_platform_driver = { .probe = altera_jtaguart_probe, - .remove = __devexit_p(altera_jtaguart_remove), + .remove = altera_jtaguart_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, @@ -493,11 +493,9 @@ static int __init altera_jtaguart_init(void) if (rc) return rc; rc = platform_driver_register(&altera_jtaguart_platform_driver); - if (rc) { + if (rc) uart_unregister_driver(&altera_jtaguart_driver); - return rc; - } - return 0; + return rc; } static void __exit altera_jtaguart_exit(void) diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 15d80b9fb303..13471dd95793 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -231,7 +231,7 @@ static void altera_uart_rx_chars(struct altera_uart *pp) flag); } - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(&port->state->port); } static void altera_uart_tx_chars(struct altera_uart *pp) @@ -532,7 +532,7 @@ static int altera_uart_get_of_uartclk(struct platform_device *pdev, } #endif /* CONFIG_OF */ -static int __devinit altera_uart_probe(struct platform_device *pdev) +static int altera_uart_probe(struct platform_device *pdev) { struct altera_uart_platform_uart *platp = pdev->dev.platform_data; struct uart_port *port; @@ -598,7 +598,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) return 0; } -static int __devexit altera_uart_remove(struct platform_device *pdev) +static int altera_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); @@ -621,7 +621,7 @@ MODULE_DEVICE_TABLE(of, altera_uart_match); static struct platform_driver altera_uart_platform_driver = { .probe = altera_uart_probe, - .remove = __devexit_p(altera_uart_remove), + .remove = altera_uart_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, @@ -637,11 +637,9 @@ static int __init altera_uart_init(void) if (rc) return rc; rc = platform_driver_register(&altera_uart_platform_driver); - if (rc) { + if (rc) uart_unregister_driver(&altera_uart_driver); - return rc; - } - return 0; + return rc; } static void __exit altera_uart_exit(void) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 22317dd16474..c36840519527 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -116,7 +116,6 @@ static void pl010_enable_ms(struct uart_port *port) static void pl010_rx_chars(struct uart_amba_port *uap) { - struct tty_struct *tty = uap->port.state->port.tty; unsigned int status, ch, flag, rsr, max_count = 256; status = readb(uap->port.membase + UART01x_FR); @@ -165,7 +164,7 @@ static void pl010_rx_chars(struct uart_amba_port *uap) status = readb(uap->port.membase + UART01x_FR); } spin_unlock(&uap->port.lock); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&uap->port.state->port); spin_lock(&uap->port.lock); } diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index d7e1edec50b5..3ea5408fcbeb 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -56,8 +56,7 @@ #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/sizes.h> - -#include <asm/io.h> +#include <linux/io.h> #define UART_NR 14 @@ -699,7 +698,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, u32 pending, bool use_buf_b, bool readfifo) { - struct tty_struct *tty = uap->port.state->port.tty; + struct tty_port *port = &uap->port.state->port; struct pl011_sgbuf *sgbuf = use_buf_b ? &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; struct device *dev = uap->dmarx.chan->device->dev; @@ -716,8 +715,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, * Note that tty_insert_flip_buf() tries to take as many chars * as it can. */ - dma_count = tty_insert_flip_string(uap->port.state->port.tty, - sgbuf->buf, pending); + dma_count = tty_insert_flip_string(port, sgbuf->buf, pending); /* Return buffer to device */ dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE); @@ -755,7 +753,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, dev_vdbg(uap->port.dev, "Took %d chars from DMA buffer and %d chars from the FIFO\n", dma_count, fifotaken); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port); spin_lock(&uap->port.lock); } @@ -1077,12 +1075,10 @@ static void pl011_enable_ms(struct uart_port *port) static void pl011_rx_chars(struct uart_amba_port *uap) { - struct tty_struct *tty = uap->port.state->port.tty; - pl011_fifo_to_tty(uap); spin_unlock(&uap->port.lock); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&uap->port.state->port); /* * If we were temporarily out of DMA mode for a while, * attempt to switch back to DMA mode again. @@ -1973,7 +1969,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) goto out; } - uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); + uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port), + GFP_KERNEL); if (uap == NULL) { ret = -ENOMEM; goto out; @@ -1981,16 +1978,17 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) i = pl011_probe_dt_alias(i, &dev->dev); - base = ioremap(dev->res.start, resource_size(&dev->res)); + base = devm_ioremap(&dev->dev, dev->res.start, + resource_size(&dev->res)); if (!base) { ret = -ENOMEM; - goto free; + goto out; } uap->pinctrl = devm_pinctrl_get(&dev->dev); if (IS_ERR(uap->pinctrl)) { ret = PTR_ERR(uap->pinctrl); - goto unmap; + goto out; } uap->pins_default = pinctrl_lookup_state(uap->pinctrl, PINCTRL_STATE_DEFAULT); @@ -2002,10 +2000,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) if (IS_ERR(uap->pins_sleep)) dev_dbg(&dev->dev, "could not get sleep pinstate\n"); - uap->clk = clk_get(&dev->dev, NULL); + uap->clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(uap->clk)) { ret = PTR_ERR(uap->clk); - goto unmap; + goto out; } uap->vendor = vendor; @@ -2038,11 +2036,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; pl011_dma_remove(uap); - clk_put(uap->clk); - unmap: - iounmap(base); - free: - kfree(uap); } out: return ret; @@ -2062,9 +2055,6 @@ static int pl011_remove(struct amba_device *dev) amba_ports[i] = NULL; pl011_dma_remove(uap); - iounmap(uap->port.membase); - clk_put(uap->clk); - kfree(uap); return 0; } diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 7162f70d9260..6331464d9101 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -78,7 +78,6 @@ static void apbuart_enable_ms(struct uart_port *port) 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; @@ -126,7 +125,7 @@ static void apbuart_rx_chars(struct uart_port *port) status = UART_GET_STATUS(port); } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); } static void apbuart_tx_chars(struct uart_port *port) @@ -554,7 +553,7 @@ static struct uart_driver grlib_apbuart_driver = { /* OF Platform Driver */ /* ======================================================================== */ -static int __devinit apbuart_probe(struct platform_device *op) +static int apbuart_probe(struct platform_device *op) { int i; struct uart_port *port = NULL; diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index e4f60e2b87f3..27f20c57abed 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -25,11 +25,19 @@ #include <linux/io.h> #include <linux/irq.h> +#include <asm/div64.h> + #include <asm/mach-ath79/ar933x_uart.h> #include <asm/mach-ath79/ar933x_uart_platform.h> #define DRIVER_NAME "ar933x-uart" +#define AR933X_UART_MAX_SCALE 0xff +#define AR933X_UART_MAX_STEP 0xffff + +#define AR933X_UART_MIN_BAUD 300 +#define AR933X_UART_MAX_BAUD 3000000 + #define AR933X_DUMMY_STATUS_RD 0x01 static struct uart_driver ar933x_uart_driver; @@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_driver; struct ar933x_uart_port { struct uart_port port; unsigned int ier; /* shadow Interrupt Enable Register */ + unsigned int min_baud; + unsigned int max_baud; }; static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, @@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct uart_port *port) { } +/* + * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17)) + */ +static unsigned long ar933x_uart_get_baud(unsigned int clk, + unsigned int scale, + unsigned int step) +{ + u64 t; + u32 div; + + div = (2 << 16) * (scale + 1); + t = clk; + t *= step; + t += (div / 2); + do_div(t, div); + + return t; +} + +static void ar933x_uart_get_scale_step(unsigned int clk, + unsigned int baud, + unsigned int *scale, + unsigned int *step) +{ + unsigned int tscale; + long min_diff; + + *scale = 0; + *step = 0; + + min_diff = baud; + for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) { + u64 tstep; + int diff; + + tstep = baud * (tscale + 1); + tstep *= (2 << 16); + do_div(tstep, clk); + + if (tstep > AR933X_UART_MAX_STEP) + break; + + diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud); + if (diff < min_diff) { + min_diff = diff; + *scale = tscale; + *step = tstep; + } + } +} + static void ar933x_uart_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old) @@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(struct uart_port *port, struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; unsigned int cs; unsigned long flags; - unsigned int baud, scale; + unsigned int baud, scale, step; /* Only CS8 is supported */ new->c_cflag &= ~CSIZE; @@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(struct uart_port *port, /* Mark/space parity is not supported */ new->c_cflag &= ~CMSPAR; - baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); - scale = (port->uartclk / (16 * baud)) - 1; + baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud); + ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step); /* * Ok, we're now changing the port state. Do it with @@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(struct uart_port *port, */ spin_lock_irqsave(&up->port.lock, flags); + /* disable the UART */ + ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, + AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S); + /* Update the per-port timeout. */ uart_update_timeout(port, new->c_cflag, baud); @@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(struct uart_port *port, up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD; ar933x_uart_write(up, AR933X_UART_CLOCK_REG, - scale << AR933X_UART_CLOCK_SCALE_S | 8192); + scale << AR933X_UART_CLOCK_SCALE_S | step); /* setup configuration register */ ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs); @@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(struct uart_port *port, ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, AR933X_UART_CS_HOST_INT_EN); + /* reenable the UART */ + ar933x_uart_rmw(up, AR933X_UART_CS_REG, + AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S, + AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S); + spin_unlock_irqrestore(&up->port.lock, flags); if (tty_termios_baud_rate(new)) @@ -227,10 +297,9 @@ static void ar933x_uart_set_termios(struct uart_port *port, static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) { - struct tty_struct *tty; + struct tty_port *port = &up->port.state->port; int max_count = 256; - tty = tty_port_tty_get(&up->port.state->port); do { unsigned int rdata; unsigned char ch; @@ -243,11 +312,6 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) ar933x_uart_write(up, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); - if (!tty) { - /* discard the data if no tty available */ - continue; - } - up->port.icount.rx++; ch = rdata & AR933X_UART_DATA_TX_RX_MASK; @@ -255,13 +319,10 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) continue; if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) - tty_insert_flip_char(tty, ch, TTY_NORMAL); + tty_insert_flip_char(port, ch, TTY_NORMAL); } while (max_count-- > 0); - if (tty) { - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } + tty_flip_buffer_push(port); } static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) @@ -401,6 +462,8 @@ static void ar933x_uart_config_port(struct uart_port *port, int flags) static int ar933x_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_AR933X) return -EINVAL; @@ -408,7 +471,8 @@ static int ar933x_uart_verify_port(struct uart_port *port, if (ser->irq < 0 || ser->irq >= NR_IRQS) return -EINVAL; - if (ser->baud_base < 28800) + if (ser->baud_base < up->min_baud || + ser->baud_base > up->max_baud) return -EINVAL; return 0; @@ -554,13 +618,14 @@ static struct uart_driver ar933x_uart_driver = { .cons = AR933X_SERIAL_CONSOLE, }; -static int __devinit ar933x_uart_probe(struct platform_device *pdev) +static int ar933x_uart_probe(struct platform_device *pdev) { struct ar933x_uart_platform_data *pdata; struct ar933x_uart_port *up; struct uart_port *port; struct resource *mem_res; struct resource *irq_res; + unsigned int baud; int id; int ret; @@ -611,6 +676,12 @@ static int __devinit ar933x_uart_probe(struct platform_device *pdev) port->fifosize = AR933X_UART_FIFO_SIZE; port->ops = &ar933x_uart_ops; + baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); + up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); + + baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); + up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); + ar933x_uart_add_console_port(up); ret = uart_add_one_port(&ar933x_uart_driver, &up->port); @@ -627,7 +698,7 @@ err_free_up: return ret; } -static int __devexit ar933x_uart_remove(struct platform_device *pdev) +static int ar933x_uart_remove(struct platform_device *pdev) { struct ar933x_uart_port *up; @@ -645,7 +716,7 @@ static int __devexit ar933x_uart_remove(struct platform_device *pdev) static struct platform_driver ar933x_uart_platform_driver = { .probe = ar933x_uart_probe, - .remove = __devexit_p(ar933x_uart_remove), + .remove = ar933x_uart_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c new file mode 100644 index 000000000000..d97e194b6bc5 --- /dev/null +++ b/drivers/tty/serial/arc_uart.c @@ -0,0 +1,778 @@ +/* + * ARC On-Chip(fpga) UART Driver + * + * Copyright (C) 2010-2012 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * vineetg: July 10th 2012 + * -Decoupled the driver from arch/arc + * +Using platform_get_resource() for irq/membase (thx to bfin_uart.c) + * +Using early_platform_xxx() for early console (thx to mach-shmobile/xxx) + * + * Vineetg: Aug 21st 2010 + * -Is uart_tx_stopped() not done in tty write path as it has already been + * taken care of, in serial core + * + * Vineetg: Aug 18th 2010 + * -New Serial Core based ARC UART driver + * -Derived largely from blackfin driver albiet with some major tweaks + * + * TODO: + * -check if sysreq works + */ + +#if defined(CONFIG_SERIAL_ARC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/module.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/platform_device.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_core.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_platform.h> + +/************************************* + * ARC UART Hardware Specs + ************************************/ +#define ARC_UART_TX_FIFO_SIZE 1 + +/* + * UART Register set (this is not a Standards Compliant IP) + * Also each reg is Word aligned, but only 8 bits wide + */ +#define R_ID0 0 +#define R_ID1 4 +#define R_ID2 8 +#define R_ID3 12 +#define R_DATA 16 +#define R_STS 20 +#define R_BAUDL 24 +#define R_BAUDH 28 + +/* Bits for UART Status Reg (R/W) */ +#define RXIENB 0x04 /* Receive Interrupt Enable */ +#define TXIENB 0x40 /* Transmit Interrupt Enable */ + +#define RXEMPTY 0x20 /* Receive FIFO Empty: No char receivede */ +#define TXEMPTY 0x80 /* Transmit FIFO Empty, thus char can be written into */ + +#define RXFULL 0x08 /* Receive FIFO full */ +#define RXFULL1 0x10 /* Receive FIFO has space for 1 char (tot space=4) */ + +#define RXFERR 0x01 /* Frame Error: Stop Bit not detected */ +#define RXOERR 0x02 /* OverFlow Err: Char recv but RXFULL still set */ + +/* Uart bit fiddling helpers: lowest level */ +#define RBASE(uart, reg) (uart->port.membase + reg) +#define UART_REG_SET(u, r, v) writeb((v), RBASE(u, r)) +#define UART_REG_GET(u, r) readb(RBASE(u, r)) + +#define UART_REG_OR(u, r, v) UART_REG_SET(u, r, UART_REG_GET(u, r) | (v)) +#define UART_REG_CLR(u, r, v) UART_REG_SET(u, r, UART_REG_GET(u, r) & ~(v)) + +/* Uart bit fiddling helpers: API level */ +#define UART_SET_DATA(uart, val) UART_REG_SET(uart, R_DATA, val) +#define UART_GET_DATA(uart) UART_REG_GET(uart, R_DATA) + +#define UART_SET_BAUDH(uart, val) UART_REG_SET(uart, R_BAUDH, val) +#define UART_SET_BAUDL(uart, val) UART_REG_SET(uart, R_BAUDL, val) + +#define UART_CLR_STATUS(uart, val) UART_REG_CLR(uart, R_STS, val) +#define UART_GET_STATUS(uart) UART_REG_GET(uart, R_STS) + +#define UART_ALL_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, RXIENB|TXIENB) +#define UART_RX_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, RXIENB) +#define UART_TX_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, TXIENB) + +#define UART_ALL_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, RXIENB|TXIENB) +#define UART_RX_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, RXIENB) +#define UART_TX_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, TXIENB) + +#define ARC_SERIAL_DEV_NAME "ttyARC" + +struct arc_uart_port { + struct uart_port port; + unsigned long baud; + int is_emulated; /* H/w vs. Instruction Set Simulator */ +}; + +#define to_arc_port(uport) container_of(uport, struct arc_uart_port, port) + +static struct arc_uart_port arc_uart_ports[CONFIG_SERIAL_ARC_NR_PORTS]; + +#ifdef CONFIG_SERIAL_ARC_CONSOLE +static struct console arc_console; +#endif + +#define DRIVER_NAME "arc-uart" + +static struct uart_driver arc_uart_driver = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = ARC_SERIAL_DEV_NAME, + .major = 0, + .minor = 0, + .nr = CONFIG_SERIAL_ARC_NR_PORTS, +#ifdef CONFIG_SERIAL_ARC_CONSOLE + .cons = &arc_console, +#endif +}; + +static void arc_serial_stop_rx(struct uart_port *port) +{ + struct arc_uart_port *uart = to_arc_port(port); + + UART_RX_IRQ_DISABLE(uart); +} + +static void arc_serial_stop_tx(struct uart_port *port) +{ + struct arc_uart_port *uart = to_arc_port(port); + + while (!(UART_GET_STATUS(uart) & TXEMPTY)) + cpu_relax(); + + UART_TX_IRQ_DISABLE(uart); +} + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int arc_serial_tx_empty(struct uart_port *port) +{ + struct arc_uart_port *uart = to_arc_port(port); + unsigned int stat; + + stat = UART_GET_STATUS(uart); + if (stat & TXEMPTY) + return TIOCSER_TEMT; + + return 0; +} + +/* + * Driver internal routine, used by both tty(serial core) as well as tx-isr + * -Called under spinlock in either cases + * -also tty->stopped / tty->hw_stopped has already been checked + * = by uart_start( ) before calling us + * = tx_ist checks that too before calling + */ +static void arc_serial_tx_chars(struct arc_uart_port *uart) +{ + struct circ_buf *xmit = &uart->port.state->xmit; + int sent = 0; + unsigned char ch; + + if (unlikely(uart->port.x_char)) { + UART_SET_DATA(uart, uart->port.x_char); + uart->port.icount.tx++; + uart->port.x_char = 0; + sent = 1; + } else if (xmit->tail != xmit->head) { /* TODO: uart_circ_empty */ + ch = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + uart->port.icount.tx++; + while (!(UART_GET_STATUS(uart) & TXEMPTY)) + cpu_relax(); + UART_SET_DATA(uart, ch); + sent = 1; + } + + /* + * If num chars in xmit buffer are too few, ask tty layer for more. + * By Hard ISR to schedule processing in software interrupt part + */ + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uart->port); + + if (sent) + UART_TX_IRQ_ENABLE(uart); +} + +/* + * port is locked and interrupts are disabled + * uart_start( ) calls us under the port spinlock irqsave + */ +static void arc_serial_start_tx(struct uart_port *port) +{ + struct arc_uart_port *uart = to_arc_port(port); + + arc_serial_tx_chars(uart); +} + +static void arc_serial_rx_chars(struct arc_uart_port *uart) +{ + unsigned int status, ch, flg = 0; + + /* + * UART has 4 deep RX-FIFO. Driver's recongnition of this fact + * is very subtle. Here's how ... + * Upon getting a RX-Intr, such that RX-EMPTY=0, meaning data available, + * driver reads the DATA Reg and keeps doing that in a loop, until + * RX-EMPTY=1. Multiple chars being avail, with a single Interrupt, + * before RX-EMPTY=0, implies some sort of buffering going on in the + * controller, which is indeed the Rx-FIFO. + */ + while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)) { + + ch = UART_GET_DATA(uart); + uart->port.icount.rx++; + + if (unlikely(status & (RXOERR | RXFERR))) { + if (status & RXOERR) { + uart->port.icount.overrun++; + flg = TTY_OVERRUN; + UART_CLR_STATUS(uart, RXOERR); + } + + if (status & RXFERR) { + uart->port.icount.frame++; + flg = TTY_FRAME; + UART_CLR_STATUS(uart, RXFERR); + } + } else + flg = TTY_NORMAL; + + if (unlikely(uart_handle_sysrq_char(&uart->port, ch))) + goto done; + + uart_insert_char(&uart->port, status, RXOERR, ch, flg); + +done: + tty_flip_buffer_push(&uart->port.state->port); + } +} + +/* + * A note on the Interrupt handling state machine of this driver + * + * kernel printk writes funnel thru the console driver framework and in order + * to keep things simple as well as efficient, it writes to UART in polled + * mode, in one shot, and exits. + * + * OTOH, Userland output (via tty layer), uses interrupt based writes as there + * can be undeterministic delay between char writes. + * + * Thus Rx-interrupts are always enabled, while tx-interrupts are by default + * disabled. + * + * When tty has some data to send out, serial core calls driver's start_tx + * which + * -checks-if-tty-buffer-has-char-to-send + * -writes-data-to-uart + * -enable-tx-intr + * + * Once data bits are pushed out, controller raises the Tx-room-avail-Interrupt. + * The first thing Tx ISR does is disable further Tx interrupts (as this could + * be the last char to send, before settling down into the quiet polled mode). + * It then calls the exact routine used by tty layer write to send out any + * more char in tty buffer. In case of sending, it re-enables Tx-intr. In case + * of no data, it remains disabled. + * This is how the transmit state machine is dynamically switched on/off + */ + +static irqreturn_t arc_serial_isr(int irq, void *dev_id) +{ + struct arc_uart_port *uart = dev_id; + unsigned int status; + + status = UART_GET_STATUS(uart); + + /* + * Single IRQ for both Rx (data available) Tx (room available) Interrupt + * notifications from the UART Controller. + * To demultiplex between the two, we check the relevant bits + */ + if ((status & RXIENB) && !(status & RXEMPTY)) { + + /* already in ISR, no need of xx_irqsave */ + spin_lock(&uart->port.lock); + arc_serial_rx_chars(uart); + spin_unlock(&uart->port.lock); + } + + if ((status & TXIENB) && (status & TXEMPTY)) { + + /* Unconditionally disable further Tx-Interrupts. + * will be enabled by tx_chars() if needed. + */ + UART_TX_IRQ_DISABLE(uart); + + spin_lock(&uart->port.lock); + + if (!uart_tx_stopped(&uart->port)) + arc_serial_tx_chars(uart); + + spin_unlock(&uart->port.lock); + } + + return IRQ_HANDLED; +} + +static unsigned int arc_serial_get_mctrl(struct uart_port *port) +{ + /* + * Pretend we have a Modem status reg and following bits are + * always set, to satify the serial core state machine + * (DSR) Data Set Ready + * (CTS) Clear To Send + * (CAR) Carrier Detect + */ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void arc_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* MCR not present */ +} + +/* Enable Modem Status Interrupts */ + +static void arc_serial_enable_ms(struct uart_port *port) +{ + /* MSR not present */ +} + +static void arc_serial_break_ctl(struct uart_port *port, int break_state) +{ + /* ARC UART doesn't support sending Break signal */ +} + +static int arc_serial_startup(struct uart_port *port) +{ + struct arc_uart_port *uart = to_arc_port(port); + + /* Before we hook up the ISR, Disable all UART Interrupts */ + UART_ALL_IRQ_DISABLE(uart); + + if (request_irq(uart->port.irq, arc_serial_isr, 0, "arc uart rx-tx", + uart)) { + dev_warn(uart->port.dev, "Unable to attach ARC UART intr\n"); + return -EBUSY; + } + + UART_RX_IRQ_ENABLE(uart); /* Only Rx IRQ enabled to begin with */ + + return 0; +} + +/* This is not really needed */ +static void arc_serial_shutdown(struct uart_port *port) +{ + struct arc_uart_port *uart = to_arc_port(port); + free_irq(uart->port.irq, uart); +} + +static void +arc_serial_set_termios(struct uart_port *port, struct ktermios *new, + struct ktermios *old) +{ + struct arc_uart_port *uart = to_arc_port(port); + unsigned int baud, uartl, uarth, hw_val; + unsigned long flags; + + /* + * Use the generic handler so that any specially encoded baud rates + * such as SPD_xx flags or "%B0" can be handled + * Max Baud I suppose will not be more than current 115K * 4 + * Formula for ARC UART is: hw-val = ((CLK/(BAUD*4)) -1) + * spread over two 8-bit registers + */ + baud = uart_get_baud_rate(port, new, old, 0, 460800); + + hw_val = port->uartclk / (uart->baud * 4) - 1; + uartl = hw_val & 0xFF; + uarth = (hw_val >> 8) & 0xFF; + + /* + * UART ISS(Instruction Set simulator) emulation has a subtle bug: + * A existing value of Baudh = 0 is used as a indication to startup + * it's internal state machine. + * Thus if baudh is set to 0, 2 times, it chokes. + * This happens with BAUD=115200 and the formaula above + * Until that is fixed, when running on ISS, we will set baudh to !0 + */ + if (uart->is_emulated) + uarth = 1; + + spin_lock_irqsave(&port->lock, flags); + + UART_ALL_IRQ_DISABLE(uart); + + UART_SET_BAUDL(uart, uartl); + UART_SET_BAUDH(uart, uarth); + + UART_RX_IRQ_ENABLE(uart); + + /* + * UART doesn't support Parity/Hardware Flow Control; + * Only supports 8N1 character size + */ + new->c_cflag &= ~(CMSPAR|CRTSCTS|CSIZE); + new->c_cflag |= CS8; + + if (old) + tty_termios_copy_hw(new, old); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); + + uart_update_timeout(port, new->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *arc_serial_type(struct uart_port *port) +{ + struct arc_uart_port *uart = to_arc_port(port); + + return uart->port.type == PORT_ARC ? DRIVER_NAME : NULL; +} + +static void arc_serial_release_port(struct uart_port *port) +{ +} + +static int arc_serial_request_port(struct uart_port *port) +{ + return 0; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + */ +static int +arc_serial_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (port->type != PORT_UNKNOWN && ser->type != PORT_ARC) + return -EINVAL; + + return 0; +} + +/* + * Configure/autoconfigure the port. + */ +static void arc_serial_config_port(struct uart_port *port, int flags) +{ + struct arc_uart_port *uart = to_arc_port(port); + + if (flags & UART_CONFIG_TYPE) + uart->port.type = PORT_ARC; +} + +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE) + +static void arc_serial_poll_putchar(struct uart_port *port, unsigned char chr) +{ + struct arc_uart_port *uart = to_arc_port(port); + + while (!(UART_GET_STATUS(uart) & TXEMPTY)) + cpu_relax(); + + UART_SET_DATA(uart, chr); +} +#endif + +#ifdef CONFIG_CONSOLE_POLL +static int arc_serial_poll_getchar(struct uart_port *port) +{ + struct arc_uart_port *uart = to_arc_port(port); + unsigned char chr; + + while (!(UART_GET_STATUS(uart) & RXEMPTY)) + cpu_relax(); + + chr = UART_GET_DATA(uart); + return chr; +} +#endif + +static struct uart_ops arc_serial_pops = { + .tx_empty = arc_serial_tx_empty, + .set_mctrl = arc_serial_set_mctrl, + .get_mctrl = arc_serial_get_mctrl, + .stop_tx = arc_serial_stop_tx, + .start_tx = arc_serial_start_tx, + .stop_rx = arc_serial_stop_rx, + .enable_ms = arc_serial_enable_ms, + .break_ctl = arc_serial_break_ctl, + .startup = arc_serial_startup, + .shutdown = arc_serial_shutdown, + .set_termios = arc_serial_set_termios, + .type = arc_serial_type, + .release_port = arc_serial_release_port, + .request_port = arc_serial_request_port, + .config_port = arc_serial_config_port, + .verify_port = arc_serial_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_put_char = arc_serial_poll_putchar, + .poll_get_char = arc_serial_poll_getchar, +#endif +}; + +static int +arc_uart_init_one(struct platform_device *pdev, int dev_id) +{ + struct resource *res, *res2; + unsigned long *plat_data; + struct arc_uart_port *uart = &arc_uart_ports[dev_id]; + + plat_data = ((unsigned long *)(pdev->dev.platform_data)); + if (!plat_data) + return -ENODEV; + + uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */ + + if (is_early_platform_device(pdev)) { + uart->port.uartclk = plat_data[1]; + uart->baud = plat_data[2]; + } else { + struct device_node *np = pdev->dev.of_node; + u32 val; + + if (of_property_read_u32(np, "clock-frequency", &val)) { + dev_err(&pdev->dev, "clock-frequency property NOTset\n"); + return -EINVAL; + } + uart->port.uartclk = val; + + if (of_property_read_u32(np, "current-speed", &val)) { + dev_err(&pdev->dev, "current-speed property NOT set\n"); + return -EINVAL; + } + uart->baud = val; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res2) + return -ENODEV; + + uart->port.mapbase = res->start; + uart->port.membase = ioremap_nocache(res->start, resource_size(res)); + if (!uart->port.membase) + /* No point of dev_err since UART itself is hosed here */ + return -ENXIO; + + uart->port.irq = res2->start; + uart->port.dev = &pdev->dev; + uart->port.iotype = UPIO_MEM; + uart->port.flags = UPF_BOOT_AUTOCONF; + uart->port.line = dev_id; + uart->port.ops = &arc_serial_pops; + + uart->port.fifosize = ARC_UART_TX_FIFO_SIZE; + + /* + * uart_insert_char( ) uses it in decideding whether to ignore a + * char or not. Explicitly setting it here, removes the subtelty + */ + uart->port.ignore_status_mask = 0; + + return 0; +} + +#ifdef CONFIG_SERIAL_ARC_CONSOLE + +static int arc_serial_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= CONFIG_SERIAL_ARC_NR_PORTS) + return -ENODEV; + + /* + * The uart port backing the console (e.g. ttyARC1) might not have been + * init yet. If so, defer the console setup to after the port. + */ + port = &arc_uart_ports[co->index].port; + if (!port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + /* + * Serial core will call port->ops->set_termios( ) + * which will set the baud reg + */ + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static void arc_serial_console_putchar(struct uart_port *port, int ch) +{ + arc_serial_poll_putchar(port, (unsigned char)ch); +} + +/* + * Interrupts are disabled on entering + */ +static void arc_serial_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port = &arc_uart_ports[co->index].port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + uart_console_write(port, s, count, arc_serial_console_putchar); + spin_unlock_irqrestore(&port->lock, flags); +} + +static struct console arc_console = { + .name = ARC_SERIAL_DEV_NAME, + .write = arc_serial_console_write, + .device = uart_console_device, + .setup = arc_serial_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &arc_uart_driver +}; + +static __init void early_serial_write(struct console *con, const char *s, + unsigned int n) +{ + struct uart_port *port = &arc_uart_ports[con->index].port; + unsigned int i; + + for (i = 0; i < n; i++, s++) { + if (*s == '\n') + arc_serial_poll_putchar(port, '\r'); + arc_serial_poll_putchar(port, *s); + } +} + +static struct console arc_early_serial_console __initdata = { + .name = "early_ARCuart", + .write = early_serial_write, + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = -1 +}; + +static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev) +{ + int dev_id = pdev->id < 0 ? 0 : pdev->id; + int rc; + + arc_early_serial_console.index = dev_id; + + rc = arc_uart_init_one(pdev, dev_id); + if (rc) + panic("early console init failed\n"); + + arc_serial_console_setup(&arc_early_serial_console, NULL); + + register_console(&arc_early_serial_console); + return 0; +} +#endif /* CONFIG_SERIAL_ARC_CONSOLE */ + +static int arc_serial_probe(struct platform_device *pdev) +{ + int rc, dev_id; + struct device_node *np = pdev->dev.of_node; + + /* no device tree device */ + if (!np) + return -ENODEV; + + dev_id = of_alias_get_id(np, "serial"); + if (dev_id < 0) + dev_id = 0; + + rc = arc_uart_init_one(pdev, dev_id); + if (rc) + return rc; + + rc = uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port); + return rc; +} + +static int arc_serial_remove(struct platform_device *pdev) +{ + /* This will never be called */ + return 0; +} + +static const struct of_device_id arc_uart_dt_ids[] = { + { .compatible = "snps,arc-uart" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, arc_uart_dt_ids); + +static struct platform_driver arc_platform_driver = { + .probe = arc_serial_probe, + .remove = arc_serial_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = arc_uart_dt_ids, + }, +}; + +#ifdef CONFIG_SERIAL_ARC_CONSOLE + +static struct platform_driver early_arc_platform_driver __initdata = { + .probe = arc_serial_probe_earlyprintk, + .remove = arc_serial_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; +/* + * Register an early platform driver of "earlyprintk" class. + * ARCH platform code installs the driver and probes the early devices + * The installation could rely on user specifying earlyprintk=xyx in cmd line + * or it could be done independently, for all "earlyprintk" class drivers. + * [see arch/arc/plat-arcfpga/platform.c] + */ +early_platform_init("earlyprintk", &early_arc_platform_driver); + +#endif /* CONFIG_SERIAL_ARC_CONSOLE */ + +static int __init arc_serial_init(void) +{ + int ret; + + ret = uart_register_driver(&arc_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&arc_platform_driver); + if (ret) + uart_unregister_driver(&arc_uart_driver); + + return ret; +} + +static void __exit arc_serial_exit(void) +{ + platform_driver_unregister(&arc_platform_driver); + uart_unregister_driver(&arc_uart_driver); +} + +module_init(arc_serial_init); +module_exit(arc_serial_exit); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("plat-arcfpga/uart"); +MODULE_AUTHOR("Vineet Gupta"); +MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver"); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 3d7e1ee2fa57..d4a7c241b751 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -39,13 +39,12 @@ #include <linux/atmel_pdc.h> #include <linux/atmel_serial.h> #include <linux/uaccess.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_data/atmel.h> #include <asm/io.h> #include <asm/ioctls.h> -#include <asm/mach/serial_at91.h> -#include <mach/board.h> - #ifdef CONFIG_ARM #include <mach/cpu.h> #include <asm/gpio.h> @@ -775,14 +774,14 @@ static void atmel_rx_from_ring(struct uart_port *port) * uart_start(), which takes the lock. */ spin_unlock(&port->lock); - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(&port->state->port); spin_lock(&port->lock); } static void atmel_rx_from_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; struct atmel_dma_buffer *pdc; int rx_idx = atmel_port->pdc_rx_idx; unsigned int head; @@ -821,7 +820,8 @@ static void atmel_rx_from_dma(struct uart_port *port) */ count = head - tail; - tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count); + tty_insert_flip_string(tport, pdc->buf + pdc->ofs, + count); dma_sync_single_for_device(port->dev, pdc->dma_addr, pdc->dma_size, DMA_FROM_DEVICE); @@ -849,7 +849,7 @@ static void atmel_rx_from_dma(struct uart_port *port) * uart_start(), which takes the lock. */ spin_unlock(&port->lock); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); spin_lock(&port->lock); UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); @@ -1423,7 +1423,7 @@ static struct uart_ops atmel_pops = { #endif }; -static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port, +static void atmel_of_init_port(struct atmel_uart_port *atmel_port, struct device_node *np) { u32 rs485_delay[2]; @@ -1458,7 +1458,7 @@ static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port, /* * Configure the port from the platform device resource info. */ -static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, +static void atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev) { struct uart_port *port = &atmel_port->uart; @@ -1513,23 +1513,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, } } -/* - * Register board-specific modem-control line handlers. - */ -void __init atmel_register_uart_fns(struct atmel_port_fns *fns) -{ - if (fns->enable_ms) - atmel_pops.enable_ms = fns->enable_ms; - if (fns->get_mctrl) - atmel_pops.get_mctrl = fns->get_mctrl; - if (fns->set_mctrl) - atmel_pops.set_mctrl = fns->set_mctrl; - atmel_open_hook = fns->open; - atmel_close_hook = fns->close; - atmel_pops.pm = fns->pm; - atmel_pops.set_wake = fns->set_wake; -} - struct platform_device *atmel_default_console_device; /* the serial console device */ #ifdef CONFIG_SERIAL_ATMEL_CONSOLE @@ -1766,13 +1749,14 @@ static int atmel_serial_resume(struct platform_device *pdev) #define atmel_serial_resume NULL #endif -static int __devinit atmel_serial_probe(struct platform_device *pdev) +static int atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *port; struct device_node *np = pdev->dev.of_node; struct atmel_uart_data *pdata = pdev->dev.platform_data; void *data; int ret = -ENODEV; + struct pinctrl *pinctrl; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); @@ -1805,6 +1789,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) atmel_init_port(port, pdev); + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto err; + } + if (!atmel_use_dma_rx(&port->uart)) { ret = -ENOMEM; data = kmalloc(sizeof(struct atmel_uart_char) @@ -1851,7 +1841,7 @@ err: return ret; } -static int __devexit atmel_serial_remove(struct platform_device *pdev) +static int atmel_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -1876,7 +1866,7 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev) static struct platform_driver atmel_serial_driver = { .probe = atmel_serial_probe, - .remove = __devexit_p(atmel_serial_remove), + .remove = atmel_serial_remove, .suspend = atmel_serial_suspend, .resume = atmel_serial_resume, .driver = { diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index c0b68b9cad91..52a3ecd40421 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -235,14 +235,13 @@ static const char *bcm_uart_type(struct uart_port *port) */ static void bcm_uart_do_rx(struct uart_port *port) { - struct tty_struct *tty; + struct tty_port *tty_port = &port->state->port; unsigned int max_count; /* limit number of char read in interrupt, should not be * higher than fifo size anyway since we're much faster than * serial port */ max_count = 32; - tty = port->state->port.tty; do { unsigned int iestat, c, cstat; char flag; @@ -261,7 +260,7 @@ static void bcm_uart_do_rx(struct uart_port *port) bcm_uart_writel(port, val, UART_CTL_REG); port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tty_port, 0, TTY_OVERRUN); } if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) @@ -300,11 +299,11 @@ static void bcm_uart_do_rx(struct uart_port *port) if ((cstat & port->ignore_status_mask) == 0) - tty_insert_flip_char(tty, c, flag); + tty_insert_flip_char(tty_port, c, flag); } while (--max_count); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tty_port); } /* @@ -801,7 +800,7 @@ static struct uart_driver bcm_uart_driver = { /* * platform driver probe/remove callback */ -static int __devinit bcm_uart_probe(struct platform_device *pdev) +static int bcm_uart_probe(struct platform_device *pdev) { struct resource *res_mem, *res_irq; struct uart_port *port; @@ -848,7 +847,7 @@ static int __devinit bcm_uart_probe(struct platform_device *pdev) return 0; } -static int __devexit bcm_uart_remove(struct platform_device *pdev) +static int bcm_uart_remove(struct platform_device *pdev) { struct uart_port *port; @@ -865,7 +864,7 @@ static int __devexit bcm_uart_remove(struct platform_device *pdev) */ static struct platform_driver bcm_uart_platform_driver = { .probe = bcm_uart_probe, - .remove = __devexit_p(bcm_uart_remove), + .remove = bcm_uart_remove, .driver = { .owner = THIS_MODULE, .name = "bcm63xx_uart", diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index 7fbc3a08f10d..487c173b0f72 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -149,7 +149,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate) static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id) { struct sport_uart_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; + struct tty_port *port = &up->port.state->port; unsigned int ch; spin_lock(&up->port.lock); @@ -159,9 +159,10 @@ static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id) up->port.icount.rx++; if (!uart_handle_sysrq_char(&up->port, ch)) - tty_insert_flip_char(tty, ch, TTY_NORMAL); + tty_insert_flip_char(port, ch, TTY_NORMAL); } - tty_flip_buffer_push(tty); + /* XXX this won't deadlock with lowlat? */ + tty_flip_buffer_push(port); spin_unlock(&up->port.lock); @@ -182,7 +183,6 @@ static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id) static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) { struct sport_uart_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; unsigned int stat = SPORT_GET_STAT(up); spin_lock(&up->port.lock); @@ -190,7 +190,7 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) /* Overflow in RX FIFO */ if (stat & ROVF) { up->port.icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&up->port.state->port, 0, TTY_OVERRUN); SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */ } /* These should not happen */ @@ -205,6 +205,8 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) SSYNC(); spin_unlock(&up->port.lock); + /* XXX we don't push the overrun bit to TTY? */ + return IRQ_HANDLED; } @@ -740,7 +742,7 @@ static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = { }; #endif -static int __devinit sport_uart_probe(struct platform_device *pdev) +static int sport_uart_probe(struct platform_device *pdev) { struct resource *res; struct sport_uart_port *sport; @@ -850,7 +852,7 @@ out_error_free_mem: return ret; } -static int __devexit sport_uart_remove(struct platform_device *pdev) +static int sport_uart_remove(struct platform_device *pdev) { struct sport_uart_port *sport = platform_get_drvdata(pdev); @@ -871,7 +873,7 @@ static int __devexit sport_uart_remove(struct platform_device *pdev) static struct platform_driver sport_uart_driver = { .probe = sport_uart_probe, - .remove = __devexit_p(sport_uart_remove), + .remove = sport_uart_remove, .driver = { .name = DRV_NAME, #ifdef CONFIG_PM diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 9242d56ba267..12dceda9db33 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -223,7 +223,6 @@ static void bfin_serial_enable_ms(struct uart_port *port) #ifdef CONFIG_SERIAL_BFIN_PIO static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { - struct tty_struct *tty = NULL; unsigned int status, ch, flg; static struct timeval anomaly_start = { .tv_sec = 0 }; @@ -242,11 +241,9 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) return; } - if (!uart->port.state || !uart->port.state->port.tty) + if (!uart->port.state) return; #endif - tty = uart->port.state->port.tty; - if (ANOMALY_05000363) { /* The BF533 (and BF561) family of processors have a nice anomaly * where they continuously generate characters for a "single" break. @@ -325,7 +322,7 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) uart_insert_char(&uart->port, status, OE, ch, flg); ignore_char: - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&uart->port.state->port); } static void bfin_serial_tx_chars(struct bfin_serial_port *uart) @@ -426,7 +423,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) { - struct tty_struct *tty = uart->port.state->port.tty; int i, flg, status; status = UART_GET_LSR(uart); @@ -471,15 +467,15 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) } dma_ignore_char: - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&uart->port.state->port); } void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { int x_pos, pos; + unsigned long flags; - dma_disable_irq_nosync(uart->rx_dma_channel); - spin_lock_bh(&uart->rx_lock); + spin_lock_irqsave(&uart->rx_lock, flags); /* 2D DMA RX buffer ring is used. Because curr_y_count and * curr_x_count can't be read as an atomic operation, @@ -510,8 +506,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } - spin_unlock_bh(&uart->rx_lock); - dma_enable_irq(uart->rx_dma_channel); + spin_unlock_irqrestore(&uart->rx_lock, flags); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); } @@ -800,6 +795,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, unsigned long flags; unsigned int baud, quot; unsigned int ier, lcr = 0; + unsigned long timeout; switch (termios->c_cflag & CSIZE) { case CS8: @@ -815,7 +811,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, lcr = WLS(5); break; default: - printk(KERN_ERR "%s: word lengh not supported\n", + printk(KERN_ERR "%s: word length not supported\n", __func__); } @@ -869,6 +865,14 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15); + /* Wait till the transfer buffer is empty */ + timeout = jiffies + msecs_to_jiffies(10); + while (UART_GET_GCTL(uart) & UCEN && !(UART_GET_LSR(uart) & TEMT)) + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, "timeout waiting for TX buffer empty\n"); + break; + } + /* Disable UART */ ier = UART_GET_IER(uart); UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN); @@ -1390,7 +1394,7 @@ out_error_free_mem: return ret; } -static int __devexit bfin_serial_remove(struct platform_device *pdev) +static int bfin_serial_remove(struct platform_device *pdev) { struct bfin_serial_port *uart = platform_get_drvdata(pdev); @@ -1410,7 +1414,7 @@ static int __devexit bfin_serial_remove(struct platform_device *pdev) static struct platform_driver bfin_serial_driver = { .probe = bfin_serial_probe, - .remove = __devexit_p(bfin_serial_remove), + .remove = bfin_serial_remove, .suspend = bfin_serial_suspend, .resume = bfin_serial_resume, .driver = { diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index d0f719fafc84..bfb17968c8db 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -10,15 +10,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -26,172 +17,163 @@ #endif #include <linux/module.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/spinlock.h> #include <linux/device.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> +#include <linux/console.h> #include <linux/serial_core.h> #include <linux/serial.h> #include <linux/io.h> +#include <linux/clk.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> #include <mach/hardware.h> -#include <asm/irq.h> - -#define UART_NR 2 -#define SERIAL_CLPS711X_MAJOR 204 -#define SERIAL_CLPS711X_MINOR 40 -#define SERIAL_CLPS711X_NR UART_NR - -/* - * We use the relevant SYSCON register as a base address for these ports. - */ -#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1) -#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1) -#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1) -#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1) - -#define TX_IRQ(port) ((port)->irq) -#define RX_IRQ(port) ((port)->irq + 1) - -#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR) - -#define tx_enabled(port) ((port)->unused[0]) +#define UART_CLPS711X_NAME "uart-clps711x" +#define UART_CLPS711X_NR 2 +#define UART_CLPS711X_MAJOR 204 +#define UART_CLPS711X_MINOR 40 + +#define UBRLCR(port) ((port)->line ? UBRLCR2 : UBRLCR1) +#define UARTDR(port) ((port)->line ? UARTDR2 : UARTDR1) +#define SYSFLG(port) ((port)->line ? SYSFLG2 : SYSFLG1) +#define SYSCON(port) ((port)->line ? SYSCON2 : SYSCON1) +#define TX_IRQ(port) ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1) +#define RX_IRQ(port) ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1) + +struct clps711x_port { + struct uart_driver uart; + struct clk *uart_clk; + struct uart_port port[UART_CLPS711X_NR]; + int tx_enabled[UART_CLPS711X_NR]; +#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE + struct console console; +#endif +}; -static void clps711xuart_stop_tx(struct uart_port *port) +static void uart_clps711x_stop_tx(struct uart_port *port) { - if (tx_enabled(port)) { + struct clps711x_port *s = dev_get_drvdata(port->dev); + + if (s->tx_enabled[port->line]) { disable_irq(TX_IRQ(port)); - tx_enabled(port) = 0; + s->tx_enabled[port->line] = 0; } } -static void clps711xuart_start_tx(struct uart_port *port) +static void uart_clps711x_start_tx(struct uart_port *port) { - if (!tx_enabled(port)) { + struct clps711x_port *s = dev_get_drvdata(port->dev); + + if (!s->tx_enabled[port->line]) { enable_irq(TX_IRQ(port)); - tx_enabled(port) = 1; + s->tx_enabled[port->line] = 1; } } -static void clps711xuart_stop_rx(struct uart_port *port) +static void uart_clps711x_stop_rx(struct uart_port *port) { disable_irq(RX_IRQ(port)); } -static void clps711xuart_enable_ms(struct uart_port *port) +static void uart_clps711x_enable_ms(struct uart_port *port) { + /* Do nothing */ } -static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) +static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; unsigned int status, ch, flg; - status = clps_readl(SYSFLG(port)); - while (!(status & SYSFLG_URXFE)) { - ch = clps_readl(UARTDR(port)); + for (;;) { + status = clps_readl(SYSFLG(port)); + if (status & SYSFLG_URXFE) + break; + + ch = clps_readw(UARTDR(port)); + status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR); + ch &= 0xff; port->icount.rx++; - flg = TTY_NORMAL; - /* - * Note that the error handling code is - * out of the main execution path - */ - if (unlikely(ch & UART_ANY_ERR)) { - if (ch & UARTDR_PARERR) + if (unlikely(status)) { + if (status & UARTDR_PARERR) port->icount.parity++; - else if (ch & UARTDR_FRMERR) + else if (status & UARTDR_FRMERR) port->icount.frame++; - if (ch & UARTDR_OVERR) + else if (status & UARTDR_OVERR) port->icount.overrun++; - ch &= port->read_status_mask; + status &= port->read_status_mask; - if (ch & UARTDR_PARERR) + if (status & UARTDR_PARERR) flg = TTY_PARITY; - else if (ch & UARTDR_FRMERR) + else if (status & UARTDR_FRMERR) flg = TTY_FRAME; - -#ifdef SUPPORT_SYSRQ - port->sysrq = 0; -#endif + else if (status & UARTDR_OVERR) + flg = TTY_OVERRUN; } if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; + continue; - /* - * CHECK: does overrun affect the current character? - * ASSUMPTION: it does not. - */ - uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); + if (status & port->ignore_status_mask) + continue; - ignore_char: - status = clps_readl(SYSFLG(port)); + uart_insert_char(port, status, UARTDR_OVERR, ch, flg); } - tty_flip_buffer_push(tty); + + tty_flip_buffer_push(&port->state->port); + return IRQ_HANDLED; } -static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id) +static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) { struct uart_port *port = dev_id; + struct clps711x_port *s = dev_get_drvdata(port->dev); struct circ_buf *xmit = &port->state->xmit; - int count; if (port->x_char) { - clps_writel(port->x_char, UARTDR(port)); + clps_writew(port->x_char, UARTDR(port)); port->icount.tx++; port->x_char = 0; return IRQ_HANDLED; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - goto disable_tx_irq; + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + disable_irq_nosync(TX_IRQ(port)); + s->tx_enabled[port->line] = 0; + return IRQ_HANDLED; + } - count = port->fifosize >> 1; - do { - clps_writel(xmit->buf[xmit->tail], UARTDR(port)); + while (!uart_circ_empty(xmit)) { + clps_writew(xmit->buf[xmit->tail], UARTDR(port)); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; - if (uart_circ_empty(xmit)) + if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF)) break; - } while (--count > 0); + } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { - disable_tx_irq: - disable_irq_nosync(TX_IRQ(port)); - tx_enabled(port) = 0; - } - return IRQ_HANDLED; } -static unsigned int clps711xuart_tx_empty(struct uart_port *port) +static unsigned int uart_clps711x_tx_empty(struct uart_port *port) { - unsigned int status = clps_readl(SYSFLG(port)); - return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT; + return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT; } -static unsigned int clps711xuart_get_mctrl(struct uart_port *port) +static unsigned int uart_clps711x_get_mctrl(struct uart_port *port) { - unsigned int port_addr; - unsigned int result = 0; - unsigned int status; + unsigned int status, result = 0; - port_addr = SYSFLG(port); - if (port_addr == SYSFLG1) { + if (port->line == 0) { status = clps_readl(SYSFLG1); if (status & SYSFLG1_DCD) result |= TIOCM_CAR; @@ -199,104 +181,86 @@ static unsigned int clps711xuart_get_mctrl(struct uart_port *port) result |= TIOCM_DSR; if (status & SYSFLG1_CTS) result |= TIOCM_CTS; - } + } else + result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; return result; } -static void -clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl) +static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl) { + /* Do nothing */ } -static void clps711xuart_break_ctl(struct uart_port *port, int break_state) +static void uart_clps711x_break_ctl(struct uart_port *port, int break_state) { unsigned long flags; unsigned int ubrlcr; spin_lock_irqsave(&port->lock, flags); + ubrlcr = clps_readl(UBRLCR(port)); - if (break_state == -1) + if (break_state) ubrlcr |= UBRLCR_BREAK; else ubrlcr &= ~UBRLCR_BREAK; clps_writel(ubrlcr, UBRLCR(port)); + spin_unlock_irqrestore(&port->lock, flags); } -static int clps711xuart_startup(struct uart_port *port) +static int uart_clps711x_startup(struct uart_port *port) { - unsigned int syscon; - int retval; - - tx_enabled(port) = 1; - - /* - * Allocate the IRQs - */ - retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0, - "clps711xuart_tx", port); - if (retval) - return retval; - - retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0, - "clps711xuart_rx", port); - if (retval) { - free_irq(TX_IRQ(port), port); - return retval; + struct clps711x_port *s = dev_get_drvdata(port->dev); + int ret; + + s->tx_enabled[port->line] = 1; + /* Allocate the IRQs */ + ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx, + 0, UART_CLPS711X_NAME " TX", port); + if (ret) + return ret; + + ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx, + 0, UART_CLPS711X_NAME " RX", port); + if (ret) { + devm_free_irq(port->dev, TX_IRQ(port), port); + return ret; } - /* - * enable the port - */ - syscon = clps_readl(SYSCON(port)); - syscon |= SYSCON_UARTEN; - clps_writel(syscon, SYSCON(port)); + /* Disable break */ + clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port)); + + /* Enable the port */ + clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port)); return 0; } -static void clps711xuart_shutdown(struct uart_port *port) +static void uart_clps711x_shutdown(struct uart_port *port) { - unsigned int ubrlcr, syscon; - - /* - * Free the interrupt - */ - free_irq(TX_IRQ(port), port); /* TX interrupt */ - free_irq(RX_IRQ(port), port); /* RX interrupt */ - - /* - * disable the port - */ - syscon = clps_readl(SYSCON(port)); - syscon &= ~SYSCON_UARTEN; - clps_writel(syscon, SYSCON(port)); + /* Free the interrupts */ + devm_free_irq(port->dev, TX_IRQ(port), port); + devm_free_irq(port->dev, RX_IRQ(port), port); - /* - * disable break condition and fifos - */ - ubrlcr = clps_readl(UBRLCR(port)); - ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK); - clps_writel(ubrlcr, UBRLCR(port)); + /* Disable the port */ + clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port)); } -static void -clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +static void uart_clps711x_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) { unsigned int ubrlcr, baud, quot; unsigned long flags; - /* - * We don't implement CREAD. - */ - termios->c_cflag |= CREAD; + /* Mask termios capabilities we don't support */ + termios->c_cflag &= ~CMSPAR; + termios->c_iflag &= ~(BRKINT | IGNBRK); - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + /* Ask the core to calculate the divisor for us */ + baud = uart_get_baud_rate(port, termios, old, port->uartclk / 4096, + port->uartclk / 16); quot = uart_get_divisor(port, baud); switch (termios->c_cflag & CSIZE) { @@ -309,160 +273,117 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios, case CS7: ubrlcr = UBRLCR_WRDLEN7; break; - default: // CS8 + case CS8: + default: ubrlcr = UBRLCR_WRDLEN8; break; } + if (termios->c_cflag & CSTOPB) ubrlcr |= UBRLCR_XSTOP; + if (termios->c_cflag & PARENB) { ubrlcr |= UBRLCR_PRTEN; if (!(termios->c_cflag & PARODD)) ubrlcr |= UBRLCR_EVENPRT; } - if (port->fifosize > 1) - ubrlcr |= UBRLCR_FIFOEN; - spin_lock_irqsave(&port->lock, flags); + /* Enable FIFO */ + ubrlcr |= UBRLCR_FIFOEN; - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); + spin_lock_irqsave(&port->lock, flags); + /* Set read status mask */ port->read_status_mask = UARTDR_OVERR; if (termios->c_iflag & INPCK) port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; - /* - * Characters to ignore - */ + /* Set status ignore mask */ port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; - if (termios->c_iflag & IGNBRK) { - /* - * If we're ignoring parity and break indicators, - * ignore overruns to (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UARTDR_OVERR; - } + if (!(termios->c_cflag & CREAD)) + port->ignore_status_mask |= UARTDR_OVERR | UARTDR_PARERR | + UARTDR_FRMERR; - quot -= 1; + uart_update_timeout(port, termios->c_cflag, baud); - clps_writel(ubrlcr | quot, UBRLCR(port)); + clps_writel(ubrlcr | (quot - 1), UBRLCR(port)); spin_unlock_irqrestore(&port->lock, flags); } -static const char *clps711xuart_type(struct uart_port *port) +static const char *uart_clps711x_type(struct uart_port *port) { - return port->type == PORT_CLPS711X ? "CLPS711x" : NULL; + return (port->type == PORT_CLPS711X) ? "CLPS711X" : NULL; } -/* - * Configure/autoconfigure the port. - */ -static void clps711xuart_config_port(struct uart_port *port, int flags) +static void uart_clps711x_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) port->type = PORT_CLPS711X; } -static void clps711xuart_release_port(struct uart_port *port) +static void uart_clps711x_release_port(struct uart_port *port) { + /* Do nothing */ } -static int clps711xuart_request_port(struct uart_port *port) +static int uart_clps711x_request_port(struct uart_port *port) { + /* Do nothing */ return 0; } -static struct uart_ops clps711x_pops = { - .tx_empty = clps711xuart_tx_empty, - .set_mctrl = clps711xuart_set_mctrl_null, - .get_mctrl = clps711xuart_get_mctrl, - .stop_tx = clps711xuart_stop_tx, - .start_tx = clps711xuart_start_tx, - .stop_rx = clps711xuart_stop_rx, - .enable_ms = clps711xuart_enable_ms, - .break_ctl = clps711xuart_break_ctl, - .startup = clps711xuart_startup, - .shutdown = clps711xuart_shutdown, - .set_termios = clps711xuart_set_termios, - .type = clps711xuart_type, - .config_port = clps711xuart_config_port, - .release_port = clps711xuart_release_port, - .request_port = clps711xuart_request_port, -}; - -static struct uart_port clps711x_ports[UART_NR] = { - { - .iobase = SYSCON1, - .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ - .uartclk = 3686400, - .fifosize = 16, - .ops = &clps711x_pops, - .line = 0, - .flags = UPF_BOOT_AUTOCONF, - }, - { - .iobase = SYSCON2, - .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ - .uartclk = 3686400, - .fifosize = 16, - .ops = &clps711x_pops, - .line = 1, - .flags = UPF_BOOT_AUTOCONF, - } +static const struct uart_ops uart_clps711x_ops = { + .tx_empty = uart_clps711x_tx_empty, + .set_mctrl = uart_clps711x_set_mctrl, + .get_mctrl = uart_clps711x_get_mctrl, + .stop_tx = uart_clps711x_stop_tx, + .start_tx = uart_clps711x_start_tx, + .stop_rx = uart_clps711x_stop_rx, + .enable_ms = uart_clps711x_enable_ms, + .break_ctl = uart_clps711x_break_ctl, + .startup = uart_clps711x_startup, + .shutdown = uart_clps711x_shutdown, + .set_termios = uart_clps711x_set_termios, + .type = uart_clps711x_type, + .config_port = uart_clps711x_config_port, + .release_port = uart_clps711x_release_port, + .request_port = uart_clps711x_request_port, }; #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE -static void clps711xuart_console_putchar(struct uart_port *port, int ch) +static void uart_clps711x_console_putchar(struct uart_port *port, int ch) { while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF) barrier(); - clps_writel(ch, UARTDR(port)); + + clps_writew(ch, UARTDR(port)); } -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - * - * Note that this is called with interrupts already disabled - */ -static void -clps711xuart_console_write(struct console *co, const char *s, - unsigned int count) +static void uart_clps711x_console_write(struct console *co, const char *c, + unsigned n) { - struct uart_port *port = clps711x_ports + co->index; - unsigned int status, syscon; + struct clps711x_port *s = (struct clps711x_port *)co->data; + struct uart_port *port = &s->port[co->index]; + u32 syscon; - /* - * Ensure that the port is enabled. - */ + /* Ensure that the port is enabled */ syscon = clps_readl(SYSCON(port)); clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); - uart_console_write(port, s, count, clps711xuart_console_putchar); + uart_console_write(port, c, n, uart_clps711x_console_putchar); - /* - * Finally, wait for transmitter to become empty - * and restore the uart state. - */ - do { - status = clps_readl(SYSFLG(port)); - } while (status & SYSFLG_UBUSY); + /* Wait for transmitter to become empty */ + while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY) + barrier(); + /* Restore the uart state */ clps_writel(syscon, SYSCON(port)); } -static void __init -clps711xuart_console_get_options(struct uart_port *port, int *baud, - int *parity, int *bits) +static void uart_clps711x_console_get_options(struct uart_port *port, + int *baud, int *parity, + int *bits) { if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { unsigned int ubrlcr, quot; @@ -487,92 +408,124 @@ clps711xuart_console_get_options(struct uart_port *port, int *baud, } } -static int __init clps711xuart_console_setup(struct console *co, char *options) +static int uart_clps711x_console_setup(struct console *co, char *options) { - struct uart_port *port; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - port = uart_get_console(clps711x_ports, UART_NR, co); + int baud = 38400, bits = 8, parity = 'n', flow = 'n'; + struct clps711x_port *s = (struct clps711x_port *)co->data; + struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0]; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else - clps711xuart_console_get_options(port, &baud, &parity, &bits); + uart_clps711x_console_get_options(port, &baud, &parity, &bits); return uart_set_options(port, co, baud, parity, bits, flow); } +#endif -static struct uart_driver clps711x_reg; -static struct console clps711x_console = { - .name = "ttyCL", - .write = clps711xuart_console_write, - .device = uart_console_device, - .setup = clps711xuart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &clps711x_reg, -}; - -static int __init clps711xuart_console_init(void) +static int uart_clps711x_probe(struct platform_device *pdev) { - register_console(&clps711x_console); - return 0; -} -console_initcall(clps711xuart_console_init); + struct clps711x_port *s; + int ret, i; + + s = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_port), GFP_KERNEL); + if (!s) { + dev_err(&pdev->dev, "Error allocating port structure\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, s); -#define CLPS711X_CONSOLE &clps711x_console -#else -#define CLPS711X_CONSOLE NULL + s->uart_clk = devm_clk_get(&pdev->dev, "uart"); + if (IS_ERR(s->uart_clk)) { + dev_err(&pdev->dev, "Can't get UART clocks\n"); + ret = PTR_ERR(s->uart_clk); + goto err_out; + } + + s->uart.owner = THIS_MODULE; + s->uart.dev_name = "ttyCL"; + s->uart.major = UART_CLPS711X_MAJOR; + s->uart.minor = UART_CLPS711X_MINOR; + s->uart.nr = UART_CLPS711X_NR; +#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE + s->uart.cons = &s->console; + s->uart.cons->device = uart_console_device; + s->uart.cons->write = uart_clps711x_console_write; + s->uart.cons->setup = uart_clps711x_console_setup; + s->uart.cons->flags = CON_PRINTBUFFER; + s->uart.cons->index = -1; + s->uart.cons->data = s; + strcpy(s->uart.cons->name, "ttyCL"); #endif + ret = uart_register_driver(&s->uart); + if (ret) { + dev_err(&pdev->dev, "Registering UART driver failed\n"); + devm_clk_put(&pdev->dev, s->uart_clk); + goto err_out; + } -static struct uart_driver clps711x_reg = { - .driver_name = "ttyCL", - .dev_name = "ttyCL", - .major = SERIAL_CLPS711X_MAJOR, - .minor = SERIAL_CLPS711X_MINOR, - .nr = UART_NR, + for (i = 0; i < UART_CLPS711X_NR; i++) { + s->port[i].line = i; + s->port[i].dev = &pdev->dev; + s->port[i].irq = TX_IRQ(&s->port[i]); + s->port[i].iobase = SYSCON(&s->port[i]); + s->port[i].type = PORT_CLPS711X; + s->port[i].fifosize = 16; + s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; + s->port[i].uartclk = clk_get_rate(s->uart_clk); + s->port[i].ops = &uart_clps711x_ops; + WARN_ON(uart_add_one_port(&s->uart, &s->port[i])); + } - .cons = CLPS711X_CONSOLE, -}; + return 0; -static int __init clps711xuart_init(void) -{ - int ret, i; +err_out: + platform_set_drvdata(pdev, NULL); + + return ret; +} - printk(KERN_INFO "Serial: CLPS711x driver\n"); +static int uart_clps711x_remove(struct platform_device *pdev) +{ + struct clps711x_port *s = platform_get_drvdata(pdev); + int i; - ret = uart_register_driver(&clps711x_reg); - if (ret) - return ret; + for (i = 0; i < UART_CLPS711X_NR; i++) + uart_remove_one_port(&s->uart, &s->port[i]); - for (i = 0; i < UART_NR; i++) - uart_add_one_port(&clps711x_reg, &clps711x_ports[i]); + devm_clk_put(&pdev->dev, s->uart_clk); + uart_unregister_driver(&s->uart); + platform_set_drvdata(pdev, NULL); return 0; } -static void __exit clps711xuart_exit(void) -{ - int i; +static struct platform_driver clps711x_uart_driver = { + .driver = { + .name = UART_CLPS711X_NAME, + .owner = THIS_MODULE, + }, + .probe = uart_clps711x_probe, + .remove = uart_clps711x_remove, +}; +module_platform_driver(clps711x_uart_driver); - for (i = 0; i < UART_NR; i++) - uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]); +static struct platform_device clps711x_uart_device = { + .name = UART_CLPS711X_NAME, +}; - uart_unregister_driver(&clps711x_reg); +static int __init uart_clps711x_init(void) +{ + return platform_device_register(&clps711x_uart_device); } +module_init(uart_clps711x_init); -module_init(clps711xuart_init); -module_exit(clps711xuart_exit); +static void __exit uart_clps711x_exit(void) +{ + platform_device_unregister(&clps711x_uart_device); +} +module_exit(uart_clps711x_exit); MODULE_AUTHOR("Deep Blue Solutions Ltd"); -MODULE_DESCRIPTION("CLPS-711x generic serial driver"); +MODULE_DESCRIPTION("CLPS711X serial driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR); diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index d0dd9194cecc..97f4e1858649 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -245,7 +245,7 @@ static void cpm_uart_int_rx(struct uart_port *port) int i; unsigned char ch; u8 *cp; - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; cbd_t __iomem *bdp; u16 status; @@ -276,7 +276,7 @@ static void cpm_uart_int_rx(struct uart_port *port) /* If we have not enough room in tty flip buffer, then we try * later, which will be the next rx-interrupt or a timeout */ - if(tty_buffer_request_room(tty, i) < i) { + if (tty_buffer_request_room(tport, i) < i) { printk(KERN_WARNING "No room in flip buffer\n"); return; } @@ -302,7 +302,7 @@ static void cpm_uart_int_rx(struct uart_port *port) } #endif error_return: - tty_insert_flip_char(tty, ch, flg); + tty_insert_flip_char(tport, ch, flg); } /* End while (i--) */ @@ -322,7 +322,7 @@ static void cpm_uart_int_rx(struct uart_port *port) pinfo->rx_cur = bdp; /* activate BH processing */ - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); return; @@ -507,7 +507,7 @@ static void cpm_uart_set_termios(struct uart_port *port, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); if (baud < HW_BUF_SPD_THRESHOLD || - (pinfo->port.state && pinfo->port.state->port.tty->low_latency)) + (pinfo->port.state && pinfo->port.state->port.low_latency)) pinfo->rx_fifosize = 1; else pinfo->rx_fifosize = RX_BUF_SIZE; @@ -1373,7 +1373,7 @@ static struct uart_driver cpm_reg = { static int probe_index; -static int __devinit cpm_uart_probe(struct platform_device *ofdev) +static int cpm_uart_probe(struct platform_device *ofdev) { int index = probe_index++; struct uart_cpm_port *pinfo = &cpm_uart_ports[index]; @@ -1396,7 +1396,7 @@ static int __devinit cpm_uart_probe(struct platform_device *ofdev) return uart_add_one_port(&cpm_reg, &pinfo->port); } -static int __devexit cpm_uart_remove(struct platform_device *ofdev) +static int cpm_uart_remove(struct platform_device *ofdev) { struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev); return uart_remove_one_port(&cpm_reg, &pinfo->port); diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 35ee6a2c6877..5f37c31e32bc 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -1760,8 +1760,7 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl info->icount.rx++; } else { - struct tty_struct *tty = info->port.tty; - tty_insert_flip_char(tty, data, flag); + tty_insert_flip_char(&info->port, data, flag); info->icount.rx++; } @@ -2105,22 +2104,15 @@ static int force_eop_if_needed(struct e100_serial *info) static void flush_to_flip_buffer(struct e100_serial *info) { - struct tty_struct *tty; struct etrax_recv_buffer *buffer; unsigned long flags; local_irq_save(flags); - tty = info->port.tty; - - if (!tty) { - local_irq_restore(flags); - return; - } while ((buffer = info->first_recv_buffer) != NULL) { unsigned int count = buffer->length; - tty_insert_flip_string(tty, buffer->buffer, count); + tty_insert_flip_string(&info->port, buffer->buffer, count); info->recv_cnt -= count; if (count == buffer->length) { @@ -2139,7 +2131,7 @@ static void flush_to_flip_buffer(struct e100_serial *info) local_irq_restore(flags); /* This includes a check for low-latency */ - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&info->port); } static void check_flush_timeout(struct e100_serial *info) @@ -2275,12 +2267,6 @@ static struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) { unsigned long data_read; - struct tty_struct *tty = info->port.tty; - - if (!tty) { - printk("!NO TTY!\n"); - return info; - } /* Read data and status at the same time */ data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); @@ -2338,8 +2324,7 @@ more_data: data_in, data_read); char flag = TTY_NORMAL; if (info->errorcode == ERRCODE_INSERT_BREAK) { - struct tty_struct *tty = info->port.tty; - tty_insert_flip_char(tty, 0, flag); + tty_insert_flip_char(&info->port, 0, flag); info->icount.rx++; } @@ -2353,7 +2338,7 @@ more_data: info->icount.frame++; flag = TTY_FRAME; } - tty_insert_flip_char(tty, data, flag); + tty_insert_flip_char(&info->port, data, flag); info->errorcode = 0; } info->break_detected_cnt = 0; @@ -2369,7 +2354,7 @@ more_data: log_int(rdpc(), 0, 0); } ); - tty_insert_flip_char(tty, + tty_insert_flip_char(&info->port, IO_EXTRACT(R_SERIAL0_READ, data_in, data_read), TTY_NORMAL); } else { @@ -2384,7 +2369,7 @@ more_data: goto more_data; } - tty_flip_buffer_push(info->port.tty); + tty_flip_buffer_push(&info->port); return info; } @@ -3137,7 +3122,7 @@ static int rs_raw_write(struct tty_struct *tty, /* first some sanity checks */ - if (!tty || !info->xmit.buf) + if (!info->xmit.buf) return 0; #ifdef SERIAL_DEBUG_DATA @@ -3464,7 +3449,7 @@ set_serial_info(struct e100_serial *info, info->type = new_serial.type; info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait; - info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->port.low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: if (info->flags & ASYNC_INITIALIZED) { @@ -4108,7 +4093,7 @@ rs_open(struct tty_struct *tty, struct file * filp) tty->driver_data = info; info->port.tty = tty; - tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY); + info->port.low_latency = !!(info->flags & ASYNC_LOW_LATENCY); /* * If the port is in the middle of closing, bail out now diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index 6491b8644a7f..2f2b2e538a54 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -187,7 +187,6 @@ static inline void dz_receive_chars(struct dz_mux *mux) { struct uart_port *uport; struct dz_port *dport = &mux->dport[0]; - struct tty_struct *tty = NULL; struct uart_icount *icount; int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 }; unsigned char ch, flag; @@ -197,7 +196,6 @@ static inline void dz_receive_chars(struct dz_mux *mux) while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) { dport = &mux->dport[LINE(status)]; uport = &dport->port; - tty = uport->state->port.tty; /* point to the proper dev */ ch = UCHAR(status); /* grab the char */ flag = TTY_NORMAL; @@ -249,7 +247,7 @@ static inline void dz_receive_chars(struct dz_mux *mux) } for (i = 0; i < DZ_NB_PORT; i++) if (lines_rx[i]) - tty_flip_buffer_push(mux->dport[i].port.state->port.tty); + tty_flip_buffer_push(&mux->dport[i].port.state->port); } /* diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 615e46470491..7d199c8e1a75 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -81,6 +81,7 @@ struct efm32_uart_port { struct uart_port port; unsigned int txirq; struct clk *clk; + struct efm32_uart_pdata pdata; }; #define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port) #define efm_debug(efm_port, format, arg...) \ @@ -194,8 +195,7 @@ static void efm32_uart_break_ctl(struct uart_port *port, int ctl) /* not possible without fiddling with gpios */ } -static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port, - struct tty_struct *tty) +static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port) { struct uart_port *port = &efm_port->port; @@ -237,8 +237,8 @@ static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port, rxdata & UARTn_RXDATAX_RXDATA__MASK)) continue; - if (tty && (rxdata & port->ignore_status_mask) == 0) - tty_insert_flip_char(tty, + if ((rxdata & port->ignore_status_mask) == 0) + tty_insert_flip_char(&port->state->port, rxdata & UARTn_RXDATAX_RXDATA__MASK, flag); } } @@ -249,15 +249,13 @@ static irqreturn_t efm32_uart_rxirq(int irq, void *data) u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); int handled = IRQ_NONE; struct uart_port *port = &efm_port->port; - struct tty_struct *tty; + struct tty_port *tport = &port->state->port; spin_lock(&port->lock); - tty = tty_kref_get(port->state->port.tty); - if (irqflag & UARTn_IF_RXDATAV) { efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC); - efm32_uart_rx_chars(efm_port, tty); + efm32_uart_rx_chars(efm_port); handled = IRQ_HANDLED; } @@ -265,16 +263,12 @@ static irqreturn_t efm32_uart_rxirq(int irq, void *data) if (irqflag & UARTn_IF_RXOF) { efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC); port->icount.overrun++; - if (tty) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); handled = IRQ_HANDLED; } - if (tty) { - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } + tty_flip_buffer_push(tport); spin_unlock(&port->lock); @@ -300,13 +294,8 @@ static irqreturn_t efm32_uart_txirq(int irq, void *data) static int efm32_uart_startup(struct uart_port *port) { struct efm32_uart_port *efm_port = to_efm_port(port); - u32 location = 0; - struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev); int ret; - if (pdata) - location = UARTn_ROUTE_LOCATION(pdata->location); - ret = clk_enable(efm_port->clk); if (ret) { efm_debug(efm_port, "failed to enable clk\n"); @@ -315,7 +304,9 @@ static int efm32_uart_startup(struct uart_port *port) port->uartclk = clk_get_rate(efm_port->clk); /* Enable pins at configured location */ - efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN, + efm32_uart_write32(efm_port, + UARTn_ROUTE_LOCATION(efm_port->pdata.location) | + UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN, UARTn_ROUTE); ret = request_irq(port->irq, efm32_uart_rxirq, 0, @@ -674,11 +665,24 @@ static int efm32_uart_probe_dt(struct platform_device *pdev, struct efm32_uart_port *efm_port) { struct device_node *np = pdev->dev.of_node; + u32 location; int ret; if (!np) return 1; + ret = of_property_read_u32(np, "location", &location); + if (!ret) { + if (location > 5) { + dev_err(&pdev->dev, "invalid location\n"); + return -EINVAL; + } + efm_debug(efm_port, "using location %u\n", location); + efm_port->pdata.location = location; + } else { + efm_debug(efm_port, "fall back to location 0\n"); + } + ret = of_alias_get_id(np, "serial"); if (ret < 0) { dev_err(&pdev->dev, "failed to get alias id: %d\n", ret); @@ -690,7 +694,7 @@ static int efm32_uart_probe_dt(struct platform_device *pdev, } -static int __devinit efm32_uart_probe(struct platform_device *pdev) +static int efm32_uart_probe(struct platform_device *pdev) { struct efm32_uart_port *efm_port; struct resource *res; @@ -738,10 +742,16 @@ static int __devinit efm32_uart_probe(struct platform_device *pdev) efm_port->port.flags = UPF_BOOT_AUTOCONF; ret = efm32_uart_probe_dt(pdev, efm_port); - if (ret > 0) + if (ret > 0) { /* not created by device tree */ + const struct efm32_uart_pdata *pdata = dev_get_platdata(&pdev->dev); + efm_port->port.line = pdev->id; + if (pdata) + efm_port->pdata = *pdata; + } + if (efm_port->port.line >= 0 && efm_port->port.line < ARRAY_SIZE(efm32_uart_ports)) efm32_uart_ports[efm_port->port.line] = efm_port; @@ -764,7 +774,7 @@ err_get_base: return ret; } -static int __devexit efm32_uart_remove(struct platform_device *pdev) +static int efm32_uart_remove(struct platform_device *pdev) { struct efm32_uart_port *efm_port = platform_get_drvdata(pdev); @@ -791,7 +801,7 @@ MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids); static struct platform_driver efm32_uart_driver = { .probe = efm32_uart_probe, - .remove = __devexit_p(efm32_uart_remove), + .remove = efm32_uart_remove, .driver = { .name = DRIVER_NAME, diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index defc4e3393a3..bc9e6b017b05 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -175,7 +175,7 @@ static void free_port_memory(struct icom_port *icom_port) } } -static int __devinit get_port_memory(struct icom_port *icom_port) +static int get_port_memory(struct icom_port *icom_port) { int index; unsigned long stgAddr; @@ -505,7 +505,7 @@ static void load_code(struct icom_port *icom_port) /* Stop processor */ stop_processor(icom_port); - dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n"); + dev_err(&icom_port->adapter->pci_dev->dev,"Port not operational\n"); } if (new_page != NULL) @@ -734,7 +734,7 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) { short int count, rcv_buff; - struct tty_struct *tty = icom_port->uart_port.state->port.tty; + struct tty_port *port = &icom_port->uart_port.state->port; unsigned short int status; struct uart_icount *icount; unsigned long offset; @@ -761,7 +761,7 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) /* Block copy all but the last byte as this may have status */ if (count > 0) { first = icom_port->recv_buf[offset]; - tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1); + tty_insert_flip_string(port, icom_port->recv_buf + offset, count - 1); } icount = &icom_port->uart_port.icount; @@ -812,7 +812,7 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) } - tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag); + tty_insert_flip_char(port, *(icom_port->recv_buf + offset + count - 1), flag); if (status & SA_FLAGS_OVERRUN) /* @@ -820,7 +820,7 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) * reported immediately, and doesn't * affect the current character */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(port, 0, TTY_OVERRUN); ignore_char: icom_port->statStg->rcv[rcv_buff].flags = 0; icom_port->statStg->rcv[rcv_buff].leLength = 0; @@ -834,7 +834,7 @@ ignore_char: status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); } icom_port->next_rcv = rcv_buff; - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port); } static void process_interrupt(u16 port_int_reg, @@ -1314,7 +1314,7 @@ static struct uart_driver icom_uart_driver = { .cons = ICOM_CONSOLE, }; -static int __devinit icom_init_ports(struct icom_adapter *icom_adapter) +static int icom_init_ports(struct icom_adapter *icom_adapter) { u32 subsystem_id = icom_adapter->subsystem_id; int i; @@ -1381,7 +1381,7 @@ static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *i 0x8024 + 2 - 2 * (icom_port->port - 2); } } -static int __devinit icom_load_ports(struct icom_adapter *icom_adapter) +static int icom_load_ports(struct icom_adapter *icom_adapter) { struct icom_port *icom_port; int port_num; @@ -1407,7 +1407,7 @@ static int __devinit icom_load_ports(struct icom_adapter *icom_adapter) return 0; } -static int __devinit icom_alloc_adapter(struct icom_adapter +static int icom_alloc_adapter(struct icom_adapter **icom_adapter_ref) { int adapter_count = 0; @@ -1487,7 +1487,7 @@ static void icom_kref_release(struct kref *kref) icom_remove_adapter(icom_adapter); } -static int __devinit icom_probe(struct pci_dev *dev, +static int icom_probe(struct pci_dev *dev, const struct pci_device_id *ent) { int index; @@ -1596,7 +1596,7 @@ probe_exit0: return retval; } -static void __devexit icom_remove(struct pci_dev *dev) +static void icom_remove(struct pci_dev *dev) { struct icom_adapter *icom_adapter; struct list_head *tmp; @@ -1617,7 +1617,7 @@ static struct pci_driver icom_pci_driver = { .name = ICOM_DRIVER_NAME, .id_table = icom_pci_table, .probe = icom_probe, - .remove = __devexit_p(icom_remove), + .remove = icom_remove, }; static int __init icom_init(void) diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 5b9bc19ed134..68d7ce997ede 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -60,20 +60,27 @@ #include <linux/pm_runtime.h> #include <linux/spi/ifx_modem.h> #include <linux/delay.h> +#include <linux/reboot.h> #include "ifx6x60.h" #define IFX_SPI_MORE_MASK 0x10 -#define IFX_SPI_MORE_BIT 12 /* bit position in u16 */ -#define IFX_SPI_CTS_BIT 13 /* bit position in u16 */ +#define IFX_SPI_MORE_BIT 4 /* bit position in u8 */ +#define IFX_SPI_CTS_BIT 6 /* bit position in u8 */ #define IFX_SPI_MODE SPI_MODE_1 #define IFX_SPI_TTY_ID 0 #define IFX_SPI_TIMEOUT_SEC 2 #define IFX_SPI_HEADER_0 (-1) #define IFX_SPI_HEADER_F (-2) +#define PO_POST_DELAY 200 +#define IFX_MDM_RST_PMU 4 + /* forward reference */ static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev); +static int ifx_modem_reboot_callback(struct notifier_block *nfb, + unsigned long event, void *data); +static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev); /* local variables */ static int spi_bpw = 16; /* 8, 16 or 32 bit word length */ @@ -81,6 +88,29 @@ static struct tty_driver *tty_drv; static struct ifx_spi_device *saved_ifx_dev; static struct lock_class_key ifx_spi_key; +static struct notifier_block ifx_modem_reboot_notifier_block = { + .notifier_call = ifx_modem_reboot_callback, +}; + +static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev) +{ + gpio_set_value(IFX_MDM_RST_PMU, 1); + msleep(PO_POST_DELAY); + + return 0; +} + +static int ifx_modem_reboot_callback(struct notifier_block *nfb, + unsigned long event, void *data) +{ + if (saved_ifx_dev) + ifx_modem_power_off(saved_ifx_dev); + else + pr_warn("no ifx modem active;\n"); + + return NOTIFY_OK; +} + /* GPIO/GPE settings */ /** @@ -152,26 +182,67 @@ ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val) } /** - * swap_buf + * swap_buf_8 * @buf: our buffer * @len : number of bytes (not words) in the buffer * @end: end of buffer * * Swap the contents of a buffer into big endian format */ -static inline void swap_buf(u16 *buf, int len, void *end) +static inline void swap_buf_8(unsigned char *buf, int len, void *end) +{ + /* don't swap buffer if SPI word width is 8 bits */ + return; +} + +/** + * swap_buf_16 + * @buf: our buffer + * @len : number of bytes (not words) in the buffer + * @end: end of buffer + * + * Swap the contents of a buffer into big endian format + */ +static inline void swap_buf_16(unsigned char *buf, int len, void *end) { int n; + u16 *buf_16 = (u16 *)buf; len = ((len + 1) >> 1); - if ((void *)&buf[len] > end) { - pr_err("swap_buf: swap exceeds boundary (%p > %p)!", - &buf[len], end); + if ((void *)&buf_16[len] > end) { + pr_err("swap_buf_16: swap exceeds boundary (%p > %p)!", + &buf_16[len], end); return; } for (n = 0; n < len; n++) { - *buf = cpu_to_be16(*buf); - buf++; + *buf_16 = cpu_to_be16(*buf_16); + buf_16++; + } +} + +/** + * swap_buf_32 + * @buf: our buffer + * @len : number of bytes (not words) in the buffer + * @end: end of buffer + * + * Swap the contents of a buffer into big endian format + */ +static inline void swap_buf_32(unsigned char *buf, int len, void *end) +{ + int n; + + u32 *buf_32 = (u32 *)buf; + len = (len + 3) >> 2; + + if ((void *)&buf_32[len] > end) { + pr_err("swap_buf_32: swap exceeds boundary (%p > %p)!\n", + &buf_32[len], end); + return; + } + for (n = 0; n < len; n++) { + *buf_32 = cpu_to_be32(*buf_32); + buf_32++; } } @@ -190,9 +261,7 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev) if (!val) { if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) { - ifx_dev->spi_timer.expires = - jiffies + IFX_SPI_TIMEOUT_SEC*HZ; - add_timer(&ifx_dev->spi_timer); + mod_timer(&ifx_dev->spi_timer,jiffies + IFX_SPI_TIMEOUT_SEC*HZ); } } @@ -412,7 +481,6 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev) unsigned char *tx_buffer; tx_buffer = ifx_dev->tx_buffer; - memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE); /* make room for required SPI header */ tx_buffer += IFX_SPI_HEADER_OVERHEAD; @@ -449,7 +517,7 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev) tx_count-IFX_SPI_HEADER_OVERHEAD, ifx_dev->spi_more); /* swap actual data in the buffer */ - swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count, + ifx_dev->swap_buf((ifx_dev->tx_buffer), tx_count, &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]); return tx_count; } @@ -469,9 +537,17 @@ static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf, { struct ifx_spi_device *ifx_dev = tty->driver_data; unsigned char *tmp_buf = (unsigned char *)buf; - int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count, - &ifx_dev->fifo_lock); - mrdy_assert(ifx_dev); + unsigned long flags; + bool is_fifo_empty; + int tx_count; + + spin_lock_irqsave(&ifx_dev->fifo_lock, flags); + is_fifo_empty = kfifo_is_empty(&ifx_dev->tx_fifo); + tx_count = kfifo_in(&ifx_dev->tx_fifo, tmp_buf, count); + spin_unlock_irqrestore(&ifx_dev->fifo_lock, flags); + if (is_fifo_empty) + mrdy_assert(ifx_dev); + return tx_count; } @@ -530,11 +606,18 @@ static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty) /* clear any old data; can't do this in 'close' */ kfifo_reset(&ifx_dev->tx_fifo); + /* clear any flag which may be set in port shutdown procedure */ + clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags); + clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags); + /* put port data into this tty */ tty->driver_data = ifx_dev; /* allows flip string push from int context */ - tty->low_latency = 1; + port->low_latency = 1; + + /* set flag to allows data transfer */ + set_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); return 0; } @@ -551,7 +634,9 @@ static void ifx_port_shutdown(struct tty_port *port) struct ifx_spi_device *ifx_dev = container_of(port, struct ifx_spi_device, tty_port); + clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); mrdy_set_low(ifx_dev); + del_timer(&ifx_dev->spi_timer); clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); tasklet_kill(&ifx_dev->io_work_tasklet); } @@ -584,12 +669,8 @@ static const struct tty_operations ifx_spi_serial_ops = { static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev, unsigned char *chars, size_t size) { - struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port); - if (!tty) - return; - tty_insert_flip_string(tty, chars, size); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_insert_flip_string(&ifx_dev->tty_port, chars, size); + tty_flip_buffer_push(&ifx_dev->tty_port); } /** @@ -617,7 +698,7 @@ static void ifx_spi_complete(void *ctx) if (!ifx_dev->spi_msg.status) { /* check header validity, get comm flags */ - swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD, + ifx_dev->swap_buf(ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD, &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]); decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer, &length, &more, &cts); @@ -636,7 +717,8 @@ static void ifx_spi_complete(void *ctx) actual_length = min((unsigned int)length, ifx_dev->spi_msg.actual_length); - swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD), + ifx_dev->swap_buf( + (ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD), actual_length, &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]); ifx_spi_insert_flip_string( @@ -705,7 +787,8 @@ static void ifx_spi_io(unsigned long data) int retval; struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data; - if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) { + if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags) && + test_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags)) { if (ifx_dev->gpio.unack_srdy_int_nb > 0) ifx_dev->gpio.unack_srdy_int_nb--; @@ -723,7 +806,8 @@ static void ifx_spi_io(unsigned long data) ifx_dev->spi_xfer.cs_change = 0; ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz; /* ifx_dev->spi_xfer.speed_hz = 390625; */ - ifx_dev->spi_xfer.bits_per_word = spi_bpw; + ifx_dev->spi_xfer.bits_per_word = + ifx_dev->spi_dev->bits_per_word; ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; @@ -773,6 +857,7 @@ static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev) { if (ifx_dev->tty_dev) tty_unregister_device(tty_drv, ifx_dev->minor); + tty_port_destroy(&ifx_dev->tty_port); kfifo_free(&ifx_dev->tx_fifo); } @@ -806,10 +891,12 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev) dev_dbg(&ifx_dev->spi_dev->dev, "%s: registering tty device failed", __func__); ret = PTR_ERR(ifx_dev->tty_dev); - goto error_ret; + goto error_port; } return 0; +error_port: + tty_port_destroy(pport); error_ret: ifx_spi_free_port(ifx_dev); return ret; @@ -826,7 +913,7 @@ error_ret: static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev) { if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) { - del_timer_sync(&ifx_dev->spi_timer); + del_timer(&ifx_dev->spi_timer); clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); } @@ -1001,6 +1088,14 @@ static int ifx_spi_spi_probe(struct spi_device *spi) return -ENODEV; } + /* init swap_buf function according to word width configuration */ + if (spi->bits_per_word == 32) + ifx_dev->swap_buf = swap_buf_32; + else if (spi->bits_per_word == 16) + ifx_dev->swap_buf = swap_buf_16; + else + ifx_dev->swap_buf = swap_buf_8; + /* ensure SPI protocol flags are initialized to enable transfer */ ifx_dev->spi_more = 0; ifx_dev->spi_slave_cts = 0; @@ -1219,6 +1314,9 @@ static int ifx_spi_spi_remove(struct spi_device *spi) static void ifx_spi_spi_shutdown(struct spi_device *spi) { + struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); + + ifx_modem_power_off(ifx_dev); } /* @@ -1338,7 +1436,7 @@ static struct spi_driver ifx_spi_driver = { .owner = THIS_MODULE}, .probe = ifx_spi_spi_probe, .shutdown = ifx_spi_spi_shutdown, - .remove = __devexit_p(ifx_spi_spi_remove), + .remove = ifx_spi_spi_remove, .suspend = ifx_spi_spi_suspend, .resume = ifx_spi_spi_resume, .id_table = ifx_id_table @@ -1354,7 +1452,9 @@ static void __exit ifx_spi_exit(void) { /* unregister */ tty_unregister_driver(tty_drv); + put_tty_driver(tty_drv); spi_unregister_driver((void *)&ifx_spi_driver); + unregister_reboot_notifier(&ifx_modem_reboot_notifier_block); } /** @@ -1389,16 +1489,31 @@ static int __init ifx_spi_init(void) if (result) { pr_err("%s: tty_register_driver failed(%d)", DRVNAME, result); - put_tty_driver(tty_drv); - return result; + goto err_free_tty; } result = spi_register_driver((void *)&ifx_spi_driver); if (result) { pr_err("%s: spi_register_driver failed(%d)", DRVNAME, result); - tty_unregister_driver(tty_drv); + goto err_unreg_tty; + } + + result = register_reboot_notifier(&ifx_modem_reboot_notifier_block); + if (result) { + pr_err("%s: register ifx modem reboot notifier failed(%d)", + DRVNAME, result); + goto err_unreg_spi; } + + return 0; +err_unreg_spi: + spi_unregister_driver((void *)&ifx_spi_driver); +err_unreg_tty: + tty_unregister_driver(tty_drv); +err_free_tty: + put_tty_driver(tty_drv); + return result; } diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h index e8464baf9e75..4fbddc297839 100644 --- a/drivers/tty/serial/ifx6x60.h +++ b/drivers/tty/serial/ifx6x60.h @@ -41,6 +41,7 @@ #define IFX_SPI_STATE_IO_IN_PROGRESS 1 #define IFX_SPI_STATE_IO_READY 2 #define IFX_SPI_STATE_TIMER_PENDING 3 +#define IFX_SPI_STATE_IO_AVAILABLE 4 /* flow control bitfields */ #define IFX_SPI_DCD 0 @@ -124,6 +125,7 @@ struct ifx_spi_device { #define MR_INPROGRESS 1 #define MR_COMPLETE 2 wait_queue_head_t mdm_reset_wait; + void (*swap_buf)(unsigned char *buf, int len, void *end); }; #endif /* _IFX6X60_H */ diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 59819121fe9b..147c9e193595 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -48,8 +48,8 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> +#include <linux/io.h> -#include <asm/io.h> #include <asm/irq.h> #include <linux/platform_data/serial-imx.h> @@ -73,102 +73,102 @@ #define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/ /* UART Control Register Bit Fields.*/ -#define URXD_CHARRDY (1<<15) -#define URXD_ERR (1<<14) -#define URXD_OVRRUN (1<<13) -#define URXD_FRMERR (1<<12) -#define URXD_BRK (1<<11) -#define URXD_PRERR (1<<10) -#define UCR1_ADEN (1<<15) /* Auto detect interrupt */ -#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ -#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ -#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ -#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ -#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ -#define UCR1_IREN (1<<7) /* Infrared interface enable */ -#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ -#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ -#define UCR1_SNDBRK (1<<4) /* Send break */ -#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ -#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */ -#define UCR1_DOZE (1<<1) /* Doze */ -#define UCR1_UARTEN (1<<0) /* UART enabled */ -#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ -#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ -#define UCR2_CTSC (1<<13) /* CTS pin control */ -#define UCR2_CTS (1<<12) /* Clear to send */ -#define UCR2_ESCEN (1<<11) /* Escape enable */ -#define UCR2_PREN (1<<8) /* Parity enable */ -#define UCR2_PROE (1<<7) /* Parity odd/even */ -#define UCR2_STPB (1<<6) /* Stop */ -#define UCR2_WS (1<<5) /* Word size */ -#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ -#define UCR2_ATEN (1<<3) /* Aging Timer Enable */ -#define UCR2_TXEN (1<<2) /* Transmitter enabled */ -#define UCR2_RXEN (1<<1) /* Receiver enabled */ -#define UCR2_SRST (1<<0) /* SW reset */ -#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ -#define UCR3_PARERREN (1<<12) /* Parity enable */ -#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ -#define UCR3_DSR (1<<10) /* Data set ready */ -#define UCR3_DCD (1<<9) /* Data carrier detect */ -#define UCR3_RI (1<<8) /* Ring indicator */ -#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ -#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ -#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ -#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ -#define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */ -#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ -#define UCR3_BPEN (1<<0) /* Preset registers enable */ -#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */ -#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */ -#define UCR4_INVR (1<<9) /* Inverted infrared reception */ -#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ -#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ -#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ -#define UCR4_IRSC (1<<5) /* IR special case */ -#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ -#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ -#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ -#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ -#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ -#define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */ -#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ -#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) -#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ -#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ -#define USR1_RTSS (1<<14) /* RTS pin status */ -#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ -#define USR1_RTSD (1<<12) /* RTS delta */ -#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ -#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ -#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ -#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ -#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ -#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ -#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ -#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ -#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ -#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ -#define USR2_IDLE (1<<12) /* Idle condition */ -#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ -#define USR2_WAKE (1<<7) /* Wake */ -#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ -#define USR2_TXDC (1<<3) /* Transmitter complete */ -#define USR2_BRCD (1<<2) /* Break condition */ -#define USR2_ORE (1<<1) /* Overrun error */ -#define USR2_RDR (1<<0) /* Recv data ready */ -#define UTS_FRCPERR (1<<13) /* Force parity error */ -#define UTS_LOOP (1<<12) /* Loop tx and rx */ -#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ -#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ -#define UTS_TXFULL (1<<4) /* TxFIFO full */ -#define UTS_RXFULL (1<<3) /* RxFIFO full */ -#define UTS_SOFTRST (1<<0) /* Software reset */ +#define URXD_CHARRDY (1<<15) +#define URXD_ERR (1<<14) +#define URXD_OVRRUN (1<<13) +#define URXD_FRMERR (1<<12) +#define URXD_BRK (1<<11) +#define URXD_PRERR (1<<10) +#define UCR1_ADEN (1<<15) /* Auto detect interrupt */ +#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ +#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ +#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ +#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ +#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ +#define UCR1_IREN (1<<7) /* Infrared interface enable */ +#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ +#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ +#define UCR1_SNDBRK (1<<4) /* Send break */ +#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ +#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */ +#define UCR1_DOZE (1<<1) /* Doze */ +#define UCR1_UARTEN (1<<0) /* UART enabled */ +#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ +#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ +#define UCR2_CTSC (1<<13) /* CTS pin control */ +#define UCR2_CTS (1<<12) /* Clear to send */ +#define UCR2_ESCEN (1<<11) /* Escape enable */ +#define UCR2_PREN (1<<8) /* Parity enable */ +#define UCR2_PROE (1<<7) /* Parity odd/even */ +#define UCR2_STPB (1<<6) /* Stop */ +#define UCR2_WS (1<<5) /* Word size */ +#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ +#define UCR2_ATEN (1<<3) /* Aging Timer Enable */ +#define UCR2_TXEN (1<<2) /* Transmitter enabled */ +#define UCR2_RXEN (1<<1) /* Receiver enabled */ +#define UCR2_SRST (1<<0) /* SW reset */ +#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ +#define UCR3_PARERREN (1<<12) /* Parity enable */ +#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ +#define UCR3_DSR (1<<10) /* Data set ready */ +#define UCR3_DCD (1<<9) /* Data carrier detect */ +#define UCR3_RI (1<<8) /* Ring indicator */ +#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ +#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ +#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ +#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ +#define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */ +#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ +#define UCR3_BPEN (1<<0) /* Preset registers enable */ +#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */ +#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */ +#define UCR4_INVR (1<<9) /* Inverted infrared reception */ +#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ +#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ +#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ +#define UCR4_IRSC (1<<5) /* IR special case */ +#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ +#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ +#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ +#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ +#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ +#define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */ +#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) +#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ +#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ +#define USR1_RTSS (1<<14) /* RTS pin status */ +#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ +#define USR1_RTSD (1<<12) /* RTS delta */ +#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ +#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ +#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ +#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ +#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ +#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ +#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ +#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ +#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ +#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ +#define USR2_IDLE (1<<12) /* Idle condition */ +#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ +#define USR2_WAKE (1<<7) /* Wake */ +#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ +#define USR2_TXDC (1<<3) /* Transmitter complete */ +#define USR2_BRCD (1<<2) /* Break condition */ +#define USR2_ORE (1<<1) /* Overrun error */ +#define USR2_RDR (1<<0) /* Recv data ready */ +#define UTS_FRCPERR (1<<13) /* Force parity error */ +#define UTS_LOOP (1<<12) /* Loop tx and rx */ +#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ +#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ +#define UTS_TXFULL (1<<4) /* TxFIFO full */ +#define UTS_RXFULL (1<<3) /* RxFIFO full */ +#define UTS_SOFTRST (1<<0) /* Software reset */ /* We've been assigned a range on the "Low-density serial ports" major */ -#define SERIAL_IMX_MAJOR 207 -#define MINOR_START 16 +#define SERIAL_IMX_MAJOR 207 +#define MINOR_START 16 #define DEV_NAME "ttymxc" /* @@ -199,7 +199,7 @@ struct imx_port { struct uart_port port; struct timer_list timer; unsigned int old_status; - int txirq,rxirq,rtsirq; + int txirq, rxirq, rtsirq; unsigned int have_rtscts:1; unsigned int use_irda:1; unsigned int irda_inv_rx:1; @@ -397,7 +397,7 @@ static void imx_stop_rx(struct uart_port *port) unsigned long temp; temp = readl(sport->port.membase + UCR2); - writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2); + writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); } /* @@ -490,9 +490,8 @@ static irqreturn_t imx_txint(int irq, void *dev_id) struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; - spin_lock_irqsave(&sport->port.lock,flags); - if (sport->port.x_char) - { + spin_lock_irqsave(&sport->port.lock, flags); + if (sport->port.x_char) { /* Send next char */ writel(sport->port.x_char, sport->port.membase + URTX0); goto out; @@ -509,18 +508,18 @@ static irqreturn_t imx_txint(int irq, void *dev_id) uart_write_wakeup(&sport->port); out: - spin_unlock_irqrestore(&sport->port.lock,flags); + spin_unlock_irqrestore(&sport->port.lock, flags); return IRQ_HANDLED; } static irqreturn_t imx_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int rx,flg,ignored = 0; - struct tty_struct *tty = sport->port.state->port.tty; + unsigned int rx, flg, ignored = 0; + struct tty_port *port = &sport->port.state->port; unsigned long flags, temp; - spin_lock_irqsave(&sport->port.lock,flags); + spin_lock_irqsave(&sport->port.lock, flags); while (readl(sport->port.membase + USR2) & USR2_RDR) { flg = TTY_NORMAL; @@ -570,12 +569,12 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) #endif } - tty_insert_flip_char(tty, rx, flg); + tty_insert_flip_char(port, rx, flg); } out: - spin_unlock_irqrestore(&sport->port.lock,flags); - tty_flip_buffer_push(tty); + spin_unlock_irqrestore(&sport->port.lock, flags); + tty_flip_buffer_push(port); return IRQ_HANDLED; } @@ -654,7 +653,7 @@ static void imx_break_ctl(struct uart_port *port, int break_state) temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK; - if ( break_state != 0 ) + if (break_state != 0) temp |= UCR1_SNDBRK; writel(temp, sport->port.membase + UCR1); @@ -696,8 +695,8 @@ static int imx_startup(struct uart_port *port) temp |= UCR4_IRSC; /* set the trigger level for CTS */ - temp &= ~(UCR4_CTSTL_MASK<< UCR4_CTSTL_SHF); - temp |= CTSTL<< UCR4_CTSTL_SHF; + temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF); + temp |= CTSTL << UCR4_CTSTL_SHF; writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); @@ -799,7 +798,7 @@ static int imx_startup(struct uart_port *port) * Enable modem status interrupts */ imx_enable_ms(&sport->port); - spin_unlock_irqrestore(&sport->port.lock,flags); + spin_unlock_irqrestore(&sport->port.lock, flags); if (USE_IRDA(sport)) { struct imxuart_platform_data *pdata; @@ -909,7 +908,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, ucr2 = UCR2_SRST | UCR2_IRTS; if (termios->c_cflag & CRTSCTS) { - if( sport->have_rtscts ) { + if (sport->have_rtscts) { ucr2 &= ~UCR2_IRTS; ucr2 |= UCR2_CTSC; } else { @@ -969,12 +968,12 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), sport->port.membase + UCR1); - while ( !(readl(sport->port.membase + USR2) & USR2_TXDC)) + while (!(readl(sport->port.membase + USR2) & USR2_TXDC)) barrier(); /* then, disable everything */ old_txrxen = readl(sport->port.membase + UCR2); - writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN), + writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN), sport->port.membase + UCR2); old_txrxen &= (UCR2_TXEN | UCR2_RXEN); @@ -1212,9 +1211,15 @@ imx_console_write(struct console *co, const char *s, unsigned int count) struct imx_port *sport = imx_ports[co->index]; struct imx_port_ucrs old_ucr; unsigned int ucr1; - unsigned long flags; + unsigned long flags = 0; + int locked = 1; - spin_lock_irqsave(&sport->port.lock, flags); + if (sport->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock_irqsave(&sport->port.lock, flags); + else + spin_lock_irqsave(&sport->port.lock, flags); /* * First, save UCR1/2/3 and then disable interrupts @@ -1241,7 +1246,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count) imx_port_ucrs_restore(&sport->port, &old_ucr); - spin_unlock_irqrestore(&sport->port.lock, flags); + if (locked) + spin_unlock_irqrestore(&sport->port.lock, flags); } /* @@ -1255,7 +1261,7 @@ imx_console_get_options(struct imx_port *sport, int *baud, if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) { /* ok, the port was enabled */ - unsigned int ucr2, ubir,ubmr, uartclk; + unsigned int ucr2, ubir, ubmr, uartclk; unsigned int baud_raw; unsigned int ucfr_rfdiv; @@ -1301,8 +1307,8 @@ imx_console_get_options(struct imx_port *sport, int *baud, *baud = (baud_raw + 50) / 100 * 100; } - if(*baud != baud_raw) - printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n", + if (*baud != baud_raw) + pr_info("Console IMX rounded baud rate from %d to %d\n", baud_raw, *baud); } } @@ -1324,7 +1330,7 @@ imx_console_setup(struct console *co, char *options) if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) co->index = 0; sport = imx_ports[co->index]; - if(sport == NULL) + if (sport == NULL) return -ENODEV; if (options) @@ -1462,7 +1468,7 @@ static int serial_imx_probe(struct platform_device *pdev) struct resource *res; struct pinctrl *pinctrl; - sport = kzalloc(sizeof(*sport), GFP_KERNEL); + sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); if (!sport) return -ENOMEM; @@ -1470,19 +1476,15 @@ static int serial_imx_probe(struct platform_device *pdev) if (ret > 0) serial_imx_probe_pdata(sport, pdev); else if (ret < 0) - goto free; + return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto free; - } + if (!res) + return -ENODEV; - base = ioremap(res->start, PAGE_SIZE); - if (!base) { - ret = -ENOMEM; - goto free; - } + base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE); + if (!base) + return -ENOMEM; sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; @@ -1504,21 +1506,21 @@ static int serial_imx_probe(struct platform_device *pdev) if (IS_ERR(pinctrl)) { ret = PTR_ERR(pinctrl); dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret); - goto unmap; + return ret; } sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk_ipg)) { ret = PTR_ERR(sport->clk_ipg); dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret); - goto unmap; + return ret; } sport->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(sport->clk_per)) { ret = PTR_ERR(sport->clk_per); dev_err(&pdev->dev, "failed to get per clk: %d\n", ret); - goto unmap; + return ret; } clk_prepare_enable(sport->clk_per); @@ -1547,11 +1549,6 @@ deinit: clkput: clk_disable_unprepare(sport->clk_per); clk_disable_unprepare(sport->clk_ipg); -unmap: - iounmap(sport->port.membase); -free: - kfree(sport); - return ret; } @@ -1572,9 +1569,6 @@ static int serial_imx_remove(struct platform_device *pdev) if (pdata && pdata->exit) pdata->exit(pdev); - iounmap(sport->port.membase); - kfree(sport); - return 0; } @@ -1596,7 +1590,7 @@ static int __init imx_serial_init(void) { int ret; - printk(KERN_INFO "Serial: IMX driver\n"); + pr_info("Serial: IMX driver\n"); ret = uart_register_driver(&imx_reg); if (ret) diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c index 5ac52898a0bb..6e4c715c5d26 100644 --- a/drivers/tty/serial/ioc3_serial.c +++ b/drivers/tty/serial/ioc3_serial.c @@ -1000,7 +1000,7 @@ ioc3_change_speed(struct uart_port *the_port, the_port->ignore_status_mask = N_ALL_INPUT; - state->port.tty->low_latency = 1; + state->port.low_latency = 1; if (iflag & IGNPAR) the_port->ignore_status_mask &= ~(N_PARITY_ERROR @@ -1393,7 +1393,6 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len) */ static int receive_chars(struct uart_port *the_port) { - struct tty_struct *tty; unsigned char ch[MAX_CHARS]; int read_count = 0, read_room, flip = 0; struct uart_state *state = the_port->state; @@ -1403,25 +1402,23 @@ static int receive_chars(struct uart_port *the_port) /* Make sure all the pointers are "good" ones */ if (!state) return 0; - if (!state->port.tty) - return 0; if (!(port->ip_flags & INPUT_ENABLE)) return 0; spin_lock_irqsave(&the_port->lock, pflags); - tty = state->port.tty; read_count = do_read(the_port, ch, MAX_CHARS); if (read_count > 0) { flip = 1; - read_room = tty_insert_flip_string(tty, ch, read_count); + read_room = tty_insert_flip_string(&state->port, ch, + read_count); the_port->icount.rx += read_count; } spin_unlock_irqrestore(&the_port->lock, pflags); if (flip) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&state->port); return read_count; } @@ -2010,7 +2007,7 @@ static int ioc3uart_remove(struct ioc3_submodule *is, * @idd: ioc3 driver data for this card */ -static int __devinit +static int ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) { struct pci_dev *pdev = idd->pdev; diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index 3e7da10cebba..e2520abcb1c4 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -1740,7 +1740,7 @@ ioc4_change_speed(struct uart_port *the_port, the_port->ignore_status_mask = N_ALL_INPUT; - state->port.tty->low_latency = 1; + state->port.low_latency = 1; if (iflag & IGNPAR) the_port->ignore_status_mask &= ~(N_PARITY_ERROR @@ -2340,7 +2340,6 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf, */ static void receive_chars(struct uart_port *the_port) { - struct tty_struct *tty; unsigned char ch[IOC4_MAX_CHARS]; int read_count, request_count = IOC4_MAX_CHARS; struct uart_icount *icount; @@ -2350,26 +2349,23 @@ static void receive_chars(struct uart_port *the_port) /* Make sure all the pointers are "good" ones */ if (!state) return; - if (!state->port.tty) - return; spin_lock_irqsave(&the_port->lock, pflags); - tty = state->port.tty; - request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS); + request_count = tty_buffer_request_room(&state->port, IOC4_MAX_CHARS); if (request_count > 0) { icount = &the_port->icount; read_count = do_read(the_port, ch, request_count); if (read_count > 0) { - tty_insert_flip_string(tty, ch, read_count); + tty_insert_flip_string(&state->port, ch, read_count); icount->rx += read_count; } } spin_unlock_irqrestore(&the_port->lock, pflags); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&state->port); } /** @@ -2883,6 +2879,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) /* error exits that give back resources */ out5: ioc4_serial_remove_one(idd); + return ret; out4: kfree(soft); out3: diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index 7b1cda59ebb5..cb3c81eb0996 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -248,17 +248,12 @@ static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up, #define Rx_BRK 0x0100 /* BREAK event software flag. */ #define Rx_SYS 0x0200 /* SysRq event software flag. */ -static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up, +static bool ip22zilog_receive_chars(struct uart_ip22zilog_port *up, struct zilog_channel *channel) { - struct tty_struct *tty; unsigned char ch, flag; unsigned int r1; - - tty = NULL; - if (up->port.state != NULL && - up->port.state->port.tty != NULL) - tty = up->port.state->port.tty; + bool push = up->port.state != NULL; for (;;) { ch = readb(&channel->control); @@ -312,10 +307,10 @@ static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up if (uart_handle_sysrq_char(&up->port, ch)) continue; - if (tty) + if (push) uart_insert_char(&up->port, r1, Rx_OVR, ch, flag); } - return tty; + return push; } static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, @@ -438,21 +433,20 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) while (up) { struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - struct tty_struct *tty; unsigned char r3; + bool push = false; spin_lock(&up->port.lock); r3 = read_zsreg(channel, R3); /* Channel A */ - tty = NULL; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); if (r3 & CHARxIP) - tty = ip22zilog_receive_chars(up, channel); + push = ip22zilog_receive_chars(up, channel); if (r3 & CHAEXT) ip22zilog_status_handle(up, channel); if (r3 & CHATxIP) @@ -460,22 +454,22 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) } spin_unlock(&up->port.lock); - if (tty) - tty_flip_buffer_push(tty); + if (push) + tty_flip_buffer_push(&up->port.state->port); /* Channel B */ up = up->next; channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + push = false; spin_lock(&up->port.lock); - tty = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); if (r3 & CHBRxIP) - tty = ip22zilog_receive_chars(up, channel); + push = ip22zilog_receive_chars(up, channel); if (r3 & CHBEXT) ip22zilog_status_handle(up, channel); if (r3 & CHBTxIP) @@ -483,8 +477,8 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) } spin_unlock(&up->port.lock); - if (tty) - tty_flip_buffer_push(tty); + if (push) + tty_flip_buffer_push(&up->port.state->port); up = up->next; } diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index 529bec6edaf8..844d5e4eb1aa 100644 --- a/drivers/tty/serial/jsm/jsm.h +++ b/drivers/tty/serial/jsm/jsm.h @@ -57,9 +57,11 @@ enum { DBG_CARR = 0x10000, }; -#define jsm_printk(nlevel, klevel, pdev, fmt, args...) \ - if ((DBG_##nlevel & jsm_debug)) \ - dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) +#define jsm_dbg(nlevel, pdev, fmt, ...) \ +do { \ + if (DBG_##nlevel & jsm_debug) \ + dev_dbg(pdev->dev, fmt, ##__VA_ARGS__); \ +} while (0) #define MAXLINES 256 #define MAXPORTS 8 diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 5ab3c3b595e4..a47d882d6743 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -64,7 +64,7 @@ int jsm_debug; module_param(jsm_debug, int, 0); MODULE_PARM_DESC(jsm_debug, "Driver debugging level"); -static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) +static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc = 0; struct jsm_board *brd; @@ -107,8 +107,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device brd->irq = pdev->irq; - jsm_printk(INIT, INFO, &brd->pci_dev, - "jsm_found_board - NEO adapter\n"); + jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n"); /* get the PCI Base Address Registers */ brd->membase = pci_resource_start(pdev, 0); @@ -179,7 +178,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device return rc; } -static void __devexit jsm_remove_one(struct pci_dev *pdev) +static void jsm_remove_one(struct pci_dev *pdev) { struct jsm_board *brd = pci_get_drvdata(pdev); int i = 0; @@ -218,7 +217,7 @@ static struct pci_driver jsm_driver = { .name = "jsm", .id_table = jsm_pci_tbl, .probe = jsm_probe_one, - .remove = __devexit_p(jsm_remove_one), + .remove = jsm_remove_one, .err_handler = &jsm_err_handler, }; diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 81dfafa11b0b..dfaf48826417 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -52,7 +52,7 @@ static void neo_set_cts_flow_control(struct jsm_channel *ch) ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n"); + jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n"); /* Turn on auto CTS flow control */ ier |= (UART_17158_IER_CTSDSR); @@ -83,7 +83,7 @@ static void neo_set_rts_flow_control(struct jsm_channel *ch) ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n"); + jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n"); /* Turn on auto RTS flow control */ ier |= (UART_17158_IER_RTSDTR); @@ -123,7 +123,7 @@ static void neo_set_ixon_flow_control(struct jsm_channel *ch) ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n"); + jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n"); /* Turn off auto CTS flow control */ ier &= ~(UART_17158_IER_CTSDSR); @@ -160,7 +160,7 @@ static void neo_set_ixoff_flow_control(struct jsm_channel *ch) ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n"); + jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n"); /* Turn off auto RTS flow control */ ier &= ~(UART_17158_IER_RTSDTR); @@ -198,7 +198,7 @@ static void neo_set_no_input_flow_control(struct jsm_channel *ch) ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n"); + jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n"); /* Turn off auto RTS flow control */ ier &= ~(UART_17158_IER_RTSDTR); @@ -237,7 +237,7 @@ static void neo_set_no_output_flow_control(struct jsm_channel *ch) ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n"); + jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n"); /* Turn off auto CTS flow control */ ier &= ~(UART_17158_IER_CTSDSR); @@ -276,7 +276,7 @@ static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch) if (ch->ch_c_cflag & CRTSCTS) return; - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n"); + jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "start\n"); /* Tell UART what start/stop chars it should be looking for */ writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); @@ -455,7 +455,7 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) * I hope thats okay with everyone? Yes? Good. */ while (qleft < 1) { - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, + jsm_dbg(READ, &ch->ch_bd->pci_dev, "Queue full, dropping DATA:%x LSR:%x\n", ch->ch_rqueue[tail], ch->ch_equeue[tail]); @@ -467,8 +467,8 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1); ch->ch_equeue[head] = (u8) linestatus; - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]); + jsm_dbg(READ, &ch->ch_bd->pci_dev, "DATA/LSR pair: %x %x\n", + ch->ch_rqueue[head], ch->ch_equeue[head]); /* Ditch any remaining linestatus value. */ linestatus = 0; @@ -521,8 +521,8 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) ch->ch_cached_lsr &= ~(UART_LSR_THRE); writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx); - jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev, - "Tx data: %x\n", circ->buf[circ->tail]); + jsm_dbg(WRITE, &ch->ch_bd->pci_dev, + "Tx data: %x\n", circ->buf[circ->tail]); circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1); ch->ch_txcount++; } @@ -575,8 +575,9 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals) { u8 msignals = signals; - jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev, - "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals); + jsm_dbg(MSIGS, &ch->ch_bd->pci_dev, + "neo_parse_modem: port: %d msignals: %x\n", + ch->ch_portnum, msignals); /* Scrub off lower bits. They signify delta's, which I don't care about */ /* Keep DDCD and DDSR though */ @@ -606,8 +607,8 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals) else ch->ch_mistat &= ~UART_MSR_CTS; - jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev, - "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n", + jsm_dbg(MSIGS, &ch->ch_bd->pci_dev, + "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n", ch->ch_portnum, !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR), !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS), @@ -649,8 +650,8 @@ static void neo_flush_uart_write(struct jsm_channel *ch) /* Check to see if the UART feels it completely flushed the FIFO. */ tmp = readb(&ch->ch_neo_uart->isr_fcr); if (tmp & 4) { - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, - "Still flushing TX UART... i: %d\n", i); + jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, + "Still flushing TX UART... i: %d\n", i); udelay(10); } else @@ -681,8 +682,8 @@ static void neo_flush_uart_read(struct jsm_channel *ch) /* Check to see if the UART feels it completely flushed the FIFO. */ tmp = readb(&ch->ch_neo_uart->isr_fcr); if (tmp & 2) { - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, - "Still flushing RX UART... i: %d\n", i); + jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, + "Still flushing RX UART... i: %d\n", i); udelay(10); } else @@ -705,8 +706,9 @@ static void neo_clear_break(struct jsm_channel *ch, int force) writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr); ch->ch_flags &= ~(CH_BREAK_SENDING); - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, - "clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies); + jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, + "clear break Finishing UART_LCR_SBC! finished: %lx\n", + jiffies); /* flush write operation */ neo_pci_posting_flush(ch->ch_bd); @@ -748,8 +750,8 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port) */ isr &= ~(UART_17158_IIR_FIFO_ENABLED); - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "%s:%d isr: %x\n", __FILE__, __LINE__, isr); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d isr: %x\n", + __FILE__, __LINE__, isr); if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) { /* Read data from uart -> queue */ @@ -772,8 +774,9 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port) if (isr & UART_17158_IIR_XONXOFF) { cause = readb(&ch->ch_neo_uart->xoffchar1); - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, + "Port %d. Got ISR_XONXOFF: cause:%x\n", + port, cause); /* * Since the UART detected either an XON or @@ -786,17 +789,19 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port) if (brd->channels[port]->ch_flags & CH_STOP) { ch->ch_flags &= ~(CH_STOP); } - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "Port %d. XON detected in incoming data\n", port); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, + "Port %d. XON detected in incoming data\n", + port); } else if (cause == UART_17158_XOFF_DETECT) { if (!(brd->channels[port]->ch_flags & CH_STOP)) { ch->ch_flags |= CH_STOP; - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "Setting CH_STOP\n"); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, + "Setting CH_STOP\n"); } - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "Port: %d. XOFF detected in incoming data\n", port); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, + "Port: %d. XOFF detected in incoming data\n", + port); } spin_unlock_irqrestore(&ch->ch_lock, lock_flags); } @@ -825,8 +830,8 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port) } /* Parse any modem signal changes */ - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "MOD_STAT: sending to parse_modem_sigs\n"); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, + "MOD_STAT: sending to parse_modem_sigs\n"); neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); } } @@ -849,8 +854,8 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) linestatus = readb(&ch->ch_neo_uart->lsr); - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d port: %d linestatus: %x\n", + __FILE__, __LINE__, port, linestatus); ch->ch_cached_lsr |= linestatus; @@ -869,7 +874,7 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) *to do the special RX+LSR read for this FIFO load. */ if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, + jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d Got an RX error, need to parse LSR\n", __FILE__, __LINE__, port); @@ -880,20 +885,21 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) if (linestatus & UART_LSR_PE) { ch->ch_err_parity++; - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d. PAR ERR!\n", + __FILE__, __LINE__, port); } if (linestatus & UART_LSR_FE) { ch->ch_err_frame++; - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d. FRM ERR!\n", + __FILE__, __LINE__, port); } if (linestatus & UART_LSR_BI) { ch->ch_err_break++; - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, + "%s:%d Port: %d. BRK INTR!\n", + __FILE__, __LINE__, port); } if (linestatus & UART_LSR_OE) { @@ -904,8 +910,9 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) * Probably we should eventually have an orun stat in our driver... */ ch->ch_err_overrun++; - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port); + jsm_dbg(INTR, &ch->ch_bd->pci_dev, + "%s:%d Port: %d. Rx Overrun!\n", + __FILE__, __LINE__, port); } if (linestatus & UART_LSR_THRE) { @@ -1128,11 +1135,11 @@ static irqreturn_t neo_intr(int irq, void *voidbrd) */ uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET); - jsm_printk(INTR, INFO, &brd->pci_dev, - "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll); + jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n", + __FILE__, __LINE__, uart_poll); if (!uart_poll) { - jsm_printk(INTR, INFO, &brd->pci_dev, + jsm_dbg(INTR, &brd->pci_dev, "Kernel interrupted to me, but no pending interrupts...\n"); spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); return IRQ_NONE; @@ -1158,15 +1165,15 @@ static irqreturn_t neo_intr(int irq, void *voidbrd) continue; } - jsm_printk(INTR, INFO, &brd->pci_dev, - "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type); + jsm_dbg(INTR, &brd->pci_dev, "%s:%d port: %x type: %x\n", + __FILE__, __LINE__, port, type); /* Remove this port + type from uart_poll */ uart_poll &= ~(jsm_offset_table[port]); if (!type) { /* If no type, just ignore it, and move onto next port */ - jsm_printk(INTR, ERR, &brd->pci_dev, + jsm_dbg(INTR, &brd->pci_dev, "Interrupt with no type! port: %d\n", port); continue; } @@ -1231,15 +1238,16 @@ static irqreturn_t neo_intr(int irq, void *voidbrd) * these once and awhile. * Its harmless, just ignore it and move on. */ - jsm_printk(INTR, ERR, &brd->pci_dev, - "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type); + jsm_dbg(INTR, &brd->pci_dev, + "%s:%d Unknown Interrupt type: %x\n", + __FILE__, __LINE__, type); continue; } } spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); - jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n"); + jsm_dbg(INTR, &brd->pci_dev, "finish\n"); return IRQ_HANDLED; } diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 71397961773c..00f250ae14c5 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -43,7 +43,7 @@ static inline int jsm_get_mstat(struct jsm_channel *ch) unsigned char mstat; unsigned result; - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n"); + jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "start\n"); mstat = (ch->ch_mostat | ch->ch_mistat); @@ -62,7 +62,7 @@ static inline int jsm_get_mstat(struct jsm_channel *ch) if (mstat & UART_MSR_DCD) result |= TIOCM_CD; - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); + jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n"); return result; } @@ -79,14 +79,14 @@ static unsigned int jsm_tty_get_mctrl(struct uart_port *port) int result; struct jsm_channel *channel = (struct jsm_channel *)port; - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); + jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n"); result = jsm_get_mstat(channel); if (result < 0) return -ENXIO; - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); + jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n"); return result; } @@ -100,7 +100,7 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct jsm_channel *channel = (struct jsm_channel *)port; - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); + jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n"); if (mctrl & TIOCM_RTS) channel->ch_mostat |= UART_MCR_RTS; @@ -114,7 +114,7 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl) channel->ch_bd->bd_ops->assert_modem_signals(channel); - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); + jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n"); udelay(10); } @@ -135,23 +135,23 @@ static void jsm_tty_start_tx(struct uart_port *port) { struct jsm_channel *channel = (struct jsm_channel *)port; - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); + jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n"); channel->ch_flags &= ~(CH_STOP); jsm_tty_write(port); - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); + jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n"); } static void jsm_tty_stop_tx(struct uart_port *port) { struct jsm_channel *channel = (struct jsm_channel *)port; - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); + jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n"); channel->ch_flags |= (CH_STOP); - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); + jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n"); } static void jsm_tty_send_xchar(struct uart_port *port, char ch) @@ -216,16 +216,16 @@ static int jsm_tty_open(struct uart_port *port) if (!channel->ch_rqueue) { channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL); if (!channel->ch_rqueue) { - jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, - "unable to allocate read queue buf"); + jsm_dbg(INIT, &channel->ch_bd->pci_dev, + "unable to allocate read queue buf\n"); return -ENOMEM; } } if (!channel->ch_equeue) { channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL); if (!channel->ch_equeue) { - jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, - "unable to allocate error queue buf"); + jsm_dbg(INIT, &channel->ch_bd->pci_dev, + "unable to allocate error queue buf\n"); return -ENOMEM; } } @@ -234,7 +234,7 @@ static int jsm_tty_open(struct uart_port *port) /* * Initialize if neither terminal is open. */ - jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, + jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "jsm_open: initializing channel in open...\n"); /* @@ -270,7 +270,7 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_open_count++; - jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n"); + jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n"); return 0; } @@ -280,7 +280,7 @@ static void jsm_tty_close(struct uart_port *port) struct ktermios *ts; struct jsm_channel *channel = (struct jsm_channel *)port; - jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); + jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "start\n"); bd = channel->ch_bd; ts = &port->state->port.tty->termios; @@ -293,7 +293,7 @@ static void jsm_tty_close(struct uart_port *port) * If we have HUPCL set, lower DTR and RTS */ if (channel->ch_c_cflag & HUPCL) { - jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, + jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "Close. HUPCL set, dropping DTR/RTS\n"); /* Drop RTS/DTR */ @@ -304,7 +304,7 @@ static void jsm_tty_close(struct uart_port *port) /* Turn off UART interrupts for this port */ channel->ch_bd->bd_ops->uart_off(channel); - jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n"); + jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "finish\n"); } static void jsm_tty_set_termios(struct uart_port *port, @@ -371,7 +371,7 @@ static struct uart_ops jsm_ops = { * Init the tty subsystem. Called once per board after board has been * downloaded and init'ed. */ -int __devinit jsm_tty_init(struct jsm_board *brd) +int jsm_tty_init(struct jsm_board *brd) { int i; void __iomem *vaddr; @@ -380,7 +380,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd) if (!brd) return -ENXIO; - jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); + jsm_dbg(INIT, &brd->pci_dev, "start\n"); /* * Initialize board structure elements. @@ -401,9 +401,9 @@ int __devinit jsm_tty_init(struct jsm_board *brd) */ brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL); if (!brd->channels[i]) { - jsm_printk(CORE, ERR, &brd->pci_dev, + jsm_dbg(CORE, &brd->pci_dev, "%s:%d Unable to allocate memory for channel struct\n", - __FILE__, __LINE__); + __FILE__, __LINE__); } } } @@ -431,7 +431,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd) init_waitqueue_head(&ch->ch_flags_wait); } - jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); + jsm_dbg(INIT, &brd->pci_dev, "finish\n"); return 0; } @@ -444,7 +444,7 @@ int jsm_uart_port_init(struct jsm_board *brd) if (!brd) return -ENXIO; - jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); + jsm_dbg(INIT, &brd->pci_dev, "start\n"); /* * Initialize board structure elements. @@ -481,7 +481,7 @@ int jsm_uart_port_init(struct jsm_board *brd) printk(KERN_INFO "jsm: Port %d added\n", i); } - jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); + jsm_dbg(INIT, &brd->pci_dev, "finish\n"); return 0; } @@ -493,7 +493,7 @@ int jsm_remove_uart_port(struct jsm_board *brd) if (!brd) return -ENXIO; - jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); + jsm_dbg(INIT, &brd->pci_dev, "start\n"); /* * Initialize board structure elements. @@ -513,7 +513,7 @@ int jsm_remove_uart_port(struct jsm_board *brd) uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); } - jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); + jsm_dbg(INIT, &brd->pci_dev, "finish\n"); return 0; } @@ -521,6 +521,7 @@ void jsm_input(struct jsm_channel *ch) { struct jsm_board *bd; struct tty_struct *tp; + struct tty_port *port; u32 rmask; u16 head; u16 tail; @@ -531,12 +532,13 @@ void jsm_input(struct jsm_channel *ch) int s = 0; int i = 0; - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); + jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n"); if (!ch) return; - tp = ch->uart_port.state->port.tty; + port = &ch->uart_port.state->port; + tp = port->tty; bd = ch->ch_bd; if(!bd) @@ -560,7 +562,7 @@ void jsm_input(struct jsm_channel *ch) return; } - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); + jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n"); /* *If the device is not open, or CREAD is off, flush @@ -569,8 +571,9 @@ void jsm_input(struct jsm_channel *ch) if (!tp || !(tp->termios.c_cflag & CREAD) ) { - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum); + jsm_dbg(READ, &ch->ch_bd->pci_dev, + "input. dropping %d bytes on port %d...\n", + data_len, ch->ch_portnum); ch->ch_r_head = tail; /* Force queue flow control to be released, if needed */ @@ -585,21 +588,21 @@ void jsm_input(struct jsm_channel *ch) */ if (ch->ch_flags & CH_STOPI) { spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, + jsm_dbg(READ, &ch->ch_bd->pci_dev, "Port %d throttled, not reading any data. head: %x tail: %x\n", ch->ch_portnum, head, tail); return; } - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n"); + jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n"); if (data_len <= 0) { spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n"); + jsm_dbg(READ, &ch->ch_bd->pci_dev, "jsm_input 1\n"); return; } - len = tty_buffer_request_room(tp, data_len); + len = tty_buffer_request_room(port, data_len); n = len; /* @@ -628,16 +631,16 @@ void jsm_input(struct jsm_channel *ch) * format it likes. */ if (*(ch->ch_equeue +tail +i) & UART_LSR_BI) - tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_BREAK); + tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_BREAK); else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE) - tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY); + tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_PARITY); else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE) - tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME); + tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_FRAME); else - tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL); + tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_NORMAL); } } else { - tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ; + tty_insert_flip_string(port, ch->ch_rqueue + tail, s); } tail += s; n -= s; @@ -651,9 +654,9 @@ void jsm_input(struct jsm_channel *ch) spin_unlock_irqrestore(&ch->ch_lock, lock_flags); /* Tell the tty layer its okay to "eat" the data now */ - tty_flip_buffer_push(tp); + tty_flip_buffer_push(port); - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); + jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n"); } static void jsm_carrier(struct jsm_channel *ch) @@ -663,7 +666,7 @@ static void jsm_carrier(struct jsm_channel *ch) int virt_carrier = 0; int phys_carrier = 0; - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n"); + jsm_dbg(CARR, &ch->ch_bd->pci_dev, "start\n"); if (!ch) return; @@ -673,16 +676,16 @@ static void jsm_carrier(struct jsm_channel *ch) return; if (ch->ch_mistat & UART_MSR_DCD) { - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, - "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD); + jsm_dbg(CARR, &ch->ch_bd->pci_dev, "mistat: %x D_CD: %x\n", + ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD); phys_carrier = 1; } if (ch->ch_c_cflag & CLOCAL) virt_carrier = 1; - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, - "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier); + jsm_dbg(CARR, &ch->ch_bd->pci_dev, "DCD: physical: %d virt: %d\n", + phys_carrier, virt_carrier); /* * Test for a VIRTUAL carrier transition to HIGH. @@ -694,8 +697,7 @@ static void jsm_carrier(struct jsm_channel *ch) * for carrier in the open routine. */ - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, - "carrier: virt DCD rose\n"); + jsm_dbg(CARR, &ch->ch_bd->pci_dev, "carrier: virt DCD rose\n"); if (waitqueue_active(&(ch->ch_flags_wait))) wake_up_interruptible(&ch->ch_flags_wait); @@ -711,7 +713,7 @@ static void jsm_carrier(struct jsm_channel *ch) * for carrier in the open routine. */ - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, + jsm_dbg(CARR, &ch->ch_bd->pci_dev, "carrier: physical DCD rose\n"); if (waitqueue_active(&(ch->ch_flags_wait))) @@ -790,8 +792,8 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) if(!(ch->ch_flags & CH_RECEIVER_OFF)) { bd_ops->disable_receiver(ch); ch->ch_flags |= (CH_RECEIVER_OFF); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n", + jsm_dbg(READ, &ch->ch_bd->pci_dev, + "Internal queue hit hilevel mark (%d)! Turning off interrupts\n", qleft); } } @@ -800,8 +802,9 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) if (ch->ch_stops_sent <= MAX_STOPS_SENT) { bd_ops->send_stop_character(ch); ch->ch_stops_sent++; - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "Sending stop char! Times sent: %x\n", ch->ch_stops_sent); + jsm_dbg(READ, &ch->ch_bd->pci_dev, + "Sending stop char! Times sent: %x\n", + ch->ch_stops_sent); } } } @@ -827,8 +830,8 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) if (ch->ch_flags & CH_RECEIVER_OFF) { bd_ops->enable_receiver(ch); ch->ch_flags &= ~(CH_RECEIVER_OFF); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n", + jsm_dbg(READ, &ch->ch_bd->pci_dev, + "Internal queue hit lowlevel mark (%d)! Turning on interrupts\n", qleft); } } @@ -836,7 +839,8 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) { ch->ch_stops_sent = 0; bd_ops->send_start_character(ch); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n"); + jsm_dbg(READ, &ch->ch_bd->pci_dev, + "Sending start char!\n"); } } } diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index d185247ba1aa..5dafcf1c227b 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -23,6 +23,7 @@ #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> +#include <linux/serial_core.h> #include <linux/interrupt.h> #include <linux/hrtimer.h> #include <linux/tick.h> @@ -202,7 +203,6 @@ bool kgdb_nmi_poll_knock(void) static void kgdb_nmi_tty_receiver(unsigned long data) { struct kgdb_nmi_tty_priv *priv = (void *)data; - struct tty_struct *tty; char ch; tasklet_schedule(&priv->tlet); @@ -210,16 +210,9 @@ static void kgdb_nmi_tty_receiver(unsigned long data) if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo))) return; - /* Port is there, but tty might be hung up, check. */ - tty = tty_port_tty_get(kgdb_nmi_port); - if (!tty) - return; - while (kfifo_out(&priv->fifo, &ch, 1)) - tty_insert_flip_char(priv->port.tty, ch, TTY_NORMAL); - tty_flip_buffer_push(priv->port.tty); - - tty_kref_put(tty); + tty_insert_flip_char(&priv->port, ch, TTY_NORMAL); + tty_flip_buffer_push(&priv->port); } static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty) @@ -266,6 +259,7 @@ static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty) } return 0; err: + tty_port_destroy(&priv->port); kfree(priv); return ret; } @@ -275,6 +269,7 @@ static void kgdb_nmi_tty_cleanup(struct tty_struct *tty) struct kgdb_nmi_tty_priv *priv = tty->driver_data; tty->driver_data = NULL; + tty_port_destroy(&priv->port); kfree(priv); } diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 02da071fe1e7..15733da757c6 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -162,21 +162,16 @@ lqasc_enable_ms(struct uart_port *port) static int lqasc_rx_chars(struct uart_port *port) { - struct tty_struct *tty = tty_port_tty_get(&port->state->port); + struct tty_port *tport = &port->state->port; unsigned int ch = 0, rsr = 0, fifocnt; - if (!tty) { - dev_dbg(port->dev, "%s:tty is busy now", __func__); - return -EBUSY; - } - fifocnt = - ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; + fifocnt = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; while (fifocnt--) { u8 flag = TTY_NORMAL; ch = ltq_r8(port->membase + LTQ_ASC_RBUF); rsr = (ltq_r32(port->membase + LTQ_ASC_STATE) & ASCSTATE_ANY) | UART_DUMMY_UER_RX; - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); port->icount.rx++; /* @@ -208,7 +203,7 @@ lqasc_rx_chars(struct uart_port *port) } if ((rsr & port->ignore_status_mask) == 0) - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(tport, ch, flag); if (rsr & ASCSTATE_ROE) /* @@ -216,11 +211,12 @@ lqasc_rx_chars(struct uart_port *port) * immediately, and doesn't affect the current * character */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); } + if (ch != 0) - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(tport); + return 0; } diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index ba3af3bf6d43..dffea6b2cd7d 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -257,17 +257,8 @@ static void __serial_uart_flush(struct uart_port *port) static void __serial_lpc32xx_rx(struct uart_port *port) { + struct tty_port *tport = &port->state->port; unsigned int tmp, flag; - struct tty_struct *tty = tty_port_tty_get(&port->state->port); - - if (!tty) { - /* Discard data: no tty available */ - while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) & - LPC32XX_HSU_RX_EMPTY)) - ; - - return; - } /* Read data from FIFO and push into terminal */ tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); @@ -281,15 +272,14 @@ static void __serial_lpc32xx_rx(struct uart_port *port) LPC32XX_HSUART_IIR(port->membase)); port->icount.frame++; flag = TTY_FRAME; - tty_insert_flip_char(tty, 0, TTY_FRAME); + tty_insert_flip_char(tport, 0, TTY_FRAME); } - tty_insert_flip_char(tty, (tmp & 0xFF), flag); + tty_insert_flip_char(tport, (tmp & 0xFF), flag); tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); } - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(tport); } static void __serial_lpc32xx_tx(struct uart_port *port) @@ -332,7 +322,7 @@ exit_tx: static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = tty_port_tty_get(&port->state->port); + struct tty_port *tport = &port->state->port; u32 status; spin_lock(&port->lock); @@ -356,17 +346,14 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) writel(LPC32XX_HSU_RX_OE_INT, LPC32XX_HSUART_IIR(port->membase)); port->icount.overrun++; - if (tty) { - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - tty_schedule_flip(tty); - } + tty_insert_flip_char(tport, 0, TTY_OVERRUN); + tty_schedule_flip(tport); } /* Data received? */ if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) { __serial_lpc32xx_rx(port); - if (tty) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); } /* Transmit data request? */ @@ -376,7 +363,6 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) } spin_unlock(&port->lock); - tty_kref_put(tty); return IRQ_HANDLED; } @@ -686,7 +672,7 @@ static struct uart_ops serial_lpc32xx_pops = { /* * Register a set of serial devices attached to a platform device */ -static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev) +static int serial_hs_lpc32xx_probe(struct platform_device *pdev) { struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered]; int ret = 0; @@ -740,7 +726,7 @@ static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev) /* * Remove serial ports registered against a platform device. */ -static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev) +static int serial_hs_lpc32xx_remove(struct platform_device *pdev) { struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); @@ -783,7 +769,7 @@ MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids); static struct platform_driver serial_hs_lpc32xx_driver = { .probe = serial_hs_lpc32xx_probe, - .remove = __devexit_p(serial_hs_lpc32xx_remove), + .remove = serial_hs_lpc32xx_remove, .suspend = serial_hs_lpc32xx_suspend, .resume = serial_hs_lpc32xx_resume, .driver = { diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index b13949ad3408..bb1afa0922e1 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -300,7 +300,7 @@ static void m32r_sio_enable_ms(struct uart_port *port) static void receive_chars(struct uart_sio_port *up, int *status) { - struct tty_struct *tty = up->port.state->port.tty; + struct tty_port *port = &up->port.state->port; unsigned char ch; unsigned char flag; int max_count = 256; @@ -355,7 +355,7 @@ static void receive_chars(struct uart_sio_port *up, int *status) if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; if ((*status & up->port.ignore_status_mask) == 0) - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(port, ch, flag); if (*status & UART_LSR_OE) { /* @@ -363,12 +363,12 @@ static void receive_chars(struct uart_sio_port *up, int *status) * immediately, and doesn't affect the current * character. */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(port, 0, TTY_OVERRUN); } ignore_char: *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port); } static void transmit_chars(struct uart_sio_port *up) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 0f24486be532..32517d4bceab 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -179,8 +179,7 @@ static void max3100_work(struct work_struct *w); static void max3100_dowork(struct max3100_port *s) { - if (!s->force_end_work && !work_pending(&s->work) && - !freezing(current) && !s->suspending) + if (!s->force_end_work && !freezing(current) && !s->suspending) queue_work(s->workqueue, &s->work); } @@ -311,8 +310,8 @@ static void max3100_work(struct work_struct *w) } } - if (rxchars > 16 && s->port.state->port.tty != NULL) { - tty_flip_buffer_push(s->port.state->port.tty); + if (rxchars > 16) { + tty_flip_buffer_push(&s->port.state->port); rxchars = 0; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -324,8 +323,8 @@ static void max3100_work(struct work_struct *w) (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)))); - if (rxchars > 0 && s->port.state->port.tty != NULL) - tty_flip_buffer_push(s->port.state->port.tty); + if (rxchars > 0) + tty_flip_buffer_push(&s->port.state->port); } static irqreturn_t max3100_irq(int irqno, void *dev_id) @@ -530,7 +529,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, MAX3100_STATUS_OE; /* we are sending char from a workqueue so enable */ - s->port.state->port.tty->low_latency = 1; + s->port.state->port.low_latency = 1; if (s->poll_time > 0) del_timer_sync(&s->timer); @@ -742,7 +741,7 @@ static struct uart_driver max3100_uart_driver = { }; static int uart_driver_registered; -static int __devinit max3100_probe(struct spi_device *spi) +static int max3100_probe(struct spi_device *spi) { int i, retval; struct plat_max3100 *pdata; @@ -818,7 +817,7 @@ static int __devinit max3100_probe(struct spi_device *spi) return 0; } -static int __devexit max3100_remove(struct spi_device *spi) +static int max3100_remove(struct spi_device *spi) { struct max3100_port *s = dev_get_drvdata(&spi->dev); int i; @@ -907,7 +906,7 @@ static struct spi_driver max3100_driver = { }, .probe = max3100_probe, - .remove = __devexit_p(max3100_remove), + .remove = max3100_remove, .suspend = max3100_suspend, .resume = max3100_resume, }; diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 2bc28a59d385..0c2422cb04ea 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -378,7 +378,7 @@ static void max310x_wait_pll(struct max310x_port *s) } } -static int __devinit max310x_update_best_err(unsigned long f, long *besterr) +static int max310x_update_best_err(unsigned long f, long *besterr) { /* Use baudrate 115200 for calculate error */ long err = f % (115200 * 16); @@ -391,7 +391,7 @@ static int __devinit max310x_update_best_err(unsigned long f, long *besterr) return 1; } -static int __devinit max310x_set_ref_clk(struct max310x_port *s) +static int max310x_set_ref_clk(struct max310x_port *s) { unsigned int div, clksrc, pllcfg = 0; long besterr = -1; @@ -460,10 +460,6 @@ static int __devinit max310x_set_ref_clk(struct max310x_port *s) static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen) { unsigned int sts = 0, ch = 0, flag; - struct tty_struct *tty = tty_port_tty_get(&s->port.state->port); - - if (!tty) - return; if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) { dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen); @@ -516,9 +512,7 @@ static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen) ch, flag); } - tty_flip_buffer_push(tty); - - tty_kref_put(tty); + tty_flip_buffer_push(&s->port.state->port); } static void max310x_handle_tx(struct max310x_port *s) @@ -995,7 +989,7 @@ static struct max310x_pdata generic_plat_data = { .frequency = 26000000, }; -static int __devinit max310x_probe(struct spi_device *spi) +static int max310x_probe(struct spi_device *spi) { struct max310x_port *s; struct device *dev = &spi->dev; @@ -1178,6 +1172,7 @@ static int __devinit max310x_probe(struct spi_device *spi) s->gpio.set = max310x_gpio_set; s->gpio.base = pdata->gpio_base; s->gpio.ngpio = s->nr_gpio; + s->gpio.can_sleep = 1; if (gpiochip_add(&s->gpio)) { /* Indicate that we should not call gpiochip_remove */ s->gpio.base = 0; @@ -1202,7 +1197,7 @@ err_out: return ret; } -static int __devexit max310x_remove(struct spi_device *spi) +static int max310x_remove(struct spi_device *spi) { struct device *dev = &spi->dev; struct max310x_port *s = dev_get_drvdata(dev); @@ -1239,6 +1234,7 @@ static int __devexit max310x_remove(struct spi_device *spi) static const struct spi_device_id max310x_id_table[] = { { "max3107", MAX310X_TYPE_MAX3107 }, { "max3108", MAX310X_TYPE_MAX3108 }, + { } }; MODULE_DEVICE_TABLE(spi, max310x_id_table); @@ -1248,7 +1244,7 @@ static struct spi_driver max310x_driver = { .owner = THIS_MODULE, }, .probe = max310x_probe, - .remove = __devexit_p(max310x_remove), + .remove = max310x_remove, .suspend = max310x_suspend, .resume = max310x_resume, .id_table = max310x_id_table, diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 9afca093d6ec..e956377a38fe 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -23,6 +23,7 @@ #include <linux/serial.h> #include <linux/serial_core.h> #include <linux/io.h> +#include <linux/uaccess.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> @@ -55,6 +56,7 @@ struct mcf_uart { struct uart_port port; unsigned int sigs; /* Local copy of line sigs */ unsigned char imr; /* Local IMR mirror */ + struct serial_rs485 rs485; /* RS485 settings */ }; /****************************************************************************/ @@ -101,6 +103,12 @@ static void mcf_start_tx(struct uart_port *port) { struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + if (pp->rs485.flags & SER_RS485_ENABLED) { + /* Enable Transmitter */ + writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR); + /* Manually assert RTS */ + writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1); + } pp->imr |= MCFUART_UIR_TXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); } @@ -196,6 +204,7 @@ static void mcf_shutdown(struct uart_port *port) static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; unsigned int baud, baudclk; #if defined(CONFIG_M5272) @@ -248,6 +257,11 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, mr2 |= MCFUART_MR2_TXCTS; } + if (pp->rs485.flags & SER_RS485_ENABLED) { + dev_dbg(port->dev, "Setting UART to RS485\n"); + mr2 |= MCFUART_MR2_TXRTS; + } + spin_lock_irqsave(&port->lock, flags); uart_update_timeout(port, termios->c_cflag, baud); writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); @@ -310,7 +324,7 @@ static void mcf_rx_chars(struct mcf_uart *pp) uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); } - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(&port->state->port); } /****************************************************************************/ @@ -342,6 +356,10 @@ static void mcf_tx_chars(struct mcf_uart *pp) if (xmit->head == xmit->tail) { pp->imr &= ~MCFUART_UIR_TXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); + /* Disable TX to negate RTS automatically */ + if (pp->rs485.flags & SER_RS485_ENABLED) + writeb(MCFUART_UCR_TXDISABLE, + port->membase + MCFUART_UCR); } } @@ -418,6 +436,58 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) /****************************************************************************/ +/* Enable or disable the RS485 support */ +static void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) +{ + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + unsigned char mr1, mr2; + + spin_lock_irqsave(&port->lock, flags); + /* Get mode registers */ + mr1 = readb(port->membase + MCFUART_UMR); + mr2 = readb(port->membase + MCFUART_UMR); + if (rs485->flags & SER_RS485_ENABLED) { + dev_dbg(port->dev, "Setting UART to RS485\n"); + /* Automatically negate RTS after TX completes */ + mr2 |= MCFUART_MR2_TXRTS; + } else { + dev_dbg(port->dev, "Setting UART to RS232\n"); + mr2 &= ~MCFUART_MR2_TXRTS; + } + writeb(mr1, port->membase + MCFUART_UMR); + writeb(mr2, port->membase + MCFUART_UMR); + pp->rs485 = *rs485; + spin_unlock_irqrestore(&port->lock, flags); +} + +static int mcf_ioctl(struct uart_port *port, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case TIOCSRS485: { + struct serial_rs485 rs485; + if (copy_from_user(&rs485, (struct serial_rs485 *)arg, + sizeof(struct serial_rs485))) + return -EFAULT; + mcf_config_rs485(port, &rs485); + break; + } + case TIOCGRS485: { + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + if (copy_to_user((struct serial_rs485 *)arg, &pp->rs485, + sizeof(struct serial_rs485))) + return -EFAULT; + break; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/****************************************************************************/ + /* * Define the basic serial functions we support. */ @@ -438,6 +508,7 @@ static const struct uart_ops mcf_uart_ops = { .release_port = mcf_release_port, .config_port = mcf_config_port, .verify_port = mcf_verify_port, + .ioctl = mcf_ioctl, }; static struct mcf_uart mcf_ports[4]; @@ -571,7 +642,7 @@ static struct uart_driver mcf_driver = { /****************************************************************************/ -static int __devinit mcf_probe(struct platform_device *pdev) +static int mcf_probe(struct platform_device *pdev) { struct mcf_platform_uart *platp = pdev->dev.platform_data; struct uart_port *port; @@ -599,7 +670,7 @@ static int __devinit mcf_probe(struct platform_device *pdev) /****************************************************************************/ -static int __devexit mcf_remove(struct platform_device *pdev) +static int mcf_remove(struct platform_device *pdev) { struct uart_port *port; int i; @@ -617,7 +688,7 @@ static int __devexit mcf_remove(struct platform_device *pdev) static struct platform_driver mcf_platform_driver = { .probe = mcf_probe, - .remove = __devexit_p(mcf_remove), + .remove = mcf_remove, .driver = { .name = "mcfuart", .owner = THIS_MODULE, diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index c4b50af46c44..5f4765a7a5c5 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -36,6 +36,7 @@ #include <linux/serial_mfd.h> #include <linux/dma-mapping.h> #include <linux/pci.h> +#include <linux/nmi.h> #include <linux/io.h> #include <linux/debugfs.h> #include <linux/pm_runtime.h> @@ -386,12 +387,9 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) struct hsu_dma_buffer *dbuf = &up->rxbuf; struct hsu_dma_chan *chan = up->rxc; struct uart_port *port = &up->port; - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; int count; - if (!tty) - return; - /* * First need to know how many is already transferred, * then check if its a timeout DMA irq, and return @@ -422,7 +420,7 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) * explicitly set tail to 0. So head will * always be greater than tail. */ - tty_insert_flip_string(tty, dbuf->buf, count); + tty_insert_flip_string(tport, dbuf->buf, count); port->icount.rx += count; dma_sync_single_for_device(up->port.dev, dbuf->dma_addr, @@ -436,7 +434,7 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) | (0x1 << 16) | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ ); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); chan_writel(chan, HSU_CH_CR, 0x3); @@ -459,13 +457,9 @@ static void serial_hsu_stop_rx(struct uart_port *port) static inline void receive_chars(struct uart_hsu_port *up, int *status) { - struct tty_struct *tty = up->port.state->port.tty; unsigned int ch, flag; unsigned int max_count = 256; - if (!tty) - return; - do { ch = serial_in(up, UART_RX); flag = TTY_NORMAL; @@ -521,7 +515,7 @@ static inline void receive_chars(struct uart_hsu_port *up, int *status) ignore_char: *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && max_count--); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&up->port.state->port); } static void transmit_chars(struct uart_hsu_port *up) @@ -1113,6 +1107,8 @@ serial_hsu_console_write(struct console *co, const char *s, unsigned int count) unsigned int ier; int locked = 1; + touch_nmi_watchdog(); + local_irq_save(flags); if (up->port.sysrq) locked = 0; @@ -1456,7 +1452,7 @@ static void serial_hsu_remove(struct pci_dev *pdev) } /* First 3 are UART ports, and the 4th is the DMA */ -static const struct pci_device_id pci_ids[] __devinitconst = { +static const struct pci_device_id pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, @@ -1468,7 +1464,7 @@ static struct pci_driver hsu_pci_driver = { .name = "HSU serial", .id_table = pci_ids, .probe = serial_hsu_probe, - .remove = __devexit_p(serial_hsu_remove), + .remove = serial_hsu_remove, .suspend = serial_hsu_suspend, .resume = serial_hsu_resume, .driver = { diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 8cf577008ad7..018bad922554 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -550,7 +550,7 @@ static int mpc512x_psc_clock(struct uart_port *port, int enable) return 0; psc_num = (port->mapbase & 0xf00) >> 8; - snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num); + snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num); psc_clk = clk_get(port->dev, clk_name); if (IS_ERR(psc_clk)) { dev_err(port->dev, "Failed to get PSC clock entry!\n"); @@ -941,7 +941,7 @@ static struct uart_ops mpc52xx_uart_ops = { static inline int mpc52xx_uart_int_rx_chars(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; unsigned char ch, flag; unsigned short status; @@ -986,20 +986,20 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT); } - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(tport, ch, flag); if (status & MPC52xx_PSC_SR_OE) { /* * Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); port->icount.overrun++; } } spin_unlock(&port->lock); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); spin_lock(&port->lock); return psc_ops->raw_rx_rdy(port); @@ -1308,7 +1308,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = { {}, }; -static int __devinit mpc52xx_uart_of_probe(struct platform_device *op) +static int mpc52xx_uart_of_probe(struct platform_device *op) { int idx = -1; unsigned int uartclk; diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index 6a9c6605666a..bc24f4931670 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -937,7 +937,7 @@ static int serial_polled; static int mpsc_rx_intr(struct mpsc_port_info *pi) { struct mpsc_rx_desc *rxre; - struct tty_struct *tty = pi->port.state->port.tty; + struct tty_port *port = &pi->port.state->port; u32 cmdstat, bytes_in, i; int rc = 0; u8 *bp; @@ -968,10 +968,9 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi) } #endif /* Following use of tty struct directly is deprecated */ - if (unlikely(tty_buffer_request_room(tty, bytes_in) - < bytes_in)) { - if (tty->low_latency) - tty_flip_buffer_push(tty); + if (tty_buffer_request_room(port, bytes_in) < bytes_in) { + if (port->low_latency) + tty_flip_buffer_push(port); /* * If this failed then we will throw away the bytes * but must do so to clear interrupts. @@ -1040,10 +1039,10 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi) | SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) && !(cmdstat & pi->port.ignore_status_mask)) { - tty_insert_flip_char(tty, *bp, flag); + tty_insert_flip_char(port, *bp, flag); } else { for (i=0; i<bytes_in; i++) - tty_insert_flip_char(tty, *bp++, TTY_NORMAL); + tty_insert_flip_char(port, *bp++, TTY_NORMAL); pi->port.icount.rx += bytes_in; } @@ -1081,7 +1080,7 @@ next_frame: if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0) mpsc_start_rx(pi); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port); return rc; } diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index df2a2240a3ae..f641c232beca 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -339,7 +339,7 @@ static int receive_chars(struct uart_max3110 *max, unsigned short *str, int len) { struct uart_port *port = &max->port; - struct tty_struct *tty; + struct tty_port *tport; char buf[M3110_RX_FIFO_DEPTH]; int r, w, usable; @@ -347,9 +347,7 @@ receive_chars(struct uart_max3110 *max, unsigned short *str, int len) if (!port->state) return 0; - tty = tty_port_tty_get(&port->state->port); - if (!tty) - return 0; + tport = &port->state->port; for (r = 0, w = 0; r < len; r++) { if (str[r] & MAX3110_BREAK && @@ -364,20 +362,17 @@ receive_chars(struct uart_max3110 *max, unsigned short *str, int len) } } - if (!w) { - tty_kref_put(tty); + if (!w) return 0; - } for (r = 0; w; r += usable, w -= usable) { - usable = tty_buffer_request_room(tty, w); + usable = tty_buffer_request_room(tport, w); if (usable) { - tty_insert_flip_string(tty, buf + r, usable); + tty_insert_flip_string(tport, buf + r, usable); port->icount.rx += usable; } } - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(tport); return r; } @@ -493,7 +488,7 @@ static int serial_m3110_startup(struct uart_port *port) | WC_BAUD_DR2; /* as we use thread to handle tx/rx, need set low latency */ - port->state->port.tty->low_latency = 1; + port->state->port.low_latency = 1; if (max->irq) { max->read_thread = NULL; @@ -773,7 +768,7 @@ static int serial_m3110_resume(struct spi_device *spi) #define serial_m3110_resume NULL #endif -static int __devinit serial_m3110_probe(struct spi_device *spi) +static int serial_m3110_probe(struct spi_device *spi) { struct uart_max3110 *max; void *buffer; @@ -855,7 +850,7 @@ err_get_page: return ret; } -static int __devexit serial_m3110_remove(struct spi_device *dev) +static int serial_m3110_remove(struct spi_device *dev) { struct uart_max3110 *max = spi_get_drvdata(dev); @@ -879,7 +874,7 @@ static struct spi_driver uart_max3110_driver = { .owner = THIS_MODULE, }, .probe = serial_m3110_probe, - .remove = __devexit_p(serial_m3110_remove), + .remove = serial_m3110_remove, .suspend = serial_m3110_suspend, .resume = serial_m3110_resume, }; diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 033e0bc9ebab..b11e99797fd8 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -91,14 +91,14 @@ static void msm_enable_ms(struct uart_port *port) static void handle_rx_dm(struct uart_port *port, unsigned int misr) { - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; unsigned int sr; int count = 0; struct msm_port *msm_port = UART_TO_MSM(port); if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); } @@ -132,12 +132,12 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr) port->icount.frame++; /* TODO: handle sysrq */ - tty_insert_flip_string(tty, (char *) &c, + tty_insert_flip_string(tport, (char *)&c, (count > 4) ? 4 : count); count -= 4; } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); if (misr & (UART_IMR_RXSTALE)) msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); @@ -146,7 +146,7 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr) static void handle_rx(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; unsigned int sr; /* @@ -155,7 +155,7 @@ static void handle_rx(struct uart_port *port) */ if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); } @@ -186,10 +186,10 @@ static void handle_rx(struct uart_port *port) } if (!uart_handle_sysrq_char(port, c)) - tty_insert_flip_char(tty, c, flag); + tty_insert_flip_char(tport, c, flag); } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); } static void reset_dm_count(struct uart_port *port) @@ -917,7 +917,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) return uart_add_one_port(&msm_uart_driver, port); } -static int __devexit msm_serial_remove(struct platform_device *pdev) +static int msm_serial_remove(struct platform_device *pdev) { struct msm_port *msm_port = platform_get_drvdata(pdev); diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index fca13dc73e23..4a942c78347e 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -401,7 +401,7 @@ static int msm_hs_request_port(struct uart_port *port) return 0; } -static int __devexit msm_hs_remove(struct platform_device *pdev) +static int msm_hs_remove(struct platform_device *pdev) { struct msm_hs_port *msm_uport; @@ -908,6 +908,7 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, unsigned long flags; unsigned int flush; struct tty_struct *tty; + struct tty_port *port; struct uart_port *uport; struct msm_hs_port *msm_uport; @@ -917,7 +918,8 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, spin_lock_irqsave(&uport->lock, flags); clk_enable(msm_uport->clk); - tty = uport->state->port.tty; + port = &uport->state->port; + tty = port->tty; msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); @@ -926,7 +928,7 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, /* overflow is not connect to data in a FIFO */ if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) && (uport->read_status_mask & CREAD))) { - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(port, 0, TTY_OVERRUN); uport->icount.buf_overrun++; error_f = 1; } @@ -939,7 +941,7 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, uport->icount.parity++; error_f = 1; if (uport->ignore_status_mask & IGNPAR) - tty_insert_flip_char(tty, 0, TTY_PARITY); + tty_insert_flip_char(port, 0, TTY_PARITY); } if (error_f) @@ -959,7 +961,7 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR); if (0 != (uport->read_status_mask & CREAD)) { - retval = tty_insert_flip_string(tty, msm_uport->rx.buffer, + retval = tty_insert_flip_string(port, msm_uport->rx.buffer, rx_count); BUG_ON(retval != rx_count); } @@ -979,9 +981,8 @@ static void msm_hs_tty_flip_buffer_work(struct work_struct *work) { struct msm_hs_port *msm_uport = container_of(work, struct msm_hs_port, rx.tty_work); - struct tty_struct *tty = msm_uport->uport.state->port.tty; - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&msm_uport->uport.state->port); } /* @@ -1344,7 +1345,6 @@ static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev) unsigned long flags; struct msm_hs_port *msm_uport = dev; struct uart_port *uport = &msm_uport->uport; - struct tty_struct *tty = NULL; spin_lock_irqsave(&uport->lock, flags); if (msm_uport->clk_state == MSM_HS_CLK_OFF) { @@ -1361,8 +1361,7 @@ static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev) * optionally inject char into tty rx */ msm_hs_request_clock_on_locked(uport); if (msm_uport->rx_wakeup.inject_rx) { - tty = uport->state->port.tty; - tty_insert_flip_char(tty, + tty_insert_flip_char(&uport->state->port, msm_uport->rx_wakeup.rx_to_inject, TTY_NORMAL); queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); @@ -1400,7 +1399,7 @@ static int msm_hs_startup(struct uart_port *uport) /* do not let tty layer execute RX in global workqueue, use a * dedicated workqueue managed by this driver */ - uport->state->port.tty->low_latency = 1; + uport->state->port.low_latency = 1; /* turn on uart clk */ ret = msm_hs_init_clk_locked(uport); @@ -1521,7 +1520,7 @@ err_msm_hs_init_clk: } /* Initialize tx and rx data structures */ -static int __devinit uartdm_init_port(struct uart_port *uport) +static int uartdm_init_port(struct uart_port *uport) { int ret = 0; struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); @@ -1614,7 +1613,7 @@ err_tx_command_ptr_ptr: return ret; } -static int __devinit msm_hs_probe(struct platform_device *pdev) +static int msm_hs_probe(struct platform_device *pdev) { int ret; struct uart_port *uport; @@ -1838,7 +1837,7 @@ static const struct dev_pm_ops msm_hs_dev_pm_ops = { static struct platform_driver msm_serial_hs_platform_driver = { .probe = msm_hs_probe, - .remove = __devexit_p(msm_hs_remove), + .remove = msm_hs_remove, .driver = { .name = "msm_serial_hs", .owner = THIS_MODULE, diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c index 925d1fa153db..e722ff163d91 100644 --- a/drivers/tty/serial/msm_smd_tty.c +++ b/drivers/tty/serial/msm_smd_tty.c @@ -70,7 +70,7 @@ static void smd_tty_notify(void *priv, unsigned event) if (avail == 0) break; - avail = tty_prepare_flip_string(tty, &ptr, avail); + avail = tty_prepare_flip_string(&info->port, &ptr, avail); if (smd_read(info->ch, ptr, avail) != avail) { /* shouldn't be possible since we're in interrupt @@ -80,7 +80,7 @@ static void smd_tty_notify(void *priv, unsigned event) pr_err("OOPS - smd_tty_buffer mismatch?!"); } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&info->port); } /* XXX only when writable and necessary */ diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 7ea8a263fd9e..7fd6aaaacd8e 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -242,8 +242,8 @@ static void mux_write(struct uart_port *port) */ static void mux_read(struct uart_port *port) { + struct tty_port *tport = &port->state->port; int data; - struct tty_struct *tty = port->state->port.tty; __u32 start_count = port->icount.rx; while(1) { @@ -266,12 +266,11 @@ static void mux_read(struct uart_port *port) if (uart_handle_sysrq_char(port, data & 0xffu)) continue; - tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL); + tty_insert_flip_char(tport, data & 0xFF, TTY_NORMAL); } - if (start_count != port->icount.rx) { - tty_flip_buffer_push(tty); - } + if (start_count != port->icount.rx) + tty_flip_buffer_push(tport); } /** @@ -520,7 +519,7 @@ static int __init mux_probe(struct parisc_device *dev) return 0; } -static int __devexit mux_remove(struct parisc_device *dev) +static int mux_remove(struct parisc_device *dev) { int i, j; int port_count = (long)dev_get_drvdata(&dev->dev); @@ -571,14 +570,14 @@ static struct parisc_driver builtin_serial_mux_driver = { .name = "builtin_serial_mux", .id_table = builtin_mux_tbl, .probe = mux_probe, - .remove = __devexit_p(mux_remove), + .remove = mux_remove, }; static struct parisc_driver serial_mux_driver = { .name = "serial_mux", .id_table = mux_tbl, .probe = mux_probe, - .remove = __devexit_p(mux_remove), + .remove = mux_remove, }; /** diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 6db3baa39a97..d549fe1fa42a 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -34,6 +34,8 @@ #include <linux/io.h> #include <linux/pinctrl/consumer.h> #include <linux/of_device.h> +#include <linux/dma-mapping.h> +#include <linux/fsl/mxs-dma.h> #include <asm/cacheflush.h> @@ -71,6 +73,15 @@ #define AUART_CTRL0_SFTRST (1 << 31) #define AUART_CTRL0_CLKGATE (1 << 30) +#define AUART_CTRL0_RXTO_ENABLE (1 << 27) +#define AUART_CTRL0_RXTIMEOUT(v) (((v) & 0x7ff) << 16) +#define AUART_CTRL0_XFER_COUNT(v) ((v) & 0xffff) + +#define AUART_CTRL1_XFER_COUNT(v) ((v) & 0xffff) + +#define AUART_CTRL2_DMAONERR (1 << 26) +#define AUART_CTRL2_TXDMAE (1 << 25) +#define AUART_CTRL2_RXDMAE (1 << 24) #define AUART_CTRL2_CTSEN (1 << 15) #define AUART_CTRL2_RTSEN (1 << 14) @@ -111,29 +122,170 @@ #define AUART_STAT_BERR (1 << 18) #define AUART_STAT_PERR (1 << 17) #define AUART_STAT_FERR (1 << 16) +#define AUART_STAT_RXCOUNT_MASK 0xffff static struct uart_driver auart_driver; +enum mxs_auart_type { + IMX23_AUART, + IMX28_AUART, +}; + struct mxs_auart_port { struct uart_port port; - unsigned int flags; +#define MXS_AUART_DMA_CONFIG 0x1 +#define MXS_AUART_DMA_ENABLED 0x2 +#define MXS_AUART_DMA_TX_SYNC 2 /* bit 2 */ +#define MXS_AUART_DMA_RX_READY 3 /* bit 3 */ + unsigned long flags; unsigned int ctrl; + enum mxs_auart_type devtype; unsigned int irq; struct clk *clk; struct device *dev; + + /* for DMA */ + struct mxs_dma_data dma_data; + int dma_channel_rx, dma_channel_tx; + int dma_irq_rx, dma_irq_tx; + int dma_channel; + + struct scatterlist tx_sgl; + struct dma_chan *tx_dma_chan; + void *tx_dma_buf; + + struct scatterlist rx_sgl; + struct dma_chan *rx_dma_chan; + void *rx_dma_buf; }; +static struct platform_device_id mxs_auart_devtype[] = { + { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART }, + { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, mxs_auart_devtype); + +static struct of_device_id mxs_auart_dt_ids[] = { + { + .compatible = "fsl,imx28-auart", + .data = &mxs_auart_devtype[IMX28_AUART] + }, { + .compatible = "fsl,imx23-auart", + .data = &mxs_auart_devtype[IMX23_AUART] + }, { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids); + +static inline int is_imx28_auart(struct mxs_auart_port *s) +{ + return s->devtype == IMX28_AUART; +} + +static inline bool auart_dma_enabled(struct mxs_auart_port *s) +{ + return s->flags & MXS_AUART_DMA_ENABLED; +} + static void mxs_auart_stop_tx(struct uart_port *u); #define to_auart_port(u) container_of(u, struct mxs_auart_port, port) -static inline void mxs_auart_tx_chars(struct mxs_auart_port *s) +static void mxs_auart_tx_chars(struct mxs_auart_port *s); + +static void dma_tx_callback(void *param) +{ + struct mxs_auart_port *s = param; + struct circ_buf *xmit = &s->port.state->xmit; + + dma_unmap_sg(s->dev, &s->tx_sgl, 1, DMA_TO_DEVICE); + + /* clear the bit used to serialize the DMA tx. */ + clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); + smp_mb__after_clear_bit(); + + /* wake up the possible processes. */ + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&s->port); + + mxs_auart_tx_chars(s); +} + +static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size) +{ + struct dma_async_tx_descriptor *desc; + struct scatterlist *sgl = &s->tx_sgl; + struct dma_chan *channel = s->tx_dma_chan; + u32 pio; + + /* [1] : send PIO. Note, the first pio word is CTRL1. */ + pio = AUART_CTRL1_XFER_COUNT(size); + desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)&pio, + 1, DMA_TRANS_NONE, 0); + if (!desc) { + dev_err(s->dev, "step 1 error\n"); + return -EINVAL; + } + + /* [2] : set DMA buffer. */ + sg_init_one(sgl, s->tx_dma_buf, size); + dma_map_sg(s->dev, sgl, 1, DMA_TO_DEVICE); + desc = dmaengine_prep_slave_sg(channel, sgl, + 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(s->dev, "step 2 error\n"); + return -EINVAL; + } + + /* [3] : submit the DMA */ + desc->callback = dma_tx_callback; + desc->callback_param = s; + dmaengine_submit(desc); + dma_async_issue_pending(channel); + return 0; +} + +static void mxs_auart_tx_chars(struct mxs_auart_port *s) { struct circ_buf *xmit = &s->port.state->xmit; + if (auart_dma_enabled(s)) { + u32 i = 0; + int size; + void *buffer = s->tx_dma_buf; + + if (test_and_set_bit(MXS_AUART_DMA_TX_SYNC, &s->flags)) + return; + + while (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) { + size = min_t(u32, UART_XMIT_SIZE - i, + CIRC_CNT_TO_END(xmit->head, + xmit->tail, + UART_XMIT_SIZE)); + memcpy(buffer + i, xmit->buf + xmit->tail, size); + xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1); + + i += size; + if (i >= UART_XMIT_SIZE) + break; + } + + if (uart_tx_stopped(&s->port)) + mxs_auart_stop_tx(&s->port); + + if (i) { + mxs_auart_dma_tx(s, i); + } else { + clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); + smp_mb__after_clear_bit(); + } + return; + } + + while (!(readl(s->port.membase + AUART_STAT) & AUART_STAT_TXFF)) { if (s->port.x_char) { @@ -212,7 +364,6 @@ out: static void mxs_auart_rx_chars(struct mxs_auart_port *s) { - struct tty_struct *tty = s->port.state->port.tty; u32 stat = 0; for (;;) { @@ -223,7 +374,7 @@ static void mxs_auart_rx_chars(struct mxs_auart_port *s) } writel(stat, s->port.membase + AUART_STAT); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&s->port.state->port); } static int mxs_auart_request_port(struct uart_port *u) @@ -260,10 +411,12 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) u32 ctrl = readl(u->membase + AUART_CTRL2); - ctrl &= ~AUART_CTRL2_RTSEN; + ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS); if (mctrl & TIOCM_RTS) { if (tty_port_cts_enabled(&u->state->port)) ctrl |= AUART_CTRL2_RTSEN; + else + ctrl |= AUART_CTRL2_RTS; } s->ctrl = mctrl; @@ -287,10 +440,159 @@ static u32 mxs_auart_get_mctrl(struct uart_port *u) return mctrl; } +static bool mxs_auart_dma_filter(struct dma_chan *chan, void *param) +{ + struct mxs_auart_port *s = param; + + if (!mxs_dma_is_apbx(chan)) + return false; + + if (s->dma_channel == chan->chan_id) { + chan->private = &s->dma_data; + return true; + } + return false; +} + +static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s); +static void dma_rx_callback(void *arg) +{ + struct mxs_auart_port *s = (struct mxs_auart_port *) arg; + struct tty_port *port = &s->port.state->port; + int count; + u32 stat; + + dma_unmap_sg(s->dev, &s->rx_sgl, 1, DMA_FROM_DEVICE); + + stat = readl(s->port.membase + AUART_STAT); + stat &= ~(AUART_STAT_OERR | AUART_STAT_BERR | + AUART_STAT_PERR | AUART_STAT_FERR); + + count = stat & AUART_STAT_RXCOUNT_MASK; + tty_insert_flip_string(port, s->rx_dma_buf, count); + + writel(stat, s->port.membase + AUART_STAT); + tty_flip_buffer_push(port); + + /* start the next DMA for RX. */ + mxs_auart_dma_prep_rx(s); +} + +static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s) +{ + struct dma_async_tx_descriptor *desc; + struct scatterlist *sgl = &s->rx_sgl; + struct dma_chan *channel = s->rx_dma_chan; + u32 pio[1]; + + /* [1] : send PIO */ + pio[0] = AUART_CTRL0_RXTO_ENABLE + | AUART_CTRL0_RXTIMEOUT(0x80) + | AUART_CTRL0_XFER_COUNT(UART_XMIT_SIZE); + desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, + 1, DMA_TRANS_NONE, 0); + if (!desc) { + dev_err(s->dev, "step 1 error\n"); + return -EINVAL; + } + + /* [2] : send DMA request */ + sg_init_one(sgl, s->rx_dma_buf, UART_XMIT_SIZE); + dma_map_sg(s->dev, sgl, 1, DMA_FROM_DEVICE); + desc = dmaengine_prep_slave_sg(channel, sgl, 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(s->dev, "step 2 error\n"); + return -1; + } + + /* [3] : submit the DMA, but do not issue it. */ + desc->callback = dma_rx_callback; + desc->callback_param = s; + dmaengine_submit(desc); + dma_async_issue_pending(channel); + return 0; +} + +static void mxs_auart_dma_exit_channel(struct mxs_auart_port *s) +{ + if (s->tx_dma_chan) { + dma_release_channel(s->tx_dma_chan); + s->tx_dma_chan = NULL; + } + if (s->rx_dma_chan) { + dma_release_channel(s->rx_dma_chan); + s->rx_dma_chan = NULL; + } + + kfree(s->tx_dma_buf); + kfree(s->rx_dma_buf); + s->tx_dma_buf = NULL; + s->rx_dma_buf = NULL; +} + +static void mxs_auart_dma_exit(struct mxs_auart_port *s) +{ + + writel(AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE | AUART_CTRL2_DMAONERR, + s->port.membase + AUART_CTRL2_CLR); + + mxs_auart_dma_exit_channel(s); + s->flags &= ~MXS_AUART_DMA_ENABLED; + clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); + clear_bit(MXS_AUART_DMA_RX_READY, &s->flags); +} + +static int mxs_auart_dma_init(struct mxs_auart_port *s) +{ + dma_cap_mask_t mask; + + if (auart_dma_enabled(s)) + return 0; + + /* We do not get the right DMA channels. */ + if (s->dma_channel_rx == -1 || s->dma_channel_tx == -1) + return -EINVAL; + + /* init for RX */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + s->dma_channel = s->dma_channel_rx; + s->dma_data.chan_irq = s->dma_irq_rx; + s->rx_dma_chan = dma_request_channel(mask, mxs_auart_dma_filter, s); + if (!s->rx_dma_chan) + goto err_out; + s->rx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA); + if (!s->rx_dma_buf) + goto err_out; + + /* init for TX */ + s->dma_channel = s->dma_channel_tx; + s->dma_data.chan_irq = s->dma_irq_tx; + s->tx_dma_chan = dma_request_channel(mask, mxs_auart_dma_filter, s); + if (!s->tx_dma_chan) + goto err_out; + s->tx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA); + if (!s->tx_dma_buf) + goto err_out; + + /* set the flags */ + s->flags |= MXS_AUART_DMA_ENABLED; + dev_dbg(s->dev, "enabled the DMA support."); + + return 0; + +err_out: + mxs_auart_dma_exit_channel(s); + return -EINVAL; + +} + static void mxs_auart_settermios(struct uart_port *u, struct ktermios *termios, struct ktermios *old) { + struct mxs_auart_port *s = to_auart_port(u); u32 bm, ctrl, ctrl2, div; unsigned int cflag, baud; @@ -362,10 +664,23 @@ static void mxs_auart_settermios(struct uart_port *u, ctrl |= AUART_LINECTRL_STP2; /* figure out the hardware flow control settings */ - if (cflag & CRTSCTS) + if (cflag & CRTSCTS) { + /* + * The DMA has a bug(see errata:2836) in mx23. + * So we can not implement the DMA for auart in mx23, + * we can only implement the DMA support for auart + * in mx28. + */ + if (is_imx28_auart(s) && (s->flags & MXS_AUART_DMA_CONFIG)) { + if (!mxs_auart_dma_init(s)) + /* enable DMA tranfer */ + ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE + | AUART_CTRL2_DMAONERR; + } ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN; - else + } else { ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN); + } /* set baud rate */ baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk); @@ -377,6 +692,19 @@ static void mxs_auart_settermios(struct uart_port *u, writel(ctrl2, u->membase + AUART_CTRL2); uart_update_timeout(u, termios->c_cflag, baud); + + /* prepare for the DMA RX. */ + if (auart_dma_enabled(s) && + !test_and_set_bit(MXS_AUART_DMA_RX_READY, &s->flags)) { + if (!mxs_auart_dma_prep_rx(s)) { + /* Disable the normal RX interrupt. */ + writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN, + u->membase + AUART_INTR_CLR); + } else { + mxs_auart_dma_exit(s); + dev_err(s->dev, "We can not start up the DMA.\n"); + } + } } static irqreturn_t mxs_auart_irq_handle(int irq, void *context) @@ -395,7 +723,8 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) } if (istat & (AUART_INTR_RTIS | AUART_INTR_RXIS)) { - mxs_auart_rx_chars(s); + if (!auart_dma_enabled(s)) + mxs_auart_rx_chars(s); istat &= ~(AUART_INTR_RTIS | AUART_INTR_RXIS); } @@ -455,6 +784,9 @@ static void mxs_auart_shutdown(struct uart_port *u) { struct mxs_auart_port *s = to_auart_port(u); + if (auart_dma_enabled(s)) + mxs_auart_dma_exit(s); + writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR); writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, @@ -688,6 +1020,7 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s, struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + u32 dma_channel[2]; int ret; if (!np) @@ -701,11 +1034,27 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s, } s->port.line = ret; + s->dma_irq_rx = platform_get_irq(pdev, 1); + s->dma_irq_tx = platform_get_irq(pdev, 2); + + ret = of_property_read_u32_array(np, "fsl,auart-dma-channel", + dma_channel, 2); + if (ret == 0) { + s->dma_channel_rx = dma_channel[0]; + s->dma_channel_tx = dma_channel[1]; + + s->flags |= MXS_AUART_DMA_CONFIG; + } else { + s->dma_channel_rx = -1; + s->dma_channel_tx = -1; + } return 0; } -static int __devinit mxs_auart_probe(struct platform_device *pdev) +static int mxs_auart_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(mxs_auart_dt_ids, &pdev->dev); struct mxs_auart_port *s; u32 version; int ret = 0; @@ -730,6 +1079,11 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev) goto out_free; } + if (of_id) { + pdev->id_entry = of_id->data; + s->devtype = pdev->id_entry->driver_data; + } + s->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(s->clk)) { ret = PTR_ERR(s->clk); @@ -751,7 +1105,6 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev) s->port.type = PORT_IMX; s->port.dev = s->dev = get_device(&pdev->dev); - s->flags = 0; s->ctrl = 0; s->irq = platform_get_irq(pdev, 0); @@ -789,7 +1142,7 @@ out: return ret; } -static int __devexit mxs_auart_remove(struct platform_device *pdev) +static int mxs_auart_remove(struct platform_device *pdev) { struct mxs_auart_port *s = platform_get_drvdata(pdev); @@ -805,15 +1158,9 @@ static int __devexit mxs_auart_remove(struct platform_device *pdev) return 0; } -static struct of_device_id mxs_auart_dt_ids[] = { - { .compatible = "fsl,imx23-auart", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids); - static struct platform_driver mxs_auart_driver = { .probe = mxs_auart_probe, - .remove = __devexit_p(mxs_auart_remove), + .remove = mxs_auart_remove, .driver = { .name = "mxs-auart", .owner = THIS_MODULE, diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c index d40da78e7c85..b9a40ed70be2 100644 --- a/drivers/tty/serial/netx-serial.c +++ b/drivers/tty/serial/netx-serial.c @@ -199,7 +199,6 @@ static void netx_txint(struct uart_port *port) static void netx_rxint(struct uart_port *port) { unsigned char rx, flg, status; - struct tty_struct *tty = port->state->port.tty; while (!(readl(port->membase + UART_FR) & FR_RXFE)) { rx = readl(port->membase + UART_DR); @@ -237,8 +236,7 @@ static void netx_rxint(struct uart_port *port) uart_insert_char(port, status, SR_OE, rx, flg); } - tty_flip_buffer_push(tty); - return; + tty_flip_buffer_push(&port->state->port); } static irqreturn_t netx_int(int irq, void *dev_id) diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c index dd4c31d1aee5..77287c54f331 100644 --- a/drivers/tty/serial/nwpserial.c +++ b/drivers/tty/serial/nwpserial.c @@ -128,7 +128,7 @@ static void nwpserial_config_port(struct uart_port *port, int flags) static irqreturn_t nwpserial_interrupt(int irq, void *dev_id) { struct nwpserial_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; + struct tty_port *port = &up->port.state->port; irqreturn_t ret; unsigned int iir; unsigned char ch; @@ -146,10 +146,10 @@ static irqreturn_t nwpserial_interrupt(int irq, void *dev_id) up->port.icount.rx++; ch = dcr_read(up->dcr_host, UART_RX); if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID) - tty_insert_flip_char(tty, ch, TTY_NORMAL); + tty_insert_flip_char(port, ch, TTY_NORMAL); } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port); ret = IRQ_HANDLED; /* clear interrupt */ diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index df443b908ca3..b025d5438275 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -18,11 +18,12 @@ #include <linux/serial_reg.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/of_serial.h> #include <linux/of_platform.h> #include <linux/nwpserial.h> +#include <linux/clk.h> struct of_serial_info { + struct clk *clk; int type; int line; }; @@ -43,15 +44,18 @@ void tegra_serial_handle_break(struct uart_port *p) udelay(1); } while (1); } -/* FIXME remove this export when tegra finishes conversion to open firmware */ -EXPORT_SYMBOL_GPL(tegra_serial_handle_break); +#else +static inline void tegra_serial_handle_break(struct uart_port *port) +{ +} #endif /* * Fill a struct uart_port for a given device node */ -static int __devinit of_platform_serial_setup(struct platform_device *ofdev, - int type, struct uart_port *port) +static int of_platform_serial_setup(struct platform_device *ofdev, + int type, struct uart_port *port, + struct of_serial_info *info) { struct resource resource; struct device_node *np = ofdev->dev.of_node; @@ -60,8 +64,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, memset(port, 0, sizeof *port); if (of_property_read_u32(np, "clock-frequency", &clk)) { - dev_warn(&ofdev->dev, "no clock-frequency property set\n"); - return -ENODEV; + + /* Get clk rate through clk driver if present */ + info->clk = clk_get(&ofdev->dev, NULL); + if (IS_ERR(info->clk)) { + dev_warn(&ofdev->dev, + "clk or clock-frequency not defined\n"); + return PTR_ERR(info->clk); + } + + clk_prepare_enable(info->clk); + clk = clk_get_rate(info->clk); } /* If current-speed was set, then try not to change it. */ if (of_property_read_u32(np, "current-speed", &spd) == 0) @@ -70,7 +83,7 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, ret = of_address_to_resource(np, 0, &resource); if (ret) { dev_warn(&ofdev->dev, "invalid address\n"); - return ret; + goto out; } spin_lock_init(&port->lock); @@ -97,7 +110,8 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, default: dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", prop); - return -EINVAL; + ret = -EINVAL; + goto out; } } @@ -115,13 +129,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, port->handle_break = tegra_serial_handle_break; return 0; +out: + if (info->clk) + clk_disable_unprepare(info->clk); + return ret; } /* * Try to register a serial port */ static struct of_device_id of_platform_serial_table[]; -static int __devinit of_platform_serial_probe(struct platform_device *ofdev) +static int of_platform_serial_probe(struct platform_device *ofdev) { const struct of_device_id *match; struct of_serial_info *info; @@ -141,7 +159,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev) return -ENOMEM; port_type = (unsigned long)match->data; - ret = of_platform_serial_setup(ofdev, port_type, &port); + ret = of_platform_serial_setup(ofdev, port_type, &port, info); if (ret) goto out; @@ -204,6 +222,9 @@ static int of_platform_serial_remove(struct platform_device *ofdev) /* need to add code for these */ break; } + + if (info->clk) + clk_disable_unprepare(info->clk); kfree(info); return 0; } @@ -211,7 +232,7 @@ static int of_platform_serial_remove(struct platform_device *ofdev) /* * A few common types, add more as needed. */ -static struct of_device_id __devinitdata of_platform_serial_table[] = { +static struct of_device_id of_platform_serial_table[] = { { .compatible = "ns8250", .data = (void *)PORT_8250, }, { .compatible = "ns16450", .data = (void *)PORT_16450, }, { .compatible = "ns16550a", .data = (void *)PORT_16550A, }, @@ -220,6 +241,12 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = { { .compatible = "ns16850", .data = (void *)PORT_16850, }, { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, + { .compatible = "altr,16550-FIFO32", + .data = (void *)PORT_ALTR_16550_F32, }, + { .compatible = "altr,16550-FIFO64", + .data = (void *)PORT_ALTR_16550_F64, }, + { .compatible = "altr,16550-FIFO128", + .data = (void *)PORT_ALTR_16550_F128, }, #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL { .compatible = "ibm,qpace-nwp-serial", .data = (void *)PORT_NWPSERIAL, }, diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 6d3d26a607b9..4dc41408ecb7 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -41,8 +41,9 @@ #include <linux/of.h> #include <linux/gpio.h> #include <linux/pinctrl/consumer.h> +#include <linux/platform_data/serial-omap.h> -#include <plat/omap-serial.h> +#define OMAP_MAX_HSUART_PORTS 6 #define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) @@ -51,10 +52,15 @@ #define OMAP_UART_REV_52 0x0502 #define OMAP_UART_REV_63 0x0603 +#define UART_ERRATA_i202_MDR1_ACCESS BIT(0) +#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1) + #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/ /* SCR register bitmasks */ #define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7) +#define OMAP_UART_SCR_TX_TRIG_GRANU1_MASK (1 << 6) +#define OMAP_UART_SCR_TX_EMPTY (1 << 3) /* FCR register bitmasks */ #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) @@ -71,6 +77,52 @@ #define OMAP_UART_MVR_MAJ_SHIFT 8 #define OMAP_UART_MVR_MIN_MASK 0x3f +#define OMAP_UART_DMA_CH_FREE -1 + +#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA +#define OMAP_MODE13X_SPEED 230400 + +/* WER = 0x7F + * Enable module level wakeup in WER reg + */ +#define OMAP_UART_WER_MOD_WKUP 0X7F + +/* Enable XON/XOFF flow control on output */ +#define OMAP_UART_SW_TX 0x08 + +/* Enable XON/XOFF flow control on input */ +#define OMAP_UART_SW_RX 0x02 + +#define OMAP_UART_SW_CLR 0xF0 + +#define OMAP_UART_TCR_TRIG 0x0F + +struct uart_omap_dma { + u8 uart_dma_tx; + u8 uart_dma_rx; + int rx_dma_channel; + int tx_dma_channel; + dma_addr_t rx_buf_dma_phys; + dma_addr_t tx_buf_dma_phys; + unsigned int uart_base; + /* + * Buffer for rx dma.It is not required for tx because the buffer + * comes from port structure. + */ + unsigned char *rx_buf; + unsigned int prev_rx_dma_pos; + int tx_buf_size; + int tx_dma_used; + int rx_dma_used; + spinlock_t tx_lock; + spinlock_t rx_lock; + /* timer to poll activity on rx dma */ + struct timer_list rx_timer; + unsigned int rx_buf_size; + unsigned int rx_poll_rate; + unsigned int rx_timeout; +}; + struct uart_omap_port { struct uart_port port; struct uart_omap_dma uart_dma; @@ -96,10 +148,9 @@ struct uart_omap_port { unsigned char msr_saved_flags; char name[20]; unsigned long port_activity; - u32 context_loss_cnt; + int context_loss_cnt; u32 errata; u8 wakeups_enabled; - unsigned int irq_pending:1; int DTR_gpio; int DTR_inverted; @@ -182,24 +233,42 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) } /* + * serial_omap_baud_is_mode16 - check if baud rate is MODE16X + * @port: uart port info + * @baud: baudrate for which mode needs to be determined + * + * Returns true if baud rate is MODE16X and false if MODE13X + * Original table in OMAP TRM named "UART Mode Baud Rates, Divisor Values, + * and Error Rates" determines modes not for all common baud rates. + * E.g. for 1000000 baud rate mode must be 16x, but according to that + * table it's determined as 13x. + */ +static bool +serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud) +{ + unsigned int n13 = port->uartclk / (13 * baud); + unsigned int n16 = port->uartclk / (16 * baud); + int baudAbsDiff13 = baud - (port->uartclk / (13 * n13)); + int baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); + if(baudAbsDiff13 < 0) + baudAbsDiff13 = -baudAbsDiff13; + if(baudAbsDiff16 < 0) + baudAbsDiff16 = -baudAbsDiff16; + + return (baudAbsDiff13 > baudAbsDiff16); +} + +/* * serial_omap_get_divisor - calculate divisor value * @port: uart port info * @baud: baudrate for which divisor needs to be calculated. - * - * We have written our own function to get the divisor so as to support - * 13x mode. 3Mbps Baudrate as an different divisor. - * Reference OMAP TRM Chapter 17: - * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates - * referring to oversampling - divisor value - * baudrate 460,800 to 3,686,400 all have divisor 13 - * except 3,000,000 which has divisor value 16 */ static unsigned int serial_omap_get_divisor(struct uart_port *port, unsigned int baud) { unsigned int divisor; - if (baud > OMAP_MODE13X_SPEED && baud != 3000000) + if (!serial_omap_baud_is_mode16(port, baud)) divisor = 13; else divisor = 16; @@ -252,9 +321,6 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) struct circ_buf *xmit = &up->port.state->xmit; int count; - if (!(lsr & UART_LSR_THRE)) - return; - if (up->port.x_char) { serial_out(up, UART_TX, up->port.x_char); up->port.icount.tx++; @@ -303,6 +369,34 @@ static void serial_omap_start_tx(struct uart_port *port) pm_runtime_put_autosuspend(up->dev); } +static void serial_omap_throttle(struct uart_port *port) +{ + struct uart_omap_port *up = to_uart_omap_port(port); + unsigned long flags; + + pm_runtime_get_sync(up->dev); + spin_lock_irqsave(&up->port.lock, flags); + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&up->port.lock, flags); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); +} + +static void serial_omap_unthrottle(struct uart_port *port) +{ + struct uart_omap_port *up = to_uart_omap_port(port); + unsigned long flags; + + pm_runtime_get_sync(up->dev); + spin_lock_irqsave(&up->port.lock, flags); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&up->port.lock, flags); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); +} + static unsigned int check_modem_status(struct uart_omap_port *up) { unsigned int status; @@ -405,7 +499,6 @@ static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) static irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; unsigned int iir, lsr; unsigned int type; irqreturn_t ret = IRQ_NONE; @@ -452,7 +545,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) spin_unlock(&up->port.lock); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&up->port.state->port); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); @@ -504,7 +597,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned char mcr = 0; + unsigned char mcr = 0, old_mcr; dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line); if (mctrl & TIOCM_RTS) @@ -519,8 +612,10 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) mcr |= UART_MCR_LOOP; pm_runtime_get_sync(up->dev); - up->mcr = serial_in(up, UART_MCR); - up->mcr |= mcr; + old_mcr = serial_in(up, UART_MCR); + old_mcr &= ~(UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_OUT1 | + UART_MCR_DTR | UART_MCR_RTS); + up->mcr = old_mcr | mcr; serial_out(up, UART_MCR, up->mcr); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); @@ -654,65 +749,6 @@ static void serial_omap_shutdown(struct uart_port *port) free_irq(up->port.irq, up); } -static inline void -serial_omap_configure_xonxoff - (struct uart_omap_port *up, struct ktermios *termios) -{ - up->lcr = serial_in(up, UART_LCR); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - up->efr = serial_in(up, UART_EFR); - serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB); - - serial_out(up, UART_XON1, termios->c_cc[VSTART]); - serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]); - - /* clear SW control mode bits */ - up->efr &= OMAP_UART_SW_CLR; - - /* - * IXON Flag: - * Enable XON/XOFF flow control on output. - * Transmit XON1, XOFF1 - */ - if (termios->c_iflag & IXON) - up->efr |= OMAP_UART_SW_TX; - - /* - * IXOFF Flag: - * Enable XON/XOFF flow control on input. - * Receiver compares XON1, XOFF1. - */ - if (termios->c_iflag & IXOFF) - up->efr |= OMAP_UART_SW_RX; - - serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - - up->mcr = serial_in(up, UART_MCR); - - /* - * IXANY Flag: - * Enable any character to restart output. - * Operation resumes after receiving any - * character after recognition of the XOFF character - */ - if (termios->c_iflag & IXANY) - up->mcr |= UART_MCR_XONANY; - - serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); - /* Enable special char function UARTi.EFR_REG[5] and - * load the new software flow control mode IXON or IXOFF - * and restore the UARTi.EFR_REG[4] ENHANCED_EN value. - */ - serial_out(up, UART_EFR, up->efr | UART_EFR_SCD); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - - serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR); - serial_out(up, UART_LCR, up->lcr); -} - static void serial_omap_uart_qos_work(struct work_struct *work) { struct uart_omap_port *up = container_of(work, struct uart_omap_port, @@ -730,7 +766,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, { struct uart_omap_port *up = to_uart_omap_port(port); unsigned char cval = 0; - unsigned char efr = 0; unsigned long flags = 0; unsigned int baud, quot; @@ -756,6 +791,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, cval |= UART_LCR_PARITY; if (!(termios->c_cflag & PARODD)) cval |= UART_LCR_EPAR; + if (termios->c_cflag & CMSPAR) + cval |= UART_LCR_SPAR; /* * Ask the core to calculate the divisor for us. @@ -825,7 +862,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_IER, up->ier); serial_out(up, UART_LCR, cval); /* reset DLAB */ up->lcr = cval; - up->scr = OMAP_UART_SCR_TX_EMPTY; + up->scr = 0; /* FIFOs and DMA Settings */ @@ -840,16 +877,15 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - up->efr = serial_in(up, UART_EFR); + up->efr = serial_in(up, UART_EFR) & ~UART_EFR_ECB; + up->efr &= ~UART_EFR_SCD; serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - up->mcr = serial_in(up, UART_MCR); + up->mcr = serial_in(up, UART_MCR) & ~UART_MCR_TCRTLR; serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); /* FIFO ENABLE, DMA MODE */ - up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; - /* Set receive FIFO threshold to 16 characters and * transmit FIFO threshold to 16 spaces */ @@ -863,9 +899,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_OMAP_SCR, up->scr); - serial_out(up, UART_EFR, up->efr); + /* Reset UART_MCR_TCRTLR: this must be done with the EFR_ECB bit set */ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_out(up, UART_MCR, up->mcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, up->efr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); /* Protocol, Baud Rate, and Interrupt Settings */ @@ -875,8 +914,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_OMAP_MDR1, up->mdr1); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - up->efr = serial_in(up, UART_EFR); serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); serial_out(up, UART_LCR, 0); @@ -893,7 +930,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_EFR, up->efr); serial_out(up, UART_LCR, cval); - if (baud > 230400 && baud != 3000000) + if (!serial_omap_baud_is_mode16(port, baud)) up->mdr1 = UART_OMAP_MDR1_13X_MODE; else up->mdr1 = UART_OMAP_MDR1_16X_MODE; @@ -903,29 +940,68 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, else serial_out(up, UART_OMAP_MDR1, up->mdr1); - /* Hardware Flow Control Configuration */ + /* Configure flow control */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - if (termios->c_cflag & CRTSCTS) { - efr |= (UART_EFR_CTS | UART_EFR_RTS); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + /* XON1/XOFF1 accessible mode B, TCRTLR=0, ECB=0 */ + serial_out(up, UART_XON1, termios->c_cc[VSTART]); + serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]); - up->mcr = serial_in(up, UART_MCR); - serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + /* Enable access to TCR/TLR */ + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + + serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - up->efr = serial_in(up, UART_EFR); - serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { + /* Enable AUTORTS and AUTOCTS */ + up->efr |= UART_EFR_CTS | UART_EFR_RTS; - serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); - serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS); - serial_out(up, UART_LCR, cval); + /* Ensure MCR RTS is asserted */ + up->mcr |= UART_MCR_RTS; + } else { + /* Disable AUTORTS and AUTOCTS */ + up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS); } + if (up->port.flags & UPF_SOFT_FLOW) { + /* clear SW control mode bits */ + up->efr &= OMAP_UART_SW_CLR; + + /* + * IXON Flag: + * Enable XON/XOFF flow control on input. + * Receiver compares XON1, XOFF1. + */ + if (termios->c_iflag & IXON) + up->efr |= OMAP_UART_SW_RX; + + /* + * IXOFF Flag: + * Enable XON/XOFF flow control on output. + * Transmit XON1, XOFF1 + */ + if (termios->c_iflag & IXOFF) + up->efr |= OMAP_UART_SW_TX; + + /* + * IXANY Flag: + * Enable any character to restart output. + * Operation resumes after receiving any + * character after recognition of the XOFF character + */ + if (termios->c_iflag & IXANY) + up->mcr |= UART_MCR_XONANY; + else + up->mcr &= ~UART_MCR_XONANY; + } + serial_out(up, UART_MCR, up->mcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, up->efr); + serial_out(up, UART_LCR, up->lcr); + serial_omap_set_mctrl(&up->port, up->port.mctrl); - /* Software Flow Control Configuration */ - serial_omap_configure_xonxoff(up, termios); spin_unlock_irqrestore(&up->port.lock, flags); pm_runtime_mark_last_busy(up->dev); @@ -991,6 +1067,7 @@ static void serial_omap_config_port(struct uart_port *port, int flags) dev_dbg(up->port.dev, "serial_omap_config_port+%d\n", up->port.line); up->port.type = PORT_OMAP; + up->port.flags |= UPF_SOFT_FLOW | UPF_HARD_FLOW; } static int @@ -1081,7 +1158,7 @@ out: #ifdef CONFIG_SERIAL_OMAP_CONSOLE -static struct uart_omap_port *serial_omap_console_ports[4]; +static struct uart_omap_port *serial_omap_console_ports[OMAP_MAX_HSUART_PORTS]; static struct uart_driver serial_omap_reg; @@ -1194,6 +1271,8 @@ static struct uart_ops serial_omap_pops = { .get_mctrl = serial_omap_get_mctrl, .stop_tx = serial_omap_stop_tx, .start_tx = serial_omap_start_tx, + .throttle = serial_omap_throttle, + .unthrottle = serial_omap_unthrottle, .stop_rx = serial_omap_stop_rx, .enable_ms = serial_omap_enable_ms, .break_ctl = serial_omap_break_ctl, @@ -1242,7 +1321,7 @@ static int serial_omap_resume(struct device *dev) } #endif -static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *up) +static void omap_serial_fill_features_erratas(struct uart_omap_port *up) { u32 mvr, scheme; u16 revision, major, minor; @@ -1295,7 +1374,7 @@ static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *u } } -static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) +static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) { struct omap_uart_port_info *omap_up_info; @@ -1308,7 +1387,7 @@ static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device return omap_up_info; } -static int __devinit serial_omap_probe(struct platform_device *pdev) +static int serial_omap_probe(struct platform_device *pdev) { struct uart_omap_port *up; struct resource *mem, *irq; @@ -1445,7 +1524,7 @@ err_port_line: return ret; } -static int __devexit serial_omap_remove(struct platform_device *dev) +static int serial_omap_remove(struct platform_device *dev) { struct uart_omap_port *up = platform_get_drvdata(dev); @@ -1556,11 +1635,15 @@ static int serial_omap_runtime_resume(struct device *dev) { struct uart_omap_port *up = dev_get_drvdata(dev); - u32 loss_cnt = serial_omap_get_context_loss_count(up); + int loss_cnt = serial_omap_get_context_loss_count(up); - if (up->context_loss_cnt != loss_cnt) + if (loss_cnt < 0) { + dev_err(dev, "serial_omap_get_context_loss_count failed : %d\n", + loss_cnt); serial_omap_restore_context(up); - + } else if (up->context_loss_cnt != loss_cnt) { + serial_omap_restore_context(up); + } up->latency = up->calc_latency; schedule_work(&up->qos_work); @@ -1586,7 +1669,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match); static struct platform_driver serial_omap_driver = { .probe = serial_omap_probe, - .remove = __devexit_p(serial_omap_remove), + .remove = serial_omap_remove, .driver = { .name = DRIVER_NAME, .pm = &serial_omap_dev_pm_ops, diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 4cd6c2381528..7a6c989924b3 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -14,18 +14,21 @@ *along with this program; if not, write to the Free Software *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ +#if defined(CONFIG_SERIAL_PCH_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif #include <linux/kernel.h> #include <linux/serial_reg.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/console.h> #include <linux/serial_core.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/dmi.h> -#include <linux/console.h> #include <linux/nmi.h> #include <linux/delay.h> @@ -553,12 +556,26 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, { int i; u8 rbr, lsr; + struct uart_port *port = &priv->port; lsr = ioread8(priv->membase + UART_LSR); for (i = 0, lsr = ioread8(priv->membase + UART_LSR); - i < rx_size && lsr & UART_LSR_DR; + i < rx_size && lsr & (UART_LSR_DR | UART_LSR_BI); lsr = ioread8(priv->membase + UART_LSR)) { rbr = ioread8(priv->membase + PCH_UART_RBR); + + if (lsr & UART_LSR_BI) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } +#ifdef SUPPORT_SYSRQ + if (port->sysrq) { + if (uart_handle_sysrq_char(port, rbr)) + continue; + } +#endif + buf[i++] = rbr; } return i; @@ -591,19 +608,11 @@ static void pch_uart_hal_set_break(struct eg20t_port *priv, int on) static int push_rx(struct eg20t_port *priv, const unsigned char *buf, int size) { - struct uart_port *port; - struct tty_struct *tty; - - port = &priv->port; - tty = tty_port_tty_get(&port->state->port); - if (!tty) { - dev_dbg(priv->port.dev, "%s:tty is busy now", __func__); - return -EBUSY; - } + struct uart_port *port = &priv->port; + struct tty_port *tport = &port->state->port; - tty_insert_flip_string(tty, buf, size); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_insert_flip_string(tport, buf, size); + tty_flip_buffer_push(tport); return 0; } @@ -629,15 +638,16 @@ static int dma_push_rx(struct eg20t_port *priv, int size) struct tty_struct *tty; int room; struct uart_port *port = &priv->port; + struct tty_port *tport = &port->state->port; port = &priv->port; - tty = tty_port_tty_get(&port->state->port); + tty = tty_port_tty_get(tport); if (!tty) { dev_dbg(priv->port.dev, "%s:tty is busy now", __func__); return 0; } - room = tty_buffer_request_room(tty, size); + room = tty_buffer_request_room(tport, size); if (room < size) dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", @@ -645,7 +655,7 @@ static int dma_push_rx(struct eg20t_port *priv, int size) if (!room) return room; - tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size); + tty_insert_flip_string(tport, sg_virt(&priv->sg_rx), size); port->icount.rx += room; tty_kref_put(tty); @@ -743,19 +753,12 @@ static void pch_dma_rx_complete(void *arg) { struct eg20t_port *priv = arg; struct uart_port *port = &priv->port; - struct tty_struct *tty = tty_port_tty_get(&port->state->port); int count; - if (!tty) { - dev_dbg(priv->port.dev, "%s:tty is busy now", __func__); - return; - } - dma_sync_sg_for_cpu(port->dev, &priv->sg_rx, 1, DMA_FROM_DEVICE); count = dma_push_rx(priv, priv->trigger_level); if (count) - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->state->port); async_tx_ack(priv->desc_rx); pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT | PCH_UART_HAL_RX_ERR_INT); @@ -1037,23 +1040,33 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr) { - u8 fcr = ioread8(priv->membase + UART_FCR); - - /* Reset FIFO */ - fcr |= UART_FCR_CLEAR_RCVR; - iowrite8(fcr, priv->membase + UART_FCR); + struct uart_port *port = &priv->port; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + char *error_msg[5] = {}; + int i = 0; if (lsr & PCH_UART_LSR_ERR) - dev_err(&priv->pdev->dev, "Error data in FIFO\n"); + error_msg[i++] = "Error data in FIFO\n"; - if (lsr & UART_LSR_FE) - dev_err(&priv->pdev->dev, "Framing Error\n"); + if (lsr & UART_LSR_FE) { + port->icount.frame++; + error_msg[i++] = " Framing Error\n"; + } - if (lsr & UART_LSR_PE) - dev_err(&priv->pdev->dev, "Parity Error\n"); + if (lsr & UART_LSR_PE) { + port->icount.parity++; + error_msg[i++] = " Parity Error\n"; + } - if (lsr & UART_LSR_OE) - dev_err(&priv->pdev->dev, "Overrun Error\n"); + if (lsr & UART_LSR_OE) { + port->icount.overrun++; + error_msg[i++] = " Overrun Error\n"; + } + + if (tty == NULL) { + for (i = 0; error_msg[i] != NULL; i++) + dev_err(&priv->pdev->dev, error_msg[i]); + } } static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) @@ -1564,7 +1577,8 @@ pch_console_write(struct console *co, const char *s, unsigned int count) local_irq_save(flags); if (priv->port.sysrq) { - spin_lock(&priv->lock); + /* call to uart_handle_sysrq_char already took the priv lock */ + priv_locked = 0; /* serial8250_handle_port() already took the port lock */ port_locked = 0; } else if (oops_in_progress) { @@ -1839,7 +1853,7 @@ static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { {0,}, }; -static int __devinit pch_uart_pci_probe(struct pci_dev *pdev, +static int pch_uart_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int ret; @@ -1869,7 +1883,7 @@ static struct pci_driver pch_uart_pci_driver = { .name = "pch_uart", .id_table = pch_uart_pci_id, .probe = pch_uart_pci_probe, - .remove = __devexit_p(pch_uart_pci_remove), + .remove = pch_uart_pci_remove, .suspend = pch_uart_pci_suspend, .resume = pch_uart_pci_resume, }; diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 333c8d012b0e..b1785f58b6e3 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -227,19 +227,19 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable) write_zsreg(uap, R1, uap->curregs[1]); } -static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) +static bool pmz_receive_chars(struct uart_pmac_port *uap) { - struct tty_struct *tty = NULL; + struct tty_port *port; unsigned char ch, r1, drop, error, flag; int loops = 0; /* Sanity check, make sure the old bug is no longer happening */ - if (uap->port.state == NULL || uap->port.state->port.tty == NULL) { + if (uap->port.state == NULL) { WARN_ON(1); (void)read_zsdata(uap); - return NULL; + return false; } - tty = uap->port.state->port.tty; + port = &uap->port.state->port; while (1) { error = 0; @@ -309,10 +309,10 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) if (uap->port.ignore_status_mask == 0xff || (r1 & uap->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(port, ch, flag); } if (r1 & Rx_OVR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(port, 0, TTY_OVERRUN); next_char: /* We can get stuck in an infinite loop getting char 0 when the * line is in a wrong HW state, we break that here. @@ -328,11 +328,11 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) break; } - return tty; + return true; flood: pmz_interrupt_control(uap, 0); pmz_error("pmz: rx irq flood !\n"); - return tty; + return true; } static void pmz_status_handle(struct uart_pmac_port *uap) @@ -453,7 +453,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) struct uart_pmac_port *uap_a; struct uart_pmac_port *uap_b; int rc = IRQ_NONE; - struct tty_struct *tty; + bool push; u8 r3; uap_a = pmz_get_port_A(uap); @@ -466,7 +466,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) pmz_debug("irq, r3: %x\n", r3); #endif /* Channel A */ - tty = NULL; + push = false; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { if (!ZS_IS_OPEN(uap_a)) { pmz_debug("ChanA interrupt while not open !\n"); @@ -477,21 +477,21 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) if (r3 & CHAEXT) pmz_status_handle(uap_a); if (r3 & CHARxIP) - tty = pmz_receive_chars(uap_a); + push = pmz_receive_chars(uap_a); if (r3 & CHATxIP) pmz_transmit_chars(uap_a); rc = IRQ_HANDLED; } skip_a: spin_unlock(&uap_a->port.lock); - if (tty != NULL) - tty_flip_buffer_push(tty); + if (push) + tty_flip_buffer_push(&uap->port.state->port); if (!uap_b) goto out; spin_lock(&uap_b->port.lock); - tty = NULL; + push = false; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { if (!ZS_IS_OPEN(uap_b)) { pmz_debug("ChanB interrupt while not open !\n"); @@ -502,15 +502,15 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) if (r3 & CHBEXT) pmz_status_handle(uap_b); if (r3 & CHBRxIP) - tty = pmz_receive_chars(uap_b); + push = pmz_receive_chars(uap_b); if (r3 & CHBTxIP) pmz_transmit_chars(uap_b); rc = IRQ_HANDLED; } skip_b: spin_unlock(&uap_b->port.lock); - if (tty != NULL) - tty_flip_buffer_push(tty); + if (push) + tty_flip_buffer_push(&uap->port.state->port); out: return rc; diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c index 0aa75a97531c..7e277a5384a7 100644 --- a/drivers/tty/serial/pnx8xxx_uart.c +++ b/drivers/tty/serial/pnx8xxx_uart.c @@ -181,7 +181,6 @@ static void pnx8xxx_enable_ms(struct uart_port *port) static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) { - struct tty_struct *tty = sport->port.state->port.tty; unsigned int status, ch, flg; status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | @@ -238,7 +237,7 @@ static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&sport->port.state->port); } static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport) diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 9033fc6e0e4e..05f504e0c271 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -98,7 +98,6 @@ static void serial_pxa_stop_rx(struct uart_port *port) static inline void receive_chars(struct uart_pxa_port *up, int *status) { - struct tty_struct *tty = up->port.state->port.tty; unsigned int ch, flag; int max_count = 256; @@ -168,7 +167,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) ignore_char: *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&up->port.state->port); /* work around Errata #20 according to * Intel(R) PXA27x Processor Family @@ -673,8 +672,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) unsigned long flags; int locked = 1; - clk_prepare_enable(up->clk); - + clk_enable(up->clk); local_irq_save(flags); if (up->port.sysrq) locked = 0; @@ -701,10 +699,61 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) if (locked) spin_unlock(&up->port.lock); local_irq_restore(flags); + clk_disable(up->clk); + +} + +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial_pxa_get_poll_char(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned char lsr = serial_in(up, UART_LSR); + + while (!(lsr & UART_LSR_DR)) + lsr = serial_in(up, UART_LSR); + + return serial_in(up, UART_RX); +} + + +static void serial_pxa_put_poll_char(struct uart_port *port, + unsigned char c) +{ + unsigned int ier; + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, UART_IER_UUE); + + wait_for_xmitr(up); + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_out(up, UART_TX, c); + if (c == 10) { + wait_for_xmitr(up); + serial_out(up, UART_TX, 13); + } - clk_disable_unprepare(up->clk); + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + serial_out(up, UART_IER, ier); } +#endif /* CONFIG_CONSOLE_POLL */ + static int __init serial_pxa_console_setup(struct console *co, char *options) { @@ -759,6 +808,10 @@ struct uart_ops serial_pxa_pops = { .request_port = serial_pxa_request_port, .config_port = serial_pxa_config_port, .verify_port = serial_pxa_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial_pxa_get_poll_char, + .poll_put_char = serial_pxa_put_poll_char, +#endif }; static struct uart_driver serial_pxa_reg = { @@ -844,6 +897,12 @@ static int serial_pxa_probe(struct platform_device *dev) goto err_free; } + ret = clk_prepare(sport->clk); + if (ret) { + clk_put(sport->clk); + goto err_free; + } + sport->port.type = PORT_PXA; sport->port.iotype = UPIO_MEM; sport->port.mapbase = mmres->start; @@ -875,6 +934,7 @@ static int serial_pxa_probe(struct platform_device *dev) return 0; err_clk: + clk_unprepare(sport->clk); clk_put(sport->clk); err_free: kfree(sport); @@ -888,6 +948,8 @@ static int serial_pxa_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); uart_remove_one_port(&serial_pxa_reg, &sport->port); + + clk_unprepare(sport->clk); clk_put(sport->clk); kfree(sport); diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c new file mode 100644 index 000000000000..a314a943f124 --- /dev/null +++ b/drivers/tty/serial/rp2.c @@ -0,0 +1,885 @@ +/* + * Driver for Comtrol RocketPort EXPRESS/INFINITY cards + * + * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com> + * + * Inspired by, and loosely based on: + * + * ar933x_uart.c + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * + * rocketport_infinity_express-linux-1.20.tar.gz + * Copyright (C) 2004-2011 Comtrol, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/bitops.h> +#include <linux/compiler.h> +#include <linux/completion.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/log2.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/sysrq.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/types.h> + +#define DRV_NAME "rp2" + +#define RP2_FW_NAME "rp2.fw" +#define RP2_UCODE_BYTES 0x3f + +#define PORTS_PER_ASIC 16 +#define ALL_PORTS_MASK (BIT(PORTS_PER_ASIC) - 1) + +#define UART_CLOCK 44236800 +#define DEFAULT_BAUD_DIV (UART_CLOCK / (9600 * 16)) +#define FIFO_SIZE 512 + +/* BAR0 registers */ +#define RP2_FPGA_CTL0 0x110 +#define RP2_FPGA_CTL1 0x11c +#define RP2_IRQ_MASK 0x1ec +#define RP2_IRQ_MASK_EN_m BIT(0) +#define RP2_IRQ_STATUS 0x1f0 + +/* BAR1 registers */ +#define RP2_ASIC_SPACING 0x1000 +#define RP2_ASIC_OFFSET(i) ((i) << ilog2(RP2_ASIC_SPACING)) + +#define RP2_PORT_BASE 0x000 +#define RP2_PORT_SPACING 0x040 + +#define RP2_UCODE_BASE 0x400 +#define RP2_UCODE_SPACING 0x80 + +#define RP2_CLK_PRESCALER 0xc00 +#define RP2_CH_IRQ_STAT 0xc04 +#define RP2_CH_IRQ_MASK 0xc08 +#define RP2_ASIC_IRQ 0xd00 +#define RP2_ASIC_IRQ_EN_m BIT(20) +#define RP2_GLOBAL_CMD 0xd0c +#define RP2_ASIC_CFG 0xd04 + +/* port registers */ +#define RP2_DATA_DWORD 0x000 + +#define RP2_DATA_BYTE 0x008 +#define RP2_DATA_BYTE_ERR_PARITY_m BIT(8) +#define RP2_DATA_BYTE_ERR_OVERRUN_m BIT(9) +#define RP2_DATA_BYTE_ERR_FRAMING_m BIT(10) +#define RP2_DATA_BYTE_BREAK_m BIT(11) + +/* This lets uart_insert_char() drop bytes received on a !CREAD port */ +#define RP2_DUMMY_READ BIT(16) + +#define RP2_DATA_BYTE_EXCEPTION_MASK (RP2_DATA_BYTE_ERR_PARITY_m | \ + RP2_DATA_BYTE_ERR_OVERRUN_m | \ + RP2_DATA_BYTE_ERR_FRAMING_m | \ + RP2_DATA_BYTE_BREAK_m) + +#define RP2_RX_FIFO_COUNT 0x00c +#define RP2_TX_FIFO_COUNT 0x00e + +#define RP2_CHAN_STAT 0x010 +#define RP2_CHAN_STAT_RXDATA_m BIT(0) +#define RP2_CHAN_STAT_DCD_m BIT(3) +#define RP2_CHAN_STAT_DSR_m BIT(4) +#define RP2_CHAN_STAT_CTS_m BIT(5) +#define RP2_CHAN_STAT_RI_m BIT(6) +#define RP2_CHAN_STAT_OVERRUN_m BIT(13) +#define RP2_CHAN_STAT_DSR_CHANGED_m BIT(16) +#define RP2_CHAN_STAT_CTS_CHANGED_m BIT(17) +#define RP2_CHAN_STAT_CD_CHANGED_m BIT(18) +#define RP2_CHAN_STAT_RI_CHANGED_m BIT(22) +#define RP2_CHAN_STAT_TXEMPTY_m BIT(25) + +#define RP2_CHAN_STAT_MS_CHANGED_MASK (RP2_CHAN_STAT_DSR_CHANGED_m | \ + RP2_CHAN_STAT_CTS_CHANGED_m | \ + RP2_CHAN_STAT_CD_CHANGED_m | \ + RP2_CHAN_STAT_RI_CHANGED_m) + +#define RP2_TXRX_CTL 0x014 +#define RP2_TXRX_CTL_MSRIRQ_m BIT(0) +#define RP2_TXRX_CTL_RXIRQ_m BIT(2) +#define RP2_TXRX_CTL_RX_TRIG_s 3 +#define RP2_TXRX_CTL_RX_TRIG_m (0x3 << RP2_TXRX_CTL_RX_TRIG_s) +#define RP2_TXRX_CTL_RX_TRIG_1 (0x1 << RP2_TXRX_CTL_RX_TRIG_s) +#define RP2_TXRX_CTL_RX_TRIG_256 (0x2 << RP2_TXRX_CTL_RX_TRIG_s) +#define RP2_TXRX_CTL_RX_TRIG_448 (0x3 << RP2_TXRX_CTL_RX_TRIG_s) +#define RP2_TXRX_CTL_RX_EN_m BIT(5) +#define RP2_TXRX_CTL_RTSFLOW_m BIT(6) +#define RP2_TXRX_CTL_DTRFLOW_m BIT(7) +#define RP2_TXRX_CTL_TX_TRIG_s 16 +#define RP2_TXRX_CTL_TX_TRIG_m (0x3 << RP2_TXRX_CTL_RX_TRIG_s) +#define RP2_TXRX_CTL_DSRFLOW_m BIT(18) +#define RP2_TXRX_CTL_TXIRQ_m BIT(19) +#define RP2_TXRX_CTL_CTSFLOW_m BIT(23) +#define RP2_TXRX_CTL_TX_EN_m BIT(24) +#define RP2_TXRX_CTL_RTS_m BIT(25) +#define RP2_TXRX_CTL_DTR_m BIT(26) +#define RP2_TXRX_CTL_LOOP_m BIT(27) +#define RP2_TXRX_CTL_BREAK_m BIT(28) +#define RP2_TXRX_CTL_CMSPAR_m BIT(29) +#define RP2_TXRX_CTL_nPARODD_m BIT(30) +#define RP2_TXRX_CTL_PARENB_m BIT(31) + +#define RP2_UART_CTL 0x018 +#define RP2_UART_CTL_MODE_s 0 +#define RP2_UART_CTL_MODE_m (0x7 << RP2_UART_CTL_MODE_s) +#define RP2_UART_CTL_MODE_rs232 (0x1 << RP2_UART_CTL_MODE_s) +#define RP2_UART_CTL_FLUSH_RX_m BIT(3) +#define RP2_UART_CTL_FLUSH_TX_m BIT(4) +#define RP2_UART_CTL_RESET_CH_m BIT(5) +#define RP2_UART_CTL_XMIT_EN_m BIT(6) +#define RP2_UART_CTL_DATABITS_s 8 +#define RP2_UART_CTL_DATABITS_m (0x3 << RP2_UART_CTL_DATABITS_s) +#define RP2_UART_CTL_DATABITS_8 (0x3 << RP2_UART_CTL_DATABITS_s) +#define RP2_UART_CTL_DATABITS_7 (0x2 << RP2_UART_CTL_DATABITS_s) +#define RP2_UART_CTL_DATABITS_6 (0x1 << RP2_UART_CTL_DATABITS_s) +#define RP2_UART_CTL_DATABITS_5 (0x0 << RP2_UART_CTL_DATABITS_s) +#define RP2_UART_CTL_STOPBITS_m BIT(10) + +#define RP2_BAUD 0x01c + +/* ucode registers */ +#define RP2_TX_SWFLOW 0x02 +#define RP2_TX_SWFLOW_ena 0x81 +#define RP2_TX_SWFLOW_dis 0x9d + +#define RP2_RX_SWFLOW 0x0c +#define RP2_RX_SWFLOW_ena 0x81 +#define RP2_RX_SWFLOW_dis 0x8d + +#define RP2_RX_FIFO 0x37 +#define RP2_RX_FIFO_ena 0x08 +#define RP2_RX_FIFO_dis 0x81 + +static struct uart_driver rp2_uart_driver = { + .owner = THIS_MODULE, + .driver_name = DRV_NAME, + .dev_name = "ttyRP", + .nr = CONFIG_SERIAL_RP2_NR_UARTS, +}; + +struct rp2_card; + +struct rp2_uart_port { + struct uart_port port; + int idx; + int ignore_rx; + struct rp2_card *card; + void __iomem *asic_base; + void __iomem *base; + void __iomem *ucode; +}; + +struct rp2_card { + struct pci_dev *pdev; + struct rp2_uart_port *ports; + int n_ports; + int initialized_ports; + int minor_start; + int smpte; + void __iomem *bar0; + void __iomem *bar1; + spinlock_t card_lock; + struct completion fw_loaded; +}; + +#define RP_ID(prod) PCI_VDEVICE(RP, (prod)) +#define RP_CAP(ports, smpte) (((ports) << 8) | ((smpte) << 0)) + +static inline void rp2_decode_cap(const struct pci_device_id *id, + int *ports, int *smpte) +{ + *ports = id->driver_data >> 8; + *smpte = id->driver_data & 0xff; +} + +static DEFINE_SPINLOCK(rp2_minor_lock); +static int rp2_minor_next; + +static int rp2_alloc_ports(int n_ports) +{ + int ret = -ENOSPC; + + spin_lock(&rp2_minor_lock); + if (rp2_minor_next + n_ports <= CONFIG_SERIAL_RP2_NR_UARTS) { + /* sorry, no support for hot unplugging individual cards */ + ret = rp2_minor_next; + rp2_minor_next += n_ports; + } + spin_unlock(&rp2_minor_lock); + + return ret; +} + +static inline struct rp2_uart_port *port_to_up(struct uart_port *port) +{ + return container_of(port, struct rp2_uart_port, port); +} + +static void rp2_rmw(struct rp2_uart_port *up, int reg, + u32 clr_bits, u32 set_bits) +{ + u32 tmp = readl(up->base + reg); + tmp &= ~clr_bits; + tmp |= set_bits; + writel(tmp, up->base + reg); +} + +static void rp2_rmw_clr(struct rp2_uart_port *up, int reg, u32 val) +{ + rp2_rmw(up, reg, val, 0); +} + +static void rp2_rmw_set(struct rp2_uart_port *up, int reg, u32 val) +{ + rp2_rmw(up, reg, 0, val); +} + +static void rp2_mask_ch_irq(struct rp2_uart_port *up, int ch_num, + int is_enabled) +{ + unsigned long flags, irq_mask; + + spin_lock_irqsave(&up->card->card_lock, flags); + + irq_mask = readl(up->asic_base + RP2_CH_IRQ_MASK); + if (is_enabled) + irq_mask &= ~BIT(ch_num); + else + irq_mask |= BIT(ch_num); + writel(irq_mask, up->asic_base + RP2_CH_IRQ_MASK); + + spin_unlock_irqrestore(&up->card->card_lock, flags); +} + +static unsigned int rp2_uart_tx_empty(struct uart_port *port) +{ + struct rp2_uart_port *up = port_to_up(port); + unsigned long tx_fifo_bytes, flags; + + /* + * This should probably check the transmitter, not the FIFO. + * But the TXEMPTY bit doesn't seem to work unless the TX IRQ is + * enabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + tx_fifo_bytes = readw(up->base + RP2_TX_FIFO_COUNT); + spin_unlock_irqrestore(&up->port.lock, flags); + + return tx_fifo_bytes ? 0 : TIOCSER_TEMT; +} + +static unsigned int rp2_uart_get_mctrl(struct uart_port *port) +{ + struct rp2_uart_port *up = port_to_up(port); + u32 status; + + status = readl(up->base + RP2_CHAN_STAT); + return ((status & RP2_CHAN_STAT_DCD_m) ? TIOCM_CAR : 0) | + ((status & RP2_CHAN_STAT_DSR_m) ? TIOCM_DSR : 0) | + ((status & RP2_CHAN_STAT_CTS_m) ? TIOCM_CTS : 0) | + ((status & RP2_CHAN_STAT_RI_m) ? TIOCM_RI : 0); +} + +static void rp2_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + rp2_rmw(port_to_up(port), RP2_TXRX_CTL, + RP2_TXRX_CTL_DTR_m | RP2_TXRX_CTL_RTS_m | RP2_TXRX_CTL_LOOP_m, + ((mctrl & TIOCM_DTR) ? RP2_TXRX_CTL_DTR_m : 0) | + ((mctrl & TIOCM_RTS) ? RP2_TXRX_CTL_RTS_m : 0) | + ((mctrl & TIOCM_LOOP) ? RP2_TXRX_CTL_LOOP_m : 0)); +} + +static void rp2_uart_start_tx(struct uart_port *port) +{ + rp2_rmw_set(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_TXIRQ_m); +} + +static void rp2_uart_stop_tx(struct uart_port *port) +{ + rp2_rmw_clr(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_TXIRQ_m); +} + +static void rp2_uart_stop_rx(struct uart_port *port) +{ + rp2_rmw_clr(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_RXIRQ_m); +} + +static void rp2_uart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + rp2_rmw(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_BREAK_m, + break_state ? RP2_TXRX_CTL_BREAK_m : 0); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void rp2_uart_enable_ms(struct uart_port *port) +{ + rp2_rmw_set(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_MSRIRQ_m); +} + +static void __rp2_uart_set_termios(struct rp2_uart_port *up, + unsigned long cfl, + unsigned long ifl, + unsigned int baud_div) +{ + /* baud rate divisor (calculated elsewhere). 0 = divide-by-1 */ + writew(baud_div - 1, up->base + RP2_BAUD); + + /* data bits and stop bits */ + rp2_rmw(up, RP2_UART_CTL, + RP2_UART_CTL_STOPBITS_m | RP2_UART_CTL_DATABITS_m, + ((cfl & CSTOPB) ? RP2_UART_CTL_STOPBITS_m : 0) | + (((cfl & CSIZE) == CS8) ? RP2_UART_CTL_DATABITS_8 : 0) | + (((cfl & CSIZE) == CS7) ? RP2_UART_CTL_DATABITS_7 : 0) | + (((cfl & CSIZE) == CS6) ? RP2_UART_CTL_DATABITS_6 : 0) | + (((cfl & CSIZE) == CS5) ? RP2_UART_CTL_DATABITS_5 : 0)); + + /* parity and hardware flow control */ + rp2_rmw(up, RP2_TXRX_CTL, + RP2_TXRX_CTL_PARENB_m | RP2_TXRX_CTL_nPARODD_m | + RP2_TXRX_CTL_CMSPAR_m | RP2_TXRX_CTL_DTRFLOW_m | + RP2_TXRX_CTL_DSRFLOW_m | RP2_TXRX_CTL_RTSFLOW_m | + RP2_TXRX_CTL_CTSFLOW_m, + ((cfl & PARENB) ? RP2_TXRX_CTL_PARENB_m : 0) | + ((cfl & PARODD) ? 0 : RP2_TXRX_CTL_nPARODD_m) | + ((cfl & CMSPAR) ? RP2_TXRX_CTL_CMSPAR_m : 0) | + ((cfl & CRTSCTS) ? (RP2_TXRX_CTL_RTSFLOW_m | + RP2_TXRX_CTL_CTSFLOW_m) : 0)); + + /* XON/XOFF software flow control */ + writeb((ifl & IXON) ? RP2_TX_SWFLOW_ena : RP2_TX_SWFLOW_dis, + up->ucode + RP2_TX_SWFLOW); + writeb((ifl & IXOFF) ? RP2_RX_SWFLOW_ena : RP2_RX_SWFLOW_dis, + up->ucode + RP2_RX_SWFLOW); +} + +static void rp2_uart_set_termios(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + struct rp2_uart_port *up = port_to_up(port); + unsigned long flags; + unsigned int baud, baud_div; + + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + baud_div = uart_get_divisor(port, baud); + + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); + + spin_lock_irqsave(&port->lock, flags); + + /* ignore all characters if CREAD is not set */ + port->ignore_status_mask = (new->c_cflag & CREAD) ? 0 : RP2_DUMMY_READ; + + __rp2_uart_set_termios(up, new->c_cflag, new->c_iflag, baud_div); + uart_update_timeout(port, new->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void rp2_rx_chars(struct rp2_uart_port *up) +{ + u16 bytes = readw(up->base + RP2_RX_FIFO_COUNT); + struct tty_port *port = &up->port.state->port; + + for (; bytes != 0; bytes--) { + u32 byte = readw(up->base + RP2_DATA_BYTE) | RP2_DUMMY_READ; + char ch = byte & 0xff; + + if (likely(!(byte & RP2_DATA_BYTE_EXCEPTION_MASK))) { + if (!uart_handle_sysrq_char(&up->port, ch)) + uart_insert_char(&up->port, byte, 0, ch, + TTY_NORMAL); + } else { + char flag = TTY_NORMAL; + + if (byte & RP2_DATA_BYTE_BREAK_m) + flag = TTY_BREAK; + else if (byte & RP2_DATA_BYTE_ERR_FRAMING_m) + flag = TTY_FRAME; + else if (byte & RP2_DATA_BYTE_ERR_PARITY_m) + flag = TTY_PARITY; + uart_insert_char(&up->port, byte, + RP2_DATA_BYTE_ERR_OVERRUN_m, ch, flag); + } + up->port.icount.rx++; + } + + tty_flip_buffer_push(port); +} + +static void rp2_tx_chars(struct rp2_uart_port *up) +{ + u16 max_tx = FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT); + struct circ_buf *xmit = &up->port.state->xmit; + + if (uart_tx_stopped(&up->port)) { + rp2_uart_stop_tx(&up->port); + return; + } + + for (; max_tx != 0; max_tx--) { + if (up->port.x_char) { + writeb(up->port.x_char, up->base + RP2_DATA_BYTE); + up->port.x_char = 0; + up->port.icount.tx++; + continue; + } + if (uart_circ_empty(xmit)) { + rp2_uart_stop_tx(&up->port); + break; + } + writeb(xmit->buf[xmit->tail], up->base + RP2_DATA_BYTE); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); +} + +static void rp2_ch_interrupt(struct rp2_uart_port *up) +{ + u32 status; + + spin_lock(&up->port.lock); + + /* + * The IRQ status bits are clear-on-write. Other status bits in + * this register aren't, so it's harmless to write to them. + */ + status = readl(up->base + RP2_CHAN_STAT); + writel(status, up->base + RP2_CHAN_STAT); + + if (status & RP2_CHAN_STAT_RXDATA_m) + rp2_rx_chars(up); + if (status & RP2_CHAN_STAT_TXEMPTY_m) + rp2_tx_chars(up); + if (status & RP2_CHAN_STAT_MS_CHANGED_MASK) + wake_up_interruptible(&up->port.state->port.delta_msr_wait); + + spin_unlock(&up->port.lock); +} + +static int rp2_asic_interrupt(struct rp2_card *card, unsigned int asic_id) +{ + void __iomem *base = card->bar1 + RP2_ASIC_OFFSET(asic_id); + int ch, handled = 0; + unsigned long status = readl(base + RP2_CH_IRQ_STAT) & + ~readl(base + RP2_CH_IRQ_MASK); + + for_each_set_bit(ch, &status, PORTS_PER_ASIC) { + rp2_ch_interrupt(&card->ports[ch]); + handled++; + } + return handled; +} + +static irqreturn_t rp2_uart_interrupt(int irq, void *dev_id) +{ + struct rp2_card *card = dev_id; + int handled; + + handled = rp2_asic_interrupt(card, 0); + if (card->n_ports >= PORTS_PER_ASIC) + handled += rp2_asic_interrupt(card, 1); + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static inline void rp2_flush_fifos(struct rp2_uart_port *up) +{ + rp2_rmw_set(up, RP2_UART_CTL, + RP2_UART_CTL_FLUSH_RX_m | RP2_UART_CTL_FLUSH_TX_m); + readl(up->base + RP2_UART_CTL); + udelay(10); + rp2_rmw_clr(up, RP2_UART_CTL, + RP2_UART_CTL_FLUSH_RX_m | RP2_UART_CTL_FLUSH_TX_m); +} + +static int rp2_uart_startup(struct uart_port *port) +{ + struct rp2_uart_port *up = port_to_up(port); + + rp2_flush_fifos(up); + rp2_rmw(up, RP2_TXRX_CTL, RP2_TXRX_CTL_MSRIRQ_m, RP2_TXRX_CTL_RXIRQ_m); + rp2_rmw(up, RP2_TXRX_CTL, RP2_TXRX_CTL_RX_TRIG_m, + RP2_TXRX_CTL_RX_TRIG_1); + rp2_rmw(up, RP2_CHAN_STAT, 0, 0); + rp2_mask_ch_irq(up, up->idx, 1); + + return 0; +} + +static void rp2_uart_shutdown(struct uart_port *port) +{ + struct rp2_uart_port *up = port_to_up(port); + unsigned long flags; + + rp2_uart_break_ctl(port, 0); + + spin_lock_irqsave(&port->lock, flags); + rp2_mask_ch_irq(up, up->idx, 0); + rp2_rmw(up, RP2_CHAN_STAT, 0, 0); + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *rp2_uart_type(struct uart_port *port) +{ + return (port->type == PORT_RP2) ? "RocketPort 2 UART" : NULL; +} + +static void rp2_uart_release_port(struct uart_port *port) +{ + /* Nothing to release ... */ +} + +static int rp2_uart_request_port(struct uart_port *port) +{ + /* UARTs always present */ + return 0; +} + +static void rp2_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_RP2; +} + +static int rp2_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_RP2) + return -EINVAL; + + return 0; +} + +static const struct uart_ops rp2_uart_ops = { + .tx_empty = rp2_uart_tx_empty, + .set_mctrl = rp2_uart_set_mctrl, + .get_mctrl = rp2_uart_get_mctrl, + .stop_tx = rp2_uart_stop_tx, + .start_tx = rp2_uart_start_tx, + .stop_rx = rp2_uart_stop_rx, + .enable_ms = rp2_uart_enable_ms, + .break_ctl = rp2_uart_break_ctl, + .startup = rp2_uart_startup, + .shutdown = rp2_uart_shutdown, + .set_termios = rp2_uart_set_termios, + .type = rp2_uart_type, + .release_port = rp2_uart_release_port, + .request_port = rp2_uart_request_port, + .config_port = rp2_uart_config_port, + .verify_port = rp2_uart_verify_port, +}; + +static void rp2_reset_asic(struct rp2_card *card, unsigned int asic_id) +{ + void __iomem *base = card->bar1 + RP2_ASIC_OFFSET(asic_id); + u32 clk_cfg; + + writew(1, base + RP2_GLOBAL_CMD); + readw(base + RP2_GLOBAL_CMD); + msleep(100); + writel(0, base + RP2_CLK_PRESCALER); + + /* TDM clock configuration */ + clk_cfg = readw(base + RP2_ASIC_CFG); + clk_cfg = (clk_cfg & ~BIT(8)) | BIT(9); + writew(clk_cfg, base + RP2_ASIC_CFG); + + /* IRQ routing */ + writel(ALL_PORTS_MASK, base + RP2_CH_IRQ_MASK); + writel(RP2_ASIC_IRQ_EN_m, base + RP2_ASIC_IRQ); +} + +static void rp2_init_card(struct rp2_card *card) +{ + writel(4, card->bar0 + RP2_FPGA_CTL0); + writel(0, card->bar0 + RP2_FPGA_CTL1); + + rp2_reset_asic(card, 0); + if (card->n_ports >= PORTS_PER_ASIC) + rp2_reset_asic(card, 1); + + writel(RP2_IRQ_MASK_EN_m, card->bar0 + RP2_IRQ_MASK); +} + +static void rp2_init_port(struct rp2_uart_port *up, const struct firmware *fw) +{ + int i; + + writel(RP2_UART_CTL_RESET_CH_m, up->base + RP2_UART_CTL); + readl(up->base + RP2_UART_CTL); + udelay(1); + + writel(0, up->base + RP2_TXRX_CTL); + writel(0, up->base + RP2_UART_CTL); + readl(up->base + RP2_UART_CTL); + udelay(1); + + rp2_flush_fifos(up); + + for (i = 0; i < min_t(int, fw->size, RP2_UCODE_BYTES); i++) + writeb(fw->data[i], up->ucode + i); + + __rp2_uart_set_termios(up, CS8 | CREAD | CLOCAL, 0, DEFAULT_BAUD_DIV); + rp2_uart_set_mctrl(&up->port, 0); + + writeb(RP2_RX_FIFO_ena, up->ucode + RP2_RX_FIFO); + rp2_rmw(up, RP2_UART_CTL, RP2_UART_CTL_MODE_m, + RP2_UART_CTL_XMIT_EN_m | RP2_UART_CTL_MODE_rs232); + rp2_rmw_set(up, RP2_TXRX_CTL, + RP2_TXRX_CTL_TX_EN_m | RP2_TXRX_CTL_RX_EN_m); +} + +static void rp2_remove_ports(struct rp2_card *card) +{ + int i; + + for (i = 0; i < card->initialized_ports; i++) + uart_remove_one_port(&rp2_uart_driver, &card->ports[i].port); + card->initialized_ports = 0; +} + +static void rp2_fw_cb(const struct firmware *fw, void *context) +{ + struct rp2_card *card = context; + resource_size_t phys_base; + int i, rc = -ENOENT; + + if (!fw) { + dev_err(&card->pdev->dev, "cannot find '%s' firmware image\n", + RP2_FW_NAME); + goto no_fw; + } + + phys_base = pci_resource_start(card->pdev, 1); + + for (i = 0; i < card->n_ports; i++) { + struct rp2_uart_port *rp = &card->ports[i]; + struct uart_port *p; + int j = (unsigned)i % PORTS_PER_ASIC; + + rp->asic_base = card->bar1; + rp->base = card->bar1 + RP2_PORT_BASE + j*RP2_PORT_SPACING; + rp->ucode = card->bar1 + RP2_UCODE_BASE + j*RP2_UCODE_SPACING; + rp->card = card; + rp->idx = j; + + p = &rp->port; + p->line = card->minor_start + i; + p->dev = &card->pdev->dev; + p->type = PORT_RP2; + p->iotype = UPIO_MEM32; + p->uartclk = UART_CLOCK; + p->regshift = 2; + p->fifosize = FIFO_SIZE; + p->ops = &rp2_uart_ops; + p->irq = card->pdev->irq; + p->membase = rp->base; + p->mapbase = phys_base + RP2_PORT_BASE + j*RP2_PORT_SPACING; + + if (i >= PORTS_PER_ASIC) { + rp->asic_base += RP2_ASIC_SPACING; + rp->base += RP2_ASIC_SPACING; + rp->ucode += RP2_ASIC_SPACING; + p->mapbase += RP2_ASIC_SPACING; + } + + rp2_init_port(rp, fw); + rc = uart_add_one_port(&rp2_uart_driver, p); + if (rc) { + dev_err(&card->pdev->dev, + "error registering port %d: %d\n", i, rc); + rp2_remove_ports(card); + break; + } + card->initialized_ports++; + } + + release_firmware(fw); +no_fw: + /* + * rp2_fw_cb() is called from a workqueue long after rp2_probe() + * has already returned success. So if something failed here, + * we'll just leave the now-dormant device in place until somebody + * unbinds it. + */ + if (rc) + dev_warn(&card->pdev->dev, "driver initialization failed\n"); + + complete(&card->fw_loaded); +} + +static int rp2_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct rp2_card *card; + struct rp2_uart_port *ports; + void __iomem * const *bars; + int rc; + + card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + pci_set_drvdata(pdev, card); + spin_lock_init(&card->card_lock); + init_completion(&card->fw_loaded); + + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + rc = pcim_iomap_regions_request_all(pdev, 0x03, DRV_NAME); + if (rc) + return rc; + + bars = pcim_iomap_table(pdev); + card->bar0 = bars[0]; + card->bar1 = bars[1]; + card->pdev = pdev; + + rp2_decode_cap(id, &card->n_ports, &card->smpte); + dev_info(&pdev->dev, "found new card with %d ports\n", card->n_ports); + + card->minor_start = rp2_alloc_ports(card->n_ports); + if (card->minor_start < 0) { + dev_err(&pdev->dev, + "too many ports (try increasing CONFIG_SERIAL_RP2_NR_UARTS)\n"); + return -EINVAL; + } + + rp2_init_card(card); + + ports = devm_kzalloc(&pdev->dev, sizeof(*ports) * card->n_ports, + GFP_KERNEL); + if (!ports) + return -ENOMEM; + card->ports = ports; + + rc = devm_request_irq(&pdev->dev, pdev->irq, rp2_uart_interrupt, + IRQF_SHARED, DRV_NAME, card); + if (rc) + return rc; + + /* + * Only catastrophic errors (e.g. ENOMEM) are reported here. + * If the FW image is missing, we'll find out in rp2_fw_cb() + * and print an error message. + */ + rc = request_firmware_nowait(THIS_MODULE, 1, RP2_FW_NAME, &pdev->dev, + GFP_KERNEL, card, rp2_fw_cb); + if (rc) + return rc; + dev_dbg(&pdev->dev, "waiting for firmware blob...\n"); + + return 0; +} + +static void rp2_remove(struct pci_dev *pdev) +{ + struct rp2_card *card = pci_get_drvdata(pdev); + + wait_for_completion(&card->fw_loaded); + rp2_remove_ports(card); +} + +static DEFINE_PCI_DEVICE_TABLE(rp2_pci_tbl) = { + + /* RocketPort INFINITY cards */ + + { RP_ID(0x0040), RP_CAP(8, 0) }, /* INF Octa, RJ45, selectable */ + { RP_ID(0x0041), RP_CAP(32, 0) }, /* INF 32, ext interface */ + { RP_ID(0x0042), RP_CAP(8, 0) }, /* INF Octa, ext interface */ + { RP_ID(0x0043), RP_CAP(16, 0) }, /* INF 16, ext interface */ + { RP_ID(0x0044), RP_CAP(4, 0) }, /* INF Quad, DB, selectable */ + { RP_ID(0x0045), RP_CAP(8, 0) }, /* INF Octa, DB, selectable */ + { RP_ID(0x0046), RP_CAP(4, 0) }, /* INF Quad, ext interface */ + { RP_ID(0x0047), RP_CAP(4, 0) }, /* INF Quad, RJ45 */ + { RP_ID(0x004a), RP_CAP(4, 0) }, /* INF Plus, Quad */ + { RP_ID(0x004b), RP_CAP(8, 0) }, /* INF Plus, Octa */ + { RP_ID(0x004c), RP_CAP(8, 0) }, /* INF III, Octa */ + { RP_ID(0x004d), RP_CAP(4, 0) }, /* INF III, Quad */ + { RP_ID(0x004e), RP_CAP(2, 0) }, /* INF Plus, 2, RS232 */ + { RP_ID(0x004f), RP_CAP(2, 1) }, /* INF Plus, 2, SMPTE */ + { RP_ID(0x0050), RP_CAP(4, 0) }, /* INF Plus, Quad, RJ45 */ + { RP_ID(0x0051), RP_CAP(8, 0) }, /* INF Plus, Octa, RJ45 */ + { RP_ID(0x0052), RP_CAP(8, 1) }, /* INF Octa, SMPTE */ + + /* RocketPort EXPRESS cards */ + + { RP_ID(0x0060), RP_CAP(8, 0) }, /* EXP Octa, RJ45, selectable */ + { RP_ID(0x0061), RP_CAP(32, 0) }, /* EXP 32, ext interface */ + { RP_ID(0x0062), RP_CAP(8, 0) }, /* EXP Octa, ext interface */ + { RP_ID(0x0063), RP_CAP(16, 0) }, /* EXP 16, ext interface */ + { RP_ID(0x0064), RP_CAP(4, 0) }, /* EXP Quad, DB, selectable */ + { RP_ID(0x0065), RP_CAP(8, 0) }, /* EXP Octa, DB, selectable */ + { RP_ID(0x0066), RP_CAP(4, 0) }, /* EXP Quad, ext interface */ + { RP_ID(0x0067), RP_CAP(4, 0) }, /* EXP Quad, RJ45 */ + { RP_ID(0x0068), RP_CAP(8, 0) }, /* EXP Octa, RJ11 */ + { RP_ID(0x0072), RP_CAP(8, 1) }, /* EXP Octa, SMPTE */ + { } +}; +MODULE_DEVICE_TABLE(pci, rp2_pci_tbl); + +static struct pci_driver rp2_pci_driver = { + .name = DRV_NAME, + .id_table = rp2_pci_tbl, + .probe = rp2_probe, + .remove = rp2_remove, +}; + +static int __init rp2_uart_init(void) +{ + int rc; + + rc = uart_register_driver(&rp2_uart_driver); + if (rc) + return rc; + + rc = pci_register_driver(&rp2_pci_driver); + if (rc) { + uart_unregister_driver(&rp2_uart_driver); + return rc; + } + + return 0; +} + +static void __exit rp2_uart_exit(void) +{ + pci_unregister_driver(&rp2_pci_driver); + uart_unregister_driver(&rp2_uart_driver); +} + +module_init(rp2_uart_init); +module_exit(rp2_uart_exit); + +MODULE_DESCRIPTION("Comtrol RocketPort EXPRESS/INFINITY driver"); +MODULE_AUTHOR("Kevin Cernekee <cernekee@gmail.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE(RP2_FW_NAME); diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index 2ca5959ec3fa..af6b3e3ad24d 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -29,6 +29,7 @@ #include <linux/init.h> #include <linux/console.h> #include <linux/sysrq.h> +#include <linux/platform_data/sa11x0-serial.h> #include <linux/platform_device.h> #include <linux/tty.h> #include <linux/tty_flip.h> @@ -39,7 +40,6 @@ #include <asm/irq.h> #include <mach/hardware.h> #include <mach/irqs.h> -#include <asm/mach/serial_sa1100.h> /* We've been assigned a range on the "Low-density serial ports" major */ #define SERIAL_SA1100_MAJOR 204 @@ -188,7 +188,6 @@ static void sa1100_enable_ms(struct uart_port *port) static void sa1100_rx_chars(struct sa1100_port *sport) { - struct tty_struct *tty = sport->port.state->port.tty; unsigned int status, ch, flg; status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | @@ -233,7 +232,7 @@ sa1100_rx_chars(struct sa1100_port *sport) status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | UTSR0_TO_SM(UART_GET_UTSR0(sport)); } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&sport->port.state->port); } static void sa1100_tx_chars(struct sa1100_port *sport) @@ -637,7 +636,7 @@ static void __init sa1100_init_ports(void) PPSR |= PPC_TXD1 | PPC_TXD3; } -void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns) +void sa1100_register_uart_fns(struct sa1100_port_fns *fns) { if (fns->get_mctrl) sa1100_pops.get_mctrl = fns->get_mctrl; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 7f04717176aa..2769a38d15b6 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -47,7 +47,6 @@ #include <asm/irq.h> #include <mach/hardware.h> -#include <mach/map.h> #include <plat/regs-serial.h> #include <plat/clock.h> @@ -221,10 +220,12 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) { struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; - struct tty_struct *tty = port->state->port.tty; unsigned int ufcon, ch, flag, ufstat, uerstat; + unsigned long flags; int max_count = 64; + spin_lock_irqsave(&port->lock, flags); + while (max_count-- > 0) { ufcon = rd_regl(port, S3C2410_UFCON); ufstat = rd_regl(port, S3C2410_UFSTAT); @@ -296,9 +297,10 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) ignore_char: continue; } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); out: + spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; } @@ -307,8 +309,11 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; struct circ_buf *xmit = &port->state->xmit; + unsigned long flags; int count = 256; + spin_lock_irqsave(&port->lock, flags); + if (port->x_char) { wr_regb(port, S3C2410_UTXH, port->x_char); port->icount.tx++; @@ -336,13 +341,17 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) port->icount.tx++; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { + spin_unlock(&port->lock); uart_write_wakeup(port); + spin_lock(&port->lock); + } if (uart_circ_empty(xmit)) s3c24xx_serial_stop_tx(port); out: + spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; } @@ -352,10 +361,8 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; unsigned int pend = rd_regl(port, S3C64XX_UINTP); - unsigned long flags; irqreturn_t ret = IRQ_HANDLED; - spin_lock_irqsave(&port->lock, flags); if (pend & S3C64XX_UINTM_RXD_MSK) { ret = s3c24xx_serial_rx_chars(irq, id); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK); @@ -364,7 +371,6 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) ret = s3c24xx_serial_tx_chars(irq, id); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK); } - spin_unlock_irqrestore(&port->lock, flags); return ret; } @@ -530,16 +536,16 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, switch (level) { case 3: if (!IS_ERR(ourport->baudclk)) - clk_disable(ourport->baudclk); + clk_disable_unprepare(ourport->baudclk); - clk_disable(ourport->clk); + clk_disable_unprepare(ourport->clk); break; case 0: - clk_enable(ourport->clk); + clk_prepare_enable(ourport->clk); if (!IS_ERR(ourport->baudclk)) - clk_enable(ourport->baudclk); + clk_prepare_enable(ourport->baudclk); break; default: @@ -713,11 +719,11 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, s3c24xx_serial_setsource(port, clk_sel); if (!IS_ERR(ourport->baudclk)) { - clk_disable(ourport->baudclk); + clk_disable_unprepare(ourport->baudclk); ourport->baudclk = ERR_PTR(-EINVAL); } - clk_enable(clk); + clk_prepare_enable(clk); ourport->baudclk = clk; ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; @@ -998,7 +1004,6 @@ static void s3c24xx_serial_resetport(struct uart_port *port, ucon &= ucon_mask; wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); - wr_regl(port, S3C2410_ULCON, cfg->ulcon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); @@ -1136,8 +1141,13 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, dbg("resource %p (%lx..%lx)\n", res, res->start, res->end); + port->membase = devm_ioremap(port->dev, res->start, resource_size(res)); + if (!port->membase) { + dev_err(port->dev, "failed to remap controller address\n"); + return -EBUSY; + } + port->mapbase = res->start; - port->membase = S3C_VA_UART + (res->start & 0xfffff); ret = platform_get_irq(platdev, 0); if (ret < 0) port->irq = 0; @@ -1256,7 +1266,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) return ret; } -static int __devexit s3c24xx_serial_remove(struct platform_device *dev) +static int s3c24xx_serial_remove(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); @@ -1287,9 +1297,9 @@ static int s3c24xx_serial_resume(struct device *dev) struct s3c24xx_uart_port *ourport = to_ourport(port); if (port) { - clk_enable(ourport->clk); + clk_prepare_enable(ourport->clk); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); - clk_disable(ourport->clk); + clk_disable_unprepare(ourport->clk); uart_resume_port(&s3c24xx_uart_drv, port); } @@ -1646,7 +1656,8 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #endif #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) || \ - defined(CONFIG_SOC_EXYNOS4412) || defined(CONFIG_SOC_EXYNOS5250) + defined(CONFIG_SOC_EXYNOS4412) || defined(CONFIG_SOC_EXYNOS5250) || \ + defined(CONFIG_SOC_EXYNOS5440) static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung Exynos4 UART", @@ -1701,24 +1712,32 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids); #ifdef CONFIG_OF static const struct of_device_id s3c24xx_uart_dt_match[] = { + { .compatible = "samsung,s3c2410-uart", + .data = (void *)S3C2410_SERIAL_DRV_DATA }, + { .compatible = "samsung,s3c2412-uart", + .data = (void *)S3C2412_SERIAL_DRV_DATA }, + { .compatible = "samsung,s3c2440-uart", + .data = (void *)S3C2440_SERIAL_DRV_DATA }, + { .compatible = "samsung,s3c6400-uart", + .data = (void *)S3C6400_SERIAL_DRV_DATA }, + { .compatible = "samsung,s5pv210-uart", + .data = (void *)S5PV210_SERIAL_DRV_DATA }, { .compatible = "samsung,exynos4210-uart", .data = (void *)EXYNOS4210_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); -#else -#define s3c24xx_uart_dt_match NULL #endif static struct platform_driver samsung_serial_driver = { .probe = s3c24xx_serial_probe, - .remove = __devexit_p(s3c24xx_serial_remove), + .remove = s3c24xx_serial_remove, .id_table = s3c24xx_serial_driver_ids, .driver = { .name = "samsung-uart", .owner = THIS_MODULE, .pm = SERIAL_SAMSUNG_PM_OPS, - .of_match_table = s3c24xx_uart_dt_match, + .of_match_table = of_match_ptr(s3c24xx_uart_dt_match), }, }; diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index f76b1688c5c8..a7cdec2962dd 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -384,7 +384,7 @@ static void sbd_receive_chars(struct sbd_port *sport) uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag); } - tty_flip_buffer_push(uport->state->port.tty); + tty_flip_buffer_push(&uport->state->port); } static void sbd_transmit_chars(struct sbd_port *sport) diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c index 9d664242b312..c9735680762d 100644 --- a/drivers/tty/serial/sc26xx.c +++ b/drivers/tty/serial/sc26xx.c @@ -136,16 +136,17 @@ static void sc26xx_disable_irq(struct uart_port *port, int mask) WRITE_SC(port, IMR, up->imr); } -static struct tty_struct *receive_chars(struct uart_port *port) +static bool receive_chars(struct uart_port *port) { - struct tty_struct *tty = NULL; + struct tty_port *tport = NULL; int limit = 10000; unsigned char ch; char flag; u8 status; + /* FIXME what is this trying to achieve? */ if (port->state != NULL) /* Unopened serial console */ - tty = port->state->port.tty; + tport = &port->state->port; while (limit-- > 0) { status = READ_SC_PORT(port, SR); @@ -185,9 +186,9 @@ static struct tty_struct *receive_chars(struct uart_port *port) if (status & port->ignore_status_mask) continue; - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(tport, ch, flag); } - return tty; + return !!tport; } static void transmit_chars(struct uart_port *port) @@ -217,36 +218,36 @@ static void transmit_chars(struct uart_port *port) static irqreturn_t sc26xx_interrupt(int irq, void *dev_id) { struct uart_sc26xx_port *up = dev_id; - struct tty_struct *tty; unsigned long flags; + bool push; u8 isr; spin_lock_irqsave(&up->port[0].lock, flags); - tty = NULL; + push = false; isr = READ_SC(&up->port[0], ISR); if (isr & ISR_TXRDYA) transmit_chars(&up->port[0]); if (isr & ISR_RXRDYA) - tty = receive_chars(&up->port[0]); + push = receive_chars(&up->port[0]); spin_unlock(&up->port[0].lock); - if (tty) - tty_flip_buffer_push(tty); + if (push) + tty_flip_buffer_push(&up->port[0].state->port); spin_lock(&up->port[1].lock); - tty = NULL; + push = false; if (isr & ISR_TXRDYB) transmit_chars(&up->port[1]); if (isr & ISR_RXRDYB) - tty = receive_chars(&up->port[1]); + push = receive_chars(&up->port[1]); spin_unlock_irqrestore(&up->port[1].lock, flags); - if (tty) - tty_flip_buffer_push(tty); + if (push) + tty_flip_buffer_push(&up->port[1].state->port); return IRQ_HANDLED; } @@ -621,7 +622,7 @@ static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos) return bit ? (1 << (bit - 1)) : 0; } -static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up, +static void sc26xx_init_masks(struct uart_sc26xx_port *up, int line, unsigned int data) { up->dtr_mask[line] = sc26xx_flags2mask(data, 0); @@ -632,7 +633,7 @@ static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up, up->ri_mask[line] = sc26xx_flags2mask(data, 20); } -static int __devinit sc26xx_probe(struct platform_device *dev) +static int sc26xx_probe(struct platform_device *dev) { struct resource *res; struct uart_sc26xx_port *up; @@ -733,7 +734,7 @@ static int __exit sc26xx_driver_remove(struct platform_device *dev) static struct platform_driver sc26xx_driver = { .probe = sc26xx_probe, - .remove = __devexit_p(sc26xx_driver_remove), + .remove = sc26xx_driver_remove, .driver = { .name = "SC26xx", .owner = THIS_MODULE, diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index e821068cd95b..08dbfb88d42c 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -15,6 +15,7 @@ #define SUPPORT_SYSRQ #endif +#include <linux/err.h> #include <linux/module.h> #include <linux/device.h> #include <linux/console.h> @@ -23,8 +24,9 @@ #include <linux/io.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/spinlock.h> #include <linux/platform_device.h> -#include <linux/platform_data/sccnxp.h> +#include <linux/platform_data/serial-sccnxp.h> #define SCCNXP_NAME "uart-sccnxp" #define SCCNXP_MAJOR 204 @@ -106,6 +108,7 @@ enum { struct sccnxp_port { struct uart_driver uart; struct uart_port port[SCCNXP_MAX_UARTS]; + bool opened[SCCNXP_MAX_UARTS]; const char *name; int irq; @@ -122,7 +125,10 @@ struct sccnxp_port { struct console console; #endif - struct mutex sccnxp_mutex; + spinlock_t lock; + + bool poll; + struct timer_list timer; struct sccnxp_pdata pdata; }; @@ -174,14 +180,12 @@ static int sccnxp_update_best_err(int a, int b, int *besterr) return 1; } -struct baud_table { +static const struct { u8 csr; u8 acr; u8 mr0; int baud; -}; - -const struct baud_table baud_std[] = { +} baud_std[] = { { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, }, { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, }, { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, }, @@ -285,10 +289,6 @@ static void sccnxp_handle_rx(struct uart_port *port) { u8 sr; unsigned int ch, flag; - struct tty_struct *tty = tty_port_tty_get(&port->state->port); - - if (!tty) - return; for (;;) { sr = sccnxp_port_read(port, SCCNXP_SR_REG); @@ -304,14 +304,19 @@ static void sccnxp_handle_rx(struct uart_port *port) if (unlikely(sr)) { if (sr & SR_BRK) { port->icount.brk++; + sccnxp_port_write(port, SCCNXP_CR_REG, + CR_CMD_BREAK_RESET); if (uart_handle_break(port)) continue; } else if (sr & SR_PE) port->icount.parity++; else if (sr & SR_FE) port->icount.frame++; - else if (sr & SR_OVR) + else if (sr & SR_OVR) { port->icount.overrun++; + sccnxp_port_write(port, SCCNXP_CR_REG, + CR_CMD_STATUS_RESET); + } sr &= port->read_status_mask; if (sr & SR_BRK) @@ -333,9 +338,7 @@ static void sccnxp_handle_rx(struct uart_port *port) uart_insert_char(port, sr, SR_OVR, ch, flag); } - tty_flip_buffer_push(tty); - - tty_kref_put(tty); + tty_flip_buffer_push(&port->state->port); } static void sccnxp_handle_tx(struct uart_port *port) @@ -377,31 +380,48 @@ static void sccnxp_handle_tx(struct uart_port *port) uart_write_wakeup(port); } -static irqreturn_t sccnxp_ist(int irq, void *dev_id) +static void sccnxp_handle_events(struct sccnxp_port *s) { int i; u8 isr; - struct sccnxp_port *s = (struct sccnxp_port *)dev_id; - - mutex_lock(&s->sccnxp_mutex); - for (;;) { + do { isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG); isr &= s->imr; if (!isr) break; - dev_dbg(s->port[0].dev, "IRQ status: 0x%02x\n", isr); - for (i = 0; i < s->uart.nr; i++) { - if (isr & ISR_RXRDY(i)) + if (s->opened[i] && (isr & ISR_RXRDY(i))) sccnxp_handle_rx(&s->port[i]); - if (isr & ISR_TXRDY(i)) + if (s->opened[i] && (isr & ISR_TXRDY(i))) sccnxp_handle_tx(&s->port[i]); } - } + } while (1); +} + +static void sccnxp_timer(unsigned long data) +{ + struct sccnxp_port *s = (struct sccnxp_port *)data; + unsigned long flags; - mutex_unlock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); + sccnxp_handle_events(s); + spin_unlock_irqrestore(&s->lock, flags); + + if (!timer_pending(&s->timer)) + mod_timer(&s->timer, jiffies + + usecs_to_jiffies(s->pdata.poll_time_us)); +} + +static irqreturn_t sccnxp_ist(int irq, void *dev_id) +{ + struct sccnxp_port *s = (struct sccnxp_port *)dev_id; + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + sccnxp_handle_events(s); + spin_unlock_irqrestore(&s->lock, flags); return IRQ_HANDLED; } @@ -409,8 +429,9 @@ static irqreturn_t sccnxp_ist(int irq, void *dev_id) static void sccnxp_start_tx(struct uart_port *port) { struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned long flags; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); /* Set direction to output */ if (s->flags & SCCNXP_HAVE_IO) @@ -418,7 +439,7 @@ static void sccnxp_start_tx(struct uart_port *port) sccnxp_enable_irq(port, IMR_TXRDY); - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); } static void sccnxp_stop_tx(struct uart_port *port) @@ -429,20 +450,22 @@ static void sccnxp_stop_tx(struct uart_port *port) static void sccnxp_stop_rx(struct uart_port *port) { struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned long flags; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE); - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); } static unsigned int sccnxp_tx_empty(struct uart_port *port) { u8 val; + unsigned long flags; struct sccnxp_port *s = dev_get_drvdata(port->dev); - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); val = sccnxp_port_read(port, SCCNXP_SR_REG); - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); return (val & SR_TXEMT) ? TIOCSER_TEMT : 0; } @@ -455,28 +478,30 @@ static void sccnxp_enable_ms(struct uart_port *port) static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned long flags; if (!(s->flags & SCCNXP_HAVE_IO)) return; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR); sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS); - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); } static unsigned int sccnxp_get_mctrl(struct uart_port *port) { u8 bitmask, ipr; + unsigned long flags; struct sccnxp_port *s = dev_get_drvdata(port->dev); unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; if (!(s->flags & SCCNXP_HAVE_IO)) return mctrl; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG); @@ -505,7 +530,7 @@ static unsigned int sccnxp_get_mctrl(struct uart_port *port) mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0; } - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); return mctrl; } @@ -513,21 +538,23 @@ static unsigned int sccnxp_get_mctrl(struct uart_port *port) static void sccnxp_break_ctl(struct uart_port *port, int break_state) { struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned long flags; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); sccnxp_port_write(port, SCCNXP_CR_REG, break_state ? CR_CMD_START_BREAK : CR_CMD_STOP_BREAK); - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); } static void sccnxp_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned long flags; u8 mr1, mr2; int baud; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); /* Mask termios capabilities we don't support */ termios->c_cflag &= ~CMSPAR; @@ -594,20 +621,22 @@ static void sccnxp_set_termios(struct uart_port *port, /* Update timeout according to new baud rate */ uart_update_timeout(port, termios->c_cflag, baud); + /* Report actual baudrate back to core */ if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); /* Enable RX & TX */ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); } static int sccnxp_startup(struct uart_port *port) { struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned long flags; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); if (s->flags & SCCNXP_HAVE_IO) { /* Outputs are controlled manually */ @@ -626,7 +655,9 @@ static int sccnxp_startup(struct uart_port *port) /* Enable RX interrupt */ sccnxp_enable_irq(port, IMR_RXRDY); - mutex_unlock(&s->sccnxp_mutex); + s->opened[port->line] = 1; + + spin_unlock_irqrestore(&s->lock, flags); return 0; } @@ -634,8 +665,11 @@ static int sccnxp_startup(struct uart_port *port) static void sccnxp_shutdown(struct uart_port *port) { struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned long flags; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); + + s->opened[port->line] = 0; /* Disable interrupts */ sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY); @@ -647,7 +681,7 @@ static void sccnxp_shutdown(struct uart_port *port) if (s->flags & SCCNXP_HAVE_IO) sccnxp_set_bit(port, DIR_OP, 0); - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); } static const char *sccnxp_type(struct uart_port *port) @@ -721,10 +755,11 @@ static void sccnxp_console_write(struct console *co, const char *c, unsigned n) { struct sccnxp_port *s = (struct sccnxp_port *)co->data; struct uart_port *port = &s->port[co->index]; + unsigned long flags; - mutex_lock(&s->sccnxp_mutex); + spin_lock_irqsave(&s->lock, flags); uart_console_write(port, c, n, sccnxp_console_putchar); - mutex_unlock(&s->sccnxp_mutex); + spin_unlock_irqrestore(&s->lock, flags); } static int sccnxp_console_setup(struct console *co, char *options) @@ -740,7 +775,7 @@ static int sccnxp_console_setup(struct console *co, char *options) } #endif -static int __devinit sccnxp_probe(struct platform_device *pdev) +static int sccnxp_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); int chiptype = pdev->id_entry->driver_data; @@ -763,7 +798,7 @@ static int __devinit sccnxp_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, s); - mutex_init(&s->sccnxp_mutex); + spin_lock_init(&s->lock); /* Individual chip settings */ switch (chiptype) { @@ -860,11 +895,19 @@ static int __devinit sccnxp_probe(struct platform_device *pdev) } else memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); - s->irq = platform_get_irq(pdev, 0); - if (s->irq <= 0) { - dev_err(&pdev->dev, "Missing irq resource data\n"); - ret = -ENXIO; - goto err_out; + if (s->pdata.poll_time_us) { + dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n", + s->pdata.poll_time_us); + s->poll = 1; + } + + if (!s->poll) { + s->irq = platform_get_irq(pdev, 0); + if (s->irq < 0) { + dev_err(&pdev->dev, "Missing irq resource data\n"); + ret = -ENXIO; + goto err_out; + } } /* Check input frequency */ @@ -875,10 +918,9 @@ static int __devinit sccnxp_probe(struct platform_device *pdev) goto err_out; } - membase = devm_request_and_ioremap(&pdev->dev, res); - if (!membase) { - dev_err(&pdev->dev, "Failed to ioremap\n"); - ret = -EIO; + membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(membase)) { + ret = PTR_ERR(membase); goto err_out; } @@ -929,13 +971,23 @@ static int __devinit sccnxp_probe(struct platform_device *pdev) if (s->pdata.init) s->pdata.init(); - ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, sccnxp_ist, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(&pdev->dev), s); - if (!ret) + if (!s->poll) { + ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, + sccnxp_ist, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + dev_name(&pdev->dev), s); + if (!ret) + return 0; + + dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq); + } else { + init_timer(&s->timer); + setup_timer(&s->timer, sccnxp_timer, (unsigned long)s); + mod_timer(&s->timer, jiffies + + usecs_to_jiffies(s->pdata.poll_time_us)); return 0; - - dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq); + } err_out: platform_set_drvdata(pdev, NULL); @@ -943,12 +995,15 @@ err_out: return ret; } -static int __devexit sccnxp_remove(struct platform_device *pdev) +static int sccnxp_remove(struct platform_device *pdev) { int i; struct sccnxp_port *s = platform_get_drvdata(pdev); - devm_free_irq(&pdev->dev, s->irq, s); + if (!s->poll) + devm_free_irq(&pdev->dev, s->irq, s); + else + del_timer_sync(&s->timer); for (i = 0; i < s->uart.nr; i++) uart_remove_one_port(&s->uart, &s->port[i]); @@ -981,7 +1036,7 @@ static struct platform_driver sccnxp_uart_driver = { .owner = THIS_MODULE, }, .probe = sccnxp_probe, - .remove = __devexit_p(sccnxp_remove), + .remove = sccnxp_remove, .id_table = sccnxp_id_table, }; module_platform_driver(sccnxp_uart_driver); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c new file mode 100644 index 000000000000..372de8ade76a --- /dev/null +++ b/drivers/tty/serial/serial-tegra.c @@ -0,0 +1,1401 @@ +/* + * serial_tegra.c + * + * High-speed serial driver for NVIDIA Tegra SoCs + * + * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. + * + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pagemap.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_8250.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/termios.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> + +#include <linux/clk/tegra.h> + +#define TEGRA_UART_TYPE "TEGRA_UART" +#define TX_EMPTY_STATUS (UART_LSR_TEMT | UART_LSR_THRE) +#define BYTES_TO_ALIGN(x) ((unsigned long)(x) & 0x3) + +#define TEGRA_UART_RX_DMA_BUFFER_SIZE 4096 +#define TEGRA_UART_LSR_TXFIFO_FULL 0x100 +#define TEGRA_UART_IER_EORD 0x20 +#define TEGRA_UART_MCR_RTS_EN 0x40 +#define TEGRA_UART_MCR_CTS_EN 0x20 +#define TEGRA_UART_LSR_ANY (UART_LSR_OE | UART_LSR_BI | \ + UART_LSR_PE | UART_LSR_FE) +#define TEGRA_UART_IRDA_CSR 0x08 +#define TEGRA_UART_SIR_ENABLED 0x80 + +#define TEGRA_UART_TX_PIO 1 +#define TEGRA_UART_TX_DMA 2 +#define TEGRA_UART_MIN_DMA 16 +#define TEGRA_UART_FIFO_SIZE 32 + +/* + * Tx fifo trigger level setting in tegra uart is in + * reverse way then conventional uart. + */ +#define TEGRA_UART_TX_TRIG_16B 0x00 +#define TEGRA_UART_TX_TRIG_8B 0x10 +#define TEGRA_UART_TX_TRIG_4B 0x20 +#define TEGRA_UART_TX_TRIG_1B 0x30 + +#define TEGRA_UART_MAXIMUM 5 + +/* Default UART setting when started: 115200 no parity, stop, 8 data bits */ +#define TEGRA_UART_DEFAULT_BAUD 115200 +#define TEGRA_UART_DEFAULT_LSR UART_LCR_WLEN8 + +/* Tx transfer mode */ +#define TEGRA_TX_PIO 1 +#define TEGRA_TX_DMA 2 + +/** + * tegra_uart_chip_data: SOC specific data. + * + * @tx_fifo_full_status: Status flag available for checking tx fifo full. + * @allow_txfifo_reset_fifo_mode: allow_tx fifo reset with fifo mode or not. + * Tegra30 does not allow this. + * @support_clk_src_div: Clock source support the clock divider. + */ +struct tegra_uart_chip_data { + bool tx_fifo_full_status; + bool allow_txfifo_reset_fifo_mode; + bool support_clk_src_div; +}; + +struct tegra_uart_port { + struct uart_port uport; + const struct tegra_uart_chip_data *cdata; + + struct clk *uart_clk; + unsigned int current_baud; + + /* Register shadow */ + unsigned long fcr_shadow; + unsigned long mcr_shadow; + unsigned long lcr_shadow; + unsigned long ier_shadow; + bool rts_active; + + int tx_in_progress; + unsigned int tx_bytes; + + bool enable_modem_interrupt; + + bool rx_timeout; + int rx_in_progress; + int symb_bit; + int dma_req_sel; + + struct dma_chan *rx_dma_chan; + struct dma_chan *tx_dma_chan; + dma_addr_t rx_dma_buf_phys; + dma_addr_t tx_dma_buf_phys; + unsigned char *rx_dma_buf_virt; + unsigned char *tx_dma_buf_virt; + struct dma_async_tx_descriptor *tx_dma_desc; + struct dma_async_tx_descriptor *rx_dma_desc; + dma_cookie_t tx_cookie; + dma_cookie_t rx_cookie; + int tx_bytes_requested; + int rx_bytes_requested; +}; + +static void tegra_uart_start_next_tx(struct tegra_uart_port *tup); +static int tegra_uart_start_rx_dma(struct tegra_uart_port *tup); + +static inline unsigned long tegra_uart_read(struct tegra_uart_port *tup, + unsigned long reg) +{ + return readl(tup->uport.membase + (reg << tup->uport.regshift)); +} + +static inline void tegra_uart_write(struct tegra_uart_port *tup, unsigned val, + unsigned long reg) +{ + writel(val, tup->uport.membase + (reg << tup->uport.regshift)); +} + +static inline struct tegra_uart_port *to_tegra_uport(struct uart_port *u) +{ + return container_of(u, struct tegra_uart_port, uport); +} + +static unsigned int tegra_uart_get_mctrl(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + + /* + * RI - Ring detector is active + * CD/DCD/CAR - Carrier detect is always active. For some reason + * linux has different names for carrier detect. + * DSR - Data Set ready is active as the hardware doesn't support it. + * Don't know if the linux support this yet? + * CTS - Clear to send. Always set to active, as the hardware handles + * CTS automatically. + */ + if (tup->enable_modem_interrupt) + return TIOCM_RI | TIOCM_CD | TIOCM_DSR | TIOCM_CTS; + return TIOCM_CTS; +} + +static void set_rts(struct tegra_uart_port *tup, bool active) +{ + unsigned long mcr; + + mcr = tup->mcr_shadow; + if (active) + mcr |= TEGRA_UART_MCR_RTS_EN; + else + mcr &= ~TEGRA_UART_MCR_RTS_EN; + if (mcr != tup->mcr_shadow) { + tegra_uart_write(tup, mcr, UART_MCR); + tup->mcr_shadow = mcr; + } + return; +} + +static void set_dtr(struct tegra_uart_port *tup, bool active) +{ + unsigned long mcr; + + mcr = tup->mcr_shadow; + if (active) + mcr |= UART_MCR_DTR; + else + mcr &= ~UART_MCR_DTR; + if (mcr != tup->mcr_shadow) { + tegra_uart_write(tup, mcr, UART_MCR); + tup->mcr_shadow = mcr; + } + return; +} + +static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + unsigned long mcr; + int dtr_enable; + + mcr = tup->mcr_shadow; + tup->rts_active = !!(mctrl & TIOCM_RTS); + set_rts(tup, tup->rts_active); + + dtr_enable = !!(mctrl & TIOCM_DTR); + set_dtr(tup, dtr_enable); + return; +} + +static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + unsigned long lcr; + + lcr = tup->lcr_shadow; + if (break_ctl) + lcr |= UART_LCR_SBC; + else + lcr &= ~UART_LCR_SBC; + tegra_uart_write(tup, lcr, UART_LCR); + tup->lcr_shadow = lcr; +} + +/* Wait for a symbol-time. */ +static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup, + unsigned int syms) +{ + if (tup->current_baud) + udelay(DIV_ROUND_UP(syms * tup->symb_bit * 1000000, + tup->current_baud)); +} + +static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) +{ + unsigned long fcr = tup->fcr_shadow; + + if (tup->cdata->allow_txfifo_reset_fifo_mode) { + fcr |= fcr_bits & (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + tegra_uart_write(tup, fcr, UART_FCR); + } else { + fcr &= ~UART_FCR_ENABLE_FIFO; + tegra_uart_write(tup, fcr, UART_FCR); + udelay(60); + fcr |= fcr_bits & (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + tegra_uart_write(tup, fcr, UART_FCR); + fcr |= UART_FCR_ENABLE_FIFO; + tegra_uart_write(tup, fcr, UART_FCR); + } + + /* Dummy read to ensure the write is posted */ + tegra_uart_read(tup, UART_SCR); + + /* Wait for the flush to propagate. */ + tegra_uart_wait_sym_time(tup, 1); +} + +static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) +{ + unsigned long rate; + unsigned int divisor; + unsigned long lcr; + int ret; + + if (tup->current_baud == baud) + return 0; + + if (tup->cdata->support_clk_src_div) { + rate = baud * 16; + ret = clk_set_rate(tup->uart_clk, rate); + if (ret < 0) { + dev_err(tup->uport.dev, + "clk_set_rate() failed for rate %lu\n", rate); + return ret; + } + divisor = 1; + } else { + rate = clk_get_rate(tup->uart_clk); + divisor = DIV_ROUND_CLOSEST(rate, baud * 16); + } + + lcr = tup->lcr_shadow; + lcr |= UART_LCR_DLAB; + tegra_uart_write(tup, lcr, UART_LCR); + + tegra_uart_write(tup, divisor & 0xFF, UART_TX); + tegra_uart_write(tup, ((divisor >> 8) & 0xFF), UART_IER); + + lcr &= ~UART_LCR_DLAB; + tegra_uart_write(tup, lcr, UART_LCR); + + /* Dummy read to ensure the write is posted */ + tegra_uart_read(tup, UART_SCR); + + tup->current_baud = baud; + + /* wait two character intervals at new rate */ + tegra_uart_wait_sym_time(tup, 2); + return 0; +} + +static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup, + unsigned long lsr) +{ + char flag = TTY_NORMAL; + + if (unlikely(lsr & TEGRA_UART_LSR_ANY)) { + if (lsr & UART_LSR_OE) { + /* Overrrun error */ + flag |= TTY_OVERRUN; + tup->uport.icount.overrun++; + dev_err(tup->uport.dev, "Got overrun errors\n"); + } else if (lsr & UART_LSR_PE) { + /* Parity error */ + flag |= TTY_PARITY; + tup->uport.icount.parity++; + dev_err(tup->uport.dev, "Got Parity errors\n"); + } else if (lsr & UART_LSR_FE) { + flag |= TTY_FRAME; + tup->uport.icount.frame++; + dev_err(tup->uport.dev, "Got frame errors\n"); + } else if (lsr & UART_LSR_BI) { + dev_err(tup->uport.dev, "Got Break\n"); + tup->uport.icount.brk++; + /* If FIFO read error without any data, reset Rx FIFO */ + if (!(lsr & UART_LSR_DR) && (lsr & UART_LSR_FIFOE)) + tegra_uart_fifo_reset(tup, UART_FCR_CLEAR_RCVR); + } + } + return flag; +} + +static int tegra_uart_request_port(struct uart_port *u) +{ + return 0; +} + +static void tegra_uart_release_port(struct uart_port *u) +{ + /* Nothing to do here */ +} + +static void tegra_uart_fill_tx_fifo(struct tegra_uart_port *tup, int max_bytes) +{ + struct circ_buf *xmit = &tup->uport.state->xmit; + int i; + + for (i = 0; i < max_bytes; i++) { + BUG_ON(uart_circ_empty(xmit)); + if (tup->cdata->tx_fifo_full_status) { + unsigned long lsr = tegra_uart_read(tup, UART_LSR); + if ((lsr & TEGRA_UART_LSR_TXFIFO_FULL)) + break; + } + tegra_uart_write(tup, xmit->buf[xmit->tail], UART_TX); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + tup->uport.icount.tx++; + } +} + +static void tegra_uart_start_pio_tx(struct tegra_uart_port *tup, + unsigned int bytes) +{ + if (bytes > TEGRA_UART_MIN_DMA) + bytes = TEGRA_UART_MIN_DMA; + + tup->tx_in_progress = TEGRA_UART_TX_PIO; + tup->tx_bytes = bytes; + tup->ier_shadow |= UART_IER_THRI; + tegra_uart_write(tup, tup->ier_shadow, UART_IER); +} + +static void tegra_uart_tx_dma_complete(void *args) +{ + struct tegra_uart_port *tup = args; + struct circ_buf *xmit = &tup->uport.state->xmit; + struct dma_tx_state state; + unsigned long flags; + int count; + + dmaengine_tx_status(tup->tx_dma_chan, tup->rx_cookie, &state); + count = tup->tx_bytes_requested - state.residue; + async_tx_ack(tup->tx_dma_desc); + spin_lock_irqsave(&tup->uport.lock, flags); + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + tup->tx_in_progress = 0; + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&tup->uport); + tegra_uart_start_next_tx(tup); + spin_unlock_irqrestore(&tup->uport.lock, flags); +} + +static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup, + unsigned long count) +{ + struct circ_buf *xmit = &tup->uport.state->xmit; + dma_addr_t tx_phys_addr; + + dma_sync_single_for_device(tup->uport.dev, tup->tx_dma_buf_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + tup->tx_bytes = count & ~(0xF); + tx_phys_addr = tup->tx_dma_buf_phys + xmit->tail; + tup->tx_dma_desc = dmaengine_prep_slave_single(tup->tx_dma_chan, + tx_phys_addr, tup->tx_bytes, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT); + if (!tup->tx_dma_desc) { + dev_err(tup->uport.dev, "Not able to get desc for Tx\n"); + return -EIO; + } + + tup->tx_dma_desc->callback = tegra_uart_tx_dma_complete; + tup->tx_dma_desc->callback_param = tup; + tup->tx_in_progress = TEGRA_UART_TX_DMA; + tup->tx_bytes_requested = tup->tx_bytes; + tup->tx_cookie = dmaengine_submit(tup->tx_dma_desc); + dma_async_issue_pending(tup->tx_dma_chan); + return 0; +} + +static void tegra_uart_start_next_tx(struct tegra_uart_port *tup) +{ + unsigned long tail; + unsigned long count; + struct circ_buf *xmit = &tup->uport.state->xmit; + + tail = (unsigned long)&xmit->buf[xmit->tail]; + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (!count) + return; + + if (count < TEGRA_UART_MIN_DMA) + tegra_uart_start_pio_tx(tup, count); + else if (BYTES_TO_ALIGN(tail) > 0) + tegra_uart_start_pio_tx(tup, BYTES_TO_ALIGN(tail)); + else + tegra_uart_start_tx_dma(tup, count); +} + +/* Called by serial core driver with u->lock taken. */ +static void tegra_uart_start_tx(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + struct circ_buf *xmit = &u->state->xmit; + + if (!uart_circ_empty(xmit) && !tup->tx_in_progress) + tegra_uart_start_next_tx(tup); +} + +static unsigned int tegra_uart_tx_empty(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + unsigned int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&u->lock, flags); + if (!tup->tx_in_progress) { + unsigned long lsr = tegra_uart_read(tup, UART_LSR); + if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS) + ret = TIOCSER_TEMT; + } + spin_unlock_irqrestore(&u->lock, flags); + return ret; +} + +static void tegra_uart_stop_tx(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + struct circ_buf *xmit = &tup->uport.state->xmit; + struct dma_tx_state state; + int count; + + dmaengine_terminate_all(tup->tx_dma_chan); + dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); + count = tup->tx_bytes_requested - state.residue; + async_tx_ack(tup->tx_dma_desc); + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + tup->tx_in_progress = 0; + return; +} + +static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup) +{ + struct circ_buf *xmit = &tup->uport.state->xmit; + + tegra_uart_fill_tx_fifo(tup, tup->tx_bytes); + tup->tx_in_progress = 0; + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&tup->uport); + tegra_uart_start_next_tx(tup); + return; +} + +static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, + struct tty_port *tty) +{ + do { + char flag = TTY_NORMAL; + unsigned long lsr = 0; + unsigned char ch; + + lsr = tegra_uart_read(tup, UART_LSR); + if (!(lsr & UART_LSR_DR)) + break; + + flag = tegra_uart_decode_rx_error(tup, lsr); + ch = (unsigned char) tegra_uart_read(tup, UART_RX); + tup->uport.icount.rx++; + + if (!uart_handle_sysrq_char(&tup->uport, ch) && tty) + tty_insert_flip_char(tty, ch, flag); + } while (1); + + return; +} + +static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, + struct tty_port *tty, int count) +{ + int copied; + + tup->uport.icount.rx += count; + if (!tty) { + dev_err(tup->uport.dev, "No tty port\n"); + return; + } + dma_sync_single_for_cpu(tup->uport.dev, tup->rx_dma_buf_phys, + TEGRA_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + copied = tty_insert_flip_string(tty, + ((unsigned char *)(tup->rx_dma_buf_virt)), count); + if (copied != count) { + WARN_ON(1); + dev_err(tup->uport.dev, "RxData copy to tty layer failed\n"); + } + dma_sync_single_for_device(tup->uport.dev, tup->rx_dma_buf_phys, + TEGRA_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); +} + +static void tegra_uart_rx_dma_complete(void *args) +{ + struct tegra_uart_port *tup = args; + struct uart_port *u = &tup->uport; + int count = tup->rx_bytes_requested; + struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); + struct tty_port *port = &u->state->port; + unsigned long flags; + + async_tx_ack(tup->rx_dma_desc); + spin_lock_irqsave(&u->lock, flags); + + /* Deactivate flow control to stop sender */ + if (tup->rts_active) + set_rts(tup, false); + + /* If we are here, DMA is stopped */ + if (count) + tegra_uart_copy_rx_to_tty(tup, port, count); + + tegra_uart_handle_rx_pio(tup, port); + if (tty) { + tty_flip_buffer_push(port); + tty_kref_put(tty); + } + tegra_uart_start_rx_dma(tup); + + /* Activate flow control to start transfer */ + if (tup->rts_active) + set_rts(tup, true); + + spin_unlock_irqrestore(&u->lock, flags); +} + +static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup) +{ + struct dma_tx_state state; + struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); + struct tty_port *port = &tup->uport.state->port; + int count; + + /* Deactivate flow control to stop sender */ + if (tup->rts_active) + set_rts(tup, false); + + dmaengine_terminate_all(tup->rx_dma_chan); + dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + count = tup->rx_bytes_requested - state.residue; + + /* If we are here, DMA is stopped */ + if (count) + tegra_uart_copy_rx_to_tty(tup, port, count); + + tegra_uart_handle_rx_pio(tup, port); + if (tty) { + tty_flip_buffer_push(port); + tty_kref_put(tty); + } + tegra_uart_start_rx_dma(tup); + + if (tup->rts_active) + set_rts(tup, true); +} + +static int tegra_uart_start_rx_dma(struct tegra_uart_port *tup) +{ + unsigned int count = TEGRA_UART_RX_DMA_BUFFER_SIZE; + + tup->rx_dma_desc = dmaengine_prep_slave_single(tup->rx_dma_chan, + tup->rx_dma_buf_phys, count, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!tup->rx_dma_desc) { + dev_err(tup->uport.dev, "Not able to get desc for Rx\n"); + return -EIO; + } + + tup->rx_dma_desc->callback = tegra_uart_rx_dma_complete; + tup->rx_dma_desc->callback_param = tup; + dma_sync_single_for_device(tup->uport.dev, tup->rx_dma_buf_phys, + count, DMA_TO_DEVICE); + tup->rx_bytes_requested = count; + tup->rx_cookie = dmaengine_submit(tup->rx_dma_desc); + dma_async_issue_pending(tup->rx_dma_chan); + return 0; +} + +static void tegra_uart_handle_modem_signal_change(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + unsigned long msr; + + msr = tegra_uart_read(tup, UART_MSR); + if (!(msr & UART_MSR_ANY_DELTA)) + return; + + if (msr & UART_MSR_TERI) + tup->uport.icount.rng++; + if (msr & UART_MSR_DDSR) + tup->uport.icount.dsr++; + /* We may only get DDCD when HW init and reset */ + if (msr & UART_MSR_DDCD) + uart_handle_dcd_change(&tup->uport, msr & UART_MSR_DCD); + /* Will start/stop_tx accordingly */ + if (msr & UART_MSR_DCTS) + uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS); + return; +} + +static irqreturn_t tegra_uart_isr(int irq, void *data) +{ + struct tegra_uart_port *tup = data; + struct uart_port *u = &tup->uport; + unsigned long iir; + unsigned long ier; + bool is_rx_int = false; + unsigned long flags; + + spin_lock_irqsave(&u->lock, flags); + while (1) { + iir = tegra_uart_read(tup, UART_IIR); + if (iir & UART_IIR_NO_INT) { + if (is_rx_int) { + tegra_uart_handle_rx_dma(tup); + if (tup->rx_in_progress) { + ier = tup->ier_shadow; + ier |= (UART_IER_RLSI | UART_IER_RTOIE | + TEGRA_UART_IER_EORD); + tup->ier_shadow = ier; + tegra_uart_write(tup, ier, UART_IER); + } + } + spin_unlock_irqrestore(&u->lock, flags); + return IRQ_HANDLED; + } + + switch ((iir >> 1) & 0x7) { + case 0: /* Modem signal change interrupt */ + tegra_uart_handle_modem_signal_change(u); + break; + + case 1: /* Transmit interrupt only triggered when using PIO */ + tup->ier_shadow &= ~UART_IER_THRI; + tegra_uart_write(tup, tup->ier_shadow, UART_IER); + tegra_uart_handle_tx_pio(tup); + break; + + case 4: /* End of data */ + case 6: /* Rx timeout */ + case 2: /* Receive */ + if (!is_rx_int) { + is_rx_int = true; + /* Disable Rx interrupts */ + ier = tup->ier_shadow; + ier |= UART_IER_RDI; + tegra_uart_write(tup, ier, UART_IER); + ier &= ~(UART_IER_RDI | UART_IER_RLSI | + UART_IER_RTOIE | TEGRA_UART_IER_EORD); + tup->ier_shadow = ier; + tegra_uart_write(tup, ier, UART_IER); + } + break; + + case 3: /* Receive error */ + tegra_uart_decode_rx_error(tup, + tegra_uart_read(tup, UART_LSR)); + break; + + case 5: /* break nothing to handle */ + case 7: /* break nothing to handle */ + break; + } + } +} + +static void tegra_uart_stop_rx(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); + struct tty_port *port = &u->state->port; + struct dma_tx_state state; + unsigned long ier; + int count; + + if (tup->rts_active) + set_rts(tup, false); + + if (!tup->rx_in_progress) + return; + + tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */ + + ier = tup->ier_shadow; + ier &= ~(UART_IER_RDI | UART_IER_RLSI | UART_IER_RTOIE | + TEGRA_UART_IER_EORD); + tup->ier_shadow = ier; + tegra_uart_write(tup, ier, UART_IER); + tup->rx_in_progress = 0; + if (tup->rx_dma_chan) { + dmaengine_terminate_all(tup->rx_dma_chan); + dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + async_tx_ack(tup->rx_dma_desc); + count = tup->rx_bytes_requested - state.residue; + tegra_uart_copy_rx_to_tty(tup, port, count); + tegra_uart_handle_rx_pio(tup, port); + } else { + tegra_uart_handle_rx_pio(tup, port); + } + if (tty) { + tty_flip_buffer_push(port); + tty_kref_put(tty); + } + return; +} + +static void tegra_uart_hw_deinit(struct tegra_uart_port *tup) +{ + unsigned long flags; + unsigned long char_time = DIV_ROUND_UP(10000000, tup->current_baud); + unsigned long fifo_empty_time = tup->uport.fifosize * char_time; + unsigned long wait_time; + unsigned long lsr; + unsigned long msr; + unsigned long mcr; + + /* Disable interrupts */ + tegra_uart_write(tup, 0, UART_IER); + + lsr = tegra_uart_read(tup, UART_LSR); + if ((lsr & UART_LSR_TEMT) != UART_LSR_TEMT) { + msr = tegra_uart_read(tup, UART_MSR); + mcr = tegra_uart_read(tup, UART_MCR); + if ((mcr & TEGRA_UART_MCR_CTS_EN) && (msr & UART_MSR_CTS)) + dev_err(tup->uport.dev, + "Tx Fifo not empty, CTS disabled, waiting\n"); + + /* Wait for Tx fifo to be empty */ + while ((lsr & UART_LSR_TEMT) != UART_LSR_TEMT) { + wait_time = min(fifo_empty_time, 100lu); + udelay(wait_time); + fifo_empty_time -= wait_time; + if (!fifo_empty_time) { + msr = tegra_uart_read(tup, UART_MSR); + mcr = tegra_uart_read(tup, UART_MCR); + if ((mcr & TEGRA_UART_MCR_CTS_EN) && + (msr & UART_MSR_CTS)) + dev_err(tup->uport.dev, + "Slave not ready\n"); + break; + } + lsr = tegra_uart_read(tup, UART_LSR); + } + } + + spin_lock_irqsave(&tup->uport.lock, flags); + /* Reset the Rx and Tx FIFOs */ + tegra_uart_fifo_reset(tup, UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); + tup->current_baud = 0; + spin_unlock_irqrestore(&tup->uport.lock, flags); + + clk_disable_unprepare(tup->uart_clk); +} + +static int tegra_uart_hw_init(struct tegra_uart_port *tup) +{ + int ret; + + tup->fcr_shadow = 0; + tup->mcr_shadow = 0; + tup->lcr_shadow = 0; + tup->ier_shadow = 0; + tup->current_baud = 0; + + clk_prepare_enable(tup->uart_clk); + + /* Reset the UART controller to clear all previous status.*/ + tegra_periph_reset_assert(tup->uart_clk); + udelay(10); + tegra_periph_reset_deassert(tup->uart_clk); + + tup->rx_in_progress = 0; + tup->tx_in_progress = 0; + + /* + * Set the trigger level + * + * For PIO mode: + * + * For receive, this will interrupt the CPU after that many number of + * bytes are received, for the remaining bytes the receive timeout + * interrupt is received. Rx high watermark is set to 4. + * + * For transmit, if the trasnmit interrupt is enabled, this will + * interrupt the CPU when the number of entries in the FIFO reaches the + * low watermark. Tx low watermark is set to 16 bytes. + * + * For DMA mode: + * + * Set the Tx trigger to 16. This should match the DMA burst size that + * programmed in the DMA registers. + */ + tup->fcr_shadow = UART_FCR_ENABLE_FIFO; + tup->fcr_shadow |= UART_FCR_R_TRIG_01; + tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B; + tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); + + /* + * Initialize the UART with default configuration + * (115200, N, 8, 1) so that the receive DMA buffer may be + * enqueued + */ + tup->lcr_shadow = TEGRA_UART_DEFAULT_LSR; + tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD); + tup->fcr_shadow |= UART_FCR_DMA_SELECT; + tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); + + ret = tegra_uart_start_rx_dma(tup); + if (ret < 0) { + dev_err(tup->uport.dev, "Not able to start Rx DMA\n"); + return ret; + } + tup->rx_in_progress = 1; + + /* + * Enable IE_RXS for the receive status interrupts like line errros. + * Enable IE_RX_TIMEOUT to get the bytes which cannot be DMA'd. + * + * If using DMA mode, enable EORD instead of receive interrupt which + * will interrupt after the UART is done with the receive instead of + * the interrupt when the FIFO "threshold" is reached. + * + * EORD is different interrupt than RX_TIMEOUT - RX_TIMEOUT occurs when + * the DATA is sitting in the FIFO and couldn't be transferred to the + * DMA as the DMA size alignment(4 bytes) is not met. EORD will be + * triggered when there is a pause of the incomming data stream for 4 + * characters long. + * + * For pauses in the data which is not aligned to 4 bytes, we get + * both the EORD as well as RX_TIMEOUT - SW sees RX_TIMEOUT first + * then the EORD. + */ + tup->ier_shadow = UART_IER_RLSI | UART_IER_RTOIE | TEGRA_UART_IER_EORD; + tegra_uart_write(tup, tup->ier_shadow, UART_IER); + return 0; +} + +static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, + bool dma_to_memory) +{ + struct dma_chan *dma_chan; + unsigned char *dma_buf; + dma_addr_t dma_phys; + int ret; + struct dma_slave_config dma_sconfig; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_chan = dma_request_channel(mask, NULL, NULL); + if (!dma_chan) { + dev_err(tup->uport.dev, + "Dma channel is not available, will try later\n"); + return -EPROBE_DEFER; + } + + if (dma_to_memory) { + dma_buf = dma_alloc_coherent(tup->uport.dev, + TEGRA_UART_RX_DMA_BUFFER_SIZE, + &dma_phys, GFP_KERNEL); + if (!dma_buf) { + dev_err(tup->uport.dev, + "Not able to allocate the dma buffer\n"); + dma_release_channel(dma_chan); + return -ENOMEM; + } + } else { + dma_phys = dma_map_single(tup->uport.dev, + tup->uport.state->xmit.buf, UART_XMIT_SIZE, + DMA_TO_DEVICE); + dma_buf = tup->uport.state->xmit.buf; + } + + dma_sconfig.slave_id = tup->dma_req_sel; + if (dma_to_memory) { + dma_sconfig.src_addr = tup->uport.mapbase; + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.src_maxburst = 4; + } else { + dma_sconfig.dst_addr = tup->uport.mapbase; + dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.dst_maxburst = 16; + } + + ret = dmaengine_slave_config(dma_chan, &dma_sconfig); + if (ret < 0) { + dev_err(tup->uport.dev, + "Dma slave config failed, err = %d\n", ret); + goto scrub; + } + + if (dma_to_memory) { + tup->rx_dma_chan = dma_chan; + tup->rx_dma_buf_virt = dma_buf; + tup->rx_dma_buf_phys = dma_phys; + } else { + tup->tx_dma_chan = dma_chan; + tup->tx_dma_buf_virt = dma_buf; + tup->tx_dma_buf_phys = dma_phys; + } + return 0; + +scrub: + dma_release_channel(dma_chan); + return ret; +} + +static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, + bool dma_to_memory) +{ + struct dma_chan *dma_chan; + + if (dma_to_memory) { + dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, + tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); + dma_chan = tup->rx_dma_chan; + tup->rx_dma_chan = NULL; + tup->rx_dma_buf_phys = 0; + tup->rx_dma_buf_virt = NULL; + } else { + dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); + dma_chan = tup->tx_dma_chan; + tup->tx_dma_chan = NULL; + tup->tx_dma_buf_phys = 0; + tup->tx_dma_buf_virt = NULL; + } + dma_release_channel(dma_chan); +} + +static int tegra_uart_startup(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + int ret; + + ret = tegra_uart_dma_channel_allocate(tup, false); + if (ret < 0) { + dev_err(u->dev, "Tx Dma allocation failed, err = %d\n", ret); + return ret; + } + + ret = tegra_uart_dma_channel_allocate(tup, true); + if (ret < 0) { + dev_err(u->dev, "Rx Dma allocation failed, err = %d\n", ret); + goto fail_rx_dma; + } + + ret = tegra_uart_hw_init(tup); + if (ret < 0) { + dev_err(u->dev, "Uart HW init failed, err = %d\n", ret); + goto fail_hw_init; + } + + ret = request_irq(u->irq, tegra_uart_isr, IRQF_DISABLED, + dev_name(u->dev), tup); + if (ret < 0) { + dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq); + goto fail_hw_init; + } + return 0; + +fail_hw_init: + tegra_uart_dma_channel_free(tup, true); +fail_rx_dma: + tegra_uart_dma_channel_free(tup, false); + return ret; +} + +static void tegra_uart_shutdown(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + + tegra_uart_hw_deinit(tup); + + tup->rx_in_progress = 0; + tup->tx_in_progress = 0; + + tegra_uart_dma_channel_free(tup, true); + tegra_uart_dma_channel_free(tup, false); + free_irq(u->irq, tup); +} + +static void tegra_uart_enable_ms(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + + if (tup->enable_modem_interrupt) { + tup->ier_shadow |= UART_IER_MSI; + tegra_uart_write(tup, tup->ier_shadow, UART_IER); + } +} + +static void tegra_uart_set_termios(struct uart_port *u, + struct ktermios *termios, struct ktermios *oldtermios) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + unsigned int baud; + unsigned long flags; + unsigned int lcr; + int symb_bit = 1; + struct clk *parent_clk = clk_get_parent(tup->uart_clk); + unsigned long parent_clk_rate = clk_get_rate(parent_clk); + int max_divider = (tup->cdata->support_clk_src_div) ? 0x7FFF : 0xFFFF; + + max_divider *= 16; + spin_lock_irqsave(&u->lock, flags); + + /* Changing configuration, it is safe to stop any rx now */ + if (tup->rts_active) + set_rts(tup, false); + + /* Clear all interrupts as configuration is going to be change */ + tegra_uart_write(tup, tup->ier_shadow | UART_IER_RDI, UART_IER); + tegra_uart_read(tup, UART_IER); + tegra_uart_write(tup, 0, UART_IER); + tegra_uart_read(tup, UART_IER); + + /* Parity */ + lcr = tup->lcr_shadow; + lcr &= ~UART_LCR_PARITY; + + /* CMSPAR isn't supported by this driver */ + termios->c_cflag &= ~CMSPAR; + + if ((termios->c_cflag & PARENB) == PARENB) { + symb_bit++; + if (termios->c_cflag & PARODD) { + lcr |= UART_LCR_PARITY; + lcr &= ~UART_LCR_EPAR; + lcr &= ~UART_LCR_SPAR; + } else { + lcr |= UART_LCR_PARITY; + lcr |= UART_LCR_EPAR; + lcr &= ~UART_LCR_SPAR; + } + } + + lcr &= ~UART_LCR_WLEN8; + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr |= UART_LCR_WLEN5; + symb_bit += 5; + break; + case CS6: + lcr |= UART_LCR_WLEN6; + symb_bit += 6; + break; + case CS7: + lcr |= UART_LCR_WLEN7; + symb_bit += 7; + break; + default: + lcr |= UART_LCR_WLEN8; + symb_bit += 8; + break; + } + + /* Stop bits */ + if (termios->c_cflag & CSTOPB) { + lcr |= UART_LCR_STOP; + symb_bit += 2; + } else { + lcr &= ~UART_LCR_STOP; + symb_bit++; + } + + tegra_uart_write(tup, lcr, UART_LCR); + tup->lcr_shadow = lcr; + tup->symb_bit = symb_bit; + + /* Baud rate. */ + baud = uart_get_baud_rate(u, termios, oldtermios, + parent_clk_rate/max_divider, + parent_clk_rate/16); + spin_unlock_irqrestore(&u->lock, flags); + tegra_set_baudrate(tup, baud); + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + spin_lock_irqsave(&u->lock, flags); + + /* Flow control */ + if (termios->c_cflag & CRTSCTS) { + tup->mcr_shadow |= TEGRA_UART_MCR_CTS_EN; + tup->mcr_shadow &= ~TEGRA_UART_MCR_RTS_EN; + tegra_uart_write(tup, tup->mcr_shadow, UART_MCR); + /* if top layer has asked to set rts active then do so here */ + if (tup->rts_active) + set_rts(tup, true); + } else { + tup->mcr_shadow &= ~TEGRA_UART_MCR_CTS_EN; + tup->mcr_shadow &= ~TEGRA_UART_MCR_RTS_EN; + tegra_uart_write(tup, tup->mcr_shadow, UART_MCR); + } + + /* update the port timeout based on new settings */ + uart_update_timeout(u, termios->c_cflag, baud); + + /* Make sure all write has completed */ + tegra_uart_read(tup, UART_IER); + + /* Reenable interrupt */ + tegra_uart_write(tup, tup->ier_shadow, UART_IER); + tegra_uart_read(tup, UART_IER); + + spin_unlock_irqrestore(&u->lock, flags); + return; +} + +/* + * Flush any TX data submitted for DMA and PIO. Called when the + * TX circular buffer is reset. + */ +static void tegra_uart_flush_buffer(struct uart_port *u) +{ + struct tegra_uart_port *tup = to_tegra_uport(u); + + tup->tx_bytes = 0; + if (tup->tx_dma_chan) + dmaengine_terminate_all(tup->tx_dma_chan); + return; +} + +static const char *tegra_uart_type(struct uart_port *u) +{ + return TEGRA_UART_TYPE; +} + +static struct uart_ops tegra_uart_ops = { + .tx_empty = tegra_uart_tx_empty, + .set_mctrl = tegra_uart_set_mctrl, + .get_mctrl = tegra_uart_get_mctrl, + .stop_tx = tegra_uart_stop_tx, + .start_tx = tegra_uart_start_tx, + .stop_rx = tegra_uart_stop_rx, + .flush_buffer = tegra_uart_flush_buffer, + .enable_ms = tegra_uart_enable_ms, + .break_ctl = tegra_uart_break_ctl, + .startup = tegra_uart_startup, + .shutdown = tegra_uart_shutdown, + .set_termios = tegra_uart_set_termios, + .type = tegra_uart_type, + .request_port = tegra_uart_request_port, + .release_port = tegra_uart_release_port, +}; + +static struct uart_driver tegra_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "tegra_hsuart", + .dev_name = "ttyTHS", + .cons = 0, + .nr = TEGRA_UART_MAXIMUM, +}; + +static int tegra_uart_parse_dt(struct platform_device *pdev, + struct tegra_uart_port *tup) +{ + struct device_node *np = pdev->dev.of_node; + u32 of_dma[2]; + int port; + + if (of_property_read_u32_array(np, "nvidia,dma-request-selector", + of_dma, 2) >= 0) { + tup->dma_req_sel = of_dma[1]; + } else { + dev_err(&pdev->dev, "missing dma requestor in device tree\n"); + return -EINVAL; + } + + port = of_alias_get_id(np, "serial"); + if (port < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", port); + return port; + } + tup->uport.line = port; + + tup->enable_modem_interrupt = of_property_read_bool(np, + "nvidia,enable-modem-interrupt"); + return 0; +} + +struct tegra_uart_chip_data tegra20_uart_chip_data = { + .tx_fifo_full_status = false, + .allow_txfifo_reset_fifo_mode = true, + .support_clk_src_div = false, +}; + +struct tegra_uart_chip_data tegra30_uart_chip_data = { + .tx_fifo_full_status = true, + .allow_txfifo_reset_fifo_mode = false, + .support_clk_src_div = true, +}; + +static struct of_device_id tegra_uart_of_match[] = { + { + .compatible = "nvidia,tegra30-hsuart", + .data = &tegra30_uart_chip_data, + }, { + .compatible = "nvidia,tegra20-hsuart", + .data = &tegra20_uart_chip_data, + }, { + }, +}; +MODULE_DEVICE_TABLE(of, tegra_uart_of_match); + +static int tegra_uart_probe(struct platform_device *pdev) +{ + struct tegra_uart_port *tup; + struct uart_port *u; + struct resource *resource; + int ret; + const struct tegra_uart_chip_data *cdata; + const struct of_device_id *match; + + match = of_match_device(tegra_uart_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + cdata = match->data; + + tup = devm_kzalloc(&pdev->dev, sizeof(*tup), GFP_KERNEL); + if (!tup) { + dev_err(&pdev->dev, "Failed to allocate memory for tup\n"); + return -ENOMEM; + } + + ret = tegra_uart_parse_dt(pdev, tup); + if (ret < 0) + return ret; + + u = &tup->uport; + u->dev = &pdev->dev; + u->ops = &tegra_uart_ops; + u->type = PORT_TEGRA; + u->fifosize = 32; + tup->cdata = cdata; + + platform_set_drvdata(pdev, tup); + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!resource) { + dev_err(&pdev->dev, "No IO memory resource\n"); + return -ENODEV; + } + + u->mapbase = resource->start; + u->membase = devm_request_and_ioremap(&pdev->dev, resource); + if (!u->membase) { + dev_err(&pdev->dev, "memregion/iomap address req failed\n"); + return -EADDRNOTAVAIL; + } + + tup->uart_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(tup->uart_clk)) { + dev_err(&pdev->dev, "Couldn't get the clock\n"); + return PTR_ERR(tup->uart_clk); + } + + u->iotype = UPIO_MEM32; + u->irq = platform_get_irq(pdev, 0); + u->regshift = 2; + ret = uart_add_one_port(&tegra_uart_driver, u); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to add uart port, err %d\n", ret); + return ret; + } + return ret; +} + +static int tegra_uart_remove(struct platform_device *pdev) +{ + struct tegra_uart_port *tup = platform_get_drvdata(pdev); + struct uart_port *u = &tup->uport; + + uart_remove_one_port(&tegra_uart_driver, u); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tegra_uart_suspend(struct device *dev) +{ + struct tegra_uart_port *tup = dev_get_drvdata(dev); + struct uart_port *u = &tup->uport; + + return uart_suspend_port(&tegra_uart_driver, u); +} + +static int tegra_uart_resume(struct device *dev) +{ + struct tegra_uart_port *tup = dev_get_drvdata(dev); + struct uart_port *u = &tup->uport; + + return uart_resume_port(&tegra_uart_driver, u); +} +#endif + +static const struct dev_pm_ops tegra_uart_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tegra_uart_suspend, tegra_uart_resume) +}; + +static struct platform_driver tegra_uart_platform_driver = { + .probe = tegra_uart_probe, + .remove = tegra_uart_remove, + .driver = { + .name = "serial-tegra", + .of_match_table = tegra_uart_of_match, + .pm = &tegra_uart_pm_ops, + }, +}; + +static int __init tegra_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&tegra_uart_driver); + if (ret < 0) { + pr_err("Could not register %s driver\n", + tegra_uart_driver.driver_name); + return ret; + } + + ret = platform_driver_register(&tegra_uart_platform_driver); + if (ret < 0) { + pr_err("Uart platfrom driver register failed, e = %d\n", ret); + uart_unregister_driver(&tegra_uart_driver); + return ret; + } + return 0; +} + +static void __exit tegra_uart_exit(void) +{ + pr_info("Unloading tegra uart driver\n"); + platform_driver_unregister(&tegra_uart_platform_driver); + uart_unregister_driver(&tegra_uart_driver); +} + +module_init(tegra_uart_init); +module_exit(tegra_uart_exit); + +MODULE_ALIAS("platform:serial-tegra"); +MODULE_DESCRIPTION("High speed UART driver for tegra chipset"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0fcfd98a9566..a400002dfa84 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -59,7 +59,8 @@ static struct lock_class_key port_lock_key; static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); -static void uart_change_pm(struct uart_state *state, int pm_state); +static void uart_change_pm(struct uart_state *state, + enum uart_pm_state pm_state); static void uart_port_shutdown(struct tty_port *port); @@ -610,34 +611,57 @@ static void uart_send_xchar(struct tty_struct *tty, char ch) static void uart_throttle(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + uint32_t mask = 0; if (I_IXOFF(tty)) + mask |= UPF_SOFT_FLOW; + if (tty->termios.c_cflag & CRTSCTS) + mask |= UPF_HARD_FLOW; + + if (port->flags & mask) { + port->ops->throttle(port); + mask &= ~port->flags; + } + + if (mask & UPF_SOFT_FLOW) uart_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios.c_cflag & CRTSCTS) - uart_clear_mctrl(state->uart_port, TIOCM_RTS); + if (mask & UPF_HARD_FLOW) + uart_clear_mctrl(port, TIOCM_RTS); } static void uart_unthrottle(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; + uint32_t mask = 0; - if (I_IXOFF(tty)) { + if (I_IXOFF(tty)) + mask |= UPF_SOFT_FLOW; + if (tty->termios.c_cflag & CRTSCTS) + mask |= UPF_HARD_FLOW; + + if (port->flags & mask) { + port->ops->unthrottle(port); + mask &= ~port->flags; + } + + if (mask & UPF_SOFT_FLOW) { if (port->x_char) port->x_char = 0; else uart_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios.c_cflag & CRTSCTS) + if (mask & UPF_HARD_FLOW) uart_set_mctrl(port, TIOCM_RTS); } -static void uart_get_info(struct tty_port *port, - struct uart_state *state, +static void do_uart_get_info(struct tty_port *port, struct serial_struct *retinfo) { + struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport = state->uart_port; memset(retinfo, 0, sizeof(*retinfo)); @@ -662,17 +686,21 @@ static void uart_get_info(struct tty_port *port, retinfo->iomem_base = (void *)(unsigned long)uport->mapbase; } -static int uart_get_info_user(struct uart_state *state, - struct serial_struct __user *retinfo) +static void uart_get_info(struct tty_port *port, + struct serial_struct *retinfo) { - struct tty_port *port = &state->port; - struct serial_struct tmp; - /* Ensure the state we copy is consistent and no hardware changes occur as we go */ mutex_lock(&port->mutex); - uart_get_info(port, state, &tmp); + do_uart_get_info(port, retinfo); mutex_unlock(&port->mutex); +} + +static int uart_get_info_user(struct tty_port *port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + uart_get_info(port, &tmp); if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; @@ -839,9 +867,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, port->closing_wait = closing_wait; if (new_info->xmit_fifo_size) uport->fifosize = new_info->xmit_fifo_size; - if (port->tty) - port->tty->low_latency = - (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; + port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; check_and_exit: retval = 0; @@ -1131,7 +1157,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, */ switch (cmd) { case TIOCGSERIAL: - ret = uart_get_info_user(state, uarg); + ret = uart_get_info_user(port, uarg); break; case TIOCSSERIAL: @@ -1210,9 +1236,22 @@ static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct uart_state *state = tty->driver_data; + struct uart_port *uport = state->uart_port; unsigned long flags; unsigned int cflag = tty->termios.c_cflag; + unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK; + bool sw_changed = false; + /* + * Drivers doing software flow control also need to know + * about changes to these input settings. + */ + if (uport->flags & UPF_SOFT_FLOW) { + iflag_mask |= IXANY|IXON|IXOFF; + sw_changed = + tty->termios.c_cc[VSTART] != old_termios->c_cc[VSTART] || + tty->termios.c_cc[VSTOP] != old_termios->c_cc[VSTOP]; + } /* * These are the bits that are used to setup various @@ -1220,11 +1259,11 @@ static void uart_set_termios(struct tty_struct *tty, * bits in c_cflag; c_[io]speed will always be set * appropriately by set_termios() in tty_ioctl.c */ -#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) if ((cflag ^ old_termios->c_cflag) == 0 && tty->termios.c_ospeed == old_termios->c_ospeed && tty->termios.c_ispeed == old_termios->c_ispeed && - RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) { + ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 && + !sw_changed) { return; } @@ -1232,38 +1271,46 @@ 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); + uart_clear_mctrl(uport, TIOCM_RTS | TIOCM_DTR); /* Handle transition away from B0 status */ else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { unsigned int mask = TIOCM_DTR; if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) mask |= TIOCM_RTS; - uart_set_mctrl(state->uart_port, mask); + uart_set_mctrl(uport, mask); } + /* + * If the port is doing h/w assisted flow control, do nothing. + * We assume that tty->hw_stopped has never been set. + */ + if (uport->flags & UPF_HARD_FLOW) + return; + /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { - spin_lock_irqsave(&state->uart_port->lock, flags); + spin_lock_irqsave(&uport->lock, flags); tty->hw_stopped = 0; __uart_start(tty); - spin_unlock_irqrestore(&state->uart_port->lock, flags); + spin_unlock_irqrestore(&uport->lock, flags); } /* Handle turning on 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)) { + spin_lock_irqsave(&uport->lock, flags); + if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) { tty->hw_stopped = 1; - state->uart_port->ops->stop_tx(state->uart_port); + uport->ops->stop_tx(uport); } - spin_unlock_irqrestore(&state->uart_port->lock, flags); + spin_unlock_irqrestore(&uport->lock, flags); } } /* - * In 2.4.5, calls to this will be serialized via the BKL in - * linux/drivers/char/tty_io.c:tty_release() - * linux/drivers/char/tty_io.c:do_tty_handup() + * Calls to uart_close() are serialised via the tty_lock in + * drivers/tty/tty_io.c:tty_release() + * drivers/tty/tty_io.c:do_tty_hangup() + * This runs from a workqueue and can sleep for a _short_ time only. */ static void uart_close(struct tty_struct *tty, struct file *filp) { @@ -1318,7 +1365,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&port->lock, flags); } else if (!uart_console(uport)) { spin_unlock_irqrestore(&port->lock, flags); - uart_change_pm(state, 3); + uart_change_pm(state, UART_PM_STATE_OFF); spin_lock_irqsave(&port->lock, flags); } @@ -1390,10 +1437,9 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) } /* - * This is called with the BKL held in - * linux/drivers/char/tty_io.c:do_tty_hangup() - * We're called from the eventd thread, so we can sleep for - * a _short_ time only. + * Calls to uart_hangup() are serialised by the tty_lock in + * drivers/tty/tty_io.c:do_tty_hangup() + * This runs from a workqueue and can sleep for a _short_ time only. */ static void uart_hangup(struct tty_struct *tty) { @@ -1474,8 +1520,8 @@ static void uart_dtr_rts(struct tty_port *port, int onoff) } /* - * calls to uart_open are serialised by the BKL in - * fs/char_dev.c:chrdev_open() + * Calls to uart_open are serialised by the tty_lock in + * drivers/tty/tty_io.c:tty_open() * Note that if this fails, then uart_close() _will_ be called. * * In time, we want to scrap the "opening nonpresent ports" @@ -1517,7 +1563,8 @@ static int uart_open(struct tty_struct *tty, struct file *filp) */ tty->driver_data = state; state->uart_port->state = state; - tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; + state->port.low_latency = + (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; tty_port_tty_set(port, tty); /* @@ -1532,7 +1579,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) * Make sure the device is in D0 state. */ if (port->count == 1) - uart_change_pm(state, 0); + uart_change_pm(state, UART_PM_STATE_ON); /* * Start up the serial port. @@ -1573,7 +1620,7 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) { struct uart_state *state = drv->state + i; struct tty_port *port = &state->port; - int pm_state; + enum uart_pm_state pm_state; struct uart_port *uport = state->uart_port; char stat_buf[32]; unsigned int status; @@ -1598,12 +1645,12 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) if (capable(CAP_SYS_ADMIN)) { mutex_lock(&port->mutex); pm_state = state->pm_state; - if (pm_state) - uart_change_pm(state, 0); + if (pm_state != UART_PM_STATE_ON) + uart_change_pm(state, UART_PM_STATE_ON); spin_lock_irq(&uport->lock); status = uport->ops->get_mctrl(uport); spin_unlock_irq(&uport->lock); - if (pm_state) + if (pm_state != UART_PM_STATE_ON) uart_change_pm(state, pm_state); mutex_unlock(&port->mutex); @@ -1850,7 +1897,8 @@ EXPORT_SYMBOL_GPL(uart_set_options); * * Locking: port->mutex has to be held */ -static void uart_change_pm(struct uart_state *state, int pm_state) +static void uart_change_pm(struct uart_state *state, + enum uart_pm_state pm_state) { struct uart_port *port = state->uart_port; @@ -1935,7 +1983,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) console_stop(uport->cons); if (console_suspend_enabled || !uart_console(uport)) - uart_change_pm(state, 3); + uart_change_pm(state, UART_PM_STATE_OFF); mutex_unlock(&port->mutex); @@ -1980,7 +2028,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) termios = port->tty->termios; if (console_suspend_enabled) - uart_change_pm(state, 0); + uart_change_pm(state, UART_PM_STATE_ON); uport->ops->set_termios(uport, &termios, NULL); if (console_suspend_enabled) console_start(uport->cons); @@ -1990,7 +2038,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) const struct uart_ops *ops = uport->ops; int ret; - uart_change_pm(state, 0); + uart_change_pm(state, UART_PM_STATE_ON); spin_lock_irq(&uport->lock); ops->set_mctrl(uport, 0); spin_unlock_irq(&uport->lock); @@ -2090,7 +2138,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, uart_report_port(drv, port); /* Power up port for set_mctrl() */ - uart_change_pm(state, 0); + uart_change_pm(state, UART_PM_STATE_ON); /* * Ensure that the modem control lines are de-activated. @@ -2114,7 +2162,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, * console if we have one. */ if (!uart_console(port)) - uart_change_pm(state, 3); + uart_change_pm(state, UART_PM_STATE_OFF); } } @@ -2293,6 +2341,8 @@ int uart_register_driver(struct uart_driver *drv) if (retval >= 0) return retval; + for (i = 0; i < drv->nr; i++) + tty_port_destroy(&drv->state[i].port); put_tty_driver(normal); out_kfree: kfree(drv->state); @@ -2312,8 +2362,12 @@ out: void uart_unregister_driver(struct uart_driver *drv) { struct tty_driver *p = drv->tty_driver; + unsigned int i; + tty_unregister_driver(p); put_tty_driver(p); + for (i = 0; i < drv->nr; i++) + tty_port_destroy(&drv->state[i].port); kfree(drv->state); drv->state = NULL; drv->tty_driver = NULL; @@ -2329,21 +2383,166 @@ struct tty_driver *uart_console_device(struct console *co, int *index) static ssize_t uart_get_attr_uartclk(struct device *dev, struct device_attribute *attr, char *buf) { - int ret; + struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); - struct uart_state *state = container_of(port, struct uart_state, port); - mutex_lock(&state->port.mutex); - ret = snprintf(buf, PAGE_SIZE, "%d\n", state->uart_port->uartclk); - mutex_unlock(&state->port.mutex); + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16); +} - return ret; +static ssize_t uart_get_attr_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type); +} +static ssize_t uart_get_attr_line(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line); +} + +static ssize_t uart_get_attr_port(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + unsigned long ioaddr; + + uart_get_info(port, &tmp); + ioaddr = tmp.port; + if (HIGH_BITS_OFFSET) + ioaddr |= (unsigned long)tmp.port_high << HIGH_BITS_OFFSET; + return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr); +} + +static ssize_t uart_get_attr_irq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq); +} + +static ssize_t uart_get_attr_flags(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags); +} + +static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size); +} + + +static ssize_t uart_get_attr_close_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay); +} + + +static ssize_t uart_get_attr_closing_wait(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait); +} + +static ssize_t uart_get_attr_custom_divisor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor); +} + +static ssize_t uart_get_attr_io_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type); } +static ssize_t uart_get_attr_iomem_base(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base); +} + +static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct serial_struct tmp; + struct tty_port *port = dev_get_drvdata(dev); + + uart_get_info(port, &tmp); + return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); +} + +static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL); +static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL); +static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL); +static DEVICE_ATTR(irq, S_IRUSR | S_IRGRP, uart_get_attr_irq, NULL); +static DEVICE_ATTR(flags, S_IRUSR | S_IRGRP, uart_get_attr_flags, NULL); +static DEVICE_ATTR(xmit_fifo_size, S_IRUSR | S_IRGRP, uart_get_attr_xmit_fifo_size, NULL); static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL); +static DEVICE_ATTR(close_delay, S_IRUSR | S_IRGRP, uart_get_attr_close_delay, NULL); +static DEVICE_ATTR(closing_wait, S_IRUSR | S_IRGRP, uart_get_attr_closing_wait, NULL); +static DEVICE_ATTR(custom_divisor, S_IRUSR | S_IRGRP, uart_get_attr_custom_divisor, NULL); +static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL); +static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL); +static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL); static struct attribute *tty_dev_attrs[] = { + &dev_attr_type.attr, + &dev_attr_line.attr, + &dev_attr_port.attr, + &dev_attr_irq.attr, + &dev_attr_flags.attr, + &dev_attr_xmit_fifo_size.attr, &dev_attr_uartclk.attr, + &dev_attr_close_delay.attr, + &dev_attr_closing_wait.attr, + &dev_attr_custom_divisor.attr, + &dev_attr_io_type.attr, + &dev_attr_iomem_base.attr, + &dev_attr_iomem_reg_shift.attr, NULL, }; @@ -2356,6 +2555,7 @@ static const struct attribute_group *tty_dev_attr_groups[] = { NULL }; + /** * uart_add_one_port - attach a driver-defined port structure * @drv: pointer to the uart low level driver structure for this port @@ -2389,7 +2589,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) } state->uart_port = uport; - state->pm_state = -1; + state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons; uport->state = state; @@ -2443,6 +2643,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) { struct uart_state *state = drv->state + uport->line; struct tty_port *port = &state->port; + int ret = 0; BUG_ON(in_interrupt()); @@ -2457,6 +2658,11 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) * succeeding while we shut down the port. */ mutex_lock(&port->mutex); + if (!state->uart_port) { + mutex_unlock(&port->mutex); + ret = -EINVAL; + goto out; + } uport->flags |= UPF_DEAD; mutex_unlock(&port->mutex); @@ -2480,9 +2686,10 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) uport->type = PORT_UNKNOWN; state->uart_port = NULL; +out: mutex_unlock(&port_mutex); - return 0; + return ret; } /* @@ -2516,22 +2723,17 @@ EXPORT_SYMBOL(uart_match_port); */ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) { - struct uart_state *state = uport->state; - struct tty_port *port = &state->port; - struct tty_ldisc *ld = NULL; - struct pps_event_time ts; + struct tty_port *port = &uport->state->port; struct tty_struct *tty = port->tty; + struct tty_ldisc *ld = tty ? tty_ldisc_ref(tty) : NULL; - if (tty) - ld = tty_ldisc_ref(tty); - if (ld && ld->ops->dcd_change) - pps_get_ts(&ts); + if (ld) { + if (ld->ops->dcd_change) + ld->ops->dcd_change(tty, status); + tty_ldisc_deref(ld); + } uport->icount.dcd++; -#ifdef CONFIG_HARD_PPS - if ((uport->flags & UPF_HARDPPS_CD) && status) - hardpps(); -#endif if (port->flags & ASYNC_CHECK_CD) { if (status) @@ -2539,11 +2741,6 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) else if (tty) tty_hangup(tty); } - - if (ld && ld->ops->dcd_change) - ld->ops->dcd_change(tty, status, &ts); - if (ld) - tty_ldisc_deref(ld); } EXPORT_SYMBOL_GPL(uart_handle_dcd_change); @@ -2591,10 +2788,10 @@ EXPORT_SYMBOL_GPL(uart_handle_cts_change); void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag) { - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; if ((status & port->ignore_status_mask & ~overrun) == 0) - if (tty_insert_flip_char(tty, ch, flag) == 0) + if (tty_insert_flip_char(tport, ch, flag) == 0) ++port->icount.buf_overrun; /* @@ -2602,7 +2799,7 @@ void uart_insert_char(struct uart_port *port, unsigned int status, * it doesn't affect the current character. */ if (status & ~port->ignore_status_mask & overrun) - if (tty_insert_flip_char(tty, 0, TTY_OVERRUN) == 0) + if (tty_insert_flip_char(tport, 0, TTY_OVERRUN) == 0) ++port->icount.buf_overrun; } EXPORT_SYMBOL_GPL(uart_insert_char); diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c index 9bd004f9da89..e1caa99e3d3b 100644 --- a/drivers/tty/serial/serial_ks8695.c +++ b/drivers/tty/serial/serial_ks8695.c @@ -153,7 +153,6 @@ static void ks8695uart_disable_ms(struct uart_port *port) static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; unsigned int status, ch, lsr, flg, max_count = 256; status = UART_GET_LSR(port); /* clears pending LSR interrupts */ @@ -200,7 +199,7 @@ static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) ignore_char: status = UART_GET_LSR(port); } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); return IRQ_HANDLED; } diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 6ae2a58d62f2..fe48a0c2b4ca 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -277,7 +277,6 @@ static void serial_txx9_initialize(struct uart_port *port) static inline void receive_chars(struct uart_txx9_port *up, unsigned int *status) { - struct tty_struct *tty = up->port.state->port.tty; unsigned char ch; unsigned int disr = *status; int max_count = 256; @@ -346,7 +345,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status) disr = sio_in(up, TXX9_SIDISR); } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); spin_unlock(&up->port.lock); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&up->port.state->port); spin_lock(&up->port.lock); *status = disr; } @@ -1030,7 +1029,7 @@ static DEFINE_MUTEX(serial_txx9_mutex); * * On success the port is ready to use and the line number is returned. */ -static int __devinit serial_txx9_register_port(struct uart_port *port) +static int serial_txx9_register_port(struct uart_port *port) { int i; struct uart_txx9_port *uart; @@ -1078,7 +1077,7 @@ static int __devinit serial_txx9_register_port(struct uart_port *port) * Remove one serial port. This may not be called from interrupt * context. We hand the port back to the our control. */ -static void __devexit serial_txx9_unregister_port(int line) +static void serial_txx9_unregister_port(int line) { struct uart_txx9_port *uart = &serial_txx9_ports[line]; @@ -1096,7 +1095,7 @@ static void __devexit serial_txx9_unregister_port(int line) /* * Register a set of serial devices attached to a platform device. */ -static int __devinit serial_txx9_probe(struct platform_device *dev) +static int serial_txx9_probe(struct platform_device *dev) { struct uart_port *p = dev->dev.platform_data; struct uart_port port; @@ -1126,7 +1125,7 @@ static int __devinit serial_txx9_probe(struct platform_device *dev) /* * Remove serial ports registered against a platform device. */ -static int __devexit serial_txx9_remove(struct platform_device *dev) +static int serial_txx9_remove(struct platform_device *dev) { int i; @@ -1171,7 +1170,7 @@ static int serial_txx9_resume(struct platform_device *dev) static struct platform_driver serial_txx9_plat_driver = { .probe = serial_txx9_probe, - .remove = __devexit_p(serial_txx9_remove), + .remove = serial_txx9_remove, #ifdef CONFIG_PM .suspend = serial_txx9_suspend, .resume = serial_txx9_resume, @@ -1187,7 +1186,7 @@ static struct platform_driver serial_txx9_plat_driver = { * Probe one serial board. Unfortunately, there is no rhyme nor reason * to the arrangement of serial ports on a PCI card. */ -static int __devinit +static int pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { struct uart_port port; @@ -1217,7 +1216,7 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent) return 0; } -static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) +static void pciserial_txx9_remove_one(struct pci_dev *dev) { struct uart_txx9_port *up = pci_get_drvdata(dev); @@ -1261,7 +1260,7 @@ static const struct pci_device_id serial_txx9_pci_tbl[] = { static struct pci_driver serial_txx9_pci_driver = { .name = "serial_txx9", .probe = pciserial_txx9_init_one, - .remove = __devexit_p(pciserial_txx9_remove_one), + .remove = pciserial_txx9_remove_one, #ifdef CONFIG_PM .suspend = pciserial_txx9_suspend_one, .resume = pciserial_txx9_resume_one, diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 6ee59001d61d..156418619949 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -99,12 +99,6 @@ struct sci_port { #endif struct notifier_block freq_transition; - -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE - unsigned short saved_smr; - unsigned short saved_fcr; - unsigned char saved_brr; -#endif }; /* Function prototypes */ @@ -202,9 +196,9 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCxSR] = { 0x14, 16 }, [SCxRDR] = { 0x60, 8 }, [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, + [SCFDR] = sci_reg_invalid, + [SCTFDR] = { 0x38, 16 }, + [SCRFDR] = { 0x3c, 16 }, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, }, @@ -491,7 +485,7 @@ static int sci_txfill(struct uart_port *port) reg = sci_getreg(port, SCTFDR); if (reg->size) - return serial_port_in(port, SCTFDR) & 0xff; + return serial_port_in(port, SCTFDR) & ((port->fifosize << 1) - 1); reg = sci_getreg(port, SCFDR); if (reg->size) @@ -511,7 +505,7 @@ static int sci_rxfill(struct uart_port *port) reg = sci_getreg(port, SCRFDR); if (reg->size) - return serial_port_in(port, SCRFDR) & 0xff; + return serial_port_in(port, SCRFDR) & ((port->fifosize << 1) - 1); reg = sci_getreg(port, SCFDR); if (reg->size) @@ -602,7 +596,7 @@ static void sci_transmit_chars(struct uart_port *port) static void sci_receive_chars(struct uart_port *port) { struct sci_port *sci_port = to_sci_port(port); - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; int i, count, copied = 0; unsigned short status; unsigned char flag; @@ -613,7 +607,7 @@ static void sci_receive_chars(struct uart_port *port) while (1) { /* Don't copy more bytes than there is room for in the buffer */ - count = tty_buffer_request_room(tty, sci_rxfill(port)); + count = tty_buffer_request_room(tport, sci_rxfill(port)); /* If for any reason we can't copy more data, we're done! */ if (count == 0) @@ -625,7 +619,7 @@ static void sci_receive_chars(struct uart_port *port) sci_port->break_flag) count = 0; else - tty_insert_flip_char(tty, c, TTY_NORMAL); + tty_insert_flip_char(tport, c, TTY_NORMAL); } else { for (i = 0; i < count; i++) { char c = serial_port_in(port, SCxRDR); @@ -667,7 +661,7 @@ static void sci_receive_chars(struct uart_port *port) } else flag = TTY_NORMAL; - tty_insert_flip_char(tty, c, flag); + tty_insert_flip_char(tport, c, flag); } } @@ -680,7 +674,7 @@ static void sci_receive_chars(struct uart_port *port) if (copied) { /* Tell the rest of the system the news. New characters! */ - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); } else { serial_port_in(port, SCxSR); /* dummy read */ serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); @@ -726,7 +720,7 @@ static int sci_handle_errors(struct uart_port *port) { int copied = 0; unsigned short status = serial_port_in(port, SCxSR); - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); /* @@ -737,7 +731,7 @@ static int sci_handle_errors(struct uart_port *port) port->icount.overrun++; /* overrun error */ - if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) + if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) copied++; dev_notice(port->dev, "overrun error"); @@ -761,7 +755,7 @@ static int sci_handle_errors(struct uart_port *port) dev_dbg(port->dev, "BREAK detected\n"); - if (tty_insert_flip_char(tty, 0, TTY_BREAK)) + if (tty_insert_flip_char(tport, 0, TTY_BREAK)) copied++; } @@ -769,7 +763,7 @@ static int sci_handle_errors(struct uart_port *port) /* frame error */ port->icount.frame++; - if (tty_insert_flip_char(tty, 0, TTY_FRAME)) + if (tty_insert_flip_char(tport, 0, TTY_FRAME)) copied++; dev_notice(port->dev, "frame error\n"); @@ -780,21 +774,21 @@ static int sci_handle_errors(struct uart_port *port) /* parity error */ port->icount.parity++; - if (tty_insert_flip_char(tty, 0, TTY_PARITY)) + if (tty_insert_flip_char(tport, 0, TTY_PARITY)) copied++; dev_notice(port->dev, "parity error"); } if (copied) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); return copied; } static int sci_handle_fifo_overrun(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg; int copied = 0; @@ -808,8 +802,8 @@ static int sci_handle_fifo_overrun(struct uart_port *port) port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - tty_flip_buffer_push(tty); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); + tty_flip_buffer_push(tport); dev_notice(port->dev, "overrun error\n"); copied++; @@ -822,7 +816,7 @@ static int sci_handle_breaks(struct uart_port *port) { int copied = 0; unsigned short status = serial_port_in(port, SCxSR); - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); if (uart_handle_break(port)) @@ -837,14 +831,14 @@ static int sci_handle_breaks(struct uart_port *port) port->icount.brk++; /* Notify of BREAK */ - if (tty_insert_flip_char(tty, 0, TTY_BREAK)) + if (tty_insert_flip_char(tport, 0, TTY_BREAK)) copied++; dev_dbg(port->dev, "BREAK detected\n"); } if (copied) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); copied += sci_handle_fifo_overrun(port); @@ -1132,7 +1126,7 @@ static const char *sci_gpio_str(unsigned int index) return sci_gpio_names[index]; } -static void __devinit sci_init_gpios(struct sci_port *port) +static void sci_init_gpios(struct sci_port *port) { struct uart_port *up = &port->port; int i; @@ -1265,13 +1259,13 @@ static void sci_dma_tx_complete(void *arg) } /* Locking: called with port lock held */ -static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty, - size_t count) +static int sci_dma_rx_push(struct sci_port *s, size_t count) { struct uart_port *port = &s->port; + struct tty_port *tport = &port->state->port; int i, active, room; - room = tty_buffer_request_room(tty, count); + room = tty_buffer_request_room(tport, count); if (s->active_rx == s->cookie_rx[0]) { active = 0; @@ -1289,7 +1283,7 @@ static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty, return room; for (i = 0; i < room; i++) - tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i], + tty_insert_flip_char(tport, ((u8 *)sg_virt(&s->sg_rx[active]))[i], TTY_NORMAL); port->icount.rx += room; @@ -1301,7 +1295,6 @@ static void sci_dma_rx_complete(void *arg) { struct sci_port *s = arg; struct uart_port *port = &s->port; - struct tty_struct *tty = port->state->port.tty; unsigned long flags; int count; @@ -1309,14 +1302,14 @@ static void sci_dma_rx_complete(void *arg) spin_lock_irqsave(&port->lock, flags); - count = sci_dma_rx_push(s, tty, s->buf_len_rx); + count = sci_dma_rx_push(s, s->buf_len_rx); mod_timer(&s->rx_timer, jiffies + s->rx_timeout); spin_unlock_irqrestore(&port->lock, flags); if (count) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); schedule_work(&s->work_rx); } @@ -1410,7 +1403,6 @@ static void work_fn_rx(struct work_struct *work) if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != DMA_SUCCESS) { /* Handle incomplete DMA receive */ - struct tty_struct *tty = port->state->port.tty; struct dma_chan *chan = s->chan_rx; struct shdma_desc *sh_desc = container_of(desc, struct shdma_desc, async_tx); @@ -1422,11 +1414,11 @@ static void work_fn_rx(struct work_struct *work) sh_desc->partial, sh_desc->cookie); spin_lock_irqsave(&port->lock, flags); - count = sci_dma_rx_push(s, tty, sh_desc->partial); + count = sci_dma_rx_push(s, sh_desc->partial); spin_unlock_irqrestore(&port->lock, flags); if (count) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); sci_submit_rx(s); @@ -1749,22 +1741,21 @@ static inline void sci_free_dma(struct uart_port *port) static int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); + unsigned long flags; int ret; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - pm_runtime_put_noidle(port->dev); - - sci_port_enable(s); - ret = sci_request_irq(s); if (unlikely(ret < 0)) return ret; sci_request_dma(port); + spin_lock_irqsave(&port->lock, flags); sci_start_tx(port); sci_start_rx(port); + spin_unlock_irqrestore(&port->lock, flags); return 0; } @@ -1772,18 +1763,17 @@ static int sci_startup(struct uart_port *port) static void sci_shutdown(struct uart_port *port) { struct sci_port *s = to_sci_port(port); + unsigned long flags; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + spin_lock_irqsave(&port->lock, flags); sci_stop_rx(port); sci_stop_tx(port); + spin_unlock_irqrestore(&port->lock, flags); sci_free_dma(port); sci_free_irq(s); - - sci_port_disable(s); - - pm_runtime_get_noresume(port->dev); } static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, @@ -1829,7 +1819,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, { struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg; - unsigned int baud, smr_val, max_baud; + unsigned int baud, smr_val, max_baud, cks; int t = -1; /* @@ -1863,21 +1853,18 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); - serial_port_out(port, SCSMR, smr_val); - - dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, - s->cfg->scscr); + for (cks = 0; t >= 256 && cks <= 3; cks++) + t >>= 2; - if (t > 0) { - if (t >= 256) { - serial_port_out(port, SCSMR, (serial_port_in(port, SCSMR) & ~3) | 1); - t >>= 2; - } else - serial_port_out(port, SCSMR, serial_port_in(port, SCSMR) & ~3); + dev_dbg(port->dev, "%s: SMR %x, cks %x, t %x, SCSCR %x\n", + __func__, smr_val, cks, t, s->cfg->scscr); + if (t >= 0) { + serial_port_out(port, SCSMR, (smr_val & ~3) | cks); serial_port_out(port, SCBRR, t); udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ - } + } else + serial_port_out(port, SCSMR, smr_val); sci_init_pins(port, termios->c_cflag); @@ -1932,6 +1919,21 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_port_disable(s); } +static void sci_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct sci_port *sci_port = to_sci_port(port); + + switch (state) { + case 3: + sci_port_disable(sci_port); + break; + default: + sci_port_enable(sci_port); + break; + } +} + static const char *sci_type(struct uart_port *port) { switch (port->type) { @@ -2053,6 +2055,7 @@ static struct uart_ops sci_uart_ops = { .startup = sci_startup, .shutdown = sci_shutdown, .set_termios = sci_set_termios, + .pm = sci_pm, .type = sci_type, .release_port = sci_release_port, .request_port = sci_request_port, @@ -2064,7 +2067,7 @@ static struct uart_ops sci_uart_ops = { #endif }; -static int __devinit sci_init_single(struct platform_device *dev, +static int sci_init_single(struct platform_device *dev, struct sci_port *sci_port, unsigned int index, struct plat_sci_port *p) @@ -2121,8 +2124,6 @@ static int __devinit sci_init_single(struct platform_device *dev, sci_init_gpios(sci_port); - pm_runtime_irq_safe(&dev->dev); - pm_runtime_get_noresume(&dev->dev); pm_runtime_enable(&dev->dev); } @@ -2206,9 +2207,21 @@ static void serial_console_write(struct console *co, const char *s, { struct sci_port *sci_port = &sci_ports[co->index]; struct uart_port *port = &sci_port->port; - unsigned short bits; + unsigned short bits, ctrl; + unsigned long flags; + int locked = 1; + + local_irq_save(flags); + if (port->sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&port->lock); + else + spin_lock(&port->lock); - sci_port_enable(sci_port); + /* first save the SCSCR then disable the interrupts */ + ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, sci_port->cfg->scscr); uart_console_write(port, s, count, serial_console_putchar); @@ -2217,10 +2230,15 @@ static void serial_console_write(struct console *co, const char *s, while ((serial_port_in(port, SCxSR) & bits) != bits) cpu_relax(); - sci_port_disable(sci_port); + /* restore the SCSCR */ + serial_port_out(port, SCSCR, ctrl); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); } -static int __devinit serial_console_setup(struct console *co, char *options) +static int serial_console_setup(struct console *co, char *options) { struct sci_port *sci_port; struct uart_port *port; @@ -2249,13 +2267,9 @@ static int __devinit serial_console_setup(struct console *co, char *options) if (unlikely(ret != 0)) return ret; - sci_port_enable(sci_port); - if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - sci_port_disable(sci_port); - return uart_set_options(port, co, baud, parity, bits, flow); } @@ -2278,7 +2292,7 @@ static struct console early_serial_console = { static char early_serial_buf[32]; -static int __devinit sci_probe_earlyprintk(struct platform_device *pdev) +static int sci_probe_earlyprintk(struct platform_device *pdev) { struct plat_sci_port *cfg = pdev->dev.platform_data; @@ -2298,57 +2312,15 @@ static int __devinit sci_probe_earlyprintk(struct platform_device *pdev) return 0; } -#define uart_console(port) ((port)->cons->index == (port)->line) - -static int sci_runtime_suspend(struct device *dev) -{ - struct sci_port *sci_port = dev_get_drvdata(dev); - struct uart_port *port = &sci_port->port; - - if (uart_console(port)) { - struct plat_sci_reg *reg; - - sci_port->saved_smr = serial_port_in(port, SCSMR); - sci_port->saved_brr = serial_port_in(port, SCBRR); - - reg = sci_getreg(port, SCFCR); - if (reg->size) - sci_port->saved_fcr = serial_port_in(port, SCFCR); - else - sci_port->saved_fcr = 0; - } - return 0; -} - -static int sci_runtime_resume(struct device *dev) -{ - struct sci_port *sci_port = dev_get_drvdata(dev); - struct uart_port *port = &sci_port->port; - - if (uart_console(port)) { - sci_reset(port); - serial_port_out(port, SCSMR, sci_port->saved_smr); - serial_port_out(port, SCBRR, sci_port->saved_brr); - - if (sci_port->saved_fcr) - serial_port_out(port, SCFCR, sci_port->saved_fcr); - - serial_port_out(port, SCSCR, sci_port->cfg->scscr); - } - return 0; -} - #define SCI_CONSOLE (&serial_console) #else -static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev) +static inline int sci_probe_earlyprintk(struct platform_device *pdev) { return -EINVAL; } #define SCI_CONSOLE NULL -#define sci_runtime_suspend NULL -#define sci_runtime_resume NULL #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ @@ -2379,7 +2351,7 @@ static int sci_remove(struct platform_device *dev) return 0; } -static int __devinit sci_probe_single(struct platform_device *dev, +static int sci_probe_single(struct platform_device *dev, unsigned int index, struct plat_sci_port *p, struct sci_port *sciport) @@ -2409,7 +2381,7 @@ static int __devinit sci_probe_single(struct platform_device *dev, return 0; } -static int __devinit sci_probe(struct platform_device *dev) +static int sci_probe(struct platform_device *dev) { struct plat_sci_port *p = dev->dev.platform_data; struct sci_port *sp = &sci_ports[dev->id]; @@ -2466,8 +2438,6 @@ static int sci_resume(struct device *dev) } static const struct dev_pm_ops sci_dev_pm_ops = { - .runtime_suspend = sci_runtime_suspend, - .runtime_resume = sci_runtime_resume, .suspend = sci_suspend, .resume = sci_resume, }; diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index a9e2bd1ab534..6bbfe9934a4d 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -75,6 +75,20 @@ static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = { .line = 2, }, }, + [3] = { + .port = { + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF, + .line = 3, + }, + }, + [4] = { + .port = { + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF, + .line = 4, + }, + }, }; static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port) @@ -192,11 +206,6 @@ static unsigned int sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) { unsigned int ch, rx_count = 0; - struct tty_struct *tty; - - tty = tty_port_tty_get(&port->state->port); - if (!tty) - return -ENODEV; while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) & SIRFUART_FIFOEMPTY_MASK(port))) { @@ -210,8 +219,7 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) } port->icount.rx += rx_count; - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(&port->state->port); return rx_count; } @@ -245,6 +253,7 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) struct uart_port *port = &sirfport->port; struct uart_state *state = port->state; struct circ_buf *xmit = &port->state->xmit; + spin_lock(&port->lock); intr_status = rd_regl(port, SIRFUART_INT_STATUS); wr_regl(port, SIRFUART_INT_STATUS, intr_status); intr_status &= rd_regl(port, SIRFUART_INT_EN); @@ -254,6 +263,7 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) goto recv_char; uart_insert_char(port, intr_status, SIRFUART_RX_OFLOW, 0, TTY_BREAK); + spin_unlock(&port->lock); return IRQ_HANDLED; } if (intr_status & SIRFUART_RX_OFLOW) @@ -286,6 +296,7 @@ recv_char: sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT); if (intr_status & SIRFUART_TX_INT_EN) { if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + spin_unlock(&port->lock); return IRQ_HANDLED; } else { sirfsoc_uart_pio_tx_chars(sirfport, @@ -296,6 +307,7 @@ recv_char: sirfsoc_uart_stop_tx(port); } } + spin_unlock(&port->lock); return IRQ_HANDLED; } @@ -345,7 +357,6 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, struct ktermios *old) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); - unsigned long ioclk_rate; unsigned long config_reg = 0; unsigned long baud_rate; unsigned long setted_baud; @@ -357,7 +368,6 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, int threshold_div; int temp; - ioclk_rate = 150000000; switch (termios->c_cflag & CSIZE) { default: case CS8: @@ -413,14 +423,17 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, sirfsoc_uart_disable_ms(port); } - /* common rate: fast calculation */ - for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++) - if (baud_rate == baudrate_to_regv[ic].baud_rate) - clk_div_reg = baudrate_to_regv[ic].reg_val; + if (port->uartclk == 150000000) { + /* common rate: fast calculation */ + for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++) + if (baud_rate == baudrate_to_regv[ic].baud_rate) + clk_div_reg = baudrate_to_regv[ic].reg_val; + } + setted_baud = baud_rate; /* arbitary rate setting */ if (unlikely(clk_div_reg == 0)) - clk_div_reg = sirfsoc_calc_sample_div(baud_rate, ioclk_rate, + clk_div_reg = sirfsoc_calc_sample_div(baud_rate, port->uartclk, &setted_baud); wr_regl(port, SIRFUART_DIVISOR, clk_div_reg); @@ -679,6 +692,14 @@ int sirfsoc_uart_probe(struct platform_device *pdev) goto err; } + sirfport->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(sirfport->clk)) { + ret = PTR_ERR(sirfport->clk); + goto clk_err; + } + clk_prepare_enable(sirfport->clk); + port->uartclk = clk_get_rate(sirfport->clk); + port->ops = &sirfsoc_uart_ops; spin_lock_init(&port->lock); @@ -692,6 +713,9 @@ int sirfsoc_uart_probe(struct platform_device *pdev) return 0; port_err: + clk_disable_unprepare(sirfport->clk); + clk_put(sirfport->clk); +clk_err: platform_set_drvdata(pdev, NULL); if (sirfport->hw_flow_ctrl) pinctrl_put(sirfport->p); @@ -706,6 +730,8 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (sirfport->hw_flow_ctrl) pinctrl_put(sirfport->p); + clk_disable_unprepare(sirfport->clk); + clk_put(sirfport->clk); uart_remove_one_port(&sirfsoc_uart_drv, port); return 0; } @@ -727,15 +753,16 @@ static int sirfsoc_uart_resume(struct platform_device *pdev) return 0; } -static struct of_device_id sirfsoc_uart_ids[] __devinitdata = { +static struct of_device_id sirfsoc_uart_ids[] = { { .compatible = "sirf,prima2-uart", }, + { .compatible = "sirf,marco-uart", }, {} }; MODULE_DEVICE_TABLE(of, sirfsoc_serial_of_match); static struct platform_driver sirfsoc_uart_driver = { .probe = sirfsoc_uart_probe, - .remove = __devexit_p(sirfsoc_uart_remove), + .remove = sirfsoc_uart_remove, .suspend = sirfsoc_uart_suspend, .resume = sirfsoc_uart_resume, .driver = { diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index 6e207fdc2fed..85328ba0c4e3 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -139,7 +139,7 @@ #define SIRFSOC_UART_MINOR 0 #define SIRFUART_PORT_NAME "sirfsoc-uart" #define SIRFUART_MAP_SIZE 0x200 -#define SIRFSOC_UART_NR 3 +#define SIRFSOC_UART_NR 5 #define SIRFSOC_PORT_TYPE 0xa5 /* Baud Rate Calculation */ @@ -163,6 +163,7 @@ struct sirfsoc_uart_port { struct uart_port port; struct pinctrl *p; + struct clk *clk; }; /* Hardware Flow Control */ diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c index 1c6de9f58699..f51ffdc696fd 100644 --- a/drivers/tty/serial/sn_console.c +++ b/drivers/tty/serial/sn_console.c @@ -457,8 +457,8 @@ static int sn_debug_printf(const char *fmt, ...) static void sn_receive_chars(struct sn_cons_port *port, unsigned long flags) { + struct tty_port *tport = NULL; int ch; - struct tty_struct *tty; if (!port) { printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n"); @@ -472,11 +472,7 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags) if (port->sc_port.state) { /* The serial_core stuffs are initialized, use them */ - tty = port->sc_port.state->port.tty; - } - else { - /* Not registered yet - can't pass to tty layer. */ - tty = NULL; + tport = &port->sc_port.state->port; } while (port->sc_ops->sal_input_pending()) { @@ -516,15 +512,15 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags) #endif /* CONFIG_MAGIC_SYSRQ */ /* record the character to pass up to the tty layer */ - if (tty) { - if(tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0) + if (tport) { + if (tty_insert_flip_char(tport, ch, TTY_NORMAL) == 0) break; } port->sc_port.icount.rx++; } - if (tty) - tty_flip_buffer_push(tty); + if (tport) + tty_flip_buffer_push(tport); } /** diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index 505961cfd934..ba60708053e0 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -72,7 +72,7 @@ static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit) } } -static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty) +static int receive_chars_getchar(struct uart_port *port) { int saw_console_brk = 0; int limit = 10000; @@ -99,7 +99,7 @@ static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty) uart_handle_dcd_change(port, 1); } - if (tty == NULL) { + if (port->state == NULL) { uart_handle_sysrq_char(port, c); continue; } @@ -109,13 +109,13 @@ static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty) if (uart_handle_sysrq_char(port, c)) continue; - tty_insert_flip_char(tty, c, TTY_NORMAL); + tty_insert_flip_char(&port->state->port, c, TTY_NORMAL); } return saw_console_brk; } -static int receive_chars_read(struct uart_port *port, struct tty_struct *tty) +static int receive_chars_read(struct uart_port *port) { int saw_console_brk = 0; int limit = 10000; @@ -152,12 +152,13 @@ static int receive_chars_read(struct uart_port *port, struct tty_struct *tty) for (i = 0; i < bytes_read; i++) uart_handle_sysrq_char(port, con_read_page[i]); - if (tty == NULL) + if (port->state == NULL) continue; port->icount.rx += bytes_read; - tty_insert_flip_string(tty, con_read_page, bytes_read); + tty_insert_flip_string(&port->state->port, con_read_page, + bytes_read); } return saw_console_brk; @@ -165,7 +166,7 @@ static int receive_chars_read(struct uart_port *port, struct tty_struct *tty) struct sunhv_ops { void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit); - int (*receive_chars)(struct uart_port *port, struct tty_struct *tty); + int (*receive_chars)(struct uart_port *port); }; static struct sunhv_ops bychar_ops = { @@ -180,17 +181,17 @@ static struct sunhv_ops bywrite_ops = { static struct sunhv_ops *sunhv_ops = &bychar_ops; -static struct tty_struct *receive_chars(struct uart_port *port) +static struct tty_port *receive_chars(struct uart_port *port) { - struct tty_struct *tty = NULL; + struct tty_port *tport = NULL; if (port->state != NULL) /* Unopened serial console */ - tty = port->state->port.tty; + tport = &port->state->port; - if (sunhv_ops->receive_chars(port, tty)) + if (sunhv_ops->receive_chars(port)) sun_do_break(); - return tty; + return tport; } static void transmit_chars(struct uart_port *port) @@ -213,16 +214,16 @@ static void transmit_chars(struct uart_port *port) static irqreturn_t sunhv_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty; + struct tty_port *tport; unsigned long flags; spin_lock_irqsave(&port->lock, flags); - tty = receive_chars(port); + tport = receive_chars(port); transmit_chars(port); spin_unlock_irqrestore(&port->lock, flags); - if (tty) - tty_flip_buffer_push(tty); + if (tport) + tty_flip_buffer_push(tport); return IRQ_HANDLED; } @@ -519,7 +520,7 @@ static struct console sunhv_console = { .data = &sunhv_reg, }; -static int __devinit hv_probe(struct platform_device *op) +static int hv_probe(struct platform_device *op) { struct uart_port *port; unsigned long minor; @@ -598,7 +599,7 @@ out_free_port: return err; } -static int __devexit hv_remove(struct platform_device *dev) +static int hv_remove(struct platform_device *dev) { struct uart_port *port = dev_get_drvdata(&dev->dev); @@ -636,7 +637,7 @@ static struct platform_driver hv_driver = { .of_match_table = hv_match, }, .probe = hv_probe, - .remove = __devexit_p(hv_remove), + .remove = hv_remove, }; static int __init sunhv_init(void) diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index f0d93eb7e6ec..8de2213664e0 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -107,11 +107,11 @@ static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up) udelay(1); } -static struct tty_struct * +static struct tty_port * receive_chars(struct uart_sunsab_port *up, union sab82532_irq_status *stat) { - struct tty_struct *tty = NULL; + struct tty_port *port = NULL; unsigned char buf[32]; int saw_console_brk = 0; int free_fifo = 0; @@ -119,7 +119,7 @@ receive_chars(struct uart_sunsab_port *up, int i; if (up->port.state != NULL) /* Unopened serial console */ - tty = up->port.state->port.tty; + port = &up->port.state->port; /* Read number of BYTES (Character + Status) available. */ if (stat->sreg.isr0 & SAB82532_ISR0_RPF) { @@ -136,7 +136,7 @@ receive_chars(struct uart_sunsab_port *up, if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { sunsab_cec_wait(up); writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr); - return tty; + return port; } if (stat->sreg.isr0 & SAB82532_ISR0_RFO) @@ -160,11 +160,6 @@ receive_chars(struct uart_sunsab_port *up, for (i = 0; i < count; i++) { unsigned char ch = buf[i], flag; - if (tty == NULL) { - uart_handle_sysrq_char(&up->port, ch); - continue; - } - flag = TTY_NORMAL; up->port.icount.rx++; @@ -213,15 +208,15 @@ receive_chars(struct uart_sunsab_port *up, if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 && (stat->sreg.isr1 & ((up->port.ignore_status_mask >> 8) & 0xff)) == 0) - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(port, ch, flag); if (stat->sreg.isr0 & SAB82532_ISR0_RFO) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(port, 0, TTY_OVERRUN); } if (saw_console_brk) sun_do_break(); - return tty; + return port; } static void sunsab_stop_tx(struct uart_port *); @@ -304,7 +299,7 @@ static void check_status(struct uart_sunsab_port *up, static irqreturn_t sunsab_interrupt(int irq, void *dev_id) { struct uart_sunsab_port *up = dev_id; - struct tty_struct *tty; + struct tty_port *port = NULL; union sab82532_irq_status status; unsigned long flags; unsigned char gis; @@ -318,12 +313,11 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) if (gis & 2) status.sreg.isr1 = readb(&up->regs->r.isr1); - tty = NULL; if (status.stat) { if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) || (status.sreg.isr1 & SAB82532_ISR1_BRK)) - tty = receive_chars(up, &status); + port = receive_chars(up, &status); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & SAB82532_ISR1_CSC)) check_status(up, &status); @@ -333,8 +327,8 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) spin_unlock_irqrestore(&up->port.lock, flags); - if (tty) - tty_flip_buffer_push(tty); + if (port) + tty_flip_buffer_push(port); return IRQ_HANDLED; } @@ -954,7 +948,7 @@ static inline struct console *SUNSAB_CONSOLE(void) #define sunsab_console_init() do { } while (0) #endif -static int __devinit sunsab_init_one(struct uart_sunsab_port *up, +static int sunsab_init_one(struct uart_sunsab_port *up, struct platform_device *op, unsigned long offset, int line) @@ -1007,7 +1001,7 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up, return 0; } -static int __devinit sab_probe(struct platform_device *op) +static int sab_probe(struct platform_device *op) { static int inst; struct uart_sunsab_port *up; @@ -1063,7 +1057,7 @@ out: return err; } -static int __devexit sab_remove(struct platform_device *op) +static int sab_remove(struct platform_device *op) { struct uart_sunsab_port *up = dev_get_drvdata(&op->dev); @@ -1100,7 +1094,7 @@ static struct platform_driver sab_driver = { .of_match_table = sab_match, }, .probe = sab_probe, - .remove = __devexit_p(sab_remove), + .remove = sab_remove, }; static int __init sunsab_init(void) diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index b97913dcdbff..e343d6670854 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -315,10 +315,10 @@ static void sunsu_enable_ms(struct uart_port *port) spin_unlock_irqrestore(&up->port.lock, flags); } -static struct tty_struct * +static void receive_chars(struct uart_sunsu_port *up, unsigned char *status) { - struct tty_struct *tty = up->port.state->port.tty; + struct tty_port *port = &up->port.state->port; unsigned char ch, flag; int max_count = 256; int saw_console_brk = 0; @@ -376,22 +376,20 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status) if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; if ((*status & up->port.ignore_status_mask) == 0) - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(port, ch, flag); if (*status & UART_LSR_OE) /* * Overrun is special, since it's reported * immediately, and doesn't affect the current * character. */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(port, 0, TTY_OVERRUN); ignore_char: *status = serial_inp(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); if (saw_console_brk) sun_do_break(); - - return tty; } static void transmit_chars(struct uart_sunsu_port *up) @@ -460,20 +458,16 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) spin_lock_irqsave(&up->port.lock, flags); do { - struct tty_struct *tty; - status = serial_inp(up, UART_LSR); - tty = NULL; if (status & UART_LSR_DR) - tty = receive_chars(up, &status); + receive_chars(up, &status); check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); spin_unlock_irqrestore(&up->port.lock, flags); - if (tty) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&up->port.state->port); spin_lock_irqsave(&up->port.lock, flags); @@ -1185,7 +1179,7 @@ static struct uart_driver sunsu_reg = { .major = TTY_MAJOR, }; -static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up) +static int sunsu_kbd_ms_init(struct uart_sunsu_port *up) { int quot, baud; #ifdef CONFIG_SERIO @@ -1391,7 +1385,7 @@ static inline struct console *SUNSU_CONSOLE(void) #define sunsu_serial_console_init() do { } while (0) #endif -static enum su_type __devinit su_get_type(struct device_node *dp) +static enum su_type su_get_type(struct device_node *dp) { struct device_node *ap = of_find_node_by_path("/aliases"); @@ -1412,7 +1406,7 @@ static enum su_type __devinit su_get_type(struct device_node *dp) return SU_PORT_PORT; } -static int __devinit su_probe(struct platform_device *op) +static int su_probe(struct platform_device *op) { static int inst; struct device_node *dp = op->dev.of_node; @@ -1503,7 +1497,7 @@ out_unmap: return err; } -static int __devexit su_remove(struct platform_device *op) +static int su_remove(struct platform_device *op) { struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); bool kbdms = false; @@ -1556,7 +1550,7 @@ static struct platform_driver su_driver = { .of_match_table = su_match, }, .probe = su_probe, - .remove = __devexit_p(su_remove), + .remove = su_remove, }; static int __init sunsu_init(void) diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index babd9470982b..27669ff3d446 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -323,17 +323,15 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, } } -static struct tty_struct * +static struct tty_port * sunzilog_receive_chars(struct uart_sunzilog_port *up, struct zilog_channel __iomem *channel) { - struct tty_struct *tty; + struct tty_port *port = NULL; unsigned char ch, r1, flag; - tty = NULL; - if (up->port.state != NULL && /* Unopened serial console */ - up->port.state->port.tty != NULL) /* Keyboard || mouse */ - tty = up->port.state->port.tty; + if (up->port.state != NULL) /* Unopened serial console */ + port = &up->port.state->port; for (;;) { @@ -366,11 +364,6 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, continue; } - if (tty == NULL) { - uart_handle_sysrq_char(&up->port, ch); - continue; - } - /* A real serial line, record the character and status. */ flag = TTY_NORMAL; up->port.icount.rx++; @@ -400,13 +393,13 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, if (up->port.ignore_status_mask == 0xff || (r1 & up->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(port, ch, flag); } if (r1 & Rx_OVR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(port, 0, TTY_OVERRUN); } - return tty; + return port; } static void sunzilog_status_handle(struct uart_sunzilog_port *up, @@ -539,21 +532,21 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) while (up) { struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - struct tty_struct *tty; + struct tty_port *port; unsigned char r3; spin_lock(&up->port.lock); r3 = read_zsreg(channel, R3); /* Channel A */ - tty = NULL; + port = NULL; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); if (r3 & CHARxIP) - tty = sunzilog_receive_chars(up, channel); + port = sunzilog_receive_chars(up, channel); if (r3 & CHAEXT) sunzilog_status_handle(up, channel); if (r3 & CHATxIP) @@ -561,22 +554,22 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) } spin_unlock(&up->port.lock); - if (tty) - tty_flip_buffer_push(tty); + if (port) + tty_flip_buffer_push(port); /* Channel B */ up = up->next; channel = ZILOG_CHANNEL_FROM_PORT(&up->port); spin_lock(&up->port.lock); - tty = NULL; + port = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); if (r3 & CHBRxIP) - tty = sunzilog_receive_chars(up, channel); + port = sunzilog_receive_chars(up, channel); if (r3 & CHBEXT) sunzilog_status_handle(up, channel); if (r3 & CHBTxIP) @@ -584,8 +577,8 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) } spin_unlock(&up->port.lock); - if (tty) - tty_flip_buffer_push(tty); + if (port) + tty_flip_buffer_push(port); up = up->next; } @@ -1282,7 +1275,7 @@ static inline struct console *SUNZILOG_CONSOLE(void) #define SUNZILOG_CONSOLE() (NULL) #endif -static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up) +static void sunzilog_init_kbdms(struct uart_sunzilog_port *up) { int baud, brg; @@ -1302,7 +1295,7 @@ static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up) } #ifdef CONFIG_SERIO -static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up) +static void sunzilog_register_serio(struct uart_sunzilog_port *up) { struct serio *serio = &up->serio; @@ -1331,7 +1324,7 @@ static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up) } #endif -static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) +static void sunzilog_init_hw(struct uart_sunzilog_port *up) { struct zilog_channel __iomem *channel; unsigned long flags; @@ -1400,7 +1393,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) static int zilog_irq; -static int __devinit zs_probe(struct platform_device *op) +static int zs_probe(struct platform_device *op) { static int kbm_inst, uart_inst; int inst; @@ -1507,7 +1500,7 @@ static int __devinit zs_probe(struct platform_device *op) return 0; } -static void __devexit zs_remove_one(struct uart_sunzilog_port *up) +static void zs_remove_one(struct uart_sunzilog_port *up) { if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { #ifdef CONFIG_SERIO @@ -1517,7 +1510,7 @@ static void __devexit zs_remove_one(struct uart_sunzilog_port *up) uart_remove_one_port(&sunzilog_reg, &up->port); } -static int __devexit zs_remove(struct platform_device *op) +static int zs_remove(struct platform_device *op) { struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev); struct zilog_layout __iomem *regs; @@ -1548,7 +1541,7 @@ static struct platform_driver zs_driver = { .of_match_table = zs_match, }, .probe = zs_probe, - .remove = __devexit_p(zs_remove), + .remove = zs_remove, }; static int __init sunzilog_init(void) diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 70f97491d8f2..6818410a2bea 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -91,16 +91,16 @@ static void timbuart_flush_buffer(struct uart_port *port) static void timbuart_rx_chars(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; while (ioread32(port->membase + TIMBUART_ISR) & RXDP) { u8 ch = ioread8(port->membase + TIMBUART_RXFIFO); port->icount.rx++; - tty_insert_flip_char(tty, ch, TTY_NORMAL); + tty_insert_flip_char(tport, ch, TTY_NORMAL); } spin_unlock(&port->lock); - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(tport); spin_lock(&port->lock); dev_dbg(port->dev, "%s - total read %d bytes\n", @@ -426,7 +426,7 @@ static struct uart_driver timbuart_driver = { .nr = 1 }; -static int __devinit timbuart_probe(struct platform_device *dev) +static int timbuart_probe(struct platform_device *dev) { int err, irq; struct timbuart_port *uart; @@ -492,7 +492,7 @@ err_mem: return err; } -static int __devexit timbuart_remove(struct platform_device *dev) +static int timbuart_remove(struct platform_device *dev) { struct timbuart_port *uart = platform_get_drvdata(dev); @@ -510,7 +510,7 @@ static struct platform_driver timbuart_platform_driver = { .owner = THIS_MODULE, }, .probe = timbuart_probe, - .remove = __devexit_p(timbuart_remove), + .remove = timbuart_remove, }; module_platform_driver(timbuart_platform_driver); diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 6579ffdd8e9b..5f90ef24d475 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -19,7 +19,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> @@ -34,7 +34,7 @@ * Register definitions * * For register details see datasheet: - * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf + * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf */ #define ULITE_RX 0x00 @@ -57,6 +57,54 @@ #define ULITE_CONTROL_RST_RX 0x02 #define ULITE_CONTROL_IE 0x10 +struct uartlite_reg_ops { + u32 (*in)(void __iomem *addr); + void (*out)(u32 val, void __iomem *addr); +}; + +static u32 uartlite_inbe32(void __iomem *addr) +{ + return ioread32be(addr); +} + +static void uartlite_outbe32(u32 val, void __iomem *addr) +{ + iowrite32be(val, addr); +} + +static struct uartlite_reg_ops uartlite_be = { + .in = uartlite_inbe32, + .out = uartlite_outbe32, +}; + +static u32 uartlite_inle32(void __iomem *addr) +{ + return ioread32(addr); +} + +static void uartlite_outle32(u32 val, void __iomem *addr) +{ + iowrite32(val, addr); +} + +static struct uartlite_reg_ops uartlite_le = { + .in = uartlite_inle32, + .out = uartlite_outle32, +}; + +static inline u32 uart_in32(u32 offset, struct uart_port *port) +{ + struct uartlite_reg_ops *reg_ops = port->private_data; + + return reg_ops->in(port->membase + offset); +} + +static inline void uart_out32(u32 val, u32 offset, struct uart_port *port) +{ + struct uartlite_reg_ops *reg_ops = port->private_data; + + reg_ops->out(val, port->membase + offset); +} static struct uart_port ulite_ports[ULITE_NR_UARTS]; @@ -66,7 +114,7 @@ static struct uart_port ulite_ports[ULITE_NR_UARTS]; static int ulite_receive(struct uart_port *port, int stat) { - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; unsigned char ch = 0; char flag = TTY_NORMAL; @@ -77,7 +125,7 @@ static int ulite_receive(struct uart_port *port, int stat) /* stats */ if (stat & ULITE_STATUS_RXVALID) { port->icount.rx++; - ch = ioread32be(port->membase + ULITE_RX); + ch = uart_in32(ULITE_RX, port); if (stat & ULITE_STATUS_PARITY) port->icount.parity++; @@ -103,13 +151,13 @@ static int ulite_receive(struct uart_port *port, int stat) stat &= ~port->ignore_status_mask; if (stat & ULITE_STATUS_RXVALID) - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(tport, ch, flag); if (stat & ULITE_STATUS_FRAME) - tty_insert_flip_char(tty, 0, TTY_FRAME); + tty_insert_flip_char(tport, 0, TTY_FRAME); if (stat & ULITE_STATUS_OVERRUN) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); return 1; } @@ -122,7 +170,7 @@ static int ulite_transmit(struct uart_port *port, int stat) return 0; if (port->x_char) { - iowrite32be(port->x_char, port->membase + ULITE_TX); + uart_out32(port->x_char, ULITE_TX, port); port->x_char = 0; port->icount.tx++; return 1; @@ -131,7 +179,7 @@ static int ulite_transmit(struct uart_port *port, int stat) if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return 0; - iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX); + uart_out32(xmit->buf[xmit->tail], ULITE_TX, port); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); port->icount.tx++; @@ -148,7 +196,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) int busy, n = 0; do { - int stat = ioread32be(port->membase + ULITE_STATUS); + int stat = uart_in32(ULITE_STATUS, port); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); n++; @@ -156,7 +204,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) /* work done? */ if (n > 1) { - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(&port->state->port); return IRQ_HANDLED; } else { return IRQ_NONE; @@ -169,7 +217,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port) unsigned int ret; spin_lock_irqsave(&port->lock, flags); - ret = ioread32be(port->membase + ULITE_STATUS); + ret = uart_in32(ULITE_STATUS, port); spin_unlock_irqrestore(&port->lock, flags); return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; @@ -192,7 +240,7 @@ static void ulite_stop_tx(struct uart_port *port) static void ulite_start_tx(struct uart_port *port) { - ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS)); + ulite_transmit(port, uart_in32(ULITE_STATUS, port)); } static void ulite_stop_rx(struct uart_port *port) @@ -220,17 +268,17 @@ static int ulite_startup(struct uart_port *port) if (ret) return ret; - iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, - port->membase + ULITE_CONTROL); - iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + uart_out32(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, + ULITE_CONTROL, port); + uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port); return 0; } static void ulite_shutdown(struct uart_port *port) { - iowrite32be(0, port->membase + ULITE_CONTROL); - ioread32be(port->membase + ULITE_CONTROL); /* dummy */ + uart_out32(0, ULITE_CONTROL, port); + uart_in32(ULITE_CONTROL, port); /* dummy */ free_irq(port->irq, port); } @@ -281,6 +329,8 @@ static void ulite_release_port(struct uart_port *port) static int ulite_request_port(struct uart_port *port) { + int ret; + pr_debug("ulite console: port=%p; port->mapbase=%llx\n", port, (unsigned long long) port->mapbase); @@ -296,6 +346,14 @@ static int ulite_request_port(struct uart_port *port) return -EBUSY; } + port->private_data = &uartlite_be; + ret = uart_in32(ULITE_CONTROL, port); + uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port); + ret = uart_in32(ULITE_STATUS, port); + /* Endianess detection */ + if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY) + port->private_data = &uartlite_le; + return 0; } @@ -314,20 +372,19 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) #ifdef CONFIG_CONSOLE_POLL static int ulite_get_poll_char(struct uart_port *port) { - if (!(ioread32be(port->membase + ULITE_STATUS) - & ULITE_STATUS_RXVALID)) + if (!(uart_in32(ULITE_STATUS, port) & ULITE_STATUS_RXVALID)) return NO_POLL_CHAR; - return ioread32be(port->membase + ULITE_RX); + return uart_in32(ULITE_RX, port); } static void ulite_put_poll_char(struct uart_port *port, unsigned char ch) { - while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL) + while (uart_in32(ULITE_STATUS, port) & ULITE_STATUS_TXFULL) cpu_relax(); /* write char to device */ - iowrite32be(ch, port->membase + ULITE_TX); + uart_out32(ch, ULITE_TX, port); } #endif @@ -366,7 +423,7 @@ static void ulite_console_wait_tx(struct uart_port *port) /* Spin waiting for TX fifo to have space available */ for (i = 0; i < 100000; i++) { - val = ioread32be(port->membase + ULITE_STATUS); + val = uart_in32(ULITE_STATUS, port); if ((val & ULITE_STATUS_TXFULL) == 0) break; cpu_relax(); @@ -376,7 +433,7 @@ static void ulite_console_wait_tx(struct uart_port *port) static void ulite_console_putchar(struct uart_port *port, int ch) { ulite_console_wait_tx(port); - iowrite32be(ch, port->membase + ULITE_TX); + uart_out32(ch, ULITE_TX, port); } static void ulite_console_write(struct console *co, const char *s, @@ -393,8 +450,8 @@ static void ulite_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; - iowrite32be(0, port->membase + ULITE_CONTROL); + ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE; + uart_out32(0, ULITE_CONTROL, port); uart_console_write(port, s, count, ulite_console_putchar); @@ -402,13 +459,13 @@ static void ulite_console_write(struct console *co, const char *s, /* restore interrupt state */ if (ier) - iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port); if (locked) spin_unlock_irqrestore(&port->lock, flags); } -static int __devinit ulite_console_setup(struct console *co, char *options) +static int ulite_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 9600; @@ -486,7 +543,7 @@ static struct uart_driver ulite_uart_driver = { * * Returns: 0 on success, <0 otherwise */ -static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) +static int ulite_assign(struct device *dev, int id, u32 base, int irq) { struct uart_port *port; int rc; @@ -542,7 +599,7 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) * * @dev: pointer to device structure */ -static int __devexit ulite_release(struct device *dev) +static int ulite_release(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); int rc = 0; @@ -562,7 +619,7 @@ static int __devexit ulite_release(struct device *dev) #if defined(CONFIG_OF) /* Match table for of_platform binding */ -static struct of_device_id ulite_of_match[] __devinitdata = { +static struct of_device_id ulite_of_match[] = { { .compatible = "xlnx,opb-uartlite-1.00.b", }, { .compatible = "xlnx,xps-uartlite-1.00.a", }, {} @@ -570,7 +627,7 @@ static struct of_device_id ulite_of_match[] __devinitdata = { MODULE_DEVICE_TABLE(of, ulite_of_match); #endif /* CONFIG_OF */ -static int __devinit ulite_probe(struct platform_device *pdev) +static int ulite_probe(struct platform_device *pdev) { struct resource *res, *res2; int id = pdev->id; @@ -593,7 +650,7 @@ static int __devinit ulite_probe(struct platform_device *pdev) return ulite_assign(&pdev->dev, id, res->start, res2->start); } -static int __devexit ulite_remove(struct platform_device *pdev) +static int ulite_remove(struct platform_device *pdev) { return ulite_release(&pdev->dev); } @@ -603,7 +660,7 @@ MODULE_ALIAS("platform:uartlite"); static struct platform_driver ulite_platform_driver = { .probe = ulite_probe, - .remove = __devexit_p(ulite_remove), + .remove = ulite_remove, .driver = { .owner = THIS_MODULE, .name = "uartlite", @@ -615,7 +672,7 @@ static struct platform_driver ulite_platform_driver = { * Module setup/teardown */ -int __init ulite_init(void) +static int __init ulite_init(void) { int ret; @@ -634,11 +691,11 @@ int __init ulite_init(void) err_plat: uart_unregister_driver(&ulite_uart_driver); err_uart: - printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); + pr_err("registering uartlite driver failed: err=%i", ret); return ret; } -void __exit ulite_exit(void) +static void __exit ulite_exit(void) { platform_driver_unregister(&ulite_platform_driver); uart_unregister_driver(&ulite_uart_driver); diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index f99b0c965f85..7355303dad99 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -469,7 +469,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) int i; unsigned char ch, *cp; struct uart_port *port = &qe_port->port; - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; struct qe_bd *bdp; u16 status; unsigned int flg; @@ -491,7 +491,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) /* If we don't have enough room in RX buffer for the entire BD, * then we try later, which will be the next RX interrupt. */ - if (tty_buffer_request_room(tty, i) < i) { + if (tty_buffer_request_room(tport, i) < i) { dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n"); return; } @@ -512,7 +512,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) continue; error_return: - tty_insert_flip_char(tty, ch, flg); + tty_insert_flip_char(tport, ch, flg); } @@ -530,7 +530,7 @@ error_return: qe_port->rx_cur = bdp; /* Activate BH processing */ - tty_flip_buffer_push(tty); + tty_flip_buffer_push(tport); return; @@ -560,7 +560,7 @@ handle_error: /* Overrun does not affect the current character ! */ if (status & BD_SC_OV) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); #ifdef SUPPORT_SYSRQ port->sysrq = 0; #endif diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index cf0d9485ec08..f655997f44af 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -313,12 +313,10 @@ static void siu_break_ctl(struct uart_port *port, int ctl) static inline void receive_chars(struct uart_port *port, uint8_t *status) { - struct tty_struct *tty; uint8_t lsr, ch; char flag; int max_count = RX_MAX_COUNT; - tty = port->state->port.tty; lsr = *status; do { @@ -365,7 +363,7 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status) lsr = siu_read(port, UART_LSR); } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); *status = lsr; } @@ -823,7 +821,7 @@ static struct console siu_console = { .data = &siu_uart_driver, }; -static int __devinit siu_console_init(void) +static int siu_console_init(void) { struct uart_port *port; int i; @@ -867,7 +865,7 @@ static struct uart_driver siu_uart_driver = { .cons = SERIAL_VR41XX_CONSOLE, }; -static int __devinit siu_probe(struct platform_device *dev) +static int siu_probe(struct platform_device *dev) { struct uart_port *port; int num, i, retval; @@ -901,7 +899,7 @@ static int __devinit siu_probe(struct platform_device *dev) return 0; } -static int __devexit siu_remove(struct platform_device *dev) +static int siu_remove(struct platform_device *dev) { struct uart_port *port; int i; @@ -952,7 +950,7 @@ static int siu_resume(struct platform_device *dev) static struct platform_driver siu_device_driver = { .probe = siu_probe, - .remove = __devexit_p(siu_remove), + .remove = siu_remove, .suspend = siu_suspend, .resume = siu_resume, .driver = { diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 205d4cf4a063..705240e6c4ec 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -136,22 +136,14 @@ static void vt8500_enable_ms(struct uart_port *port) static void handle_rx(struct uart_port *port) { - struct tty_struct *tty = tty_port_tty_get(&port->state->port); - if (!tty) { - /* Discard data: no tty available */ - int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8; - u16 ch; - while (count--) - ch = readw(port->membase + VT8500_RXFIFO); - return; - } + struct tty_port *tport = &port->state->port; /* * Handle overrun */ if ((vt8500_read(port, VT8500_URISR) & RXOVER)) { port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); } /* and now the main RX loop */ @@ -174,11 +166,10 @@ static void handle_rx(struct uart_port *port) port->icount.rx++; if (!uart_handle_sysrq_char(port, c)) - tty_insert_flip_char(tty, c, flag); + tty_insert_flip_char(tport, c, flag); } - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(tport); } static void handle_tx(struct uart_port *port) @@ -554,7 +545,7 @@ static struct uart_driver vt8500_uart_driver = { .cons = VT8500_CONSOLE, }; -static int __devinit vt8500_serial_probe(struct platform_device *pdev) +static int vt8500_serial_probe(struct platform_device *pdev) { struct vt8500_port *vt8500_port; struct resource *mmres, *irqres; @@ -567,13 +558,9 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) if (!mmres || !irqres) return -ENODEV; - vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL); - if (!vt8500_port) - return -ENOMEM; - if (np) port = of_alias_get_id(np, "serial"); - if (port > VT8500_MAX_PORTS) + if (port >= VT8500_MAX_PORTS) port = -1; else port = -1; @@ -584,7 +571,7 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) sizeof(vt8500_ports_in_use)); } - if (port > VT8500_MAX_PORTS) + if (port >= VT8500_MAX_PORTS) return -ENODEV; /* reserve the port id */ @@ -593,6 +580,27 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) return -EBUSY; } + vt8500_port = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_port), + GFP_KERNEL); + if (!vt8500_port) + return -ENOMEM; + + vt8500_port->uart.membase = devm_request_and_ioremap(&pdev->dev, mmres); + if (!vt8500_port->uart.membase) + return -EADDRNOTAVAIL; + + vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0); + if (IS_ERR(vt8500_port->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + return -EINVAL; + } + + ret = clk_prepare_enable(vt8500_port->clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock\n"); + return ret; + } + vt8500_port->uart.type = PORT_VT8500; vt8500_port->uart.iotype = UPIO_MEM; vt8500_port->uart.mapbase = mmres->start; @@ -603,24 +611,11 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) vt8500_port->uart.dev = &pdev->dev; vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0); - if (vt8500_port->clk) { - vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk); - } else { - /* use the default of 24Mhz if not specified and warn */ - pr_warn("%s: serial clock source not specified\n", __func__); - vt8500_port->uart.uartclk = 24000000; - } + vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk); snprintf(vt8500_port->name, sizeof(vt8500_port->name), "VT8500 UART%d", pdev->id); - vt8500_port->uart.membase = ioremap(mmres->start, resource_size(mmres)); - if (!vt8500_port->uart.membase) { - ret = -ENOMEM; - goto err; - } - vt8500_uart_ports[port] = vt8500_port; uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart); @@ -628,19 +623,15 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vt8500_port); return 0; - -err: - kfree(vt8500_port); - return ret; } -static int __devexit vt8500_serial_remove(struct platform_device *pdev) +static int vt8500_serial_remove(struct platform_device *pdev) { struct vt8500_port *vt8500_port = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); + clk_disable_unprepare(vt8500_port->clk); uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart); - kfree(vt8500_port); return 0; } @@ -652,7 +643,7 @@ static const struct of_device_id wmt_dt_ids[] = { static struct platform_driver vt8500_platform_driver = { .probe = vt8500_serial_probe, - .remove = __devexit_p(vt8500_serial_remove), + .remove = vt8500_serial_remove, .driver = { .name = "vt8500_serial", .owner = THIS_MODULE, diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index b627363352e5..ba451c7209fc 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -17,6 +17,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/console.h> +#include <linux/clk.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/of.h> @@ -147,15 +148,11 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; - struct tty_struct *tty; unsigned long flags; unsigned int isrstatus, numbytes; unsigned int data; char status = TTY_NORMAL; - /* Get the tty which could be NULL so don't assume it's valid */ - tty = tty_port_tty_get(&port->state->port); - spin_lock_irqsave(&port->lock, flags); /* Read the interrupt status register to determine which @@ -187,14 +184,11 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } else if (isrstatus & XUARTPS_IXR_OVERRUN) port->icount.overrun++; - if (tty) - uart_insert_char(port, isrstatus, - XUARTPS_IXR_OVERRUN, data, - status); + uart_insert_char(port, isrstatus, XUARTPS_IXR_OVERRUN, + data, status); } spin_unlock(&port->lock); - if (tty) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); spin_lock(&port->lock); } @@ -237,7 +231,6 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) /* be sure to release the lock and tty before leaving */ spin_unlock_irqrestore(&port->lock, flags); - tty_kref_put(tty); return IRQ_HANDLED; } @@ -939,25 +932,23 @@ static struct uart_driver xuartps_uart_driver = { * * Returns 0 on success, negative error otherwise **/ -static int __devinit xuartps_probe(struct platform_device *pdev) +static int xuartps_probe(struct platform_device *pdev) { int rc; struct uart_port *port; struct resource *res, *res2; - int clk = 0; - -#ifdef CONFIG_OF - const unsigned int *prop; + struct clk *clk; - prop = of_get_property(pdev->dev.of_node, "clock", NULL); - if (prop) - clk = be32_to_cpup(prop); -#else - clk = *((unsigned int *)(pdev->dev.platform_data)); -#endif - if (!clk) { + clk = of_clk_get(pdev->dev.of_node, 0); + if (IS_ERR(clk)) { dev_err(&pdev->dev, "no clock specified\n"); - return -ENODEV; + return PTR_ERR(clk); + } + + rc = clk_prepare_enable(clk); + if (rc) { + dev_err(&pdev->dev, "could not enable clock\n"); + return -EBUSY; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -982,7 +973,8 @@ static int __devinit xuartps_probe(struct platform_device *pdev) port->mapbase = res->start; port->irq = res2->start; port->dev = &pdev->dev; - port->uartclk = clk; + port->uartclk = clk_get_rate(clk); + port->private_data = clk; dev_set_drvdata(&pdev->dev, port); rc = uart_add_one_port(&xuartps_uart_driver, port); if (rc) { @@ -1001,17 +993,17 @@ static int __devinit xuartps_probe(struct platform_device *pdev) * * Returns 0 on success, negative error otherwise **/ -static int __devexit xuartps_remove(struct platform_device *pdev) +static int xuartps_remove(struct platform_device *pdev) { struct uart_port *port = dev_get_drvdata(&pdev->dev); - int rc = 0; + struct clk *clk = port->private_data; + int rc; /* Remove the xuartps port from the serial core */ - if (port) { - rc = uart_remove_one_port(&xuartps_uart_driver, port); - dev_set_drvdata(&pdev->dev, NULL); - port->mapbase = 0; - } + rc = uart_remove_one_port(&xuartps_uart_driver, port); + dev_set_drvdata(&pdev->dev, NULL); + port->mapbase = 0; + clk_disable_unprepare(clk); return rc; } @@ -1044,20 +1036,15 @@ static int xuartps_resume(struct platform_device *pdev) } /* Match table for of_platform binding */ - -#ifdef CONFIG_OF -static struct of_device_id xuartps_of_match[] __devinitdata = { +static struct of_device_id xuartps_of_match[] = { { .compatible = "xlnx,xuartps", }, {} }; MODULE_DEVICE_TABLE(of, xuartps_of_match); -#else -#define xuartps_of_match NULL -#endif static struct platform_driver xuartps_platform_driver = { .probe = xuartps_probe, /* Probe method */ - .remove = __exit_p(xuartps_remove), /* Detach method */ + .remove = xuartps_remove, /* Detach method */ .suspend = xuartps_suspend, /* Suspend */ .resume = xuartps_resume, /* Resume after a suspend */ .driver = { diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 92c00b24d0df..6a169877109b 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -603,7 +603,7 @@ static void zs_receive_chars(struct zs_port *zport) uart_insert_char(uport, status, Rx_OVR, ch, flag); } - tty_flip_buffer_push(uport->state->port.tty); + tty_flip_buffer_push(&uport->state->port); } static void zs_raw_transmit_chars(struct zs_port *zport) |