summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/8250/8250_fsl.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-01 14:08:15 +0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-01 14:08:15 +0400
commit177f72fd101d512d938558b53cd4faa6a5434090 (patch)
tree1cfe58343c705f02c53886d7aa781b97b671b704 /drivers/tty/serial/8250/8250_fsl.c
parent761bfdd91184c6662a9233976e855b4ccb883c96 (diff)
parent62aa2b537c6f5957afd98e29f96897419ed5ebab (diff)
downloadlinux-177f72fd101d512d938558b53cd4faa6a5434090.tar.xz
Merge tag 'v3.3-rc2' into for-3.4
A reasonable amount of new development is causing fiddly merge conflicts between different resource management changes (mostly fixing bugs in resource management due to noticing things while doing enhancements in the same area). Linux 3.3-rc2 .. several days delayed. No reason, I just didn't think of it.
Diffstat (limited to 'drivers/tty/serial/8250/8250_fsl.c')
-rw-r--r--drivers/tty/serial/8250/8250_fsl.c63
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 @@
+#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
+
+#include "8250.h"
+
+/*
+ * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This isn't a full driver; it just provides an alternate IRQ
+ * handler to deal with an errata. Everything else is just
+ * using the bog standard 8250 support.
+ *
+ * We follow code flow of serial8250_default_handle_irq() but add
+ * a check for a break and insert a dummy read on the Rx for the
+ * immediately following IRQ event.
+ *
+ * We re-use the already existing "bug handling" lsr_saved_flags
+ * field to carry the "what we just did" information from the one
+ * IRQ event to the next one.
+ */
+
+int fsl8250_handle_irq(struct uart_port *port)
+{
+ unsigned char lsr, orig_lsr;
+ unsigned long flags;
+ unsigned int iir;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ iir = port->serial_in(port, UART_IIR);
+ if (iir & UART_IIR_NO_INT) {
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ return 0;
+ }
+
+ /* This is the WAR; if last event was BRK, then read and return */
+ if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) {
+ up->lsr_saved_flags &= ~UART_LSR_BI;
+ port->serial_in(port, UART_RX);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ return 1;
+ }
+
+ lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
+
+ if (lsr & (UART_LSR_DR | UART_LSR_BI))
+ lsr = serial8250_rx_chars(up, lsr);
+
+ serial8250_modem_status(up);
+
+ if (lsr & UART_LSR_THRE)
+ serial8250_tx_chars(up);
+
+ up->lsr_saved_flags = orig_lsr;
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ return 1;
+}