From 9f3745f3719ccd27e0da22a883756e9716fc8cb7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Apr 2020 20:43:00 +0200 Subject: serial: lpc32xx_hs: Drop surplus include The driver includes but does not use any symbols from the file so drop this include. Cc: Roland Stigge Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20200415184300.269889-1-linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/lpc32xx_hs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 9a836dcac157..b5898c932036 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 5745fd0f950f1ac99c7c680245353a961da3ca14 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Apr 2020 20:39:27 +0200 Subject: serial: omap: Convert to use GPIO descriptors This converts the OMAP serial driver to use a GPIO descriptor for the optional RTS signal. Cc: Shubhrajyoti D Cc: Tony Lindgren Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20200415183927.269445-1-linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 48 +++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index f7d6b3c9ea45..c71c1a2266dc 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -33,8 +33,7 @@ #include #include #include -#include -#include +#include #include #define OMAP_MAX_HSUART_PORTS 10 @@ -153,7 +152,7 @@ struct uart_omap_port { u32 errata; u32 features; - int rts_gpio; + struct gpio_desc *rts_gpiod; struct pm_qos_request pm_qos_request; u32 latency; @@ -303,11 +302,11 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_OMAP_SCR, up->scr); res = (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; - if (gpio_get_value(up->rts_gpio) != res) { + if (gpiod_get_value(up->rts_gpiod) != res) { if (port->rs485.delay_rts_after_send > 0) mdelay( port->rs485.delay_rts_after_send); - gpio_set_value(up->rts_gpio, res); + gpiod_set_value(up->rts_gpiod, res); } } else { /* We're asked to stop, but there's still stuff in the @@ -412,8 +411,8 @@ static void serial_omap_start_tx(struct uart_port *port) /* if rts not already enabled */ res = (port->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; - if (gpio_get_value(up->rts_gpio) != res) { - gpio_set_value(up->rts_gpio, res); + if (gpiod_get_value(up->rts_gpiod) != res) { + gpiod_set_value(up->rts_gpiod, res); if (port->rs485.delay_rts_before_send > 0) mdelay(port->rs485.delay_rts_before_send); } @@ -1414,12 +1413,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) * Just as a precaution, only allow rs485 * to be enabled if the gpio pin is valid */ - if (gpio_is_valid(up->rts_gpio)) { + if (up->rts_gpiod) { /* enable / disable rts */ val = (port->rs485.flags & SER_RS485_ENABLED) ? SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND; val = (port->rs485.flags & val) ? 1 : 0; - gpio_set_value(up->rts_gpio, val); + gpiod_set_value(up->rts_gpiod, val); } else port->rs485.flags &= ~SER_RS485_ENABLED; @@ -1596,13 +1595,15 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) } static int serial_omap_probe_rs485(struct uart_omap_port *up, - struct device_node *np) + struct device *dev) { struct serial_rs485 *rs485conf = &up->port.rs485; + struct device_node *np = dev->of_node; + enum gpiod_flags gflags; int ret; rs485conf->flags = 0; - up->rts_gpio = -EINVAL; + up->rts_gpiod = NULL; if (!np) return 0; @@ -1618,19 +1619,20 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, } /* check for tx enable gpio */ - up->rts_gpio = of_get_named_gpio(np, "rts-gpio", 0); - if (gpio_is_valid(up->rts_gpio)) { - ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial"); - if (ret < 0) + gflags = rs485conf->flags & SER_RS485_RTS_AFTER_SEND ? + GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + up->rts_gpiod = devm_gpiod_get_optional(dev, "rts", gflags); + if (IS_ERR(up->rts_gpiod)) { + ret = PTR_ERR(up->rts_gpiod); + if (ret == -EPROBE_DEFER) return ret; - ret = rs485conf->flags & SER_RS485_RTS_AFTER_SEND ? 1 : 0; - ret = gpio_direction_output(up->rts_gpio, ret); - if (ret < 0) - return ret; - } else if (up->rts_gpio == -EPROBE_DEFER) { - return -EPROBE_DEFER; + /* + * FIXME: the code historically ignored any other error than + * -EPROBE_DEFER and just went on without GPIO. + */ + up->rts_gpiod = NULL; } else { - up->rts_gpio = -EINVAL; + gpiod_set_consumer_name(up->rts_gpiod, "omap-serial"); } return 0; @@ -1703,7 +1705,7 @@ static int serial_omap_probe(struct platform_device *pdev) dev_info(up->port.dev, "no wakeirq for uart%d\n", up->port.line); - ret = serial_omap_probe_rs485(up, pdev->dev.of_node); + ret = serial_omap_probe_rs485(up, &pdev->dev); if (ret < 0) goto err_rs485; -- cgit v1.2.3 From 810bc0a5fafb8575b9406fcc8b0be77ff93a7be0 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 3 Apr 2020 19:49:42 +0200 Subject: tty: serial: fsl_lpuart: make coverity happy Coverity reports the following: var_compare_op: Comparing chan to null implies that chan might be null. 1234 if (chan) 1235 dmaengine_terminate_all(chan); 1236 Dereference after null check (FORWARD_NULL) var_deref_op: Dereferencing null pointer chan. 1237 dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); Technically, this is correct. But lpuart_dma_rx_free() is guarded by lpuart_dma_rx_use which is only true if there is a dma channel, see lpuart_rx_dma_startup(). In any way, this looks bogus. So remove the superfluous "if (chan)" check and make coverity happy. Fixes: a092ab25fdaa ("tty: serial: fsl_lpuart: fix DMA mapping") Signed-off-by: Michael Walle Reported-by: Colin Ian King Acked-by: Jiri Slaby Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20200403174942.9594-1-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 5d41075964f2..dba730d1801f 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1231,9 +1231,7 @@ static void lpuart_dma_rx_free(struct uart_port *port) struct lpuart_port, port); struct dma_chan *chan = sport->dma_rx_chan; - if (chan) - dmaengine_terminate_all(chan); - + dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); kfree(sport->rx_ring.buf); sport->rx_ring.tail = 0; -- cgit v1.2.3 From cd9479a16720a6a38b3b614d2adece2413aebefc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 5 Apr 2020 14:54:23 +0100 Subject: drivers/tty: remove redundant assignment to variable i and rename it to ret The variable i is being assigned a value that is never read and it is being updated later with a new value. The assignment is redundant and can be removed. Also rename i to ret as this new name makes makes more sense. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Acked-by: Jiri Slaby Link: https://lore.kernel.org/r/20200405135423.383466-1-colin.king@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/serial_cs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index c8186a05a453..e3d10794dbba 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -440,7 +440,7 @@ static int simple_config_check_notpicky(struct pcmcia_device *p_dev, static int simple_config(struct pcmcia_device *link) { struct serial_info *info = link->priv; - int i = -ENODEV, try; + int ret, try; /* * First pass: look for a config entry that looks normal. @@ -472,8 +472,8 @@ found_port: if (info->quirk && info->quirk->config) info->quirk->config(link); - i = pcmcia_enable_device(link); - if (i != 0) + ret = pcmcia_enable_device(link); + if (ret != 0) return -1; return setup_serial(link, info, link->resource[0]->start, link->irq); } -- cgit v1.2.3 From 30c67b91973cc6a9d4118d53eaf6da059a8d3996 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Apr 2020 20:02:50 +0200 Subject: serial: sh-sci: Drop unused include The sh-sci.h file includes the legacy header but the driver is actually migrated to use the mctrl_gpio library so this is not needed. Cc: George G. Davis Signed-off-by: Linus Walleij Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200415180250.221762-1-linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 0b9e804e61a9..c0dfe4382898 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -2,7 +2,6 @@ #include #include #include -#include #define SCI_MAJOR 204 #define SCI_MINOR_START 8 -- cgit v1.2.3 From 42e11948ddf68b9f799cad8c0ddeab0a39da33e8 Mon Sep 17 00:00:00 2001 From: Raviteja Narayanam Date: Thu, 9 Apr 2020 11:56:02 +0530 Subject: serial: uartps: Wait for tx_empty in console setup On some platforms, the log is corrupted while console is being registered. It is observed that when set_termios is called, there are still some bytes in the FIFO to be transmitted. So, wait for tx_empty inside cdns_uart_console_setup before calling set_termios. Signed-off-by: Raviteja Narayanam Reviewed-by: Shubhrajyoti Datta Link: https://lore.kernel.org/r/1586413563-29125-2-git-send-email-raviteja.narayanam@xilinx.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 6b26f767768e..0bf946b0b198 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1260,6 +1260,7 @@ static int cdns_uart_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; + unsigned long time_out; if (!port->membase) { pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n", @@ -1270,6 +1271,13 @@ static int cdns_uart_console_setup(struct console *co, char *options) if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); + /* Wait for tx_empty before setting up the console */ + time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT); + + while (time_before(jiffies, time_out) && + cdns_uart_tx_empty(port) != TIOCSER_TEMT) + cpu_relax(); + return uart_set_options(port, co, baud, parity, bits, flow); } #endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */ -- cgit v1.2.3 From a8e7346b7c0a3b33963e5e043e2c612fdf69de34 Mon Sep 17 00:00:00 2001 From: Raviteja Narayanam Date: Thu, 9 Apr 2020 11:56:03 +0530 Subject: serial: uartps: Use cdns_uart_tx_empty in console_write Instead of accessing the registers and checking for tx_empty, use cdns_uart_tx_empty in cdns_uart_console_write function. Signed-off-by: Raviteja Narayanam Reviewed-by: Shubhrajyoti Datta Link: https://lore.kernel.org/r/1586413563-29125-3-git-send-email-raviteja.narayanam@xilinx.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 0bf946b0b198..042aa6f1c9c4 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1233,9 +1233,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, writel(ctrl, port->membase + CDNS_UART_CR); uart_console_write(port, s, count, cdns_uart_console_putchar); - while ((readl(port->membase + CDNS_UART_SR) & - (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE)) != - CDNS_UART_SR_TXEMPTY) + while (cdns_uart_tx_empty(port) != TIOCSER_TEMT) cpu_relax(); /* restore interrupt state */ -- cgit v1.2.3 From 44da03628b841635b157ea8d3fd46626783fe70d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 16 Apr 2020 12:34:53 -0300 Subject: serial: fsl_lpuart: Change DMA failure messages to debug level Currently the following messages are seen when booting i.MX8QXP: fsl-lpuart 5a060000.serial: DMA tx channel request failed, operating without tx DMA (-19) fsl-lpuart 5a060000.serial: DMA rx channel request failed, operating without rx DMA (-19) It is not really useful to have such messages on every boot, so change them to debug level instead. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20200416153453.18825-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index dba730d1801f..6a9909e56449 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1512,17 +1512,17 @@ static void lpuart_request_dma(struct lpuart_port *sport) { sport->dma_tx_chan = dma_request_chan(sport->port.dev, "tx"); if (IS_ERR(sport->dma_tx_chan)) { - dev_info_once(sport->port.dev, - "DMA tx channel request failed, operating without tx DMA (%ld)\n", - PTR_ERR(sport->dma_tx_chan)); + dev_dbg_once(sport->port.dev, + "DMA tx channel request failed, operating without tx DMA (%ld)\n", + PTR_ERR(sport->dma_tx_chan)); sport->dma_tx_chan = NULL; } sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx"); if (IS_ERR(sport->dma_rx_chan)) { - dev_info_once(sport->port.dev, - "DMA rx channel request failed, operating without rx DMA (%ld)\n", - PTR_ERR(sport->dma_rx_chan)); + dev_dbg_once(sport->port.dev, + "DMA rx channel request failed, operating without rx DMA (%ld)\n", + PTR_ERR(sport->dma_rx_chan)); sport->dma_rx_chan = NULL; } } -- cgit v1.2.3 From c2880ec6c0862e11673742ab512c262b5e97a34c Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Mon, 4 May 2020 16:03:52 +0800 Subject: serial: lantiq: Add x86 in Kconfig dependencies for Lantiq serial driver Lantiq serial driver/IP is reused for a x86 based SoC as well. Update the Kconfig accordingly. Signed-off-by: Rahul Tanwar Link: https://lore.kernel.org/r/96fd193c0a8939d27641ff93573545c02313048f.1588577002.git.rahul.tanwar@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 0aea76cd67ff..4b0a7b98f8c7 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1035,7 +1035,7 @@ config SERIAL_SIFIVE_CONSOLE config SERIAL_LANTIQ bool "Lantiq serial driver" - depends on LANTIQ + depends on (LANTIQ || X86) || COMPILE_TEST select SERIAL_CORE select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON -- cgit v1.2.3 From 3d9231e69831551da3a78a618b31702ea4dedd5e Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Sun, 3 May 2020 17:34:24 +0530 Subject: tty: serial: qcom_geni_serial: Use OPP API to set clk/perf state geni serial needs to express a perforamnce state requirement on CX powerdomain depending on the frequency of the clock rates. Use OPP table from DT to register with OPP framework and use dev_pm_opp_set_rate() to set the clk/perf state. Signed-off-by: Rajendra Nayak Reviewed-by: Matthias Kaehlcke Cc: Greg Kroah-Hartman Cc: Akash Asthana Cc: linux-serial@vger.kernel.org Link: https://lore.kernel.org/r/1588507469-31889-2-git-send-email-rnayak@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 34 +++++++++++++++++++++++++++++----- include/linux/qcom-geni-se.h | 4 ++++ 2 files changed, 33 insertions(+), 5 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 6119090ce045..dd3d1ba38bd9 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -961,7 +962,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, goto out_restart_rx; uport->uartclk = clk_rate; - clk_set_rate(port->se.clk, clk_rate); + dev_pm_opp_set_rate(uport->dev, clk_rate); ser_clk_cfg = SER_CLK_EN; ser_clk_cfg |= clk_div << CLK_DIV_SHFT; @@ -1198,8 +1199,11 @@ static void qcom_geni_serial_pm(struct uart_port *uport, if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) geni_se_resources_on(&port->se); else if (new_state == UART_PM_STATE_OFF && - old_state == UART_PM_STATE_ON) + old_state == UART_PM_STATE_ON) { + /* Drop the performance state vote */ + dev_pm_opp_set_rate(uport->dev, 0); geni_se_resources_off(&port->se); + } } static const struct uart_ops qcom_geni_console_pops = { @@ -1318,13 +1322,25 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap")) port->cts_rts_swap = true; + port->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se"); + if (IS_ERR(port->se.opp_table)) + return PTR_ERR(port->se.opp_table); + /* OPP table is optional */ + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (!ret) { + port->se.has_opp_table = true; + } else if (ret != -ENODEV) { + dev_err(&pdev->dev, "invalid OPP table in device tree\n"); + return ret; + } + uport->private_data = drv; platform_set_drvdata(pdev, port); port->handle_rx = console ? handle_rx_console : handle_rx_uart; ret = uart_add_one_port(drv, uport); if (ret) - return ret; + goto err; irq_set_status_flags(uport->irq, IRQ_NOAUTOEN); ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr, @@ -1332,7 +1348,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (ret) { dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); uart_remove_one_port(drv, uport); - return ret; + goto err; } /* @@ -1349,11 +1365,16 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (ret) { device_init_wakeup(&pdev->dev, false); uart_remove_one_port(drv, uport); - return ret; + goto err; } } return 0; +err: + if (port->se.has_opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(port->se.opp_table); + return ret; } static int qcom_geni_serial_remove(struct platform_device *pdev) @@ -1361,6 +1382,9 @@ static int qcom_geni_serial_remove(struct platform_device *pdev) struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); struct uart_driver *drv = port->uport.private_data; + if (port->se.has_opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(port->se.opp_table); dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); uart_remove_one_port(drv, &port->uport); diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h index dd464943f717..6b78094a4e23 100644 --- a/include/linux/qcom-geni-se.h +++ b/include/linux/qcom-geni-se.h @@ -33,6 +33,8 @@ struct clk; * @clk: Handle to the core serial engine clock * @num_clk_levels: Number of valid clock levels in clk_perf_tbl * @clk_perf_tbl: Table of clock frequency input to serial engine clock + * @opp_table: Pointer to the OPP table + * @has_opp_table: Specifies if the SE has an OPP table */ struct geni_se { void __iomem *base; @@ -41,6 +43,8 @@ struct geni_se { struct clk *clk; unsigned int num_clk_levels; unsigned long *clk_perf_tbl; + struct opp_table *opp_table; + bool has_opp_table; }; /* Common SE registers */ -- cgit v1.2.3 From 8508f4cba308f785b2fd4b8c38849c117b407297 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 28 Apr 2020 18:40:50 +0000 Subject: serial: amba-pl011: Make sure we initialize the port.lock spinlock Valentine reported seeing: [ 3.626638] INFO: trying to register non-static key. [ 3.626639] the code is fine but needs lockdep annotation. [ 3.626640] turning off the locking correctness validator. [ 3.626644] CPU: 7 PID: 51 Comm: kworker/7:1 Not tainted 5.7.0-rc2-00115-g8c2e9790f196 #116 [ 3.626646] Hardware name: HiKey960 (DT) [ 3.626656] Workqueue: events deferred_probe_work_func [ 3.632476] sd 0:0:0:0: [sda] Optimal transfer size 8192 bytes not a multiple of physical block size (16384 bytes) [ 3.640220] Call trace: [ 3.640225] dump_backtrace+0x0/0x1b8 [ 3.640227] show_stack+0x20/0x30 [ 3.640230] dump_stack+0xec/0x158 [ 3.640234] register_lock_class+0x598/0x5c0 [ 3.640235] __lock_acquire+0x80/0x16c0 [ 3.640236] lock_acquire+0xf4/0x4a0 [ 3.640241] _raw_spin_lock_irqsave+0x70/0xa8 [ 3.640245] uart_add_one_port+0x388/0x4b8 [ 3.640248] pl011_register_port+0x70/0xf0 [ 3.640250] pl011_probe+0x184/0x1b8 [ 3.640254] amba_probe+0xdc/0x180 [ 3.640256] really_probe+0xe0/0x338 [ 3.640257] driver_probe_device+0x60/0xf8 [ 3.640259] __device_attach_driver+0x8c/0xd0 [ 3.640260] bus_for_each_drv+0x84/0xd8 [ 3.640261] __device_attach+0xe4/0x140 [ 3.640263] device_initial_probe+0x1c/0x28 [ 3.640265] bus_probe_device+0xa4/0xb0 [ 3.640266] deferred_probe_work_func+0x7c/0xb8 [ 3.640269] process_one_work+0x2c0/0x768 [ 3.640271] worker_thread+0x4c/0x498 [ 3.640272] kthread+0x14c/0x158 [ 3.640275] ret_from_fork+0x10/0x1c Which seems to be due to the fact that after allocating the uap structure, nothing initializes the spinlock. Its a little confusing, as uart_port_spin_lock_init() is one place where the lock is supposed to be initialized, but it has an exception for the case where the port is a console. This makes it seem like a deeper fix is needed to properly register the console, but I'm not sure what that entails, and Andy suggested that this approach is less invasive. Thus, this patch resolves the issue by initializing the spinlock in the driver, and resolves the resulting warning. Cc: Andy Shevchenko Cc: Russell King Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Reported-by: Valentin Schneider Reviewed-by: Andy Shevchenko Signed-off-by: John Stultz Reviewed-and-tested-by: Valentin Schneider Link: https://lore.kernel.org/r/20200428184050.6501-1-john.stultz@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 2296bb0f9578..458fc3d9d48c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2575,6 +2575,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE); uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = index; + spin_lock_init(&uap->port.lock); amba_ports[index] = uap; -- cgit v1.2.3 From 0a64f38037cc230e2ad888a74263db6f6588cd90 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 6 May 2020 14:29:02 +0200 Subject: Revert "tty: serial: qcom_geni_serial: Use OPP API to set clk/perf state" This reverts commit 3d9231e69831551da3a78a618b31702ea4dedd5e Rajendra writes: Greg, there are other patches in the series which have a dependency on this patch [1] would it be possible for you to drop this patch and instead ack it so it can be taken via the msm tree? So dropping it from here. Reported-by: Rajendra Nayak Cc: Matthias Kaehlcke Cc: Akash Asthana Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 34 +++++----------------------------- include/linux/qcom-geni-se.h | 4 ---- 2 files changed, 5 insertions(+), 33 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index dd3d1ba38bd9..6119090ce045 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -962,7 +961,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, goto out_restart_rx; uport->uartclk = clk_rate; - dev_pm_opp_set_rate(uport->dev, clk_rate); + clk_set_rate(port->se.clk, clk_rate); ser_clk_cfg = SER_CLK_EN; ser_clk_cfg |= clk_div << CLK_DIV_SHFT; @@ -1199,11 +1198,8 @@ static void qcom_geni_serial_pm(struct uart_port *uport, if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) geni_se_resources_on(&port->se); else if (new_state == UART_PM_STATE_OFF && - old_state == UART_PM_STATE_ON) { - /* Drop the performance state vote */ - dev_pm_opp_set_rate(uport->dev, 0); + old_state == UART_PM_STATE_ON) geni_se_resources_off(&port->se); - } } static const struct uart_ops qcom_geni_console_pops = { @@ -1322,25 +1318,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap")) port->cts_rts_swap = true; - port->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se"); - if (IS_ERR(port->se.opp_table)) - return PTR_ERR(port->se.opp_table); - /* OPP table is optional */ - ret = dev_pm_opp_of_add_table(&pdev->dev); - if (!ret) { - port->se.has_opp_table = true; - } else if (ret != -ENODEV) { - dev_err(&pdev->dev, "invalid OPP table in device tree\n"); - return ret; - } - uport->private_data = drv; platform_set_drvdata(pdev, port); port->handle_rx = console ? handle_rx_console : handle_rx_uart; ret = uart_add_one_port(drv, uport); if (ret) - goto err; + return ret; irq_set_status_flags(uport->irq, IRQ_NOAUTOEN); ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr, @@ -1348,7 +1332,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (ret) { dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); uart_remove_one_port(drv, uport); - goto err; + return ret; } /* @@ -1365,16 +1349,11 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (ret) { device_init_wakeup(&pdev->dev, false); uart_remove_one_port(drv, uport); - goto err; + return ret; } } return 0; -err: - if (port->se.has_opp_table) - dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_clkname(port->se.opp_table); - return ret; } static int qcom_geni_serial_remove(struct platform_device *pdev) @@ -1382,9 +1361,6 @@ static int qcom_geni_serial_remove(struct platform_device *pdev) struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); struct uart_driver *drv = port->uport.private_data; - if (port->se.has_opp_table) - dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_clkname(port->se.opp_table); dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); uart_remove_one_port(drv, &port->uport); diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h index 6b78094a4e23..dd464943f717 100644 --- a/include/linux/qcom-geni-se.h +++ b/include/linux/qcom-geni-se.h @@ -33,8 +33,6 @@ struct clk; * @clk: Handle to the core serial engine clock * @num_clk_levels: Number of valid clock levels in clk_perf_tbl * @clk_perf_tbl: Table of clock frequency input to serial engine clock - * @opp_table: Pointer to the OPP table - * @has_opp_table: Specifies if the SE has an OPP table */ struct geni_se { void __iomem *base; @@ -43,8 +41,6 @@ struct geni_se { struct clk *clk; unsigned int num_clk_levels; unsigned long *clk_perf_tbl; - struct opp_table *opp_table; - bool has_opp_table; }; /* Common SE registers */ -- cgit v1.2.3 From 8fba6c0c4c4a5291a62dd231e996eff09725489f Mon Sep 17 00:00:00 2001 From: Hyunki Koo Date: Wed, 6 May 2020 17:02:38 +0900 Subject: serial: samsung: Replace rd_regb/wr_regb with rd_reg/wr_reg This patch change the name of macro for general usage. Signed-off-by: Hyunki Koo Reviewed-by: Krzysztof Kozlowski Tested on Odroid HC1 (Exynos5422): Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200506080242.18623-1-hyunki00.koo@samsung.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 73f951d65b93..326b0164609c 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -154,10 +154,10 @@ struct s3c24xx_uart_port { #define portaddrl(port, reg) \ ((unsigned long *)(unsigned long)((port)->membase + (reg))) -#define rd_regb(port, reg) (readb_relaxed(portaddr(port, reg))) +#define rd_reg(port, reg) (readb_relaxed(portaddr(port, reg))) #define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg))) -#define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) +#define wr_reg(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) #define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg)) /* Byte-order aware bit setting/clearing functions. */ @@ -714,7 +714,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) fifocnt--; uerstat = rd_regl(port, S3C2410_UERSTAT); - ch = rd_regb(port, S3C2410_URXH); + ch = rd_reg(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { int txe = s3c24xx_serial_txempty_nofifo(port); @@ -826,7 +826,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) } if (port->x_char) { - wr_regb(port, S3C2410_UTXH, port->x_char); + wr_reg(port, S3C2410_UTXH, port->x_char); port->icount.tx++; port->x_char = 0; goto out; @@ -852,7 +852,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) break; - wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]); + wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; count--; @@ -916,7 +916,7 @@ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) /* no modem control lines */ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) { - unsigned int umstat = rd_regb(port, S3C2410_UMSTAT); + unsigned int umstat = rd_reg(port, S3C2410_UMSTAT); if (umstat & S3C2410_UMSTAT_CTS) return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; @@ -2185,7 +2185,7 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port) if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) return NO_POLL_CHAR; - return rd_regb(port, S3C2410_URXH); + return rd_reg(port, S3C2410_URXH); } static void s3c24xx_serial_put_poll_char(struct uart_port *port, @@ -2200,7 +2200,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); - wr_regb(port, S3C2410_UTXH, c); + wr_reg(port, S3C2410_UTXH, c); } #endif /* CONFIG_CONSOLE_POLL */ @@ -2212,7 +2212,7 @@ s3c24xx_serial_console_putchar(struct uart_port *port, int ch) while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); - wr_regb(port, S3C2410_UTXH, ch); + wr_reg(port, S3C2410_UTXH, ch); } static void -- cgit v1.2.3 From 57253ccd5831e7e5720c433437775c3e6b7d0c72 Mon Sep 17 00:00:00 2001 From: Hyunki Koo Date: Wed, 6 May 2020 17:02:40 +0900 Subject: serial: samsung: 32-bit access for TX/RX hold registers Support 32-bit access for the TX/RX hold registers UTXH and URXH. This is required for some newer SoCs. Signed-off-by: Hyunki Koo Reviewed-by: Krzysztof Kozlowski Tested on Odroid HC1 (Exynos5422): Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200506080242.18623-3-hyunki00.koo@samsung.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 62 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 326b0164609c..6ef614d8648c 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -154,10 +154,33 @@ struct s3c24xx_uart_port { #define portaddrl(port, reg) \ ((unsigned long *)(unsigned long)((port)->membase + (reg))) -#define rd_reg(port, reg) (readb_relaxed(portaddr(port, reg))) +static u32 rd_reg(struct uart_port *port, u32 reg) +{ + switch (port->iotype) { + case UPIO_MEM: + return readb_relaxed(portaddr(port, reg)); + case UPIO_MEM32: + return readl_relaxed(portaddr(port, reg)); + default: + return 0; + } + return 0; +} + #define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg))) -#define wr_reg(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) +static void wr_reg(struct uart_port *port, u32 reg, u32 val) +{ + switch (port->iotype) { + case UPIO_MEM: + writeb_relaxed(val, portaddr(port, reg)); + break; + case UPIO_MEM32: + writel_relaxed(val, portaddr(port, reg)); + break; + } +} + #define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg)) /* Byte-order aware bit setting/clearing functions. */ @@ -1974,7 +1997,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct s3c24xx_uart_port *ourport; int index = probe_index; - int ret; + int ret, prop = 0; if (np) { ret = of_alias_get_id(np, "serial"); @@ -2000,10 +2023,27 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; - if (np) + if (np) { of_property_read_u32(np, "samsung,uart-fifosize", &ourport->port.fifosize); + if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { + switch (prop) { + case 1: + ourport->port.iotype = UPIO_MEM; + break; + case 4: + ourport->port.iotype = UPIO_MEM32; + break; + default: + dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n", + prop); + ret = -EINVAL; + break; + } + } + } + if (ourport->drv_data->fifosize[index]) ourport->port.fifosize = ourport->drv_data->fifosize[index]; else if (ourport->info->fifosize) @@ -2587,6 +2627,18 @@ module_platform_driver(samsung_serial_driver); * Early console. */ +static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val) +{ + switch (port->iotype) { + case UPIO_MEM: + writeb(val, portaddr(port, reg)); + break; + case UPIO_MEM32: + writel(val, portaddr(port, reg)); + break; + } +} + struct samsung_early_console_data { u32 txfull_mask; }; @@ -2612,7 +2664,7 @@ static void samsung_early_putc(struct uart_port *port, int c) else samsung_early_busyuart(port); - writeb(c, port->membase + S3C2410_UTXH); + wr_reg_barrier(port, S3C2410_UTXH, c); } static void samsung_early_write(struct console *con, const char *s, -- cgit v1.2.3 From ea7d3fd8a6d0654f8bbb1cb7d4ecc57a346f7daf Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Mon, 11 May 2020 13:57:26 +0800 Subject: serial: lantiq: Make UART's use as console selectable Lantiq UART driver can be used for system console. Add changes to make this driver's use as console selectable/configurable. Signed-off-by: Rahul Tanwar Link: https://lore.kernel.org/r/35f2d002ba1cb26192fe4d9b8cdab275300705bc.1589176044.git.rahul.tanwar@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 9 ++++++++- drivers/tty/serial/lantiq.c | 11 ++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a3cd1cc64c1e..a81b42b1d534 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1037,10 +1037,17 @@ config SERIAL_LANTIQ bool "Lantiq serial driver" depends on (LANTIQ || X86) || COMPILE_TEST select SERIAL_CORE + help + Support for UART on Lantiq and Intel SoCs. + +config SERIAL_LANTIQ_CONSOLE + bool "Console on Lantiq UART" + depends on SERIAL_LANTIQ=y select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help - Support for console and UART on Lantiq SoCs. + Select this option if you would like to use a Lantiq UART as the + system console. config SERIAL_QE tristate "Freescale QUICC Engine serial port support" diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index c5e46ff972e4..d3b62a1be6ad 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -597,6 +597,7 @@ static const struct uart_ops lqasc_pops = { .verify_port = lqasc_verify_port, }; +#ifdef CONFIG_SERIAL_LANTIQ_CONSOLE static void lqasc_console_putchar(struct uart_port *port, int ch) { @@ -705,6 +706,14 @@ lqasc_serial_early_console_setup(struct earlycon_device *device, OF_EARLYCON_DECLARE(lantiq, "lantiq,asc", lqasc_serial_early_console_setup); OF_EARLYCON_DECLARE(lantiq, "intel,lgm-asc", lqasc_serial_early_console_setup); +#define LANTIQ_SERIAL_CONSOLE (&lqasc_console) + +#else + +#define LANTIQ_SERIAL_CONSOLE NULL + +#endif /* CONFIG_SERIAL_LANTIQ_CONSOLE */ + static struct uart_driver lqasc_reg = { .owner = THIS_MODULE, .driver_name = DRVNAME, @@ -712,7 +721,7 @@ static struct uart_driver lqasc_reg = { .major = 0, .minor = 0, .nr = MAXPORTS, - .cons = &lqasc_console, + .cons = LANTIQ_SERIAL_CONSOLE, }; static int fetch_irq_lantiq(struct device *dev, struct ltq_uart_port *ltq_port) -- cgit v1.2.3 From ad406341bdd7d22ba9497931c2df5dde6bb9440e Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Mon, 11 May 2020 13:57:27 +0800 Subject: serial: lantiq: Make driver modular Add changes so Lantiq serial driver can be compiled as a module. Signed-off-by: Rahul Tanwar Link: https://lore.kernel.org/r/ad9422de006c317401bfa5fe61bdd4293dd29b5e.1589176044.git.rahul.tanwar@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 4 +++- drivers/tty/serial/lantiq.c | 29 +++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a81b42b1d534..1cb99d9f983e 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1034,11 +1034,13 @@ config SERIAL_SIFIVE_CONSOLE boot time.) config SERIAL_LANTIQ - bool "Lantiq serial driver" + tristate "Lantiq serial driver" depends on (LANTIQ || X86) || COMPILE_TEST select SERIAL_CORE help Support for UART on Lantiq and Intel SoCs. + To compile this driver as a module, select M here. The + module will be called lantiq. config SERIAL_LANTIQ_CONSOLE bool "Console on Lantiq UART" diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index d3b62a1be6ad..62813e421f12 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -823,8 +824,7 @@ static void free_irq_intel(struct uart_port *port) free_irq(ltq_port->common_irq, port); } -static int __init -lqasc_probe(struct platform_device *pdev) +static int lqasc_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct ltq_uart_port *ltq_port; @@ -908,6 +908,13 @@ lqasc_probe(struct platform_device *pdev) return ret; } +static int lqasc_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + + return uart_remove_one_port(&lqasc_reg, port); +} + static const struct ltq_soc_data soc_data_lantiq = { .fetch_irq = fetch_irq_lantiq, .request_irq = request_irq_lantiq, @@ -925,8 +932,11 @@ static const struct of_device_id ltq_asc_match[] = { { .compatible = "intel,lgm-asc", .data = &soc_data_intel }, {}, }; +MODULE_DEVICE_TABLE(of, ltq_asc_match); static struct platform_driver lqasc_driver = { + .probe = lqasc_probe, + .remove = lqasc_remove, .driver = { .name = DRVNAME, .of_match_table = ltq_asc_match, @@ -942,10 +952,21 @@ init_lqasc(void) if (ret != 0) return ret; - ret = platform_driver_probe(&lqasc_driver, lqasc_probe); + ret = platform_driver_register(&lqasc_driver); if (ret != 0) uart_unregister_driver(&lqasc_reg); return ret; } -device_initcall(init_lqasc); + +static void __exit exit_lqasc(void) +{ + platform_driver_unregister(&lqasc_driver); + uart_unregister_driver(&lqasc_reg); +} + +module_init(init_lqasc); +module_exit(exit_lqasc); + +MODULE_DESCRIPTION("Serial driver for Lantiq & Intel gateway SoCs"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 7d31676a8d91dd18e08853efd1cb26961a38c6a6 Mon Sep 17 00:00:00 2001 From: Jonathan Bakker Date: Fri, 8 May 2020 18:34:33 -0700 Subject: tty: serial: samsung: Correct clock selection logic Some variants of the samsung tty driver can pick which clock to use for their baud rate generation. In the DT conversion, a default clock was selected to be used if a specific one wasn't assigned and then a comparison of which clock rate worked better was done. Unfortunately, the comparison was implemented in such a way that only the default clock was ever actually compared. Fix this by iterating through all possible clocks, except when a specific clock has already been picked via clk_sel (which is only possible via board files). Signed-off-by: Jonathan Bakker Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/BN6PR04MB06604E63833EA41837EBF77BA3A30@BN6PR04MB0660.namprd04.prod.outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 6ef614d8648c..d913d9b2762a 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1304,14 +1304,14 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, struct s3c24xx_uart_info *info = ourport->info; struct clk *clk; unsigned long rate; - unsigned int cnt, baud, quot, clk_sel, best_quot = 0; + unsigned int cnt, baud, quot, best_quot = 0; char clkname[MAX_CLK_NAME_LENGTH]; int calc_deviation, deviation = (1 << 30) - 1; - clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel : - ourport->info->def_clk_sel; for (cnt = 0; cnt < info->num_clks; cnt++) { - if (!(clk_sel & (1 << cnt))) + /* Keep selected clock if provided */ + if (ourport->cfg->clk_sel && + !(ourport->cfg->clk_sel & (1 << cnt))) continue; sprintf(clkname, "clk_uart_baud%d", cnt); -- cgit v1.2.3 From 6cf61b9bd7cc95ebaeb256155f2c83966555151a Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 20 Apr 2020 22:32:04 +0530 Subject: tty: serial: Add modem control gpio support for STM32 UART STM32 UART controllers have the built in modem control support using dedicated gpios which can be enabled using 'st,hw-flow-ctrl' flag in DT. But there might be cases where the board design need to use different gpios for modem control. For supporting such cases, this commit adds modem control gpio support to STM32 UART controller using mctrl_gpio driver. Reviewed-by: Andy Shevchenko Signed-off-by: Manivannan Sadhasivam Acked-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20200420170204.24541-3-mani@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/stm32-usart.c | 53 ++++++++++++++++++++++++++++++++++++++-- drivers/tty/serial/stm32-usart.h | 1 + 3 files changed, 53 insertions(+), 2 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 1cb99d9f983e..0282ad9cdaa7 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1471,6 +1471,7 @@ config SERIAL_STM32 tristate "STMicroelectronics STM32 serial port support" select SERIAL_CORE depends on ARCH_STM32 || COMPILE_TEST + select SERIAL_MCTRL_GPIO if GPIOLIB help This driver is for the on-chip Serial Controller on STMicroelectronics STM32 MCUs. diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 5e93e8d40f59..17c2f3276888 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -31,6 +31,7 @@ #include #include +#include "serial_mctrl_gpio.h" #include "stm32-usart.h" static void stm32_stop_tx(struct uart_port *port); @@ -510,12 +511,29 @@ static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE); else stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE); + + mctrl_gpio_set(stm32_port->gpios, mctrl); } static unsigned int stm32_get_mctrl(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int ret; + /* This routine is used to get signals of: DCD, DSR, RI, and CTS */ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + ret = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + + return mctrl_gpio_get(stm32_port->gpios, &ret); +} + +static void stm32_enable_ms(struct uart_port *port) +{ + mctrl_gpio_enable_ms(to_stm32_port(port)->gpios); +} + +static void stm32_disable_ms(struct uart_port *port) +{ + mctrl_gpio_disable_ms(to_stm32_port(port)->gpios); } /* Transmit stop */ @@ -626,6 +644,9 @@ static void stm32_shutdown(struct uart_port *port) u32 val, isr; int ret; + /* Disable modem control interrupts */ + stm32_disable_ms(port); + val = USART_CR1_TXEIE | USART_CR1_TE; val |= stm32_port->cr1_irq | USART_CR1_RE; val |= BIT(cfg->uart_enable_bit); @@ -764,6 +785,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; } + /* Handle modem control interrupts */ + if (UART_ENABLE_MS(port, termios->c_cflag)) + stm32_enable_ms(port); + else + stm32_disable_ms(port); + usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); /* @@ -898,6 +925,7 @@ static const struct uart_ops stm32_uart_ops = { .throttle = stm32_throttle, .unthrottle = stm32_unthrottle, .stop_rx = stm32_stop_rx, + .enable_ms = stm32_enable_ms, .break_ctl = stm32_break_ctl, .startup = stm32_startup, .shutdown = stm32_shutdown, @@ -960,10 +988,31 @@ static int stm32_init_port(struct stm32_port *stm32port, stm32port->port.uartclk = clk_get_rate(stm32port->clk); if (!stm32port->port.uartclk) { - clk_disable_unprepare(stm32port->clk); ret = -EINVAL; + goto err_clk; + } + + stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0); + if (IS_ERR(stm32port->gpios)) { + ret = PTR_ERR(stm32port->gpios); + goto err_clk; } + /* Both CTS/RTS gpios and "st,hw-flow-ctrl" should not be specified */ + if (stm32port->hw_flow_control) { + if (mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_CTS) || + mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_RTS)) { + dev_err(&pdev->dev, "Conflicting RTS/CTS config\n"); + ret = -EINVAL; + goto err_clk; + } + } + + return ret; + +err_clk: + clk_disable_unprepare(stm32port->clk); + return ret; } diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index db8bf0d4982d..d4c916e78d40 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -274,6 +274,7 @@ struct stm32_port { bool fifoen; int wakeirq; int rdr_mask; /* receive data register mask */ + struct mctrl_gpios *gpios; /* modem control gpios */ }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; -- cgit v1.2.3 From 24637007394e85737ff1798fcd0f62f1fd7dc6af Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 May 2020 17:02:52 +0300 Subject: serial: 8250_exar: Make use of PCI_DEVICE_DATA() macro Since PCI core provides a generic PCI_DEVICE_DATA() macro, replace contents of EXAR_DEVICE() with former one. No functional change intended. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200512140252.67631-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 65 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 34 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 59449b6500cd..ddb6aeb76dc5 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -25,13 +25,13 @@ #include "8250.h" -#define PCI_DEVICE_ID_ACCES_COM_2S 0x1052 -#define PCI_DEVICE_ID_ACCES_COM_4S 0x105d -#define PCI_DEVICE_ID_ACCES_COM_8S 0x106c -#define PCI_DEVICE_ID_ACCES_COM232_8 0x10a8 -#define PCI_DEVICE_ID_ACCES_COM_2SM 0x10d2 -#define PCI_DEVICE_ID_ACCES_COM_4SM 0x10db -#define PCI_DEVICE_ID_ACCES_COM_8SM 0x10ea +#define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052 +#define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d +#define PCI_DEVICE_ID_ACCESSIO_COM_8S 0x106c +#define PCI_DEVICE_ID_ACCESSIO_COM232_8 0x10a8 +#define PCI_DEVICE_ID_ACCESSIO_COM_2SM 0x10d2 +#define PCI_DEVICE_ID_ACCESSIO_COM_4SM 0x10db +#define PCI_DEVICE_ID_ACCESSIO_COM_8SM 0x10ea #define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002 #define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004 @@ -755,9 +755,7 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { (kernel_ulong_t)&bd \ } -#define EXAR_DEVICE(vend, devid, bd) { \ - PCI_VDEVICE(vend, PCI_DEVICE_ID_##devid), (kernel_ulong_t)&bd \ - } +#define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) } #define IBM_DEVICE(devid, sdevid, bd) { \ PCI_DEVICE_SUB( \ @@ -769,14 +767,13 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { } static const struct pci_device_id exar_pci_tbl[] = { - EXAR_DEVICE(ACCESSIO, ACCES_COM_2S, acces_com_2x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_4S, acces_com_4x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_8S, acces_com_8x), - EXAR_DEVICE(ACCESSIO, ACCES_COM232_8, acces_com_8x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_2SM, acces_com_2x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_4SM, acces_com_4x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_8SM, acces_com_8x), - + EXAR_DEVICE(ACCESSIO, COM_2S, acces_com_2x), + EXAR_DEVICE(ACCESSIO, COM_4S, acces_com_4x), + EXAR_DEVICE(ACCESSIO, COM_8S, acces_com_8x), + EXAR_DEVICE(ACCESSIO, COM232_8, acces_com_8x), + EXAR_DEVICE(ACCESSIO, COM_2SM, acces_com_2x), + EXAR_DEVICE(ACCESSIO, COM_4SM, acces_com_4x), + EXAR_DEVICE(ACCESSIO, COM_8SM, acces_com_8x), CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), @@ -794,24 +791,24 @@ static const struct pci_device_id exar_pci_tbl[] = { IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn), /* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */ - EXAR_DEVICE(EXAR, EXAR_XR17C152, pbn_exar_XR17C15x), - EXAR_DEVICE(EXAR, EXAR_XR17C154, pbn_exar_XR17C15x), - EXAR_DEVICE(EXAR, EXAR_XR17C158, pbn_exar_XR17C15x), + EXAR_DEVICE(EXAR, XR17C152, pbn_exar_XR17C15x), + EXAR_DEVICE(EXAR, XR17C154, pbn_exar_XR17C15x), + EXAR_DEVICE(EXAR, XR17C158, pbn_exar_XR17C15x), /* Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs */ - EXAR_DEVICE(EXAR, EXAR_XR17V352, pbn_exar_XR17V35x), - EXAR_DEVICE(EXAR, EXAR_XR17V354, pbn_exar_XR17V35x), - EXAR_DEVICE(EXAR, EXAR_XR17V358, pbn_exar_XR17V35x), - EXAR_DEVICE(EXAR, EXAR_XR17V4358, pbn_exar_XR17V4358), - EXAR_DEVICE(EXAR, EXAR_XR17V8358, pbn_exar_XR17V8358), - EXAR_DEVICE(COMMTECH, COMMTECH_4222PCIE, pbn_exar_XR17V35x), - EXAR_DEVICE(COMMTECH, COMMTECH_4224PCIE, pbn_exar_XR17V35x), - EXAR_DEVICE(COMMTECH, COMMTECH_4228PCIE, pbn_exar_XR17V35x), - - EXAR_DEVICE(COMMTECH, COMMTECH_4222PCI335, pbn_fastcom335_2), - EXAR_DEVICE(COMMTECH, COMMTECH_4224PCI335, pbn_fastcom335_4), - EXAR_DEVICE(COMMTECH, COMMTECH_2324PCI335, pbn_fastcom335_4), - EXAR_DEVICE(COMMTECH, COMMTECH_2328PCI335, pbn_fastcom335_8), + EXAR_DEVICE(EXAR, XR17V352, pbn_exar_XR17V35x), + EXAR_DEVICE(EXAR, XR17V354, pbn_exar_XR17V35x), + EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x), + EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358), + EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358), + EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_exar_XR17V35x), + EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_exar_XR17V35x), + EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_exar_XR17V35x), + + EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2), + EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4), + EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4), + EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8), { 0, } }; MODULE_DEVICE_TABLE(pci, exar_pci_tbl); -- cgit v1.2.3 From aa49d8e8b2dfc112f7de9c58698ae06b2101c73c Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 11 May 2020 15:09:56 +0800 Subject: tty: serial: imx: Add return value check for platform_get_irq() RX irq is required, so add return value check for platform_get_irq(). Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1589180996-618-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index f4d68109bc8b..f4023d9d8e7a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2252,6 +2252,8 @@ static int imx_uart_probe(struct platform_device *pdev) return PTR_ERR(base); rxirq = platform_get_irq(pdev, 0); + if (rxirq < 0) + return rxirq; txirq = platform_get_irq_optional(pdev, 1); rtsirq = platform_get_irq_optional(pdev, 2); -- cgit v1.2.3 From e0a851fe6b9b619527bd928aa93caaddd003f70c Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 12 May 2020 14:40:01 +0200 Subject: serial: 8250: Avoid error message on reprobe If the call to uart_add_one_port() in serial8250_register_8250_port() fails, a half-initialized entry in the serial_8250ports[] array is left behind. A subsequent reprobe of the same serial port causes that entry to be reused. Because uart->port.dev is set, uart_remove_one_port() is called for the half-initialized entry and bails out with an error message: bcm2835-aux-uart 3f215040.serial: Removing wrong port: (null) != (ptrval) The same happens on failure of mctrl_gpio_init() since commit 4a96895f74c9 ("tty/serial/8250: use mctrl_gpio helpers"). Fix by zeroing the uart->port.dev pointer in the probe error path. The bug was introduced in v2.6.10 by historical commit befff6f5bf5f ("[SERIAL] Add new port registration/unregistration functions."): https://git.kernel.org/tglx/history/c/befff6f5bf5f The commit added an unconditional call to uart_remove_one_port() in serial8250_register_port(). In v3.7, commit 835d844d1a28 ("8250_pnp: do pnp probe before legacy probe") made that call conditional on uart->port.dev which allows me to fix the issue by zeroing that pointer in the error path. Thus, the present commit will fix the problem as far back as v3.7 whereas still older versions need to also cherry-pick 835d844d1a28. Fixes: 835d844d1a28 ("8250_pnp: do pnp probe before legacy probe") Signed-off-by: Lukas Wunner Cc: stable@vger.kernel.org # v2.6.10 Cc: stable@vger.kernel.org # v2.6.10: 835d844d1a28: 8250_pnp: do pnp probe before legacy Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/b4a072013ee1a1d13ee06b4325afb19bda57ca1b.1589285873.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 45d9117cab68..9548d3f8fc8e 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1040,7 +1040,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up) gpios = mctrl_gpio_init(&uart->port, 0); if (IS_ERR(gpios)) { ret = PTR_ERR(gpios); - goto out_unlock; + goto err; } else { uart->gpios = gpios; } @@ -1089,8 +1089,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) serial8250_apply_quirks(uart); ret = uart_add_one_port(&serial8250_reg, &uart->port); - if (ret == 0) - ret = uart->port.line; + if (ret) + goto err; + + ret = uart->port.line; } else { dev_info(uart->port.dev, "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n", @@ -1112,10 +1114,14 @@ int serial8250_register_8250_port(struct uart_8250_port *up) } } -out_unlock: mutex_unlock(&serial_mutex); return ret; + +err: + uart->port.dev = NULL; + mutex_unlock(&serial_mutex); + return ret; } EXPORT_SYMBOL(serial8250_register_8250_port); -- cgit v1.2.3 From c150c0f362c1e51c0e3216c9912b85b71d00e70d Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 12 May 2020 14:40:02 +0200 Subject: serial: Allow uart_get_rs485_mode() to return errno We're about to amend uart_get_rs485_mode() to support a GPIO pin for rs485 bus termination. Retrieving the GPIO descriptor may fail, so allow uart_get_rs485_mode() to return an errno and change all callers to check for failure. The GPIO descriptor is going to be stored in struct uart_port. Pass that struct to uart_get_rs485_mode() in lieu of a struct device and struct serial_rs485, both of which are directly accessible from struct uart_port. A few drivers call uart_get_rs485_mode() before setting the struct device pointer in struct uart_port. Shuffle those calls around where necessary. [Heiko Stuebner did the ar933x_uart.c portion, hence his Signed-off-by.] Signed-off-by: Heiko Stuebner Signed-off-by: Lukas Wunner Link: https://lore.kernel.org/r/271e814af4b0db3bffbbb74abf2b46b75add4516.1589285873.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 4 +++- drivers/tty/serial/ar933x_uart.c | 6 ++++-- drivers/tty/serial/atmel_serial.c | 6 ++++-- drivers/tty/serial/fsl_lpuart.c | 5 ++++- drivers/tty/serial/imx.c | 6 +++++- drivers/tty/serial/omap-serial.c | 4 +++- drivers/tty/serial/serial_core.c | 6 +++++- drivers/tty/serial/stm32-usart.c | 8 ++++---- include/linux/serial_core.h | 2 +- 9 files changed, 33 insertions(+), 14 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 9548d3f8fc8e..fc118f649887 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1026,7 +1026,9 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->port.dev) { uart->port.dev = up->port.dev; - uart_get_rs485_mode(uart->port.dev, &uart->port.rs485); + ret = uart_get_rs485_mode(&uart->port); + if (ret) + goto err; } if (up->port.flags & UPF_FIXED_TYPE) diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 7e7f1398019f..0c80a79d7442 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -766,8 +766,6 @@ static int ar933x_uart_probe(struct platform_device *pdev) goto err_disable_clk; } - uart_get_rs485_mode(&pdev->dev, &port->rs485); - port->mapbase = mem_res->start; port->line = id; port->irq = irq_res->start; @@ -786,6 +784,10 @@ static int ar933x_uart_probe(struct platform_device *pdev) baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); + ret = uart_get_rs485_mode(port); + if (ret) + goto err_disable_clk; + up->gpios = mctrl_gpio_init(port, 0); if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) return PTR_ERR(up->gpios); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 8d7080efad9b..e43471b33710 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2491,8 +2491,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, atmel_init_property(atmel_port, pdev); atmel_set_ops(port); - uart_get_rs485_mode(&mpdev->dev, &port->rs485); - port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->ops = &atmel_pops; @@ -2506,6 +2504,10 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); + ret = uart_get_rs485_mode(port); + if (ret) + return ret; + /* for console, the clock could already be configured */ if (!atmel_port->clk) { atmel_port->clk = clk_get(&mpdev->dev, "usart"); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 6a9909e56449..029324c77cd7 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2619,7 +2619,9 @@ static int lpuart_probe(struct platform_device *pdev) if (ret) goto failed_attach_port; - uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); + ret = uart_get_rs485_mode(&sport->port); + if (ret) + goto failed_get_rs485; if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX) dev_err(&pdev->dev, "driver doesn't support RX during TX\n"); @@ -2632,6 +2634,7 @@ static int lpuart_probe(struct platform_device *pdev) return 0; +failed_get_rs485: failed_attach_port: failed_irq_request: lpuart_disable_clks(sport); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index f4023d9d8e7a..986d902fb7fe 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2304,7 +2304,11 @@ static int imx_uart_probe(struct platform_device *pdev) sport->ucr4 = readl(sport->port.membase + UCR4); sport->ufcr = readl(sport->port.membase + UFCR); - uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); + ret = uart_get_rs485_mode(&sport->port); + if (ret) { + clk_disable_unprepare(sport->clk_ipg); + return ret; + } if (sport->port.rs485.flags & SER_RS485_ENABLED && (!sport->have_rtscts && !sport->have_rtsgpio)) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index c71c1a2266dc..8573fc9cb0cd 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1608,7 +1608,9 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, if (!np) return 0; - uart_get_rs485_mode(up->dev, rs485conf); + ret = uart_get_rs485_mode(&up->port); + if (ret) + return ret; if (of_property_read_bool(np, "rs485-rts-active-high")) { rs485conf->flags |= SER_RS485_RTS_ON_SEND; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 66a5e2faf57e..43b6682877d5 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3295,8 +3295,10 @@ EXPORT_SYMBOL(uart_remove_one_port); * This function implements the device tree binding described in * Documentation/devicetree/bindings/serial/rs485.txt. */ -void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf) +int uart_get_rs485_mode(struct uart_port *port) { + struct serial_rs485 *rs485conf = &port->rs485; + struct device *dev = port->dev; u32 rs485_delay[2]; int ret; @@ -3328,6 +3330,8 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf) rs485conf->flags &= ~SER_RS485_RTS_ON_SEND; rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; } + + return 0; } EXPORT_SYMBOL_GPL(uart_get_rs485_mode); diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 17c2f3276888..7d1acb3786b8 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -159,9 +159,7 @@ static int stm32_init_rs485(struct uart_port *port, if (!pdev->dev.of_node) return -ENODEV; - uart_get_rs485_mode(&pdev->dev, rs485conf); - - return 0; + return uart_get_rs485_mode(port); } static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, @@ -959,7 +957,9 @@ static int stm32_init_port(struct stm32_port *stm32port, port->rs485_config = stm32_config_rs485; - stm32_init_rs485(port, pdev); + ret = stm32_init_rs485(port, pdev); + if (ret) + return ret; if (stm32port->info->cfg.has_wakeup) { stm32port->wakeirq = platform_get_irq(pdev, 1); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 92f5eba86052..b649a2b894e7 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -472,5 +472,5 @@ extern int uart_handle_break(struct uart_port *port); (cflag) & CRTSCTS || \ !((cflag) & CLOCAL)) -void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf); +int uart_get_rs485_mode(struct uart_port *port); #endif /* LINUX_SERIAL_CORE_H */ -- cgit v1.2.3 From 7b668c064ec33f3d687c3a413d05e355172e6c92 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 7 May 2020 02:31:32 +0300 Subject: serial: 8250: Fix max baud limit in generic 8250 port Standard 8250 UART ports are designed in a way so they can communicate with baud rates up to 1/16 of a reference frequency. It's expected from most of the currently supported UART controllers. That's why the former version of serial8250_get_baud_rate() method called uart_get_baud_rate() with min and max baud rates passed as (port->uartclk / 16 / UART_DIV_MAX) and ((port->uartclk + tolerance) / 16) respectively. Doing otherwise, like it was suggested in commit ("serial: 8250_mtk: support big baud rate."), caused acceptance of bauds, which was higher than the normal UART controllers actually supported. As a result if some user-space program requested to set a baud greater than (uartclk / 16) it would have been permitted without truncation, but then serial8250_get_divisor(baud) (which calls uart_get_divisor() to get the reference clock divisor) would have returned a zero divisor. Setting zero divisor will cause an unpredictable effect varying from chip to chip. In case of DW APB UART the communications just stop. Lets fix this problem by getting back the limitation of (uartclk + tolerance) / 16 maximum baud supported by the generic 8250 port. Mediatek 8250 UART ports driver developer shouldn't have touched it in the first place notably seeing he already provided a custom version of set_termios() callback in that glue-driver which took into account the extended baud rate values and accordingly updated the standard and vendor-specific divisor latch registers anyway. Fixes: 81bb549fdf14 ("serial: 8250_mtk: support big baud rate.") Signed-off-by: Serge Semin Cc: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Cc: Arnd Bergmann Cc: Long Cheng Cc: Andy Shevchenko Cc: Maxime Ripard Cc: Catalin Marinas Cc: Will Deacon Cc: Russell King Cc: linux-mips@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mediatek@lists.infradead.org Link: https://lore.kernel.org/r/20200506233136.11842-2-Sergey.Semin@baikalelectronics.ru Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index f77bf820b7a3..4d83c85a7389 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2615,6 +2615,8 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + unsigned int tolerance = port->uartclk / 100; + /* * Ask the core to calculate the divisor for us. * Allow 1% tolerance at the upper limit so uart clks marginally @@ -2623,7 +2625,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, */ return uart_get_baud_rate(port, termios, old, port->uartclk / 16 / UART_DIV_MAX, - port->uartclk); + (port->uartclk + tolerance) / 16); } void -- cgit v1.2.3 From b14109f302d01899a8d7aad0d9a2097faa5fb486 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 15 May 2020 20:58:01 +0800 Subject: tty: serial: fsl_lpuart: Use __maybe_unused instead of #if CONFIG_PM_SLEEP Use __maybe_unused for power management related functions to simplify the code. Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1589547481-25932-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 029324c77cd7..90298c403042 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2665,8 +2665,7 @@ static int lpuart_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int lpuart_suspend(struct device *dev) +static int __maybe_unused lpuart_suspend(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); unsigned long temp; @@ -2724,7 +2723,7 @@ static int lpuart_suspend(struct device *dev) return 0; } -static int lpuart_resume(struct device *dev) +static int __maybe_unused lpuart_resume(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); @@ -2755,7 +2754,6 @@ static int lpuart_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume); -- cgit v1.2.3 From 55484fcc5061c3f41b2f8f37b4a5754d3682f1a5 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Tue, 19 May 2020 11:41:04 +0200 Subject: serial: stm32: add no_console_suspend support In order to display console messages in low power mode, console pins must be kept active after suspend call. Initial patch "serial: stm32: add support for no_console_suspend" was part of "STM32 usart power improvement" series, but as dependancy to console_suspend pinctl state has been removed to fit with Rob comment [1], this patch has no more dependancy with any other patch of this series. [1] https://lkml.org/lkml/2019/7/9/451 Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20200519094104.27082-1-erwan.leray@st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 7d1acb3786b8..8602ff357321 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1424,7 +1424,18 @@ static int __maybe_unused stm32_serial_suspend(struct device *dev) else stm32_serial_enable_wakeup(port, false); - pinctrl_pm_select_sleep_state(dev); + /* + * When "no_console_suspend" is enabled, keep the pinctrl default state + * and rely on bootloader stage to restore this state upon resume. + * Otherwise, apply the idle or sleep states depending on wakeup + * capabilities. + */ + if (console_suspend_enabled || !uart_console(port)) { + if (device_may_wakeup(dev)) + pinctrl_pm_select_idle_state(dev); + else + pinctrl_pm_select_sleep_state(dev); + } return 0; } -- cgit v1.2.3 From 37f3965d74d5b5c914f8f8a108ae1d94ab5ffae3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 21 May 2020 11:11:49 +0200 Subject: sc16is7xx: Always use falling edge IRQ The driver currently only uses IRQF_TRIGGER_FALLING if the probing happened without a device-tree setup. The device however will always generate falling edges on its IRQ line, so let's use that flag in all cases. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20200521091152.404404-4-daniel@zonque.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 06e8071d5601..71a0b288fa11 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1176,7 +1176,7 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, static int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, - struct regmap *regmap, int irq, unsigned long flags) + struct regmap *regmap, int irq) { struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 }; unsigned long freq = 0, *pfreq = dev_get_platdata(dev); @@ -1304,7 +1304,7 @@ static int sc16is7xx_probe(struct device *dev, /* Setup interrupt */ ret = devm_request_irq(dev, irq, sc16is7xx_irq, - flags, dev_name(dev), s); + IRQF_TRIGGER_FALLING, dev_name(dev), s); if (!ret) return 0; @@ -1378,7 +1378,6 @@ static struct regmap_config regcfg = { static int sc16is7xx_spi_probe(struct spi_device *spi) { const struct sc16is7xx_devtype *devtype; - unsigned long flags = 0; struct regmap *regmap; int ret; @@ -1399,14 +1398,13 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) const struct spi_device_id *id_entry = spi_get_device_id(spi); devtype = (struct sc16is7xx_devtype *)id_entry->driver_data; - flags = IRQF_TRIGGER_FALLING; } regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | (devtype->nr_uart - 1); regmap = devm_regmap_init_spi(spi, ®cfg); - return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq, flags); + return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq); } static int sc16is7xx_spi_remove(struct spi_device *spi) @@ -1445,7 +1443,6 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { const struct sc16is7xx_devtype *devtype; - unsigned long flags = 0; struct regmap *regmap; if (i2c->dev.of_node) { @@ -1454,14 +1451,13 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c, return -ENODEV; } else { devtype = (struct sc16is7xx_devtype *)id->driver_data; - flags = IRQF_TRIGGER_FALLING; } regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | (devtype->nr_uart - 1); regmap = devm_regmap_init_i2c(i2c, ®cfg); - return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq, flags); + return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq); } static int sc16is7xx_i2c_remove(struct i2c_client *client) -- cgit v1.2.3 From 6393ff1c4435acc343b1481f5b834b918cb42b12 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 21 May 2020 11:11:50 +0200 Subject: sc16is7xx: Use threaded IRQ Use a threaded IRQ handler to get rid of the irq_work kthread. This also allows for the driver to use interrupts generated by a threaded controller. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20200521091152.404404-5-daniel@zonque.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 71a0b288fa11..3908a2154b7f 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -327,7 +327,6 @@ struct sc16is7xx_port { unsigned char buf[SC16IS7XX_FIFO_SIZE]; struct kthread_worker kworker; struct task_struct *kworker_task; - struct kthread_work irq_work; struct mutex efr_lock; struct sc16is7xx_one p[]; }; @@ -710,9 +709,9 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) return true; } -static void sc16is7xx_ist(struct kthread_work *ws) +static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) { - struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; mutex_lock(&s->efr_lock); @@ -727,13 +726,6 @@ static void sc16is7xx_ist(struct kthread_work *ws) } mutex_unlock(&s->efr_lock); -} - -static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) -{ - struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; - - kthread_queue_work(&s->kworker, &s->irq_work); return IRQ_HANDLED; } @@ -1221,7 +1213,6 @@ static int sc16is7xx_probe(struct device *dev, mutex_init(&s->efr_lock); kthread_init_worker(&s->kworker); - kthread_init_work(&s->irq_work, sc16is7xx_ist); s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, "sc16is7xx"); if (IS_ERR(s->kworker_task)) { @@ -1303,8 +1294,9 @@ static int sc16is7xx_probe(struct device *dev, } /* Setup interrupt */ - ret = devm_request_irq(dev, irq, sc16is7xx_irq, - IRQF_TRIGGER_FALLING, dev_name(dev), s); + ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(dev), s); if (!ret) return 0; -- cgit v1.2.3 From 2d12fc792cdd43da8502de4a425a98e520b1c302 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 21 May 2020 11:11:51 +0200 Subject: sc16is7xx: Allow sharing the IRQ line When the interrupt line is shared with other devices, the IRQ must be level-triggered, as only one device can trigger a falling edge. To support this, try to acquire the IRQ with IRQF_TRIGGER_LOW|IRQF_SHARED first. Interrupt controllers that lack support for level-triggers will return an error, in which case the driver will now retry the acqusition with IRQF_TRIGGER_FALLING, which was also the default before. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20200521091152.404404-6-daniel@zonque.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 3908a2154b7f..7d98367d6e83 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1293,7 +1293,19 @@ static int sc16is7xx_probe(struct device *dev, sc16is7xx_power(&s->p[i].port, 0); } - /* Setup interrupt */ + /* + * Setup interrupt. We first try to acquire the IRQ line as level IRQ. + * If that succeeds, we can allow sharing the interrupt as well. + * In case the interrupt controller doesn't support that, we fall + * back to a non-shared falling-edge trigger. + */ + ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq, + IRQF_TRIGGER_LOW | IRQF_SHARED | + IRQF_ONESHOT, + dev_name(dev), s); + if (!ret) + return 0; + ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), s); -- cgit v1.2.3 From 2aa916e67db3e625cc0bfe577f67034a46f81c8a Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 21 May 2020 11:11:52 +0200 Subject: sc16is7xx: Read the LSR register for basic device presence check Currently, the driver probes just fine and binds all its resources even if the physical device is not present. As the device lacks an identification register, let's at least read the LSR register to check whether a device at the configured address responds to the request at all. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20200521091152.404404-7-daniel@zonque.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 7d98367d6e83..8fee0e8b851f 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1172,6 +1172,7 @@ static int sc16is7xx_probe(struct device *dev, { struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 }; unsigned long freq = 0, *pfreq = dev_get_platdata(dev); + unsigned int val; u32 uartclk = 0; int i, ret; struct sc16is7xx_port *s; @@ -1179,6 +1180,16 @@ static int sc16is7xx_probe(struct device *dev, if (IS_ERR(regmap)) return PTR_ERR(regmap); + /* + * This device does not have an identification register that would + * tell us if we are really connected to the correct device. + * The best we can do is to check if communication is at all possible. + */ + ret = regmap_read(regmap, + SC16IS7XX_LSR_REG << SC16IS7XX_REG_SHIFT, &val); + if (ret < 0) + return ret; + /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL); if (!s) { -- cgit v1.2.3 From 8f065acec7573672dd15916e31d1e9b2e785566c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 May 2020 13:59:52 +0300 Subject: serial: imx: Initialize lock for non-registered console The commit a3cb39d258ef ("serial: core: Allow detach and attach serial device for console") changed a bit logic behind lock initialization since for most of the console driver it's supposed to have lock already initialized even if console is not enabled. However, it's not the case for Freescale IMX console. Initialize lock explicitly in the ->probe(). Note, there is still an open question should or shouldn't not this driver register console properly. Fixes: a3cb39d258ef ("serial: core: Allow detach and attach serial device for console") Reported-by: Guenter Roeck Cc: stable Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200525105952.13744-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 986d902fb7fe..6b078e395931 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2404,6 +2404,9 @@ static int imx_uart_probe(struct platform_device *pdev) } } + /* We need to initialize lock even for non-registered console */ + spin_lock_init(&sport->port.lock); + imx_uart_ports[sport->port.line] = sport; platform_set_drvdata(pdev, sport); -- cgit v1.2.3 From 15a3f03d5ec0118f1e5db3fc1018686e72744e37 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 26 May 2020 09:13:57 -0700 Subject: serial: 8250: Enable 16550A variants by default on non-x86 Some embedded devices still use these serial ports; make sure they're still enabled by default on architectures more likely to have them, to avoid rendering someone's console unavailable. Reported-by: Vladimir Oltean Reported-by: Maxim Kochetkov Fixes: dc56ecb81a0a ("serial: 8250: Support disabling mdelay-filled probes of 16550A variants") Cc: stable Signed-off-by: Josh Triplett Link: https://lore.kernel.org/r/a20b5fb7dd295cfb48160eecf4bdebd76332d67d.1590509426.git.josh@joshtriplett.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index af0688156dd0..8195a31519ea 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -63,6 +63,7 @@ config SERIAL_8250_PNP config SERIAL_8250_16550A_VARIANTS bool "Support for variants of the 16550A serial port" depends on SERIAL_8250 + default !X86 help The 8250 driver can probe for many variants of the venerable 16550A serial port. Doing so takes additional time at boot. -- cgit v1.2.3 From f40a6be4a4e4985aef5365007e2459d757f26bdd Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sun, 17 May 2020 23:56:06 +0200 Subject: serial: 8520_port: Fix function param documentation The parameter is named p while the documentation talks about up. Fix the doc to be in line with the code. Fixes: 058bc104f7ca ("serial: 8250: Generalize rs485 software emulation") Suggested-by: Andy Shevchenko Signed-off-by: Heiko Stuebner Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200517215610.2131618-2-heiko@sntech.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 4d83c85a7389..bf2722e5e3aa 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1432,7 +1432,7 @@ static void serial8250_stop_rx(struct uart_port *port) /** * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback - * @up: uart 8250 port + * @p: uart 8250 port * * Generic callback usable by 8250 uart drivers to stop rs485 transmission. */ -- cgit v1.2.3 From d58a2df3d8877b91ecbfb936a15da364251a228f Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 18 May 2020 16:45:02 +0200 Subject: serial: 8250: Support rs485 bus termination GPIO Commit e8759ad17d41 ("serial: uapi: Add support for bus termination") introduced the ability to enable rs485 bus termination from user space. So far the feature is only used by a single driver, 8250_exar.c, using a hardcoded GPIO pin specific to Siemens IOT2040 products. Provide for a more generic solution by allowing specification of an rs485 bus termination GPIO pin in the device tree: Amend the serial core to retrieve the GPIO from the device tree (or ACPI table) and amend the default ->rs485_config() callback for 8250 drivers to change the GPIO on request from user space. Perhaps 8250_exar.c can be converted to the generic approach in a follow-up patch. Signed-off-by: Lukas Wunner Reviewed-by: Andy Shevchenko Cc: Jan Kiszka Link: https://lore.kernel.org/r/94c6c800d1ca9fa04766dd1d43a8272c5ad4bedd.1589811297.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 +++ drivers/tty/serial/serial_core.c | 16 ++++++++++++++++ include/linux/serial_core.h | 2 ++ 3 files changed, 21 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index bf2722e5e3aa..1632f7d25acc 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -681,6 +681,9 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) memset(rs485->padding, 0, sizeof(rs485->padding)); port->rs485 = *rs485; + gpiod_set_value(port->rs485_term_gpio, + rs485->flags & SER_RS485_TERMINATE_BUS); + /* * Both serial8250_em485_init() and serial8250_em485_destroy() * are idempotent. diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 43b6682877d5..57840cf90388 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3317,6 +3317,7 @@ int uart_get_rs485_mode(struct uart_port *port) * to get to a defined state with the following properties: */ rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED | + SER_RS485_TERMINATE_BUS | SER_RS485_RTS_AFTER_SEND); rs485conf->flags |= SER_RS485_RTS_ON_SEND; @@ -3331,6 +3332,21 @@ int uart_get_rs485_mode(struct uart_port *port) rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; } + /* + * Disabling termination by default is the safe choice: Else if many + * bus participants enable it, no communication is possible at all. + * Works fine for short cables and users may enable for longer cables. + */ + port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term", + GPIOD_OUT_LOW); + if (IS_ERR(port->rs485_term_gpio)) { + ret = PTR_ERR(port->rs485_term_gpio); + port->rs485_term_gpio = NULL; + if (ret != -EPROBE_DEFER) + dev_err(dev, "Cannot get rs485-term-gpios\n"); + return ret; + } + return 0; } EXPORT_SYMBOL_GPL(uart_get_rs485_mode); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index b649a2b894e7..9fd550e7946a 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,7 @@ struct uart_port { struct attribute_group *attr_group; /* port specific attributes */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ struct serial_rs485 rs485; + struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */ struct serial_iso7816 iso7816; void *private_data; /* generic platform data pointer */ }; -- cgit v1.2.3 From 9eb90d57b55a0af499e8fee14ef942e80ad5f6f9 Mon Sep 17 00:00:00 2001 From: Pascal Huerst Date: Fri, 29 May 2020 07:50:58 +0200 Subject: sc16is7xx: Add flag to activate IrDA mode This series of uart controllers is able to work in IrDA mode. Add per-port flag to the device-tree to enable that feature if needed. Signed-off-by: Pascal Huerst Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20200529055058.1606910-3-daniel@zonque.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 8fee0e8b851f..d2e5c6c86643 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -315,6 +315,7 @@ struct sc16is7xx_one { struct kthread_work tx_work; struct kthread_work reg_work; struct sc16is7xx_one_config config; + bool irda_mode; }; struct sc16is7xx_port { @@ -986,6 +987,7 @@ static int sc16is7xx_config_rs485(struct uart_port *port, static int sc16is7xx_startup(struct uart_port *port) { + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val; @@ -1024,6 +1026,13 @@ static int sc16is7xx_startup(struct uart_port *port) /* Now, initialize the UART */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); + /* Enable IrDA mode if requested in DT */ + /* This bit must be written with LCR[7] = 0 */ + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_IRDA_BIT, + one->irda_mode ? + SC16IS7XX_MCR_IRDA_BIT : 0); + /* Enable the Rx and Tx FIFO */ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | @@ -1304,6 +1313,17 @@ static int sc16is7xx_probe(struct device *dev, sc16is7xx_power(&s->p[i].port, 0); } + if (dev->of_node) { + struct property *prop; + const __be32 *p; + u32 u; + + of_property_for_each_u32(dev->of_node, "irda-mode-ports", + prop, p, u) + if (u < devtype->nr_uart) + s->p[u].irda_mode = true; + } + /* * Setup interrupt. We first try to acquire the IRQ line as level IRQ. * If that succeeds, we can allow sharing the interrupt as well. -- cgit v1.2.3 From 423d9118c6240eabb78bd3c75fc91ba6e3151431 Mon Sep 17 00:00:00 2001 From: "Ji-Ze Hong (Peter Hong)" Date: Thu, 28 May 2020 10:24:29 +0800 Subject: serial: 8250_fintek: Add F81966 Support Fintek F81966 is a LPC/eSPI to 6 UARTs SuperIO. It has fully compatible with F81866. It's also need check the IRQ mode with system assigned. F81966 IRQ Mode setting: 0xf0 Bit1: IRQ_MODE0 Bit0: Share mode (always on) 0xf6 Bit3: IRQ_MODE1 Level/Low: IRQ_MODE0:0, IRQ_MODE1:0 Edge/High: IRQ_MODE0:1, IRQ_MODE1:0 Signed-off-by: Ji-Ze Hong (Peter Hong) Cc: Ji-Ze Hong (Peter Hong) Link: https://lore.kernel.org/r/20200528022429.32078-1-hpeter+linux_kernel@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 31c91c2f8c6e..d1d253c4b518 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -19,6 +19,7 @@ #define CHIP_ID2 0x21 #define CHIP_ID_F81865 0x0407 #define CHIP_ID_F81866 0x1010 +#define CHIP_ID_F81966 0x0215 #define CHIP_ID_F81216AD 0x1602 #define CHIP_ID_F81216H 0x0501 #define CHIP_ID_F81216 0x0802 @@ -62,9 +63,9 @@ #define F81216_LDN_HIGH 0x4 /* - * F81866 registers + * F81866/966 registers * - * The IRQ setting mode of F81866 is not the same with F81216 series. + * The IRQ setting mode of F81866/966 is not the same with F81216 series. * Level/Low: IRQ_MODE0:0, IRQ_MODE1:0 * Edge/High: IRQ_MODE0:1, IRQ_MODE1:0 * @@ -155,6 +156,7 @@ static int fintek_8250_check_id(struct fintek_8250 *pdata) switch (chip) { case CHIP_ID_F81865: case CHIP_ID_F81866: + case CHIP_ID_F81966: case CHIP_ID_F81216AD: case CHIP_ID_F81216H: case CHIP_ID_F81216: @@ -171,6 +173,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min, int *max) { switch (pdata->pid) { + case CHIP_ID_F81966: case CHIP_ID_F81865: case CHIP_ID_F81866: *min = F81866_LDN_LOW; @@ -248,6 +251,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) sio_write_reg(pdata, LDN, pdata->index); switch (pdata->pid) { + case CHIP_ID_F81966: case CHIP_ID_F81866: sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1, 0); @@ -274,6 +278,7 @@ static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata) { switch (pdata->pid) { case CHIP_ID_F81216H: /* 128Bytes FIFO */ + case CHIP_ID_F81966: case CHIP_ID_F81866: sio_write_mask_reg(pdata, FIFO_CTRL, FIFO_MODE_MASK | RXFTHR_MODE_MASK, @@ -291,6 +296,7 @@ static void fintek_8250_goto_highspeed(struct uart_8250_port *uart, sio_write_reg(pdata, LDN, pdata->index); switch (pdata->pid) { + case CHIP_ID_F81966: case CHIP_ID_F81866: /* set uart clock for high speed serial mode */ sio_write_mask_reg(pdata, F81866_UART_CLK, F81866_UART_CLK_MASK, @@ -327,6 +333,7 @@ static void fintek_8250_set_termios(struct uart_port *port, case CHIP_ID_F81216H: reg = RS485; break; + case CHIP_ID_F81966: case CHIP_ID_F81866: reg = F81866_UART_CLK; break; @@ -373,6 +380,7 @@ static void fintek_8250_set_termios_handler(struct uart_8250_port *uart) switch (pdata->pid) { case CHIP_ID_F81216H: + case CHIP_ID_F81966: case CHIP_ID_F81866: uart->port.set_termios = fintek_8250_set_termios; break; @@ -443,6 +451,7 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) switch (pdata->pid) { case CHIP_ID_F81216AD: case CHIP_ID_F81216H: + case CHIP_ID_F81966: case CHIP_ID_F81866: case CHIP_ID_F81865: uart->port.rs485_config = fintek_8250_rs485_config; -- cgit v1.2.3 From d1d996afbd2bca3bf3c484fc1f7a738134d65207 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 28 May 2020 17:47:47 +0200 Subject: tty: serial: imx: clear Ageing Timer Interrupt in handler The AGTIM flag must be cleared explicitly, otherwise the IRQ handler will be called in an endless loop. Fortunately, this issue currently doesn't affect mainline kernels in practice, as the the RX FIFO trigger level is set to 1 in UFCR. When setting the trigger level to a higher number, the issue is trivially reproducible by any RX without DMA that doesn't fill the FIFO up to the configured level. Signed-off-by: Matthias Schiffer Link: https://lore.kernel.org/r/20200528154747.14201-1-matthias.schiffer@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 6b078e395931..1265e8d86d8a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -909,6 +909,8 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) usr2 &= ~USR2_ORE; if (usr1 & (USR1_RRDY | USR1_AGTIM)) { + imx_uart_writel(sport, USR1_AGTIM, USR1); + __imx_uart_rxint(irq, dev_id); ret = IRQ_HANDLED; } -- cgit v1.2.3 From a1b44ea340b21c99b34c93acad233da727cb88ba Mon Sep 17 00:00:00 2001 From: satya priya Date: Fri, 29 May 2020 15:44:42 +0530 Subject: tty: serial: qcom_geni_serial: Add 51.2MHz frequency support To support BT use case over UART at baud rate of 3.2 Mbps, we need SE clocks to run at 51.2MHz frequency. Previously this frequency was not available in clk src, so, we were requesting for 102.4 MHz and dividing it internally by 2 to get 51.2MHz. As now 51.2MHz frequency is made available in clk src, adding this frequency to UART frequency table. We will save significant amount of power, if 51.2 is used because it belongs to LowSVS range whereas 102.4 fall into Nominal category. Signed-off-by: satya priya Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/1590747282-5487-1-git-send-email-skakit@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 6119090ce045..168e1c0c0ae3 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -141,9 +141,10 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport); static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop); static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200, - 32000000, 48000000, 64000000, 80000000, - 96000000, 100000000, 102400000, - 112000000, 120000000, 128000000}; + 32000000, 48000000, 51200000, 64000000, + 80000000, 96000000, 100000000, + 102400000, 112000000, 120000000, + 128000000}; #define to_dev_port(ptr, member) \ container_of(ptr, struct qcom_geni_serial_port, member) -- cgit v1.2.3