[PATCH] txx9 serial update

Support for the new RBHMA4500 eval board for the TX4938.  General update
from the 8250 ancestor of this driver.  Replace use of deprecated
interfaces.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 49afadb..f10c86d 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -31,6 +31,8 @@
  *	1.01	Set fifosize to make tx_empry called properly.
  *		Use standard uart_get_divisor.
  *	1.02	Cleanup. (import 8250.c changes)
+ *	1.03	Fix low-latency mode. (import 8250.c changes)
+ *	1.04	Remove usage of deprecated functions, cleanup.
  */
 #include <linux/config.h>
 
@@ -54,7 +56,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-static char *serial_version = "1.02";
+static char *serial_version = "1.04";
 static char *serial_name = "TX39/49 Serial driver";
 
 #define PASS_LIMIT	256
@@ -86,9 +88,9 @@
  */
 #ifdef ENABLE_SERIAL_TXX9_PCI
 #define NR_PCI_BOARDS	4
-#define UART_NR  (2 + NR_PCI_BOARDS)
+#define UART_NR  (4 + NR_PCI_BOARDS)
 #else
-#define UART_NR  2
+#define UART_NR  4
 #endif
 
 struct uart_txx9_port {
@@ -304,8 +306,11 @@
 		/* The following is not allowed by the tty layer and
 		   unsafe. It should be fixed ASAP */
 		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
-			if(tty->low_latency)
+			if (tty->low_latency) {
+				spin_unlock(&up->port.lock);
 				tty_flip_buffer_push(tty);
+				spin_lock(&up->port.lock);
+			}
 			/* If this failed then we will throw away the
 			   bytes but must do so to clear interrupts */
 		}
@@ -356,7 +361,9 @@
 	ignore_char:
 		disr = sio_in(up, TXX9_SIDISR);
 	} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
+	spin_unlock(&up->port.lock);
 	tty_flip_buffer_push(tty);
+	spin_lock(&up->port.lock);
 	*status = disr;
 }
 
@@ -667,17 +674,8 @@
 	      unsigned int oldstate)
 {
 	struct uart_txx9_port *up = (struct uart_txx9_port *)port;
-	if (state) {
-		/* sleep */
-
-		if (up->pm)
-			up->pm(port, state, oldstate);
-	} else {
-		/* wake */
-
-		if (up->pm)
-			up->pm(port, state, oldstate);
-	}
+	if (up->pm)
+		up->pm(port, state, oldstate);
 }
 
 static int serial_txx9_request_resource(struct uart_txx9_port *up)
@@ -979,14 +977,6 @@
 }
 console_initcall(serial_txx9_console_init);
 
-static int __init serial_txx9_late_console_init(void)
-{
-	if (!(serial_txx9_console.flags & CON_ENABLED))
-		register_console(&serial_txx9_console);
-	return 0;
-}
-late_initcall(serial_txx9_late_console_init);
-
 #define SERIAL_TXX9_CONSOLE	&serial_txx9_console
 #else
 #define SERIAL_TXX9_CONSOLE	NULL
@@ -1039,6 +1029,73 @@
 	uart_resume_port(&serial_txx9_reg, &serial_txx9_ports[line].port);
 }
 
+static DECLARE_MUTEX(serial_txx9_sem);
+
+/**
+ *	serial_txx9_register_port - register a serial port
+ *	@port: serial port template
+ *
+ *	Configure the serial port specified by the request.
+ *
+ *	The port is then probed and if necessary the IRQ is autodetected
+ *	If this fails an error is returned.
+ *
+ *	On success the port is ready to use and the line number is returned.
+ */
+static int __devinit serial_txx9_register_port(struct uart_port *port)
+{
+	int i;
+	struct uart_txx9_port *uart;
+	int ret = -ENOSPC;
+
+	down(&serial_txx9_sem);
+	for (i = 0; i < UART_NR; i++) {
+		uart = &serial_txx9_ports[i];
+		if (uart->port.type == PORT_UNKNOWN)
+			break;
+	}
+	if (i < UART_NR) {
+		uart_remove_one_port(&serial_txx9_reg, &uart->port);
+		uart->port.iobase = port->iobase;
+		uart->port.membase = port->membase;
+		uart->port.irq      = port->irq;
+		uart->port.uartclk  = port->uartclk;
+		uart->port.iotype   = port->iotype;
+		uart->port.flags    = port->flags | UPF_BOOT_AUTOCONF;
+		uart->port.mapbase  = port->mapbase;
+		if (port->dev)
+			uart->port.dev = port->dev;
+		ret = uart_add_one_port(&serial_txx9_reg, &uart->port);
+		if (ret == 0)
+			ret = uart->port.line;
+	}
+	up(&serial_txx9_sem);
+	return ret;
+}
+
+/**
+ *	serial_txx9_unregister_port - remove a txx9 serial port at runtime
+ *	@line: serial line number
+ *
+ *	Remove one serial port.  This may not be called from interrupt
+ *	context.  We hand the port back to the our control.
+ */
+static void __devexit serial_txx9_unregister_port(int line)
+{
+	struct uart_txx9_port *uart = &serial_txx9_ports[line];
+
+	down(&serial_txx9_sem);
+	uart_remove_one_port(&serial_txx9_reg, &uart->port);
+	uart->port.flags = 0;
+	uart->port.type = PORT_UNKNOWN;
+	uart->port.iobase = 0;
+	uart->port.mapbase = 0;
+	uart->port.membase = 0;
+	uart->port.dev = NULL;
+	uart_add_one_port(&serial_txx9_reg, &uart->port);
+	up(&serial_txx9_sem);
+}
+
 /*
  * Probe one serial board.  Unfortunately, there is no rhyme nor reason
  * to the arrangement of serial ports on a PCI card.
@@ -1056,13 +1113,13 @@
 
 	memset(&port, 0, sizeof(port));
 	port.ops = &serial_txx9_pops;
-	port.flags |= UPF_BOOT_AUTOCONF; /* uart_ops.config_port will be called */
 	port.flags |= UPF_TXX9_HAVE_CTS_LINE;
 	port.uartclk = 66670000;
 	port.irq = dev->irq;
 	port.iotype = UPIO_PORT;
 	port.iobase = pci_resource_start(dev, 1);
-	line = uart_register_port(&serial_txx9_reg, &port);
+	port.dev = &dev->dev;
+	line = serial_txx9_register_port(&port);
 	if (line < 0) {
 		printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line);
 	}
@@ -1078,7 +1135,7 @@
 	pci_set_drvdata(dev, NULL);
 
 	if (line) {
-		uart_unregister_port(&serial_txx9_reg, line);
+		serial_txx9_unregister_port(line);
 		pci_disable_device(dev);
 	}
 }
@@ -1089,6 +1146,8 @@
 
 	if (line)
 		serial_txx9_suspend_port(line);
+	pci_save_state(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
 	return 0;
 }
 
@@ -1096,8 +1155,13 @@
 {
 	int line = (int)(long)pci_get_drvdata(dev);
 
-	if (line)
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+
+	if (line) {
+		pci_enable_device(dev);
 		serial_txx9_resume_port(line);
+	}
 	return 0;
 }