From f7e54d7ad743a0cf0e400ac185036df6a592567c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 14 Jan 2014 12:34:55 -0800 Subject: msm_serial: Add support for poll_{get,put}_char() Implement the polling functionality for the MSM serial driver. This allows us to use KGDB on this hardware. Cc: David Brown Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index b5d779c..053b98e 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -39,6 +39,13 @@ #include "msm_serial.h" +enum { + UARTDM_1P1 = 1, + UARTDM_1P2, + UARTDM_1P3, + UARTDM_1P4, +}; + struct msm_port { struct uart_port uart; char name[16]; @@ -309,6 +316,8 @@ static unsigned int msm_get_mctrl(struct uart_port *port) static void msm_reset(struct uart_port *port) { + struct msm_port *msm_port = UART_TO_MSM(port); + /* reset everything */ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); @@ -316,6 +325,10 @@ static void msm_reset(struct uart_port *port) msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); + + /* Disable DM modes */ + if (msm_port->is_uartdm) + msm_write(port, 0, UARTDM_DMEN); } static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -711,6 +724,117 @@ static void msm_power(struct uart_port *port, unsigned int state, } } +#ifdef CONFIG_CONSOLE_POLL +static int msm_poll_init(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Enable single character mode on RX FIFO */ + if (msm_port->is_uartdm >= UARTDM_1P4) + msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN); + + return 0; +} + +static int msm_poll_get_char_single(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; + + if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) + return NO_POLL_CHAR; + else + return msm_read(port, rf_reg) & 0xff; +} + +static int msm_poll_get_char_dm_1p3(struct uart_port *port) +{ + int c; + static u32 slop; + static int count; + unsigned char *sp = (unsigned char *)&slop; + + /* Check if a previous read had more than one char */ + if (count) { + c = sp[sizeof(slop) - count]; + count--; + /* Or if FIFO is empty */ + } else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) { + /* + * If RX packing buffer has less than a word, force stale to + * push contents into RX FIFO + */ + count = msm_read(port, UARTDM_RXFS); + count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK; + if (count) { + msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); + slop = msm_read(port, UARTDM_RF); + c = sp[0]; + count--; + } else { + c = NO_POLL_CHAR; + } + /* FIFO has a word */ + } else { + slop = msm_read(port, UARTDM_RF); + c = sp[0]; + count = sizeof(slop) - 1; + } + + return c; +} + +static int msm_poll_get_char(struct uart_port *port) +{ + u32 imr; + int c; + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Disable all interrupts */ + imr = msm_read(port, UART_IMR); + msm_write(port, 0, UART_IMR); + + if (msm_port->is_uartdm == UARTDM_1P3) + c = msm_poll_get_char_dm_1p3(port); + else + c = msm_poll_get_char_single(port); + + /* Enable interrupts */ + msm_write(port, imr, UART_IMR); + + return c; +} + +static void msm_poll_put_char(struct uart_port *port, unsigned char c) +{ + u32 imr; + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Disable all interrupts */ + imr = msm_read(port, UART_IMR); + msm_write(port, 0, UART_IMR); + + if (msm_port->is_uartdm) + reset_dm_count(port, 1); + + /* Wait until FIFO is empty */ + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); + + /* Write a character */ + msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + + /* Wait until FIFO is empty */ + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); + + /* Enable interrupts */ + msm_write(port, imr, UART_IMR); + + return; +} +#endif + static struct uart_ops msm_uart_pops = { .tx_empty = msm_tx_empty, .set_mctrl = msm_set_mctrl, @@ -729,6 +853,11 @@ static struct uart_ops msm_uart_pops = { .config_port = msm_config_port, .verify_port = msm_verify_port, .pm = msm_power, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = msm_poll_init, + .poll_get_char = msm_poll_get_char, + .poll_put_char = msm_poll_put_char, +#endif }; static struct msm_port msm_uart_ports[] = { @@ -900,7 +1029,10 @@ static struct uart_driver msm_uart_driver = { static atomic_t msm_uart_next_id = ATOMIC_INIT(0); static const struct of_device_id msm_uartdm_table[] = { - { .compatible = "qcom,msm-uartdm" }, + { .compatible = "qcom,msm-uartdm-v1.1", .data = (void *)UARTDM_1P1 }, + { .compatible = "qcom,msm-uartdm-v1.2", .data = (void *)UARTDM_1P2 }, + { .compatible = "qcom,msm-uartdm-v1.3", .data = (void *)UARTDM_1P3 }, + { .compatible = "qcom,msm-uartdm-v1.4", .data = (void *)UARTDM_1P4 }, { } }; @@ -909,6 +1041,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) struct msm_port *msm_port; struct resource *resource; struct uart_port *port; + const struct of_device_id *id; int irq; if (pdev->id == -1) @@ -923,8 +1056,9 @@ static int __init msm_serial_probe(struct platform_device *pdev) port->dev = &pdev->dev; msm_port = UART_TO_MSM(port); - if (of_match_device(msm_uartdm_table, &pdev->dev)) - msm_port->is_uartdm = 1; + id = of_match_device(msm_uartdm_table, &pdev->dev); + if (id) + msm_port->is_uartdm = (unsigned long)id->data; else msm_port->is_uartdm = 0; diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index 469fda5..1e9b68b 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h @@ -59,6 +59,7 @@ #define UART_CR_CMD_RESET_RFR (14 << 4) #define UART_CR_CMD_PROTECTION_EN (16 << 4) #define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define UART_CR_CMD_FORCE_STALE (4 << 8) #define UART_CR_CMD_RESET_TX_READY (3 << 8) #define UART_CR_TX_DISABLE (1 << 3) #define UART_CR_TX_ENABLE (1 << 2) @@ -113,6 +114,14 @@ #define GSBI_PROTOCOL_UART 0x40 #define GSBI_PROTOCOL_IDLE 0x0 +#define UARTDM_RXFS 0x50 +#define UARTDM_RXFS_BUF_SHIFT 0x7 +#define UARTDM_RXFS_BUF_MASK 0x7 + +#define UARTDM_DMEN 0x3C +#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) +#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) + #define UARTDM_DMRX 0x34 #define UARTDM_NCF_TX 0x40 #define UARTDM_RX_TOTAL_SNAP 0x38 -- cgit v0.10.2 From 4a818a09c050ebd0d99398742016bdf7e788be2a Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Fri, 24 Jan 2014 18:09:41 +0100 Subject: serial: omap-serial: Move info message to probe function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the info message about a missing wakeirq for uart is printed every time the serial driver's startup function is called. This happens multiple times and not just once. This patch moves the infomessage to the probe function to display it only once. Acked-by: Tony Lindgren Signed-off-by: Markus Pargmann Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index fa511eb..2051581 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -738,9 +738,6 @@ static int serial_omap_startup(struct uart_port *port) return retval; } disable_irq(up->wakeirq); - } else { - dev_info(up->port.dev, "no wakeirq for uart%d\n", - up->port.line); } dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); @@ -1687,6 +1684,9 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.iotype = UPIO_MEM; up->port.irq = uartirq; up->wakeirq = wakeirq; + if (!up->wakeirq) + dev_info(up->port.dev, "no wakeirq for uart%d\n", + up->port.line); up->port.regshift = 2; up->port.fifosize = 64; -- cgit v0.10.2 From 3af4e960b8a12b3f07033f1c12504305e6d4df1a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 5 Feb 2014 09:56:37 +0900 Subject: serial: sh-sci: Fix cast warning Fix the following compile warning about cast to pointer from integer of different size. drivers/tty/serial/sh-sci.c:2021:19: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] Signed-off-by: Jingoo Han Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index be33d2b..1668523 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2018,7 +2018,7 @@ static int sci_remap_port(struct uart_port *port) * need to do any remapping, just cast the cookie * directly. */ - port->membase = (void __iomem *)port->mapbase; + port->membase = (void __iomem *)(uintptr_t)port->mapbase; } return 0; -- cgit v0.10.2 From 6ec0656dc8ef2f4d4dfd6c83c4a3c946110afe1a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 5 Feb 2014 09:58:02 +0900 Subject: serial: pch_uart: Fix build warning when CONFIG_DEBUG_FS=n Add CONFIG_DEBUG_FS to 'char name' in order to fix the following build warning, because 'char name' is used only when CONFIG_DEBUG_FS is enabled. drivers/tty/serial/pch_uart.c:1765:7: warning: unused variable 'name' [-Wunused-variable] Signed-off-by: Jingoo Han Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 8fa1134..0931b3f 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1762,7 +1762,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, int fifosize; int port_type; struct pch_uart_driver_data *board; +#ifdef CONFIG_DEBUG_FS char name[32]; /* for debugfs file name */ +#endif board = &drv_dat[id->driver_data]; port_type = board->port_type; -- cgit v0.10.2 From 25eb50b97b61a237168137411550aa792bb27c00 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 6 Feb 2014 15:47:40 +0900 Subject: serial: sh-sci: Fix compatible string in DT bindings example Remove the -generic suffix from the compatible string in the serial port DT bindings example. Cc: devicetree@vger.kernel.org Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index f372cf2..53e6c17 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -37,7 +37,7 @@ Example: }; scifa0: serial@e6c40000 { - compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic"; + compatible = "renesas,scifa-r8a7790", "renesas,scifa"; reg = <0 0xe6c40000 0 64>; interrupt-parent = <&gic>; interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>; -- cgit v0.10.2 From 42f36ba47d6973fbf8ef9974073e06e847180be8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 6 Feb 2014 15:47:39 +0900 Subject: serial: sh-sci: Restrict non-COMPILE_TEST compilation Hardware supported by the driver is only found on SUPERH or ARCH_SHMOBILE platforms. Restrict non-COMPILE_TEST compilation to them. Cc: linux-serial@vger.kernel.org Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a3815ea..923d3de 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -708,7 +708,8 @@ config SERIAL_IP22_ZILOG_CONSOLE config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" - depends on HAVE_CLK && (SUPERH || ARM || COMPILE_TEST) + depends on HAVE_CLK + depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST select SERIAL_CORE config SERIAL_SH_SCI_NR_UARTS -- cgit v0.10.2 From d0fd413cffb7cd8efac6d4d192ba62fc2fa60d2d Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 7 Feb 2014 18:16:03 +0400 Subject: serial: max310x: Allow driver to be compiled as module Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 923d3de..7cfa2ed 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -289,7 +289,7 @@ config SERIAL_MAX3100 MAX3100 chip support config SERIAL_MAX310X - bool "MAX310X support" + tristate "MAX310X support" depends on SPI_MASTER select SERIAL_CORE select REGMAP_SPI if SPI_MASTER -- cgit v0.10.2 From e97e15561cd885926f78200a1e75e713172da60e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 7 Feb 2014 18:16:04 +0400 Subject: serial: max310x: Setup baud rate generator more precisely This patch provide more precisely setup of baud rate generator. If the result of division has a remainder, we use the multiplier for the base frequency. Additionally, we report result baud rate back to serial core. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 8d71e40..313bdf0 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1,7 +1,7 @@ /* * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver * - * Copyright (C) 2012-2013 Alexander Shiyan + * Copyright (C) 2012-2014 Alexander Shiyan * * Based on max3100.c, by Christian Pellegrin * Based on max3110.c, by Feng Tang @@ -504,25 +504,33 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg) return false; } -static void max310x_set_baud(struct uart_port *port, int baud) +static int max310x_set_baud(struct uart_port *port, int baud) { - unsigned int mode = 0, div = port->uartclk / baud; + unsigned int mode = 0, clk = port->uartclk, div = clk / baud; - if (!(div / 16)) { + /* Check for minimal value for divider */ + if (div < 16) + div = 16; + + if (clk % baud && (div / 16) < 0x8000) { /* Mode x2 */ mode = MAX310X_BRGCFG_2XMODE_BIT; - div = (port->uartclk * 2) / baud; - } - - if (!(div / 16)) { - /* Mode x4 */ - mode = MAX310X_BRGCFG_4XMODE_BIT; - div = (port->uartclk * 4) / baud; + clk = port->uartclk * 2; + div = clk / baud; + + if (clk % baud && (div / 16) < 0x8000) { + /* Mode x4 */ + mode = MAX310X_BRGCFG_4XMODE_BIT; + clk = port->uartclk * 4; + div = clk / baud; + } } max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8); max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16); max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode); + + return DIV_ROUND_CLOSEST(clk, div); } static int max310x_update_best_err(unsigned long f, long *besterr) @@ -875,7 +883,7 @@ static void max310x_set_termios(struct uart_port *port, port->uartclk / 4); /* Setup baudrate generator */ - max310x_set_baud(port, baud); + baud = max310x_set_baud(port, baud); /* Update timeout according to new baud rate */ uart_update_timeout(port, termios->c_cflag, baud); -- cgit v0.10.2 From 1e6128b63597adf97f1865fba7d778a6f8ccb7a0 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 7 Feb 2014 18:16:05 +0400 Subject: serial: max310x: Remove init() and exit() callbacks These callbacks were previously used for the IC power initialization. If this initialization will be needed in the future, it should be implemented with the regulator API. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 313bdf0..202c1fb6 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1135,10 +1135,6 @@ static int max310x_probe(struct device *dev, int is_spi, return PTR_ERR(s->regmap); } - /* Board specific configure */ - if (s->pdata->init) - s->pdata->init(); - /* Check device to ensure we are talking to what we expect */ ret = devtype->detect(dev); if (ret) @@ -1265,9 +1261,6 @@ static int max310x_remove(struct device *dev) ret = gpiochip_remove(&s->gpio); #endif - if (s->pdata->exit) - s->pdata->exit(); - return ret; } diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h index dd11dcd..5f4b35d 100644 --- a/include/linux/platform_data/max310x.h +++ b/include/linux/platform_data/max310x.h @@ -55,10 +55,6 @@ struct max310x_pdata { const int frequency; /* GPIO base number (can be negative) */ const int gpio_base; - /* Called during startup */ - void (*init)(void); - /* Called before finish */ - void (*exit)(void); }; #endif -- cgit v0.10.2 From f4fcc40b564dd1920029053be9c4dd557b23a7ec Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 7 Feb 2014 18:16:06 +0400 Subject: serial: max310x: Remove excess port configure at startup Serial core calls set_termios() after port startup, so there are no reason to setup port twice. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 202c1fb6..1fb3895 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -896,12 +896,6 @@ static int max310x_startup(struct uart_port *port) s->devtype->power(port, 1); - /* Configure baud rate, 9600 as default */ - max310x_set_baud(port, 9600); - - /* Configure LCR register, 8N1 mode by default */ - max310x_port_write(port, MAX310X_LCR_REG, MAX310X_LCR_WORD_LEN_8); - /* Configure MODE1 register */ max310x_port_update(port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, -- cgit v0.10.2 From e7b8a3ceff5e5c4e2bd329717976b18ce033d7cd Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 7 Feb 2014 18:16:07 +0400 Subject: serial: max310x: Add the loopback mode support This patch replaces loopback mode support from platform data to dynamic setup with TIOCMSET ioctl. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 1fb3895..3c93814 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -283,6 +283,7 @@ struct max310x_devtype { struct max310x_one { struct uart_port port; struct work_struct tx_work; + struct work_struct md_work; }; struct max310x_port { @@ -790,11 +791,21 @@ static unsigned int max310x_get_mctrl(struct uart_port *port) return TIOCM_DSR | TIOCM_CAR; } +static void max310x_md_proc(struct work_struct *ws) +{ + struct max310x_one *one = container_of(ws, struct max310x_one, md_work); + + max310x_port_update(&one->port, MAX310X_MODE2_REG, + MAX310X_MODE2_LOOPBACK_BIT, + (one->port.mctrl & TIOCM_LOOP) ? + MAX310X_MODE2_LOOPBACK_BIT : 0); +} + static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* DCD and DSR are not wired and CTS/RTS is hadnled automatically - * so do nothing - */ + struct max310x_one *one = container_of(port, struct max310x_one, port); + + schedule_work(&one->md_work); } static void max310x_break_ctl(struct uart_port *port, int break_state) @@ -904,8 +915,6 @@ static int max310x_startup(struct uart_port *port) /* Configure MODE2 register */ val = MAX310X_MODE2_RXEMPTINV_BIT; - if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK) - val |= MAX310X_MODE2_LOOPBACK_BIT; if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS) val |= MAX310X_MODE2_ECHOSUPR_BIT; @@ -1176,8 +1185,7 @@ static int max310x_probe(struct device *dev, int is_spi, s->p[i].port.irq = irq; s->p[i].port.type = PORT_MAX310X; s->p[i].port.fifosize = MAX310X_FIFO_SIZE; - s->p[i].port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE | - UPF_LOW_LATENCY; + s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; s->p[i].port.iotype = UPIO_PORT; s->p[i].port.iobase = i * 0x20; s->p[i].port.membase = (void __iomem *)~0; @@ -1193,6 +1201,8 @@ static int max310x_probe(struct device *dev, int is_spi, MAX310X_MODE1_IRQSEL_BIT); /* Initialize queue for start TX */ INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); + /* Initialize queue for changing mode */ + INIT_WORK(&s->p[i].md_work, max310x_md_proc); /* Register port */ uart_add_one_port(&s->uart, &s->p[i].port); /* Go to suspend mode */ @@ -1244,6 +1254,7 @@ static int max310x_remove(struct device *dev) for (i = 0; i < s->uart.nr; i++) { cancel_work_sync(&s->p[i].tx_work); + cancel_work_sync(&s->p[i].md_work); uart_remove_one_port(&s->uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h index 5f4b35d..9d5f69b 100644 --- a/include/linux/platform_data/max310x.h +++ b/include/linux/platform_data/max310x.h @@ -46,7 +46,6 @@ struct max310x_pdata { #define MAX310X_EXT_CLK (0x00000001) /* External clock enable */ /* Flags global to UART port */ const u8 uart_flags[MAX310X_MAX_UARTS]; -#define MAX310X_LOOPBACK (0x00000001) /* Loopback mode enable */ #define MAX310X_ECHO_SUPRESS (0x00000002) /* Enable echo supress */ #define MAX310X_AUTO_DIR_CTRL (0x00000004) /* Enable Auto direction * control (RS-485) -- cgit v0.10.2 From bb157e50cd7e5100d22a98fb37dd4df4b8520ab1 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 7 Feb 2014 18:16:08 +0400 Subject: serial: max310x: Remove IRQ validation This patch removes excess IRQ checks at driver probe(). IRQ validation is already provided by request_threaded_irq(). Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3c93814..ac1d54c 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1081,12 +1081,6 @@ static int max310x_probe(struct device *dev, int is_spi, struct max310x_pdata *pdata = dev_get_platdata(dev); int i, ret, uartclk; - /* Check for IRQ */ - if (irq <= 0) { - dev_err(dev, "No IRQ specified\n"); - return -ENOTSUPP; - } - if (!pdata) { dev_err(dev, "No platform data supplied\n"); return -EINVAL; -- cgit v0.10.2 From aa7b2e5684ec37331413231b31883ca15ae688ce Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 5 Feb 2014 21:28:38 +0200 Subject: serial: sh_sci: remove HAVE_CLK build dependecy Since 93abe8e4 (clk: add non CONFIG_HAVE_CLK routines) code using clk.h like this driver needs not depend on HAVE_CLK. Signed-off-by: Baruch Siach Acked-by: Simon Horman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 7cfa2ed..2577d67 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -708,7 +708,6 @@ config SERIAL_IP22_ZILOG_CONSOLE config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" - depends on HAVE_CLK depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST select SERIAL_CORE -- cgit v0.10.2 From 27027a70e21f62d143da142d66e508e70fc311b7 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Feb 2014 22:18:30 +0400 Subject: serial: max310x: Move all SPI-dependent stuff in one place Patch move all SPI-dependent stuff in one place. This include move PM-function definitions out of CONFIG_SPI_MASTER and move regmap initialization out of common probe into CONFIG_SPI_MASTER which may help to add I2C support in the future for this driver. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ac1d54c..9e147f3 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -290,7 +290,6 @@ struct max310x_port { struct uart_driver uart; struct max310x_devtype *devtype; struct regmap *regmap; - struct regmap_config regcfg; struct mutex mutex; struct max310x_pdata *pdata; int gpio_used; @@ -1028,6 +1027,8 @@ static int __maybe_unused max310x_resume(struct device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); + #ifdef CONFIG_GPIOLIB static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) { @@ -1074,13 +1075,16 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, } #endif -static int max310x_probe(struct device *dev, int is_spi, - struct max310x_devtype *devtype, int irq) +static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, + struct regmap *regmap, int irq) { struct max310x_port *s; struct max310x_pdata *pdata = dev_get_platdata(dev); int i, ret, uartclk; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + if (!pdata) { dev_err(dev, "No platform data supplied\n"); return -EINVAL; @@ -1104,34 +1108,12 @@ static int max310x_probe(struct device *dev, int is_spi, goto err_freq; s->pdata = pdata; + s->regmap = regmap; s->devtype = devtype; dev_set_drvdata(dev, s); mutex_init(&s->mutex); - /* Setup regmap */ - s->regcfg.reg_bits = 8; - s->regcfg.val_bits = 8; - s->regcfg.read_flag_mask = 0x00; - s->regcfg.write_flag_mask = 0x80; - s->regcfg.cache_type = REGCACHE_RBTREE; - s->regcfg.writeable_reg = max310x_reg_writeable; - s->regcfg.volatile_reg = max310x_reg_volatile; - s->regcfg.precious_reg = max310x_reg_precious; - s->regcfg.max_register = devtype->nr * 0x20 - 1; - - if (IS_ENABLED(CONFIG_SPI_MASTER) && is_spi) { - struct spi_device *spi = to_spi_device(dev); - - s->regmap = devm_regmap_init_spi(spi, &s->regcfg); - } else - return -ENOTSUPP; - - if (IS_ERR(s->regmap)) { - dev_err(dev, "Failed to initialize register map\n"); - return PTR_ERR(s->regmap); - } - /* Check device to ensure we are talking to what we expect */ ret = devtype->detect(dev); if (ret) @@ -1263,11 +1245,22 @@ static int max310x_remove(struct device *dev) return ret; } +static struct regmap_config regcfg = { + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = 0x80, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = max310x_reg_writeable, + .volatile_reg = max310x_reg_volatile, + .precious_reg = max310x_reg_precious, +}; + #ifdef CONFIG_SPI_MASTER static int max310x_spi_probe(struct spi_device *spi) { struct max310x_devtype *devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; + struct regmap *regmap; int ret; /* Setup SPI bus */ @@ -1275,12 +1268,13 @@ static int max310x_spi_probe(struct spi_device *spi) spi->mode = spi->mode ? : SPI_MODE_0; spi->max_speed_hz = spi->max_speed_hz ? : 26000000; ret = spi_setup(spi); - if (ret) { - dev_err(&spi->dev, "SPI setup failed\n"); + if (ret) return ret; - } - return max310x_probe(&spi->dev, 1, devtype, spi->irq); + regcfg.max_register = devtype->nr * 0x20 - 1; + regmap = devm_regmap_init_spi(spi, ®cfg); + + return max310x_probe(&spi->dev, devtype, regmap, spi->irq); } static int max310x_spi_remove(struct spi_device *spi) @@ -1288,8 +1282,6 @@ static int max310x_spi_remove(struct spi_device *spi) return max310x_remove(&spi->dev); } -static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); - static const struct spi_device_id max310x_id_table[] = { { "max3107", (kernel_ulong_t)&max3107_devtype, }, { "max3108", (kernel_ulong_t)&max3108_devtype, }, -- cgit v0.10.2 From d3a8a252e177cfaa2fb04120dd944104e4417bf5 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Feb 2014 22:18:31 +0400 Subject: serial: max310x: Migrate to CLK API This patch removes "frequency" parameter from MAX310X platform_data and uses CLK API for getting clock. Clock type (XTAL/OSC) is determined by clk name. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9e147f3..310ee55 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -291,6 +292,7 @@ struct max310x_port { struct max310x_devtype *devtype; struct regmap *regmap; struct mutex mutex; + struct clk *clk; struct max310x_pdata *pdata; int gpio_used; #ifdef CONFIG_GPIOLIB @@ -546,18 +548,19 @@ static int max310x_update_best_err(unsigned long f, long *besterr) return 1; } -static int max310x_set_ref_clk(struct max310x_port *s) +static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq, + bool xtal) { unsigned int div, clksrc, pllcfg = 0; long besterr = -1; - unsigned long fdiv, fmul, bestfreq = s->pdata->frequency; + unsigned long fdiv, fmul, bestfreq = freq; /* First, update error without PLL */ - max310x_update_best_err(s->pdata->frequency, &besterr); + max310x_update_best_err(freq, &besterr); /* Try all possible PLL dividers */ for (div = 1; (div <= 63) && besterr; div++) { - fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div); + fdiv = DIV_ROUND_CLOSEST(freq, div); /* Try multiplier 6 */ fmul = fdiv * 6; @@ -590,10 +593,7 @@ static int max310x_set_ref_clk(struct max310x_port *s) } /* Configure clock source */ - if (s->pdata->driver_flags & MAX310X_EXT_CLK) - clksrc = MAX310X_CLKSRC_EXTCLK_BIT; - else - clksrc = MAX310X_CLKSRC_CRYST_BIT; + clksrc = xtal ? MAX310X_CLKSRC_CRYST_BIT : MAX310X_CLKSRC_EXTCLK_BIT; /* Configure PLL */ if (pllcfg) { @@ -605,7 +605,7 @@ static int max310x_set_ref_clk(struct max310x_port *s) regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc); /* Wait for crystal */ - if (pllcfg && !(s->pdata->driver_flags & MAX310X_EXT_CLK)) + if (pllcfg && xtal) msleep(10); return (int)bestfreq; @@ -1078,9 +1078,11 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, struct regmap *regmap, int irq) { - struct max310x_port *s; struct max310x_pdata *pdata = dev_get_platdata(dev); - int i, ret, uartclk; + int i, ret, fmin, fmax, freq, uartclk; + struct clk *clk_osc, *clk_xtal; + struct max310x_port *s; + bool xtal = false; if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -1098,14 +1100,35 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, return -ENOMEM; } - /* Check input frequency */ - if ((pdata->driver_flags & MAX310X_EXT_CLK) && - ((pdata->frequency < 500000) || (pdata->frequency > 35000000))) - goto err_freq; - /* Check frequency for quartz */ - if (!(pdata->driver_flags & MAX310X_EXT_CLK) && - ((pdata->frequency < 1000000) || (pdata->frequency > 4000000))) - goto err_freq; + clk_osc = devm_clk_get(dev, "osc"); + clk_xtal = devm_clk_get(dev, "xtal"); + if (!IS_ERR(clk_osc)) { + s->clk = clk_osc; + fmin = 500000; + fmax = 35000000; + } else if (!IS_ERR(clk_xtal)) { + s->clk = clk_xtal; + fmin = 1000000; + fmax = 4000000; + xtal = true; + } else if (PTR_ERR(clk_osc) == -EPROBE_DEFER || + PTR_ERR(clk_xtal) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else { + dev_err(dev, "Cannot get clock\n"); + return -EINVAL; + } + + ret = clk_prepare_enable(s->clk); + if (ret) + return ret; + + freq = clk_get_rate(s->clk); + /* Check frequency limits */ + if (freq < fmin || freq > fmax) { + ret = -ERANGE; + goto out_clk; + } s->pdata = pdata; s->regmap = regmap; @@ -1117,7 +1140,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, /* Check device to ensure we are talking to what we expect */ ret = devtype->detect(dev); if (ret) - return ret; + goto out_clk; for (i = 0; i < devtype->nr; i++) { unsigned int offs = i << 5; @@ -1139,7 +1162,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, MAX310X_MODE1_AUTOSLEEP_BIT); } - uartclk = max310x_set_ref_clk(s); + uartclk = max310x_set_ref_clk(s, freq, xtal); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); /* Register UART driver */ @@ -1151,7 +1174,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, ret = uart_register_driver(&s->uart); if (ret) { dev_err(dev, "Registering UART driver failed\n"); - return ret; + goto out_clk; } for (i = 0; i < devtype->nr; i++) { @@ -1208,19 +1231,19 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), s); - if (ret) { - dev_err(dev, "Unable to reguest IRQ %i\n", irq); + if (!ret) + return 0; + + dev_err(dev, "Unable to reguest IRQ %i\n", irq); #ifdef CONFIG_GPIOLIB - if (s->gpio_used) - WARN_ON(gpiochip_remove(&s->gpio)); + if (s->gpio_used) + WARN_ON(gpiochip_remove(&s->gpio)); #endif - } - return ret; +out_clk: + clk_disable_unprepare(s->clk); -err_freq: - dev_err(dev, "Frequency parameter incorrect\n"); - return -EINVAL; + return ret; } static int max310x_remove(struct device *dev) @@ -1236,6 +1259,7 @@ static int max310x_remove(struct device *dev) } uart_unregister_driver(&s->uart); + clk_disable_unprepare(s->clk); #ifdef CONFIG_GPIOLIB if (s->gpio_used) diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h index 9d5f69b..57a0cd4 100644 --- a/include/linux/platform_data/max310x.h +++ b/include/linux/platform_data/max310x.h @@ -20,9 +20,7 @@ * Example board initialization data: * * static struct max310x_pdata max3107_pdata = { - * .driver_flags = MAX310X_EXT_CLK, * .uart_flags[0] = MAX310X_ECHO_SUPRESS | MAX310X_AUTO_DIR_CTRL, - * .frequency = 3686400, * .gpio_base = -1, * }; * @@ -41,17 +39,12 @@ /* MAX310X platform data structure */ struct max310x_pdata { - /* Flags global to driver */ - const u8 driver_flags; -#define MAX310X_EXT_CLK (0x00000001) /* External clock enable */ /* Flags global to UART port */ const u8 uart_flags[MAX310X_MAX_UARTS]; #define MAX310X_ECHO_SUPRESS (0x00000002) /* Enable echo supress */ #define MAX310X_AUTO_DIR_CTRL (0x00000004) /* Enable Auto direction * control (RS-485) */ - /* Frequency (extrenal clock or crystal) */ - const int frequency; /* GPIO base number (can be negative) */ const int gpio_base; }; -- cgit v0.10.2 From dba29a2894771562d265232ae4b61f0310bab1f5 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Feb 2014 22:18:32 +0400 Subject: serial: max310x: Always use dynamic GPIO ID assignment Always register GPIOs and use dynamic GPIO ID assignment. This is no much worth if GPIOs is not used, but helps remove private driver header and add DT support in the future. Additionally, patch adds missing uart_unregister_driver() call if probe() fails. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 310ee55..2a12cbc 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -294,7 +294,6 @@ struct max310x_port { struct mutex mutex; struct clk *clk; struct max310x_pdata *pdata; - int gpio_used; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; #endif @@ -1177,6 +1176,23 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, goto out_clk; } +#ifdef CONFIG_GPIOLIB + /* Setup GPIO cotroller */ + s->gpio.owner = THIS_MODULE; + s->gpio.dev = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = max310x_gpio_direction_input; + s->gpio.get = max310x_gpio_get; + s->gpio.direction_output= max310x_gpio_direction_output; + s->gpio.set = max310x_gpio_set; + s->gpio.base = -1; + s->gpio.ngpio = devtype->nr * 4; + s->gpio.can_sleep = 1; + ret = gpiochip_add(&s->gpio); + if (ret) + goto out_uart; +#endif + for (i = 0; i < devtype->nr; i++) { /* Initialize port data */ s->p[i].port.line = i; @@ -1208,25 +1224,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, devtype->power(&s->p[i].port, 0); } -#ifdef CONFIG_GPIOLIB - /* Setup GPIO cotroller */ - if (s->pdata->gpio_base) { - s->gpio.owner = THIS_MODULE; - s->gpio.dev = dev; - s->gpio.label = dev_name(dev); - s->gpio.direction_input = max310x_gpio_direction_input; - s->gpio.get = max310x_gpio_get; - s->gpio.direction_output= max310x_gpio_direction_output; - s->gpio.set = max310x_gpio_set; - s->gpio.base = s->pdata->gpio_base; - s->gpio.ngpio = devtype->nr * 4; - s->gpio.can_sleep = 1; - if (!gpiochip_add(&s->gpio)) - s->gpio_used = 1; - } else - dev_info(dev, "GPIO support not enabled\n"); -#endif - /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, @@ -1235,11 +1232,14 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, return 0; dev_err(dev, "Unable to reguest IRQ %i\n", irq); + #ifdef CONFIG_GPIOLIB - if (s->gpio_used) - WARN_ON(gpiochip_remove(&s->gpio)); + WARN_ON(gpiochip_remove(&s->gpio)); #endif +out_uart: + uart_unregister_driver(&s->uart); + out_clk: clk_disable_unprepare(s->clk); @@ -1251,6 +1251,12 @@ static int max310x_remove(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i, ret = 0; +#ifdef CONFIG_GPIOLIB + ret = gpiochip_remove(&s->gpio); + if (ret) + return ret; +#endif + for (i = 0; i < s->uart.nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); @@ -1261,11 +1267,6 @@ static int max310x_remove(struct device *dev) uart_unregister_driver(&s->uart); clk_disable_unprepare(s->clk); -#ifdef CONFIG_GPIOLIB - if (s->gpio_used) - ret = gpiochip_remove(&s->gpio); -#endif - return ret; } diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h index 57a0cd4..1140a57 100644 --- a/include/linux/platform_data/max310x.h +++ b/include/linux/platform_data/max310x.h @@ -21,7 +21,6 @@ * * static struct max310x_pdata max3107_pdata = { * .uart_flags[0] = MAX310X_ECHO_SUPRESS | MAX310X_AUTO_DIR_CTRL, - * .gpio_base = -1, * }; * * static struct spi_board_info spi_device_max3107[] = { @@ -45,8 +44,6 @@ struct max310x_pdata { #define MAX310X_AUTO_DIR_CTRL (0x00000004) /* Enable Auto direction * control (RS-485) */ - /* GPIO base number (can be negative) */ - const int gpio_base; }; #endif -- cgit v0.10.2 From 0fbae8874eea124591aee10efae98d244a2d072d Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Feb 2014 22:18:33 +0400 Subject: serial: max310x: Add missing mutex_destroy() on driver exit Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 2a12cbc..c180576 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1134,8 +1134,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->devtype = devtype; dev_set_drvdata(dev, s); - mutex_init(&s->mutex); - /* Check device to ensure we are talking to what we expect */ ret = devtype->detect(dev); if (ret) @@ -1193,6 +1191,8 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, goto out_uart; #endif + mutex_init(&s->mutex); + for (i = 0; i < devtype->nr; i++) { /* Initialize port data */ s->p[i].port.line = i; @@ -1233,6 +1233,8 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, dev_err(dev, "Unable to reguest IRQ %i\n", irq); + mutex_destroy(&s->mutex); + #ifdef CONFIG_GPIOLIB WARN_ON(gpiochip_remove(&s->gpio)); #endif @@ -1264,6 +1266,7 @@ static int max310x_remove(struct device *dev) s->devtype->power(&s->p[i].port, 0); } + mutex_destroy(&s->mutex); uart_unregister_driver(&s->uart); clk_disable_unprepare(s->clk); -- cgit v0.10.2 From 55367c620aed6bc27a82bb1763366931d7f2ee66 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Feb 2014 22:18:34 +0400 Subject: serial: max310x: Add support for RS-485 mode This patch adds support for RS-485 (TIOCSRS485/TIOCGRS485) IOCTLs. As a result this patch eliminate private driver header. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index c180576..090f25d 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -26,8 +26,6 @@ #include #include -#include - #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 @@ -293,7 +291,6 @@ struct max310x_port { struct regmap *regmap; struct mutex mutex; struct clk *clk; - struct max310x_pdata *pdata; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; #endif @@ -898,26 +895,70 @@ static void max310x_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); } +static int max310x_ioctl(struct uart_port *port, unsigned int cmd, + unsigned long arg) +{ + struct serial_rs485 rs485; + unsigned int val; + + switch (cmd) { + case TIOCSRS485: + if (copy_from_user(&rs485, (struct serial_rs485 *)arg, + sizeof(rs485))) + return -EFAULT; + if (rs485.delay_rts_before_send > 0x0f || + rs485.delay_rts_after_send > 0x0f) + return -ERANGE; + val = (rs485.delay_rts_before_send << 4) | + rs485.delay_rts_after_send; + max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val); + if (rs485.flags & SER_RS485_ENABLED) { + max310x_port_update(port, MAX310X_MODE1_REG, + MAX310X_MODE1_TRNSCVCTRL_BIT, + MAX310X_MODE1_TRNSCVCTRL_BIT); + max310x_port_update(port, MAX310X_MODE2_REG, + MAX310X_MODE2_ECHOSUPR_BIT, + MAX310X_MODE2_ECHOSUPR_BIT); + } else { + max310x_port_update(port, MAX310X_MODE1_REG, + MAX310X_MODE1_TRNSCVCTRL_BIT, 0); + max310x_port_update(port, MAX310X_MODE2_REG, + MAX310X_MODE2_ECHOSUPR_BIT, 0); + } + break; + case TIOCGRS485: + memset(&rs485, 0, sizeof(rs485)); + val = max310x_port_read(port, MAX310X_MODE1_REG); + rs485.flags = (val & MAX310X_MODE1_TRNSCVCTRL_BIT) ? + SER_RS485_ENABLED : 0; + rs485.flags |= SER_RS485_RTS_ON_SEND; + val = max310x_port_read(port, MAX310X_HDPIXDELAY_REG); + rs485.delay_rts_before_send = val >> 4; + rs485.delay_rts_after_send = val & 0x0f; + if (copy_to_user((struct serial_rs485 *)arg, &rs485, + sizeof(rs485))) + return -EFAULT; + break; + default: + return -ENOIOCTLCMD; + } + + return 0; +} + static int max310x_startup(struct uart_port *port) { - unsigned int val, line = port->line; struct max310x_port *s = dev_get_drvdata(port->dev); + unsigned int val; s->devtype->power(port, 1); /* Configure MODE1 register */ max310x_port_update(port, MAX310X_MODE1_REG, - MAX310X_MODE1_TRNSCVCTRL_BIT, - (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL) - ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0); + MAX310X_MODE1_TRNSCVCTRL_BIT, 0); - /* Configure MODE2 register */ - val = MAX310X_MODE2_RXEMPTINV_BIT; - if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS) - val |= MAX310X_MODE2_ECHOSUPR_BIT; - - /* Reset FIFOs */ - val |= MAX310X_MODE2_FIFORST_BIT; + /* Configure MODE2 register & Reset FIFOs*/ + val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT; max310x_port_write(port, MAX310X_MODE2_REG, val); max310x_port_update(port, MAX310X_MODE2_REG, MAX310X_MODE2_FIFORST_BIT, 0); @@ -998,6 +1039,7 @@ static const struct uart_ops max310x_ops = { .release_port = max310x_null_void, .config_port = max310x_config_port, .verify_port = max310x_verify_port, + .ioctl = max310x_ioctl, }; static int __maybe_unused max310x_suspend(struct device *dev) @@ -1077,7 +1119,6 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, struct regmap *regmap, int irq) { - struct max310x_pdata *pdata = dev_get_platdata(dev); int i, ret, fmin, fmax, freq, uartclk; struct clk *clk_osc, *clk_xtal; struct max310x_port *s; @@ -1086,11 +1127,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, if (IS_ERR(regmap)) return PTR_ERR(regmap); - if (!pdata) { - dev_err(dev, "No platform data supplied\n"); - return -EINVAL; - } - /* Alloc port structure */ s = devm_kzalloc(dev, sizeof(*s) + sizeof(struct max310x_one) * devtype->nr, GFP_KERNEL); @@ -1129,7 +1165,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, goto out_clk; } - s->pdata = pdata; s->regmap = regmap; s->devtype = devtype; dev_set_drvdata(dev, s); diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h deleted file mode 100644 index 1140a57..0000000 --- a/include/linux/platform_data/max310x.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver - * - * Copyright (C) 2012 Alexander Shiyan - * - * Based on max3100.c, by Christian Pellegrin - * Based on max3110.c, by Feng Tang - * Based on max3107.c, by Aavamobile - * - * 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 _MAX310X_H_ -#define _MAX310X_H_ - -/* - * Example board initialization data: - * - * static struct max310x_pdata max3107_pdata = { - * .uart_flags[0] = MAX310X_ECHO_SUPRESS | MAX310X_AUTO_DIR_CTRL, - * }; - * - * static struct spi_board_info spi_device_max3107[] = { - * { - * .modalias = "max3107", - * .irq = IRQ_EINT3, - * .bus_num = 1, - * .chip_select = 1, - * .platform_data = &max3107_pdata, - * }, - * }; - */ - -#define MAX310X_MAX_UARTS 4 - -/* MAX310X platform data structure */ -struct max310x_pdata { - /* Flags global to UART port */ - const u8 uart_flags[MAX310X_MAX_UARTS]; -#define MAX310X_ECHO_SUPRESS (0x00000002) /* Enable echo supress */ -#define MAX310X_AUTO_DIR_CTRL (0x00000004) /* Enable Auto direction - * control (RS-485) - */ -}; - -#endif -- cgit v0.10.2 From 5f529049cb044ed2cbea2599b246985912c0770d Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Feb 2014 22:18:35 +0400 Subject: serial: max310x: Driver cleanup This patch removes some unused definitions from driver code and sort #includes alphabetically. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 090f25d..e273854 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -13,17 +13,17 @@ * (at your option) any later version. */ -#include -#include -#include #include #include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include #include #define MAX310X_NAME "max310x" @@ -160,10 +160,6 @@ /* IRDA register bits */ #define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ #define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ -#define MAX310X_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */ -#define MAX310X_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */ -#define MAX310X_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */ -#define MAX310X_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */ /* Flow control trigger level register masks */ #define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ @@ -219,26 +215,6 @@ * XOFF2 */ -/* GPIO configuration register bits */ -#define MAX310X_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */ -#define MAX310X_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */ -#define MAX310X_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */ -#define MAX310X_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */ -#define MAX310X_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */ -#define MAX310X_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */ -#define MAX310X_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */ -#define MAX310X_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */ - -/* GPIO DATA register bits */ -#define MAX310X_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */ -#define MAX310X_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */ -#define MAX310X_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */ -#define MAX310X_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */ -#define MAX310X_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */ -#define MAX310X_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */ -#define MAX310X_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */ -#define MAX310X_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */ - /* PLL configuration register masks */ #define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */ #define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */ -- cgit v0.10.2 From 58afc909772c9bffef24f20618693f64e7cfe96f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Feb 2014 22:18:36 +0400 Subject: serial: max310x: Add devicetree support This patch adds devicetree support for the MAX310X serial driver. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e273854..8a035d6 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -1093,7 +1095,7 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, #endif static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, - struct regmap *regmap, int irq) + struct regmap *regmap, int irq, unsigned long flags) { int i, ret, fmin, fmax, freq, uartclk; struct clk *clk_osc, *clk_xtal; @@ -1237,8 +1239,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(dev), s); + IRQF_ONESHOT | flags, dev_name(dev), s); if (!ret) return 0; @@ -1284,6 +1285,15 @@ static int max310x_remove(struct device *dev) return ret; } +static const struct of_device_id __maybe_unused max310x_dt_ids[] = { + { .compatible = "maxim,max3107", .data = &max3107_devtype, }, + { .compatible = "maxim,max3108", .data = &max3108_devtype, }, + { .compatible = "maxim,max3109", .data = &max3109_devtype, }, + { .compatible = "maxim,max14830", .data = &max14830_devtype }, + { } +}; +MODULE_DEVICE_TABLE(of, max310x_dt_ids); + static struct regmap_config regcfg = { .reg_bits = 8, .val_bits = 8, @@ -1297,8 +1307,8 @@ static struct regmap_config regcfg = { #ifdef CONFIG_SPI_MASTER static int max310x_spi_probe(struct spi_device *spi) { - struct max310x_devtype *devtype = - (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; + struct max310x_devtype *devtype; + unsigned long flags = 0; struct regmap *regmap; int ret; @@ -1310,10 +1320,22 @@ static int max310x_spi_probe(struct spi_device *spi) if (ret) return ret; + if (spi->dev.of_node) { + const struct of_device_id *of_id = + of_match_device(max310x_dt_ids, &spi->dev); + + devtype = (struct max310x_devtype *)of_id->data; + } else { + const struct spi_device_id *id_entry = spi_get_device_id(spi); + + devtype = (struct max310x_devtype *)id_entry->driver_data; + flags = IRQF_TRIGGER_FALLING; + } + regcfg.max_register = devtype->nr * 0x20 - 1; regmap = devm_regmap_init_spi(spi, ®cfg); - return max310x_probe(&spi->dev, devtype, regmap, spi->irq); + return max310x_probe(&spi->dev, devtype, regmap, spi->irq, flags); } static int max310x_spi_remove(struct spi_device *spi) @@ -1332,9 +1354,10 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table); static struct spi_driver max310x_uart_driver = { .driver = { - .name = MAX310X_NAME, - .owner = THIS_MODULE, - .pm = &max310x_pm_ops, + .name = MAX310X_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max310x_dt_ids), + .pm = &max310x_pm_ops, }, .probe = max310x_spi_probe, .remove = max310x_spi_remove, -- cgit v0.10.2 From 05202872ca98f8ea61943a9b530417c5503b816f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Feb 2014 22:17:47 +0400 Subject: serial: max310x: Add bindings documentation for the MAX310X UARTs This patch adds the devicetree documentation for the Maxim MAX310X UARTs. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.txt b/Documentation/devicetree/bindings/serial/maxim,max310x.txt new file mode 100644 index 0000000..0daf780 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/maxim,max310x.txt @@ -0,0 +1,36 @@ +* Maxim MAX310X advanced Universal Asynchronous Receiver-Transmitter (UART) + +Required properties: +- compatible: Should be one of the following: + - "maxim,max3107" for Maxim MAX3107, + - "maxim,max3108" for Maxim MAX3108, + - "maxim,max3109" for Maxim MAX3109, + - "maxim,max14830" for Maxim MAX14830. +- reg: SPI chip select number. +- interrupt-parent: The phandle for the interrupt controller that + services interrupts for this IC. +- interrupts: Specifies the interrupt source of the parent interrupt + controller. The format of the interrupt specifier depends on the + parent interrupt controller. +- clocks: phandle to the IC source clock. +- clock-names: Should be "osc" if clock is an external crystal or + "xtal" if an external clock source is used. + +Optional properties: +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be two. The first cell is the GPIO number and + the second cell is used to specify the GPIO polarity: + 0 = active high, + 1 = active low. + +Example: + max14830: max14830@0 { + compatible = "maxim,max14830"; + reg = <0>; + clocks = <&clk20m>; + clock-names = "osc"; + interrupt-parent = <&gpio3>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + }; -- cgit v0.10.2 From 25e8d0ed75a6b3e7c2f533f0460a48f903d94269 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 11 Feb 2014 18:55:30 -0500 Subject: n_tty: Simplify input_available_p() Greg, Please note this patch requires n_tty: Fix poll() when TIME_CHAR and MIN_CHAR == 0 Regards, Peter Hurley Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index d15624c..41fe8a0 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1900,13 +1900,10 @@ static inline int input_available_p(struct tty_struct *tty, int poll) struct n_tty_data *ldata = tty->disc_data; int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1; - if (ldata->icanon && !L_EXTPROC(tty)) { - if (ldata->canon_head != ldata->read_tail) - return 1; - } else if (read_cnt(ldata) >= amt) - return 1; - - return 0; + if (ldata->icanon && !L_EXTPROC(tty)) + return ldata->canon_head != ldata->read_tail; + else + return read_cnt(ldata) >= amt; } /** -- cgit v0.10.2 From c972d806fddfb7852ce0d37d2ed14072b6de670b Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 22 Jan 2014 10:38:52 +0100 Subject: tty/serial: atmel_serial: remove dev_dbg in atmel_set_termios This fixes a driver bug which stopped the whole system (in case of serial console). This log message is not useful anyway as this information is printed elsewhere. Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index a49f10d..3d7206f 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1853,13 +1853,10 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, mode &= ~ATMEL_US_USMODE; if (atmel_port->rs485.flags & SER_RS485_ENABLED) { - dev_dbg(port->dev, "Setting UART to RS485\n"); if ((atmel_port->rs485.delay_rts_after_send) > 0) UART_PUT_TTGR(port, atmel_port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; - } else { - dev_dbg(port->dev, "Setting UART to RS232\n"); } /* set the parity, stop bits and data size */ -- cgit v0.10.2 From 2ad28e3efee21a5bbf940c83d1f0395b76bd3efb Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 22 Jan 2014 16:23:37 +0800 Subject: serial: imx: always wake up the processes in the TX callback The current code only wakes up the processes when the circle buffer has less data then the WAKEUP_CHARS. But sometimes, the circle buffer may has data more then the WAKEUP_CHARS, in such case, the processes will hang. This patch makes it always wakes up the processes in the TX callback. Signed-off-by: Huang Shijie Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d799140..dff0f0a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -496,8 +496,7 @@ static void dma_tx_callback(void *data) dev_dbg(sport->port.dev, "we finish the TX DMA.\n"); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); + uart_write_wakeup(&sport->port); if (waitqueue_active(&sport->dma_wait)) { wake_up(&sport->dma_wait); -- cgit v0.10.2 From e3c6ea9b1b81b87de96c01d5d37764009d546636 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 13 Feb 2014 22:08:28 +0400 Subject: serial: max310x: Fix build error config: make ARCH=alpha allyesconfig All error/warnings: drivers/tty/serial/max310x.c: In function 'max310x_ioctl': >> drivers/tty/serial/max310x.c:905:7: error: 'TIOCSRS485' undeclared (first use in this function) drivers/tty/serial/max310x.c:905:7: note: each undeclared identifier is reported only once for each function it appears in >> drivers/tty/serial/max310x.c:906:3: error: implicit declaration of function 'copy_from_user' [-Werror=implicit-function-declaration] >> drivers/tty/serial/max310x.c:929:7: error: 'TIOCGRS485' undeclared (first use in this function) >> drivers/tty/serial/max310x.c:938:3: error: implicit declaration of function 'copy_to_user' [-Werror=implicit-function-declaration] cc1: some warnings being treated as errors Reported-by: kbuild test robot Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 8a035d6..e49d88a 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -24,9 +24,10 @@ #include #include #include +#include #include #include -#include +#include #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 -- cgit v0.10.2 From d4f6b412ec2b2c02f9ad9cb972af44842d387924 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 13 Feb 2014 22:08:29 +0400 Subject: serial: max310x: Fix build warning config: x86_64-randconfig-x006 (attached as .config) All warnings: drivers/tty/serial/max310x.c: In function 'max310x_probe': >> drivers/tty/serial/max310x.c:1240:1: warning: label 'out_uart' defined but not used [-Wunused-label] Reported-by: kbuild test robot Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e49d88a..ef01d37 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1250,9 +1250,9 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, #ifdef CONFIG_GPIOLIB WARN_ON(gpiochip_remove(&s->gpio)); -#endif out_uart: +#endif uart_unregister_driver(&s->uart); out_clk: -- cgit v0.10.2 From 6f134c3c770355b7e930d3ffc558864668f13055 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Mon, 20 Jan 2014 14:32:34 +0530 Subject: serial: samsung: Move uart_register_driver call to device probe uart_register_driver call binds the driver to a specific device node through tty_register_driver call. This should typically happen during device probe call. In a multiplatform scenario, it is possible that multiple serial drivers are part of the kernel. Currently the driver registration fails if multiple serial drivers with same default major/minor numbers are included in the kernel. A typical case is observed with amba-pl011 and samsung-uart drivers. Signed-off-by: Tushar Behera Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 9cd706d..23f4596 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1282,6 +1282,14 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) if (ret < 0) goto probe_err; + if (!s3c24xx_uart_drv.state) { + ret = uart_register_driver(&s3c24xx_uart_drv); + if (ret < 0) { + pr_err("Failed to register Samsung UART driver\n"); + return ret; + } + } + dbg("%s: adding port\n", __func__); uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); platform_set_drvdata(pdev, &ourport->port); @@ -1321,6 +1329,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev) uart_remove_one_port(&s3c24xx_uart_drv, port); } + uart_unregister_driver(&s3c24xx_uart_drv); + return 0; } @@ -1820,35 +1830,7 @@ static struct platform_driver samsung_serial_driver = { }, }; -/* module initialisation code */ - -static int __init s3c24xx_serial_modinit(void) -{ - int ret; - - ret = uart_register_driver(&s3c24xx_uart_drv); - if (ret < 0) { - pr_err("Failed to register Samsung UART driver\n"); - return ret; - } - - ret = platform_driver_register(&samsung_serial_driver); - if (ret < 0) { - pr_err("Failed to register platform driver\n"); - uart_unregister_driver(&s3c24xx_uart_drv); - } - - return ret; -} - -static void __exit s3c24xx_serial_modexit(void) -{ - platform_driver_unregister(&samsung_serial_driver); - uart_unregister_driver(&s3c24xx_uart_drv); -} - -module_init(s3c24xx_serial_modinit); -module_exit(s3c24xx_serial_modexit); +module_platform_driver(samsung_serial_driver); MODULE_ALIAS("platform:samsung-uart"); MODULE_DESCRIPTION("Samsung SoC Serial port driver"); -- cgit v0.10.2 From ef2889f7ffee67f0aed49e854c72be63f1466759 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Mon, 20 Jan 2014 14:32:35 +0530 Subject: serial: pl011: Move uart_register_driver call to device probe uart_register_driver call binds the driver to a specific device node through tty_register_driver call. This should typically happen during device probe call. In a multiplatform scenario, it is possible that multiple serial drivers are part of the kernel. Currently the driver registration fails if multiple serial drivers with same default major/minor numbers are included in the kernel. A typical case is observed with amba-pl011 and samsung-uart drivers. Signed-off-by: Tushar Behera Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index d58783d..d4eda24 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2154,9 +2154,19 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) amba_ports[i] = uap; amba_set_drvdata(dev, uap); + + if (!amba_reg.state) { + ret = uart_register_driver(&amba_reg); + if (ret < 0) { + pr_err("Failed to register AMBA-PL011 driver\n"); + return ret; + } + } + ret = uart_add_one_port(&amba_reg, &uap->port); if (ret) { amba_ports[i] = NULL; + uart_unregister_driver(&amba_reg); pl011_dma_remove(uap); } out: @@ -2175,6 +2185,7 @@ static int pl011_remove(struct amba_device *dev) amba_ports[i] = NULL; pl011_dma_remove(uap); + uart_unregister_driver(&amba_reg); return 0; } @@ -2230,22 +2241,14 @@ static struct amba_driver pl011_driver = { static int __init pl011_init(void) { - int ret; printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); - ret = uart_register_driver(&amba_reg); - if (ret == 0) { - ret = amba_driver_register(&pl011_driver); - if (ret) - uart_unregister_driver(&amba_reg); - } - return ret; + return amba_driver_register(&pl011_driver); } static void __exit pl011_exit(void) { amba_driver_unregister(&pl011_driver); - uart_unregister_driver(&amba_reg); } /* -- cgit v0.10.2 From 9be16b38cf43181efc12ee6f467aaf222ad31b03 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Thu, 30 Jan 2014 13:57:29 +0800 Subject: serial: sirf: move to use generic dma dt-binding to get dma channels instead of using sirf specific dma channel property like "sirf,uart-dma-rx-channel" and "sirf,uart-dma-tx-channel", here we move to use generic dma dt-binding to get the channel like: - sirf,uart-dma-rx-channel = <21>; - sirf,uart-dma-tx-channel = <2>; + dmas = <&dmac1 5>, <&dmac0 2>; + dma-names = "rx", "tx"; and we move dma_request_channel() to dma_request_slave_channel(), we don't need to call sirfsoc dma filter function sirfsoc_dma_filter_id() again. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/boot/dts/atlas6.dtsi b/arch/arm/boot/dts/atlas6.dtsi index f8674bc..0c81dc9 100644 --- a/arch/arm/boot/dts/atlas6.dtsi +++ b/arch/arm/boot/dts/atlas6.dtsi @@ -217,8 +217,8 @@ interrupts = <17>; fifosize = <128>; clocks = <&clks 13>; - sirf,uart-dma-rx-channel = <21>; - sirf,uart-dma-tx-channel = <2>; + dmas = <&dmac1 5>, <&dmac0 2>; + dma-names = "rx", "tx"; }; uart1: uart@b0060000 { @@ -228,6 +228,7 @@ interrupts = <18>; fifosize = <32>; clocks = <&clks 14>; + dma-names = "no-rx", "no-tx"; }; uart2: uart@b0070000 { @@ -237,8 +238,8 @@ interrupts = <19>; fifosize = <128>; clocks = <&clks 15>; - sirf,uart-dma-rx-channel = <6>; - sirf,uart-dma-tx-channel = <7>; + dmas = <&dmac0 6>, <&dmac0 7>; + dma-names = "rx", "tx"; }; usp0: usp@b0080000 { @@ -248,8 +249,8 @@ interrupts = <20>; fifosize = <128>; clocks = <&clks 28>; - sirf,usp-dma-rx-channel = <17>; - sirf,usp-dma-tx-channel = <18>; + dmas = <&dmac1 1>, <&dmac1 2>; + dma-names = "rx", "tx"; }; usp1: usp@b0090000 { @@ -259,8 +260,8 @@ interrupts = <21>; fifosize = <128>; clocks = <&clks 29>; - sirf,usp-dma-rx-channel = <14>; - sirf,usp-dma-tx-channel = <15>; + dmas = <&dmac0 14>, <&dmac0 15>; + dma-names = "rx", "tx"; }; dmac0: dma-controller@b00b0000 { diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi index 0e21993..8582ae4 100644 --- a/arch/arm/boot/dts/prima2.dtsi +++ b/arch/arm/boot/dts/prima2.dtsi @@ -223,8 +223,8 @@ interrupts = <17>; fifosize = <128>; clocks = <&clks 13>; - sirf,uart-dma-rx-channel = <21>; - sirf,uart-dma-tx-channel = <2>; + dmas = <&dmac1 5>, <&dmac0 2>; + dma-names = "rx", "tx"; }; uart1: uart@b0060000 { @@ -243,8 +243,8 @@ interrupts = <19>; fifosize = <128>; clocks = <&clks 15>; - sirf,uart-dma-rx-channel = <6>; - sirf,uart-dma-tx-channel = <7>; + dmas = <&dmac0 6>, <&dmac0 7>; + dma-names = "rx", "tx"; }; usp0: usp@b0080000 { @@ -254,8 +254,8 @@ interrupts = <20>; fifosize = <128>; clocks = <&clks 28>; - sirf,usp-dma-rx-channel = <17>; - sirf,usp-dma-tx-channel = <18>; + dmas = <&dmac1 1>, <&dmac1 2>; + dma-names = "rx", "tx"; }; usp1: usp@b0090000 { @@ -265,8 +265,8 @@ interrupts = <21>; fifosize = <128>; clocks = <&clks 29>; - sirf,usp-dma-rx-channel = <14>; - sirf,usp-dma-tx-channel = <15>; + dmas = <&dmac0 14>, <&dmac0 15>; + dma-names = "rx", "tx"; }; usp2: usp@b00a0000 { @@ -276,8 +276,8 @@ interrupts = <22>; fifosize = <128>; clocks = <&clks 30>; - sirf,usp-dma-rx-channel = <10>; - sirf,usp-dma-tx-channel = <11>; + dmas = <&dmac0 10>, <&dmac0 11>; + dma-names = "rx", "tx"; }; dmac0: dma-controller@b00b0000 { diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index b7bfe24..68b0fd4 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -173,7 +172,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port) struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { + if (sirfport->tx_dma_chan) { if (sirfport->tx_dma_state == TX_DMA_RUNNING) { dmaengine_pause(sirfport->tx_dma_chan); sirfport->tx_dma_state = TX_DMA_PAUSE; @@ -288,7 +287,7 @@ static void sirfsoc_uart_start_tx(struct uart_port *port) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) + if (sirfport->tx_dma_chan) sirfsoc_uart_tx_with_dma(sirfport); else { sirfsoc_uart_pio_tx_chars(sirfport, 1); @@ -310,7 +309,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port) struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { + if (sirfport->rx_dma_chan) { if (!sirfport->is_marco) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) & @@ -675,7 +674,7 @@ recv_char: uart_handle_cts_change(port, cts_status); wake_up_interruptible(&state->port.delta_msr_wait); } - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { + if (sirfport->rx_dma_chan) { if (intr_status & uint_st->sirfsoc_rx_timeout) sirfsoc_uart_handle_rx_tmo(sirfport); if (intr_status & uint_st->sirfsoc_rx_done) @@ -686,7 +685,7 @@ recv_char: SIRFSOC_UART_IO_RX_MAX_CNT); } if (intr_status & uint_st->sirfsoc_txfifo_empty) { - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) + if (sirfport->tx_dma_chan) sirfsoc_uart_tx_with_dma(sirfport); else { if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { @@ -778,7 +777,7 @@ static void sirfsoc_uart_start_rx(struct uart_port *port) wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) + if (sirfport->rx_dma_chan) sirfsoc_uart_start_next_rx_dma(port); else { if (!sirfport->is_marco) @@ -1014,11 +1013,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, (sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) << SIRFSOC_USP_ASYNC_DIV2_OFFSET); } - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) + if (sirfport->tx_dma_chan) wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE); else wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE); - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) + if (sirfport->rx_dma_chan) wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE); else wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE); @@ -1049,93 +1048,6 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, clk_disable_unprepare(sirfport->clk); } -static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - dma_cap_mask_t dma_mask; - struct dma_slave_config tx_slv_cfg = { - .dst_maxburst = 2, - }; - - dma_cap_zero(dma_mask); - dma_cap_set(DMA_SLAVE, dma_mask); - sirfport->tx_dma_chan = dma_request_channel(dma_mask, - (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)sirfport->tx_dma_no); - if (!sirfport->tx_dma_chan) { - dev_err(port->dev, "Uart Request Dma Channel Fail %d\n", - sirfport->tx_dma_no); - return -EPROBE_DEFER; - } - dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); - - return 0; -} - -static unsigned int sirfsoc_uart_init_rx_dma(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - dma_cap_mask_t dma_mask; - int ret; - int i, j; - struct dma_slave_config slv_cfg = { - .src_maxburst = 2, - }; - - dma_cap_zero(dma_mask); - dma_cap_set(DMA_SLAVE, dma_mask); - sirfport->rx_dma_chan = dma_request_channel(dma_mask, - (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)sirfport->rx_dma_no); - if (!sirfport->rx_dma_chan) { - dev_err(port->dev, "Uart Request Dma Channel Fail %d\n", - sirfport->rx_dma_no); - ret = -EPROBE_DEFER; - goto request_err; - } - for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) { - sirfport->rx_dma_items[i].xmit.buf = - dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL); - if (!sirfport->rx_dma_items[i].xmit.buf) { - dev_err(port->dev, "Uart alloc bufa failed\n"); - ret = -ENOMEM; - goto alloc_coherent_err; - } - sirfport->rx_dma_items[i].xmit.head = - sirfport->rx_dma_items[i].xmit.tail = 0; - } - dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); - - return 0; -alloc_coherent_err: - for (j = 0; j < i; j++) - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items[j].xmit.buf, - sirfport->rx_dma_items[j].dma_addr); - dma_release_channel(sirfport->rx_dma_chan); -request_err: - return ret; -} - -static void sirfsoc_uart_uninit_tx_dma(struct sirfsoc_uart_port *sirfport) -{ - dmaengine_terminate_all(sirfport->tx_dma_chan); - dma_release_channel(sirfport->tx_dma_chan); -} - -static void sirfsoc_uart_uninit_rx_dma(struct sirfsoc_uart_port *sirfport) -{ - int i; - struct uart_port *port = &sirfport->port; - dmaengine_terminate_all(sirfport->rx_dma_chan); - dma_release_channel(sirfport->rx_dma_chan); - for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items[i].xmit.buf, - sirfport->rx_dma_items[i].dma_addr); -} - static int sirfsoc_uart_startup(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); @@ -1174,18 +1086,12 @@ static int sirfsoc_uart_startup(struct uart_port *port) wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port)); wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port)); - - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { - ret = sirfsoc_uart_init_rx_dma(port); - if (ret) - goto init_rx_err; + if (sirfport->rx_dma_chan) wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk, - SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) | - SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) | - SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b)); - } - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { - sirfsoc_uart_init_tx_dma(port); + SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) | + SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) | + SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b)); + if (sirfport->tx_dma_chan) { sirfport->tx_dma_state = TX_DMA_IDLE; wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk, SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) | @@ -1232,12 +1138,8 @@ static void sirfsoc_uart_shutdown(struct uart_port *port) gpio_set_value(sirfport->rts_gpio, 1); free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport); } - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) - sirfsoc_uart_uninit_rx_dma(sirfport); - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { - sirfsoc_uart_uninit_tx_dma(sirfport); + if (sirfport->tx_dma_chan) sirfport->tx_dma_state = TX_DMA_IDLE; - } } static const char *sirfsoc_uart_type(struct uart_port *port) @@ -1313,8 +1215,8 @@ sirfsoc_uart_console_setup(struct console *co, char *options) port->cons = co; /* default console tx/rx transfer using io mode */ - sirfport->rx_dma_no = UNVALID_DMA_CHAN; - sirfport->tx_dma_no = UNVALID_DMA_CHAN; + sirfport->rx_dma_chan = NULL; + sirfport->tx_dma_chan = NULL; return uart_set_options(port, co, baud, parity, bits, flow); } @@ -1382,6 +1284,13 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) struct uart_port *port; struct resource *res; int ret; + int i, j; + struct dma_slave_config slv_cfg = { + .src_maxburst = 2, + }; + struct dma_slave_config tx_slv_cfg = { + .dst_maxburst = 2, + }; const struct of_device_id *match; match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node); @@ -1402,27 +1311,10 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node, "sirf,uart-has-rtscts"); - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) { + if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) sirfport->uart_reg->uart_type = SIRF_REAL_UART; - if (of_property_read_u32(pdev->dev.of_node, - "sirf,uart-dma-rx-channel", - &sirfport->rx_dma_no)) - sirfport->rx_dma_no = UNVALID_DMA_CHAN; - if (of_property_read_u32(pdev->dev.of_node, - "sirf,uart-dma-tx-channel", - &sirfport->tx_dma_no)) - sirfport->tx_dma_no = UNVALID_DMA_CHAN; - } if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) { sirfport->uart_reg->uart_type = SIRF_USP_UART; - if (of_property_read_u32(pdev->dev.of_node, - "sirf,usp-dma-rx-channel", - &sirfport->rx_dma_no)) - sirfport->rx_dma_no = UNVALID_DMA_CHAN; - if (of_property_read_u32(pdev->dev.of_node, - "sirf,usp-dma-tx-channel", - &sirfport->tx_dma_no)) - sirfport->tx_dma_no = UNVALID_DMA_CHAN; if (!sirfport->hw_flow_ctrl) goto usp_no_flow_control; if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL)) @@ -1515,8 +1407,32 @@ usp_no_flow_control: goto port_err; } - return 0; + sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx"); + for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) { + sirfport->rx_dma_items[i].xmit.buf = + dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL); + if (!sirfport->rx_dma_items[i].xmit.buf) { + dev_err(port->dev, "Uart alloc bufa failed\n"); + ret = -ENOMEM; + goto alloc_coherent_err; + } + sirfport->rx_dma_items[i].xmit.head = + sirfport->rx_dma_items[i].xmit.tail = 0; + } + if (sirfport->rx_dma_chan) + dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); + sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx"); + if (sirfport->tx_dma_chan) + dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); + return 0; +alloc_coherent_err: + for (j = 0; j < i; j++) + dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + sirfport->rx_dma_items[j].xmit.buf, + sirfport->rx_dma_items[j].dma_addr); + dma_release_channel(sirfport->rx_dma_chan); port_err: clk_put(sirfport->clk); err: @@ -1529,6 +1445,19 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) struct uart_port *port = &sirfport->port; clk_put(sirfport->clk); uart_remove_one_port(&sirfsoc_uart_drv, port); + if (sirfport->rx_dma_chan) { + int i; + dmaengine_terminate_all(sirfport->rx_dma_chan); + dma_release_channel(sirfport->rx_dma_chan); + for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) + dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + sirfport->rx_dma_items[i].xmit.buf, + sirfport->rx_dma_items[i].dma_addr); + } + if (sirfport->tx_dma_chan) { + dmaengine_terminate_all(sirfport->tx_dma_chan); + dma_release_channel(sirfport->tx_dma_chan); + } return 0; } diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index b7d679c..8a6edda 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -392,9 +392,6 @@ struct sirfsoc_uart_register sirfsoc_uart = { /* Indicate how many buffers used */ #define SIRFSOC_RX_LOOP_BUF_CNT 2 -/* Indicate if DMA channel valid */ -#define IS_DMA_CHAN_VALID(x) ((x) != -1) -#define UNVALID_DMA_CHAN -1 /* For Fast Baud Rate Calculation */ struct sirfsoc_baudrate_to_regv { unsigned int baud_rate; @@ -423,8 +420,6 @@ struct sirfsoc_uart_port { /* for SiRFmarco, there are SET/CLR for UART_INT_EN */ bool is_marco; struct sirfsoc_uart_register *uart_reg; - int rx_dma_no; - int tx_dma_no; struct dma_chan *rx_dma_chan; struct dma_chan *tx_dma_chan; dma_addr_t tx_dma_addr; -- cgit v0.10.2 From f76a1cbed18c86e2d192455f0daebb48458965f3 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 14 Jan 2014 16:03:37 -0500 Subject: hvc: ensure hvc_init is only ever called once in hvc_console.c Commit 3e6c6f630a5282df8f3393a59f10eb9c56536d23 ("Delay creation of khcvd thread") moved the call of hvc_init from being a device_initcall into hvc_alloc, and used a non-null hvc_driver as indication of whether hvc_init had already been called. The problem with this is that hvc_driver is only assigned a value at the bottom of hvc_init, and so there is a window where multiple hvc_alloc calls can be in progress at the same time and hence try and call hvc_init multiple times. Previously the use of device_init guaranteed that hvc_init was only called once. This manifests itself as sporadic instances of two hvc_init calls racing each other, and with the loser of the race getting -EBUSY from tty_register_driver() and hence that virtual console fails: Couldn't register hvc console driver virtio-ports vport0p1: error -16 allocating hvc for port Here we add an atomic_t to guarantee we'll never run hvc_init twice. Cc: stable@vger.kernel.org # v2.6.24+ Cc: Rusty Russell Cc: Greg Kroah-Hartman Fixes: 3e6c6f630a52 ("Delay creation of khcvd thread") Reported-by: Jim Somerville Tested-by: Jim Somerville Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 50b4688..94f9e3a 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,9 @@ static struct task_struct *hvc_task; /* Picks up late kicks after list walk but before schedule() */ static int hvc_kicked; +/* hvc_init is triggered from hvc_alloc, i.e. only when actually used */ +static atomic_t hvc_needs_init __read_mostly = ATOMIC_INIT(-1); + static int hvc_init(void); #ifdef CONFIG_MAGIC_SYSRQ @@ -851,7 +855,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, int i; /* We wait until a driver actually comes along */ - if (!hvc_driver) { + if (atomic_inc_not_zero(&hvc_needs_init)) { int err = hvc_init(); if (err) return ERR_PTR(err); -- cgit v0.10.2 From 1456dad9bc9ca2e4a3a4b803a2b25b7fd84e2dae Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Feb 2014 15:18:57 -0800 Subject: Revert "serial: max310x: Fix build error" This reverts commit e3c6ea9b1b81b87de96c01d5d37764009d546636 as it didn't help anything, and caused more problems than expected. Reported-by: kbuild test robot Cc: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ef01d37..8dec480 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -24,10 +24,9 @@ #include #include #include -#include #include #include -#include +#include #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 -- cgit v0.10.2 From 86a41c46c7b5a1335b849f5e48d20184e4a905e1 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 13 Feb 2014 23:12:48 +0400 Subject: serial: max310x: Fix build error This is a temporary solution to fix following issue: config: make ARCH=alpha allyesconfig All error/warnings: drivers/tty/serial/max310x.c: In function 'max310x_ioctl': >> drivers/tty/serial/max310x.c:905:7: error: 'TIOCSRS485' undeclared (first use in this function) drivers/tty/serial/max310x.c:905:7: note: each undeclared identifier is reported only once for each function it appears in >> drivers/tty/serial/max310x.c:906:3: error: implicit declaration of function 'copy_from_user' [-Werror=implicit-function-declaration] >> drivers/tty/serial/max310x.c:929:7: error: 'TIOCGRS485' undeclared (first use in this function) >> drivers/tty/serial/max310x.c:938:3: error: implicit declaration of function 'copy_to_user' [-Werror=implicit-function-declaration] cc1: some warnings being treated as errors Reported-by: kbuild test robot Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 8dec480..5836168 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -876,6 +876,7 @@ static void max310x_set_termios(struct uart_port *port, static int max310x_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) { +#if defined(TIOCSRS485) && defined(TIOCGRS485) struct serial_rs485 rs485; unsigned int val; @@ -903,7 +904,7 @@ static int max310x_ioctl(struct uart_port *port, unsigned int cmd, max310x_port_update(port, MAX310X_MODE2_REG, MAX310X_MODE2_ECHOSUPR_BIT, 0); } - break; + return 0; case TIOCGRS485: memset(&rs485, 0, sizeof(rs485)); val = max310x_port_read(port, MAX310X_MODE1_REG); @@ -916,12 +917,13 @@ static int max310x_ioctl(struct uart_port *port, unsigned int cmd, if (copy_to_user((struct serial_rs485 *)arg, &rs485, sizeof(rs485))) return -EFAULT; - break; + return 0; default: - return -ENOIOCTLCMD; + break; } +#endif - return 0; + return -ENOIOCTLCMD; } static int max310x_startup(struct uart_port *port) -- cgit v0.10.2 From b2b2d6067db89afac3185de6e869766aa259731d Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 9 Feb 2014 14:22:55 +0100 Subject: tty: serial: crisv10: Drop remaining code for CRISv10 CPU simulator The Kconfig symbol SVINTO_SIM got dropped in commit e269a869417c ("Drop code for CRISv10 CPU simulator"). Now drop the remaining code for that simulator. Signed-off-by: Paul Bolle Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 690bdea..d567ac5 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -286,7 +286,6 @@ static struct e100_serial rs_table[] = { #endif }, /* ttyS0 */ -#ifndef CONFIG_SVINTO_SIM { .baud = DEF_BAUD, .ioport = (unsigned char *)R_SERIAL1_CTRL, .irq = 1U << 16, /* uses DMA 8 and 9 */ @@ -447,7 +446,6 @@ static struct e100_serial rs_table[] = { .dma_in_enabled = 0 #endif } /* ttyS3 */ -#endif }; @@ -1035,7 +1033,6 @@ cflag_to_etrax_baud(unsigned int cflag) static inline void e100_dtr(struct e100_serial *info, int set) { -#ifndef CONFIG_SVINTO_SIM unsigned char mask = e100_modem_pins[info->line].dtr_mask; #ifdef SERIAL_DEBUG_IO @@ -1060,7 +1057,6 @@ e100_dtr(struct e100_serial *info, int set) info->line, *e100_modem_pins[info->line].dtr_shadow, E100_DTR_GET(info)); #endif -#endif } /* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive @@ -1069,7 +1065,6 @@ e100_dtr(struct e100_serial *info, int set) static inline void e100_rts(struct e100_serial *info, int set) { -#ifndef CONFIG_SVINTO_SIM unsigned long flags; local_irq_save(flags); info->rx_ctrl &= ~E100_RTS_MASK; @@ -1079,7 +1074,6 @@ e100_rts(struct e100_serial *info, int set) #ifdef SERIAL_DEBUG_IO printk("ser%i rts %i\n", info->line, set); #endif -#endif } @@ -1087,7 +1081,6 @@ e100_rts(struct e100_serial *info, int set) static inline void e100_ri_out(struct e100_serial *info, int set) { -#ifndef CONFIG_SVINTO_SIM /* RI is active low */ { unsigned char mask = e100_modem_pins[info->line].ri_mask; @@ -1099,12 +1092,10 @@ e100_ri_out(struct e100_serial *info, int set) *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; local_irq_restore(flags); } -#endif } static inline void e100_cd_out(struct e100_serial *info, int set) { -#ifndef CONFIG_SVINTO_SIM /* CD is active low */ { unsigned char mask = e100_modem_pins[info->line].cd_mask; @@ -1116,27 +1107,22 @@ e100_cd_out(struct e100_serial *info, int set) *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; local_irq_restore(flags); } -#endif } static inline void e100_disable_rx(struct e100_serial *info) { -#ifndef CONFIG_SVINTO_SIM /* disable the receiver */ info->ioport[REG_REC_CTRL] = (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -#endif } static inline void e100_enable_rx(struct e100_serial *info) { -#ifndef CONFIG_SVINTO_SIM /* enable the receiver */ info->ioport[REG_REC_CTRL] = (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -#endif } /* the rx DMA uses both the dma_descr and the dma_eop interrupts */ @@ -1554,24 +1540,6 @@ transmit_chars_dma(struct e100_serial *info) unsigned int c, sentl; struct etrax_dma_descr *descr; -#ifdef CONFIG_SVINTO_SIM - /* This will output too little if tail is not 0 always since - * we don't reloop to send the other part. Anyway this SHOULD be a - * no-op - transmit_chars_dma would never really be called during sim - * since rs_write does not write into the xmit buffer then. - */ - if (info->xmit.tail) - printk("Error in serial.c:transmit_chars-dma(), tail!=0\n"); - if (info->xmit.head != info->xmit.tail) { - SIMCOUT(info->xmit.buf + info->xmit.tail, - CIRC_CNT(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE)); - info->xmit.head = info->xmit.tail; /* move back head */ - info->tr_running = 0; - } - return; -#endif /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ *info->oclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | @@ -1842,13 +1810,6 @@ static void receive_chars_dma(struct e100_serial *info) struct tty_struct *tty; unsigned char rstat; -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - return; -#endif - /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ *info->iclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | @@ -1934,12 +1895,6 @@ static int start_recv_dma(struct e100_serial *info) static void start_receive(struct e100_serial *info) { -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - return; -#endif if (info->uses_dma_in) { /* reset the input dma channel to be sure it works */ @@ -1972,17 +1927,6 @@ tr_interrupt(int irq, void *dev_id) int i; int handled = 0; -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - { - const char *s = "What? tr_interrupt in simulator??\n"; - SIMCOUT(s,strlen(s)); - } - return IRQ_HANDLED; -#endif - /* find out the line that caused this irq and get it from rs_table */ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ @@ -2021,17 +1965,6 @@ rec_interrupt(int irq, void *dev_id) int i; int handled = 0; -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - { - const char *s = "What? rec_interrupt in simulator??\n"; - SIMCOUT(s,strlen(s)); - } - return IRQ_HANDLED; -#endif - /* find out the line that caused this irq and get it from rs_table */ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ @@ -2173,10 +2106,6 @@ timed_flush_handler(unsigned long ptr) struct e100_serial *info; int i; -#ifdef CONFIG_SVINTO_SIM - return; -#endif - for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; if (info->uses_dma_in) @@ -2729,25 +2658,6 @@ startup(struct e100_serial * info) printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf); #endif -#ifdef CONFIG_SVINTO_SIM - /* Bits and pieces collected from below. Better to have them - in one ifdef:ed clause than to mix in a lot of ifdefs, - right? */ - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->xmit.head = info->xmit.tail = 0; - info->first_recv_buffer = info->last_recv_buffer = NULL; - info->recv_cnt = info->max_recv_cnt = 0; - - for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) - info->rec_descr[i].buf = NULL; - - /* No real action in the simulator, but may set info important - to ioctl. */ - change_speed(info); -#else - /* * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) @@ -2837,8 +2747,6 @@ startup(struct e100_serial * info) e100_rts(info, 1); e100_dtr(info, 1); -#endif /* CONFIG_SVINTO_SIM */ - info->port.flags |= ASYNC_INITIALIZED; local_irq_restore(flags); @@ -2857,7 +2765,6 @@ shutdown(struct e100_serial * info) struct etrax_recv_buffer *buffer; int i; -#ifndef CONFIG_SVINTO_SIM /* shut down the transmitter and receiver */ DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line)); e100_disable_rx(info); @@ -2882,8 +2789,6 @@ shutdown(struct e100_serial * info) info->tr_running = 0; } -#endif /* CONFIG_SVINTO_SIM */ - if (!(info->port.flags & ASYNC_INITIALIZED)) return; @@ -2995,17 +2900,12 @@ change_speed(struct e100_serial *info) IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); r_alt_ser_baudrate_shadow &= ~mask; r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); -#ifndef CONFIG_SVINTO_SIM *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; -#endif /* CONFIG_SVINTO_SIM */ info->baud = cflag_to_baud(cflag); -#ifndef CONFIG_SVINTO_SIM info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); -#endif /* CONFIG_SVINTO_SIM */ } -#ifndef CONFIG_SVINTO_SIM /* start with default settings and then fill in changes */ local_irq_save(flags); /* 8 bit, no/even parity */ @@ -3073,7 +2973,6 @@ change_speed(struct e100_serial *info) *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; local_irq_restore(flags); -#endif /* !CONFIG_SVINTO_SIM */ update_char_time(info); @@ -3122,11 +3021,6 @@ static int rs_raw_write(struct tty_struct *tty, count, info->ioport[REG_STATUS]); #endif -#ifdef CONFIG_SVINTO_SIM - /* Really simple. The output is here and now. */ - SIMCOUT(buf, count); - return count; -#endif local_save_flags(flags); DFLOW(DEBUG_LOG(info->line, "write count %i ", count)); DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty))); @@ -3463,7 +3357,6 @@ static int get_lsr_info(struct e100_serial * info, unsigned int *value) { unsigned int result = TIOCSER_TEMT; -#ifndef CONFIG_SVINTO_SIM unsigned long curr_time = jiffies; unsigned long curr_time_usec = GET_JIFFIES_USEC(); unsigned long elapsed_usec = @@ -3474,7 +3367,6 @@ get_lsr_info(struct e100_serial * info, unsigned int *value) elapsed_usec < 2*info->char_time_usec) { result = 0; } -#endif if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -3804,7 +3696,6 @@ rs_close(struct tty_struct *tty, struct file * filp) e100_disable_serial_data_irq(info); #endif -#ifndef CONFIG_SVINTO_SIM e100_disable_rx(info); e100_disable_rx_irq(info); @@ -3816,7 +3707,6 @@ rs_close(struct tty_struct *tty, struct file * filp) */ rs_wait_until_sent(tty, HZ); } -#endif shutdown(info); rs_flush_buffer(tty); @@ -4479,7 +4369,6 @@ static int __init rs_init(void) fast_timer_init(); #endif -#ifndef CONFIG_SVINTO_SIM #ifndef CONFIG_ETRAX_KGDB /* Not needed in simulator. May only complicate stuff. */ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ @@ -4489,7 +4378,6 @@ static int __init rs_init(void) panic("%s: Failed to request irq8", __func__); #endif -#endif /* CONFIG_SVINTO_SIM */ return 0; } -- cgit v0.10.2 From 0fd927f578e96fe56f1acbfe97e6c71e6c3a4b11 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 15 Feb 2014 14:59:01 +0400 Subject: serial: max310x: Fix sparse warnings sparse warnings: (new ones prefixed by >>) >> drivers/tty/serial/max310x.c:906:45: sparse: incorrect type in argument 2 (different address spaces) drivers/tty/serial/max310x.c:906:45: expected void const [noderef] *from drivers/tty/serial/max310x.c:906:45: got struct serial_rs485 * >> drivers/tty/serial/max310x.c:938:35: sparse: incorrect type in argument 1 (different address spaces) drivers/tty/serial/max310x.c:938:35: expected void [noderef] *to drivers/tty/serial/max310x.c:938:35: got struct serial_rs485 * Reported-by: kbuild test robot Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 5836168..471dbc1 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -882,8 +882,7 @@ static int max310x_ioctl(struct uart_port *port, unsigned int cmd, switch (cmd) { case TIOCSRS485: - if (copy_from_user(&rs485, (struct serial_rs485 *)arg, - sizeof(rs485))) + if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485))) return -EFAULT; if (rs485.delay_rts_before_send > 0x0f || rs485.delay_rts_after_send > 0x0f) @@ -914,8 +913,7 @@ static int max310x_ioctl(struct uart_port *port, unsigned int cmd, val = max310x_port_read(port, MAX310X_HDPIXDELAY_REG); rs485.delay_rts_before_send = val >> 4; rs485.delay_rts_after_send = val & 0x0f; - if (copy_to_user((struct serial_rs485 *)arg, &rs485, - sizeof(rs485))) + if (copy_to_user((void __user *)arg, &rs485, sizeof(rs485))) return -EFAULT; return 0; default: -- cgit v0.10.2 From c600558668e4ebd0fab6bf1d90baaf95bc43f9d5 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 15 Feb 2014 14:59:02 +0400 Subject: serial: max310x: Fix devicetree documentation for clock name Clock names mistakenly given opposite. This patch fix this issue. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.txt b/Documentation/devicetree/bindings/serial/maxim,max310x.txt index 0daf780..83a919c 100644 --- a/Documentation/devicetree/bindings/serial/maxim,max310x.txt +++ b/Documentation/devicetree/bindings/serial/maxim,max310x.txt @@ -13,8 +13,8 @@ Required properties: controller. The format of the interrupt specifier depends on the parent interrupt controller. - clocks: phandle to the IC source clock. -- clock-names: Should be "osc" if clock is an external crystal or - "xtal" if an external clock source is used. +- clock-names: Should be "xtal" if clock is an external crystal or + "osc" if an external clock source is used. Optional properties: - gpio-controller: Marks the device node as a GPIO controller. -- cgit v0.10.2 From c957dd494615ccdb36d4892ef9bfd2287502fbfd Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 17 Feb 2014 15:19:18 +0530 Subject: tty: tty_ldisc.h: Remove duplicate include linux/wait.h was included twice. Signed-off-by: Sachin Kamat Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index b8347c2..add26da 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -126,7 +126,6 @@ #include #include -#include /* -- cgit v0.10.2 From f1cd8c8792ccc7e9520ef8f27fbdb748448ac482 Mon Sep 17 00:00:00 2001 From: Yuan Yao Date: Mon, 17 Feb 2014 13:28:07 +0800 Subject: serial: fsl_lpuart: add DMA support Add dma support for lpuart. This function depend on DMA driver. You can turn on it by write both the dmas and dma-name properties in dts node. Signed-off-by: Yuan Yao Acked-by: Arnd Bergmann Acked-by: Mark Rutland Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt index 6fd1dd1..b06e305 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt @@ -5,10 +5,19 @@ Required properties: - reg : Address and length of the register set for the device - interrupts : Should contain uart interrupt +Optional properties: +- dmas: A list of two dma specifiers, one for each entry in dma-names. +- dma-names: should contain "tx" and "rx". + +Note: Optional properties for DMA support. Write them both or both not. + Example: uart0: serial@40027000 { - compatible = "fsl,vf610-lpuart"; - reg = <0x40027000 0x1000>; - interrupts = <0 61 0x00>; - }; + compatible = "fsl,vf610-lpuart"; + reg = <0x40027000 0x1000>; + interrupts = <0 61 0x00>; + dmas = <&edma0 0 2>, + <&edma0 0 3>; + dma-names = "rx","tx"; + }; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 8978dc9..c5eb897 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -13,14 +13,19 @@ #define SUPPORT_SYSRQ #endif -#include +#include +#include +#include +#include +#include #include #include -#include +#include #include #include -#include +#include #include +#include #include /* All registers are 8-bit width */ @@ -112,6 +117,10 @@ #define UARTSFIFO_TXOF 0x02 #define UARTSFIFO_RXUF 0x01 +#define DMA_MAXBURST 16 +#define DMA_MAXBURST_MASK (DMA_MAXBURST - 1) +#define FSL_UART_RX_DMA_BUFFER_SIZE 64 + #define DRIVER_NAME "fsl-lpuart" #define DEV_NAME "ttyLP" #define UART_NR 6 @@ -121,6 +130,24 @@ struct lpuart_port { struct clk *clk; unsigned int txfifo_size; unsigned int rxfifo_size; + + bool lpuart_dma_use; + struct dma_chan *dma_tx_chan; + struct dma_chan *dma_rx_chan; + struct dma_async_tx_descriptor *dma_tx_desc; + struct dma_async_tx_descriptor *dma_rx_desc; + dma_addr_t dma_tx_buf_bus; + dma_addr_t dma_rx_buf_bus; + dma_cookie_t dma_tx_cookie; + dma_cookie_t dma_rx_cookie; + unsigned char *dma_tx_buf_virt; + unsigned char *dma_rx_buf_virt; + unsigned int dma_tx_bytes; + unsigned int dma_rx_bytes; + int dma_tx_in_progress; + int dma_rx_in_progress; + unsigned int dma_rx_timeout; + struct timer_list lpuart_timer; }; static struct of_device_id lpuart_dt_ids[] = { @@ -131,6 +158,10 @@ static struct of_device_id lpuart_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, lpuart_dt_ids); +/* Forward declare this for the dma callbacks*/ +static void lpuart_dma_tx_complete(void *arg); +static void lpuart_dma_rx_complete(void *arg); + static void lpuart_stop_tx(struct uart_port *port) { unsigned char temp; @@ -152,6 +183,210 @@ static void lpuart_enable_ms(struct uart_port *port) { } +static void lpuart_copy_rx_to_tty(struct lpuart_port *sport, + struct tty_port *tty, int count) +{ + int copied; + + sport->port.icount.rx += count; + + if (!tty) { + dev_err(sport->port.dev, "No tty port\n"); + return; + } + + dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + copied = tty_insert_flip_string(tty, + ((unsigned char *)(sport->dma_rx_buf_virt)), count); + + if (copied != count) { + WARN_ON(1); + dev_err(sport->port.dev, "RxData copy to tty layer failed\n"); + } + + dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); +} + +static void lpuart_pio_tx(struct lpuart_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + + while (!uart_circ_empty(xmit) && + readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) { + writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (uart_circ_empty(xmit)) + writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, + sport->port.membase + UARTCR5); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + dma_addr_t tx_bus_addr; + + dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus, + UART_XMIT_SIZE, DMA_TO_DEVICE); + sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK); + tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail; + sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan, + tx_bus_addr, sport->dma_tx_bytes, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); + + if (!sport->dma_tx_desc) { + dev_err(sport->port.dev, "Not able to get desc for tx\n"); + return -EIO; + } + + sport->dma_tx_desc->callback = lpuart_dma_tx_complete; + sport->dma_tx_desc->callback_param = sport; + sport->dma_tx_in_progress = 1; + sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc); + dma_async_issue_pending(sport->dma_tx_chan); + + return 0; +} + +static void lpuart_prepare_tx(struct lpuart_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long count = CIRC_CNT_TO_END(xmit->head, + xmit->tail, UART_XMIT_SIZE); + + if (!count) + return; + + if (count < DMA_MAXBURST) + writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS, + sport->port.membase + UARTCR5); + else { + writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, + sport->port.membase + UARTCR5); + lpuart_dma_tx(sport, count); + } +} + +static void lpuart_dma_tx_complete(void *arg) +{ + struct lpuart_port *sport = arg; + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long flags; + + async_tx_ack(sport->dma_tx_desc); + + spin_lock_irqsave(&sport->port.lock, flags); + + xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1); + sport->dma_tx_in_progress = 0; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + lpuart_prepare_tx(sport); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int lpuart_dma_rx(struct lpuart_port *sport) +{ + dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); + sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan, + sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + + if (!sport->dma_rx_desc) { + dev_err(sport->port.dev, "Not able to get desc for rx\n"); + return -EIO; + } + + sport->dma_rx_desc->callback = lpuart_dma_rx_complete; + sport->dma_rx_desc->callback_param = sport; + sport->dma_rx_in_progress = 1; + sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); + dma_async_issue_pending(sport->dma_rx_chan); + + return 0; +} + +static void lpuart_dma_rx_complete(void *arg) +{ + struct lpuart_port *sport = arg; + struct tty_port *port = &sport->port.state->port; + unsigned long flags; + + async_tx_ack(sport->dma_rx_desc); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->dma_rx_in_progress = 0; + lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE); + tty_flip_buffer_push(port); + lpuart_dma_rx(sport); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static void lpuart_timer_func(unsigned long data) +{ + struct lpuart_port *sport = (struct lpuart_port *)data; + struct tty_port *port = &sport->port.state->port; + struct dma_tx_state state; + unsigned long flags; + unsigned char temp; + int count; + + del_timer(&sport->lpuart_timer); + dmaengine_pause(sport->dma_rx_chan); + dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state); + dmaengine_terminate_all(sport->dma_rx_chan); + count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue; + async_tx_ack(sport->dma_rx_desc); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->dma_rx_in_progress = 0; + lpuart_copy_rx_to_tty(sport, port, count); + tty_flip_buffer_push(port); + temp = readb(sport->port.membase + UARTCR5); + writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static inline void lpuart_prepare_rx(struct lpuart_port *sport) +{ + unsigned long flags; + unsigned char temp; + + spin_lock_irqsave(&sport->port.lock, flags); + + init_timer(&sport->lpuart_timer); + sport->lpuart_timer.function = lpuart_timer_func; + sport->lpuart_timer.data = (unsigned long)sport; + sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; + add_timer(&sport->lpuart_timer); + + lpuart_dma_rx(sport); + temp = readb(sport->port.membase + UARTCR5); + writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + static inline void lpuart_transmit_buffer(struct lpuart_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; @@ -172,14 +407,21 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport) static void lpuart_start_tx(struct uart_port *port) { - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct circ_buf *xmit = &sport->port.state->xmit; unsigned char temp; temp = readb(port->membase + UARTCR2); writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); - if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) - lpuart_transmit_buffer(sport); + if (sport->lpuart_dma_use) { + if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress) + lpuart_prepare_tx(sport); + } else { + if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) + lpuart_transmit_buffer(sport); + } } static irqreturn_t lpuart_txint(int irq, void *dev_id) @@ -279,12 +521,19 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) sts = readb(sport->port.membase + UARTSR1); - if (sts & UARTSR1_RDRF) - lpuart_rxint(irq, dev_id); - + if (sts & UARTSR1_RDRF) { + if (sport->lpuart_dma_use) + lpuart_prepare_rx(sport); + else + lpuart_rxint(irq, dev_id); + } if (sts & UARTSR1_TDRE && - !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) - lpuart_txint(irq, dev_id); + !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) { + if (sport->lpuart_dma_use) + lpuart_pio_tx(sport); + else + lpuart_txint(irq, dev_id); + } return IRQ_HANDLED; } @@ -366,13 +615,156 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); - writeb(2, sport->port.membase + UARTTWFIFO); + writeb(0, sport->port.membase + UARTTWFIFO); writeb(1, sport->port.membase + UARTRWFIFO); /* Restore cr2 */ writeb(cr2_saved, sport->port.membase + UARTCR2); } +static int lpuart_dma_tx_request(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_chan *tx_chan; + struct dma_slave_config dma_tx_sconfig; + dma_addr_t dma_bus; + unsigned char *dma_buf; + int ret; + + tx_chan = dma_request_slave_channel(sport->port.dev, "tx"); + + if (!tx_chan) { + dev_err(sport->port.dev, "Dma tx channel request failed!\n"); + return -ENODEV; + } + + dma_bus = dma_map_single(tx_chan->device->dev, + sport->port.state->xmit.buf, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + if (dma_mapping_error(tx_chan->device->dev, dma_bus)) { + dev_err(sport->port.dev, "dma_map_single tx failed\n"); + dma_release_channel(tx_chan); + return -ENOMEM; + } + + dma_buf = sport->port.state->xmit.buf; + dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; + dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_tx_sconfig.dst_maxburst = DMA_MAXBURST; + dma_tx_sconfig.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig); + + if (ret < 0) { + dev_err(sport->port.dev, + "Dma slave config failed, err = %d\n", ret); + dma_release_channel(tx_chan); + return ret; + } + + sport->dma_tx_chan = tx_chan; + sport->dma_tx_buf_virt = dma_buf; + sport->dma_tx_buf_bus = dma_bus; + sport->dma_tx_in_progress = 0; + + return 0; +} + +static int lpuart_dma_rx_request(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_chan *rx_chan; + struct dma_slave_config dma_rx_sconfig; + dma_addr_t dma_bus; + unsigned char *dma_buf; + int ret; + + rx_chan = dma_request_slave_channel(sport->port.dev, "rx"); + + if (!rx_chan) { + dev_err(sport->port.dev, "Dma rx channel request failed!\n"); + return -ENODEV; + } + + dma_buf = devm_kzalloc(sport->port.dev, + FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL); + + if (!dma_buf) { + dev_err(sport->port.dev, "Dma rx alloc failed\n"); + dma_release_channel(rx_chan); + return -ENOMEM; + } + + dma_bus = dma_map_single(rx_chan->device->dev, dma_buf, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + + if (dma_mapping_error(rx_chan->device->dev, dma_bus)) { + dev_err(sport->port.dev, "dma_map_single rx failed\n"); + dma_release_channel(rx_chan); + return -ENOMEM; + } + + dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR; + dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_rx_sconfig.src_maxburst = 1; + dma_rx_sconfig.direction = DMA_DEV_TO_MEM; + ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig); + + if (ret < 0) { + dev_err(sport->port.dev, + "Dma slave config failed, err = %d\n", ret); + dma_release_channel(rx_chan); + return ret; + } + + sport->dma_rx_chan = rx_chan; + sport->dma_rx_buf_virt = dma_buf; + sport->dma_rx_buf_bus = dma_bus; + sport->dma_rx_in_progress = 0; + + sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) * + FSL_UART_RX_DMA_BUFFER_SIZE * 3 / + sport->rxfifo_size / 2; + + if (sport->dma_rx_timeout < msecs_to_jiffies(20)) + sport->dma_rx_timeout = msecs_to_jiffies(20); + + return 0; +} + +static void lpuart_dma_tx_free(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_chan *dma_chan; + + dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus, + UART_XMIT_SIZE, DMA_TO_DEVICE); + dma_chan = sport->dma_tx_chan; + sport->dma_tx_chan = NULL; + sport->dma_tx_buf_bus = 0; + sport->dma_tx_buf_virt = NULL; + dma_release_channel(dma_chan); +} + +static void lpuart_dma_rx_free(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_chan *dma_chan; + + dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + + dma_chan = sport->dma_rx_chan; + sport->dma_rx_chan = NULL; + sport->dma_rx_buf_bus = 0; + sport->dma_rx_buf_virt = NULL; + dma_release_channel(dma_chan); +} + static int lpuart_startup(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); @@ -380,6 +772,15 @@ static int lpuart_startup(struct uart_port *port) unsigned long flags; unsigned char temp; + /*whether use dma support by dma request results*/ + if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) { + sport->lpuart_dma_use = false; + } else { + sport->lpuart_dma_use = true; + temp = readb(port->membase + UARTCR5); + writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5); + } + ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0, DRIVER_NAME, sport); if (ret) @@ -414,6 +815,11 @@ static void lpuart_shutdown(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); devm_free_irq(port->dev, port->irq, sport); + + if (sport->lpuart_dma_use) { + lpuart_dma_tx_free(port); + lpuart_dma_rx_free(port); + } } static void -- cgit v0.10.2 From 12f287878afc39acea00b3e62baf72c79878c427 Mon Sep 17 00:00:00 2001 From: Yuan Yao Date: Mon, 17 Feb 2014 13:28:08 +0800 Subject: serial: fsl_lpuart: documented the clock requirement. This is a correction to the documentation. It was previously required but not documented. Signed-off-by: Yuan Yao Acked-by: Mark Rutland Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt index b06e305..a1d1205 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt @@ -4,6 +4,8 @@ Required properties: - compatible : Should be "fsl,-lpuart" - reg : Address and length of the register set for the device - interrupts : Should contain uart interrupt +- clocks : phandle + clock specifier pairs, one for each entry in clock-names +- clock-names : should contain: "ipg" - the uart clock Optional properties: - dmas: A list of two dma specifiers, one for each entry in dma-names. @@ -17,6 +19,8 @@ uart0: serial@40027000 { compatible = "fsl,vf610-lpuart"; reg = <0x40027000 0x1000>; interrupts = <0 61 0x00>; + clocks = <&clks VF610_CLK_UART0>; + clock-names = "ipg"; dmas = <&edma0 0 2>, <&edma0 0 3>; dma-names = "rx","tx"; -- cgit v0.10.2 From bd2fe272a8ec3841189e07a9a8e9879fe26a3cdc Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 19 Feb 2014 15:00:13 -0500 Subject: drivers/tty/serial: deal with 8250_core.c uninitialized warning for good Every couple of months, someone sends a patch to fix: drivers/tty/serial/8250/8250_core.c: In function 'serial_unlink_irq_chain': drivers/tty/serial/8250/8250_core.c:1712:2: warning: 'i' may be used uninitialized in this function [-Wuninitialized] and they in turn get a NACK for their efforts, and are told that their compiler is broken. This has been going on since at least the year 2008: https://lkml.org/lkml/2008/11/24/433 Lets add a comment, so that subsequent patches don't get as far as the maintainers or the mailing lists. Acked-by: Alan Cox Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 69932b7..747073b 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1694,6 +1694,10 @@ static int serial_link_irq_chain(struct uart_8250_port *up) static void serial_unlink_irq_chain(struct uart_8250_port *up) { + /* + * yes, some broken gcc emit "warning: 'i' may be used uninitialized" + * but no, we are not going to take a patch that assigns NULL below. + */ struct irq_info *i; struct hlist_node *n; struct hlist_head *h; -- cgit v0.10.2 From b290af68de57196e7cb34805f41cd3416ed1a791 Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Wed, 19 Feb 2014 01:40:16 +0100 Subject: vt: drop an useless enum and assignment. Signed-off-by: Adam Borowski Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 23b5d32..b7bde54 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1590,7 +1590,7 @@ static void restore_cur(struct vc_data *vc) vc->vc_need_wrap = 0; } -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey, EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, ESpalette }; @@ -1807,9 +1807,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_par[vc->vc_npar] *= 10; vc->vc_par[vc->vc_npar] += c - '0'; return; - } else - vc->vc_state = ESgotpars; - case ESgotpars: + } vc->vc_state = ESnormal; switch(c) { case 'h': -- cgit v0.10.2 From 63f3a16db915096d7a80a96748adba00feb07a32 Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Wed, 19 Feb 2014 01:38:04 +0100 Subject: vt: detect and ignore OSC codes. These can be used to send commands consisting of an arbitrary string to the terminal, most often used to set a terminal's window title or to redefine the colour palette. Our console doesn't use OSC, unlike everything else, which can lead to junk being displayed if a process sends such a code unconditionally. The rules for termination follow established practice rather than Ecma-48. Ecma-48 requires the string to use only byte values 0x08..0x0D and 0x20..0x7E, terminated with either ESC \ or 0x9C. This would disallow using 8-bit characters, which are reasonable for example in window titles. A widespread idiom is to terminate with 0x07. The behaviour for other control characters differs between terminal emulators, I followed libvte and xterm: * 0x07 and ESC anything terminate * nothing else terminates, all 8-bit values including 0x9C are considered a part of the string Signed-off-by: Adam Borowski Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index b7bde54..3ad0b61 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1592,7 +1592,7 @@ static void restore_cur(struct vc_data *vc) enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey, EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, - ESpalette }; + ESpalette, ESosc }; /* console_lock is held (except via vc_init()) */ static void reset_terminal(struct vc_data *vc, int do_clear) @@ -1652,11 +1652,15 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) * Control characters can be used in the _middle_ * of an escape sequence. */ + if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */ + return; switch (c) { case 0: return; case 7: - if (vc->vc_bell_duration) + if (vc->vc_state == ESosc) + vc->vc_state = ESnormal; + else if (vc->vc_bell_duration) kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration); return; case 8: @@ -1767,7 +1771,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) } else if (c=='R') { /* reset palette */ reset_palette(vc); vc->vc_state = ESnormal; - } else + } else if (c>='0' && c<='9') + vc->vc_state = ESosc; + else vc->vc_state = ESnormal; return; case ESpalette: @@ -2021,6 +2027,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_translate = set_translate(vc->vc_G1_charset, vc); vc->vc_state = ESnormal; return; + case ESosc: + return; default: vc->vc_state = ESnormal; } -- cgit v0.10.2 From f04430ceadbf92e142208cf58904a930417c6480 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Feb 2014 10:15:51 -0800 Subject: tty: serial: bcm63xx_uart: include linux/io.h Include linux/io.h which provides the definition for __raw_{readl,writel}, this is not necessary on MIPS since there is an implicit inclusion, but it is on ARM for instance. Signed-off-by: Florian Fainelli Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 78e82b0..d71143e 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -30,6 +30,7 @@ #include #include #include +#include #define BCM63XX_NR_UARTS 2 -- cgit v0.10.2 From 5811712ffbf593d98b6cc56461df5be4e9580245 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Feb 2014 10:15:52 -0800 Subject: tty: serial: bcm63xx_uart: define UART_REG_SIZE constant The bcm63xx_uart driver uses RSET_UART_SIZE which is a constant defined for MIPS-based BCM63xx platforms, pull this constant value from the MIPS-specific header and put it in include/linux/serial_bcm63xx.h to make the driver platform agnostic. Signed-off-by: Florian Fainelli Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index d71143e..37e7e33 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -589,7 +589,7 @@ static int bcm_uart_request_port(struct uart_port *port) { unsigned int size; - size = RSET_UART_SIZE; + size = UART_REG_SIZE; if (!request_mem_region(port->mapbase, size, "bcm63xx")) { dev_err(port->dev, "Memory region busy\n"); return -EBUSY; @@ -609,7 +609,7 @@ static int bcm_uart_request_port(struct uart_port *port) */ static void bcm_uart_release_port(struct uart_port *port) { - release_mem_region(port->mapbase, RSET_UART_SIZE); + release_mem_region(port->mapbase, UART_REG_SIZE); iounmap(port->membase); } diff --git a/include/linux/serial_bcm63xx.h b/include/linux/serial_bcm63xx.h index 570e964..a80aa1a 100644 --- a/include/linux/serial_bcm63xx.h +++ b/include/linux/serial_bcm63xx.h @@ -116,4 +116,6 @@ UART_FIFO_PARERR_MASK | \ UART_FIFO_BRKDET_MASK) +#define UART_REG_SIZE 24 + #endif /* _LINUX_SERIAL_BCM63XX_H */ -- cgit v0.10.2 From 9277285f98f08522e646211e32adbdb6ae2469a1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Feb 2014 10:15:53 -0800 Subject: tty: serial: bcm63xx_uart: add support for DT probing Add a matching table for the the bcm63xx_uart driver on the compatible string "brcm,bcm6345-uart" which covers all BCM63xx implementations and reflects the fact that this block was first introduced with the BCM6345 SoC. Also make sure that we convert the id based on the uart aliases provided by the relevant Device Tree. Signed-off-by: Florian Fainelli Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 37e7e33..a47421e 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -31,6 +31,7 @@ #include #include #include +#include #define BCM63XX_NR_UARTS 2 @@ -806,6 +807,9 @@ static int bcm_uart_probe(struct platform_device *pdev) struct clk *clk; int ret; + if (pdev->dev.of_node) + pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); + if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) return -EINVAL; @@ -857,6 +861,12 @@ static int bcm_uart_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id bcm63xx_of_match[] = { + { .compatible = "brcm,bcm6345-uart" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bcm63xx_of_match); + /* * platform driver stuff */ @@ -866,6 +876,7 @@ static struct platform_driver bcm_uart_platform_driver = { .driver = { .owner = THIS_MODULE, .name = "bcm63xx_uart", + .of_match_table = bcm63xx_of_match, }, }; -- cgit v0.10.2 From a9c3f68f3cd8d55f809fbdb0c138ed061ea1bd25 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 22 Feb 2014 07:31:21 -0500 Subject: tty: Fix low_latency BUG The user-settable knob, low_latency, has been the source of several BUG reports which stem from flush_to_ldisc() running in interrupt context. Since 3.12, which added several sleeping locks (termios_rwsem and buf->lock) to the input processing path, the frequency of these BUG reports has increased. Note that changes in 3.12 did not introduce this regression; sleeping locks were first added to the input processing path with the removal of the BKL from N_TTY in commit a88a69c91256418c5907c2f1f8a0ec0a36f9e6cc, 'n_tty: Fix loss of echoed characters and remove bkl from n_tty' and later in commit 38db89799bdf11625a831c5af33938dcb11908b6, 'tty: throttling race fix'. Since those changes, executing flush_to_ldisc() in interrupt_context (ie, low_latency set), is unsafe. However, since most devices do not validate if the low_latency setting is appropriate for the context (process or interrupt) in which they receive data, some reports are due to misconfiguration. Further, serial dma devices for which dma fails, resort to interrupt receiving as a backup without resetting low_latency. Historically, low_latency was used to force wake-up the reading process rather than wait for the next scheduler tick. The effect was to trim multiple milliseconds of latency from when the process would receive new data. Recent tests [1] have shown that the reading process now receives data with only 10's of microseconds latency without low_latency set. Remove the low_latency rx steering from tty_flip_buffer_push(); however, leave the knob as an optional hint to drivers that can tune their rx fifos and such like. Cleanup stale code comments regarding low_latency. [1] https://lkml.org/lkml/2014/2/20/434 "Yay.. thats an annoying historical pain in the butt gone." -- Alan Cox Reported-by: Beat Bolli Reported-by: Pavel Roskin Acked-by: David Sterba Cc: Grant Edwards Cc: Stanislaw Gruszka Cc: Hal Murray Cc: # 3.12.x+ Signed-off-by: Peter Hurley Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index ebd5bff..17ee3bf 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -176,9 +176,6 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, ": %d chars not inserted to flip buffer!\n", length - work); - /* - * This may sleep if ->low_latency is set - */ if (work) tty_flip_buffer_push(&tty->port); } diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 765125d..8ebd9f8 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -351,14 +351,11 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags); * Takes any pending buffers and transfers their ownership to the * ldisc side of the queue. It then schedules those characters for * processing by the line discipline. - * Note that this function can only be used when the low_latency flag - * is unset. Otherwise the workqueue won't be flushed. */ void tty_schedule_flip(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; - WARN_ON(port->low_latency); buf->tail->commit = buf->tail->used; schedule_work(&buf->work); @@ -482,17 +479,15 @@ static void flush_to_ldisc(struct work_struct *work) */ void tty_flush_to_ldisc(struct tty_struct *tty) { - if (!tty->port->low_latency) - flush_work(&tty->port->buf.work); + flush_work(&tty->port->buf.work); } /** * tty_flip_buffer_push - terminal * @port: tty port to push * - * Queue a push of the terminal flip buffers to the line discipline. This - * function must not be called from IRQ context if port->low_latency is - * set. + * Queue a push of the terminal flip buffers to the line discipline. + * Can be called from IRQ/atomic context. * * In the event of the queue being busy for flipping the work will be * held off and retried later. @@ -500,14 +495,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty) void tty_flip_buffer_push(struct tty_port *port) { - struct tty_bufhead *buf = &port->buf; - - buf->tail->commit = buf->tail->used; - - if (port->low_latency) - flush_to_ldisc(&buf->work); - else - schedule_work(&buf->work); + tty_schedule_flip(port); } EXPORT_SYMBOL(tty_flip_buffer_push); diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index b369292..ad0aca8 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -549,8 +549,8 @@ static void gs_rx_push(unsigned long _port) port->read_started--; } - /* Push from tty to ldisc; without low_latency set this is handled by - * a workqueue, so we won't get callbacks and can hold port_lock + /* Push from tty to ldisc; this is handled by a workqueue, + * so we won't get callbacks and can hold port_lock */ if (do_push) tty_flip_buffer_push(&port->port); diff --git a/include/linux/tty.h b/include/linux/tty.h index 90b4fdc..b90b5c2 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -208,7 +208,7 @@ struct tty_port { wait_queue_head_t delta_msr_wait; /* Modem status change */ unsigned long flags; /* TTY flags ASY_*/ unsigned char console:1, /* port is a console */ - low_latency:1; /* direct buffer flush */ + low_latency:1; /* optional: tune for latency */ struct mutex mutex; /* Locking */ struct mutex buf_mutex; /* Buffer alloc lock */ unsigned char *xmit_buf; /* Optional buffer */ -- cgit v0.10.2 From da82f997240a7876a40aa196c60a1e462cc91e9f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 16:01:33 +0400 Subject: serial: imx: Use devm_ioremap_resource() Use devm_ioremap_resource() in order to make the code simpler and it gives proper codes on errors. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index dff0f0a..d185972 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1469,44 +1469,13 @@ static const char *imx_type(struct uart_port *port) } /* - * Release the memory region(s) being used by 'port'. - */ -static void imx_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mmres->start, resource_size(mmres)); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int imx_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - void *ret; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mmres) - return -ENODEV; - - ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart"); - - return ret ? 0 : -EBUSY; -} - -/* * Configure/autoconfigure the port. */ static void imx_config_port(struct uart_port *port, int flags) { struct imx_port *sport = (struct imx_port *)port; - if (flags & UART_CONFIG_TYPE && - imx_request_port(&sport->port) == 0) + if (flags & UART_CONFIG_TYPE) sport->port.type = PORT_IMX; } @@ -1616,8 +1585,6 @@ static struct uart_ops imx_pops = { .flush_buffer = imx_flush_buffer, .set_termios = imx_set_termios, .type = imx_type, - .release_port = imx_release_port, - .request_port = imx_request_port, .config_port = imx_config_port, .verify_port = imx_verify_port, #if defined(CONFIG_CONSOLE_POLL) @@ -1950,12 +1917,9 @@ static int serial_imx_probe(struct platform_device *pdev) return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE); - if (!base) - return -ENOMEM; + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; -- cgit v0.10.2 From 436e4ab5fc85d3d198c292ff46ceb2fb142a39d1 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 16:01:34 +0400 Subject: serial: imx: Use dev_name() for request_irq() to distinguish UARTs Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d185972..37c3939 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1116,25 +1116,25 @@ static int imx_startup(struct uart_port *port) */ if (sport->txirq > 0) { retval = request_irq(sport->rxirq, imx_rxint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out1; retval = request_irq(sport->txirq, imx_txint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out2; /* do not use RTS IRQ on IrDA */ if (!USE_IRDA(sport)) { retval = request_irq(sport->rtsirq, imx_rtsint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out3; } } else { retval = request_irq(sport->port.irq, imx_int, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) { free_irq(sport->port.irq, sport); goto error_out1; -- cgit v0.10.2 From 45af780a0fcac8fbba0ac740a671b2af80bcf189 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 16:01:35 +0400 Subject: serial: imx: Remove init() and exit() platform callbacks Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index b3738e6..8f45afe 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -128,27 +128,15 @@ static struct platform_device mx31moboard_flash = { .num_resources = 1, }; -static int moboard_uart0_init(struct platform_device *pdev) +static void __init moboard_uart0_init(void) { - int ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack"); - if (ret) - return ret; - - ret = gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0); - if (ret) + if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack")) { + gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0); gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); - - return ret; -} - -static void moboard_uart0_exit(struct platform_device *pdev) -{ - gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); + } } static const struct imxuart_platform_data uart0_pdata __initconst = { - .init = moboard_uart0_init, - .exit = moboard_uart0_exit, }; static const struct imxuart_platform_data uart4_pdata __initconst = { @@ -543,6 +531,7 @@ static void __init mx31moboard_init(void) imx31_add_imx2_wdt(); + moboard_uart0_init(); imx31_add_imx_uart0(&uart0_pdata); imx31_add_imx_uart4(&uart4_pdata); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 37c3939..3b6c1a2 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1901,7 +1901,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport, static int serial_imx_probe(struct platform_device *pdev) { struct imx_port *sport; - struct imxuart_platform_data *pdata; void __iomem *base; int ret = 0; struct resource *res; @@ -1955,38 +1954,16 @@ static int serial_imx_probe(struct platform_device *pdev) imx_ports[sport->port.line] = sport; - pdata = dev_get_platdata(&pdev->dev); - if (pdata && pdata->init) { - ret = pdata->init(pdev); - if (ret) - return ret; - } - - ret = uart_add_one_port(&imx_reg, &sport->port); - if (ret) - goto deinit; platform_set_drvdata(pdev, sport); - return 0; -deinit: - if (pdata && pdata->exit) - pdata->exit(pdev); - return ret; + return uart_add_one_port(&imx_reg, &sport->port); } static int serial_imx_remove(struct platform_device *pdev) { - struct imxuart_platform_data *pdata; struct imx_port *sport = platform_get_drvdata(pdev); - pdata = dev_get_platdata(&pdev->dev); - - uart_remove_one_port(&imx_reg, &sport->port); - - if (pdata && pdata->exit) - pdata->exit(pdev); - - return 0; + return uart_remove_one_port(&imx_reg, &sport->port); } static struct platform_driver serial_imx_driver = { diff --git a/include/linux/platform_data/serial-imx.h b/include/linux/platform_data/serial-imx.h index 4adec9b..3cc2e3c 100644 --- a/include/linux/platform_data/serial-imx.h +++ b/include/linux/platform_data/serial-imx.h @@ -23,8 +23,6 @@ #define IMXUART_IRDA (1<<1) struct imxuart_platform_data { - int (*init)(struct platform_device *pdev); - void (*exit)(struct platform_device *pdev); unsigned int flags; void (*irda_enable)(int enable); unsigned int irda_inv_rx:1; -- cgit v0.10.2 From 723abd87f6e536f1353c8f64f621520bc29523a3 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 27 Feb 2014 12:30:51 +0100 Subject: tty: Set correct tty name in 'active' sysfs attribute The 'active' sysfs attribute should refer to the currently active tty devices the console is running on, not the currently active console. The console structure doesn't refer to any device in sysfs, only the tty the console is running on has. So we need to print out the tty names in 'active', not the console names. There is one special-case, which is tty0. If the console is directed to it, we want 'tty0' to show up in the file, so user-space knows that the messages get forwarded to the active VT. The ->device() callback would resolve tty0, though. Hence, treat it special and don't call into the VT layer to resolve it (plymouth is known to depend on it). Cc: Lennart Poettering Cc: Kay Sievers Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: stable Signed-off-by: Werner Fink Signed-off-by: Hannes Reinecke Signed-off-by: David Herrmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index c74a00a..d3448a9 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1271,12 +1271,13 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) * * Locking: None */ -static void tty_line_name(struct tty_driver *driver, int index, char *p) +static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) { if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE) - strcpy(p, driver->name); + return sprintf(p, "%s", driver->name); else - sprintf(p, "%s%d", driver->name, index + driver->name_base); + return sprintf(p, "%s%d", driver->name, + index + driver->name_base); } /** @@ -3545,9 +3546,19 @@ static ssize_t show_cons_active(struct device *dev, if (i >= ARRAY_SIZE(cs)) break; } - while (i--) - count += sprintf(buf + count, "%s%d%c", - cs[i]->name, cs[i]->index, i ? ' ':'\n'); + while (i--) { + int index = cs[i]->index; + struct tty_driver *drv = cs[i]->device(cs[i], &index); + + /* don't resolve tty0 as some programs depend on it */ + if (drv && (cs[i]->index > 0 || drv->major != TTY_MAJOR)) + count += tty_line_name(drv, index, buf + count); + else + count += sprintf(buf + count, "%s%d", + cs[i]->name, cs[i]->index); + + count += sprintf(buf + count, "%c", i ? ' ':'\n'); + } console_unlock(); return count; -- cgit v0.10.2 From ddaa603739fea273ca46d71bd1ff8fa06b8b30c6 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Wed, 26 Feb 2014 17:19:45 +0100 Subject: tty/serial: at91: use dev_err instead of printk For better consistency. Signed-off-by: Richard Genoud Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 3d7206f..d9ad19f 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1555,7 +1555,7 @@ static int atmel_startup(struct uart_port *port) retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, tty ? tty->name : "atmel_serial", port); if (retval) { - printk("atmel_serial: atmel_startup - Can't get irq\n"); + dev_err(port->dev, "atmel_startup - Can't get irq\n"); return retval; } @@ -1738,7 +1738,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, clk_disable_unprepare(atmel_port->clk); break; default: - printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); + dev_err(port->dev, "atmel_serial: unknown pm %d\n", state); } } -- cgit v0.10.2 From a3c1fa99f4d2a635f6660b946f950d379bc8271c Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Wed, 26 Feb 2014 17:19:46 +0100 Subject: tty/serial: at91: remove unused open/close hooks commit 95e629b761ce36996d1befe2824d5346b5a220b9 removed the use of board specific hooks in serial_at91.h, so now, the open/close hook are just dead code. Signed-off-by: Richard Genoud Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d9ad19f..b0603e1 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -115,9 +115,6 @@ static void atmel_stop_rx(struct uart_port *port); #define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) #define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) -static int (*atmel_open_hook)(struct uart_port *); -static void (*atmel_close_hook)(struct uart_port *); - struct atmel_dma_buffer { unsigned char *buf; dma_addr_t dma_addr; @@ -1575,17 +1572,6 @@ static int atmel_startup(struct uart_port *port) if (retval < 0) atmel_set_ops(port); } - /* - * If there is a specific "open" function (to register - * control line interrupts) - */ - if (atmel_open_hook) { - retval = atmel_open_hook(port); - if (retval) { - free_irq(port->irq, port); - return retval; - } - } /* Save current CSR for comparison in atmel_tasklet_func() */ atmel_port->irq_status_prev = UART_GET_CSR(port); @@ -1684,13 +1670,6 @@ static void atmel_shutdown(struct uart_port *port) * Free the interrupt */ free_irq(port->irq, port); - - /* - * If there is a specific "close" function (to unregister - * control line interrupts) - */ - if (atmel_close_hook) - atmel_close_hook(port); } /* -- cgit v0.10.2 From 5f5c9ae56c38942623f69c3e6dc6ec78e4da2076 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 28 Feb 2014 14:21:32 +0100 Subject: serial_core: Unregister console in uart_remove_one_port() If the serial port being removed is used as a console, it must also be unregistered from the console subsystem using unregister_console(). uart_ops.release_port() will release resources (e.g. iounmap() the serial port registers), causing a crash on subsequent kernel output if the console is still registered. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index ece2049..8ece7f1 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2677,6 +2677,12 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) tty_vhangup(port->tty); /* + * If the port is used as a console, unregister it + */ + if (uart_console(uport)) + unregister_console(uport->cons); + + /* * Free the port IO and memory resources, if any. */ if (uport->type != PORT_UNKNOWN) -- cgit v0.10.2 From bf13c9a894162a91c8bb7d9555933e9fc3ff7d0e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 28 Feb 2014 14:21:33 +0100 Subject: serial: sh-sci: Add missing call to uart_remove_one_port() in failure path If cpufreq_register_notifier() fails, we have to remove the port added by sci_probe_single(), which is not done by sci_cleanup_single(). Else the serial port stays active from the point of view of the serial subsystem, and it may crash when userspace getty is started, or when the loadable driver module is unloaded. This was introduced by commit 6dae14216c85eea13db7b12c469475c5d30e5499 ("serial: sh-sci: Fix probe error paths"). Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 1668523..0cb5237 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2564,6 +2564,7 @@ static int sci_probe(struct platform_device *dev) ret = cpufreq_register_notifier(&sp->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); if (unlikely(ret < 0)) { + uart_remove_one_port(&sci_uart_driver, &sp->port); sci_cleanup_single(sp); return ret; } -- cgit v0.10.2 From 50825c57ab80ea44cae6bdcd79ead61e3e4e4e4c Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Mon, 3 Mar 2014 19:54:29 -0600 Subject: serial: 8250_pci: more BayTrail error-free bauds Support the following additional baud rates with 0% error: 500000, 1500000, 2500000, 3500000 Signed-off-by: Aaron Sierra Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 0ff3e36..a3dbc4d 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1366,22 +1366,43 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - unsigned int m = 6912; - unsigned int n = 15625; + unsigned int m, n; u32 reg; - /* For baud rates 1M, 2M, 3M and 4M the dividers must be adjusted. */ - if (baud == 1000000 || baud == 2000000 || baud == 4000000) { + /* + * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the + * dividers must be adjusted. + * + * uartclk = (m / n) * 100 MHz, where m <= n + */ + switch (baud) { + case 500000: + case 1000000: + case 2000000: + case 4000000: m = 64; n = 100; - p->uartclk = 64000000; - } else if (baud == 3000000) { + break; + case 3500000: + m = 56; + n = 100; + p->uartclk = 56000000; + break; + case 1500000: + case 3000000: m = 48; n = 100; - p->uartclk = 48000000; - } else { + break; + case 2500000: + m = 40; + n = 100; + p->uartclk = 40000000; + break; + default: + m = 6912; + n = 15625; p->uartclk = 44236800; } -- cgit v0.10.2 From 41d3f09913a930369a26616eedc02339d0455498 Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Mon, 3 Mar 2014 19:54:36 -0600 Subject: serial: 8250_pci: change BayTrail default uartclk The Intel BayTrail HSUART power-on default reference clock is 44.2368 MHz, but 73.728 MHz provides 0% error for additional "conventional" baud rates above 460800 (e.g. 576000, 921600, and 1152000). Signed-off-by: Aaron Sierra Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index a3dbc4d..b14bcba 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1401,9 +1401,9 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, p->uartclk = 40000000; break; default: - m = 6912; - n = 15625; - p->uartclk = 44236800; + m = 2304; + n = 3125; + p->uartclk = 73728000; } /* Reset the clock */ @@ -3470,6 +3470,10 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .reg_shift = 2, }, + /* + * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on, + * but is overridden by byt_set_termios. + */ [pbn_byt] = { .flags = FL_BASE0, .num_ports = 1, -- cgit v0.10.2 From ebade5e833eda30f648d9bf4954f7d47a920b60f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 7 Mar 2014 14:58:39 +0100 Subject: serial: 8250: Clean up the locking for -rt In -RT the spin_lock_irqsave() does not spin but sleep if the lock is taken. Before that, local_irq_save() is invoked which disables interrupts even on -RT. Therefore local_irq_save() + spin_lock() does not work. In the ->sysrq and oops_in_progress case it is save to trylock the lock i.e. this is what we do now anyway except for ->sysrq where we assume that the lock is already taken. The spin_lock_irqsave() grabs the lock and disables the interrupts on vanilla (the same behavior) and on -RT it won't disable interrupts. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner [bigeasy: add a patch description] Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 747073b..81f909c 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2886,14 +2886,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) touch_nmi_watchdog(); - local_irq_save(flags); - if (port->sysrq) { - /* serial8250_handle_irq() already took the lock */ - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else - spin_lock(&port->lock); + if (port->sysrq || oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); /* * First save the IER then disable the interrupts @@ -2925,8 +2921,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) serial8250_modem_status(up); if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } static int __init serial8250_console_setup(struct console *co, char *options) -- cgit v0.10.2 From b19a47e0603ef89c4179e6e48f6dd1ccc7fa3a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Salva=20Peir=C3=B3?= Date: Tue, 11 Mar 2014 19:31:23 +0100 Subject: synclink: fix info leak in ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hdlcdev_ioctl() code fails to initialize the two padding bytes of struct sync_serial_settings after the ->loopback member. Add an explicit memset(0) before filling the structure to avoid the info leak. Signed-off-by: Salva Peiró Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 5ae14b4..d48e040 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -7866,6 +7866,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + memset(&new_line, 0, sizeof(new_line)); switch (flags){ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 144202e..53ba853 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1766,6 +1766,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + memset(&new_line, 0, sizeof(new_line)); switch (flags){ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; -- cgit v0.10.2 From 58dea3577c5b7a88a989a511d7bc16514647f472 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Mar 2014 15:01:54 +0100 Subject: serial: max310x: Add missing #include cris allmodconfig: drivers/tty/serial/max310x.c: In function 'max310x_ioctl': drivers/tty/serial/max310x.c:885:3: error: implicit declaration of function 'copy_from_user' [-Werror=implicit-function-declaration] drivers/tty/serial/max310x.c:916:3: error: implicit declaration of function 'copy_to_user' [-Werror=implicit-function-declaration] Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 471dbc1..2a99d0c 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -27,6 +27,7 @@ #include #include #include +#include #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 -- cgit v0.10.2 From 74be65a3cff5d31fcec6022de091193ae72271ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Mar 2014 21:42:11 +0100 Subject: serial: efm32: properly namespace location property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While reviewing an i2c driver for efm32 that needs a similar property Wolfram Sang pointed out that "location" is a too generic name for something that is efm32 specific. So add an appropriate namespace and fall back to the generic name in case of failure. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/efm32-uart.txt b/Documentation/devicetree/bindings/serial/efm32-uart.txt index 8e080b8..1984bdf 100644 --- a/Documentation/devicetree/bindings/serial/efm32-uart.txt +++ b/Documentation/devicetree/bindings/serial/efm32-uart.txt @@ -6,7 +6,7 @@ Required properties: - interrupts : Should contain uart interrupt Optional properties: -- location : Decides the location of the USART I/O pins. +- efm32,location : Decides the location of the USART I/O pins. Allowed range : [0 .. 5] Default: 0 @@ -16,5 +16,5 @@ uart@0x4000c400 { compatible = "efm32,uart"; reg = <0x4000c400 0x400>; interrupts = <15>; - location = <0>; + efm32,location = <0>; }; diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 0eb5b56..028582e 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -671,7 +671,10 @@ static int efm32_uart_probe_dt(struct platform_device *pdev, if (!np) return 1; - ret = of_property_read_u32(np, "location", &location); + ret = of_property_read_u32(np, "efm32,location", &location); + if (ret) + /* fall back to old and (wrongly) generic property "location" */ + ret = of_property_read_u32(np, "location", &location); if (!ret) { if (location > 5) { dev_err(&pdev->dev, "invalid location\n"); -- cgit v0.10.2 From 02088ca63b2de4f7eb575c46fc9ff3d60775b07f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:23:35 +0100 Subject: serial_core: Spelling s/contro/control/ Signed-off-by: Geert Uytterhoeven Cc: Greg Kroah-Hartman Cc: linux-serial@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 8ece7f1..55dd487 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1762,7 +1762,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) } /** - * uart_parse_options - Parse serial port baud/parity/bits/flow contro. + * uart_parse_options - Parse serial port baud/parity/bits/flow control. * @options: pointer to option string * @baud: pointer to an 'int' variable for the baud rate. * @parity: pointer to an 'int' variable for the parity. -- cgit v0.10.2 From 015355b70e074a8cc11da6ae4f82d45c5160358a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:23:36 +0100 Subject: serial_core: Grammar s/ports/port's/ Signed-off-by: Geert Uytterhoeven Cc: Greg Kroah-Hartman Cc: linux-serial@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 55dd487..203cb32 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2609,7 +2609,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) /* * Register the port whether it's detected or not. This allows - * setserial to be used to alter this ports parameters. + * setserial to be used to alter this port's parameters. */ tty_dev = tty_port_register_device_attr(port, drv->tty_driver, uport->line, uport->dev, port, tty_dev_attr_groups); -- cgit v0.10.2 From 63e3ad3252695a2b8c01b6f6c225e4537af08b85 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 11 Mar 2014 15:30:01 +0400 Subject: serial: clps711x: Give a chance to perform useful tasks during wait loop This patch adds cond_sched() calls during wait loop to perform other tasks. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index b0eacb8..5e6fdb1 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -368,11 +368,16 @@ static const struct uart_ops uart_clps711x_ops = { static void uart_clps711x_console_putchar(struct uart_port *port, int ch) { struct clps711x_port *s = dev_get_drvdata(port->dev); - u32 sysflg = 0; - do { + /* Wait for FIFO is not full */ + while (1) { + u32 sysflg = 0; + regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); - } while (sysflg & SYSFLG_UTXFF); + if (!(sysflg & SYSFLG_UTXFF)) + break; + cond_resched(); + } writew(ch, port->membase + UARTDR_OFFSET); } @@ -382,14 +387,18 @@ static void uart_clps711x_console_write(struct console *co, const char *c, { struct uart_port *port = clps711x_uart.state[co->index].uart_port; struct clps711x_port *s = dev_get_drvdata(port->dev); - u32 sysflg = 0; uart_console_write(port, c, n, uart_clps711x_console_putchar); /* Wait for transmitter to become empty */ - do { + while (1) { + u32 sysflg = 0; + regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); - } while (sysflg & SYSFLG_UBUSY); + if (!(sysflg & SYSFLG_UBUSY)) + break; + cond_resched(); + } } static int uart_clps711x_console_setup(struct console *co, char *options) -- cgit v0.10.2 From 4c6d5b4d537fbdfa310295e7071c85b07783d245 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Mar 2014 14:10:58 +0100 Subject: serial_core: Get a reference for port->tty in uart_remove_one_port() Suggested-by: Peter Hurley Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 203cb32..3253905 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2645,6 +2645,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) { struct uart_state *state = drv->state + uport->line; struct tty_port *port = &state->port; + struct tty_struct *tty; int ret = 0; BUG_ON(in_interrupt()); @@ -2673,8 +2674,11 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) */ tty_unregister_device(drv->tty_driver, uport->line); - if (port->tty) + tty = tty_port_tty_get(port); + if (tty) { tty_vhangup(port->tty); + tty_kref_put(tty); + } /* * If the port is used as a console, unregister it -- cgit v0.10.2 From 4ed94cd44039037980ce66c652b194ec21356268 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Mar 2014 14:10:59 +0100 Subject: serial_core: Avoid NULL pointer dereference in uart_close() When unbinding a serial driver that's being used as a serial console, the kernel may crash with a NULL pointer dereference in a uart_*() function called from uart_close () (e.g. uart_flush_buffer() or uart_chars_in_buffer()). To fix this, let uart_close() check for port->count == 0. If this is the case, bail out early. Else tty_port_close_start() will make the port counts inconsistent, printing out warnings like tty_port_close_start: tty->count = 1 port count = 0. and tty_port_close_start: count = -1 and once uport == NULL, it will also crash. Also fix the related crash in pr_debug() by checking for a non-NULL uport first. Detailed description: On driver unbind, uart_remove_one_port() is called. Basically it; - marks the port dead, - calls tty_vhangup(), - sets state->uart_port = NULL. What will happen depends on whether the port is just in use by e.g. getty, or was also opened as a console. A. If the tty was not opened as a console: - tty_vhangup() will (in __tty_hangup()): - mark all file descriptors for this tty hung up by pointing them to hung_up_tty_fops, - call uart_hangup(), which sets port->count to 0. - A subsequent uart_open() (this may be through /dev/ttyS*, or through /dev/console if this is a serial console) will fail with -ENXIO as the port was marked dead, - uart_close() after the failed uart_open() will return early, as tty_hung_up_p() (called from tty_port_close_start()) will notice it was hung up. B. If the tty was also opened as a console: - tty_vhangup() will (in __tty_hangup()): - mark non-console file descriptors for this tty hung up by pointing them to hung_up_tty_fops, - NOT call uart_hangup(), but instead call uart_close() for every non-console file descriptor, so port->count will still have a non-zero value afterwards. - A subsequent uart_open() will fail with -ENXIO as the port was marked dead, - uart_close() after the failed uart_open() starts to misbehave: - tty_hung_up_p() will not notice it was hung up, - As port->count is non-zero, tty_port_close_start() will decrease port->count, making the tty and port counts inconsistent. Later, warnings like these will be printed: tty_port_close_start: tty->count = 1 port count = 0. and tty_port_close_start: count = -1 - If all of this happens after state->uart_port was set to zero, a NULL pointer dereference will happen. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 3253905..2cf5649 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1319,9 +1319,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uport = state->uart_port; port = &state->port; - pr_debug("uart_close(%d) called\n", uport->line); + pr_debug("uart_close(%d) called\n", uport ? uport->line : -1); - if (tty_port_close_start(port, tty, filp) == 0) + if (!port->count || tty_port_close_start(port, tty, filp) == 0) return; /* -- cgit v0.10.2 From 6c13d5d27c5ecd7a2ce7c104c7726b0d7aa7d7b5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:11:17 +0100 Subject: serial: sh-sci: Replace printk() by pr_*() Make banner const while we're at it Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 0cb5237..60a8f7d 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -428,7 +428,7 @@ static int sci_probe_regmap(struct plat_sci_port *cfg) cfg->regtype = SCIx_HSCIF_REGTYPE; break; default: - printk(KERN_ERR "Can't probe register map for given port\n"); + pr_err("Can't probe register map for given port\n"); return -EINVAL; } @@ -2389,8 +2389,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev) #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ -static char banner[] __initdata = - KERN_INFO "SuperH (H)SCI(F) driver initialized\n"; +static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized"; static struct uart_driver sci_uart_driver = { .owner = THIS_MODULE, @@ -2616,7 +2615,7 @@ static int __init sci_init(void) { int ret; - printk(banner); + pr_info("%s\n", banner); ret = uart_register_driver(&sci_uart_driver); if (likely(ret == 0)) { -- cgit v0.10.2 From ff43da00e0d407cd8e7faaf2ac150001d29827e4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:11:18 +0100 Subject: serial: sh-sci: Remove useless casts Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 60a8f7d..c93154f 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2423,25 +2423,25 @@ struct sci_port_info { static const struct of_device_id of_sci_match[] = { { .compatible = "renesas,scif", - .data = (void *)&(const struct sci_port_info) { + .data = &(const struct sci_port_info) { .type = PORT_SCIF, .regtype = SCIx_SH4_SCIF_REGTYPE, }, }, { .compatible = "renesas,scifa", - .data = (void *)&(const struct sci_port_info) { + .data = &(const struct sci_port_info) { .type = PORT_SCIFA, .regtype = SCIx_SCIFA_REGTYPE, }, }, { .compatible = "renesas,scifb", - .data = (void *)&(const struct sci_port_info) { + .data = &(const struct sci_port_info) { .type = PORT_SCIFB, .regtype = SCIx_SCIFB_REGTYPE, }, }, { .compatible = "renesas,hscif", - .data = (void *)&(const struct sci_port_info) { + .data = &(const struct sci_port_info) { .type = PORT_HSCIF, .regtype = SCIx_HSCIF_REGTYPE, }, -- cgit v0.10.2 From 26de4f1b2fb45e53a9e8f4f913b9cdf6c294070b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:11:19 +0100 Subject: serial: sh-sci: Add more register documentation Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index c93154f..22a508a 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -911,7 +911,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) /* Disable future Rx interrupts */ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { disable_irq_nosync(irq); - scr |= 0x4000; + scr |= SCSCR_RDRQE; } else { scr &= ~SCSCR_RIE; } @@ -1200,7 +1200,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) */ reg = sci_getreg(port, SCFCR); if (reg->size) - serial_port_out(port, SCFCR, serial_port_in(port, SCFCR) | 1); + serial_port_out(port, SCFCR, + serial_port_in(port, SCFCR) | + SCFCR_LOOP); } } @@ -1496,9 +1498,9 @@ static void sci_start_tx(struct uart_port *port) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { u16 new, scr = serial_port_in(port, SCSCR); if (s->chan_tx) - new = scr | 0x8000; + new = scr | SCSCR_TDRQE; else - new = scr & ~0x8000; + new = scr & ~SCSCR_TDRQE; if (new != scr) serial_port_out(port, SCSCR, new); } @@ -1525,7 +1527,7 @@ static void sci_stop_tx(struct uart_port *port) ctrl = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x8000; + ctrl &= ~SCSCR_TDRQE; ctrl &= ~SCSCR_TIE; @@ -1539,7 +1541,7 @@ static void sci_start_rx(struct uart_port *port) ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x4000; + ctrl &= ~SCSCR_RDRQE; serial_port_out(port, SCSCR, ctrl); } @@ -1551,7 +1553,7 @@ static void sci_stop_rx(struct uart_port *port) ctrl = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x4000; + ctrl &= ~SCSCR_RDRQE; ctrl &= ~port_rx_irq_mask(port); @@ -1614,7 +1616,7 @@ static void rx_timer_fn(unsigned long arg) u16 scr = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~0x4000; + scr &= ~SCSCR_RDRQE; enable_irq(s->irqs[SCIx_RXI_IRQ]); } serial_port_out(port, SCSCR, scr | SCSCR_RIE); @@ -1871,13 +1873,13 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, smr_val = serial_port_in(port, SCSMR) & 3; if ((termios->c_cflag & CSIZE) == CS7) - smr_val |= 0x40; + smr_val |= SCSMR_CHR; if (termios->c_cflag & PARENB) - smr_val |= 0x20; + smr_val |= SCSMR_PE; if (termios->c_cflag & PARODD) - smr_val |= 0x30; + smr_val |= SCSMR_PE | SCSMR_ODD; if (termios->c_cflag & CSTOPB) - smr_val |= 0x08; + smr_val |= SCSMR_STOP; uart_update_timeout(port, termios->c_cflag, baud); @@ -1885,7 +1887,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, __func__, smr_val, cks, t, s->cfg->scscr); if (t >= 0) { - serial_port_out(port, SCSMR, (smr_val & ~3) | cks); + serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks); serial_port_out(port, SCBRR, t); reg = sci_getreg(port, HSSRR); if (reg->size) diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index 22b3640..6c5e3bb 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -10,45 +10,59 @@ #define SCIx_NOT_SUPPORTED (-1) -#define SCSCR_TIE (1 << 7) -#define SCSCR_RIE (1 << 6) -#define SCSCR_TE (1 << 5) -#define SCSCR_RE (1 << 4) -#define SCSCR_REIE (1 << 3) /* not supported by all parts */ -#define SCSCR_TOIE (1 << 2) /* not supported by all parts */ -#define SCSCR_CKE1 (1 << 1) -#define SCSCR_CKE0 (1 << 0) - -/* SCxSR SCI */ -#define SCI_TDRE 0x80 -#define SCI_RDRF 0x40 -#define SCI_ORER 0x20 -#define SCI_FER 0x10 -#define SCI_PER 0x08 -#define SCI_TEND 0x04 +/* SCSMR (Serial Mode Register) */ +#define SCSMR_CHR (1 << 6) /* 7-bit Character Length */ +#define SCSMR_PE (1 << 5) /* Parity Enable */ +#define SCSMR_ODD (1 << 4) /* Odd Parity */ +#define SCSMR_STOP (1 << 3) /* Stop Bit Length */ +#define SCSMR_CKS 0x0003 /* Clock Select */ + +/* Serial Control Register (@ = not supported by all parts) */ +#define SCSCR_TIE (1 << 7) /* Transmit Interrupt Enable */ +#define SCSCR_RIE (1 << 6) /* Receive Interrupt Enable */ +#define SCSCR_TE (1 << 5) /* Transmit Enable */ +#define SCSCR_RE (1 << 4) /* Receive Enable */ +#define SCSCR_REIE (1 << 3) /* Receive Error Interrupt Enable @ */ +#define SCSCR_TOIE (1 << 2) /* Timeout Interrupt Enable @ */ +#define SCSCR_CKE1 (1 << 1) /* Clock Enable 1 */ +#define SCSCR_CKE0 (1 << 0) /* Clock Enable 0 */ +/* SCIFA/SCIFB only */ +#define SCSCR_TDRQE (1 << 15) /* Tx Data Transfer Request Enable */ +#define SCSCR_RDRQE (1 << 14) /* Rx Data Transfer Request Enable */ + +/* SCxSR (Serial Status Register) on SCI */ +#define SCI_TDRE 0x80 /* Transmit Data Register Empty */ +#define SCI_RDRF 0x40 /* Receive Data Register Full */ +#define SCI_ORER 0x20 /* Overrun Error */ +#define SCI_FER 0x10 /* Framing Error */ +#define SCI_PER 0x08 /* Parity Error */ +#define SCI_TEND 0x04 /* Transmit End */ #define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER) -/* SCxSR SCIF, HSCIF */ -#define SCIF_ER 0x0080 -#define SCIF_TEND 0x0040 -#define SCIF_TDFE 0x0020 -#define SCIF_BRK 0x0010 -#define SCIF_FER 0x0008 -#define SCIF_PER 0x0004 -#define SCIF_RDF 0x0002 -#define SCIF_DR 0x0001 +/* SCxSR (Serial Status Register) on SCIF, HSCIF */ +#define SCIF_ER 0x0080 /* Receive Error */ +#define SCIF_TEND 0x0040 /* Transmission End */ +#define SCIF_TDFE 0x0020 /* Transmit FIFO Data Empty */ +#define SCIF_BRK 0x0010 /* Break Detect */ +#define SCIF_FER 0x0008 /* Framing Error */ +#define SCIF_PER 0x0004 /* Parity Error */ +#define SCIF_RDF 0x0002 /* Receive FIFO Data Full */ +#define SCIF_DR 0x0001 /* Receive Data Ready */ #define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) -/* SCSPTR, optional */ -#define SCSPTR_RTSIO (1 << 7) -#define SCSPTR_CTSIO (1 << 5) -#define SCSPTR_SPB2IO (1 << 1) -#define SCSPTR_SPB2DT (1 << 0) +/* SCFCR (FIFO Control Register) */ +#define SCFCR_LOOP (1 << 0) /* Loopback Test */ + +/* SCSPTR (Serial Port Register), optional */ +#define SCSPTR_RTSIO (1 << 7) /* Serial Port RTS Pin Input/Output */ +#define SCSPTR_CTSIO (1 << 5) /* Serial Port CTS Pin Input/Output */ +#define SCSPTR_SPB2IO (1 << 1) /* Serial Port Break Input/Output */ +#define SCSPTR_SPB2DT (1 << 0) /* Serial Port Break Data */ /* HSSRR HSCIF */ -#define HSCIF_SRE 0x8000 +#define HSCIF_SRE 0x8000 /* Sampling Rate Register Enable */ enum { SCIx_PROBE_REGTYPE, @@ -73,10 +87,19 @@ enum { * Not all registers will exist on all parts. */ enum { - SCSMR, SCBRR, SCSCR, SCxSR, - SCFCR, SCFDR, SCxTDR, SCxRDR, - SCLSR, SCTFDR, SCRFDR, SCSPTR, - HSSRR, + SCSMR, /* Serial Mode Register */ + SCBRR, /* Bit Rate Register */ + SCSCR, /* Serial Control Register */ + SCxSR, /* Serial Status Register */ + SCFCR, /* FIFO Control Register */ + SCFDR, /* FIFO Data Count Register */ + SCxTDR, /* Transmit (FIFO) Data Register */ + SCxRDR, /* Receive (FIFO) Data Register */ + SCLSR, /* Line Status Register */ + SCTFDR, /* Transmit FIFO Data Count Register */ + SCRFDR, /* Receive FIFO Data Count Register */ + SCSPTR, /* Serial Port Register */ + HSSRR, /* Sampling Rate Register */ SCIx_NR_REGS, }; -- cgit v0.10.2 From d3dfe5d9b4c8b3156b28f99f7a4a59ad8be09b15 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:11:20 +0100 Subject: serial: sh-sci: Replace hardcoded 3 by UART_PM_STATE_OFF Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 22a508a..634ecae 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1955,7 +1955,7 @@ static void sci_pm(struct uart_port *port, unsigned int state, struct sci_port *sci_port = to_sci_port(port); switch (state) { - case 3: + case UART_PM_STATE_OFF: sci_port_disable(sci_port); break; default: -- cgit v0.10.2 From 9b971cd206c019fc6aeeb7e04136a49f9312df4a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 11 Mar 2014 10:10:46 -0700 Subject: serial: sh-sci: Neaten dev_ uses Add missing newlines and coalesce formats. Realign arguments. Signed-off-by: Joe Perches Acked-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 634ecae..7ee5a79 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -788,7 +788,7 @@ static int sci_handle_errors(struct uart_port *port) if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) copied++; - dev_notice(port->dev, "overrun error"); + dev_notice(port->dev, "overrun error\n"); } if (status & SCxSR_FER(port)) { @@ -830,7 +830,7 @@ static int sci_handle_errors(struct uart_port *port) if (tty_insert_flip_char(tport, 0, TTY_PARITY)) copied++; - dev_notice(port->dev, "parity error"); + dev_notice(port->dev, "parity error\n"); } if (copied) @@ -1292,7 +1292,8 @@ static void sci_dma_rx_complete(void *arg) unsigned long flags; int count; - dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx); + dev_dbg(port->dev, "%s(%d) active #%d\n", + __func__, port->line, s->active_rx); spin_lock_irqsave(&port->lock, flags); @@ -1368,8 +1369,8 @@ static void sci_submit_rx(struct sci_port *s) sci_rx_dma_release(s, true); return; } - dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, - s->cookie_rx[i], i); + dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", + __func__, s->cookie_rx[i], i); } s->active_rx = s->cookie_rx[0]; @@ -1428,8 +1429,8 @@ static void work_fn_rx(struct work_struct *work) s->active_rx = s->cookie_rx[!new]; - dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__, - s->cookie_rx[new], new, s->active_rx); + dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", + __func__, s->cookie_rx[new], new, s->active_rx); } static void work_fn_tx(struct work_struct *work) @@ -1482,8 +1483,8 @@ static void work_fn_tx(struct work_struct *work) return; } - dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__, - xmit->buf, xmit->tail, xmit->head, s->cookie_tx); + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", + __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx); dma_async_issue_pending(chan); } @@ -1602,8 +1603,8 @@ static bool filter(struct dma_chan *chan, void *slave) { struct sh_dmae_slave *param = slave; - dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, - param->shdma_slave.slave_id); + dev_dbg(chan->device->dev, "%s: slave ID %d\n", + __func__, param->shdma_slave.slave_id); chan->private = ¶m->shdma_slave; return true; @@ -1632,8 +1633,7 @@ static void sci_request_dma(struct uart_port *port) dma_cap_mask_t mask; int nent; - dev_dbg(port->dev, "%s: port %d\n", __func__, - port->line); + dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0) return; @@ -1661,7 +1661,8 @@ static void sci_request_dma(struct uart_port *port) if (!nent) sci_tx_dma_release(s, false); else - dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, + dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", + __func__, sg_dma_len(&s->sg_tx), port->state->xmit.buf, &sg_dma_address(&s->sg_tx)); @@ -1935,8 +1936,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, if (s->chan_rx) { s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / port->fifosize / 2; - dev_dbg(port->dev, - "DMA Rx t-out %ums, tty t-out %u jiffies\n", + dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", s->rx_timeout * 1000 / HZ, port->timeout); if (s->rx_timeout < msecs_to_jiffies(20)) s->rx_timeout = msecs_to_jiffies(20); @@ -2503,11 +2503,9 @@ static int sci_probe_single(struct platform_device *dev, /* Sanity check */ if (unlikely(index >= SCI_NPORTS)) { - dev_notice(&dev->dev, "Attempting to register port " - "%d when only %d are available.\n", + dev_notice(&dev->dev, "Attempting to register port %d when only %d are available\n", index+1, SCI_NPORTS); - dev_notice(&dev->dev, "Consider bumping " - "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); + dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); return -EINVAL; } -- cgit v0.10.2 From cab53dc9e20f74fbd4776ea584ba3b21c957b1a8 Mon Sep 17 00:00:00 2001 From: Dimitris Lampridis Date: Thu, 13 Mar 2014 15:11:46 +0200 Subject: tty/serial: omap: fix RX interrupt enable/disable in half-duplex TX Make sure that serial_omap_stop_rx() also disables RDI (Receiver Data Interrupt), otherwise the interrupt handler will call serial_omap_rdi() to read the new data, resulting in the transmission being echoed back. When the half-duplex transmission is complete, in order to reverse the effects of serial_omap_stop_rx(), we should re-enable: * the RX interrupts _without_ overwriting up->ier * the UART_LSR_DR bit of the up->port.read_status_mask Signed-off-by: Dimitris Lampridis Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 77f0351..65abea2 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -342,7 +342,8 @@ static void serial_omap_stop_tx(struct uart_port *port) if ((up->rs485.flags & SER_RS485_ENABLED) && !(up->rs485.flags & SER_RS485_RX_DURING_TX)) { - up->ier = UART_IER_RLSI | UART_IER_RDI; + up->ier |= UART_IER_RLSI | UART_IER_RDI; + up->port.read_status_mask |= UART_LSR_DR; serial_out(up, UART_IER, up->ier); } @@ -355,7 +356,7 @@ static void serial_omap_stop_rx(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); pm_runtime_get_sync(up->dev); - up->ier &= ~UART_IER_RLSI; + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier); pm_runtime_mark_last_busy(up->dev); -- cgit v0.10.2 From 3a13884abea08a5043b98d9374486ec859d1e03a Mon Sep 17 00:00:00 2001 From: Dimitris Lampridis Date: Thu, 13 Mar 2014 15:11:47 +0200 Subject: tty/serial: omap: empty the RX FIFO at the end of half-duplex TX Provided that the SER_RS485_RX_DURING_TX flag is not set, empty the RX FIFO to prevent reading back the transmitted data. Signed-off-by: Dimitris Lampridis Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 65abea2..dd8b1a5 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -342,6 +342,12 @@ static void serial_omap_stop_tx(struct uart_port *port) if ((up->rs485.flags & SER_RS485_ENABLED) && !(up->rs485.flags & SER_RS485_RX_DURING_TX)) { + /* + * Empty the RX FIFO, we are not interested in anything + * received during the half-duplex transmission. + */ + serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_RCVR); + /* Re-enable RX interrupts */ up->ier |= UART_IER_RLSI | UART_IER_RDI; up->port.read_status_mask |= UART_LSR_DR; serial_out(up, UART_IER, up->ier); -- cgit v0.10.2