diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/Kconfig | 51 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/bfin_5xx.c | 282 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_core.c | 14 | ||||
-rw-r--r-- | drivers/serial/crisv10.c | 79 | ||||
-rw-r--r-- | drivers/serial/crisv10.h | 2 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_neo.c | 14 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_tty.c | 19 | ||||
-rw-r--r-- | drivers/serial/max3100.c | 927 | ||||
-rw-r--r-- | drivers/serial/pmac_zilog.c | 15 | ||||
-rw-r--r-- | drivers/serial/samsung.c | 4 | ||||
-rw-r--r-- | drivers/serial/sunsu.c | 2 |
12 files changed, 1250 insertions, 160 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 07c03b9eb126..343e3a35b6a3 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -533,6 +533,13 @@ config SERIAL_S3C6400 Serial port support for the Samsung S3C6400 and S3C6410 SoCs +config SERIAL_MAX3100 + tristate "MAX3100 support" + depends on SPI + select SERIAL_CORE + help + MAX3100 chip support + config SERIAL_DZ bool "DECstation DZ serial driver" depends on MACH_DECSTATION && 32BIT @@ -700,7 +707,7 @@ choice config SERIAL_BFIN_DMA bool "DMA mode" - depends on !DMA_UNCACHED_NONE && !KGDB_UART + depends on !DMA_UNCACHED_NONE && KGDB_SERIAL_CONSOLE=n help This driver works under DMA mode. If this option is selected, the blackfin simple dma driver is also enabled. @@ -727,19 +734,19 @@ config BFIN_UART0_CTSRTS config UART0_CTS_PIN int "UART0 CTS pin" - depends on BFIN_UART0_CTSRTS + depends on BFIN_UART0_CTSRTS && !BF548 default 23 help The default pin is GPIO_GP7. - Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. config UART0_RTS_PIN int "UART0 RTS pin" - depends on BFIN_UART0_CTSRTS + depends on BFIN_UART0_CTSRTS && !BF548 default 22 help The default pin is GPIO_GP6. - Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. config SERIAL_BFIN_UART1 bool "Enable UART1" @@ -756,17 +763,17 @@ config BFIN_UART1_CTSRTS config UART1_CTS_PIN int "UART1 CTS pin" - depends on BFIN_UART1_CTSRTS && !BF54x + depends on BFIN_UART1_CTSRTS && !BF548 default -1 help - Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. config UART1_RTS_PIN int "UART1 RTS pin" - depends on BFIN_UART1_CTSRTS && !BF54x + depends on BFIN_UART1_CTSRTS && !BF548 default -1 help - Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. config SERIAL_BFIN_UART2 bool "Enable UART2" @@ -783,17 +790,17 @@ config BFIN_UART2_CTSRTS config UART2_CTS_PIN int "UART2 CTS pin" - depends on BFIN_UART2_CTSRTS + depends on BFIN_UART2_CTSRTS && !BF548 default -1 help - Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. config UART2_RTS_PIN int "UART2 RTS pin" - depends on BFIN_UART2_CTSRTS + depends on BFIN_UART2_CTSRTS && !BF548 default -1 help - Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. config SERIAL_BFIN_UART3 bool "Enable UART3" @@ -808,6 +815,20 @@ config BFIN_UART3_CTSRTS Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS signal. +config UART3_CTS_PIN + int "UART3 CTS pin" + depends on BFIN_UART3_CTSRTS && !BF548 + default -1 + help + Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. + +config UART3_RTS_PIN + int "UART3 RTS pin" + depends on BFIN_UART3_CTSRTS && !BF548 + default -1 + help + Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. + config SERIAL_IMX bool "IMX serial port support" depends on ARM && (ARCH_IMX || ARCH_MXC) @@ -833,7 +854,7 @@ config SERIAL_IMX_CONSOLE config SERIAL_UARTLITE tristate "Xilinx uartlite serial port support" - depends on PPC32 + depends on PPC32 || MICROBLAZE select SERIAL_CORE help Say Y here if you want to use the Xilinx uartlite serial controller. @@ -1319,7 +1340,7 @@ config SERIAL_NETX_CONSOLE config SERIAL_OF_PLATFORM tristate "Serial port on Open Firmware platform bus" - depends on PPC_OF + depends on PPC_OF || MICROBLAZE depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL help If you have a PowerPC based system that has serial ports diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 8844c0a03929..d438eb2a73de 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o +obj-$(CONFIG_SERIAL_MAX3100) += max3100.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index f9b5a72e261a..d86123e03391 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -63,7 +63,6 @@ static int kgdboc_break_enabled; #define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT) #define DMA_RX_FLUSH_JIFFIES (HZ / 50) -#define CTS_CHECK_JIFFIES (HZ / 50) #ifdef CONFIG_SERIAL_BFIN_DMA static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart); @@ -71,10 +70,65 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart); static void bfin_serial_tx_chars(struct bfin_serial_port *uart); #endif -static void bfin_serial_mctrl_check(struct bfin_serial_port *uart); - static void bfin_serial_reset_irda(struct uart_port *port); +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +static unsigned int bfin_serial_get_mctrl(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + if (uart->cts_pin < 0) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + /* CTS PIN is negative assertive. */ + if (UART_GET_CTS(uart)) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + else + return TIOCM_DSR | TIOCM_CAR; +} + +static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + if (uart->rts_pin < 0) + return; + + /* RTS PIN is negative assertive. */ + if (mctrl & TIOCM_RTS) + UART_ENABLE_RTS(uart); + else + UART_DISABLE_RTS(uart); +} + +/* + * Handle any change of modem status signal. + */ +static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + unsigned int status; + + status = bfin_serial_get_mctrl(&uart->port); + uart_handle_cts_change(&uart->port, status & TIOCM_CTS); +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + uart->scts = 1; + UART_CLEAR_SCTS(uart); + UART_CLEAR_IER(uart, EDSSI); +#endif + + return IRQ_HANDLED; +} +#else +static unsigned int bfin_serial_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} +#endif + /* * interrupts are disabled on entry */ @@ -111,6 +165,13 @@ static void bfin_serial_start_tx(struct uart_port *port) struct bfin_serial_port *uart = (struct bfin_serial_port *)port; struct tty_struct *tty = uart->port.info->port.tty; +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif + /* * To avoid losting RX interrupt, we reset IR function * before sending data. @@ -264,12 +325,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) { struct circ_buf *xmit = &uart->port.info->xmit; - /* - * Check the modem control lines before - * transmitting anything. - */ - bfin_serial_mctrl_check(uart); - if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { #ifdef CONFIG_BF54x /* Clear TFI bit */ @@ -312,6 +367,12 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif spin_lock(&uart->port.lock); if (UART_GET_LSR(uart) & THRE) bfin_serial_tx_chars(uart); @@ -328,12 +389,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) uart->tx_done = 0; - /* - * Check the modem control lines before - * transmitting anything. - */ - bfin_serial_mctrl_check(uart); - if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { uart->tx_count = 0; uart->tx_done = 1; @@ -448,6 +503,13 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) struct bfin_serial_port *uart = dev_id; struct circ_buf *xmit = &uart->port.info->xmit; +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif + spin_lock(&uart->port.lock); if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { disable_dma(uart->tx_dma_channel); @@ -496,61 +558,6 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port) return 0; } -static unsigned int bfin_serial_get_mctrl(struct uart_port *port) -{ -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - if (uart->cts_pin < 0) - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - - if (UART_GET_CTS(uart)) - return TIOCM_DSR | TIOCM_CAR; - else -#endif - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -} - -static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - if (uart->rts_pin < 0) - return; - - if (mctrl & TIOCM_RTS) - UART_CLEAR_RTS(uart); - else - UART_SET_RTS(uart); -#endif -} - -/* - * Handle any change of modem status signal since we were last called. - */ -static void bfin_serial_mctrl_check(struct bfin_serial_port *uart) -{ -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - unsigned int status; - struct uart_info *info = uart->port.info; - struct tty_struct *tty = info->port.tty; - - status = bfin_serial_get_mctrl(&uart->port); - uart_handle_cts_change(&uart->port, status & TIOCM_CTS); - if (!(status & TIOCM_CTS)) { - tty->hw_stopped = 1; - uart->cts_timer.data = (unsigned long)(uart); - uart->cts_timer.function = (void *)bfin_serial_mctrl_check; - uart->cts_timer.expires = jiffies + CTS_CHECK_JIFFIES; - add_timer(&(uart->cts_timer)); - } else { - tty->hw_stopped = 0; - } -#endif -} - -/* - * Interrupts are always disabled. - */ static void bfin_serial_break_ctl(struct uart_port *port, int break_state) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; @@ -606,7 +613,7 @@ static int bfin_serial_startup(struct uart_port *port) uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; add_timer(&(uart->rx_dma_timer)); #else -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ +# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled) kgdboc_break_enabled = 0; @@ -661,11 +668,50 @@ static int bfin_serial_startup(struct uart_port *port) } } # endif -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ +# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) } # endif #endif + +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (uart->cts_pin >= 0) { + if (request_irq(gpio_to_irq(uart->cts_pin), + bfin_serial_mctrl_cts_int, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_DISABLED, "BFIN_UART_CTS", uart)) { + uart->cts_pin = -1; + pr_info("Unable to attach BlackFin UART CTS interrupt.\ + So, disable it.\n"); + } + } + if (uart->rts_pin >= 0) { + gpio_request(uart->rts_pin, DRIVER_NAME); + gpio_direction_output(uart->rts_pin, 0); + } +#endif +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (request_irq(uart->status_irq, + bfin_serial_mctrl_cts_int, + IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { + pr_info("Unable to attach BlackFin UART Modem \ + 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); +#endif + UART_SET_IER(uart, ERBFI); return 0; } @@ -699,6 +745,21 @@ static void bfin_serial_shutdown(struct uart_port *port) free_irq(uart->port.irq, uart); free_irq(uart->port.irq+1, uart); #endif + +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (uart->cts_pin >= 0) + free_irq(gpio_to_irq(uart->cts_pin), uart); + if (uart->rts_pin >= 0) + 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 } static void @@ -864,6 +925,20 @@ static void bfin_serial_set_ldisc(struct uart_port *port) } } +static void bfin_serial_reset_irda(struct uart_port *port) +{ + int line = port->line; + unsigned short val; + + val = UART_GET_GCTL(&bfin_serial_ports[line]); + val &= ~(IREN | RPOLC); + UART_PUT_GCTL(&bfin_serial_ports[line], val); + SSYNC(); + val |= (IREN | RPOLC); + UART_PUT_GCTL(&bfin_serial_ports[line], val); + SSYNC(); +} + #ifdef CONFIG_CONSOLE_POLL static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) { @@ -909,20 +984,6 @@ static int bfin_kgdboc_port_startup(struct uart_port *port) } #endif -static void bfin_serial_reset_irda(struct uart_port *port) -{ - int line = port->line; - unsigned short val; - - val = UART_GET_GCTL(&bfin_serial_ports[line]); - val &= ~(IREN | RPOLC); - UART_PUT_GCTL(&bfin_serial_ports[line], val); - SSYNC(); - val |= (IREN | RPOLC); - UART_PUT_GCTL(&bfin_serial_ports[line], val); - SSYNC(); -} - static struct uart_ops bfin_serial_pops = { .tx_empty = bfin_serial_tx_empty, .set_mctrl = bfin_serial_set_mctrl, @@ -952,6 +1013,39 @@ static struct uart_ops bfin_serial_pops = { #endif }; +static void __init bfin_serial_hw_init(void) +{ +#ifdef CONFIG_SERIAL_BFIN_UART0 + peripheral_request(P_UART0_TX, DRIVER_NAME); + peripheral_request(P_UART0_RX, DRIVER_NAME); +#endif + +#ifdef CONFIG_SERIAL_BFIN_UART1 + peripheral_request(P_UART1_TX, DRIVER_NAME); + peripheral_request(P_UART1_RX, DRIVER_NAME); + +# if defined(CONFIG_BFIN_UART1_CTSRTS) && defined(CONFIG_BF54x) + peripheral_request(P_UART1_RTS, DRIVER_NAME); + peripheral_request(P_UART1_CTS, DRIVER_NAME); +# endif +#endif + +#ifdef CONFIG_SERIAL_BFIN_UART2 + peripheral_request(P_UART2_TX, DRIVER_NAME); + peripheral_request(P_UART2_RX, DRIVER_NAME); +#endif + +#ifdef CONFIG_SERIAL_BFIN_UART3 + peripheral_request(P_UART3_TX, DRIVER_NAME); + peripheral_request(P_UART3_RX, DRIVER_NAME); + +# if defined(CONFIG_BFIN_UART3_CTSRTS) && defined(CONFIG_BF54x) + peripheral_request(P_UART3_RTS, DRIVER_NAME); + peripheral_request(P_UART3_CTS, DRIVER_NAME); +# endif +#endif +} + static void __init bfin_serial_init_ports(void) { static int first = 1; @@ -961,6 +1055,8 @@ static void __init bfin_serial_init_ports(void) return; first = 0; + bfin_serial_hw_init(); + for (i = 0; i < nr_active_ports; i++) { bfin_serial_ports[i].port.uartclk = get_sclk(); bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE; @@ -973,6 +1069,8 @@ static void __init bfin_serial_init_ports(void) bfin_serial_resource[i].uart_base_addr; bfin_serial_ports[i].port.irq = bfin_serial_resource[i].uart_irq; + bfin_serial_ports[i].status_irq = + bfin_serial_resource[i].uart_status_irq; bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF; #ifdef CONFIG_SERIAL_BFIN_DMA bfin_serial_ports[i].tx_done = 1; @@ -983,16 +1081,14 @@ static void __init bfin_serial_init_ports(void) bfin_serial_resource[i].uart_rx_dma_channel; init_timer(&(bfin_serial_ports[i].rx_dma_timer)); #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - init_timer(&(bfin_serial_ports[i].cts_timer)); +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) bfin_serial_ports[i].cts_pin = bfin_serial_resource[i].uart_cts_pin; bfin_serial_ports[i].rts_pin = bfin_serial_resource[i].uart_rts_pin; #endif - bfin_serial_hw_init(&bfin_serial_ports[i]); } - } #if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) @@ -1049,7 +1145,8 @@ bfin_serial_console_setup(struct console *co, char *options) int baud = 57600; int bits = 8; int parity = 'n'; -# ifdef CONFIG_SERIAL_BFIN_CTSRTS +# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) int flow = 'r'; # else int flow = 'n'; @@ -1246,7 +1343,8 @@ 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; -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) gpio_free(bfin_serial_ports[i].cts_pin); gpio_free(bfin_serial_ports[i].rts_pin); #endif diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 5c6ef51da274..f8df0681e160 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -1106,6 +1106,10 @@ static int cpm_uart_init_port(struct device_node *np, for (i = 0; i < NUM_GPIOS; i++) pinfo->gpios[i] = of_get_gpio(np, i); +#ifdef CONFIG_PPC_EARLY_DEBUG_CPM + udbg_putc = NULL; +#endif + return cpm_uart_request_port(&pinfo->port); out_pram: @@ -1255,10 +1259,6 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) baud = 9600; } -#ifdef CONFIG_PPC_EARLY_DEBUG_CPM - udbg_putc = NULL; -#endif - if (IS_SMC(pinfo)) { out_be16(&pinfo->smcup->smc_brkcr, 0); cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); @@ -1339,13 +1339,13 @@ static int __devinit cpm_uart_probe(struct of_device *ofdev, dev_set_drvdata(&ofdev->dev, pinfo); + /* initialize the device pointer for the port */ + pinfo->port.dev = &ofdev->dev; + ret = cpm_uart_init_port(ofdev->node, pinfo); if (ret) return ret; - /* initialize the device pointer for the port */ - pinfo->port.dev = &ofdev->dev; - return uart_add_one_port(&cpm_reg, &pinfo->port); } diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index e642c22c80e2..7ba7d70f04d6 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -1391,7 +1391,7 @@ static inline void e100_disable_rx_irq(struct e100_serial *info) #if defined(CONFIG_ETRAX_RS485) /* Enable RS-485 mode on selected port. This is UGLY. */ static int -e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) +e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r) { struct e100_serial * info = (struct e100_serial *)tty->driver_data; @@ -1409,13 +1409,11 @@ e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1); #endif - info->rs485.rts_on_send = 0x01 & r->rts_on_send; - info->rs485.rts_after_sent = 0x01 & r->rts_after_sent; + info->rs485.flags = r->flags; if (r->delay_rts_before_send >= 1000) info->rs485.delay_rts_before_send = 1000; else info->rs485.delay_rts_before_send = r->delay_rts_before_send; - info->rs485.enabled = r->enabled; /* printk("rts: on send = %i, after = %i, enabled = %i", info->rs485.rts_on_send, info->rs485.rts_after_sent, @@ -1430,17 +1428,18 @@ e100_write_rs485(struct tty_struct *tty, const unsigned char *buf, int count) { struct e100_serial * info = (struct e100_serial *)tty->driver_data; - int old_enabled = info->rs485.enabled; + int old_value = (info->rs485.flags) & SER_RS485_ENABLED; /* rs485 is always implicitly enabled if we're using the ioctl() - * but it doesn't have to be set in the rs485_control + * but it doesn't have to be set in the serial_rs485 * (to be backward compatible with old apps) * So we store, set and restore it. */ - info->rs485.enabled = 1; + info->rs485.flags |= SER_RS485_ENABLED; /* rs_write now deals with RS485 if enabled */ count = rs_write(tty, buf, count); - info->rs485.enabled = old_enabled; + if (!old_value) + info->rs485.flags &= ~(SER_RS485_ENABLED); return count; } @@ -1451,7 +1450,7 @@ static void rs485_toggle_rts_timer_function(unsigned long data) struct e100_serial *info = (struct e100_serial *)data; fast_timers_rs485[info->line].function = NULL; - e100_rts(info, info->rs485.rts_after_sent); + e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rx_irq(info); @@ -1647,7 +1646,7 @@ transmit_chars_dma(struct e100_serial *info) info->tr_running = 0; #if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) - if (info->rs485.enabled) { + if (info->rs485.flags & SER_RS485_ENABLED) { /* Set a short timer to toggle RTS */ start_one_shot_timer(&fast_timers_rs485[info->line], rs485_toggle_rts_timer_function, @@ -2577,7 +2576,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) info->icount.tx++; if (info->xmit.head == info->xmit.tail) { #if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) - if (info->rs485.enabled) { + if (info->rs485.flags & SER_RS485_ENABLED) { /* Set a short timer to toggle RTS */ start_one_shot_timer(&fast_timers_rs485[info->line], rs485_toggle_rts_timer_function, @@ -3218,7 +3217,7 @@ rs_write(struct tty_struct *tty, #if defined(CONFIG_ETRAX_RS485) struct e100_serial *info = (struct e100_serial *)tty->driver_data; - if (info->rs485.enabled) + if (info->rs485.flags & SER_RS485_ENABLED) { /* If we are in RS-485 mode, we need to toggle RTS and disable * the receiver before initiating a DMA transfer @@ -3228,7 +3227,7 @@ rs_write(struct tty_struct *tty, fast_timers_rs485[info->line].function = NULL; del_fast_timer(&fast_timers_rs485[info->line]); #endif - e100_rts(info, info->rs485.rts_on_send); + e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND)); #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_disable_rx(info); e100_enable_rx_irq(info); @@ -3242,7 +3241,7 @@ rs_write(struct tty_struct *tty, count = rs_raw_write(tty, buf, count); #if defined(CONFIG_ETRAX_RS485) - if (info->rs485.enabled) + if (info->rs485.flags & SER_RS485_ENABLED) { unsigned int val; /* If we are in RS-485 mode the following has to be done: @@ -3263,7 +3262,7 @@ rs_write(struct tty_struct *tty, get_lsr_info(info, &val); }while (!(val & TIOCSER_TEMT)); - e100_rts(info, info->rs485.rts_after_sent); + e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); @@ -3678,14 +3677,52 @@ rs_ioctl(struct tty_struct *tty, struct file * file, #if defined(CONFIG_ETRAX_RS485) case TIOCSERSETRS485: { + /* In this ioctl we still use the old structure + * rs485_control for backward compatibility + * (if we use serial_rs485, then old user-level code + * wouldn't work anymore...). + * The use of this ioctl is deprecated: use TIOCSRS485 + * instead.*/ struct rs485_control rs485ctrl; + struct serial_rs485 rs485data; + printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n"); if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg, sizeof(rs485ctrl))) return -EFAULT; - return e100_enable_rs485(tty, &rs485ctrl); + rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send; + rs485data.flags = 0; + if (rs485ctrl.enabled) + rs485data.flags |= SER_RS485_ENABLED; + else + rs485data.flags &= ~(SER_RS485_ENABLED); + + if (rs485ctrl.rts_on_send) + rs485data.flags |= SER_RS485_RTS_ON_SEND; + else + rs485data.flags &= ~(SER_RS485_RTS_ON_SEND); + + if (rs485ctrl.rts_after_sent) + rs485data.flags |= SER_RS485_RTS_AFTER_SEND; + else + rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND); + + return e100_enable_rs485(tty, &rs485data); } + case TIOCSRS485: + { + /* This is the new version of TIOCSRS485, with new + * data structure serial_rs485 */ + struct serial_rs485 rs485data; + if (copy_from_user(&rs485data, (struct rs485_control *)arg, + sizeof(rs485data))) + return -EFAULT; + + return e100_enable_rs485(tty, &rs485data); + } + + case TIOCSERWRRS485: { struct rs485_write rs485wr; @@ -3827,8 +3864,8 @@ rs_close(struct tty_struct *tty, struct file * filp) /* port closed */ #if defined(CONFIG_ETRAX_RS485) - if (info->rs485.enabled) { - info->rs485.enabled = 0; + if (info->rs485.flags & SER_RS485_ENABLED) { + info->rs485.flags &= ~(SER_RS485_ENABLED); #if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); #endif @@ -4493,10 +4530,10 @@ rs_init(void) #if defined(CONFIG_ETRAX_RS485) /* Set sane defaults */ - info->rs485.rts_on_send = 0; - info->rs485.rts_after_sent = 1; + info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND); + info->rs485.flags |= SER_RS485_RTS_AFTER_SEND; info->rs485.delay_rts_before_send = 0; - info->rs485.enabled = 0; + info->rs485.flags &= ~(SER_RS485_ENABLED); #endif INIT_WORK(&info->work, do_softint); diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h index f36a729280bc..ea0beb46a10d 100644 --- a/drivers/serial/crisv10.h +++ b/drivers/serial/crisv10.h @@ -125,7 +125,7 @@ struct e100_serial { int errorcode; #ifdef CONFIG_ETRAX_RS485 - struct rs485_control rs485; /* RS-485 support */ + struct serial_rs485 rs485; /* RS-485 support */ #endif }; diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c index e6390d023634..9dadaa11d266 100644 --- a/drivers/serial/jsm/jsm_neo.c +++ b/drivers/serial/jsm/jsm_neo.c @@ -533,7 +533,6 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) return; - len_written = 0; n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; /* cache head and tail of queue */ @@ -619,14 +618,10 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals) /* Make the UART raise any of the output signals we want up */ static void neo_assert_modem_signals(struct jsm_channel *ch) { - u8 out; - if (!ch) return; - out = ch->ch_mostat; - - writeb(out, &ch->ch_neo_uart->mcr); + writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr); /* flush write operation */ neo_pci_posting_flush(ch->ch_bd); @@ -936,10 +931,9 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) static void neo_param(struct jsm_channel *ch) { u8 lcr = 0; - u8 uart_lcr = 0; - u8 ier = 0; - u32 baud = 9600; - int quot = 0; + u8 uart_lcr, ier; + u32 baud; + int quot; struct jsm_board *bd; bd = ch->ch_bd; diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 330696309f76..31496dc0a0d1 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -183,7 +183,6 @@ static void jsm_tty_break(struct uart_port *port, int break_state) static int jsm_tty_open(struct uart_port *port) { struct jsm_board *brd; - int rc = 0; struct jsm_channel *channel = (struct jsm_channel *)port; struct ktermios *termios; @@ -265,7 +264,7 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_open_count++; jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n"); - return rc; + return 0; } static void jsm_tty_close(struct uart_port *port) @@ -748,7 +747,7 @@ static void jsm_carrier(struct jsm_channel *ch) void jsm_check_queue_flow_control(struct jsm_channel *ch) { struct board_ops *bd_ops = ch->ch_bd->bd_ops; - int qleft = 0; + int qleft; /* Store how much space we have left in the queue */ if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0) @@ -834,7 +833,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) */ int jsm_tty_write(struct uart_port *port) { - int bufcount = 0, n = 0; + int bufcount; int data_count = 0,data_count1 =0; u16 head; u16 tail; @@ -850,14 +849,12 @@ int jsm_tty_write(struct uart_port *port) if ((bufcount = tail - head - 1) < 0) bufcount += WQUEUESIZE; - n = bufcount; - - n = min(n, 56); + bufcount = min(bufcount, 56); remain = WQUEUESIZE - head; data_count = 0; - if (n >= remain) { - n -= remain; + if (bufcount >= remain) { + bufcount -= remain; while ((port->info->xmit.head != temp_tail) && (data_count < remain)) { channel->ch_wqueue[head++] = @@ -871,8 +868,8 @@ int jsm_tty_write(struct uart_port *port) } data_count1 = 0; - if (n > 0) { - remain = n; + if (bufcount > 0) { + remain = bufcount; while ((port->info->xmit.head != temp_tail) && (data_count1 < remain)) { channel->ch_wqueue[head++] = diff --git a/drivers/serial/max3100.c b/drivers/serial/max3100.c new file mode 100644 index 000000000000..9fd33e5622bd --- /dev/null +++ b/drivers/serial/max3100.c @@ -0,0 +1,927 @@ +/* + * + * Copyright (C) 2008 Christian Pellegrin <chripell@evolware.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. + * + * + * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have + * to use polling for flow control. TX empty IRQ is unusable, since + * writing conf clears FIFO buffer and we cannot have this interrupt + * always asking us for attention. + * + * Example platform data: + + static struct plat_max3100 max3100_plat_data = { + .loopback = 0, + .crystal = 0, + .poll_time = 100, + }; + + static struct spi_board_info spi_board_info[] = { + { + .modalias = "max3100", + .platform_data = &max3100_plat_data, + .irq = IRQ_EINT12, + .max_speed_hz = 5*1000*1000, + .chip_select = 0, + }, + }; + + * The initial minor number is 209 in the low-density serial port: + * mknod /dev/ttyMAX0 c 204 209 + */ + +#define MAX3100_MAJOR 204 +#define MAX3100_MINOR 209 +/* 4 MAX3100s should be enough for everyone */ +#define MAX_MAX3100 4 + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/spi/spi.h> +#include <linux/freezer.h> + +#include <linux/serial_max3100.h> + +#define MAX3100_C (1<<14) +#define MAX3100_D (0<<14) +#define MAX3100_W (1<<15) +#define MAX3100_RX (0<<15) + +#define MAX3100_WC (MAX3100_W | MAX3100_C) +#define MAX3100_RC (MAX3100_RX | MAX3100_C) +#define MAX3100_WD (MAX3100_W | MAX3100_D) +#define MAX3100_RD (MAX3100_RX | MAX3100_D) +#define MAX3100_CMD (3 << 14) + +#define MAX3100_T (1<<14) +#define MAX3100_R (1<<15) + +#define MAX3100_FEN (1<<13) +#define MAX3100_SHDN (1<<12) +#define MAX3100_TM (1<<11) +#define MAX3100_RM (1<<10) +#define MAX3100_PM (1<<9) +#define MAX3100_RAM (1<<8) +#define MAX3100_IR (1<<7) +#define MAX3100_ST (1<<6) +#define MAX3100_PE (1<<5) +#define MAX3100_L (1<<4) +#define MAX3100_BAUD (0xf) + +#define MAX3100_TE (1<<10) +#define MAX3100_RAFE (1<<10) +#define MAX3100_RTS (1<<9) +#define MAX3100_CTS (1<<9) +#define MAX3100_PT (1<<8) +#define MAX3100_DATA (0xff) + +#define MAX3100_RT (MAX3100_R | MAX3100_T) +#define MAX3100_RTC (MAX3100_RT | MAX3100_CTS | MAX3100_RAFE) + +/* the following simulate a status reg for ignore_status_mask */ +#define MAX3100_STATUS_PE 1 +#define MAX3100_STATUS_FE 2 +#define MAX3100_STATUS_OE 4 + +struct max3100_port { + struct uart_port port; + struct spi_device *spi; + + int cts; /* last CTS received for flow ctrl */ + int tx_empty; /* last TX empty bit */ + + spinlock_t conf_lock; /* shared data */ + int conf_commit; /* need to make changes */ + int conf; /* configuration for the MAX31000 + * (bits 0-7, bits 8-11 are irqs) */ + int rts_commit; /* need to change rts */ + int rts; /* rts status */ + int baud; /* current baud rate */ + + int parity; /* keeps track if we should send parity */ +#define MAX3100_PARITY_ON 1 +#define MAX3100_PARITY_ODD 2 +#define MAX3100_7BIT 4 + int rx_enabled; /* if we should rx chars */ + + int irq; /* irq assigned to the max3100 */ + + int minor; /* minor number */ + int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */ + int loopback; /* 1 if we are in loopback mode */ + + /* for handling irqs: need workqueue since we do spi_sync */ + struct workqueue_struct *workqueue; + struct work_struct work; + /* set to 1 to make the workhandler exit as soon as possible */ + int force_end_work; + /* need to know we are suspending to avoid deadlock on workqueue */ + int suspending; + + /* hook for suspending MAX3100 via dedicated pin */ + void (*max3100_hw_suspend) (int suspend); + + /* poll time (in ms) for ctrl lines */ + int poll_time; + /* and its timer */ + struct timer_list timer; +}; + +static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */ +static DEFINE_MUTEX(max3100s_lock); /* race on probe */ + +static int max3100_do_parity(struct max3100_port *s, u16 c) +{ + int parity; + + if (s->parity & MAX3100_PARITY_ODD) + parity = 1; + else + parity = 0; + + if (s->parity & MAX3100_7BIT) + c &= 0x7f; + else + c &= 0xff; + + parity = parity ^ (hweight8(c) & 1); + return parity; +} + +static int max3100_check_parity(struct max3100_port *s, u16 c) +{ + return max3100_do_parity(s, c) == ((c >> 8) & 1); +} + +static void max3100_calc_parity(struct max3100_port *s, u16 *c) +{ + if (s->parity & MAX3100_7BIT) + *c &= 0x7f; + else + *c &= 0xff; + + if (s->parity & MAX3100_PARITY_ON) + *c |= max3100_do_parity(s, *c) << 8; +} + +static void max3100_work(struct work_struct *w); + +static void max3100_dowork(struct max3100_port *s) +{ + if (!s->force_end_work && !work_pending(&s->work) && + !freezing(current) && !s->suspending) + queue_work(s->workqueue, &s->work); +} + +static void max3100_timeout(unsigned long data) +{ + struct max3100_port *s = (struct max3100_port *)data; + + if (s->port.info) { + max3100_dowork(s); + mod_timer(&s->timer, jiffies + s->poll_time); + } +} + +static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) +{ + struct spi_message message; + u16 etx, erx; + int status; + struct spi_transfer tran = { + .tx_buf = &etx, + .rx_buf = &erx, + .len = 2, + }; + + etx = cpu_to_be16(tx); + spi_message_init(&message); + spi_message_add_tail(&tran, &message); + status = spi_sync(s->spi, &message); + if (status) { + dev_warn(&s->spi->dev, "error while calling spi_sync\n"); + return -EIO; + } + *rx = be16_to_cpu(erx); + s->tx_empty = (*rx & MAX3100_T) > 0; + dev_dbg(&s->spi->dev, "%04x - %04x\n", tx, *rx); + return 0; +} + +static int max3100_handlerx(struct max3100_port *s, u16 rx) +{ + unsigned int ch, flg, status = 0; + int ret = 0, cts; + + if (rx & MAX3100_R && s->rx_enabled) { + dev_dbg(&s->spi->dev, "%s\n", __func__); + ch = rx & (s->parity & MAX3100_7BIT ? 0x7f : 0xff); + if (rx & MAX3100_RAFE) { + s->port.icount.frame++; + flg = TTY_FRAME; + status |= MAX3100_STATUS_FE; + } else { + if (s->parity & MAX3100_PARITY_ON) { + if (max3100_check_parity(s, rx)) { + s->port.icount.rx++; + flg = TTY_NORMAL; + } else { + s->port.icount.parity++; + flg = TTY_PARITY; + status |= MAX3100_STATUS_PE; + } + } else { + s->port.icount.rx++; + flg = TTY_NORMAL; + } + } + uart_insert_char(&s->port, status, MAX3100_STATUS_OE, ch, flg); + ret = 1; + } + + cts = (rx & MAX3100_CTS) > 0; + if (s->cts != cts) { + s->cts = cts; + uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0); + } + + return ret; +} + +static void max3100_work(struct work_struct *w) +{ + struct max3100_port *s = container_of(w, struct max3100_port, work); + int rxchars; + u16 tx, rx; + int conf, cconf, rts, crts; + struct circ_buf *xmit = &s->port.info->xmit; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + rxchars = 0; + do { + spin_lock(&s->conf_lock); + conf = s->conf; + cconf = s->conf_commit; + s->conf_commit = 0; + rts = s->rts; + crts = s->rts_commit; + s->rts_commit = 0; + spin_unlock(&s->conf_lock); + if (cconf) + max3100_sr(s, MAX3100_WC | conf, &rx); + if (crts) { + max3100_sr(s, MAX3100_WD | MAX3100_TE | + (s->rts ? MAX3100_RTS : 0), &rx); + rxchars += max3100_handlerx(s, rx); + } + + max3100_sr(s, MAX3100_RD, &rx); + rxchars += max3100_handlerx(s, rx); + + if (rx & MAX3100_T) { + tx = 0xffff; + if (s->port.x_char) { + tx = s->port.x_char; + s->port.icount.tx++; + s->port.x_char = 0; + } else if (!uart_circ_empty(xmit) && + !uart_tx_stopped(&s->port)) { + tx = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & + (UART_XMIT_SIZE - 1); + s->port.icount.tx++; + } + if (tx != 0xffff) { + max3100_calc_parity(s, &tx); + tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0); + max3100_sr(s, tx, &rx); + rxchars += max3100_handlerx(s, rx); + } + } + + if (rxchars > 16 && s->port.info->port.tty != NULL) { + tty_flip_buffer_push(s->port.info->port.tty); + rxchars = 0; + } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&s->port); + + } while (!s->force_end_work && + !freezing(current) && + ((rx & MAX3100_R) || + (!uart_circ_empty(xmit) && + !uart_tx_stopped(&s->port)))); + + if (rxchars > 0 && s->port.info->port.tty != NULL) + tty_flip_buffer_push(s->port.info->port.tty); +} + +static irqreturn_t max3100_irq(int irqno, void *dev_id) +{ + struct max3100_port *s = dev_id; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + max3100_dowork(s); + return IRQ_HANDLED; +} + +static void max3100_enable_ms(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + if (s->poll_time > 0) + mod_timer(&s->timer, jiffies); + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static void max3100_start_tx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + max3100_dowork(s); +} + +static void max3100_stop_rx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + s->rx_enabled = 0; + spin_lock(&s->conf_lock); + s->conf &= ~MAX3100_RM; + s->conf_commit = 1; + spin_unlock(&s->conf_lock); + max3100_dowork(s); +} + +static unsigned int max3100_tx_empty(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + /* may not be truly up-to-date */ + max3100_dowork(s); + return s->tx_empty; +} + +static unsigned int max3100_get_mctrl(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + /* may not be truly up-to-date */ + max3100_dowork(s); + /* always assert DCD and DSR since these lines are not wired */ + return (s->cts ? TIOCM_CTS : 0) | TIOCM_DSR | TIOCM_CAR; +} + +static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int rts; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + rts = (mctrl & TIOCM_RTS) > 0; + + spin_lock(&s->conf_lock); + if (s->rts != rts) { + s->rts = rts; + s->rts_commit = 1; + max3100_dowork(s); + } + spin_unlock(&s->conf_lock); +} + +static void +max3100_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int baud = 0; + unsigned cflag; + u32 param_new, param_mask, parity = 0; + struct tty_struct *tty = s->port.info->port.tty; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + if (!tty) + return; + + cflag = termios->c_cflag; + param_new = 0; + param_mask = 0; + + baud = tty_get_baud_rate(tty); + param_new = s->conf & MAX3100_BAUD; + switch (baud) { + case 300: + if (s->crystal) + baud = s->baud; + else + param_new = 15; + break; + case 600: + param_new = 14 + s->crystal; + break; + case 1200: + param_new = 13 + s->crystal; + break; + case 2400: + param_new = 12 + s->crystal; + break; + case 4800: + param_new = 11 + s->crystal; + break; + case 9600: + param_new = 10 + s->crystal; + break; + case 19200: + param_new = 9 + s->crystal; + break; + case 38400: + param_new = 8 + s->crystal; + break; + case 57600: + param_new = 1 + s->crystal; + break; + case 115200: + param_new = 0 + s->crystal; + break; + case 230400: + if (s->crystal) + param_new = 0; + else + baud = s->baud; + break; + default: + baud = s->baud; + } + tty_encode_baud_rate(tty, baud, baud); + s->baud = baud; + param_mask |= MAX3100_BAUD; + + if ((cflag & CSIZE) == CS8) { + param_new &= ~MAX3100_L; + parity &= ~MAX3100_7BIT; + } else { + param_new |= MAX3100_L; + parity |= MAX3100_7BIT; + cflag = (cflag & ~CSIZE) | CS7; + } + param_mask |= MAX3100_L; + + if (cflag & CSTOPB) + param_new |= MAX3100_ST; + else + param_new &= ~MAX3100_ST; + param_mask |= MAX3100_ST; + + if (cflag & PARENB) { + param_new |= MAX3100_PE; + parity |= MAX3100_PARITY_ON; + } else { + param_new &= ~MAX3100_PE; + parity &= ~MAX3100_PARITY_ON; + } + param_mask |= MAX3100_PE; + + if (cflag & PARODD) + parity |= MAX3100_PARITY_ODD; + else + parity &= ~MAX3100_PARITY_ODD; + + /* mask termios capabilities we don't support */ + cflag &= ~CMSPAR; + termios->c_cflag = cflag; + + s->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + s->port.ignore_status_mask |= + MAX3100_STATUS_PE | MAX3100_STATUS_FE | + MAX3100_STATUS_OE; + + /* we are sending char from a workqueue so enable */ + s->port.info->port.tty->low_latency = 1; + + if (s->poll_time > 0) + del_timer_sync(&s->timer); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_lock(&s->conf_lock); + s->conf = (s->conf & ~param_mask) | (param_new & param_mask); + s->conf_commit = 1; + s->parity = parity; + spin_unlock(&s->conf_lock); + max3100_dowork(s); + + if (UART_ENABLE_MS(&s->port, termios->c_cflag)) + max3100_enable_ms(&s->port); +} + +static void max3100_shutdown(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (s->suspending) + return; + + s->force_end_work = 1; + + if (s->poll_time > 0) + del_timer_sync(&s->timer); + + if (s->workqueue) { + flush_workqueue(s->workqueue); + destroy_workqueue(s->workqueue); + s->workqueue = NULL; + } + if (s->irq) + free_irq(s->irq, s); + + /* set shutdown mode to save power */ + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(1); + else { + u16 tx, rx; + + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(s, tx, &rx); + } +} + +static int max3100_startup(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + char b[12]; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + s->conf = MAX3100_RM; + s->baud = s->crystal ? 230400 : 115200; + s->rx_enabled = 1; + + if (s->suspending) + return 0; + + s->force_end_work = 0; + s->parity = 0; + s->rts = 0; + + sprintf(b, "max3100-%d", s->minor); + s->workqueue = create_freezeable_workqueue(b); + if (!s->workqueue) { + dev_warn(&s->spi->dev, "cannot create workqueue\n"); + return -EBUSY; + } + INIT_WORK(&s->work, max3100_work); + + if (request_irq(s->irq, max3100_irq, + IRQF_TRIGGER_FALLING, "max3100", s) < 0) { + dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq); + s->irq = 0; + destroy_workqueue(s->workqueue); + s->workqueue = NULL; + return -EBUSY; + } + + if (s->loopback) { + u16 tx, rx; + tx = 0x4001; + max3100_sr(s, tx, &rx); + } + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(0); + s->conf_commit = 1; + max3100_dowork(s); + /* wait for clock to settle */ + msleep(50); + + max3100_enable_ms(&s->port); + + return 0; +} + +static const char *max3100_type(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + return s->port.type == PORT_MAX3100 ? "MAX3100" : NULL; +} + +static void max3100_release_port(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static void max3100_config_port(struct uart_port *port, int flags) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (flags & UART_CONFIG_TYPE) + s->port.type = PORT_MAX3100; +} + +static int max3100_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int ret = -EINVAL; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100) + ret = 0; + return ret; +} + +static void max3100_stop_tx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static int max3100_request_port(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + return 0; +} + +static void max3100_break_ctl(struct uart_port *port, int break_state) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static struct uart_ops max3100_ops = { + .tx_empty = max3100_tx_empty, + .set_mctrl = max3100_set_mctrl, + .get_mctrl = max3100_get_mctrl, + .stop_tx = max3100_stop_tx, + .start_tx = max3100_start_tx, + .stop_rx = max3100_stop_rx, + .enable_ms = max3100_enable_ms, + .break_ctl = max3100_break_ctl, + .startup = max3100_startup, + .shutdown = max3100_shutdown, + .set_termios = max3100_set_termios, + .type = max3100_type, + .release_port = max3100_release_port, + .request_port = max3100_request_port, + .config_port = max3100_config_port, + .verify_port = max3100_verify_port, +}; + +static struct uart_driver max3100_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "ttyMAX", + .dev_name = "ttyMAX", + .major = MAX3100_MAJOR, + .minor = MAX3100_MINOR, + .nr = MAX_MAX3100, +}; +static int uart_driver_registered; + +static int __devinit max3100_probe(struct spi_device *spi) +{ + int i, retval; + struct plat_max3100 *pdata; + u16 tx, rx; + + mutex_lock(&max3100s_lock); + + if (!uart_driver_registered) { + uart_driver_registered = 1; + retval = uart_register_driver(&max3100_uart_driver); + if (retval) { + printk(KERN_ERR "Couldn't register max3100 uart driver\n"); + mutex_unlock(&max3100s_lock); + return retval; + } + } + + for (i = 0; i < MAX_MAX3100; i++) + if (!max3100s[i]) + break; + if (i == MAX_MAX3100) { + dev_warn(&spi->dev, "too many MAX3100 chips\n"); + mutex_unlock(&max3100s_lock); + return -ENOMEM; + } + + max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL); + if (!max3100s[i]) { + dev_warn(&spi->dev, + "kmalloc for max3100 structure %d failed!\n", i); + mutex_unlock(&max3100s_lock); + return -ENOMEM; + } + max3100s[i]->spi = spi; + max3100s[i]->irq = spi->irq; + spin_lock_init(&max3100s[i]->conf_lock); + dev_set_drvdata(&spi->dev, max3100s[i]); + pdata = spi->dev.platform_data; + max3100s[i]->crystal = pdata->crystal; + max3100s[i]->loopback = pdata->loopback; + max3100s[i]->poll_time = pdata->poll_time * HZ / 1000; + if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) + max3100s[i]->poll_time = 1; + max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend; + max3100s[i]->minor = i; + init_timer(&max3100s[i]->timer); + max3100s[i]->timer.function = max3100_timeout; + max3100s[i]->timer.data = (unsigned long) max3100s[i]; + + dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i); + max3100s[i]->port.irq = max3100s[i]->irq; + max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200; + max3100s[i]->port.fifosize = 16; + max3100s[i]->port.ops = &max3100_ops; + max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + max3100s[i]->port.line = i; + max3100s[i]->port.type = PORT_MAX3100; + max3100s[i]->port.dev = &spi->dev; + retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port); + if (retval < 0) + dev_warn(&spi->dev, + "uart_add_one_port failed for line %d with error %d\n", + i, retval); + + /* set shutdown mode to save power. Will be woken-up on open */ + if (max3100s[i]->max3100_hw_suspend) + max3100s[i]->max3100_hw_suspend(1); + else { + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(max3100s[i], tx, &rx); + } + mutex_unlock(&max3100s_lock); + return 0; +} + +static int __devexit max3100_remove(struct spi_device *spi) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + int i; + + mutex_lock(&max3100s_lock); + + /* find out the index for the chip we are removing */ + for (i = 0; i < MAX_MAX3100; i++) + if (max3100s[i] == s) + break; + + dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i); + uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port); + kfree(max3100s[i]); + max3100s[i] = NULL; + + /* check if this is the last chip we have */ + for (i = 0; i < MAX_MAX3100; i++) + if (max3100s[i]) { + mutex_unlock(&max3100s_lock); + return 0; + } + pr_debug("removing max3100 driver\n"); + uart_unregister_driver(&max3100_uart_driver); + + mutex_unlock(&max3100s_lock); + return 0; +} + +#ifdef CONFIG_PM + +static int max3100_suspend(struct spi_device *spi, pm_message_t state) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + disable_irq(s->irq); + + s->suspending = 1; + uart_suspend_port(&max3100_uart_driver, &s->port); + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(1); + else { + /* no HW suspend, so do SW one */ + u16 tx, rx; + + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(s, tx, &rx); + } + return 0; +} + +static int max3100_resume(struct spi_device *spi) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(0); + uart_resume_port(&max3100_uart_driver, &s->port); + s->suspending = 0; + + enable_irq(s->irq); + + s->conf_commit = 1; + if (s->workqueue) + max3100_dowork(s); + + return 0; +} + +#else +#define max3100_suspend NULL +#define max3100_resume NULL +#endif + +static struct spi_driver max3100_driver = { + .driver = { + .name = "max3100", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = max3100_probe, + .remove = __devexit_p(max3100_remove), + .suspend = max3100_suspend, + .resume = max3100_resume, +}; + +static int __init max3100_init(void) +{ + return spi_register_driver(&max3100_driver); +} +module_init(max3100_init); + +static void __exit max3100_exit(void) +{ + spi_unregister_driver(&max3100_driver); +} +module_exit(max3100_exit); + +MODULE_DESCRIPTION("MAX3100 driver"); +MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index ad3488504010..9c1243fbd512 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -1538,6 +1538,21 @@ no_dma: uap->port.type = PORT_PMAC_ZILOG; uap->port.flags = 0; + /* + * Fixup for the port on Gatwick for which the device-tree has + * missing interrupts. Normally, the macio_dev would contain + * fixed up interrupt info, but we use the device-tree directly + * here due to early probing so we need the fixup too. + */ + if (uap->port.irq == NO_IRQ && + np->parent && np->parent->parent && + of_device_is_compatible(np->parent->parent, "gatwick")) { + /* IRQs on gatwick are offset by 64 */ + uap->port.irq = irq_create_mapping(NULL, 64 + 15); + uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4); + uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5); + } + /* Setup some valid baud rate information in the register * shadows so we don't write crap there before baud rate is * first initialized. diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index 41ac94872b8d..e06686ae858b 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c @@ -127,7 +127,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) struct s3c24xx_uart_port *ourport = to_ourport(port); if (tx_enabled(port)) { - disable_irq(ourport->tx_irq); + disable_irq_nosync(ourport->tx_irq); tx_enabled(port) = 0; if (port->flags & UPF_CONS_FLOW) s3c24xx_serial_rx_enable(port); @@ -154,7 +154,7 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) if (rx_enabled(port)) { dbg("s3c24xx_serial_stop_rx: port=%p\n", port); - disable_irq(ourport->rx_irq); + disable_irq_nosync(ourport->rx_irq); rx_enabled(port) = 0; } } diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index a4dc79b1d7ab..47c6837850b1 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1178,7 +1178,7 @@ static struct uart_driver sunsu_reg = { .major = TTY_MAJOR, }; -static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up) +static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up) { int quot, baud; #ifdef CONFIG_SERIO |