diff options
author | Colin Cross <ccross@android.com> | 2012-01-23 16:58:16 -0800 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2012-01-27 14:52:15 -0800 |
commit | e41260ae321d2132f854a76aedb3e2d227dd7f93 (patch) | |
tree | c58140fbded30d42100936db777a7d2975902b00 /drivers/tty | |
parent | 673912854ca0c421ffe67f1e5aa557e01ec90c4c (diff) | |
download | kernel_samsung_tuna-e41260ae321d2132f854a76aedb3e2d227dd7f93.zip kernel_samsung_tuna-e41260ae321d2132f854a76aedb3e2d227dd7f93.tar.gz kernel_samsung_tuna-e41260ae321d2132f854a76aedb3e2d227dd7f93.tar.bz2 |
serial: omap: disable serial port irq during suspend
If the serial port interrupt is left enabled during suspend, it
can fire during uart_resume_port, while the uart is in an
undefined state and the port lock is not held.
Disable the interrupt in serial_omap_suspend, and enable it in
serial_omap_resume. This also requires moving the request_irq
into probe, instead of startup, so that the irq is always
available to disable.
Change-Id: Iaa88fa527b056828303fe1fbad6883b720278440
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 91fc121..c597da3 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -584,15 +584,8 @@ static int serial_omap_startup(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; unsigned long flags = 0; - int retval; - /* - * Allocate the IRQ - */ - retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags, - up->name, up); - if (retval) - return retval; + enable_irq(up->port.irq); dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id); @@ -701,7 +694,7 @@ static void serial_omap_shutdown(struct uart_port *port) up->uart_dma.rx_buf = NULL; } serial_omap_port_disable(up); - free_irq(up->port.irq, up); + disable_irq(up->port.irq); } static inline void @@ -1264,6 +1257,7 @@ static int serial_omap_suspend(struct device *dev) struct uart_omap_port *up = dev_get_drvdata(dev); if (up) { + disable_irq(up->port.irq); if (up->rts_mux_driver_control) { up->rts_pullup_in_suspend = 1; omap_rts_mux_write(MUX_PULL_UP, up->port.line); @@ -1282,6 +1276,7 @@ static int serial_omap_resume(struct device *dev) if (up) { uart_resume_port(&serial_omap_reg, &up->port); up->suspended = false; + enable_irq(up->port.irq); } return 0; @@ -1459,13 +1454,13 @@ static int serial_omap_probe(struct platform_device *pdev) dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); if (!dma_rx) { ret = -EINVAL; - goto err; + goto do_release_region; } dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); if (!dma_tx) { ret = -EINVAL; - goto err; + goto do_release_region; } up = kzalloc(sizeof(*up), GFP_KERNEL); @@ -1491,7 +1486,7 @@ static int serial_omap_probe(struct platform_device *pdev) if (!up->port.membase) { dev_err(&pdev->dev, "can't ioremap UART\n"); ret = -ENOMEM; - goto err1; + goto do_free; } up->port.flags = omap_up_info->flags; @@ -1535,21 +1530,31 @@ static int serial_omap_probe(struct platform_device *pdev) ui[pdev->id] = up; serial_omap_add_console_port(up); + ret = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags, + up->name, up); + if (ret) + goto do_iounmap; + disable_irq(up->port.irq); + ret = uart_add_one_port(&serial_omap_reg, &up->port); if (ret != 0) - goto err1; + goto do_free_irq; dev_set_drvdata(&pdev->dev, up); platform_set_drvdata(pdev, up); return 0; -err: - dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", - pdev->id, __func__, ret); -err1: + +do_free_irq: + free_irq(up->port.irq, up); +do_iounmap: + iounmap(up->port.membase); +do_free: kfree(up); do_release_region: release_mem_region(mem->start, (mem->end - mem->start) + 1); + dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", + pdev->id, __func__, ret); return ret; } @@ -1560,7 +1565,9 @@ static int serial_omap_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); if (up) { pm_runtime_disable(&up->pdev->dev); + free_irq(up->port.irq, up); uart_remove_one_port(&serial_omap_reg, &up->port); + iounmap(up->port.membase); kfree(up); } return 0; |