From 1f043572cbbee03f1de814e312f9dc11251fdc5a Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 16 Nov 2017 11:14:53 -0700 Subject: tty: serial: imx: remove imx_disable_rx_int Since imx_disable_rx_int is only called by imx_startup, let's integrate it into that function. Notice UCR2_ATEN is never set by the driver. The bit is still cleaned to make this patch a noop. Signed-off-by: Troy Kisky Acked-by: Uwe Kleine-Koenig Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) (limited to 'drivers/tty/serial/imx.c') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e4b3d9123a03..16311a24b483 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -703,25 +703,6 @@ out: return IRQ_HANDLED; } -static void imx_disable_rx_int(struct imx_port *sport) -{ - unsigned long temp; - - /* disable the receiver ready and aging timer interrupts */ - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RRDYEN); - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR2); - temp &= ~(UCR2_ATEN); - writel(temp, sport->port.membase + UCR2); - - /* disable the rx errors interrupts */ - temp = readl(sport->port.membase + UCR4); - temp &= ~UCR4_OREN; - writel(temp, sport->port.membase + UCR4); -} - static void clear_rx_errors(struct imx_port *sport); /* @@ -1252,18 +1233,21 @@ static int imx_startup(struct uart_port *port) if (sport->dma_is_inited && !sport->dma_is_enabled) imx_enable_dma(sport); - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN | UCR1_UARTEN; + temp = readl(sport->port.membase + UCR1) & ~UCR1_RRDYEN; + if (!sport->dma_is_enabled) + temp |= UCR1_RRDYEN; + temp |= UCR1_UARTEN; if (sport->have_rtscts) temp |= UCR1_RTSDEN; writel(temp, sport->port.membase + UCR1); - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_OREN; + temp = readl(sport->port.membase + UCR4) & ~UCR4_OREN; + if (!sport->dma_is_enabled) + temp |= UCR4_OREN; writel(temp, sport->port.membase + UCR4); - temp = readl(sport->port.membase + UCR2); + temp = readl(sport->port.membase + UCR2) & ~UCR2_ATEN; temp |= (UCR2_RXEN | UCR2_TXEN); if (!sport->have_rtscts) temp |= UCR2_IRTS; @@ -1297,10 +1281,8 @@ static int imx_startup(struct uart_port *port) * In our iMX53 the average delay for the first reception dropped from * approximately 35000 microseconds to 1000 microseconds. */ - if (sport->dma_is_enabled) { - imx_disable_rx_int(sport); + if (sport->dma_is_enabled) start_rx_dma(sport); - } spin_unlock_irqrestore(&sport->port.lock, flags); -- cgit v1.2.3 From 743f93f822be1b54f3f9bd53d13f02192e65ce0b Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 24 Nov 2017 23:26:40 +0100 Subject: serial: Make retrieval of rs485 properties platform-agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit ef838a81dd4d ("serial: Add common rs485 device tree parsing function") consolidated retrieval of rs485 OF properties in a common helper function but did not #ifdef it to CONFIG_OF. The function is therefore included on ACPI platforms as well even though it's not used. On the other hand ACPI platforms with rs485 do exist (e.g. Siemens IOT2040) and they may leverage _DSD to store rs485 properties. Likewise, UART platform devices instantiated from an MFD should be able to specify rs485 properties. In fact, the tty subsystem maintainer had asked for a "generic" function during review of commit ef838a81dd4d: https://marc.info/?l=linux-serial&m=150143441725194&w=4 Thus, instead of constraining the helper to OF platforms, make it platform-agnostic by converting it to device_property_*() functions and renaming it accordingly. In imx.c, move the invocation of uart_get_rs485_mode() from serial_imx_probe_dt() to serial_imx_probe() so that it also gets called for non-OF devices. In omap-serial.c, move its invocation further up within serial_omap_probe_rs485() so that the RTS polarity can be overridden with the driver-specific "rs485-rts-active-high" property once we introduce a generic "rs485-rts-active-low" property. Cc: Jan Kiszka Cc: Richard Genoud Cc: Sascha Hauer Signed-off-by: Lukas Wunner Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty/serial/imx.c') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 16311a24b483..aca3b7dbd09c 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1999,8 +1999,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "rts-gpios", NULL)) sport->have_rtsgpio = 1; - of_get_rs485_mode(np, &sport->port.rs485); - return 0; } #else @@ -2093,6 +2091,8 @@ static int serial_imx_probe(struct platform_device *pdev) return ret; } + uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); + /* Disable interrupts before requesting them */ reg = readl_relaxed(sport->port.membase + UCR1); reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | -- cgit v1.2.3 From f1e5b618c1c26cb8b5818e36f996e8c2fbedbeb7 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 24 Nov 2017 23:26:40 +0100 Subject: serial: core: Support common rs485 binding for RTS polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a driver invokes the uart_get_rs485_mode() helper, set the RTS polarity to active high by default unless the newly introduced "rs485-rts-active-low" property was specified. imx contains a line to set the default RTS polarity to active high, it is now superfluous and hence deleted. omap-serial historically defaults to active low and supports an "rs485-rts-active-high" property to inverse the polarity. Retain that behavior for compatibility. Cc: Mark Jackson Cc: Michał Oleszczyk Cc: Rafael Gago Castano Cc: Sascha Hauer Signed-off-by: Lukas Wunner Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty/serial/imx.c') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index aca3b7dbd09c..d2c7d88d5774 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2060,7 +2060,6 @@ static int serial_imx_probe(struct platform_device *pdev) sport->port.fifosize = 32; sport->port.ops = &imx_pops; sport->port.rs485_config = imx_rs485_config; - sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND; sport->port.flags = UPF_BOOT_AUTOCONF; timer_setup(&sport->timer, imx_timeout, 0); -- cgit v1.2.3 From b8f3bff057b017309fbd61fe74712b1f185b5399 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 24 Nov 2017 23:26:40 +0100 Subject: serial: imx: Support common rs485 binding for RTS polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invoke the ->rs485_config callback on probe to adjust the initial RTS polarity based on the UART's device properties. This implicitly fixes a bug: If RTS control is not available, rs485 should be disabled even if it was enabled through a device property. Log an error when that occurs. Cc: Sascha Hauer Signed-off-by: Lukas Wunner Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/tty/serial/imx.c') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d2c7d88d5774..c2b29fd66e8a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2092,6 +2092,12 @@ static int serial_imx_probe(struct platform_device *pdev) uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); + if (sport->port.rs485.flags & SER_RS485_ENABLED && + (!sport->have_rtscts || !sport->have_rtsgpio)) + dev_err(&pdev->dev, "no RTS control, disabling rs485\n"); + + imx_rs485_config(&sport->port, &sport->port.rs485); + /* Disable interrupts before requesting them */ reg = readl_relaxed(sport->port.membase + UCR1); reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | -- cgit v1.2.3 From 38b1f0fb42f772b8c9aac53593883a18ff5eb9d7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 4 Jan 2018 15:58:34 -0200 Subject: serial: imx: Only wakeup via RTSDEN bit if the system has RTS/CTS The wakeup mechanism via RTSDEN bit relies on the system using the RTS/CTS lines, so only allow such wakeup method when the system actually has RTS/CTS support. Fixes: bc85734b126f ("serial: imx: allow waking up on RTSD") Signed-off-by: Fabio Estevam Reviewed-by: Martin Kaiser Acked-by: Fugang Duan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/tty/serial/imx.c') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index c2b29fd66e8a..7143da39c170 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2225,12 +2225,14 @@ static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) val &= ~UCR3_AWAKEN; writel(val, sport->port.membase + UCR3); - val = readl(sport->port.membase + UCR1); - if (on) - val |= UCR1_RTSDEN; - else - val &= ~UCR1_RTSDEN; - writel(val, sport->port.membase + UCR1); + if (sport->have_rtscts) { + val = readl(sport->port.membase + UCR1); + if (on) + val |= UCR1_RTSDEN; + else + val &= ~UCR1_RTSDEN; + writel(val, sport->port.membase + UCR1); + } } static int imx_serial_port_suspend_noirq(struct device *dev) -- cgit v1.2.3 From 09df0b3464e528c6a4ca2c48d9ff6d2fd7cbd775 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Fri, 5 Jan 2018 17:46:43 +0100 Subject: serial: imx: fix endless loop during suspend Before we go into suspend mode, we enable the imx uart's interrupt for the awake bit in the UART Status Register 1. If, for some reason, the awake bit is already set before we enter suspend mode, we get an interrupt immediately when we enable interrupts for awake. The uart's clk_ipg is disabled at this point (unless there's an ongoing transfer). We end up in the interrupt handler, which usually tries to clear the awake bit. This doesn't work with the clock disabled. Therefore, we keep getting interrupts forever, resulting in an endless loop. Clear the awake bit before setting the awaken bit to signal that we want an imx interrupt when the awake bit will be set. This ensures that we're not woken up by events that happened before we started going into suspend mode. Change the clock handling so that suspend prepares and enables the clock and suspend_noirq disables it. Revert these operations in resume_noirq and resume. With these preparations in place, we can now modify awake and awaken in the suspend function when the actual imx interrupt is disabled and the required clk_ipg is active. Update the thaw and freeze functions to use the new clock handling since we share the suspend_noirq function between suspend and hibernate. Signed-off-by: Martin Kaiser Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'drivers/tty/serial/imx.c') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 7143da39c170..1d7ca382bc12 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2219,8 +2219,10 @@ static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) unsigned int val; val = readl(sport->port.membase + UCR3); - if (on) + if (on) { + writel(USR1_AWAKE, sport->port.membase + USR1); val |= UCR3_AWAKEN; + } else val &= ~UCR3_AWAKEN; writel(val, sport->port.membase + UCR3); @@ -2239,11 +2241,6 @@ static int imx_serial_port_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); - int ret; - - ret = clk_enable(sport->clk_ipg); - if (ret) - return ret; serial_imx_save_context(sport); @@ -2264,8 +2261,6 @@ static int imx_serial_port_resume_noirq(struct device *dev) serial_imx_restore_context(sport); - clk_disable(sport->clk_ipg); - return 0; } @@ -2273,15 +2268,19 @@ static int imx_serial_port_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); - - /* enable wakeup from i.MX UART */ - serial_imx_enable_wakeup(sport, true); + int ret; uart_suspend_port(&imx_reg, &sport->port); disable_irq(sport->port.irq); - /* Needed to enable clock in suspend_noirq */ - return clk_prepare(sport->clk_ipg); + ret = clk_prepare_enable(sport->clk_ipg); + if (ret) + return ret; + + /* enable wakeup from i.MX UART */ + serial_imx_enable_wakeup(sport, true); + + return 0; } static int imx_serial_port_resume(struct device *dev) @@ -2295,7 +2294,7 @@ static int imx_serial_port_resume(struct device *dev) uart_resume_port(&imx_reg, &sport->port); enable_irq(sport->port.irq); - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); return 0; } @@ -2307,8 +2306,7 @@ static int imx_serial_port_freeze(struct device *dev) uart_suspend_port(&imx_reg, &sport->port); - /* Needed to enable clock in suspend_noirq */ - return clk_prepare(sport->clk_ipg); + return clk_prepare_enable(sport->clk_ipg); } static int imx_serial_port_thaw(struct device *dev) @@ -2318,7 +2316,7 @@ static int imx_serial_port_thaw(struct device *dev) uart_resume_port(&imx_reg, &sport->port); - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); return 0; } -- cgit v1.2.3