OMAP/serial: Add support for driving a GPIO as DTR.
authorNeilBrown <neilb@suse.de>
Mon, 30 Jul 2012 00:30:26 +0000 (10:30 +1000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 16 Aug 2012 19:10:43 +0000 (12:10 -0700)
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>
arch/arm/mach-omap2/serial.c
arch/arm/plat-omap/include/plat/omap-serial.h
drivers/tty/serial/omap-serial.c

index c1b93c7..25d53b2 100644 (file)
@@ -304,6 +304,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
        omap_up.dma_rx_timeout = info->dma_rx_timeout;
        omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
        omap_up.autosuspend_timeout = info->autosuspend_timeout;
+       omap_up.DTR_gpio = info->DTR_gpio;
+       omap_up.DTR_inverted = info->DTR_inverted;
+       omap_up.DTR_present = info->DTR_present;
 
        pdata = &omap_up;
        pdata_size = sizeof(struct omap_uart_port_info);
index 1a52725..52d3de4 100644 (file)
@@ -69,6 +69,9 @@ struct omap_uart_port_info {
        unsigned int            dma_rx_timeout;
        unsigned int            autosuspend_timeout;
        unsigned int            dma_rx_poll_rate;
+       int                     DTR_gpio;
+       int                     DTR_inverted;
+       int                     DTR_present;
 
        int (*get_context_loss_count)(struct device *);
        void (*set_forceidle)(struct platform_device *);
@@ -131,6 +134,10 @@ struct uart_omap_port {
        u32                     errata;
        u8                      wakeups_enabled;
 
+       int                     DTR_gpio;
+       int                     DTR_inverted;
+       int                     DTR_active;
+
        struct pm_qos_request   pm_qos_request;
        u32                     latency;
        u32                     calc_latency;
index d3cda0c..aa603f2 100644 (file)
@@ -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 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
        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 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
                                                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 @@ static int serial_omap_probe(struct platform_device *pdev)
        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 @@ static int serial_omap_probe(struct platform_device *pdev)
        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;