serial: imx: setup DCEDTE early and ensure DCD and RI irqs to be off
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Tue, 4 Apr 2017 09:18:51 +0000 (11:18 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 8 Apr 2017 16:54:07 +0000 (18:54 +0200)
If the UART is operated in DTE mode and UCR3_DCD or UCR3_RI are 1 (which
is the reset default) and the opposite side pulls the respective line to
its active level the irq triggers after it is requested in .probe.

These irqs were already disabled in .startup but this might be too late.

Also setup of the UFCR_DCEDTE bit (currently done in .set_termios) is
done very late which is critical as it also controls direction of some
pins.

So setup UFCR_DCEDTE earlier (in .probe) and also disable the broken
irqs in DTE mode there before requesting irqs.

Acked-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/imx.c

index e3e152cbc75e71d7bc4e966f8a4ec3a1884c2b95..4167b61bf4e0c483cad20f4e4c4e14c4c5814377 100644 (file)
@@ -1317,19 +1317,10 @@ static int imx_startup(struct uart_port *port)
        if (!is_imx1_uart(sport)) {
                temp = readl(sport->port.membase + UCR3);
 
-               /*
-                * The effect of RI and DCD differs depending on the UFCR_DCEDTE
-                * bit. In DCE mode they control the outputs, in DTE mode they
-                * enable the respective irqs. At least the DCD irq cannot be
-                * cleared on i.MX25 at least, so it's not usable and must be
-                * disabled. I don't have test hardware to check if RI has the
-                * same problem but I consider this likely so it's disabled for
-                * now, too.
-                */
-               temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP |
-                       UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
+               temp |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
 
                if (sport->dte_mode)
+                       /* disable broken interrupts */
                        temp &= ~(UCR3_RI | UCR3_DCD);
 
                writel(temp, sport->port.membase + UCR3);
@@ -1584,8 +1575,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 
        ufcr = readl(sport->port.membase + UFCR);
        ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
-       if (sport->dte_mode)
-               ufcr |= UFCR_DCEDTE;
        writel(ufcr, sport->port.membase + UFCR);
 
        writel(num, sport->port.membase + UBIR);
@@ -2153,6 +2142,27 @@ static int serial_imx_probe(struct platform_device *pdev)
                 UCR1_TXMPTYEN | UCR1_RTSDEN);
        writel_relaxed(reg, sport->port.membase + UCR1);
 
+       if (!is_imx1_uart(sport) && sport->dte_mode) {
+               /*
+                * The DCEDTE bit changes the direction of DSR, DCD, DTR and RI
+                * and influences if UCR3_RI and UCR3_DCD changes the level of RI
+                * and DCD (when they are outputs) or enables the respective
+                * irqs. So set this bit early, i.e. before requesting irqs.
+                */
+               writel(UFCR_DCEDTE, sport->port.membase + UFCR);
+
+               /*
+                * Disable UCR3_RI and UCR3_DCD irqs. They are also not
+                * enabled later because they cannot be cleared
+                * (confirmed on i.MX25) which makes them unusable.
+                */
+               writel(IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | UCR3_DSR,
+                      sport->port.membase + UCR3);
+
+       } else {
+               writel(0, sport->port.membase + UFCR);
+       }
+
        clk_disable_unprepare(sport->clk_ipg);
 
        /*