OMAP/serial: Add support for driving a GPIO as DTR.

OMAP hardware doesn't provide a phyisical DTR line, but
some configurations may need a DTR line which tracks whether
the device is open or not.

So allow a gpio to be configured as the DTR line.

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index d3cda0c..aa603f2 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -39,6 +39,7 @@
 #include <linux/irq.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
+#include <linux/gpio.h>
 
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
@@ -507,6 +508,16 @@
 	up->mcr |= mcr;
 	serial_out(up, UART_MCR, up->mcr);
 	pm_runtime_put(&up->pdev->dev);
+
+	if (gpio_is_valid(up->DTR_gpio) &&
+	    !!(mctrl & TIOCM_DTR) != up->DTR_active) {
+		up->DTR_active = !up->DTR_active;
+		if (gpio_cansleep(up->DTR_gpio))
+			schedule_work(&up->qos_work);
+		else
+			gpio_set_value(up->DTR_gpio,
+				       up->DTR_active != up->DTR_inverted);
+	}
 }
 
 static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -715,6 +726,9 @@
 						qos_work);
 
 	pm_qos_update_request(&up->pm_qos_request, up->latency);
+	if (gpio_is_valid(up->DTR_gpio))
+		gpio_set_value_cansleep(up->DTR_gpio,
+					up->DTR_active != up->DTR_inverted);
 }
 
 static void
@@ -1435,7 +1449,7 @@
 	struct uart_omap_port	*up;
 	struct resource		*mem, *irq, *dma_tx, *dma_rx;
 	struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
-	int ret = -ENOSPC;
+	int ret;
 
 	if (pdev->dev.of_node)
 		omap_up_info = of_get_uart_port_info(&pdev->dev);
@@ -1466,10 +1480,29 @@
 	if (!dma_tx)
 		return -ENXIO;
 
+	if (gpio_is_valid(omap_up_info->DTR_gpio) &&
+	    omap_up_info->DTR_present) {
+		ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
+		if (ret < 0)
+			return ret;
+		ret = gpio_direction_output(omap_up_info->DTR_gpio,
+					    omap_up_info->DTR_inverted);
+		if (ret < 0)
+			return ret;
+	}
+
 	up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);
 	if (!up)
 		return -ENOMEM;
 
+	if (gpio_is_valid(omap_up_info->DTR_gpio) &&
+	    omap_up_info->DTR_present) {
+		up->DTR_gpio = omap_up_info->DTR_gpio;
+		up->DTR_inverted = omap_up_info->DTR_inverted;
+	} else
+		up->DTR_gpio = -EINVAL;
+	up->DTR_active = 0;
+
 	up->pdev = pdev;
 	up->port.dev = &pdev->dev;
 	up->port.type = PORT_OMAP;