diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-03-08 20:21:04 +0000 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-03-08 20:21:04 +0000 |
commit | 988addf82e4c03739375279de73929580a2d4a6a (patch) | |
tree | 989ae1cd4e264bbad80c65f04480486246e7b9f3 /drivers/serial | |
parent | 004c1c7096659d352b83047a7593e91d8a30e3c5 (diff) | |
parent | 25cf84cf377c0aae5dbcf937ea89bc7893db5176 (diff) |
Merge branch 'origin' into devel-stable
Conflicts:
arch/arm/mach-mx2/devices.c
arch/arm/mach-mx2/devices.h
sound/soc/pxa/pxa-ssp.c
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/68328serial.c | 8 | ||||
-rw-r--r-- | drivers/serial/8250.c | 36 | ||||
-rw-r--r-- | drivers/serial/8250_pci.c | 31 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 69 | ||||
-rw-r--r-- | drivers/serial/amba-pl011.c | 19 | ||||
-rw-r--r-- | drivers/serial/atmel_serial.c | 22 | ||||
-rw-r--r-- | drivers/serial/bcm63xx_uart.c | 7 | ||||
-rw-r--r-- | drivers/serial/bfin_5xx.c | 22 | ||||
-rw-r--r-- | drivers/serial/bfin_sport_uart.c | 701 | ||||
-rw-r--r-- | drivers/serial/bfin_sport_uart.h | 38 | ||||
-rw-r--r-- | drivers/serial/icom.c | 5 | ||||
-rw-r--r-- | drivers/serial/imx.c | 6 | ||||
-rw-r--r-- | drivers/serial/ioc3_serial.c | 3 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_driver.c | 1 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_tty.c | 9 | ||||
-rw-r--r-- | drivers/serial/mpc52xx_uart.c | 251 | ||||
-rw-r--r-- | drivers/serial/msm_serial.c | 6 | ||||
-rw-r--r-- | drivers/serial/pmac_zilog.c | 246 | ||||
-rw-r--r-- | drivers/serial/pmac_zilog.h | 34 | ||||
-rw-r--r-- | drivers/serial/serial_cs.c | 7 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 616 | ||||
-rw-r--r-- | drivers/serial/timbuart.c | 7 |
22 files changed, 1664 insertions, 480 deletions
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index d935b2d04f9..ae0251ef6f4 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -153,8 +153,6 @@ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0 }; -#define BAUD_TABLE_SIZE (sizeof(baud_table)/sizeof(baud_table[0])) - /* Sets or clears DTR/RTS on the requested line */ static inline void m68k_rtsdtr(struct m68k_serial *ss, int set) { @@ -1406,10 +1404,10 @@ static void m68328_set_baud(void) USTCNT = ustcnt & ~USTCNT_TXEN; again: - for (i = 0; i < sizeof(baud_table) / sizeof(baud_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(baud_table); i++) if (baud_table[i] == m68328_console_baud) break; - if (i >= sizeof(baud_table) / sizeof(baud_table[0])) { + if (i >= ARRAY_SIZE(baud_table)) { m68328_console_baud = 9600; goto again; } @@ -1435,7 +1433,7 @@ int m68328_console_setup(struct console *cp, char *arg) if (arg) n = simple_strtoul(arg,NULL,0); - for (i = 0; i < BAUD_TABLE_SIZE; i++) + for (i = 0; i < ARRAY_SIZE(baud_table); i++) if (baud_table[i] == n) break; if (i < BAUD_TABLE_SIZE) { diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index e9b15c3746f..7c4ebe6ee18 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1217,12 +1217,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) } #endif -#ifdef CONFIG_SERIAL_8250_AU1X00 - /* if access method is AU, it is a 16550 with a quirk */ - if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) - up->bugs |= UART_BUG_NOMSR; -#endif - serial_outp(up, UART_LCR, save_lcr); if (up->capabilities != uart_config[up->port.type].flags) { @@ -2428,7 +2422,7 @@ serial8250_pm(struct uart_port *port, unsigned int state, static unsigned int serial8250_port_size(struct uart_8250_port *pt) { if (pt->port.iotype == UPIO_AU) - return 0x100000; + return 0x1000; #ifdef CONFIG_ARCH_OMAP if (is_omap_port(pt)) return 0x16 << pt->port.regshift; @@ -2585,6 +2579,13 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (flags & UART_CONFIG_TYPE) autoconfig(up, probeflags); + +#ifdef CONFIG_SERIAL_8250_AU1X00 + /* if access method is AU, it is a 16550 with a quirk */ + if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) + up->bugs |= UART_BUG_NOMSR; +#endif + if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) autoconfig_irq(up); @@ -2689,6 +2690,15 @@ static void __init serial8250_isa_init_ports(void) } } +static void +serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) +{ + up->port.type = type; + up->port.fifosize = uart_config[type].fifo_size; + up->capabilities = uart_config[type].flags; + up->tx_loadsz = uart_config[type].tx_loadsz; +} + static void __init serial8250_register_ports(struct uart_driver *drv, struct device *dev) { @@ -2705,6 +2715,10 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) struct uart_8250_port *up = &serial8250_ports[i]; up->port.dev = dev; + + if (up->port.flags & UPF_FIXED_TYPE) + serial8250_init_fixed_type_port(up, up->port.type); + uart_add_one_port(drv, &up->port); } } @@ -3117,12 +3131,8 @@ int serial8250_register_port(struct uart_port *port) if (port->dev) uart->port.dev = port->dev; - if (port->flags & UPF_FIXED_TYPE) { - uart->port.type = port->type; - uart->port.fifosize = uart_config[port->type].fifo_size; - uart->capabilities = uart_config[port->type].flags; - uart->tx_loadsz = uart_config[port->type].tx_loadsz; - } + if (port->flags & UPF_FIXED_TYPE) + serial8250_init_fixed_type_port(uart, port->type); set_io_from_upio(&uart->port); /* Possibly override default I/O functions. */ diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index b28af13c45a..01c012da4e2 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -760,7 +760,8 @@ static int pci_netmos_init(struct pci_dev *dev) /* subdevice 0x00PS means <P> parallel, <S> serial */ unsigned int num_serial = dev->subsystem_device & 0xf; - if (dev->device == PCI_DEVICE_ID_NETMOS_9901) + if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) || + (dev->device == PCI_DEVICE_ID_NETMOS_9865)) return 0; if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && dev->subsystem_device == 0x0299) @@ -1479,6 +1480,7 @@ enum pci_board_num_t { pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, + pbn_b0_bt_4_115200, pbn_b0_bt_8_115200, pbn_b0_bt_1_460800, @@ -1703,6 +1705,12 @@ static struct pciserial_board pci_boards[] __devinitdata = { .base_baud = 115200, .uart_offset = 8, }, + [pbn_b0_bt_4_115200] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, [pbn_b0_bt_8_115200] = { .flags = FL_BASE0|FL_BASE_BARS, .num_ports = 8, @@ -3191,6 +3199,15 @@ static struct pci_device_id serial_pci_tbl[] = { 0x1208, 0x0004, 0, 0, pbn_b0_4_921600 }, + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2, + 0x1204, 0x0004, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2, + 0x1208, 0x0004, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3, + 0x1208, 0x0004, 0, 0, + pbn_b0_4_921600 }, /* * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com */ @@ -3649,6 +3666,18 @@ static struct pci_device_id serial_pci_tbl[] = { 0, 0, pbn_b0_1_115200 }, /* + * Best Connectivity PCI Multi I/O cards + */ + + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, + 0xA000, 0x1000, + 0, 0, pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, + 0xA000, 0x3004, + 0, 0, pbn_b0_bt_4_115200 }, + + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5351848cfff..f55c49475a8 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1026,6 +1026,10 @@ config SERIAL_SH_SCI_CONSOLE depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE +config SERIAL_SH_SCI_DMA + bool "DMA support" + depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL + config SERIAL_PNX8XXX bool "Enable PNX8XXX SoCs' UART Support" depends on MIPS && (SOC_PNX8550 || SOC_PNX833X) @@ -1103,12 +1107,12 @@ config SERIAL_68360 default y config SERIAL_PMACZILOG - tristate "PowerMac z85c30 ESCC support" - depends on PPC_OF && PPC_PMAC + tristate "Mac or PowerMac z85c30 ESCC support" + depends on (M68K && MAC) || (PPC_OF && PPC_PMAC) select SERIAL_CORE help This driver supports the Zilog z85C30 serial ports found on - PowerMac machines. + (Power)Mac machines. Say Y or M if you want to be able to these serial ports. config SERIAL_PMACZILOG_TTYS @@ -1133,16 +1137,16 @@ config SERIAL_PMACZILOG_TTYS unable to use the 8250 module for PCMCIA or other 16C550-style UARTs. - Say N unless you need the z85c30 ports on your powermac + Say N unless you need the z85c30 ports on your (Power)Mac to appear as /dev/ttySn. config SERIAL_PMACZILOG_CONSOLE - bool "Console on PowerMac z85c30 serial port" + bool "Console on Mac or PowerMac z85c30 serial port" depends on SERIAL_PMACZILOG=y select SERIAL_CORE_CONSOLE help If you would like to be able to use the z85c30 serial port - on your PowerMac as the console, you can do so by answering + on your (Power)Mac as the console, you can do so by answering Y to this option. config SERIAL_LH7A40X @@ -1435,42 +1439,37 @@ config SERIAL_BFIN_SPORT To compile this driver as a module, choose M here: the module will be called bfin_sport_uart. -choice - prompt "Baud rate for Blackfin SPORT UART" - depends on SERIAL_BFIN_SPORT - default SERIAL_SPORT_BAUD_RATE_57600 - help - Choose a baud rate for the SPORT UART, other uart settings are - 8 bit, 1 stop bit, no parity, no flow control. - -config SERIAL_SPORT_BAUD_RATE_115200 - bool "115200" - -config SERIAL_SPORT_BAUD_RATE_57600 - bool "57600" +config SERIAL_BFIN_SPORT_CONSOLE + bool "Console on Blackfin sport emulated uart" + depends on SERIAL_BFIN_SPORT=y + select SERIAL_CORE_CONSOLE -config SERIAL_SPORT_BAUD_RATE_38400 - bool "38400" +config SERIAL_BFIN_SPORT0_UART + bool "Enable UART over SPORT0" + depends on SERIAL_BFIN_SPORT && !(BF542 || BF542M || BF544 || BF544M) + help + Enable UART over SPORT0 -config SERIAL_SPORT_BAUD_RATE_19200 - bool "19200" +config SERIAL_BFIN_SPORT1_UART + bool "Enable UART over SPORT1" + depends on SERIAL_BFIN_SPORT + help + Enable UART over SPORT1 -config SERIAL_SPORT_BAUD_RATE_9600 - bool "9600" -endchoice +config SERIAL_BFIN_SPORT2_UART + bool "Enable UART over SPORT2" + depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) + help + Enable UART over SPORT2 -config SPORT_BAUD_RATE - int - depends on SERIAL_BFIN_SPORT - default 115200 if (SERIAL_SPORT_BAUD_RATE_115200) - default 57600 if (SERIAL_SPORT_BAUD_RATE_57600) - default 38400 if (SERIAL_SPORT_BAUD_RATE_38400) - default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) - default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) +config SERIAL_BFIN_SPORT3_UART + bool "Enable UART over SPORT3" + depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) + help + Enable UART over SPORT3 config SERIAL_TIMBERDALE tristate "Support for timberdale UART" - depends on MFD_TIMBERDALE select SERIAL_CORE ---help--- Add support for UART controller on timberdale. diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index ef7adc8135d..ce6c35333ff 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -71,6 +71,7 @@ struct uart_amba_port { unsigned int im; /* interrupt mask */ unsigned int old_status; unsigned int ifls; /* vendor-specific */ + bool autorts; }; /* There is by now at least one vendor with differing details, so handle it */ @@ -308,6 +309,11 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1); TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2); TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE); + + if (uap->autorts) { + /* We need to disable auto-RTS if we want to turn RTS off */ + TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN); + } #undef TIOCMBIT writew(cr, uap->port.membase + UART011_CR); @@ -437,6 +443,7 @@ static void pl011_shutdown(struct uart_port *port) /* * disable the port */ + uap->autorts = false; writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR); /* @@ -456,6 +463,7 @@ static void pl011_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot; @@ -532,6 +540,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, old_cr = readw(port->membase + UART011_CR); writew(0, port->membase + UART011_CR); + if (termios->c_cflag & CRTSCTS) { + if (old_cr & UART011_CR_RTS) + old_cr |= UART011_CR_RTSEN; + + old_cr |= UART011_CR_CTSEN; + uap->autorts = true; + } else { + old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN); + uap->autorts = false; + } + /* Set baud rate */ writew(quot & 0x3f, port->membase + UART011_FBRD); writew(quot >> 6, port->membase + UART011_IBRD); diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 9d948bccafa..2c9bf9b6832 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -1213,6 +1213,24 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) return ret; } +#ifdef CONFIG_CONSOLE_POLL +static int atmel_poll_get_char(struct uart_port *port) +{ + while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY)) + cpu_relax(); + + return UART_GET_CHAR(port); +} + +static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) +{ + while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + cpu_relax(); + + UART_PUT_CHAR(port, ch); +} +#endif + static struct uart_ops atmel_pops = { .tx_empty = atmel_tx_empty, .set_mctrl = atmel_set_mctrl, @@ -1232,6 +1250,10 @@ static struct uart_ops atmel_pops = { .config_port = atmel_config_port, .verify_port = atmel_verify_port, .pm = atmel_serial_pm, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = atmel_poll_get_char, + .poll_put_char = atmel_poll_put_char, +#endif }; /* diff --git a/drivers/serial/bcm63xx_uart.c b/drivers/serial/bcm63xx_uart.c index 37ad0c44993..a1a0e55d080 100644 --- a/drivers/serial/bcm63xx_uart.c +++ b/drivers/serial/bcm63xx_uart.c @@ -35,7 +35,7 @@ #include <bcm63xx_regs.h> #include <bcm63xx_io.h> -#define BCM63XX_NR_UARTS 1 +#define BCM63XX_NR_UARTS 2 static struct uart_port ports[BCM63XX_NR_UARTS]; @@ -784,7 +784,7 @@ static struct uart_driver bcm_uart_driver = { .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, - .nr = 1, + .nr = BCM63XX_NR_UARTS, .cons = BCM63XX_CONSOLE, }; @@ -826,11 +826,12 @@ static int __devinit bcm_uart_probe(struct platform_device *pdev) port->dev = &pdev->dev; port->fifosize = 16; port->uartclk = clk_get_rate(clk) / 2; + port->line = pdev->id; clk_put(clk); ret = uart_add_one_port(&bcm_uart_driver, port); if (ret) { - kfree(port); + ports[pdev->id].membase = 0; return ret; } platform_set_drvdata(pdev, port); diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 50abb7e557f..fcf273e3f48 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/ioport.h> +#include <linux/io.h> #include <linux/init.h> #include <linux/console.h> #include <linux/sysrq.h> @@ -237,7 +238,8 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) #if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - if (kgdb_connected && kgdboc_port_line == uart->port.line) + if (kgdb_connected && kgdboc_port_line == uart->port.line + && kgdboc_break_enabled) if (ch == 0x3) {/* Ctrl + C */ kgdb_breakpoint(); return; @@ -488,6 +490,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { int x_pos, pos; + dma_disable_irq(uart->tx_dma_channel); dma_disable_irq(uart->rx_dma_channel); spin_lock_bh(&uart->port.lock); @@ -521,6 +524,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) } spin_unlock_bh(&uart->port.lock); + dma_enable_irq(uart->tx_dma_channel); dma_enable_irq(uart->rx_dma_channel); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); @@ -746,15 +750,6 @@ static int bfin_serial_startup(struct uart_port *port) Status interrupt.\n"); } - if (uart->cts_pin >= 0) { - gpio_request(uart->cts_pin, DRIVER_NAME); - gpio_direction_output(uart->cts_pin, 1); - } - if (uart->rts_pin >= 0) { - gpio_request(uart->rts_pin, DRIVER_NAME); - gpio_direction_output(uart->rts_pin, 0); - } - /* CTS RTS PINs are negative assertive. */ UART_PUT_MCR(uart, ACTS); UART_SET_IER(uart, EDSSI); @@ -801,10 +796,6 @@ static void bfin_serial_shutdown(struct uart_port *port) gpio_free(uart->rts_pin); #endif #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (uart->cts_pin >= 0) - gpio_free(uart->cts_pin); - if (uart->rts_pin >= 0) - gpio_free(uart->rts_pin); if (UART_GET_IER(uart) && EDSSI) free_irq(uart->status_irq, uart); #endif @@ -1409,8 +1400,7 @@ static int bfin_serial_remove(struct platform_device *dev) continue; uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); bfin_serial_ports[i].port.dev = NULL; -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) gpio_free(bfin_serial_ports[i].cts_pin); gpio_free(bfin_serial_ports[i].rts_pin); #endif diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index 088bb35475f..7c72888fbf9 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c @@ -1,27 +1,11 @@ /* - * File: linux/drivers/serial/bfin_sport_uart.c + * Blackfin On-Chip Sport Emulated UART Driver * - * Based on: drivers/serial/bfin_5xx.c by Aubrey Li. - * Author: Roy Huang <roy.huang@analog.com> + * Copyright 2006-2009 Analog Devices Inc. * - * Created: Nov 22, 2006 - * Copyright: (c) 2006-2007 Analog Devices Inc. - * Description: this driver enable SPORTs on Blackfin emulate UART. + * Enter bugs at http://blackfin.uclinux.org/ * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Licensed under the GPL-2 or later. */ /* @@ -29,39 +13,18 @@ * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf * This application note describe how to implement a UART on a Sharc DSP, * but this driver is implemented on Blackfin Processor. + * Transmit Frame Sync is not used by this driver to transfer data out. */ -/* After reset, there is a prelude of low level pulse when transmit data first - * time. No addtional pulse in following transmit. - * According to document: - * The SPORTs are ready to start transmitting or receiving data no later than - * three serial clock cycles after they are enabled in the SPORTx_TCR1 or - * SPORTx_RCR1 register. No serial clock cycles are lost from this point on. - * The first internal frame sync will occur one frame sync delay after the - * SPORTs are ready. External frame syncs can occur as soon as the SPORT is - * ready. - */ +/* #define DEBUG */ -/* Thanks to Axel Alatalo <axel@rubico.se> for fixing sport rx bug. Sometimes - * sport receives data incorrectly. The following is Axel's words. - * As EE-191, sport rx samples 3 times of the UART baudrate and takes the - * middle smaple of every 3 samples as the data bit. For a 8-N-1 UART setting, - * 30 samples will be required for a byte. If transmitter sends a 1/3 bit short - * byte due to buadrate drift, then the 30th sample of a byte, this sample is - * also the third sample of the stop bit, will happens on the immediately - * following start bit which will be thrown away and missed. Thus since parts - * of the startbit will be missed and the receiver will begin to drift, the - * effect accumulates over time until synchronization is lost. - * If only require 2 samples of the stopbit (by sampling in total 29 samples), - * then a to short byte as in the case above will be tolerated. Then the 1/3 - * early startbit will trigger a framesync since the last read is complete - * after only 2/3 stopbit and framesync is active during the last 1/3 looking - * for a possible early startbit. */ - -//#define DEBUG +#define DRV_NAME "bfin-sport-uart" +#define DEVICE_NAME "ttySS" +#define pr_fmt(fmt) DRV_NAME ": " fmt #include <linux/module.h> #include <linux/ioport.h> +#include <linux/io.h> #include <linux/init.h> #include <linux/console.h> #include <linux/sysrq.h> @@ -75,23 +38,36 @@ #include "bfin_sport_uart.h" +#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART unsigned short bfin_uart_pin_req_sport0[] = {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \ P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0}; - +#endif +#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART unsigned short bfin_uart_pin_req_sport1[] = {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \ P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0}; - -#define DRV_NAME "bfin-sport-uart" +#endif +#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART +unsigned short bfin_uart_pin_req_sport2[] = + {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS, \ + P_SPORT2_DRPRI, P_SPORT2_RSCLK, P_SPORT2_DRSEC, P_SPORT2_DTSEC, 0}; +#endif +#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART +unsigned short bfin_uart_pin_req_sport3[] = + {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS, \ + P_SPORT3_DRPRI, P_SPORT3_RSCLK, P_SPORT3_DRSEC, P_SPORT3_DTSEC, 0}; +#endif struct sport_uart_port { struct uart_port port; - char *name; - - int tx_irq; - int rx_irq; int err_irq; + unsigned short csize; + unsigned short rxmask; + unsigned short txmask1; + unsigned short txmask2; + unsigned char stopb; +/* unsigned char parib; */ }; static void sport_uart_tx_chars(struct sport_uart_port *up); @@ -99,36 +75,42 @@ static void sport_stop_tx(struct uart_port *port); static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) { - pr_debug("%s value:%x\n", __func__, value); - /* Place a Start and Stop bit */ + pr_debug("%s value:%x, mask1=0x%x, mask2=0x%x\n", __func__, value, + up->txmask1, up->txmask2); + + /* Place Start and Stop bits */ __asm__ __volatile__ ( - "R2 = b#01111111100;" - "R3 = b#10000000001;" - "%0 <<= 2;" - "%0 = %0 & R2;" - "%0 = %0 | R3;" - : "=d"(value) - : "d"(value) - : "ASTAT", "R2", "R3" + "%[val] <<= 1;" + "%[val] = %[val] & %[mask1];" + "%[val] = %[val] | %[mask2];" + : [val]"+d"(value) + : [mask1]"d"(up->txmask1), [mask2]"d"(up->txmask2) + : "ASTAT" ); pr_debug("%s value:%x\n", __func__, value); SPORT_PUT_TX(up, value); } -static inline unsigned int rx_one_byte(struct sport_uart_port *up) +static inline unsigned char rx_one_byte(struct sport_uart_port *up) { - unsigned int value, extract; + unsigned int value; + unsigned char extract; u32 tmp_mask1, tmp_mask2, tmp_shift, tmp; - value = SPORT_GET_RX32(up); - pr_debug("%s value:%x\n", __func__, value); + if ((up->csize + up->stopb) > 7) + value = SPORT_GET_RX32(up); + else + value = SPORT_GET_RX(up); + + pr_debug("%s value:%x, cs=%d, mask=0x%x\n", __func__, value, + up->csize, up->rxmask); - /* Extract 8 bits data */ + /* Extract data */ __asm__ __volatile__ ( "%[extr] = 0;" - "%[mask1] = 0x1801(Z);" - "%[mask2] = 0x0300(Z);" + "%[mask1] = %[rxmask];" + "%[mask2] = 0x0200(Z);" "%[shift] = 0;" "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];" ".Lloop_s:" @@ -138,9 +120,9 @@ static inline unsigned int rx_one_byte(struct sport_uart_port *up) "%[mask1] = %[mask1] - %[mask2];" ".Lloop_e:" "%[shift] += 1;" - : [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp), - [mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2) - : "d"(value), [lc]"a"(8) + : [extr]"=&d"(extract), [shift]"=&d"(tmp_shift), [tmp]"=&d"(tmp), + [mask1]"=&d"(tmp_mask1), [mask2]"=&d"(tmp_mask2) + : [val]"d"(value), [rxmask]"d"(up->rxmask), [lc]"a"(up->csize) : "ASTAT", "LB0", "LC0", "LT0" ); @@ -148,29 +130,28 @@ static inline unsigned int rx_one_byte(struct sport_uart_port *up) return extract; } -static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) +static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate) { - int tclkdiv, tfsdiv, rclkdiv; + int tclkdiv, rclkdiv; + unsigned int sclk = get_sclk(); - /* Set TCR1 and TCR2 */ - SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK)); - SPORT_PUT_TCR2(up, 10); + /* Set TCR1 and TCR2, TFSR is not enabled for uart */ + SPORT_PUT_TCR1(up, (ITFS | TLSBIT | ITCLK)); + SPORT_PUT_TCR2(up, size + 1); pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); /* Set RCR1 and RCR2 */ SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK)); - SPORT_PUT_RCR2(up, 28); + SPORT_PUT_RCR2(up, (size + 1) * 2 - 1); pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up)); - tclkdiv = sclk/(2 * baud_rate) - 1; - tfsdiv = 12; - rclkdiv = sclk/(2 * baud_rate * 3) - 1; + tclkdiv = sclk / (2 * baud_rate) - 1; + rclkdiv = sclk / (2 * baud_rate * 2) - 1; SPORT_PUT_TCLKDIV(up, tclkdiv); - SPORT_PUT_TFSDIV(up, tfsdiv); SPORT_PUT_RCLKDIV(up, rclkdiv); SSYNC(); - pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n", - __func__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv); + pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, rclkdiv:%d\n", + __func__, sclk, baud_rate, tclkdiv, rclkdiv); return 0; } @@ -181,23 +162,29 @@ static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id) struct tty_struct *tty = up->port.state->port.tty; unsigned int ch; - do { + spin_lock(&up->port.lock); + + while (SPORT_GET_STAT(up) & RXNE) { ch = rx_one_byte(up); up->port.icount.rx++; - if (uart_handle_sysrq_char(&up->port, ch)) - ; - else + if (!uart_handle_sysrq_char(&up->port, ch)) tty_insert_flip_char(tty, ch, TTY_NORMAL); - } while (SPORT_GET_STAT(up) & RXNE); + } tty_flip_buffer_push(tty); + spin_unlock(&up->port.lock); + return IRQ_HANDLED; } static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id) { - sport_uart_tx_chars(dev_id); + struct sport_uart_port *up = dev_id; + + spin_lock(&up->port.lock); + sport_uart_tx_chars(up); + spin_unlock(&up->port.lock); return IRQ_HANDLED; } @@ -208,6 +195,8 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) struct tty_struct *tty = up->port.state->port.tty; unsigned int stat = SPORT_GET_STAT(up); + spin_lock(&up->port.lock); + /* Overflow in RX FIFO */ if (stat & ROVF) { up->port.icount.overrun++; @@ -216,15 +205,16 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) } /* These should not happen */ if (stat & (TOVF | TUVF | RUVF)) { - printk(KERN_ERR "SPORT Error:%s %s %s\n", - (stat & TOVF)?"TX overflow":"", - (stat & TUVF)?"TX underflow":"", - (stat & RUVF)?"RX underflow":""); + pr_err("SPORT Error:%s %s %s\n", + (stat & TOVF) ? "TX overflow" : "", + (stat & TUVF) ? "TX underflow" : "", + (stat & RUVF) ? "RX underflow" : ""); SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN); } SSYNC(); + spin_unlock(&up->port.lock); return IRQ_HANDLED; } @@ -232,60 +222,37 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) static int sport_startup(struct uart_port *port) { struct sport_uart_port *up = (struct sport_uart_port *)port; - char buffer[20]; - int retval; + int ret; pr_debug("%s enter\n", __func__); - snprintf(buffer, 20, "%s rx", up->name); - retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up); - if (retval) { - printk(KERN_ERR "Unable to request interrupt %s\n", buffer); - return retval; + ret = request_irq(up->port.irq, sport_uart_rx_irq, 0, + "SPORT_UART_RX", up); + if (ret) { + dev_err(port->dev, "unable to request SPORT RX interrupt\n"); + return ret; } - snprintf(buffer, 20, "%s tx", up->name); - retval = request_irq(up->tx_irq, sport_uart_tx_irq, IRQF_SAMPLE_RANDOM, buffer, up); - if (retval) { - printk(KERN_ERR "Unable to request interrupt %s\n", buffer); + ret = request_irq(up->port.irq+1, sport_uart_tx_irq, 0, + "SPORT_UART_TX", up); + if (ret) { + dev_err(port->dev, "unable to request SPORT TX interrupt\n"); goto fail1; } - snprintf(buffer, 20, "%s err", up->name); - retval = request_irq(up->err_irq, sport_uart_err_irq, IRQF_SAMPLE_RANDOM, buffer, up); - if (retval) { - printk(KERN_ERR "Unable to request interrupt %s\n", buffer); + ret = request_irq(up->err_irq, sport_uart_err_irq, 0, + "SPORT_UART_STATUS", up); + if (ret) { + dev_err(port->dev, "unable to request SPORT status interrupt\n"); goto fail2; } - if (port->line) { - if (peripheral_request_list(bfin_uart_pin_req_sport1, DRV_NAME)) - g |