diff mbox

[v2] serial: omap: Add support for optional wake-up

Message ID 20131022134947.GK15154@atomide.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tony Lindgren Oct. 22, 2013, 1:49 p.m. UTC
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>

---

Updated to simplify based on the review comments.

Greg, care to queue this for v3.13 if not too late?

This removes a dependency for omaps for having runtime
PM working with serial port using device tree, so we
can start moving to device tree only booting for omap3
for v3.14.

Comments

Grant Likely Oct. 24, 2013, 10:33 a.m. UTC | #1
On Tue, 22 Oct 2013 06:49:48 -0700, Tony Lindgren <tony@atomide.com> wrote:
> 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>
> 
> ---
> 
> Updated to simplify based on the review comments.
> 
> Greg, care to queue this for v3.13 if not too late?
> 
> This removes a dependency for omaps for having runtime
> PM working with serial port using device tree, so we
> can start moving to device tree only booting for omap3
> for v3.14.
> 
> --- 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/of_irq.h>
>  #include <linux/gpio.h>
>  #include <linux/of_gpio.h>
>  #include <linux/platform_data/serial-omap.h>
> @@ -134,6 +135,7 @@ struct uart_omap_port {
>  	struct uart_port	port;
>  	struct uart_omap_dma	uart_dma;
>  	struct device		*dev;
> +	int			wakeirq;
>  
>  	unsigned char		ier;
>  	unsigned char		lcr;
> @@ -214,10 +216,23 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
>  	return pdata->get_context_loss_count(up->dev);
>  }
>  
> +static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up,
> +				       bool enable)
> +{
> +	if (!up->wakeirq)
> +		return;
> +
> +	if (enable)
> +		enable_irq(up->wakeirq);
> +	else
> +		disable_irq(up->wakeirq);
> +}
> +
>  static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
>  {
>  	struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
>  
> +	serial_omap_enable_wakeirq(up, enable);
>  	if (!pdata || !pdata->enable_wakeup)
>  		return;
>  
> @@ -699,6 +714,20 @@ static int serial_omap_startup(struct uart_port *port)
>  	if (retval)
>  		return retval;
>  
> +	/* Optional wake-up IRQ */
> +	if (up->wakeirq) {
> +		retval = request_irq(up->wakeirq, serial_omap_irq,
> +				     up->port.irqflags, up->name, up);
> +		if (retval) {
> +			free_irq(up->port.irq, up);
> +			return retval;
> +		}
> +		disable_irq(up->wakeirq);
> +	} else {
> +		dev_info(up->port.dev, "no wakeirq for uart%d\n",
> +			 up->port.line);
> +	}
> +
>  	dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
>  
>  	pm_runtime_get_sync(up->dev);
> @@ -787,6 +816,8 @@ static void serial_omap_shutdown(struct uart_port *port)
>  	pm_runtime_mark_last_busy(up->dev);
>  	pm_runtime_put_autosuspend(up->dev);
>  	free_irq(up->port.irq, up);
> +	if (up->wakeirq)
> +		free_irq(up->wakeirq, up);
>  }
>  
>  static void serial_omap_uart_qos_work(struct work_struct *work)
> @@ -1572,11 +1603,23 @@ static int serial_omap_probe(struct platform_device *pdev)
>  	struct uart_omap_port	*up;
>  	struct resource		*mem, *irq;
>  	struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
> -	int ret;
> +	int ret, uartirq = 0, wakeirq = 0;
>  
> +	/* The optional wakeirq may be specified in the board dts file */
>  	if (pdev->dev.of_node) {
> +		uartirq = irq_of_parse_and_map(pdev->dev.of_node, 0);
> +		if (!uartirq)
> +			return -EPROBE_DEFER;
> +		wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
>  		omap_up_info = of_get_uart_port_info(&pdev->dev);
>  		pdev->dev.platform_data = omap_up_info;
> +	} else {
> +		irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +		if (!irq) {
> +			dev_err(&pdev->dev, "no irq resource?\n");
> +			return -ENODEV;
> +		}
> +		uartirq = irq->start;

Ugh. This is such a hack. platform_get_irq() should just work for DT and
non-DT. There is no way around it right now, but we need to get the code
in place to resolve IRQs late so that drivers don't need these special
cases.

g.
Tony Lindgren Oct. 24, 2013, 1:19 p.m. UTC | #2
* Grant Likely <grant.likely@secretlab.ca> [131024 03:33]:
> On Tue, 22 Oct 2013 06:49:48 -0700, Tony Lindgren <tony@atomide.com> wrote:
> > @@ -1572,11 +1603,23 @@ static int serial_omap_probe(struct platform_device *pdev)
> >  	struct uart_omap_port	*up;
> >  	struct resource		*mem, *irq;
> >  	struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
> > -	int ret;
> > +	int ret, uartirq = 0, wakeirq = 0;
> >  
> > +	/* The optional wakeirq may be specified in the board dts file */
> >  	if (pdev->dev.of_node) {
> > +		uartirq = irq_of_parse_and_map(pdev->dev.of_node, 0);
> > +		if (!uartirq)
> > +			return -EPROBE_DEFER;
> > +		wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
> >  		omap_up_info = of_get_uart_port_info(&pdev->dev);
> >  		pdev->dev.platform_data = omap_up_info;
> > +	} else {
> > +		irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> > +		if (!irq) {
> > +			dev_err(&pdev->dev, "no irq resource?\n");
> > +			return -ENODEV;
> > +		}
> > +		uartirq = irq->start;
> 
> Ugh. This is such a hack. platform_get_irq() should just work for DT and
> non-DT. There is no way around it right now, but we need to get the code
> in place to resolve IRQs late so that drivers don't need these special
> cases.

Yes it's pretty messed up. I wrote something about it in the
"Getting rid of subsys_initcall usage?" thread at:

http://www.mail-archive.com/linux-i2c@vger.kernel.org/msg13678.html

And having zero populated in the struct resource as valid IRQ is
not nice at all.

Regards,

Tony
Kevin Hilman Nov. 7, 2013, 6:52 p.m. UTC | #3
Tony Lindgren <tony@atomide.com> writes:

> 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>
>
> ---
>
> Updated to simplify based on the review comments.
>
> Greg, care to queue this for v3.13 if not too late?
>
> This removes a dependency for omaps for having runtime
> PM working with serial port using device tree, so we
> can start moving to device tree only booting for omap3
> for v3.14.

A bunch of DT boot failures on OMAP3 platforms with latest mainline were
bisected down to this patch.  Boot results here:
http://lists.linaro.org/pipermail/kernel-build-reports/2013-November/000954.html

This doesn't seem to properly handle the OMAP3 case where we have DT
nodes, but no reg or interrupts properties since they're still using
hwmod.

The problems seems to be because these OMAP3 platforms don't list any
interrupts in their DTS files for the UARTs, but a quick hack at adding
interrupts to omap3.dtsi didn't help either so something else is going
on.

This patch should probably be reverted until it gets broader testing.

Kevin
Tony Lindgren Nov. 7, 2013, 7:45 p.m. UTC | #4
* Kevin Hilman <khilman@linaro.org> [131107 10:53]:
> 
> A bunch of DT boot failures on OMAP3 platforms with latest mainline were
> bisected down to this patch.  Boot results here:
> http://lists.linaro.org/pipermail/kernel-build-reports/2013-November/000954.html
> 
> This doesn't seem to properly handle the OMAP3 case where we have DT
> nodes, but no reg or interrupts properties since they're still using
> hwmod.
> 
> The problems seems to be because these OMAP3 platforms don't list any
> interrupts in their DTS files for the UARTs, but a quick hack at adding
> interrupts to omap3.dtsi didn't help either so something else is going
> on.
> 
> This patch should probably be reverted until it gets broader testing.

Hmm I'm not seeing this with my tree, and sounds like it should be
already fixed by commit d7c8f2596 (ARM: dts: Add missing reg,
interrupt and dma entries for omap3).

Can you check that you have that commit in your tree?

Regards,

Tony
Olof Johansson Nov. 7, 2013, 7:48 p.m. UTC | #5
On Thu, Nov 7, 2013 at 11:45 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Kevin Hilman <khilman@linaro.org> [131107 10:53]:
>>
>> A bunch of DT boot failures on OMAP3 platforms with latest mainline were
>> bisected down to this patch.  Boot results here:
>> http://lists.linaro.org/pipermail/kernel-build-reports/2013-November/000954.html
>>
>> This doesn't seem to properly handle the OMAP3 case where we have DT
>> nodes, but no reg or interrupts properties since they're still using
>> hwmod.
>>
>> The problems seems to be because these OMAP3 platforms don't list any
>> interrupts in their DTS files for the UARTs, but a quick hack at adding
>> interrupts to omap3.dtsi didn't help either so something else is going
>> on.
>>
>> This patch should probably be reverted until it gets broader testing.
>
> Hmm I'm not seeing this with my tree, and sounds like it should be
> already fixed by commit d7c8f2596 (ARM: dts: Add missing reg,
> interrupt and dma entries for omap3).
>
> Can you check that you have that commit in your tree?

Ah, that explains why we haven't seen it in -next.

We should probably queue up our branches for Linus to merge ASAP,
that'll take care of it.


-Olof
Tony Lindgren Nov. 7, 2013, 8:01 p.m. UTC | #6
* Olof Johansson <olof@lixom.net> [131107 11:48]:
> On Thu, Nov 7, 2013 at 11:45 AM, Tony Lindgren <tony@atomide.com> wrote:
> > * Kevin Hilman <khilman@linaro.org> [131107 10:53]:
> >>
> >> A bunch of DT boot failures on OMAP3 platforms with latest mainline were
> >> bisected down to this patch.  Boot results here:
> >> http://lists.linaro.org/pipermail/kernel-build-reports/2013-November/000954.html
> >>
> >> This doesn't seem to properly handle the OMAP3 case where we have DT
> >> nodes, but no reg or interrupts properties since they're still using
> >> hwmod.
> >>
> >> The problems seems to be because these OMAP3 platforms don't list any
> >> interrupts in their DTS files for the UARTs, but a quick hack at adding
> >> interrupts to omap3.dtsi didn't help either so something else is going
> >> on.
> >>
> >> This patch should probably be reverted until it gets broader testing.
> >
> > Hmm I'm not seeing this with my tree, and sounds like it should be
> > already fixed by commit d7c8f2596 (ARM: dts: Add missing reg,
> > interrupt and dma entries for omap3).
> >
> > Can you check that you have that commit in your tree?
> 
> Ah, that explains why we haven't seen it in -next.

Yeah looks like there's a dependency that I missed. I probably
tested the serial patch separately with omap4 only.
 
> We should probably queue up our branches for Linus to merge ASAP,
> that'll take care of it.

Yeah. This issue should be of limited damage as most omap3 boards
are not DT only yet, that won't happen until for v3.14.

Regards,

Tony
Kevin Hilman Nov. 7, 2013, 8:27 p.m. UTC | #7
Tony Lindgren <tony@atomide.com> writes:

> * Kevin Hilman <khilman@linaro.org> [131107 10:53]:
>> 
>> A bunch of DT boot failures on OMAP3 platforms with latest mainline were
>> bisected down to this patch.  Boot results here:
>> http://lists.linaro.org/pipermail/kernel-build-reports/2013-November/000954.html
>> 
>> This doesn't seem to properly handle the OMAP3 case where we have DT
>> nodes, but no reg or interrupts properties since they're still using
>> hwmod.
>> 
>> The problems seems to be because these OMAP3 platforms don't list any
>> interrupts in their DTS files for the UARTs, but a quick hack at adding
>> interrupts to omap3.dtsi didn't help either so something else is going
>> on.
>> 
>> This patch should probably be reverted until it gets broader testing.
>
> Hmm I'm not seeing this with my tree, and sounds like it should be
> already fixed by commit d7c8f2596 (ARM: dts: Add missing reg,
> interrupt and dma entries for omap3).
>
> Can you check that you have that commit in your tree?

Ah, that commit is in -next but not yet in mainline.   Indeed it works
fine with that commit on top of mainline.

Time to queue up our pull requests for linus.

Kevin
diff mbox

Patch

--- 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/of_irq.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_data/serial-omap.h>
@@ -134,6 +135,7 @@  struct uart_omap_port {
 	struct uart_port	port;
 	struct uart_omap_dma	uart_dma;
 	struct device		*dev;
+	int			wakeirq;
 
 	unsigned char		ier;
 	unsigned char		lcr;
@@ -214,10 +216,23 @@  static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
 	return pdata->get_context_loss_count(up->dev);
 }
 
+static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up,
+				       bool enable)
+{
+	if (!up->wakeirq)
+		return;
+
+	if (enable)
+		enable_irq(up->wakeirq);
+	else
+		disable_irq(up->wakeirq);
+}
+
 static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
 {
 	struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
 
+	serial_omap_enable_wakeirq(up, enable);
 	if (!pdata || !pdata->enable_wakeup)
 		return;
 
@@ -699,6 +714,20 @@  static int serial_omap_startup(struct uart_port *port)
 	if (retval)
 		return retval;
 
+	/* Optional wake-up IRQ */
+	if (up->wakeirq) {
+		retval = request_irq(up->wakeirq, serial_omap_irq,
+				     up->port.irqflags, up->name, up);
+		if (retval) {
+			free_irq(up->port.irq, up);
+			return retval;
+		}
+		disable_irq(up->wakeirq);
+	} else {
+		dev_info(up->port.dev, "no wakeirq for uart%d\n",
+			 up->port.line);
+	}
+
 	dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
 
 	pm_runtime_get_sync(up->dev);
@@ -787,6 +816,8 @@  static void serial_omap_shutdown(struct uart_port *port)
 	pm_runtime_mark_last_busy(up->dev);
 	pm_runtime_put_autosuspend(up->dev);
 	free_irq(up->port.irq, up);
+	if (up->wakeirq)
+		free_irq(up->wakeirq, up);
 }
 
 static void serial_omap_uart_qos_work(struct work_struct *work)
@@ -1572,11 +1603,23 @@  static int serial_omap_probe(struct platform_device *pdev)
 	struct uart_omap_port	*up;
 	struct resource		*mem, *irq;
 	struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
-	int ret;
+	int ret, uartirq = 0, wakeirq = 0;
 
+	/* The optional wakeirq may be specified in the board dts file */
 	if (pdev->dev.of_node) {
+		uartirq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+		if (!uartirq)
+			return -EPROBE_DEFER;
+		wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
 		omap_up_info = of_get_uart_port_info(&pdev->dev);
 		pdev->dev.platform_data = omap_up_info;
+	} else {
+		irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+		if (!irq) {
+			dev_err(&pdev->dev, "no irq resource?\n");
+			return -ENODEV;
+		}
+		uartirq = irq->start;
 	}
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1585,12 +1628,6 @@  static int serial_omap_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!irq) {
-		dev_err(&pdev->dev, "no irq resource?\n");
-		return -ENODEV;
-	}
-
 	if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
 				pdev->dev.driver->name)) {
 		dev_err(&pdev->dev, "memory region already claimed\n");
@@ -1624,7 +1661,8 @@  static int serial_omap_probe(struct platform_device *pdev)
 	up->port.dev = &pdev->dev;
 	up->port.type = PORT_OMAP;
 	up->port.iotype = UPIO_MEM;
-	up->port.irq = irq->start;
+	up->port.irq = uartirq;
+	up->wakeirq = wakeirq;
 
 	up->port.regshift = 2;
 	up->port.fifosize = 64;