tegra, serial8250: add ->handle_break() uart_port op
authorDan Williams <dan.j.williams@intel.com>
Tue, 10 Apr 2012 21:10:53 +0000 (14:10 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 18 Apr 2012 22:07:53 +0000 (15:07 -0700)
The "KT" serial port has another use case for a "received break" quirk,
so before adding another special case to the 8250 core take this
opportunity to push such quirks out of the core and into a uart_port op.

Stephen says:
"If the callback function is to no longer live in 8250.c itself,
 arch/arm/mach-tegra/devices.c isn't logically a good place to put it,
 and that file will be going away once we get rid of all the board files
 and move solely to device tree."

...so since 8250_pci.c houses all the quirks for pci serial devices this
quirk is similarly housed in of_serial.c.  Once the open firmware
conversion completes the infrastructure details
(include/linux/of_serial.h, and the export) can all be removed to make
this self contained to of_serial.c.

Cc: Nhan H Mai <nhan.h.mai@intel.com>
Cc: Colin Cross <ccross@android.com>
Cc: Olof Johansson <olof@lixom.net>
[stephen: kill CONFIG_SERIAL_TEGRA in favor just using CONFIG_ARCH_TEGRA]
Cc: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Sudhakar Mamillapalli <sudhakar@fb.com>
Reported-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
Tested-by: Stephen Warren <swarren@wwwdotorg.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm/mach-tegra/board-harmony.c
arch/arm/mach-tegra/board-paz00.c
arch/arm/mach-tegra/board-seaboard.c
arch/arm/mach-tegra/board-trimslice.c
drivers/tty/serial/8250/8250.c
drivers/tty/serial/of_serial.c
include/linux/of_serial.h [new file with mode: 0644]
include/linux/serial_8250.h
include/linux/serial_core.h

index c00aadb..222182e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/pda_power.h>
@@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
                .irq            = INT_UARTD,
                .flags          = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
                .type           = PORT_TEGRA,
+               .handle_break   = tegra_serial_handle_break,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
                .uartclk        = 216000000,
index 330afdf..d0735c7 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio_keys.h>
@@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
                .irq            = INT_UARTA,
                .flags          = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
                .type           = PORT_TEGRA,
+               .handle_break   = tegra_serial_handle_break,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
                .uartclk        = 216000000,
@@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
                .irq            = INT_UARTC,
                .flags          = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
                .type           = PORT_TEGRA,
+               .handle_break   = tegra_serial_handle_break,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
                .uartclk        = 216000000,
index d669847..5b687b8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/input.h>
@@ -47,6 +48,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
                /* Memory and IRQ filled in before registration */
                .flags          = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
                .type           = PORT_TEGRA,
+               .handle_break   = tegra_serial_handle_break,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
                .uartclk        = 216000000,
index cd52820..f735858 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
@@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
                .irq            = INT_UARTA,
                .flags          = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
                .type           = PORT_TEGRA,
+               .handle_break   = tegra_serial_handle_break,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
                .uartclk        = 216000000,
index 5b149b4..dffd623 100644 (file)
@@ -1332,27 +1332,6 @@ static void serial8250_enable_ms(struct uart_port *port)
 }
 
 /*
- * Clear the Tegra rx fifo after a break
- *
- * FIXME: This needs to become a port specific callback once we have a
- * framework for this
- */
-static void clear_rx_fifo(struct uart_8250_port *up)
-{
-       unsigned int status, tmout = 10000;
-       do {
-               status = serial_in(up, UART_LSR);
-               if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
-                       status = serial_in(up, UART_RX);
-               else
-                       break;
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while (1);
-}
-
-/*
  * serial8250_rx_chars: processes according to the passed in LSR
  * value, and returns the remaining LSR bits not handled
  * by this Rx routine.
@@ -1386,20 +1365,10 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
                up->lsr_saved_flags = 0;
 
                if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
-                       /*
-                        * For statistics only
-                        */
                        if (lsr & UART_LSR_BI) {
                                lsr &= ~(UART_LSR_FE | UART_LSR_PE);
                                port->icount.brk++;
                                /*
-                                * If tegra port then clear the rx fifo to
-                                * accept another break/character.
-                                */
-                               if (port->type == PORT_TEGRA)
-                                       clear_rx_fifo(up);
-
-                               /*
                                 * We do the SysRQ and SAK checking
                                 * here because otherwise the break
                                 * may get masked by ignore_status_mask
@@ -3037,6 +3006,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
                port.serial_in          = p->serial_in;
                port.serial_out         = p->serial_out;
                port.handle_irq         = p->handle_irq;
+               port.handle_break       = p->handle_break;
                port.set_termios        = p->set_termios;
                port.pm                 = p->pm;
                port.dev                = &dev->dev;
@@ -3209,6 +3179,8 @@ int serial8250_register_port(struct uart_port *port)
                        uart->port.set_termios = port->set_termios;
                if (port->pm)
                        uart->port.pm = port->pm;
+               if (port->handle_break)
+                       uart->port.handle_break = port->handle_break;
 
                if (serial8250_isa_config != NULL)
                        serial8250_isa_config(0, &uart->port,
index e8c9cee..5410c06 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/of_serial.h>
 #include <linux/of_platform.h>
 #include <linux/nwpserial.h>
 
@@ -24,6 +27,26 @@ struct of_serial_info {
        int line;
 };
 
+#ifdef CONFIG_ARCH_TEGRA
+void tegra_serial_handle_break(struct uart_port *p)
+{
+       unsigned int status, tmout = 10000;
+
+       do {
+               status = p->serial_in(p, UART_LSR);
+               if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
+                       status = p->serial_in(p, UART_RX);
+               else
+                       break;
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while (1);
+}
+/* FIXME remove this export when tegra finishes conversion to open firmware */
+EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
+#endif
+
 /*
  * Fill a struct uart_port for a given device node
  */
@@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
                | UPF_FIXED_PORT | UPF_FIXED_TYPE;
        port->dev = &ofdev->dev;
 
+       if (type == PORT_TEGRA)
+               port->handle_break = tegra_serial_handle_break;
+
        return 0;
 }
 
diff --git a/include/linux/of_serial.h b/include/linux/of_serial.h
new file mode 100644 (file)
index 0000000..4a73ed8
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __LINUX_OF_SERIAL_H
+#define __LINUX_OF_SERIAL_H
+
+/*
+ * FIXME remove this file when tegra finishes conversion to open firmware,
+ * expectation is that all quirks will then be self-contained in
+ * drivers/tty/serial/of_serial.c.
+ */
+#ifdef CONFIG_ARCH_TEGRA
+extern void tegra_serial_handle_break(struct uart_port *port);
+#else
+static inline void tegra_serial_handle_break(struct uart_port *port)
+{
+}
+#endif
+
+#endif /* __LINUX_OF_SERIAL */
index 8f012f8..a522fd9 100644 (file)
@@ -38,6 +38,7 @@ struct plat_serial8250_port {
        int             (*handle_irq)(struct uart_port *);
        void            (*pm)(struct uart_port *, unsigned int state,
                              unsigned old);
+       void            (*handle_break)(struct uart_port *);
 };
 
 /*
index f51bf2e..0dd752f 100644 (file)
@@ -310,6 +310,7 @@ struct uart_port {
        int                     (*handle_irq)(struct uart_port *);
        void                    (*pm)(struct uart_port *, unsigned int state,
                                      unsigned int old);
+       void                    (*handle_break)(struct uart_port *);
        unsigned int            irq;                    /* irq number */
        unsigned long           irqflags;               /* irq flags  */
        unsigned int            uartclk;                /* base uart clock */
@@ -533,6 +534,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
 static inline int uart_handle_break(struct uart_port *port)
 {
        struct uart_state *state = port->state;
+
+       if (port->handle_break)
+               port->handle_break(port);
+
 #ifdef SUPPORT_SYSRQ
        if (port->cons && port->cons->index == port->line) {
                if (!port->sysrq) {