diff options
Diffstat (limited to 'drivers/tty/serial/atmel_serial.c')
-rw-r--r-- | drivers/tty/serial/atmel_serial.c | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 846552bff67d..4e959c43f680 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/gpio/consumer.h> | 47 | #include <linux/gpio/consumer.h> |
48 | #include <linux/err.h> | 48 | #include <linux/err.h> |
49 | #include <linux/irq.h> | 49 | #include <linux/irq.h> |
50 | #include <linux/suspend.h> | ||
50 | 51 | ||
51 | #include <asm/io.h> | 52 | #include <asm/io.h> |
52 | #include <asm/ioctls.h> | 53 | #include <asm/ioctls.h> |
@@ -173,6 +174,12 @@ struct atmel_uart_port { | |||
173 | bool ms_irq_enabled; | 174 | bool ms_irq_enabled; |
174 | bool is_usart; /* usart or uart */ | 175 | bool is_usart; /* usart or uart */ |
175 | struct timer_list uart_timer; /* uart timer */ | 176 | struct timer_list uart_timer; /* uart timer */ |
177 | |||
178 | bool suspended; | ||
179 | unsigned int pending; | ||
180 | unsigned int pending_status; | ||
181 | spinlock_t lock_suspended; | ||
182 | |||
176 | int (*prepare_rx)(struct uart_port *port); | 183 | int (*prepare_rx)(struct uart_port *port); |
177 | int (*prepare_tx)(struct uart_port *port); | 184 | int (*prepare_tx)(struct uart_port *port); |
178 | void (*schedule_rx)(struct uart_port *port); | 185 | void (*schedule_rx)(struct uart_port *port); |
@@ -1179,12 +1186,15 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) | |||
1179 | { | 1186 | { |
1180 | struct uart_port *port = dev_id; | 1187 | struct uart_port *port = dev_id; |
1181 | struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); | 1188 | struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); |
1182 | unsigned int status, pending, pass_counter = 0; | 1189 | unsigned int status, pending, mask, pass_counter = 0; |
1183 | bool gpio_handled = false; | 1190 | bool gpio_handled = false; |
1184 | 1191 | ||
1192 | spin_lock(&atmel_port->lock_suspended); | ||
1193 | |||
1185 | do { | 1194 | do { |
1186 | status = atmel_get_lines_status(port); | 1195 | status = atmel_get_lines_status(port); |
1187 | pending = status & UART_GET_IMR(port); | 1196 | mask = UART_GET_IMR(port); |
1197 | pending = status & mask; | ||
1188 | if (!gpio_handled) { | 1198 | if (!gpio_handled) { |
1189 | /* | 1199 | /* |
1190 | * Dealing with GPIO interrupt | 1200 | * Dealing with GPIO interrupt |
@@ -1206,11 +1216,21 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) | |||
1206 | if (!pending) | 1216 | if (!pending) |
1207 | break; | 1217 | break; |
1208 | 1218 | ||
1219 | if (atmel_port->suspended) { | ||
1220 | atmel_port->pending |= pending; | ||
1221 | atmel_port->pending_status = status; | ||
1222 | UART_PUT_IDR(port, mask); | ||
1223 | pm_system_wakeup(); | ||
1224 | break; | ||
1225 | } | ||
1226 | |||
1209 | atmel_handle_receive(port, pending); | 1227 | atmel_handle_receive(port, pending); |
1210 | atmel_handle_status(port, pending, status); | 1228 | atmel_handle_status(port, pending, status); |
1211 | atmel_handle_transmit(port, pending); | 1229 | atmel_handle_transmit(port, pending); |
1212 | } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT); | 1230 | } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT); |
1213 | 1231 | ||
1232 | spin_unlock(&atmel_port->lock_suspended); | ||
1233 | |||
1214 | return pass_counter ? IRQ_HANDLED : IRQ_NONE; | 1234 | return pass_counter ? IRQ_HANDLED : IRQ_NONE; |
1215 | } | 1235 | } |
1216 | 1236 | ||
@@ -1742,7 +1762,8 @@ static int atmel_startup(struct uart_port *port) | |||
1742 | /* | 1762 | /* |
1743 | * Allocate the IRQ | 1763 | * Allocate the IRQ |
1744 | */ | 1764 | */ |
1745 | retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, | 1765 | retval = request_irq(port->irq, atmel_interrupt, |
1766 | IRQF_SHARED | IRQF_COND_SUSPEND, | ||
1746 | tty ? tty->name : "atmel_serial", port); | 1767 | tty ? tty->name : "atmel_serial", port); |
1747 | if (retval) { | 1768 | if (retval) { |
1748 | dev_err(port->dev, "atmel_startup - Can't get irq\n"); | 1769 | dev_err(port->dev, "atmel_startup - Can't get irq\n"); |
@@ -2513,8 +2534,14 @@ static int atmel_serial_suspend(struct platform_device *pdev, | |||
2513 | 2534 | ||
2514 | /* we can not wake up if we're running on slow clock */ | 2535 | /* we can not wake up if we're running on slow clock */ |
2515 | atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); | 2536 | atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); |
2516 | if (atmel_serial_clk_will_stop()) | 2537 | if (atmel_serial_clk_will_stop()) { |
2538 | unsigned long flags; | ||
2539 | |||
2540 | spin_lock_irqsave(&atmel_port->lock_suspended, flags); | ||
2541 | atmel_port->suspended = true; | ||
2542 | spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); | ||
2517 | device_set_wakeup_enable(&pdev->dev, 0); | 2543 | device_set_wakeup_enable(&pdev->dev, 0); |
2544 | } | ||
2518 | 2545 | ||
2519 | uart_suspend_port(&atmel_uart, port); | 2546 | uart_suspend_port(&atmel_uart, port); |
2520 | 2547 | ||
@@ -2525,6 +2552,18 @@ static int atmel_serial_resume(struct platform_device *pdev) | |||
2525 | { | 2552 | { |
2526 | struct uart_port *port = platform_get_drvdata(pdev); | 2553 | struct uart_port *port = platform_get_drvdata(pdev); |
2527 | struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); | 2554 | struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); |
2555 | unsigned long flags; | ||
2556 | |||
2557 | spin_lock_irqsave(&atmel_port->lock_suspended, flags); | ||
2558 | if (atmel_port->pending) { | ||
2559 | atmel_handle_receive(port, atmel_port->pending); | ||
2560 | atmel_handle_status(port, atmel_port->pending, | ||
2561 | atmel_port->pending_status); | ||
2562 | atmel_handle_transmit(port, atmel_port->pending); | ||
2563 | atmel_port->pending = 0; | ||
2564 | } | ||
2565 | atmel_port->suspended = false; | ||
2566 | spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); | ||
2528 | 2567 | ||
2529 | uart_resume_port(&atmel_uart, port); | 2568 | uart_resume_port(&atmel_uart, port); |
2530 | device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); | 2569 | device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); |
@@ -2593,6 +2632,8 @@ static int atmel_serial_probe(struct platform_device *pdev) | |||
2593 | port->backup_imr = 0; | 2632 | port->backup_imr = 0; |
2594 | port->uart.line = ret; | 2633 | port->uart.line = ret; |
2595 | 2634 | ||
2635 | spin_lock_init(&port->lock_suspended); | ||
2636 | |||
2596 | ret = atmel_init_gpios(port, &pdev->dev); | 2637 | ret = atmel_init_gpios(port, &pdev->dev); |
2597 | if (ret < 0) | 2638 | if (ret < 0) |
2598 | dev_err(&pdev->dev, "%s", | 2639 | dev_err(&pdev->dev, "%s", |