aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2012-01-23 16:58:16 -0800
committerColin Cross <ccross@android.com>2012-01-27 14:52:15 -0800
commite41260ae321d2132f854a76aedb3e2d227dd7f93 (patch)
treec58140fbded30d42100936db777a7d2975902b00 /drivers/tty
parent673912854ca0c421ffe67f1e5aa557e01ec90c4c (diff)
downloadkernel_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.c41
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;