diff options
Diffstat (limited to 'drivers/serial')
36 files changed, 2773 insertions, 397 deletions
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index facb6785561..0276471cb25 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -237,6 +237,12 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); + if (port->info && port->info->tty) { + struct tty_struct *tty = port->info->tty; + unsigned int b = port->uartclk / (16 * quot); + tty_encode_baud_rate(tty, b, b); + } + switch (termios->c_cflag & CSIZE) { case CS5: h_lcr = 0x00; diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index aad4012bbb3..0d99120ab5a 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -1410,7 +1410,7 @@ rs68328_init(void) if (request_irq(uart_irqs[i], rs_interrupt, - IRQ_FLG_STD, + IRQF_DISABLED, "M68328_UART", NULL)) panic("Unable to attach 68328 serial interrupt\n"); } diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index f94109cbb46..b8a4bd94f51 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2047,7 +2047,7 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, * Oxford Semi 952 rev B workaround */ if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) - quot ++; + quot++; if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { if (baud < 2400) @@ -2662,16 +2662,17 @@ static int __devinit serial8250_probe(struct platform_device *dev) memset(&port, 0, sizeof(struct uart_port)); for (i = 0; p && p->flags != 0; p++, i++) { - port.iobase = p->iobase; - port.membase = p->membase; - port.irq = p->irq; - port.uartclk = p->uartclk; - port.regshift = p->regshift; - port.iotype = p->iotype; - port.flags = p->flags; - port.mapbase = p->mapbase; - port.hub6 = p->hub6; - port.dev = &dev->dev; + port.iobase = p->iobase; + port.membase = p->membase; + port.irq = p->irq; + port.uartclk = p->uartclk; + port.regshift = p->regshift; + port.iotype = p->iotype; + port.flags = p->flags; + port.mapbase = p->mapbase; + port.hub6 = p->hub6; + port.private_data = p->private_data; + port.dev = &dev->dev; if (share_irqs) port.flags |= UPF_SHARE_IRQ; ret = serial8250_register_port(&port); @@ -2812,15 +2813,16 @@ int serial8250_register_port(struct uart_port *port) if (uart) { uart_remove_one_port(&serial8250_reg, &uart->port); - uart->port.iobase = port->iobase; - uart->port.membase = port->membase; - uart->port.irq = port->irq; - uart->port.uartclk = port->uartclk; - uart->port.fifosize = port->fifosize; - uart->port.regshift = port->regshift; - uart->port.iotype = port->iotype; - uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; - uart->port.mapbase = port->mapbase; + uart->port.iobase = port->iobase; + uart->port.membase = port->membase; + uart->port.irq = port->irq; + uart->port.uartclk = port->uartclk; + uart->port.fifosize = port->fifosize; + uart->port.regshift = port->regshift; + uart->port.iotype = port->iotype; + uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; + uart->port.mapbase = port->mapbase; + uart->port.private_data = port->private_data; if (port->dev) uart->port.dev = port->dev; diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index ceb03c9e749..0a4ac2b6eb5 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -106,6 +106,32 @@ setup_port(struct serial_private *priv, struct uart_port *port, } /* + * ADDI-DATA GmbH communication cards <info@addi-data.com> + */ +static int addidata_apci7800_setup(struct serial_private *priv, + struct pciserial_board *board, + struct uart_port *port, int idx) +{ + unsigned int bar = 0, offset = board->first_offset; + bar = FL_GET_BASE(board->flags); + + if (idx < 2) { + offset += idx * board->uart_offset; + } else if ((idx >= 2) && (idx < 4)) { + bar += 1; + offset += ((idx - 2) * board->uart_offset); + } else if ((idx >= 4) && (idx < 6)) { + bar += 2; + offset += ((idx - 4) * board->uart_offset); + } else if (idx >= 6) { + bar += 3; + offset += ((idx - 6) * board->uart_offset); + } + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +/* * AFAVLAB uses a different mixture of BARs and offsets * Not that ugly ;) -- HW */ @@ -752,6 +778,16 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board, */ static struct pci_serial_quirk pci_serial_quirks[] = { /* + * ADDI-DATA GmbH communication cards <info@addi-data.com> + */ + { + .vendor = PCI_VENDOR_ID_ADDIDATA_OLD, + .device = PCI_DEVICE_ID_ADDIDATA_APCI7800, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = addidata_apci7800_setup, + }, + /* * AFAVLAB cards - these may be called via parport_serial * It is not clear whether this applies to all products. */ @@ -1179,6 +1215,12 @@ static struct pciserial_board pci_boards[] __devinitdata = { .base_baud = 115200, .uart_offset = 8, }, + [pbn_b0_8_115200] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + }, [pbn_b0_1_921600] = { .flags = FL_BASE0, @@ -2697,6 +2739,97 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_pasemi_1682M }, /* + * ADDI-DATA GmbH communication cards <info@addi-data.com> + */ + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7500, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7420, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_2_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7300, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_ADDIDATA_OLD, + PCI_DEVICE_ID_ADDIDATA_APCI7800, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b1_8_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7500_2, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7420_2, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_2_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7300_2, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7500_3, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7420_3, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_2_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7300_3, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7800_3, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_8_115200 }, + + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL */ diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index 1de098e7549..6f09cbd7fc4 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -414,8 +414,9 @@ static int __devinit check_resources(struct pnp_option *option) */ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) { - if (!(check_name(pnp_dev_name(dev)) || (dev->card && check_name(dev->card->name)))) - return -ENODEV; + if (!(check_name(pnp_dev_name(dev)) || + (dev->card && check_name(dev->card->name)))) + return -ENODEV; if (check_resources(dev->independent)) return 0; @@ -452,8 +453,9 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) return -ENODEV; #ifdef SERIAL_DEBUG_PNP - printk("Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n", - port.iobase, port.mapbase, port.irq, port.iotype); + printk(KERN_DEBUG + "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n", + port.iobase, port.mapbase, port.irq, port.iotype); #endif port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index d7e1996e2fe..6a44fb1dc16 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -877,15 +877,15 @@ config SERIAL_SUNHV systems. Say Y if you want to be able to use this device. config SERIAL_IP22_ZILOG - tristate "IP22 Zilog8530 serial support" - depends on SGI_IP22 + tristate "SGI Zilog8530 serial support" + depends on SGI_HAS_ZILOG select SERIAL_CORE help - This driver supports the Zilog8530 serial ports found on SGI IP22 + This driver supports the Zilog8530 serial ports found on SGI systems. Say Y or M if you want to be able to these serial ports. config SERIAL_IP22_ZILOG_CONSOLE - bool "Console on IP22 Zilog8530 serial port" + bool "Console on SGI Zilog8530 serial port" depends on SERIAL_IP22_ZILOG=y select SERIAL_CORE_CONSOLE @@ -960,6 +960,30 @@ config SERIAL_COLDFIRE This driver supports the built-in serial ports of the Motorola ColdFire family of CPUs. +config SERIAL_MCF + bool "Coldfire serial support (new style driver)" + depends on COLDFIRE + select SERIAL_CORE + help + This new serial driver supports the Freescale Coldfire serial ports + using the new serial driver subsystem. + +config SERIAL_MCF_BAUDRATE + int "Default baudrate for Coldfire serial ports" + depends on SERIAL_MCF + default 19200 + help + This setting lets you define what the default baudrate is for the + ColdFire serial ports. The usual default varies from board to board, + and this setting is a way of catering for that. + +config SERIAL_MCF_CONSOLE + bool "Coldfire serial console support" + depends on SERIAL_MCF + select SERIAL_CORE_CONSOLE + help + Enable a ColdFire internal serial port to be the system console. + config SERIAL_68360_SMC bool "68360 SMC uart support" depends on M68360 @@ -1271,8 +1295,8 @@ config SERIAL_NETX_CONSOLE depends on SERIAL_NETX select SERIAL_CORE_CONSOLE help - If you have enabled the serial port on the Motorola IMX - CPU you can make it the console by answering Y to this option. + If you have enabled the serial port on the Hilscher NetX SoC + you can make it the console by answering Y to this option. config SERIAL_OF_PLATFORM tristate "Serial port on Open Firmware platform bus" @@ -1284,4 +1308,29 @@ config SERIAL_OF_PLATFORM Currently, only 8250 compatible ports are supported, but others can easily be added. +config SERIAL_QE + tristate "Freescale QUICC Engine serial port support" + depends on QUICC_ENGINE + select SERIAL_CORE + select FW_LOADER + default n + help + This driver supports the QE serial ports on Freescale embedded + PowerPC that contain a QUICC Engine. + +config SERIAL_SC26XX + tristate "SC2681/SC2692 serial port support" + depends on SNI_RM + select SERIAL_CORE + help + This is a driver for the onboard serial ports of + older RM400 machines. + +config SERIAL_SC26XX_CONSOLE + bool "Console on SC2681/SC2692 serial port" + depends on SERIAL_SC26XX + select SERIAL_CORE_CONSOLE + help + Support for Console on SC2681/SC2692 serial ports. + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index af6377d480d..640cfe44a56 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o +obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o @@ -54,6 +55,7 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o obj-$(CONFIG_SERIAL_MPSC) += mpsc.o obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o +obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o @@ -64,3 +66,4 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o +obj-$(CONFIG_SERIAL_QE) += ucc_uart.o diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 111da57f533..60f52904aad 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -34,6 +34,7 @@ #include <linux/tty_flip.h> #include <linux/platform_device.h> #include <linux/atmel_pdc.h> +#include <linux/atmel_serial.h> #include <asm/io.h> @@ -45,8 +46,6 @@ #include <asm/arch/gpio.h> #endif -#include "atmel_serial.h" - #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h deleted file mode 100644 index e0141776517..00000000000 --- a/drivers/serial/atmel_serial.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * drivers/serial/atmel_serial.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * USART registers. - * Based on AT91RM9200 datasheet revision E. - * - * 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. - */ - -#ifndef ATMEL_SERIAL_H -#define ATMEL_SERIAL_H - -#define ATMEL_US_CR 0x00 /* Control Register */ -#define ATMEL_US_RSTRX (1 << 2) /* Reset Receiver */ -#define ATMEL_US_RSTTX (1 << 3) /* Reset Transmitter */ -#define ATMEL_US_RXEN (1 << 4) /* Receiver Enable */ -#define ATMEL_US_RXDIS (1 << 5) /* Receiver Disable */ -#define ATMEL_US_TXEN (1 << 6) /* Transmitter Enable */ -#define ATMEL_US_TXDIS (1 << 7) /* Transmitter Disable */ -#define ATMEL_US_RSTSTA (1 << 8) /* Reset Status Bits */ -#define ATMEL_US_STTBRK (1 << 9) /* Start Break */ -#define ATMEL_US_STPBRK (1 << 10) /* Stop Break */ -#define ATMEL_US_STTTO (1 << 11) /* Start Time-out */ -#define ATMEL_US_SENDA (1 << 12) /* Send Address */ -#define ATMEL_US_RSTIT (1 << 13) /* Reset Iterations */ -#define ATMEL_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */ -#define ATMEL_US_RETTO (1 << 15) /* Rearm Time-out */ -#define ATMEL_US_DTREN (1 << 16) /* Data Terminal Ready Enable [AT91RM9200 only] */ -#define ATMEL_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable [AT91RM9200 only] */ -#define ATMEL_US_RTSEN (1 << 18) /* Request To Send Enable */ -#define ATMEL_US_RTSDIS (1 << 19) /* Request To Send Disable */ - -#define ATMEL_US_MR 0x04 /* Mode Register */ -#define ATMEL_US_USMODE (0xf << 0) /* Mode of the USART */ -#define ATMEL_US_USMODE_NORMAL 0 -#define ATMEL_US_USMODE_RS485 1 -#define ATMEL_US_USMODE_HWHS 2 -#define ATMEL_US_USMODE_MODEM 3 -#define ATMEL_US_USMODE_ISO7816_T0 4 -#define ATMEL_US_USMODE_ISO7816_T1 6 -#define ATMEL_US_USMODE_IRDA 8 -#define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */ -#define ATMEL_US_USCLKS_MCK (0 << 4) -#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4) -#define ATMEL_US_USCLKS_SCK (3 << 4) -#define ATMEL_US_CHRL (3 << 6) /* Character Length */ -#define ATMEL_US_CHRL_5 (0 << 6) -#define ATMEL_US_CHRL_6 (1 << 6) -#define ATMEL_US_CHRL_7 (2 << 6) -#define ATMEL_US_CHRL_8 (3 << 6) -#define ATMEL_US_SYNC (1 << 8) /* Synchronous Mode Select */ -#define ATMEL_US_PAR (7 << 9) /* Parity Type */ -#define ATMEL_US_PAR_EVEN (0 << 9) -#define ATMEL_US_PAR_ODD (1 << 9) -#define ATMEL_US_PAR_SPACE (2 << 9) -#define ATMEL_US_PAR_MARK (3 << 9) -#define ATMEL_US_PAR_NONE (4 << 9) -#define ATMEL_US_PAR_MULTI_DROP (6 << 9) -#define ATMEL_US_NBSTOP (3 << 12) /* Number of Stop Bits */ -#define ATMEL_US_NBSTOP_1 (0 << 12) -#define ATMEL_US_NBSTOP_1_5 (1 << 12) -#define ATMEL_US_NBSTOP_2 (2 << 12) -#define ATMEL_US_CHMODE (3 << 14) /* Channel Mode */ -#define ATMEL_US_CHMODE_NORMAL (0 << 14) -#define ATMEL_US_CHMODE_ECHO (1 << 14) -#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14) -#define ATMEL_US_CHMODE_REM_LOOP (3 << 14) -#define ATMEL_US_MSBF (1 << 16) /* Bit Order */ -#define ATMEL_US_MODE9 (1 << 17) /* 9-bit Character Length */ -#define ATMEL_US_CLKO (1 << 18) /* Clock Output Select */ -#define ATMEL_US_OVER (1 << 19) /* Oversampling Mode */ -#define ATMEL_US_INACK (1 << 20) /* Inhibit Non Acknowledge */ -#define ATMEL_US_DSNACK (1 << 21) /* Disable Successive NACK */ -#define ATMEL_US_MAX_ITER (7 << 24) /* Max Iterations */ -#define ATMEL_US_FILTER (1 << 28) /* Infrared Receive Line Filter */ - -#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ -#define ATMEL_US_RXRDY (1 << 0) /* Receiver Ready */ -#define ATMEL_US_TXRDY (1 << 1) /* Transmitter Ready */ -#define ATMEL_US_RXBRK (1 << 2) /* Break Received / End of Break */ -#define ATMEL_US_ENDRX (1 << 3) /* End of Receiver Transfer */ -#define ATMEL_US_ENDTX (1 << 4) /* End of Transmitter Transfer */ -#define ATMEL_US_OVRE (1 << 5) /* Overrun Error */ -#define ATMEL_US_FRAME (1 << 6) /* Framing Error */ -#define ATMEL_US_PARE (1 << 7) /* Parity Error */ -#define ATMEL_US_TIMEOUT (1 << 8) /* Receiver Time-out */ -#define ATMEL_US_TXEMPTY (1 << 9) /* Transmitter Empty */ -#define ATMEL_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */ -#define ATMEL_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */ -#define ATMEL_US_RXBUFF (1 << 12) /* Reception Buffer Full */ -#define ATMEL_US_NACK (1 << 13) /* Non Acknowledge */ -#define ATMEL_US_RIIC (1 << 16) /* Ring Indicator Input Change [AT91RM9200 only] */ -#define ATMEL_US_DSRIC (1 << 17) /* Data Set Ready Input Change [AT91RM9200 only] */ -#define ATMEL_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change [AT91RM9200 only] */ -#define ATMEL_US_CTSIC (1 << 19) /* Clear to Send Input Change */ -#define ATMEL_US_RI (1 << 20) /* RI */ -#define ATMEL_US_DSR (1 << 21) /* DSR */ -#define ATMEL_US_DCD (1 << 22) /* DCD */ -#define ATMEL_US_CTS (1 << 23) /* CTS */ - -#define ATMEL_US_IDR 0x0c /* Interrupt Disable Register */ -#define ATMEL_US_IMR 0x10 /* Interrupt Mask Register */ -#define ATMEL_US_CSR 0x14 /* Channel Status Register */ -#define ATMEL_US_RHR 0x18 /* Receiver Holding Register */ -#define ATMEL_US_THR 0x1c /* Transmitter Holding Register */ -#define ATMEL_US_SYNH (1 << 15) /* Transmit/Receive Sync [AT91SAM9261 only] */ - -#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ -#define ATMEL_US_CD (0xffff << 0) /* Clock Divider */ - -#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */ -#define ATMEL_US_TO (0xffff << 0) /* Time-out Value */ - -#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */ -#define ATMEL_US_TG (0xff << 0) /* Timeguard Value */ - -#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */ -#define ATMEL_US_NER 0x44 /* Number of Errors Register */ -#define ATMEL_US_IF 0x4c /* IrDA Filter Register */ - -#endif diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 6f475b60986..ac2a3ef28d5 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -442,7 +442,8 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, INTR_ON_BUF, DIMENSION_LINEAR, - DATA_SIZE_8)); + DATA_SIZE_8, + DMA_SYNC_RESTART)); set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_modify(uart->tx_dma_channel, 1); @@ -689,7 +690,8 @@ static int bfin_serial_startup(struct uart_port *port) set_dma_config(uart->rx_dma_channel, set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, INTR_ON_ROW, DIMENSION_2D, - DATA_SIZE_8)); + DATA_SIZE_8, + DMA_SYNC_RESTART)); set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT); set_dma_x_modify(uart->rx_dma_channel, 1); set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT); diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index b5e4478de0e..236af9d3385 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -380,7 +380,7 @@ static void cpm_uart_int_rx(struct uart_port *port) static irqreturn_t cpm_uart_int(int irq, void *data) { u8 events; - struct uart_port *port = (struct uart_port *)data; + struct uart_port *port = data; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; smc_t __iomem *smcp = pinfo->smcp; scc_t __iomem *sccp = pinfo->sccp; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 52fb044bb79..6ea0366e26a 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -52,11 +52,7 @@ #ifdef CONFIG_PPC_CPM_NEW_BINDING void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { - u16 __iomem *cpcr = &cpmp->cp_cpcr; - - out_be16(cpcr, port->command | (cmd << 8) | CPM_CR_FLG); - while (in_be16(cpcr) & CPM_CR_FLG) - ; + cpm_command(port->command, cmd); } #else void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index 9b5465fb0bb..ddf46d3c964 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -10,7 +10,7 @@ #ifndef CPM_UART_CPM1_H #define CPM_UART_CPM1_H -#include <asm/commproc.h> +#include <asm/cpm1.h> /* defines for IRQs */ #ifndef CONFIG_PPC_CPM_NEW_BINDING diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 882dbc17d59..d9af06a791b 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -52,13 +52,7 @@ #ifdef CONFIG_PPC_CPM_NEW_BINDING void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { - cpm_cpm2_t __iomem *cp = cpm2_map(im_cpm); - - out_be32(&cp->cp_cpcr, port->command | cmd | CPM_CR_FLG); - while (in_be32(&cp->cp_cpcr) & CPM_CR_FLG) - ; - - cpm2_unmap(cp); + cpm_command(port->command, cmd); } #else void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) @@ -171,9 +165,9 @@ void scc2_lineif(struct uart_cpm_port *pinfo) * really has to get out of the driver so boards can * be supported in a sane fashion. */ + volatile cpmux_t *cpmux = cpm2_map(im_cpmux); #ifndef CONFIG_STX_GP3 volatile iop_cpm2_t *io = cpm2_map(im_ioport); - volatile cpmux_t *cpmux = cpm2_map(im_cpmux); io->iop_pparb |= 0x008b0000; io->iop_pdirb |= 0x00880000; diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index d31721f2744..bbae5a22021 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -324,7 +324,7 @@ static inline void check_modem_status(struct dz_port *dport) */ static irqreturn_t dz_interrupt(int irq, void *dev) { - struct dz_port *dport = (struct dz_port *)dev; + struct dz_port *dport = dev; unsigned short status; /* get the reason why we just got an irq */ diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 9d3105b64a7..9c2df5c857c 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -48,7 +48,7 @@ #include <linux/vmalloc.h> #include <linux/smp.h> #include <linux/spinlock.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/firmware.h> #include <linux/bitops.h> @@ -65,7 +65,7 @@ #define ICOM_VERSION_STR "1.3.1" #define NR_PORTS 128 #define ICOM_PORT ((struct icom_port *)port) -#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj) +#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref) static const struct pci_device_id icom_pci_table[] = { { @@ -141,6 +141,7 @@ static inline void trace(struct icom_port *, char *, unsigned long) {}; #else static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; #endif +static void icom_kref_release(struct kref *kref); static void free_port_memory(struct icom_port *icom_port) { @@ -1063,11 +1064,11 @@ static int icom_open(struct uart_port *port) { int retval; - kobject_get(&ICOM_PORT->adapter->kobj); + kref_get(&ICOM_PORT->adapter->kref); retval = startup(ICOM_PORT); if (retval) { - kobject_put(&ICOM_PORT->adapter->kobj); + kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); trace(ICOM_PORT, "STARTUP_ERROR", 0); return retval; } @@ -1088,7 +1089,7 @@ static void icom_close(struct uart_port *port) shutdown(ICOM_PORT); - kobject_put(&ICOM_PORT->adapter->kobj); + kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); } static void icom_set_termios(struct uart_port *port, @@ -1485,18 +1486,14 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) pci_release_regions(icom_adapter->pci_dev); } -static void icom_kobj_release(struct kobject *kobj) +static void icom_kref_release(struct kref *kref) { struct icom_adapter *icom_adapter; - icom_adapter = to_icom_adapter(kobj); + icom_adapter = to_icom_adapter(kref); icom_remove_adapter(icom_adapter); } -static struct kobj_type icom_kobj_type = { - .release = icom_kobj_release, -}; - static int __devinit icom_probe(struct pci_dev *dev, const struct pci_device_id *ent) { @@ -1592,8 +1589,7 @@ static int __devinit icom_probe(struct pci_dev *dev, } } - kobject_init(&icom_adapter->kobj); - icom_adapter->kobj.ktype = &icom_kobj_type; + kref_init(&icom_adapter->kref); return 0; probe_exit2: @@ -1619,7 +1615,7 @@ static void __devexit icom_remove(struct pci_dev *dev) icom_adapter = list_entry(tmp, struct icom_adapter, icom_adapter_entry); if (icom_adapter->pci_dev == dev) { - kobject_put(&icom_adapter->kobj); + kref_put(&icom_adapter->kref, icom_kref_release); return; } } diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h index e8578d8cd35..c8029e0025c 100644 --- a/drivers/serial/icom.h +++ b/drivers/serial/icom.h @@ -20,7 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include<linux/serial_core.h> +#include <linux/serial_core.h> #define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1) static int icom_acfg_baud[] = { @@ -270,7 +270,7 @@ struct icom_adapter { #define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 int numb_ports; struct list_head icom_adapter_entry; - struct kobject kobj; + struct kref kref; }; /* prototype */ diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index dc1967176fe..56af1f566a4 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -308,7 +308,7 @@ static void imx_start_tx(struct uart_port *port) static irqreturn_t imx_rtsint(int irq, void *dev_id) { - struct imx_port *sport = (struct imx_port *)dev_id; + struct imx_port *sport = dev_id; unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; unsigned long flags; @@ -324,7 +324,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id) static irqreturn_t imx_txint(int irq, void *dev_id) { - struct imx_port *sport = (struct imx_port *)dev_id; + struct imx_port *sport = dev_id; struct circ_buf *xmit = &sport->port.info->xmit; unsigned long flags; diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c index a7d4360ea7d..e76fc72c9b3 100644 --- a/drivers/serial/mcf.c +++ b/drivers/serial/mcf.c @@ -69,7 +69,7 @@ static unsigned int mcf_tx_empty(struct uart_port *port) static unsigned int mcf_get_mctrl(struct uart_port *port) { - struct mcf_uart *pp = (struct mcf_uart *) port; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; unsigned int sigs; @@ -87,7 +87,7 @@ static unsigned int mcf_get_mctrl(struct uart_port *port) static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) { - struct mcf_uart *pp = (struct mcf_uart *) port; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -104,7 +104,7 @@ static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) static void mcf_start_tx(struct uart_port *port) { - struct mcf_uart *pp = (struct mcf_uart *) port; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -117,7 +117,7 @@ static void mcf_start_tx(struct uart_port *port) static void mcf_stop_tx(struct uart_port *port) { - struct mcf_uart *pp = (struct mcf_uart *) port; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -130,7 +130,7 @@ static void mcf_stop_tx(struct uart_port *port) static void mcf_stop_rx(struct uart_port *port) { - struct mcf_uart *pp = (struct mcf_uart *) port; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -163,7 +163,7 @@ static void mcf_enable_ms(struct uart_port *port) static int mcf_startup(struct uart_port *port) { - struct mcf_uart *pp = (struct mcf_uart *) port; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -189,7 +189,7 @@ static int mcf_startup(struct uart_port *port) static void mcf_shutdown(struct uart_port *port) { - struct mcf_uart *pp = (struct mcf_uart *) port; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -273,7 +273,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, static void mcf_rx_chars(struct mcf_uart *pp) { - struct uart_port *port = (struct uart_port *) pp; + struct uart_port *port = &pp->port; unsigned char status, ch, flag; while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) { @@ -319,7 +319,7 @@ static void mcf_rx_chars(struct mcf_uart *pp) static void mcf_tx_chars(struct mcf_uart *pp) { - struct uart_port *port = (struct uart_port *) pp; + struct uart_port *port = &pp->port; struct circ_buf *xmit = &port->info->xmit; if (port->x_char) { @@ -352,7 +352,7 @@ static void mcf_tx_chars(struct mcf_uart *pp) static irqreturn_t mcf_interrupt(int irq, void *data) { struct uart_port *port = data; - struct mcf_uart *pp = (struct mcf_uart *) port; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned int isr; isr = readb(port->membase + MCFUART_UISR) & pp->imr; @@ -434,7 +434,7 @@ static struct uart_ops mcf_uart_ops = { static struct mcf_uart mcf_ports[3]; -#define MCF_MAXPORTS (sizeof(mcf_ports) / sizeof(struct mcf_uart)) +#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports) /****************************************************************************/ #if defined(CONFIG_SERIAL_MCF_CONSOLE) diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index ec36ad78d2f..3c4d29e59b2 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -36,7 +36,7 @@ * DCD. However, the pin multiplexing aren't changed and should be set either * by the bootloader or in the platform init code. * - * The idx field must be equal to the PSC index ( e.g. 0 for PSC1, 1 for PSC2, + * The idx field must be equal to the PSC index (e.g. 0 for PSC1, 1 for PSC2, * and so on). So the PSC1 is mapped to /dev/ttyPSC0, PSC2 to /dev/ttyPSC1 and * so on. But be warned, it's an ABSOLUTE REQUIREMENT ! This is needed mainly * fpr the console code : without this 1:1 mapping, at early boot time, when we @@ -68,11 +68,12 @@ #include <linux/sysrq.h> #include <linux/console.h> -#include <asm/delay.h> -#include <asm/io.h> +#include <linux/delay.h> +#include <linux/io.h> #if defined(CONFIG_PPC_MERGE) -#include <asm/of_platform.h> +#include <linux/of.h> +#include <linux/of_platform.h> #else #include <linux/platform_device.h> #endif @@ -111,23 +112,27 @@ static void mpc52xx_uart_of_enumerate(void); #endif #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) +#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) /* Forward declaration of the interruption handling routine */ -static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id); +static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); /* Simple macro to test if a port is console or not. This one is taken * for serial_core.c and maybe should be moved to serial_core.h ? */ #ifdef CONFIG_SERIAL_CORE_CONSOLE -#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) +#define uart_console(port) \ + ((port)->cons && (port)->cons->index == (port)->line) #else #define uart_console(port) (0) #endif #if defined(CONFIG_PPC_MERGE) static struct of_device_id mpc52xx_uart_of_match[] = { - { .type = "serial", .compatible = "mpc5200-psc-uart", }, + { .type = "serial", .compatible = "fsl,mpc5200-psc-uart", }, + { .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */ + { .type = "serial", .compatible = "mpc5200-serial", }, /* efika */ {}, }; #endif @@ -162,7 +167,7 @@ mpc52xx_uart_stop_tx(struct uart_port *port) { /* port->lock taken by caller */ port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); } static void @@ -170,7 +175,7 @@ mpc52xx_uart_start_tx(struct uart_port *port) { /* port->lock taken by caller */ port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); } static void @@ -184,7 +189,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch) /* Make sure tx interrupts are on */ /* Truly necessary ??? They should be anyway */ port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); } spin_unlock_irqrestore(&port->lock, flags); @@ -195,7 +200,7 @@ mpc52xx_uart_stop_rx(struct uart_port *port) { /* port->lock taken by caller */ port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); } static void @@ -210,10 +215,10 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) unsigned long flags; spin_lock_irqsave(&port->lock, flags); - if ( ctl == -1 ) - out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK); + if (ctl == -1) + out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK); else - out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK); + out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK); spin_unlock_irqrestore(&port->lock, flags); } @@ -222,6 +227,7 @@ static int mpc52xx_uart_startup(struct uart_port *port) { struct mpc52xx_psc __iomem *psc = PSC(port); + struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port); int ret; /* Request IRQ */ @@ -231,23 +237,23 @@ mpc52xx_uart_startup(struct uart_port *port) return ret; /* Reset/activate the port, clear and enable interrupts */ - out_8(&psc->command,MPC52xx_PSC_RST_RX); - out_8(&psc->command,MPC52xx_PSC_RST_TX); + out_8(&psc->command, MPC52xx_PSC_RST_RX); + out_8(&psc->command, MPC52xx_PSC_RST_TX); - out_be32(&psc->sicr,0); /* UART mode DCD ignored */ + out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */ - out_8(&psc->rfcntl, 0x00); - out_be16(&psc->rfalarm, 0x1ff); - out_8(&psc->tfcntl, 0x07); - out_be16(&psc->tfalarm, 0x80); + out_8(&fifo->rfcntl, 0x00); + out_be16(&fifo->rfalarm, 0x1ff); + out_8(&fifo->tfcntl, 0x07); + out_be16(&fifo->tfalarm, 0x80); port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; - out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask); + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); - out_8(&psc->command,MPC52xx_PSC_TX_ENABLE); - out_8(&psc->command,MPC52xx_PSC_RX_ENABLE); + out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); + out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); return 0; } @@ -258,12 +264,12 @@ mpc52xx_uart_shutdown(struct uart_port *port) struct mpc52xx_psc __iomem *psc = PSC(port); /* Shut down the port. Leave TX active if on a console port */ - out_8(&psc->command,MPC52xx_PSC_RST_RX); + out_8(&psc->command, MPC52xx_PSC_RST_RX); if (!uart_console(port)) - out_8(&psc->command,MPC52xx_PSC_RST_TX); + out_8(&psc->command, MPC52xx_PSC_RST_TX); port->read_status_mask = 0; - out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask); + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); /* Release interrupt */ free_irq(port->irq, port); @@ -271,7 +277,7 @@ mpc52xx_uart_shutdown(struct uart_port *port) static void mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + struct ktermios *old) { struct mpc52xx_psc __iomem *psc = PSC(port); unsigned long flags; @@ -283,14 +289,14 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, mr1 = 0; switch (new->c_cflag & CSIZE) { - case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS; - break; - case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS; - break; - case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS; - break; - case CS8: - default: mr1 |= MPC52xx_PSC_MODE_8_BITS; + case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS; + break; + case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS; + break; + case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS; + break; + case CS8: + default: mr1 |= MPC52xx_PSC_MODE_8_BITS; } if (new->c_cflag & PARENB) { @@ -332,24 +338,24 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, udelay(1); if (!j) - printk( KERN_ERR "mpc52xx_uart.c: " + printk(KERN_ERR "mpc52xx_uart.c: " "Unable to flush RX & TX fifos in-time in set_termios." - "Some chars may have been lost.\n" ); + "Some chars may have been lost.\n"); /* Reset the TX & RX */ - out_8(&psc->command,MPC52xx_PSC_RST_RX); - out_8(&psc->command,MPC52xx_PSC_RST_TX); + out_8(&psc->command, MPC52xx_PSC_RST_RX); + out_8(&psc->command, MPC52xx_PSC_RST_TX); /* Send new mode settings */ - out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1); - out_8(&psc->mode,mr1); - out_8(&psc->mode,mr2); - out_8(&psc->ctur,ctr >> 8); - out_8(&psc->ctlr,ctr & 0xff); + out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); + out_8(&psc->mode, mr1); + out_8(&psc->mode, mr2); + out_8(&psc->ctur, ctr >> 8); + out_8(&psc->ctlr, ctr & 0xff); /* Reenable TX & RX */ - out_8(&psc->command,MPC52xx_PSC_TX_ENABLE); - out_8(&psc->command,MPC52xx_PSC_RX_ENABLE); + out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); + out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); /* We're all set, release the lock */ spin_unlock_irqrestore(&port->lock, flags); @@ -364,7 +370,8 @@ mpc52xx_uart_type(struct uart_port *port) static void mpc52xx_uart_release_port(struct uart_port *port) { - if (port->flags & UPF_IOREMAP) { /* remapped by us ? */ + /* remapped by us ? */ + if (port->flags & UPF_IOREMAP) { iounmap(port->membase); port->membase = NULL; } @@ -379,7 +386,7 @@ mpc52xx_uart_request_port(struct uart_port *port) if (port->flags & UPF_IOREMAP) /* Need to remap ? */ port->membase = ioremap(port->mapbase, - sizeof(struct mpc52xx_psc)); + sizeof(struct mpc52xx_psc)); if (!port->membase) return -EINVAL; @@ -398,22 +405,22 @@ mpc52xx_uart_request_port(struct uart_port *port) static void mpc52xx_uart_config_port(struct uart_port *port, int flags) { - if ( (flags & UART_CONFIG_TYPE) && - (mpc52xx_uart_request_port(port) == 0) ) - port->type = PORT_MPC52xx; + if ((flags & UART_CONFIG_TYPE) + && (mpc52xx_uart_request_port(port) == 0)) + port->type = PORT_MPC52xx; } static int mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { - if ( ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx ) + if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx) return -EINVAL; - if ( (ser->irq != port->irq) || - (ser->io_type != SERIAL_IO_MEM) || - (ser->baud_base != port->uartclk) || - (ser->iomem_base != (void*)port->mapbase) || - (ser->hub6 != 0 ) ) + if ((ser->irq != port->irq) || + (ser->io_type != SERIAL_IO_MEM) || + (ser->baud_base != port->uartclk) || + (ser->iomem_base != (void *)port->mapbase) || + (ser->hub6 != 0)) return -EINVAL; return 0; @@ -455,8 +462,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) unsigned short status; /* While we can read, do so ! */ - while ( (status = in_be16(&PSC(port)->mpc52xx_psc_status)) & - MPC52xx_PSC_SR_RXRDY) { + while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) & + MPC52xx_PSC_SR_RXRDY) { /* Get the char */ ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8); @@ -474,9 +481,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) flag = TTY_NORMAL; port->icount.rx++; - if ( status & (MPC52xx_PSC_SR_PE | - MPC52xx_PSC_SR_FE | - MPC52xx_PSC_SR_RB) ) { + if (status & (MPC52xx_PSC_SR_PE | + MPC52xx_PSC_SR_FE | + MPC52xx_PSC_SR_RB)) { if (status & MPC52xx_PSC_SR_RB) { flag = TTY_BREAK; @@ -487,7 +494,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) flag = TTY_FRAME; /* Clear error condition */ - out_8(&PSC(port)->command,MPC52xx_PSC_RST_ERR_STAT); + out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT); } tty_insert_flip_char(tty, ch, flag); @@ -568,16 +575,16 @@ mpc52xx_uart_int(int irq, void *dev_id) /* Do we need to receive chars ? */ /* For this RX interrupts must be on and some chars waiting */ - if ( status & MPC52xx_PSC_IMR_RXRDY ) + if (status & MPC52xx_PSC_IMR_RXRDY) keepgoing |= mpc52xx_uart_int_rx_chars(port); /* Do we need to send chars ? */ /* For this, TX must be ready and TX interrupt enabled */ - if ( status & MPC52xx_PSC_IMR_TXRDY ) + if (status & MPC52xx_PSC_IMR_TXRDY) keepgoing |= mpc52xx_uart_int_tx_chars(port); /* Limit number of iteration */ - if ( !(--pass) ) + if (!(--pass)) keepgoing = 0; } while (keepgoing); @@ -596,7 +603,7 @@ mpc52xx_uart_int(int irq, void *dev_id) static void __init mpc52xx_console_get_options(struct uart_port *port, - int *baud, int *parity, int *bits, int *flow) + int *baud, int *parity, int *bits, int *flow) { struct mpc52xx_psc __iomem *psc = PSC(port); unsigned char mr1; @@ -604,7 +611,7 @@ mpc52xx_console_get_options(struct uart_port *port, pr_debug("mpc52xx_console_get_options(port=%p)\n", port); /* Read the mode registers */ - out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1); + out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); mr1 = in_8(&psc->mode); /* CT{U,L}R are write-only ! */ @@ -616,11 +623,18 @@ mpc52xx_console_get_options(struct uart_port *port, /* Parse them */ switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { - case MPC52xx_PSC_MODE_5_BITS: *bits = 5; break; - case MPC52xx_PSC_MODE_6_BITS: *bits = 6; break; - case MPC52xx_PSC_MODE_7_BITS: *bits = 7; break; - case MPC52xx_PSC_MODE_8_BITS: - default: *bits = 8; + case MPC52xx_PSC_MODE_5_BITS: + *bits = 5; + break; + case MPC52xx_PSC_MODE_6_BITS: + *bits = 6; + break; + case MPC52xx_PSC_MODE_7_BITS: + *bits = 7; + break; + case MPC52xx_PSC_MODE_8_BITS: + default: + *bits = 8; } if (mr1 & MPC52xx_PSC_MODE_PARNONE) @@ -657,7 +671,7 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count) /* Wait the TX buffer to be empty */ j = 20000; /* Maximum wait */ while (!(in_be16(&psc->mpc52xx_psc_status) & - MPC52xx_PSC_SR_TXEMP) && --j) + MPC52xx_PSC_SR_TXEMP) && --j) udelay(1); } @@ -730,16 +744,18 @@ mpc52xx_console_setup(struct console *co, char *options) } pr_debug("Console on ttyPSC%x is %s\n", - co->index, mpc52xx_uart_nodes[co->index]->full_name); + co->index, mpc52xx_uart_nodes[co->index]->full_name); /* Fetch register locations */ - if ((ret = of_address_to_resource(np, 0, &res)) != 0) { + ret = of_address_to_resource(np, 0, &res); + if (ret) { pr_debug("Could not get resources for PSC%x\n", co->index); return ret; } /* Search for bus-frequency property in this node or a parent */ - if ((ipb_freq = mpc52xx_find_ipb_freq(np)) == 0) { + ipb_freq = mpc52xx_find_ipb_freq(np); + if (ipb_freq == 0) { pr_debug("Could not find IPB bus frequency!\n"); return -EINVAL; } @@ -757,7 +773,8 @@ mpc52xx_console_setup(struct console *co, char *options) return -EINVAL; pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n", - (void*)port->mapbase, port->membase, port->irq, port->uartclk); + (void *)port->mapbase, port->membase, + port->irq, port->uartclk); /* Setup the port parameters accoding to options */ if (options) @@ -766,7 +783,7 @@ mpc52xx_console_setup(struct console *co, char *options) mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); pr_debug("Setting console parameters: %i %i%c1 flow=%c\n", - baud, bits, parity, flow); + baud, bits, parity, flow); return uart_set_options(port, co, baud, parity, bits, flow); } @@ -781,7 +798,7 @@ static struct console mpc52xx_console = { .device = uart_console_device, .setup = mpc52xx_console_setup, .flags = CON_PRINTBUFFER, - .index = -1, /* Specified on the cmdline (e.g. console=ttyPSC0 ) */ + .index = -1, /* Specified on the cmdline (e.g. console=ttyPSC0) */ .data = &mpc52xx_uart_driver, }; @@ -809,7 +826,6 @@ console_initcall(mpc52xx_console_init); /* ======================================================================== */ static struct uart_driver mpc52xx_uart_driver = { - .owner = THIS_MODULE, .driver_name = "mpc52xx_psc_uart", .dev_name = "ttyPSC", .major = SERIAL_PSC_MAJOR, @@ -837,7 +853,7 @@ mpc52xx_uart_probe(struct platform_device *dev) if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM) return -EINVAL; - if (!mpc52xx_match_psc_function(idx,"uart")) + if (!mpc52xx_match_psc_function(idx, "uart")) return -ENODEV; /* Init the port structure */ @@ -848,13 +864,13 @@ mpc52xx_uart_probe(struct platform_device *dev) port->fifosize = 512; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | - ( uart_console(port) ? 0 : UPF_IOREMAP ); + (uart_console(port) ? 0 : UPF_IOREMAP); port->line = idx; port->ops = &mpc52xx_uart_ops; port->dev = &dev->dev; /* Search for IRQ and mapbase */ - for (i=0 ; i<dev->num_resources ; i++, res++) { + for (i = 0 ; i < dev->num_resources ; i++, res++) { if (res->flags & IORESOURCE_MEM) port->mapbase = res->start; else if (res->flags & IORESOURCE_IRQ) @@ -866,7 +882,7 @@ mpc52xx_uart_probe(struct platform_device *dev) /* Add the port to the uart sub-system */ ret = uart_add_one_port(&mpc52xx_uart_driver, port); if (!ret) - platform_set_drvdata(dev, (void*)port); + platform_set_drvdata(dev, (void *)port); return ret; } @@ -917,6 +933,7 @@ static struct platform_driver mpc52xx_uart_platform_driver = { .resume = mpc52xx_uart_resume, #endif .driver = { + .owner = THIS_MODULE, .name = "mpc52xx-psc", }, }; @@ -946,10 +963,11 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) if (idx >= MPC52xx_PSC_MAXNUM) return -EINVAL; pr_debug("Found %s assigned to ttyPSC%x\n", - mpc52xx_uart_nodes[idx]->full_name, idx); + mpc52xx_uart_nodes[idx]->full_name, idx); /* Search for bus-frequency property in this node or a parent */ - if ((ipb_freq = mpc52xx_find_ipb_freq(op->node)) == 0) { + ipb_freq = mpc52xx_find_ipb_freq(op->node); + if (ipb_freq == 0) { dev_dbg(&op->dev, "Could not find IPB bus frequency!\n"); return -EINVAL; } @@ -962,22 +980,23 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) port->fifosize = 512; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | - ( uart_console(port) ? 0 : UPF_IOREMAP ); + (uart_console(port) ? 0 : UPF_IOREMAP); port->line = idx; port->ops = &mpc52xx_uart_ops; port->dev = &op->dev; /* Search for IRQ and mapbase */ - if ((ret = of_address_to_resource(op->node, 0, &res)) != 0) + ret = of_address_to_resource(op->node, 0, &res); + if (ret) return ret; port->mapbase = res.start; port->irq = irq_of_parse_and_map(op->node, 0); dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n", - (void*)port->mapbase, port->irq, port->uartclk); + (void *)port->mapbase, port->irq, port->uartclk); - if ((port->irq==NO_IRQ) || !port->mapbase) { + if ((port->irq == NO_IRQ) || !port->mapbase) { printk(KERN_ERR "Could not allocate resources for PSC\n"); return -EINVAL; } @@ -985,7 +1004,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) /* Add the port to the uart sub-system */ ret = uart_add_one_port(&mpc52xx_uart_driver, port); if (!ret) - dev_set_drvdata(&op->dev, (void*)port); + dev_set_drvdata(&op->dev, (void *)port); return ret; } @@ -1048,6 +1067,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx) if (idx < 0) return; /* No free slot; abort */ + of_node_get(np); /* If the slot is already occupied, then swap slots */ if (mpc52xx_uart_nodes[idx] && (free_idx != -1)) mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx]; @@ -1057,7 +1077,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx) static void mpc52xx_uart_of_enumerate(void) { - static int enum_done = 0; + static int enum_done; struct device_node *np; const unsigned int *devno; int i; @@ -1071,7 +1091,7 @@ mpc52xx_uart_of_enumerate(void) /* Is a particular device number requested? */ devno = of_get_property(np, "port-number", NULL); - mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1); + mpc52xx_uart_of_assign(np, devno ? *devno : -1); } enum_done = 1; @@ -1079,15 +1099,13 @@ mpc52xx_uart_of_enumerate(void) for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { if (mpc52xx_uart_nodes[i]) pr_debug("%s assigned to ttyPSC%x\n", - mpc52xx_uart_nodes[i]->full_name, i); + mpc52xx_uart_nodes[i]->full_name, i); } } MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); static struct of_platform_driver mpc52xx_uart_of_driver = { - .owner = THIS_MODULE, - .name = "mpc52xx-psc-uart", .match_table = mpc52xx_uart_of_match, .probe = mpc52xx_uart_of_probe, .remove = mpc52xx_uart_of_remove, @@ -1113,7 +1131,8 @@ mpc52xx_uart_init(void) printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n"); - if ((ret = uart_register_driver(&mpc52xx_uart_driver)) != 0) { + ret = uart_register_driver(&mpc52xx_uart_driver); + if (ret) { printk(KERN_ERR "%s: uart_register_driver failed (%i)\n", __FILE__, ret); return ret; diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index 4d643c92665..cb3a9196774 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -612,6 +612,7 @@ static void mpsc_hw_init(struct mpsc_port_info *pi) /* No preamble, 16x divider, low-latency, */ writel(0x04400400, pi->mpsc_base + MPSC_MMCRH); + mpsc_set_baudrate(pi, pi->default_baud); if (pi->mirror_regs) { pi->MPSC_CHR_1_m = 0; diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index 83211013deb..e94031731a4 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -582,7 +582,7 @@ static struct parisc_driver serial_mux_driver = { }; /** - * mux_init - Serial MUX initalization procedure. + * mux_init - Serial MUX initialization procedure. * * Register the Serial MUX driver. */ diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index e773c8e1496..45de1936603 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -1527,7 +1527,7 @@ static inline void s3c2440_serial_exit(void) #define s3c2440_uart_inf_at NULL #endif /* CONFIG_CPU_S3C2440 */ -#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) +#if defined(CONFIG_CPU_S3C2412) static int s3c2412_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *clk) diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c new file mode 100644 index 00000000000..a350b6d2a18 --- /dev/null +++ b/drivers/serial/sc26xx.c @@ -0,0 +1,755 @@ +/* + * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices. + * + * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de) + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/circ_buf.h> +#include <linux/serial.h> +#include <linux/sysrq.h> +#include <linux/console.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/irq.h> + +#if defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/serial_core.h> + +#define SC26XX_MAJOR 204 +#define SC26XX_MINOR_START 205 +#define SC26XX_NR 2 + +struct uart_sc26xx_port { + struct uart_port port[2]; + u8 dsr_mask[2]; + u8 cts_mask[2]; + u8 dcd_mask[2]; + u8 ri_mask[2]; + u8 dtr_mask[2]; + u8 rts_mask[2]; + u8 imr; +}; + +/* register common to both ports */ +#define RD_ISR 0x14 +#define RD_IPR 0x34 + +#define WR_ACR 0x10 +#define WR_IMR 0x14 +#define WR_OPCR 0x34 +#define WR_OPR_SET 0x38 +#define WR_OPR_CLR 0x3C + +/* access common register */ +#define READ_SC(p, r) readb((p)->membase + RD_##r) +#define WRITE_SC(p, r, v) writeb((v), (p)->membase + WR_##r) + +/* register per port */ +#define RD_PORT_MRx 0x00 +#define RD_PORT_SR 0x04 +#define RD_PORT_RHR 0x0c + +#define WR_PORT_MRx 0x00 +#define WR_PORT_CSR 0x04 +#define WR_PORT_CR 0x08 +#define WR_PORT_THR 0x0c + +/* SR bits */ +#define SR_BREAK (1 << 7) +#define SR_FRAME (1 << 6) +#define SR_PARITY (1 << 5) +#define SR_OVERRUN (1 << 4) +#define SR_TXRDY (1 << 2) +#define SR_RXRDY (1 << 0) + +#define CR_RES_MR (1 << 4) +#define CR_RES_RX (2 << 4) +#define CR_RES_TX (3 << 4) +#define CR_STRT_BRK (6 << 4) +#define CR_STOP_BRK (7 << 4) +#define CR_DIS_TX (1 << 3) +#define CR_ENA_TX (1 << 2) +#define CR_DIS_RX (1 << 1) +#define CR_ENA_RX (1 << 0) + +/* ISR bits */ +#define ISR_RXRDYB (1 << 5) +#define ISR_TXRDYB (1 << 4) +#define ISR_RXRDYA (1 << 1) +#define ISR_TXRDYA (1 << 0) + +/* IMR bits */ +#define IMR_RXRDY (1 << 1) +#define IMR_TXRDY (1 << 0) + +/* access port register */ +static inline u8 read_sc_port(struct uart_port *p, u8 reg) +{ + return readb(p->membase + p->line * 0x20 + reg); +} + +static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val) +{ + writeb(val, p->membase + p->line * 0x20 + reg); +} + +#define READ_SC_PORT(p, r) read_sc_port(p, RD_PORT_##r) +#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v) + +static void sc26xx_enable_irq(struct uart_port *port, int mask) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + up->imr |= mask << (line * 4); + WRITE_SC(port, IMR, up->imr); +} + +static void sc26xx_disable_irq(struct uart_port *port, int mask) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + up->imr &= ~(mask << (line * 4)); + WRITE_SC(port, IMR, up->imr); +} + +static struct tty_struct *receive_chars(struct uart_port *port) +{ + struct tty_struct *tty = NULL; + int limit = 10000; + unsigned char ch; + char flag; + u8 status; + + if (port->info != NULL) /* Unopened serial console */ + tty = port->info->tty; + + while (limit-- > 0) { + status = READ_SC_PORT(port, SR); + if (!(status & SR_RXRDY)) + break; + ch = READ_SC_PORT(port, RHR); + + flag = TTY_NORMAL; + port->icount.rx++; + + if (unlikely(status & (SR_BREAK | SR_FRAME | + SR_PARITY | SR_OVERRUN))) { + if (status & SR_BREAK) { + status &= ~(SR_PARITY | SR_FRAME); + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (status & SR_PARITY) + port->icount.parity++; + else if (status & SR_FRAME) + port->icount.frame++; + if (status & SR_OVERRUN) + port->icount.overrun++; + + status &= port->read_status_mask; + if (status & SR_BREAK) + flag = TTY_BREAK; + else if (status & SR_PARITY) + flag = TTY_PARITY; + else if (status & SR_FRAME) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + + if (status & port->ignore_status_mask) + continue; + + tty_insert_flip_char(tty, ch, flag); + } + return tty; +} + +static void transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit; + + if (!port->info) + return; + + xmit = &port->info->xmit; + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + sc26xx_disable_irq(port, IMR_TXRDY); + return; + } + while (!uart_circ_empty(xmit)) { + if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) + break; + + WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(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; + u8 isr; + + spin_lock_irqsave(&up->port[0].lock, flags); + + tty = NULL; + 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]); + + spin_unlock(&up->port[0].lock); + + if (tty) + tty_flip_buffer_push(tty); + + spin_lock(&up->port[1].lock); + + tty = NULL; + if (isr & ISR_TXRDYB) + transmit_chars(&up->port[1]); + if (isr & ISR_RXRDYB) + tty = receive_chars(&up->port[1]); + + spin_unlock_irqrestore(&up->port[1].lock, flags); + + if (tty) + tty_flip_buffer_push(tty); + + return IRQ_HANDLED; +} + +/* port->lock is not held. */ +static unsigned int sc26xx_tx_empty(struct uart_port *port) +{ + return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0; +} + +/* port->lock held by caller. */ +static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + if (up->dtr_mask[line]) { + if (mctrl & TIOCM_DTR) + WRITE_SC(port, OPR_SET, up->dtr_mask[line]); + else + WRITE_SC(port, OPR_CLR, up->dtr_mask[line]); + } + if (up->rts_mask[line]) { + if (mctrl & TIOCM_RTS) + WRITE_SC(port, OPR_SET, up->rts_mask[line]); + else + WRITE_SC(port, OPR_CLR, up->rts_mask[line]); + } +} + +/* port->lock is held by caller and interrupts are disabled. */ +static unsigned int sc26xx_get_mctrl(struct uart_port *port) +{ + struct uart_sc26xx_port *up; + int line = port->line; + unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; + u8 ipr; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + ipr = READ_SC(port, IPR) ^ 0xff; + + if (up->dsr_mask[line]) { + mctrl &= ~TIOCM_DSR; + mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0; + } + if (up->cts_mask[line]) { + mctrl &= ~TIOCM_CTS; + mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0; + } + if (up->dcd_mask[line]) { + mctrl &= ~TIOCM_CAR; + mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0; + } + if (up->ri_mask[line]) { + mctrl &= ~TIOCM_RNG; + mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0; + } + return mctrl; +} + +/* port->lock held by caller. */ +static void sc26xx_stop_tx(struct uart_port *port) +{ + return; +} + +/* port->lock held by caller. */ +static void sc26xx_start_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + while (!uart_circ_empty(xmit)) { + if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) { + sc26xx_enable_irq(port, IMR_TXRDY); + break; + } + WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } +} + +/* port->lock held by caller. */ +static void sc26xx_stop_rx(struct uart_port *port) +{ +} + +/* port->lock held by caller. */ +static void sc26xx_enable_ms(struct uart_port *port) +{ +} + +/* port->lock is not held. */ +static void sc26xx_break_ctl(struct uart_port *port, int break_state) +{ + if (break_state == -1) + WRITE_SC_PORT(port, CR, CR_STRT_BRK); + else + WRITE_SC_PORT(port, CR, CR_STOP_BRK); +} + +/* port->lock is not held. */ +static int sc26xx_startup(struct uart_port *port) +{ + sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); + WRITE_SC(port, OPCR, 0); + + /* reset tx and rx */ + WRITE_SC_PORT(port, CR, CR_RES_RX); + WRITE_SC_PORT(port, CR, CR_RES_TX); + + /* start rx/tx */ + WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); + + /* enable irqs */ + sc26xx_enable_irq(port, IMR_RXRDY); + return 0; +} + +/* port->lock is not held. */ +static void sc26xx_shutdown(struct uart_port *port) +{ + /* disable interrupst */ + sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); + + /* stop tx/rx */ + WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); +} + +/* port->lock is not held. */ +static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + unsigned int quot = uart_get_divisor(port, baud); + unsigned int iflag, cflag; + unsigned long flags; + u8 mr1, mr2, csr; + + spin_lock_irqsave(&port->lock, flags); + + while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) + udelay(2); + + WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); + + iflag = termios->c_iflag; + cflag = termios->c_cflag; + + port->read_status_mask = SR_OVERRUN; + if (iflag & INPCK) + port->read_status_mask |= SR_PARITY | SR_FRAME; + if (iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SR_BREAK; + + port->ignore_status_mask = 0; + if (iflag & IGNBRK) + port->ignore_status_mask |= SR_BREAK; + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= SR_BREAK | SR_FRAME | + SR_PARITY | SR_OVERRUN; + + switch (cflag & CSIZE) { + case CS5: + mr1 = 0x00; + break; + case CS6: + mr1 = 0x01; + break; + case CS7: + mr1 = 0x02; + break; + default: + case CS8: + mr1 = 0x03; + break; + } + mr2 = 0x07; + if (cflag & CSTOPB) + mr2 = 0x0f; + if (cflag & PARENB) { + if (cflag & PARODD) + mr1 |= (1 << 2); + } else + mr1 |= (2 << 3); + + switch (baud) { + case 50: + csr = 0x00; + break; + case 110: + csr = 0x11; + break; + case 134: + csr = 0x22; + break; + case 200: + csr = 0x33; + break; + case 300: + csr = 0x44; + break; + case 600: + csr = 0x55; + break; + case 1200: + csr = 0x66; + break; + case 2400: + csr = 0x88; + break; + case 4800: + csr = 0x99; + break; + default: + case 9600: + csr = 0xbb; + break; + case 19200: + csr = 0xcc; + break; + } + + WRITE_SC_PORT(port, CR, CR_RES_MR); + WRITE_SC_PORT(port, MRx, mr1); + WRITE_SC_PORT(port, MRx, mr2); + + WRITE_SC(port, ACR, 0x80); + WRITE_SC_PORT(port, CSR, csr); + + /* reset tx and rx */ + WRITE_SC_PORT(port, CR, CR_RES_RX); + WRITE_SC_PORT(port, CR, CR_RES_TX); + + WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); + while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) + udelay(2); + + /* XXX */ + uart_update_timeout(port, cflag, + (port->uartclk / (16 * quot))); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *sc26xx_type(struct uart_port *port) +{ + return "SC26XX"; +} + +static void sc26xx_release_port(struct uart_port *port) +{ +} + +static int sc26xx_request_port(struct uart_port *port) +{ + return 0; +} + +static void sc26xx_config_port(struct uart_port *port, int flags) +{ +} + +static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +static struct uart_ops sc26xx_ops = { + .tx_empty = sc26xx_tx_empty, + .set_mctrl = sc26xx_set_mctrl, + .get_mctrl = sc26xx_get_mctrl, + .stop_tx = sc26xx_stop_tx, + .start_tx = sc26xx_start_tx, + .stop_rx = sc26xx_stop_rx, + .enable_ms = sc26xx_enable_ms, + .break_ctl = sc26xx_break_ctl, + .startup = sc26xx_startup, + .shutdown = sc26xx_shutdown, + .set_termios = sc26xx_set_termios, + .type = sc26xx_type, + .release_port = sc26xx_release_port, + .request_port = sc26xx_request_port, + .config_port = sc26xx_config_port, + .verify_port = sc26xx_verify_port, +}; + +static struct uart_port *sc26xx_port; + +#ifdef CONFIG_SERIAL_SC26XX_CONSOLE +static void sc26xx_console_putchar(struct uart_port *port, char c) +{ + unsigned long flags; + int limit = 1000000; + + spin_lock_irqsave(&port->lock, flags); + + while (limit-- > 0) { + if (READ_SC_PORT(port, SR) & SR_TXRDY) { + WRITE_SC_PORT(port, THR, c); + break; + } + udelay(2); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void sc26xx_console_write(struct console *con, const char *s, unsigned n) +{ + struct uart_port *port = sc26xx_port; + int i; + + for (i = 0; i < n; i++) { + if (*s == '\n') + sc26xx_console_putchar(port, '\r'); + sc26xx_console_putchar(port, *s++); + } +} + +static int __init sc26xx_console_setup(struct console *con, char *options) +{ + struct uart_port *port = sc26xx_port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (port->type != PORT_SC26XX) + return -1; + + printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index); + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, con, baud, parity, bits, flow); +} + +static struct uart_driver sc26xx_reg; +static struct console sc26xx_console = { + .name = "ttySC", + .write = sc26xx_console_write, + .device = uart_console_device, + .setup = sc26xx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sc26xx_reg, +}; +#define SC26XX_CONSOLE &sc26xx_console +#else +#define SC26XX_CONSOLE NULL +#endif + +static struct uart_driver sc26xx_reg = { + .owner = THIS_MODULE, + .driver_name = "SC26xx", + .dev_name = "ttySC", + .major = SC26XX_MAJOR, + .minor = SC26XX_MINOR_START, + .nr = SC26XX_NR, + .cons = SC26XX_CONSOLE, +}; + +static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos) +{ + unsigned int bit = (flags >> bitpos) & 15; + + return bit ? (1 << (bit - 1)) : 0; +} + +static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up, + int line, unsigned int data) +{ + up->dtr_mask[line] = sc26xx_flags2mask(data, 0); + up->rts_mask[line] = sc26xx_flags2mask(data, 4); + up->dsr_mask[line] = sc26xx_flags2mask(data, 8); + up->cts_mask[line] = sc26xx_flags2mask(data, 12); + up->dcd_mask[line] = sc26xx_flags2mask(data, 16); + up->ri_mask[line] = sc26xx_flags2mask(data, 20); +} + +static int __devinit sc26xx_probe(struct platform_device *dev) +{ + struct resource *res; + struct uart_sc26xx_port *up; + unsigned int *sc26xx_data = dev->dev.platform_data; + int err; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + up = kzalloc(sizeof *up, GFP_KERNEL); + if (unlikely(!up)) + return -ENOMEM; + + up->port[0].line = 0; + up->port[0].ops = &sc26xx_ops; + up->port[0].type = PORT_SC26XX; + up->port[0].uartclk = (29491200 / 16); /* arbitrary */ + + up->port[0].mapbase = res->start; + up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40); + up->port[0].iotype = UPIO_MEM; + up->port[0].irq = platform_get_irq(dev, 0); + + up->port[0].dev = &dev->dev; + + sc26xx_init_masks(up, 0, sc26xx_data[0]); + + sc26xx_port = &up->port[0]; + + up->port[1].line = 1; + up->port[1].ops = &sc26xx_ops; + up->port[1].type = PORT_SC26XX; + up->port[1].uartclk = (29491200 / 16); /* arbitrary */ + + up->port[1].mapbase = up->port[0].mapbase; + up->port[1].membase = up->port[0].membase; + up->port[1].iotype = UPIO_MEM; + up->port[1].irq = up->port[0].irq; + + up->port[1].dev = &dev->dev; + + sc26xx_init_masks(up, 1, sc26xx_data[1]); + + err = uart_register_driver(&sc26xx_reg); + if (err) + goto out_free_port; + + sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor; + + err = uart_add_one_port(&sc26xx_reg, &up->port[0]); + if (err) + goto out_unregister_driver; + + err = uart_add_one_port(&sc26xx_reg, &up->port[1]); + if (err) + goto out_remove_port0; + + err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up); + if (err) + goto out_remove_ports; + + dev_set_drvdata(&dev->dev, up); + return 0; + +out_remove_ports: + uart_remove_one_port(&sc26xx_reg, &up->port[1]); +out_remove_port0: + uart_remove_one_port(&sc26xx_reg, &up->port[0]); + +out_unregister_driver: + uart_unregister_driver(&sc26xx_reg); + +out_free_port: + kfree(up); + sc26xx_port = NULL; + return err; +} + + +static int __exit sc26xx_driver_remove(struct platform_device *dev) +{ + struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev); + + free_irq(up->port[0].irq, up); + + uart_remove_one_port(&sc26xx_reg, &up->port[0]); + uart_remove_one_port(&sc26xx_reg, &up->port[1]); + + uart_unregister_driver(&sc26xx_reg); + + kfree(up); + sc26xx_port = NULL; + + dev_set_drvdata(&dev->dev, NULL); + return 0; +} + +static struct platform_driver sc26xx_driver = { + .probe = sc26xx_probe, + .remove = __devexit_p(sc26xx_driver_remove), + .driver = { + .name = "SC26xx", + }, +}; + +static int __init sc26xx_init(void) +{ + return platform_driver_register(&sc26xx_driver); +} + +static void __exit sc26xx_exit(void) +{ + platform_driver_unregister(&sc26xx_driver); +} + +module_init(sc26xx_init); +module_exit(sc26xx_exit); + + +MODULE_AUTHOR("Thomas Bogendörfer"); +MODULE_DESCRIPTION("SC681/SC2692 serial driver"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 3bb5d241dd4..276da148c57 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -371,7 +371,8 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, */ termios->c_cflag &= ~CBAUD; if (old) { - termios->c_cflag |= old->c_cflag & CBAUD; + baud = tty_termios_baud_rate(old); + tty_termios_encode_baud_rate(termios, baud, baud); old = NULL; continue; } @@ -380,7 +381,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, * As a last resort, if the quotient is zero, * default to 9600 bps */ - termios->c_cflag |= B9600; + tty_termios_encode_baud_rate(termios, 9600, 9600); } return 0; @@ -1977,6 +1978,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) if (state->info && state->info->flags & UIF_INITIALIZED) { const struct uart_ops *ops = port->ops; + int tries; state->info->flags = (state->info->flags & ~UIF_INITIALIZED) | UIF_SUSPENDED; @@ -1990,9 +1992,14 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) /* * Wait for the transmitter to empty. */ - while (!ops->tx_empty(port)) { + for (tries = 3; !ops->tx_empty(port) && tries; tries--) { msleep(10); } + if (!tries) + printk(KERN_ERR "%s%s%s%d: Unable to drain transmitter\n", + port->dev ? port->dev->bus_id : "", + port->dev ? ": " : "", + drv->dev_name, port->line); ops->shutdown(port); } @@ -2029,8 +2036,6 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) } port->suspended = 0; - uart_change_pm(state, 0); - /* * Re-enable the console device after suspending. */ @@ -2049,6 +2054,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) if (state->info && state->info->tty && termios.c_cflag == 0) termios = *state->info->tty->termios; + uart_change_pm(state, 0); port->ops->set_termios(port, &termios, NULL); console_start(port->cons); } @@ -2057,6 +2063,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) const struct uart_ops *ops = port->ops; int ret; + uart_change_pm(state, 0); ops->set_mctrl(port, 0); ret = ops->startup(port); if (ret == 0) { @@ -2150,10 +2157,11 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, /* * Ensure that the modem control lines are de-activated. + * keep the DTR setting that is set in uart_set_options() * We probably don't need a spinlock around this, but */ spin_lock_irqsave(&port->lock, flags); - port->ops->set_mctrl(port, 0); + port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); spin_unlock_irqrestore(&port->lock, flags); /* diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index d8b660061c1..164d2a42eb5 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -389,7 +389,7 @@ static void serial_detach(struct pcmcia_device *link) /*====================================================================*/ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, - kio_addr_t iobase, int irq) + unsigned int iobase, int irq) { struct uart_port port; int line; @@ -456,7 +456,7 @@ next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) static int simple_config(struct pcmcia_device *link) { - static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; static const int size_table[2] = { 8, 16 }; struct serial_info *info = link->priv; struct serial_cfg_mem *cfg_mem; @@ -480,7 +480,7 @@ static int simple_config(struct pcmcia_device *link) /* If the card is already configured, look up the port and irq */ i = pcmcia_get_configuration_info(link, &config); if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { - kio_addr_t port = 0; + unsigned int port = 0; if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { port = config.BasePort2; info->slave = 1; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 73440e26834..ddf63914453 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -302,7 +302,7 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag) } sci_out(port, SCFCR, fcr_val); } -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721) static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { unsigned int fcr_val = 0; @@ -395,7 +395,8 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) } else { #ifdef CONFIG_CPU_SUBTYPE_SH7343 /* Nothing */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \ +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) || \ defined(CONFIG_CPU_SUBTYPE_SHX3) ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */ @@ -408,6 +409,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) #endif #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) static inline int scif_txroom(struct uart_port *port) diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index d24621ce799..f5764ebcfe0 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -46,7 +46,8 @@ */ # define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0 # define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) # define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCIF_ONLY #define SCIF_ORER 0x0200 /* overrun error bit */ @@ -119,6 +120,12 @@ # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCI_ONLY # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +# define SCSPTR0 0xffe00024 /* 16 bit SCIF */ +# define SCSPTR1 0xffe08024 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH7770) # define SCSPTR0 0xff923020 /* 16 bit SCIF */ # define SCSPTR1 0xff924020 /* 16 bit SCIF */ @@ -142,7 +149,9 @@ # define SCIF_OPER 0x0001 /* Overrun error bit */ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7206) +#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \ + defined(CONFIG_CPU_SUBTYPE_SH7206) || \ + defined(CONFIG_CPU_SUBTYPE_SH7263) # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */ # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */ # define SCSPTR2 0xfffe9020 /* 16 bit SCIF */ @@ -214,7 +223,8 @@ #define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) #define SCIF_ORER 0x0200 #define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) #define SCIF_RFDC_MASK 0x007f @@ -252,7 +262,8 @@ # define SCxSR_PER(port) SCIF_PER # define SCxSR_BRK(port) SCIF_BRK #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) # define SCxSR_RDxF_CLEAR(port) (sci_in(port,SCxSR)&0xfffc) # define SCxSR_ERROR_CLEAR(port) (sci_in(port,SCxSR)&0xfd73) # define SCxSR_TDxE_CLEAR(port) (sci_in(port,SCxSR)&0xffdf) @@ -361,7 +372,8 @@ #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) #define SCIF_FNS(name, scif_offset, scif_size) \ CPU_SCIF_FNS(name, scif_offset, scif_size) #else @@ -388,7 +400,8 @@ #endif #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) SCIF_FNS(SCSMR, 0x00, 16) SCIF_FNS(SCBRR, 0x04, 8) @@ -412,6 +425,7 @@ SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) @@ -510,7 +524,8 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port) return; } } -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) static inline int sci_rxd_in(struct uart_port *port) { if (port->mapbase == 0xa4430000) @@ -580,6 +595,15 @@ static inline int sci_rxd_in(struct uart_port *port) int ch = (port->mapbase - SMR0) >> 3; return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0; } +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffe08000) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH7770) static inline int sci_rxd_in(struct uart_port *port) { @@ -617,7 +641,9 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */ return 1; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7206) +#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \ + defined(CONFIG_CPU_SUBTYPE_SH7206) || \ + defined(CONFIG_CPU_SUBTYPE_SH7263) static inline int sci_rxd_in(struct uart_port *port) { if (port->mapbase == 0xfffe8000) @@ -688,11 +714,13 @@ static inline int sci_rxd_in(struct uart_port *port) * -- Mitch Davis - 15 Jul 2000 */ -#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \ +#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) #elif defined(__H8300H__) || defined(__H8300S__) #define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1) diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c index 70a09a3d5af..a2d4a19550a 100644 --- a/drivers/serial/suncore.c +++ b/drivers/serial/suncore.c @@ -23,9 +23,34 @@ #include "suncore.h" -int sunserial_current_minor = 64; +static int sunserial_current_minor = 64; -EXPORT_SYMBOL(sunserial_current_minor); +int sunserial_register_minors(struct uart_driver *drv, int count) +{ + int err = 0; + + drv->minor = sunserial_current_minor; + drv->nr += count; + /* Register the driver on the first call */ + if (drv->nr == count) + err = uart_register_driver(drv); + if (err == 0) { + sunserial_current_minor += count; + drv->tty_driver->name_base = drv->minor - 64; + } + return err; +} +EXPORT_SYMBOL(sunserial_register_minors); + +void sunserial_unregister_minors(struct uart_driver *drv, int count) +{ + drv->nr -= count; + sunserial_current_minor -= count; + + if (drv->nr == 0) + uart_unregister_driver(drv); +} +EXPORT_SYMBOL(sunserial_unregister_minors); int sunserial_console_match(struct console *con, struct device_node *dp, struct uart_driver *drv, int line) @@ -133,8 +158,6 @@ sunserial_console_termios(struct console *con) con->cflag = cflag; } -EXPORT_SYMBOL(sunserial_console_termios); - /* Sun serial MOUSE auto baud rate detection. */ static struct mouse_baud_cflag { int baud; diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h index 829d7d65d6d..042668aa602 100644 --- a/drivers/serial/suncore.h +++ b/drivers/serial/suncore.h @@ -22,7 +22,8 @@ extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *); extern int suncore_mouse_baud_detection(unsigned char, int); -extern int sunserial_current_minor; +extern int sunserial_register_minors(struct uart_driver *, int); +extern void sunserial_unregister_minors(struct uart_driver *, int); extern int sunserial_console_match(struct console *, struct device_node *, struct uart_driver *, int); diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index 8ff900b0981..be0fe152891 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -562,16 +562,10 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m port->dev = &op->dev; - sunhv_reg.minor = sunserial_current_minor; - sunhv_reg.nr = 1; - - err = uart_register_driver(&sunhv_reg); + err = sunserial_register_minors(&sunhv_reg, 1); if (err) goto out_free_con_read_page; - sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; - sunserial_current_minor += 1; - sunserial_console_match(&sunhv_console, op->node, &sunhv_reg, port->line); @@ -591,8 +585,7 @@ out_remove_port: uart_remove_one_port(&sunhv_reg, port); out_unregister_driver: - sunserial_current_minor -= 1; - uart_unregister_driver(&sunhv_reg); + sunserial_unregister_minors(&sunhv_reg, 1); out_free_con_read_page: kfree(con_read_page); @@ -614,8 +607,7 @@ static int __devexit hv_remove(struct of_device *dev) uart_remove_one_port(&sunhv_reg, port); - sunserial_current_minor -= 1; - uart_unregister_driver(&sunhv_reg); + sunserial_unregister_minors(&sunhv_reg, 1); kfree(port); sunhv_port = NULL; diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index ff610c23314..543f93741e6 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -832,7 +832,6 @@ static struct uart_driver sunsab_reg = { }; static struct uart_sunsab_port *sunsab_ports; -static int num_channels; #ifdef CONFIG_SERIAL_SUNSAB_CONSOLE @@ -1102,8 +1101,8 @@ static int __init sunsab_init(void) { struct device_node *dp; int err; + int num_channels = 0; - num_channels = 0; for_each_node_by_name(dp, "se") num_channels += 2; for_each_node_by_name(dp, "serial") { @@ -1117,20 +1116,14 @@ static int __init sunsab_init(void) if (!sunsab_ports) return -ENOMEM; - sunsab_reg.minor = sunserial_current_minor; - sunsab_reg.nr = num_channels; sunsab_reg.cons = SUNSAB_CONSOLE(); - - err = uart_register_driver(&sunsab_reg); + err = sunserial_register_minors(&sunsab_reg, num_channels); if (err) { kfree(sunsab_ports); sunsab_ports = NULL; return err; } - - sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; - sunserial_current_minor += num_channels; } return of_register_driver(&sab_driver, &of_bus_type); @@ -1139,9 +1132,8 @@ static int __init sunsab_init(void) static void __exit sunsab_exit(void) { of_unregister_driver(&sab_driver); - if (num_channels) { - sunserial_current_minor -= num_channels; - uart_unregister_driver(&sunsab_reg); + if (sunsab_reg.nr) { + sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr); } kfree(sunsab_ports); diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index e074943feff..4e2302d43ab 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1528,14 +1528,12 @@ static struct of_platform_driver su_driver = { .remove = __devexit_p(su_remove), }; -static int num_uart; - static int __init sunsu_init(void) { struct device_node *dp; int err; + int num_uart = 0; - num_uart = 0; for_each_node_by_name(dp, "su") { if (su_get_type(dp) == SU_PORT_PORT) num_uart++; @@ -1552,26 +1550,22 @@ static int __init sunsu_init(void) } if (num_uart) { - sunsu_reg.minor = sunserial_current_minor; - sunsu_reg.nr = num_uart; - err = uart_register_driver(&sunsu_reg); + err = sunserial_register_minors(&sunsu_reg, num_uart); if (err) return err; - sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; - sunserial_current_minor += num_uart; } err = of_register_driver(&su_driver, &of_bus_type); if (err && num_uart) - uart_unregister_driver(&sunsu_reg); + sunserial_unregister_minors(&sunsu_reg, num_uart); return err; } static void __exit sunsu_exit(void) { - if (num_uart) - uart_unregister_driver(&sunsu_reg); + if (sunsu_reg.nr) + sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr); } module_init(sunsu_init); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 283bef0d24c..cb2e4050637 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -63,10 +63,6 @@ readb(&((__channel)->control)) #endif -static int num_sunzilog; -#define NUM_SUNZILOG num_sunzilog -#define NUM_CHANNELS (NUM_SUNZILOG * 2) - #define ZS_CLOCK 4915200 /* Zilog input clock rate. */ #define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ @@ -1031,18 +1027,19 @@ static struct uart_driver sunzilog_reg = { .major = TTY_MAJOR, }; -static int __init sunzilog_alloc_tables(void) +static int __init sunzilog_alloc_tables(int num_sunzilog) { struct uart_sunzilog_port *up; unsigned long size; + int num_channels = num_sunzilog * 2; int i; - size = NUM_CHANNELS * sizeof(struct uart_sunzilog_port); + size = num_channels * sizeof(struct uart_sunzilog_port); sunzilog_port_table = kzalloc(size, GFP_KERNEL); if (!sunzilog_port_table) return -ENOMEM; - for (i = 0; i < NUM_CHANNELS; i++) { + for (i = 0; i < num_channels; i++) { up = &sunzilog_port_table[i]; spin_lock_init(&up->port.lock); @@ -1050,13 +1047,13 @@ static int __init sunzilog_alloc_tables(void) if (i == 0) sunzilog_irq_chain = up; - if (i < NUM_CHANNELS - 1) + if (i < num_channels - 1) up->next = up + 1; else up->next = NULL; } - size = NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *); + size = num_sunzilog * sizeof(struct zilog_layout __iomem *); sunzilog_chip_regs = kzalloc(size, GFP_KERNEL); if (!sunzilog_chip_regs) { kfree(sunzilog_port_table); @@ -1496,34 +1493,28 @@ static int __init sunzilog_init(void) struct device_node *dp; int err, uart_count; int num_keybms; + int num_sunzilog = 0; - NUM_SUNZILOG = 0; num_keybms = 0; for_each_node_by_name(dp, "zs") { - NUM_SUNZILOG++; + num_sunzilog++; if (of_find_property(dp, "keyboard", NULL)) num_keybms++; } uart_count = 0; - if (NUM_SUNZILOG) { + if (num_sunzilog) { int uart_count; - err = sunzilog_alloc_tables(); + err = sunzilog_alloc_tables(num_sunzilog); if (err) goto out; - uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms); + uart_count = (num_sunzilog * 2) - (2 * num_keybms); - sunzilog_reg.nr = uart_count; - sunzilog_reg.minor = sunserial_current_minor; - err = uart_register_driver(&sunzilog_reg); + err = sunserial_register_minors(&sunzilog_reg, uart_count); if (err) goto out_free_tables; - - sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; - - sunserial_current_minor += uart_count; } err = of_register_driver(&zs_driver, &of_bus_type); @@ -1557,8 +1548,8 @@ out_unregister_driver: of_unregister_driver(&zs_driver); out_unregister_uart: - if (NUM_SUNZILOG) { - uart_unregister_driver(&sunzilog_reg); + if (num_sunzilog) { + sunserial_unregister_minors(&sunzilog_reg, num_sunzilog); sunzilog_reg.cons = NULL; } @@ -1590,8 +1581,8 @@ static void __exit sunzilog_exit(void) zilog_irq = -1; } - if (NUM_SUNZILOG) { - uart_unregister_driver(&sunzilog_reg); + if (sunzilog_reg.nr) { + sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr); sunzilog_free_tables(); } } diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index a85f2d31a68..bacf68dca01 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -142,7 +142,7 @@ static int ulite_transmit(struct uart_port *port, int stat) static irqreturn_t ulite_isr(int irq, void *dev_id) { - struct uart_port *port = (struct uart_port *)dev_id; + struct uart_port *port = dev_id; int busy; do { @@ -393,6 +393,7 @@ static inline void __init ulite_console_of_find_device(int id) continue; ulite_ports[id].mapbase = res.start; + of_node_put(np); return; } } @@ -538,7 +539,7 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) * * @dev: pointer to device structure */ -static int __devinit ulite_release(struct device *dev) +static int __devexit ulite_release(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); int rc = 0; @@ -571,14 +572,14 @@ static int __devinit ulite_probe(struct platform_device *pdev) return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); } -static int ulite_remove(struct platform_device *pdev) +static int __devexit ulite_remove(struct platform_device *pdev) { return ulite_release(&pdev->dev); } static struct platform_driver ulite_platform_driver = { .probe = ulite_probe, - .remove = ulite_remove, + .remove = __devexit_p(ulite_remove), .driver = { .owner = THIS_MODULE, .name = "uartlite", diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c new file mode 100644 index 00000000000..e0994f06100 --- /dev/null +++ b/drivers/serial/ucc_uart.c @@ -0,0 +1,1514 @@ +/* + * Freescale QUICC Engine UART device driver + * + * Author: Timur Tabi <timur@freescale.com> + * + * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * This driver adds support for UART devices via Freescale's QUICC Engine + * found on some Freescale SOCs. + * + * If Soft-UART support is needed but not already present, then this driver + * will request and upload the "Soft-UART" microcode upon probe. The + * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X" + * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC, + * (e.g. "11" for 1.1). + */ + +#include <linux/module.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/io.h> +#include <linux/of_platform.h> +#include <linux/dma-mapping.h> + +#include <linux/fs_uart_pd.h> +#include <asm/ucc_slow.h> + +#include <linux/firmware.h> +#include <asm/reg.h> + +/* + * The GUMR flag for Soft UART. This would normally be defined in qe.h, + * but Soft-UART is a hack and we want to keep everything related to it in + * this file. + */ +#define UCC_SLOW_GUMR_H_SUART 0x00004000 /* Soft-UART */ + +/* + * soft_uart is 1 if we need to use Soft-UART mode + */ +static int soft_uart; +/* + * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise. + */ +static int firmware_loaded; + +/* Enable this macro to configure all serial ports in internal loopback + mode */ +/* #define LOOPBACK */ + +/* The major and minor device numbers are defined in + * http://www.lanana.org/docs/device-list/devices-2.6+.txt. For the QE + * UART, we have major number 204 and minor numbers 46 - 49, which are the + * same as for the CPM2. This decision was made because no Freescale part + * has both a CPM and a QE. + */ +#define SERIAL_QE_MAJOR 204 +#define SERIAL_QE_MINOR 46 + +/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */ +#define UCC_MAX_UART 4 + +/* The number of buffer descriptors for receiving characters. */ +#define RX_NUM_FIFO 4 + +/* The number of buffer descriptors for transmitting characters. */ +#define TX_NUM_FIFO 4 + +/* The maximum size of the character buffer for a single RX BD. */ +#define RX_BUF_SIZE 32 + +/* The maximum size of the character buffer for a single TX BD. */ +#define TX_BUF_SIZE 32 + +/* + * The number of jiffies to wait after receiving a close command before the + * device is actually closed. This allows the last few characters to be + * sent over the wire. + */ +#define UCC_WAIT_CLOSING 100 + +struct ucc_uart_pram { + struct ucc_slow_pram common; + u8 res1[8]; /* reserved */ + __be16 maxidl; /* Maximum idle chars */ + __be16 idlc; /* temp idle counter */ + __be16 brkcr; /* Break count register */ + __be16 parec; /* receive parity error counter */ + __be16 frmec; /* receive framing error counter */ + __be16 nosec; /* receive noise counter */ + __be16 brkec; /* receive break condition counter */ + __be16 brkln; /* last received break length */ + __be16 uaddr[2]; /* UART address character 1 & 2 */ + __be16 rtemp; /* Temp storage */ + __be16 toseq; /* Transmit out of sequence char */ + __be16 cchars[8]; /* control characters 1-8 */ + __be16 rccm; /* receive control character mask */ + __be16 rccr; /* receive control character register */ + __be16 rlbc; /* receive last break character */ + __be16 res2; /* reserved */ + __be32 res3; /* reserved, should be cleared */ + u8 res4; /* reserved, should be cleared */ + u8 res5[3]; /* reserved, should be cleared */ + __be32 res6; /* reserved, should be cleared */ + __be32 res7; /* reserved, should be cleared */ + __be32 res8; /* reserved, should be cleared */ + __be32 res9; /* reserved, should be cleared */ + __be32 res10; /* reserved, should be cleared */ + __be32 res11; /* reserved, should be cleared */ + __be32 res12; /* reserved, should be cleared */ + __be32 res13; /* reserved, should be cleared */ +/* The rest is for Soft-UART only */ + __be16 supsmr; /* 0x90, Shadow UPSMR */ + __be16 res92; /* 0x92, reserved, initialize to 0 */ + __be32 rx_state; /* 0x94, RX state, initialize to 0 */ + __be32 rx_cnt; /* 0x98, RX count, initialize to 0 */ + u8 rx_length; /* 0x9C, Char length, set to 1+CL+PEN+1+SL */ + u8 rx_bitmark; /* 0x9D, reserved, initialize to 0 */ + u8 rx_temp_dlst_qe; /* 0x9E, reserved, initialize to 0 */ + u8 res14[0xBC - 0x9F]; /* reserved */ + __be32 dump_ptr; /* 0xBC, Dump pointer */ + __be32 rx_frame_rem; /* 0xC0, reserved, initialize to 0 */ + u8 rx_frame_rem_size; /* 0xC4, reserved, initialize to 0 */ + u8 tx_mode; /* 0xC5, mode, 0=AHDLC, 1=UART */ + __be16 tx_state; /* 0xC6, TX state */ + u8 res15[0xD0 - 0xC8]; /* reserved */ + __be32 resD0; /* 0xD0, reserved, initialize to 0 */ + u8 resD4; /* 0xD4, reserved, initialize to 0 */ + __be16 resD5; /* 0xD5, reserved, initialize to 0 */ +} __attribute__ ((packed)); + +/* SUPSMR definitions, for Soft-UART only */ +#define UCC_UART_SUPSMR_SL 0x8000 +#define UCC_UART_SUPSMR_RPM_MASK 0x6000 +#define UCC_UART_SUPSMR_RPM_ODD 0x0000 +#define UCC_UART_SUPSMR_RPM_LOW 0x2000 +#define UCC_UART_SUPSMR_RPM_EVEN 0x4000 +#define UCC_UART_SUPSMR_RPM_HIGH 0x6000 +#define UCC_UART_SUPSMR_PEN 0x1000 +#define UCC_UART_SUPSMR_TPM_MASK 0x0C00 +#define UCC_UART_SUPSMR_TPM_ODD 0x0000 +#define UCC_UART_SUPSMR_TPM_LOW 0x0400 +#define UCC_UART_SUPSMR_TPM_EVEN 0x0800 +#define UCC_UART_SUPSMR_TPM_HIGH 0x0C00 +#define UCC_UART_SUPSMR_FRZ 0x0100 +#define UCC_UART_SUPSMR_UM_MASK 0x00c0 +#define UCC_UART_SUPSMR_UM_NORMAL 0x0000 +#define UCC_UART_SUPSMR_UM_MAN_MULTI 0x0040 +#define UCC_UART_SUPSMR_UM_AUTO_MULTI 0x00c0 +#define UCC_UART_SUPSMR_CL_MASK 0x0030 +#define UCC_UART_SUPSMR_CL_8 0x0030 +#define UCC_UART_SUPSMR_CL_7 0x0020 +#define UCC_UART_SUPSMR_CL_6 0x0010 +#define UCC_UART_SUPSMR_CL_5 0x0000 + +#define UCC_UART_TX_STATE_AHDLC 0x00 +#define UCC_UART_TX_STATE_UART 0x01 +#define UCC_UART_TX_STATE_X1 0x00 +#define UCC_UART_TX_STATE_X16 0x80 + +#define UCC_UART_PRAM_ALIGNMENT 0x100 + +#define UCC_UART_SIZE_OF_BD UCC_SLOW_SIZE_OF_BD +#define NUM_CONTROL_CHARS 8 + +/* Private per-port data structure */ +struct uart_qe_port { + struct uart_port port; + struct ucc_slow __iomem *uccp; + struct ucc_uart_pram __iomem *uccup; + struct ucc_slow_info us_info; + struct ucc_slow_private *us_private; + struct device_node *np; + unsigned int ucc_num; /* First ucc is 0, not 1 */ + + u16 rx_nrfifos; + u16 rx_fifosize; + u16 tx_nrfifos; + u16 tx_fifosize; + int wait_closing; + u32 flags; + struct qe_bd *rx_bd_base; + struct qe_bd *rx_cur; + struct qe_bd *tx_bd_base; + struct qe_bd *tx_cur; + unsigned char *tx_buf; + unsigned char *rx_buf; + void *bd_virt; /* virtual address of the BD buffers */ + dma_addr_t bd_dma_addr; /* bus address of the BD buffers */ + unsigned int bd_size; /* size of BD buffer space */ +}; + +static struct uart_driver ucc_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyQE", + .major = SERIAL_QE_MAJOR, + .minor = SERIAL_QE_MINOR, + .nr = UCC_MAX_UART, +}; + +/* + * Virtual to physical address translation. + * + * Given the virtual address for a character buffer, this function returns + * the physical (DMA) equivalent. + */ +static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port) +{ + if (likely((addr >= qe_port->bd_virt)) && + (addr < (qe_port->bd_virt + qe_port->bd_size))) + return qe_port->bd_dma_addr + (addr - qe_port->bd_virt); + + /* something nasty happened */ + printk(KERN_ERR "%s: addr=%p\n", __FUNCTION__, addr); + BUG(); + return 0; +} + +/* + * Physical to virtual address translation. + * + * Given the physical (DMA) address for a character buffer, this function + * returns the virtual equivalent. + */ +static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port) +{ + /* sanity check */ + if (likely((addr >= qe_port->bd_dma_addr) && + (addr < (qe_port->bd_dma_addr + qe_port->bd_size)))) + return qe_port->bd_virt + (addr - qe_port->bd_dma_addr); + + /* something nasty happened */ + printk(KERN_ERR "%s: addr=%x\n", __FUNCTION__, addr); + BUG(); + return NULL; +} + +/* + * Return 1 if the QE is done transmitting all buffers for this port + * + * This function scans each BD in sequence. If we find a BD that is not + * ready (READY=1), then we return 0 indicating that the QE is still sending + * data. If we reach the last BD (WRAP=1), then we know we've scanned + * the entire list, and all BDs are done. + */ +static unsigned int qe_uart_tx_empty(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct qe_bd *bdp = qe_port->tx_bd_base; + + while (1) { + if (in_be16(&bdp->status) & BD_SC_READY) + /* This BD is not done, so return "not done" */ + return 0; + + if (in_be16(&bdp->status) & BD_SC_WRAP) + /* + * This BD is done and it's the last one, so return + * "done" + */ + return 1; + + bdp++; + }; +} + +/* + * Set the modem control lines + * + * Although the QE can control the modem control lines (e.g. CTS), we + * don't need that support. This function must exist, however, otherwise + * the kernel will panic. + */ +void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/* + * Get the current modem control line status + * + * Although the QE can control the modem control lines (e.g. CTS), this + * driver currently doesn't support that, so we always return Carrier + * Detect, Data Set Ready, and Clear To Send. + */ +static unsigned int qe_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/* + * Disable the transmit interrupt. + * + * Although this function is called "stop_tx", it does not actually stop + * transmission of data. Instead, it tells the QE to not generate an + * interrupt when the UCC is finished sending characters. + */ +static void qe_uart_stop_tx(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + + clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX); +} + +/* + * Transmit as many characters to the HW as possible. + * + * This function will attempt to stuff of all the characters from the + * kernel's transmit buffer into TX BDs. + * + * A return value of non-zero indicates that it sucessfully stuffed all + * characters from the kernel buffer. + * + * A return value of zero indicates that there are still characters in the + * kernel's buffer that have not been transmitted, but there are no more BDs + * available. This function should be called again after a BD has been made + * available. + */ +static int qe_uart_tx_pump(struct uart_qe_port *qe_port) +{ + struct qe_bd *bdp; + unsigned char *p; + unsigned int count; + struct uart_port *port = &qe_port->port; + struct circ_buf *xmit = &port->info->xmit; + + bdp = qe_port->rx_cur; + + /* Handle xon/xoff */ + if (port->x_char) { + /* Pick next descriptor and fill from buffer */ + bdp = qe_port->tx_cur; + + p = qe2cpu_addr(bdp->buf, qe_port); + + *p++ = port->x_char; + out_be16(&bdp->length, 1); + setbits16(&bdp->status, BD_SC_READY); + /* Get next BD. */ + if (in_be16(&bdp->status) & BD_SC_WRAP) + bdp = qe_port->tx_bd_base; + else + bdp++; + qe_port->tx_cur = bdp; + + port->icount.tx++; + port->x_char = 0; + return 1; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + qe_uart_stop_tx(port); + return 0; + } + + /* Pick next descriptor and fill from buffer */ + bdp = qe_port->tx_cur; + + while (!(in_be16(&bdp->status) & BD_SC_READY) && + (xmit->tail != xmit->head)) { + count = 0; + p = qe2cpu_addr(bdp->buf, qe_port); + while (count < qe_port->tx_fifosize) { + *p++ = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + count++; + if (xmit->head == xmit->tail) + break; + } + + out_be16(&bdp->length, count); + setbits16(&bdp->status, BD_SC_READY); + + /* Get next BD. */ + if (in_be16(&bdp->status) & BD_SC_WRAP) + bdp = qe_port->tx_bd_base; + else + bdp++; + } + qe_port->tx_cur = bdp; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) { + /* The kernel buffer is empty, so turn off TX interrupts. We + don't need to be told when the QE is finished transmitting + the data. */ + qe_uart_stop_tx(port); + return 0; + } + + return 1; +} + +/* + * Start transmitting data + * + * This function will start transmitting any available data, if the port + * isn't already transmitting data. + */ +static void qe_uart_start_tx(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + + /* If we currently are transmitting, then just return */ + if (in_be16(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX) + return; + + /* Otherwise, pump the port and start transmission */ + if (qe_uart_tx_pump(qe_port)) + setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX); +} + +/* + * Stop transmitting data + */ +static void qe_uart_stop_rx(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + + clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); +} + +/* + * Enable status change interrupts + * + * We don't support status change interrupts, but we need to define this + * function otherwise the kernel will panic. + */ +static void qe_uart_enable_ms(struct uart_port *port) +{ +} + +/* Start or stop sending break signal + * + * This function controls the sending of a break signal. If break_state=1, + * then we start sending a break signal. If break_state=0, then we stop + * sending the break signal. + */ +static void qe_uart_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + + if (break_state) + ucc_slow_stop_tx(qe_port->us_private); + else + ucc_slow_restart_tx(qe_port->us_private); +} + +/* ISR helper function for receiving character. + * + * This function is called by the ISR to handling receiving characters + */ +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->info->tty; + struct qe_bd *bdp; + u16 status; + unsigned int flg; + + /* Just loop through the closed BDs and copy the characters into + * the buffer. + */ + bdp = qe_port->rx_cur; + while (1) { + status = in_be16(&bdp->status); + + /* If this one is empty, then we assume we've read them all */ + if (status & BD_SC_EMPTY) + break; + + /* get number of characters, and check space in RX buffer */ + i = in_be16(&bdp->length); + + /* 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) { + dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n"); + return; + } + + /* get pointer */ + cp = qe2cpu_addr(bdp->buf, qe_port); + + /* loop through the buffer */ + while (i-- > 0) { + ch = *cp++; + port->icount.rx++; + flg = TTY_NORMAL; + + if (!i && status & + (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) + goto handle_error; + if (uart_handle_sysrq_char(port, ch)) + continue; + +error_return: + tty_insert_flip_char(tty, ch, flg); + + } + + /* This BD is ready to be used again. Clear status. get next */ + clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR | + BD_SC_OV | BD_SC_ID, BD_SC_EMPTY); + if (in_be16(&bdp->status) & BD_SC_WRAP) + bdp = qe_port->rx_bd_base; + else + bdp++; + + } + + /* Write back buffer pointer */ + qe_port->rx_cur = bdp; + + /* Activate BH processing */ + tty_flip_buffer_push(tty); + + return; + + /* Error processing */ + +handle_error: + /* Statistics */ + if (status & BD_SC_BR) + port->icount.brk++; + if (status & BD_SC_PR) + port->icount.parity++; + if (status & BD_SC_FR) + port->icount.frame++; + if (status & BD_SC_OV) + port->icount.overrun++; + + /* Mask out ignored conditions */ + status &= port->read_status_mask; + + /* Handle the remaining ones */ + if (status & BD_SC_BR) + flg = TTY_BREAK; + else if (status & BD_SC_PR) + flg = TTY_PARITY; + else if (status & BD_SC_FR) + flg = TTY_FRAME; + + /* Overrun does not affect the current character ! */ + if (status & BD_SC_OV) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); +#ifdef SUPPORT_SYSRQ + port->sysrq = 0; +#endif + goto error_return; +} + +/* Interrupt handler + * + * This interrupt handler is called after a BD is processed. + */ +static irqreturn_t qe_uart_int(int irq, void *data) +{ + struct uart_qe_port *qe_port = (struct uart_qe_port *) data; + struct ucc_slow __iomem *uccp = qe_port->uccp; + u16 events; + + /* Clear the interrupts */ + events = in_be16(&uccp->ucce); + out_be16(&uccp->ucce, events); + + if (events & UCC_UART_UCCE_BRKE) + uart_handle_break(&qe_port->port); + + if (events & UCC_UART_UCCE_RX) + qe_uart_int_rx(qe_port); + + if (events & UCC_UART_UCCE_TX) + qe_uart_tx_pump(qe_port); + + return events ? IRQ_HANDLED : IRQ_NONE; +} + +/* Initialize buffer descriptors + * + * This function initializes all of the RX and TX buffer descriptors. + */ +static void qe_uart_initbd(struct uart_qe_port *qe_port) +{ + int i; + void *bd_virt; + struct qe_bd *bdp; + + /* Set the physical address of the host memory buffers in the buffer + * descriptors, and the virtual address for us to work with. + */ + bd_virt = qe_port->bd_virt; + bdp = qe_port->rx_bd_base; + qe_port->rx_cur = qe_port->rx_bd_base; + for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) { + out_be16(&bdp->status, BD_SC_EMPTY | BD_SC_INTRPT); + out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); + out_be16(&bdp->length, 0); + bd_virt += qe_port->rx_fifosize; + bdp++; + } + + /* */ + out_be16(&bdp->status, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT); + out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); + out_be16(&bdp->length, 0); + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + bd_virt = qe_port->bd_virt + + L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); + qe_port->tx_cur = qe_port->tx_bd_base; + bdp = qe_port->tx_bd_base; + for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) { + out_be16(&bdp->status, BD_SC_INTRPT); + out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); + out_be16(&bdp->length, 0); + bd_virt += qe_port->tx_fifosize; + bdp++; + } + + /* Loopback requires the preamble bit to be set on the first TX BD */ +#ifdef LOOPBACK + setbits16(&qe_port->tx_cur->status, BD_SC_P); +#endif + + out_be16(&bdp->status, BD_SC_WRAP | BD_SC_INTRPT); + out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); + out_be16(&bdp->length, 0); +} + +/* + * Initialize a UCC for UART. + * + * This function configures a given UCC to be used as a UART device. Basic + * UCC initialization is handled in qe_uart_request_port(). This function + * does all the UART-specific stuff. + */ +static void qe_uart_init_ucc(struct uart_qe_port *qe_port) +{ + u32 cecr_subblock; + struct ucc_slow __iomem *uccp = qe_port->uccp; + struct ucc_uart_pram *uccup = qe_port->uccup; + + unsigned int i; + + /* First, disable TX and RX in the UCC */ + ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); + + /* Program the UCC UART parameter RAM */ + out_8(&uccup->common.rbmr, UCC_BMR_GBL | UCC_BMR_BO_BE); + out_8(&uccup->common.tbmr, UCC_BMR_GBL | UCC_BMR_BO_BE); + out_be16(&uccup->common.mrblr, qe_port->rx_fifosize); + out_be16(&uccup->maxidl, 0x10); + out_be16(&uccup->brkcr, 1); + out_be16(&uccup->parec, 0); + out_be16(&uccup->frmec, 0); + out_be16(&uccup->nosec, 0); + out_be16(&uccup->brkec, 0); + out_be16(&uccup->uaddr[0], 0); + out_be16(&uccup->uaddr[1], 0); + out_be16(&uccup->toseq, 0); + for (i = 0; i < 8; i++) + out_be16(&uccup->cchars[i], 0xC000); + out_be16(&uccup->rccm, 0xc0ff); + + /* Configure the GUMR registers for UART */ + if (soft_uart) + /* Soft-UART requires a 1X multiplier for TX */ + clrsetbits_be32(&uccp->gumr_l, + UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | + UCC_SLOW_GUMR_L_RDCR_MASK, + UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 | + UCC_SLOW_GUMR_L_RDCR_16); + else + clrsetbits_be32(&uccp->gumr_l, + UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | + UCC_SLOW_GUMR_L_RDCR_MASK, + UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 | + UCC_SLOW_GUMR_L_RDCR_16); + + clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW, + UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX); + +#ifdef LOOPBACK + clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, + UCC_SLOW_GUMR_L_DIAG_LOOP); + clrsetbits_be32(&uccp->gumr_h, + UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN, + UCC_SLOW_GUMR_H_CDS); +#endif + + /* Enable rx interrupts and clear all pending events. */ + out_be16(&uccp->uccm, 0); + out_be16(&uccp->ucce, 0xffff); + out_be16(&uccp->udsr, 0x7e7e); + + /* Initialize UPSMR */ + out_be16(&uccp->upsmr, 0); + + if (soft_uart) { + out_be16(&uccup->supsmr, 0x30); + out_be16(&uccup->res92, 0); + out_be32(&uccup->rx_state, 0); + out_be32(&uccup->rx_cnt, 0); + out_8(&uccup->rx_bitmark, 0); + out_8(&uccup->rx_length, 10); + out_be32(&uccup->dump_ptr, 0x4000); + out_8(&uccup->rx_temp_dlst_qe, 0); + out_be32(&uccup->rx_frame_rem, 0); + out_8(&uccup->rx_frame_rem_size, 0); + /* Soft-UART requires TX to be 1X */ + out_8(&uccup->tx_mode, + UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1); + out_be16(&uccup->tx_state, 0); + out_8(&uccup->resD4, 0); + out_be16(&uccup->resD5, 0); + + /* Set UART mode. + * Enable receive and transmit. + */ + + /* From the microcode errata: + * 1.GUMR_L register, set mode=0010 (QMC). + * 2.Set GUMR_H[17] bit. (UART/AHDLC mode). + * 3.Set GUMR_H[19:20] (Transparent mode) + * 4.Clear GUMR_H[26] (RFW) + * ... + * 6.Receiver must use 16x over sampling + */ + clrsetbits_be32(&uccp->gumr_l, + UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | + UCC_SLOW_GUMR_L_RDCR_MASK, + UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 | + UCC_SLOW_GUMR_L_RDCR_16); + + clrsetbits_be32(&uccp->gumr_h, + UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN, + UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX | + UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL); + +#ifdef LOOPBACK + clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, + UCC_SLOW_GUMR_L_DIAG_LOOP); + clrbits32(&uccp->gumr_h, UCC_SLOW_GUMR_H_CTSP | + UCC_SLOW_GUMR_H_CDS); +#endif + + cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); + qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, + QE_CR_PROTOCOL_UNSPECIFIED, 0); + } +} + +/* + * Initialize the port. + */ +static int qe_uart_startup(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + int ret; + + /* + * If we're using Soft-UART mode, then we need to make sure the + * firmware has been uploaded first. + */ + if (soft_uart && !firmware_loaded) { + dev_err(port->dev, "Soft-UART firmware not uploaded\n"); + return -ENODEV; + } + + qe_uart_initbd(qe_port); + qe_uart_init_ucc(qe_port); + + /* Install interrupt handler. */ + ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart", + qe_port); + if (ret) { + dev_err(port->dev, "could not claim IRQ %u\n", port->irq); + return ret; + } + + /* Startup rx-int */ + setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); + ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX); + + return 0; +} + +/* + * Shutdown the port. + */ +static void qe_uart_shutdown(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct ucc_slow __iomem *uccp = qe_port->uccp; + unsigned int timeout = 20; + + /* Disable RX and TX */ + + /* Wait for all the BDs marked sent */ + while (!qe_uart_tx_empty(port)) { + if (!--timeout) { + dev_warn(port->dev, "shutdown timeout\n"); + break; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(2); + } + + if (qe_port->wait_closing) { + /* Wait a bit longer */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(qe_port->wait_closing); + } + + /* Stop uarts */ + ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); + clrbits16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX); + + /* Shut them really down and reinit buffer descriptors */ + ucc_slow_graceful_stop_tx(qe_port->us_private); + qe_uart_initbd(qe_port); + + free_irq(port->irq, qe_port); +} + +/* + * Set the serial port parameters. + */ +static void qe_uart_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct ucc_slow __iomem *uccp = qe_port->uccp; + unsigned int baud; + unsigned long flags; + u16 upsmr = in_be16(&uccp->upsmr); + struct ucc_uart_pram __iomem *uccup = qe_port->uccup; + u16 supsmr = in_be16(&uccup->supsmr); + u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */ + + /* Character length programmed into the mode register is the + * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, + * 1 or 2 stop bits, minus 1. + * The value 'bits' counts this for us. + */ + + /* byte size */ + upsmr &= UCC_UART_UPSMR_CL_MASK; + supsmr &= UCC_UART_SUPSMR_CL_MASK; + + switch (termios->c_cflag & CSIZE) { + case CS5: + upsmr |= UCC_UART_UPSMR_CL_5; + supsmr |= UCC_UART_SUPSMR_CL_5; + char_length += 5; + break; + case CS6: + upsmr |= UCC_UART_UPSMR_CL_6; + supsmr |= UCC_UART_SUPSMR_CL_6; + char_length += 6; + break; + case CS7: + upsmr |= UCC_UART_UPSMR_CL_7; + supsmr |= UCC_UART_SUPSMR_CL_7; + char_length += 7; + break; + default: /* case CS8 */ + upsmr |= UCC_UART_UPSMR_CL_8; + supsmr |= UCC_UART_SUPSMR_CL_8; + char_length += 8; + break; + } + + /* If CSTOPB is set, we want two stop bits */ + if (termios->c_cflag & CSTOPB) { + upsmr |= UCC_UART_UPSMR_SL; + supsmr |= UCC_UART_SUPSMR_SL; + char_length++; /* + SL */ + } + + if (termios->c_cflag & PARENB) { + upsmr |= UCC_UART_UPSMR_PEN; + supsmr |= UCC_UART_SUPSMR_PEN; + char_length++; /* + PEN */ + + if (!(termios->c_cflag & PARODD)) { + upsmr &= ~(UCC_UART_UPSMR_RPM_MASK | + UCC_UART_UPSMR_TPM_MASK); + upsmr |= UCC_UART_UPSMR_RPM_EVEN | + UCC_UART_UPSMR_TPM_EVEN; + supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK | + UCC_UART_SUPSMR_TPM_MASK); + supsmr |= UCC_UART_SUPSMR_RPM_EVEN | + UCC_UART_SUPSMR_TPM_EVEN; + } + } + + /* + * Set up parity check flag + */ + port->read_status_mask = BD_SC_EMPTY | BD_SC_OV; + if (termios->c_iflag & INPCK) + port->read_status_mask |= BD_SC_FR | BD_SC_PR; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= BD_SC_BR; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= BD_SC_PR | BD_SC_FR; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= BD_SC_BR; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= BD_SC_OV; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + port->read_status_mask &= ~BD_SC_EMPTY; + + baud = uart_get_baud_rate(port, termios, old, 0, 115200); + + /* Do we really need a spinlock here? */ + spin_lock_irqsave(&port->lock, flags); + + out_be16(&uccp->upsmr, upsmr); + if (soft_uart) { + out_be16(&uccup->supsmr, supsmr); + out_8(&uccup->rx_length, char_length); + + /* Soft-UART requires a 1X multiplier for TX */ + qe_setbrg(qe_port->us_info.rx_clock, baud, 16); + qe_setbrg(qe_port->us_info.tx_clock, baud, 1); + } else { + qe_setbrg(qe_port->us_info.rx_clock, baud, 16); + qe_setbrg(qe_port->us_info.tx_clock, baud, 16); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* + * Return a pointer to a string that describes what kind of port this is. + */ +static const char *qe_uart_type(struct uart_port *port) +{ + return "QE"; +} + +/* + * Allocate any memory and I/O resources required by the port. + */ +static int qe_uart_request_port(struct uart_port *port) +{ + int ret; + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct ucc_slow_info *us_info = &qe_port->us_info; + struct ucc_slow_private *uccs; + unsigned int rx_size, tx_size; + void *bd_virt; + dma_addr_t bd_dma_addr = 0; + + ret = ucc_slow_init(us_info, &uccs); + if (ret) { + dev_err(port->dev, "could not initialize UCC%u\n", + qe_port->ucc_num); + return ret; + } + + qe_port->us_private = uccs; + qe_port->uccp = uccs->us_regs; + qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram; + qe_port->rx_bd_base = uccs->rx_bd; + qe_port->tx_bd_base = uccs->tx_bd; + + /* + * Allocate the transmit and receive data buffers. + */ + + rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); + tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize); + + bd_virt = dma_alloc_coherent(NULL, rx_size + tx_size, &bd_dma_addr, + GFP_KERNEL); + if (!bd_virt) { + dev_err(port->dev, "could not allocate buffer descriptors\n"); + return -ENOMEM; + } + + qe_port->bd_virt = bd_virt; + qe_port->bd_dma_addr = bd_dma_addr; + qe_port->bd_size = rx_size + tx_size; + + qe_port->rx_buf = bd_virt; + qe_port->tx_buf = qe_port->rx_buf + rx_size; + + return 0; +} + +/* + * Configure the port. + * + * We say we're a CPM-type port because that's mostly true. Once the device + * is configured, this driver operates almost identically to the CPM serial + * driver. + */ +static void qe_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_CPM; + qe_uart_request_port(port); + } +} + +/* + * Release any memory and I/O resources that were allocated in + * qe_uart_request_port(). + */ +static void qe_uart_release_port(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct ucc_slow_private *uccs = qe_port->us_private; + + dma_free_coherent(NULL, qe_port->bd_size, qe_port->bd_virt, + qe_port->bd_dma_addr); + + ucc_slow_free(uccs); +} + +/* + * Verify that the data in serial_struct is suitable for this device. + */ +static int qe_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) + return -EINVAL; + + if (ser->irq < 0 || ser->irq >= NR_IRQS) + return -EINVAL; + + if (ser->baud_base < 9600) + return -EINVAL; + + return 0; +} +/* UART operations + * + * Details on these functions can be found in Documentation/serial/driver + */ +static struct uart_ops qe_uart_pops = { + .tx_empty = qe_uart_tx_empty, + .set_mctrl = qe_uart_set_mctrl, + .get_mctrl = qe_uart_get_mctrl, + .stop_tx = qe_uart_stop_tx, + .start_tx = qe_uart_start_tx, + .stop_rx = qe_uart_stop_rx, + .enable_ms = qe_uart_enable_ms, + .break_ctl = qe_uart_break_ctl, + .startup = qe_uart_startup, + .shutdown = qe_uart_shutdown, + .set_termios = qe_uart_set_termios, + .type = qe_uart_type, + .release_port = qe_uart_release_port, + .request_port = qe_uart_request_port, + .config_port = qe_uart_config_port, + .verify_port = qe_uart_verify_port, +}; + +/* + * Obtain the SOC model number and revision level + * + * This function parses the device tree to obtain the SOC model. It then + * reads the SVR register to the revision. + * + * The device tree stores the SOC model two different ways. + * + * The new way is: + * + * cpu@0 { + * compatible = "PowerPC,8323"; + * device_type = "cpu"; + * ... + * + * + * The old way is: + * PowerPC,8323@0 { + * device_type = "cpu"; + * ... + * + * This code first checks the new way, and then the old way. + */ +static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l) +{ + struct device_node *np; + const char *soc_string; + unsigned int svr; + unsigned int soc; + + /* Find the CPU node */ + np = of_find_node_by_type(NULL, "cpu"); + if (!np) + return 0; + /* Find the compatible property */ + soc_string = of_get_property(np, "compatible", NULL); + if (!soc_string) + /* No compatible property, so try the name. */ + soc_string = np->name; + + /* Extract the SOC number from the "PowerPC," string */ + if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc) + return 0; + + /* Get the revision from the SVR */ + svr = mfspr(SPRN_SVR); + *rev_h = (svr >> 4) & 0xf; + *rev_l = svr & 0xf; + + return soc; +} + +/* + * requst_firmware_nowait() callback function + * + * This function is called by the kernel when a firmware is made available, + * or if it times out waiting for the firmware. + */ +static void uart_firmware_cont(const struct firmware *fw, void *context) +{ + struct qe_firmware *firmware; + struct device *dev = context; + int ret; + + if (!fw) { + dev_err(dev, "firmware not found\n"); + return; + } + + firmware = (struct qe_firmware *) fw->data; + + if (firmware->header.length != fw->size) { + dev_err(dev, "invalid firmware\n"); + return; + } + + ret = qe_upload_firmware(firmware); + if (ret) { + dev_err(dev, "could not load firmware\n"); + return; + } + + firmware_loaded = 1; +} + +static int ucc_uart_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + const unsigned int *iprop; /* Integer OF properties */ + const char *sprop; /* String OF properties */ + struct uart_qe_port *qe_port = NULL; + struct resource res; + int ret; + + /* + * Determine if we need Soft-UART mode + */ + if (of_find_property(np, "soft-uart", NULL)) { + dev_dbg(&ofdev->dev, "using Soft-UART mode\n"); + soft_uart = 1; + } + + /* + * If we are using Soft-UART, determine if we need to upload the + * firmware, too. + */ + if (soft_uart) { + struct qe_firmware_info *qe_fw_info; + + qe_fw_info = qe_get_firmware_info(); + + /* Check if the firmware has been uploaded. */ + if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) { + firmware_loaded = 1; + } else { + char filename[32]; + unsigned int soc; + unsigned int rev_h; + unsigned int rev_l; + + soc = soc_info(&rev_h, &rev_l); + if (!soc) { + dev_err(&ofdev->dev, "unknown CPU model\n"); + return -ENXIO; + } + sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin", + soc, rev_h, rev_l); + + dev_info(&ofdev->dev, "waiting for firmware %s\n", + filename); + + /* + * We call request_firmware_nowait instead of + * request_firmware so that the driver can load and + * initialize the ports without holding up the rest of + * the kernel. If hotplug support is enabled in the + * kernel, then we use it. + */ + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, filename, &ofdev->dev, + &ofdev->dev, uart_firmware_cont); + if (ret) { + dev_err(&ofdev->dev, + "could not load firmware %s\n", + filename); + return ret; + } + } + } + + qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL); + if (!qe_port) { + dev_err(&ofdev->dev, "can't allocate QE port structure\n"); + return -ENOMEM; + } + + /* Search for IRQ and mapbase */ + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(&ofdev->dev, "missing 'reg' property in device tree\n"); + kfree(qe_port); + return ret; + } + if (!res.start) { + dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + qe_port->port.mapbase = res.start; + + /* Get the UCC number (device ID) */ + /* UCCs are numbered 1-7 */ + iprop = of_get_property(np, "device-id", NULL); + if (!iprop || (*iprop < 1) || (*iprop > UCC_MAX_NUM)) { + dev_err(&ofdev->dev, + "missing or invalid UCC specified in device tree\n"); + kfree(qe_port); + return -ENODEV; + } + qe_port->ucc_num = *iprop - 1; + + /* + * In the future, we should not require the BRG to be specified in the + * device tree. If no clock-source is specified, then just pick a BRG + * to use. This requires a new QE library function that manages BRG + * assignments. + */ + + sprop = of_get_property(np, "rx-clock-name", NULL); + if (!sprop) { + dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n"); + kfree(qe_port); + return -ENODEV; + } + + qe_port->us_info.rx_clock = qe_clock_source(sprop); + if ((qe_port->us_info.rx_clock < QE_BRG1) || + (qe_port->us_info.rx_clock > QE_BRG16)) { + dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n"); + kfree(qe_port); + return -ENODEV; + } + +#ifdef LOOPBACK + /* In internal loopback mode, TX and RX must use the same clock */ + qe_port->us_info.tx_clock = qe_port->us_info.rx_clock; +#else + sprop = of_get_property(np, "tx-clock-name", NULL); + if (!sprop) { + dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n"); + kfree(qe_port); + return -ENODEV; + } + qe_port->us_info.tx_clock = qe_clock_source(sprop); +#endif + if ((qe_port->us_info.tx_clock < QE_BRG1) || + (qe_port->us_info.tx_clock > QE_BRG16)) { + dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n"); + kfree(qe_port); + return -ENODEV; + } + + /* Get the port number, numbered 0-3 */ + iprop = of_get_property(np, "port-number", NULL); + if (!iprop) { + dev_err(&ofdev->dev, "missing port-number in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + qe_port->port.line = *iprop; + if (qe_port->port.line >= UCC_MAX_UART) { + dev_err(&ofdev->dev, "port-number must be 0-%u\n", + UCC_MAX_UART - 1); + kfree(qe_port); + return -EINVAL; + } + + qe_port->port.irq = irq_of_parse_and_map(np, 0); + if (qe_port->port.irq == NO_IRQ) { + dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", + qe_port->ucc_num + 1); + kfree(qe_port); + return -EINVAL; + } + + /* + * Newer device trees have an "fsl,qe" compatible property for the QE + * node, but we still need to support older device trees. + */ + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!np) { + np = of_find_node_by_type(NULL, "qe"); + if (!np) { + dev_err(&ofdev->dev, "could not find 'qe' node\n"); + kfree(qe_port); + return -EINVAL; + } + } + + iprop = of_get_property(np, "brg-frequency", NULL); + if (!iprop) { + dev_err(&ofdev->dev, + "missing brg-frequency in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + + if (*iprop) + qe_port->port.uartclk = *iprop; + else { + /* + * Older versions of U-Boot do not initialize the brg-frequency + * property, so in this case we assume the BRG frequency is + * half the QE bus frequency. + */ + iprop = of_get_property(np, "bus-frequency", NULL); + if (!iprop) { + dev_err(&ofdev->dev, + "missing QE bus-frequency in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + if (*iprop) + qe_port->port.uartclk = *iprop / 2; + else { + dev_err(&ofdev->dev, + "invalid QE bus-frequency in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + } + + spin_lock_init(&qe_port->port.lock); + qe_port->np = np; + qe_port->port.dev = &ofdev->dev; + qe_port->port.ops = &qe_uart_pops; + qe_port->port.iotype = UPIO_MEM; + + qe_port->tx_nrfifos = TX_NUM_FIFO; + qe_port->tx_fifosize = TX_BUF_SIZE; + qe_port->rx_nrfifos = RX_NUM_FIFO; + qe_port->rx_fifosize = RX_BUF_SIZE; + + qe_port->wait_closing = UCC_WAIT_CLOSING; + qe_port->port.fifosize = 512; + qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; + + qe_port->us_info.ucc_num = qe_port->ucc_num; + qe_port->us_info.regs = (phys_addr_t) res.start; + qe_port->us_info.irq = qe_port->port.irq; + + qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos; + qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos; + + /* Make sure ucc_slow_init() initializes both TX and RX */ + qe_port->us_info.init_tx = 1; + qe_port->us_info.init_rx = 1; + + /* Add the port to the uart sub-system. This will cause + * qe_uart_config_port() to be called, so the us_info structure must + * be initialized. + */ + ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port); + if (ret) { + dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n", + qe_port->port.line); + kfree(qe_port); + return ret; + } + + dev_set_drvdata(&ofdev->dev, qe_port); + + dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n", + qe_port->ucc_num + 1, qe_port->port.line); + + /* Display the mknod command for this device */ + dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n", + qe_port->port.line, SERIAL_QE_MAJOR, + SERIAL_QE_MINOR + qe_port->port.line); + + return 0; +} + +static int ucc_uart_remove(struct of_device *ofdev) +{ + struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev); + + dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line); + + uart_remove_one_port(&ucc_uart_driver, &qe_port->port); + + dev_set_drvdata(&ofdev->dev, NULL); + kfree(qe_port); + + return 0; +} + +static struct of_device_id ucc_uart_match[] = { + { + .type = "serial", + .compatible = "ucc_uart", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ucc_uart_match); + +static struct of_platform_driver ucc_uart_of_driver = { + .owner = THIS_MODULE, + .name = "ucc_uart", + .match_table = ucc_uart_match, + .probe = ucc_uart_probe, + .remove = ucc_uart_remove, +}; + +static int __init ucc_uart_init(void) +{ + int ret; + + printk(KERN_INFO "Freescale QUICC Engine UART device driver\n"); +#ifdef LOOPBACK + printk(KERN_INFO "ucc-uart: Using loopback mode\n"); +#endif + + ret = uart_register_driver(&ucc_uart_driver); + if (ret) { + printk(KERN_ERR "ucc-uart: could not register UART driver\n"); + return ret; + } + + ret = of_register_platform_driver(&ucc_uart_of_driver); + if (ret) + printk(KERN_ERR + "ucc-uart: could not register platform driver\n"); + + return ret; +} + +static void __exit ucc_uart_exit(void) +{ + printk(KERN_INFO + "Freescale QUICC Engine UART device driver unloading\n"); + + of_unregister_platform_driver(&ucc_uart_of_driver); + uart_unregister_driver(&ucc_uart_driver); +} + +module_init(ucc_uart_init); +module_exit(ucc_uart_exit); + +MODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART"); +MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR); + |