diff options
Diffstat (limited to 'drivers/tty/serial/8250/8250_fsl.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_fsl.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c new file mode 100644 index 000000000000..f4d3c47b88e8 --- /dev/null +++ b/drivers/tty/serial/8250/8250_fsl.c | |||
@@ -0,0 +1,63 @@ | |||
1 | #include <linux/serial_reg.h> | ||
2 | #include <linux/serial_8250.h> | ||
3 | |||
4 | #include "8250.h" | ||
5 | |||
6 | /* | ||
7 | * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This isn't a full driver; it just provides an alternate IRQ | ||
14 | * handler to deal with an errata. Everything else is just | ||
15 | * using the bog standard 8250 support. | ||
16 | * | ||
17 | * We follow code flow of serial8250_default_handle_irq() but add | ||
18 | * a check for a break and insert a dummy read on the Rx for the | ||
19 | * immediately following IRQ event. | ||
20 | * | ||
21 | * We re-use the already existing "bug handling" lsr_saved_flags | ||
22 | * field to carry the "what we just did" information from the one | ||
23 | * IRQ event to the next one. | ||
24 | */ | ||
25 | |||
26 | int fsl8250_handle_irq(struct uart_port *port) | ||
27 | { | ||
28 | unsigned char lsr, orig_lsr; | ||
29 | unsigned long flags; | ||
30 | unsigned int iir; | ||
31 | struct uart_8250_port *up = | ||
32 | container_of(port, struct uart_8250_port, port); | ||
33 | |||
34 | spin_lock_irqsave(&up->port.lock, flags); | ||
35 | |||
36 | iir = port->serial_in(port, UART_IIR); | ||
37 | if (iir & UART_IIR_NO_INT) { | ||
38 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | /* This is the WAR; if last event was BRK, then read and return */ | ||
43 | if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) { | ||
44 | up->lsr_saved_flags &= ~UART_LSR_BI; | ||
45 | port->serial_in(port, UART_RX); | ||
46 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
47 | return 1; | ||
48 | } | ||
49 | |||
50 | lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR); | ||
51 | |||
52 | if (lsr & (UART_LSR_DR | UART_LSR_BI)) | ||
53 | lsr = serial8250_rx_chars(up, lsr); | ||
54 | |||
55 | serial8250_modem_status(up); | ||
56 | |||
57 | if (lsr & UART_LSR_THRE) | ||
58 | serial8250_tx_chars(up); | ||
59 | |||
60 | up->lsr_saved_flags = orig_lsr; | ||
61 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
62 | return 1; | ||
63 | } | ||