aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2013-10-22 09:49:48 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-29 19:26:54 -0400
commit2a0b965cfb6efc667228831fc3a30308b4f94a87 (patch)
tree1226df08fda75015daee1882ebf8d6354880898c
parent24b6bb0714508e3a4f51dec9f4333c988f8afb76 (diff)
serial: omap: Add support for optional wake-up
With the recent pinctrl-single changes, omaps can treat wake-up events from deeper idle states as interrupts. There's a separate "io chain" controller on most omaps that stays enabled when the device hits off-idle and the regular interrupt controller is powered off. Let's add support for the optional second interrupt for wake-up events. And then serial-omap can manage the wake-up interrupt from it's runtime PM calls to avoid spurious interrupts during runtime. Note that the wake interrupt is board specific as it uses the UART RX pin, and for omap3, there are six pin options for UART3 RX pin. Also Note that the legacy platform based booting handles the wake-ups in the legacy mux driver and does not need to pass the wake-up interrupt to the driver. And finally, to pass the wake-up interrupt in the dts file, either interrupt-map or the pending interrupts-extended property needs to be passed. It's probably best to use interrupts-extended when it's available. Cc: Felipe Balbi <balbi@ti.com> Cc: Kevin Hilman <khilman@linaro.org> Cc: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Felipe Balbi <balbi@ti.com> Reviewed-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/omap-serial.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index c715778a745c..b69393f2817d 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/of_irq.h>
42#include <linux/gpio.h> 43#include <linux/gpio.h>
43#include <linux/of_gpio.h> 44#include <linux/of_gpio.h>
44#include <linux/platform_data/serial-omap.h> 45#include <linux/platform_data/serial-omap.h>
@@ -134,6 +135,7 @@ struct uart_omap_port {
134 struct uart_port port; 135 struct uart_port port;
135 struct uart_omap_dma uart_dma; 136 struct uart_omap_dma uart_dma;
136 struct device *dev; 137 struct device *dev;
138 int wakeirq;
137 139
138 unsigned char ier; 140 unsigned char ier;
139 unsigned char lcr; 141 unsigned char lcr;
@@ -214,10 +216,23 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
214 return pdata->get_context_loss_count(up->dev); 216 return pdata->get_context_loss_count(up->dev);
215} 217}
216 218
219static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up,
220 bool enable)
221{
222 if (!up->wakeirq)
223 return;
224
225 if (enable)
226 enable_irq(up->wakeirq);
227 else
228 disable_irq(up->wakeirq);
229}
230
217static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) 231static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
218{ 232{
219 struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); 233 struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
220 234
235 serial_omap_enable_wakeirq(up, enable);
221 if (!pdata || !pdata->enable_wakeup) 236 if (!pdata || !pdata->enable_wakeup)
222 return; 237 return;
223 238
@@ -699,6 +714,20 @@ static int serial_omap_startup(struct uart_port *port)
699 if (retval) 714 if (retval)
700 return retval; 715 return retval;
701 716
717 /* Optional wake-up IRQ */
718 if (up->wakeirq) {
719 retval = request_irq(up->wakeirq, serial_omap_irq,
720 up->port.irqflags, up->name, up);
721 if (retval) {
722 free_irq(up->port.irq, up);
723 return retval;
724 }
725 disable_irq(up->wakeirq);
726 } else {
727 dev_info(up->port.dev, "no wakeirq for uart%d\n",
728 up->port.line);
729 }
730
702 dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); 731 dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
703 732
704 pm_runtime_get_sync(up->dev); 733 pm_runtime_get_sync(up->dev);
@@ -787,6 +816,8 @@ static void serial_omap_shutdown(struct uart_port *port)
787 pm_runtime_mark_last_busy(up->dev); 816 pm_runtime_mark_last_busy(up->dev);
788 pm_runtime_put_autosuspend(up->dev); 817 pm_runtime_put_autosuspend(up->dev);
789 free_irq(up->port.irq, up); 818 free_irq(up->port.irq, up);
819 if (up->wakeirq)
820 free_irq(up->wakeirq, up);
790} 821}
791 822
792static void serial_omap_uart_qos_work(struct work_struct *work) 823static void serial_omap_uart_qos_work(struct work_struct *work)
@@ -1572,11 +1603,23 @@ static int serial_omap_probe(struct platform_device *pdev)
1572 struct uart_omap_port *up; 1603 struct uart_omap_port *up;
1573 struct resource *mem, *irq; 1604 struct resource *mem, *irq;
1574 struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); 1605 struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
1575 int ret; 1606 int ret, uartirq = 0, wakeirq = 0;
1576 1607
1608 /* The optional wakeirq may be specified in the board dts file */
1577 if (pdev->dev.of_node) { 1609 if (pdev->dev.of_node) {
1610 uartirq = irq_of_parse_and_map(pdev->dev.of_node, 0);
1611 if (!uartirq)
1612 return -EPROBE_DEFER;
1613 wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
1578 omap_up_info = of_get_uart_port_info(&pdev->dev); 1614 omap_up_info = of_get_uart_port_info(&pdev->dev);
1579 pdev->dev.platform_data = omap_up_info; 1615 pdev->dev.platform_data = omap_up_info;
1616 } else {
1617 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1618 if (!irq) {
1619 dev_err(&pdev->dev, "no irq resource?\n");
1620 return -ENODEV;
1621 }
1622 uartirq = irq->start;
1580 } 1623 }
1581 1624
1582 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1625 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1585,12 +1628,6 @@ static int serial_omap_probe(struct platform_device *pdev)
1585 return -ENODEV; 1628 return -ENODEV;
1586 } 1629 }
1587 1630
1588 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1589 if (!irq) {
1590 dev_err(&pdev->dev, "no irq resource?\n");
1591 return -ENODEV;
1592 }
1593
1594 if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), 1631 if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
1595 pdev->dev.driver->name)) { 1632 pdev->dev.driver->name)) {
1596 dev_err(&pdev->dev, "memory region already claimed\n"); 1633 dev_err(&pdev->dev, "memory region already claimed\n");
@@ -1624,7 +1661,8 @@ static int serial_omap_probe(struct platform_device *pdev)
1624 up->port.dev = &pdev->dev; 1661 up->port.dev = &pdev->dev;
1625 up->port.type = PORT_OMAP; 1662 up->port.type = PORT_OMAP;
1626 up->port.iotype = UPIO_MEM; 1663 up->port.iotype = UPIO_MEM;
1627 up->port.irq = irq->start; 1664 up->port.irq = uartirq;
1665 up->wakeirq = wakeirq;
1628 1666
1629 up->port.regshift = 2; 1667 up->port.regshift = 2;
1630 up->port.fifosize = 64; 1668 up->port.fifosize = 64;