diff options
author | NeilBrown <neilb@suse.de> | 2012-07-29 20:30:26 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-08-16 15:10:43 -0400 |
commit | 9574f36fb801035f6ab0fbb1b53ce2c12c17d100 (patch) | |
tree | feb4794a8c1a54b5fb0e3024b836e93f2a39f36e | |
parent | a92098a1cb7ec08c86d1b97d1831d8edaf26b1a2 (diff) |
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>
-rw-r--r-- | arch/arm/mach-omap2/serial.c | 3 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/omap-serial.h | 7 | ||||
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 35 |
3 files changed, 44 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index c1b93c752d70..25d53b2800c1 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c | |||
@@ -304,6 +304,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, | |||
304 | omap_up.dma_rx_timeout = info->dma_rx_timeout; | 304 | omap_up.dma_rx_timeout = info->dma_rx_timeout; |
305 | omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; | 305 | omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; |
306 | omap_up.autosuspend_timeout = info->autosuspend_timeout; | 306 | omap_up.autosuspend_timeout = info->autosuspend_timeout; |
307 | omap_up.DTR_gpio = info->DTR_gpio; | ||
308 | omap_up.DTR_inverted = info->DTR_inverted; | ||
309 | omap_up.DTR_present = info->DTR_present; | ||
307 | 310 | ||
308 | pdata = &omap_up; | 311 | pdata = &omap_up; |
309 | pdata_size = sizeof(struct omap_uart_port_info); | 312 | pdata_size = sizeof(struct omap_uart_port_info); |
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 1a52725ffcf2..52d3de45745f 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h | |||
@@ -69,6 +69,9 @@ struct omap_uart_port_info { | |||
69 | unsigned int dma_rx_timeout; | 69 | unsigned int dma_rx_timeout; |
70 | unsigned int autosuspend_timeout; | 70 | unsigned int autosuspend_timeout; |
71 | unsigned int dma_rx_poll_rate; | 71 | unsigned int dma_rx_poll_rate; |
72 | int DTR_gpio; | ||
73 | int DTR_inverted; | ||
74 | int DTR_present; | ||
72 | 75 | ||
73 | int (*get_context_loss_count)(struct device *); | 76 | int (*get_context_loss_count)(struct device *); |
74 | void (*set_forceidle)(struct platform_device *); | 77 | void (*set_forceidle)(struct platform_device *); |
@@ -131,6 +134,10 @@ struct uart_omap_port { | |||
131 | u32 errata; | 134 | u32 errata; |
132 | u8 wakeups_enabled; | 135 | u8 wakeups_enabled; |
133 | 136 | ||
137 | int DTR_gpio; | ||
138 | int DTR_inverted; | ||
139 | int DTR_active; | ||
140 | |||
134 | struct pm_qos_request pm_qos_request; | 141 | struct pm_qos_request pm_qos_request; |
135 | u32 latency; | 142 | u32 latency; |
136 | u32 calc_latency; | 143 | u32 calc_latency; |
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d3cda0cb2df0..aa603f221c6a 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/irq.h> | 39 | #include <linux/irq.h> |
40 | #include <linux/pm_runtime.h> | 40 | #include <linux/pm_runtime.h> |
41 | #include <linux/of.h> | 41 | #include <linux/of.h> |
42 | #include <linux/gpio.h> | ||
42 | 43 | ||
43 | #include <plat/dma.h> | 44 | #include <plat/dma.h> |
44 | #include <plat/dmtimer.h> | 45 | #include <plat/dmtimer.h> |
@@ -507,6 +508,16 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
507 | up->mcr |= mcr; | 508 | up->mcr |= mcr; |
508 | serial_out(up, UART_MCR, up->mcr); | 509 | serial_out(up, UART_MCR, up->mcr); |
509 | pm_runtime_put(&up->pdev->dev); | 510 | pm_runtime_put(&up->pdev->dev); |
511 | |||
512 | if (gpio_is_valid(up->DTR_gpio) && | ||
513 | !!(mctrl & TIOCM_DTR) != up->DTR_active) { | ||
514 | up->DTR_active = !up->DTR_active; | ||
515 | if (gpio_cansleep(up->DTR_gpio)) | ||
516 | schedule_work(&up->qos_work); | ||
517 | else | ||
518 | gpio_set_value(up->DTR_gpio, | ||
519 | up->DTR_active != up->DTR_inverted); | ||
520 | } | ||
510 | } | 521 | } |
511 | 522 | ||
512 | static void serial_omap_break_ctl(struct uart_port *port, int break_state) | 523 | 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) | |||
715 | qos_work); | 726 | qos_work); |
716 | 727 | ||
717 | pm_qos_update_request(&up->pm_qos_request, up->latency); | 728 | pm_qos_update_request(&up->pm_qos_request, up->latency); |
729 | if (gpio_is_valid(up->DTR_gpio)) | ||
730 | gpio_set_value_cansleep(up->DTR_gpio, | ||
731 | up->DTR_active != up->DTR_inverted); | ||
718 | } | 732 | } |
719 | 733 | ||
720 | static void | 734 | static void |
@@ -1435,7 +1449,7 @@ static int serial_omap_probe(struct platform_device *pdev) | |||
1435 | struct uart_omap_port *up; | 1449 | struct uart_omap_port *up; |
1436 | struct resource *mem, *irq, *dma_tx, *dma_rx; | 1450 | struct resource *mem, *irq, *dma_tx, *dma_rx; |
1437 | struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; | 1451 | struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; |
1438 | int ret = -ENOSPC; | 1452 | int ret; |
1439 | 1453 | ||
1440 | if (pdev->dev.of_node) | 1454 | if (pdev->dev.of_node) |
1441 | omap_up_info = of_get_uart_port_info(&pdev->dev); | 1455 | omap_up_info = of_get_uart_port_info(&pdev->dev); |
@@ -1466,10 +1480,29 @@ static int serial_omap_probe(struct platform_device *pdev) | |||
1466 | if (!dma_tx) | 1480 | if (!dma_tx) |
1467 | return -ENXIO; | 1481 | return -ENXIO; |
1468 | 1482 | ||
1483 | if (gpio_is_valid(omap_up_info->DTR_gpio) && | ||
1484 | omap_up_info->DTR_present) { | ||
1485 | ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial"); | ||
1486 | if (ret < 0) | ||
1487 | return ret; | ||
1488 | ret = gpio_direction_output(omap_up_info->DTR_gpio, | ||
1489 | omap_up_info->DTR_inverted); | ||
1490 | if (ret < 0) | ||
1491 | return ret; | ||
1492 | } | ||
1493 | |||
1469 | up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL); | 1494 | up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL); |
1470 | if (!up) | 1495 | if (!up) |
1471 | return -ENOMEM; | 1496 | return -ENOMEM; |
1472 | 1497 | ||
1498 | if (gpio_is_valid(omap_up_info->DTR_gpio) && | ||
1499 | omap_up_info->DTR_present) { | ||
1500 | up->DTR_gpio = omap_up_info->DTR_gpio; | ||
1501 | up->DTR_inverted = omap_up_info->DTR_inverted; | ||
1502 | } else | ||
1503 | up->DTR_gpio = -EINVAL; | ||
1504 | up->DTR_active = 0; | ||
1505 | |||
1473 | up->pdev = pdev; | 1506 | up->pdev = pdev; |
1474 | up->port.dev = &pdev->dev; | 1507 | up->port.dev = &pdev->dev; |
1475 | up->port.type = PORT_OMAP; | 1508 | up->port.type = PORT_OMAP; |