serial: imx: implement handshaking using gpios with the mctrl_gpio helper
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Sun, 13 Dec 2015 10:30:03 +0000 (11:30 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 14 Dec 2015 04:01:47 +0000 (20:01 -0800)
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/Kconfig
drivers/tty/serial/imx.c

index 0bdf4d5c7c657c310e74bec8925e64bdc48156f2..d27a0c62a75f3745d29710bbbb35aac5684d5cb3 100644 (file)
@@ -576,6 +576,7 @@ config SERIAL_IMX
        depends on ARCH_MXC || COMPILE_TEST
        select SERIAL_CORE
        select RATIONAL
+       select SERIAL_MCTRL_GPIO if GPIOLIB
        help
          If you have a machine based on a Motorola IMX CPU you
          can enable its onboard serial port by enabling this option.
index 591f1c26e3e987cf6a4d986d4c5693526f861bf5..9362f54c816c99c73957209cd49bd781e5a61e09 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/platform_data/serial-imx.h>
 #include <linux/platform_data/dma-imx.h>
 
+#include "serial_mctrl_gpio.h"
+
 /* Register definitions */
 #define URXD0 0x0  /* Receiver Register */
 #define URTX0 0x40 /* Transmitter Register */
@@ -209,6 +211,8 @@ struct imx_port {
        struct clk              *clk_per;
        const struct imx_uart_data *devdata;
 
+       struct mctrl_gpios *gpios;
+
        /* DMA fields */
        unsigned int            dma_is_inited:1;
        unsigned int            dma_is_enabled:1;
@@ -311,6 +315,26 @@ static void imx_port_ucrs_restore(struct uart_port *port,
 }
 #endif
 
+static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2)
+{
+       *ucr2 &= ~UCR2_CTSC;
+       *ucr2 |= UCR2_CTS;
+
+       mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS);
+}
+
+static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2)
+{
+       *ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
+
+       mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS);
+}
+
+static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2)
+{
+       *ucr2 |= UCR2_CTSC;
+}
+
 /*
  * interrupts disabled on entry
  */
@@ -334,9 +358,9 @@ static void imx_stop_tx(struct uart_port *port)
            readl(port->membase + USR2) & USR2_TXDC) {
                temp = readl(port->membase + UCR2);
                if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
-                       temp &= ~UCR2_CTS;
+                       imx_port_rts_inactive(sport, &temp);
                else
-                       temp |= UCR2_CTS;
+                       imx_port_rts_active(sport, &temp);
                writel(temp, port->membase + UCR2);
 
                temp = readl(port->membase + UCR4);
@@ -378,6 +402,8 @@ static void imx_enable_ms(struct uart_port *port)
        struct imx_port *sport = (struct imx_port *)port;
 
        mod_timer(&sport->timer, jiffies);
+
+       mctrl_gpio_enable_ms(sport->gpios);
 }
 
 static void imx_dma_tx(struct imx_port *sport);
@@ -537,14 +563,14 @@ static void imx_start_tx(struct uart_port *port)
        unsigned long temp;
 
        if (port->rs485.flags & SER_RS485_ENABLED) {
-               /* enable transmitter and shifter empty irq */
                temp = readl(port->membase + UCR2);
                if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
-                       temp &= ~UCR2_CTS;
+                       imx_port_rts_inactive(sport, &temp);
                else
-                       temp |= UCR2_CTS;
+                       imx_port_rts_active(sport, &temp);
                writel(temp, port->membase + UCR2);
 
+               /* enable transmitter and shifter empty irq */
                temp = readl(port->membase + UCR4);
                temp |= UCR4_TCEN;
                writel(temp, port->membase + UCR4);
@@ -759,9 +785,8 @@ static unsigned int imx_tx_empty(struct uart_port *port)
 /*
  * We have a modem side uart, so the meanings of RTS and CTS are inverted.
  */
-static unsigned int imx_get_mctrl(struct uart_port *port)
+static unsigned int imx_get_hwmctrl(struct imx_port *sport)
 {
-       struct imx_port *sport = (struct imx_port *)port;
        unsigned int tmp = TIOCM_DSR;
        unsigned usr1 = readl(sport->port.membase + USR1);
 
@@ -779,6 +804,16 @@ static unsigned int imx_get_mctrl(struct uart_port *port)
        return tmp;
 }
 
+static unsigned int imx_get_mctrl(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned int ret = imx_get_hwmctrl(sport);
+
+       mctrl_gpio_get(sport->gpios, &ret);
+
+       return ret;
+}
+
 static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
        struct imx_port *sport = (struct imx_port *)port;
@@ -801,6 +836,8 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
        if (mctrl & TIOCM_LOOP)
                temp |= UTS_LOOP;
        writel(temp, sport->port.membase + uts_reg(sport));
+
+       mctrl_gpio_set(sport->gpios, mctrl);
 }
 
 /*
@@ -830,7 +867,7 @@ static void imx_mctrl_check(struct imx_port *sport)
 {
        unsigned int status, changed;
 
-       status = imx_get_mctrl(&sport->port);
+       status = imx_get_hwmctrl(sport);
        changed = status ^ sport->old_status;
 
        if (changed == 0)
@@ -1218,6 +1255,8 @@ static void imx_shutdown(struct uart_port *port)
                imx_uart_dma_exit(sport);
        }
 
+       mctrl_gpio_disable_ms(sport->gpios);
+
        spin_lock_irqsave(&sport->port.lock, flags);
        temp = readl(sport->port.membase + UCR2);
        temp &= ~(UCR2_TXEN);
@@ -1295,9 +1334,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 {
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long flags;
-       unsigned int ucr2, old_ucr1, old_ucr2, baud, quot;
+       unsigned long ucr2, old_ucr1, old_ucr2;
+       unsigned int baud, quot;
        unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-       unsigned int div, ufcr;
+       unsigned long div, ufcr;
        unsigned long num, denom;
        uint64_t tdiv64;
 
@@ -1326,19 +1366,25 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                                 * it under manual control and keep transmitter
                                 * disabled.
                                 */
-                               if (!(port->rs485.flags &
-                                     SER_RS485_RTS_AFTER_SEND))
-                                       ucr2 |= UCR2_CTS;
+                               if (port->rs485.flags &
+                                   SER_RS485_RTS_AFTER_SEND)
+                                       imx_port_rts_inactive(sport, &ucr2);
+                               else
+                                       imx_port_rts_active(sport, &ucr2);
                        } else {
-                               ucr2 |= UCR2_CTSC;
+                               imx_port_rts_auto(sport, &ucr2);
                        }
                } else {
                        termios->c_cflag &= ~CRTSCTS;
                }
-       } else if (port->rs485.flags & SER_RS485_ENABLED)
+       } else if (port->rs485.flags & SER_RS485_ENABLED) {
                /* disable transmitter */
-               if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
-                       ucr2 |= UCR2_CTS;
+               if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+                       imx_port_rts_inactive(sport, &ucr2);
+               else
+                       imx_port_rts_active(sport, &ucr2);
+       }
+
 
        if (termios->c_cflag & CSTOPB)
                ucr2 |= UCR2_STPB;
@@ -1579,11 +1625,10 @@ static int imx_rs485_config(struct uart_port *port,
 
                /* disable transmitter */
                temp = readl(sport->port.membase + UCR2);
-               temp &= ~UCR2_CTSC;
                if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
-                       temp &= ~UCR2_CTS;
+                       imx_port_rts_inactive(sport, &temp);
                else
-                       temp |= UCR2_CTS;
+                       imx_port_rts_active(sport, &temp);
                writel(temp, sport->port.membase + UCR2);
        }
 
@@ -1956,6 +2001,10 @@ static int serial_imx_probe(struct platform_device *pdev)
        sport->timer.function = imx_timeout;
        sport->timer.data     = (unsigned long)sport;
 
+       sport->gpios = mctrl_gpio_init(&sport->port, 0);
+       if (IS_ERR(sport->gpios))
+               return PTR_ERR(sport->gpios);
+
        sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(sport->clk_ipg)) {
                ret = PTR_ERR(sport->clk_ipg);
This page took 0.02942 seconds and 5 git commands to generate.