[POWERPC] mpc512x: Factor out 5200 dependencies from 52xx psc driver

PSC devices are different between the mpc5200 and the mpc5121
this patch localizes the differences in preparation for adding mpc5121
support to the psc uart driver.

Signed-off-by: John Rigby <jrigby@freescale.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 3c4d29e..7ab73fa 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -67,7 +67,6 @@
 #include <linux/serial.h>
 #include <linux/sysrq.h>
 #include <linux/console.h>
-
 #include <linux/delay.h>
 #include <linux/io.h>
 
@@ -111,8 +110,8 @@
 static void mpc52xx_uart_of_enumerate(void);
 #endif
 
+
 #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
-#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
 
 
 /* Forward declaration of the interruption handling routine */
@@ -137,6 +136,162 @@
 };
 #endif
 
+/* ======================================================================== */
+/* PSC fifo operations for isolating differences between 52xx and 512x      */
+/* ======================================================================== */
+
+struct psc_ops {
+	void		(*fifo_init)(struct uart_port *port);
+	int		(*raw_rx_rdy)(struct uart_port *port);
+	int		(*raw_tx_rdy)(struct uart_port *port);
+	int		(*rx_rdy)(struct uart_port *port);
+	int		(*tx_rdy)(struct uart_port *port);
+	int		(*tx_empty)(struct uart_port *port);
+	void		(*stop_rx)(struct uart_port *port);
+	void		(*start_tx)(struct uart_port *port);
+	void		(*stop_tx)(struct uart_port *port);
+	void		(*rx_clr_irq)(struct uart_port *port);
+	void		(*tx_clr_irq)(struct uart_port *port);
+	void		(*write_char)(struct uart_port *port, unsigned char c);
+	unsigned char	(*read_char)(struct uart_port *port);
+	void		(*cw_disable_ints)(struct uart_port *port);
+	void		(*cw_restore_ints)(struct uart_port *port);
+	unsigned long	(*getuartclk)(void *p);
+};
+
+#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
+static void mpc52xx_psc_fifo_init(struct uart_port *port)
+{
+	struct mpc52xx_psc __iomem *psc = PSC(port);
+	struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
+
+	/* /32 prescaler */
+	out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
+
+	out_8(&fifo->rfcntl, 0x00);
+	out_be16(&fifo->rfalarm, 0x1ff);
+	out_8(&fifo->tfcntl, 0x07);
+	out_be16(&fifo->tfalarm, 0x80);
+
+	port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
+	out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
+{
+	return in_be16(&PSC(port)->mpc52xx_psc_status)
+	    & MPC52xx_PSC_SR_RXRDY;
+}
+
+static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
+{
+	return in_be16(&PSC(port)->mpc52xx_psc_status)
+	    & MPC52xx_PSC_SR_TXRDY;
+}
+
+
+static int mpc52xx_psc_rx_rdy(struct uart_port *port)
+{
+	return in_be16(&PSC(port)->mpc52xx_psc_isr)
+	    & port->read_status_mask
+	    & MPC52xx_PSC_IMR_RXRDY;
+}
+
+static int mpc52xx_psc_tx_rdy(struct uart_port *port)
+{
+	return in_be16(&PSC(port)->mpc52xx_psc_isr)
+	    & port->read_status_mask
+	    & MPC52xx_PSC_IMR_TXRDY;
+}
+
+static int mpc52xx_psc_tx_empty(struct uart_port *port)
+{
+	return in_be16(&PSC(port)->mpc52xx_psc_status)
+	    & MPC52xx_PSC_SR_TXEMP;
+}
+
+static void mpc52xx_psc_start_tx(struct uart_port *port)
+{
+	port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
+	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_stop_tx(struct uart_port *port)
+{
+	port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
+	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_stop_rx(struct uart_port *port)
+{
+	port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
+	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_rx_clr_irq(struct uart_port *port)
+{
+}
+
+static void mpc52xx_psc_tx_clr_irq(struct uart_port *port)
+{
+}
+
+static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c)
+{
+	out_8(&PSC(port)->mpc52xx_psc_buffer_8, c);
+}
+
+static unsigned char mpc52xx_psc_read_char(struct uart_port *port)
+{
+	return in_8(&PSC(port)->mpc52xx_psc_buffer_8);
+}
+
+static void mpc52xx_psc_cw_disable_ints(struct uart_port *port)
+{
+	out_be16(&PSC(port)->mpc52xx_psc_imr, 0);
+}
+
+static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
+{
+	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+/* Search for bus-frequency property in this node or a parent */
+static unsigned long mpc52xx_getuartclk(void *p)
+{
+#if defined(CONFIG_PPC_MERGE)
+	/*
+	 * 5200 UARTs have a / 32 prescaler
+	 * but the generic serial code assumes 16
+	 * so return ipb freq / 2
+	 */
+	return mpc52xx_find_ipb_freq(p) / 2;
+#else
+	pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n");
+	return NULL;
+#endif
+}
+
+static struct psc_ops mpc52xx_psc_ops = {
+	.fifo_init = mpc52xx_psc_fifo_init,
+	.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
+	.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
+	.rx_rdy = mpc52xx_psc_rx_rdy,
+	.tx_rdy = mpc52xx_psc_tx_rdy,
+	.tx_empty = mpc52xx_psc_tx_empty,
+	.stop_rx = mpc52xx_psc_stop_rx,
+	.start_tx = mpc52xx_psc_start_tx,
+	.stop_tx = mpc52xx_psc_stop_tx,
+	.rx_clr_irq = mpc52xx_psc_rx_clr_irq,
+	.tx_clr_irq = mpc52xx_psc_tx_clr_irq,
+	.write_char = mpc52xx_psc_write_char,
+	.read_char = mpc52xx_psc_read_char,
+	.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
+	.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
+	.getuartclk = mpc52xx_getuartclk,
+};
+
+static struct psc_ops *psc_ops = &mpc52xx_psc_ops;
 
 /* ======================================================================== */
 /* UART operations                                                          */
@@ -145,8 +300,7 @@
 static unsigned int
 mpc52xx_uart_tx_empty(struct uart_port *port)
 {
-	int status = in_be16(&PSC(port)->mpc52xx_psc_status);
-	return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
+	return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
 }
 
 static void
@@ -166,16 +320,14 @@
 mpc52xx_uart_stop_tx(struct uart_port *port)
 {
 	/* port->lock taken by caller */
-	port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
-	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+	psc_ops->stop_tx(port);
 }
 
 static void
 mpc52xx_uart_start_tx(struct uart_port *port)
 {
 	/* port->lock taken by caller */
-	port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
-	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+	psc_ops->start_tx(port);
 }
 
 static void
@@ -188,8 +340,7 @@
 	if (ch) {
 		/* Make sure tx interrupts are on */
 		/* Truly necessary ??? They should be anyway */
-		port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
-		out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+		psc_ops->start_tx(port);
 	}
 
 	spin_unlock_irqrestore(&port->lock, flags);
@@ -199,8 +350,7 @@
 mpc52xx_uart_stop_rx(struct uart_port *port)
 {
 	/* port->lock taken by caller */
-	port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
-	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+	psc_ops->stop_rx(port);
 }
 
 static void
@@ -227,7 +377,6 @@
 mpc52xx_uart_startup(struct uart_port *port)
 {
 	struct mpc52xx_psc __iomem *psc = PSC(port);
-	struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port);
 	int ret;
 
 	/* Request IRQ */
@@ -242,15 +391,7 @@
 
 	out_be32(&psc->sicr, 0);	/* UART mode DCD ignored */
 
-	out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
-
-	out_8(&fifo->rfcntl, 0x00);
-	out_be16(&fifo->rfalarm, 0x1ff);
-	out_8(&fifo->tfcntl, 0x07);
-	out_be16(&fifo->tfalarm, 0x80);
-
-	port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
-	out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+	psc_ops->fifo_init(port);
 
 	out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
 	out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
@@ -333,8 +474,7 @@
 	 * boot for the console, all stuff is not yet ready to receive at that
 	 * time and that just makes the kernel oops */
 	/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
-	while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
-	       --j)
+	while (!mpc52xx_uart_tx_empty(port) && --j)
 		udelay(1);
 
 	if (!j)
@@ -462,11 +602,9 @@
 	unsigned short status;
 
 	/* While we can read, do so ! */
-	while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) &
-		MPC52xx_PSC_SR_RXRDY) {
-
+	while (psc_ops->raw_rx_rdy(port)) {
 		/* Get the char */
-		ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8);
+		ch = psc_ops->read_char(port);
 
 		/* Handle sysreq char */
 #ifdef SUPPORT_SYSRQ
@@ -481,6 +619,8 @@
 		flag = TTY_NORMAL;
 		port->icount.rx++;
 
+		status = in_be16(&PSC(port)->mpc52xx_psc_status);
+
 		if (status & (MPC52xx_PSC_SR_PE |
 			      MPC52xx_PSC_SR_FE |
 			      MPC52xx_PSC_SR_RB)) {
@@ -510,7 +650,7 @@
 
 	tty_flip_buffer_push(tty);
 
-	return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
+	return psc_ops->raw_rx_rdy(port);
 }
 
 static inline int
@@ -520,7 +660,7 @@
 
 	/* Process out of band chars */
 	if (port->x_char) {
-		out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char);
+		psc_ops->write_char(port, port->x_char);
 		port->icount.tx++;
 		port->x_char = 0;
 		return 1;
@@ -533,8 +673,8 @@
 	}
 
 	/* Send chars */
-	while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) {
-		out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]);
+	while (psc_ops->raw_tx_rdy(port)) {
+		psc_ops->write_char(port, xmit->buf[xmit->tail]);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		port->icount.tx++;
 		if (uart_circ_empty(xmit))
@@ -560,7 +700,6 @@
 	struct uart_port *port = dev_id;
 	unsigned long pass = ISR_PASS_LIMIT;
 	unsigned int keepgoing;
-	unsigned short status;
 
 	spin_lock(&port->lock);
 
@@ -569,18 +708,12 @@
 		/* If we don't find anything to do, we stop */
 		keepgoing = 0;
 
-		/* Read status */
-		status = in_be16(&PSC(port)->mpc52xx_psc_isr);
-		status &= port->read_status_mask;
-
-		/* Do we need to receive chars ? */
-		/* For this RX interrupts must be on and some chars waiting */
-		if (status & MPC52xx_PSC_IMR_RXRDY)
+		psc_ops->rx_clr_irq(port);
+		if (psc_ops->rx_rdy(port))
 			keepgoing |= mpc52xx_uart_int_rx_chars(port);
 
-		/* Do we need to send chars ? */
-		/* For this, TX must be ready and TX interrupt enabled */
-		if (status & MPC52xx_PSC_IMR_TXRDY)
+		psc_ops->tx_clr_irq(port);
+		if (psc_ops->tx_rdy(port))
 			keepgoing |= mpc52xx_uart_int_tx_chars(port);
 
 		/* Limit number of iteration */
@@ -647,36 +780,33 @@
 mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
 {
 	struct uart_port *port = &mpc52xx_uart_ports[co->index];
-	struct mpc52xx_psc __iomem *psc = PSC(port);
 	unsigned int i, j;
 
 	/* Disable interrupts */
-	out_be16(&psc->mpc52xx_psc_imr, 0);
+	psc_ops->cw_disable_ints(port);
 
 	/* Wait the TX buffer to be empty */
 	j = 5000000;	/* Maximum wait */
-	while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
-	       --j)
+	while (!mpc52xx_uart_tx_empty(port) && --j)
 		udelay(1);
 
 	/* Write all the chars */
 	for (i = 0; i < count; i++, s++) {
 		/* Line return handling */
 		if (*s == '\n')
-			out_8(&psc->mpc52xx_psc_buffer_8, '\r');
+			psc_ops->write_char(port, '\r');
 
 		/* Send the char */
-		out_8(&psc->mpc52xx_psc_buffer_8, *s);
+		psc_ops->write_char(port, *s);
 
 		/* Wait the TX buffer to be empty */
 		j = 20000;	/* Maximum wait */
-		while (!(in_be16(&psc->mpc52xx_psc_status) &
-			 MPC52xx_PSC_SR_TXEMP) && --j)
+		while (!mpc52xx_uart_tx_empty(port) && --j)
 			udelay(1);
 	}
 
 	/* Restore interrupt state */
-	out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+	psc_ops->cw_restore_ints(port);
 }
 
 #if !defined(CONFIG_PPC_MERGE)
@@ -721,7 +851,7 @@
 {
 	struct uart_port *port = &mpc52xx_uart_ports[co->index];
 	struct device_node *np = mpc52xx_uart_nodes[co->index];
-	unsigned int ipb_freq;
+	unsigned int uartclk;
 	struct resource res;
 	int ret;
 
@@ -753,17 +883,16 @@
 		return ret;
 	}
 
-	/* Search for bus-frequency property in this node or a parent */
-	ipb_freq = mpc52xx_find_ipb_freq(np);
-	if (ipb_freq == 0) {
-		pr_debug("Could not find IPB bus frequency!\n");
+	uartclk = psc_ops->getuartclk(np);
+	if (uartclk == 0) {
+		pr_debug("Could not find uart clock frequency!\n");
 		return -EINVAL;
 	}
 
 	/* Basic port init. Needed since we use some uart_??? func before
 	 * real init for early access */
 	spin_lock_init(&port->lock);
-	port->uartclk	= ipb_freq / 2;
+	port->uartclk = uartclk;
 	port->ops	= &mpc52xx_uart_ops;
 	port->mapbase = res.start;
 	port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
@@ -949,7 +1078,7 @@
 mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
 {
 	int idx = -1;
-	unsigned int ipb_freq;
+	unsigned int uartclk;
 	struct uart_port *port = NULL;
 	struct resource res;
 	int ret;
@@ -965,10 +1094,9 @@
 	pr_debug("Found %s assigned to ttyPSC%x\n",
 		 mpc52xx_uart_nodes[idx]->full_name, idx);
 
-	/* Search for bus-frequency property in this node or a parent */
-	ipb_freq = mpc52xx_find_ipb_freq(op->node);
-	if (ipb_freq == 0) {
-		dev_dbg(&op->dev, "Could not find IPB bus frequency!\n");
+	uartclk = psc_ops->getuartclk(op->node);
+	if (uartclk == 0) {
+		dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
 		return -EINVAL;
 	}
 
@@ -976,7 +1104,7 @@
 	port = &mpc52xx_uart_ports[idx];
 
 	spin_lock_init(&port->lock);
-	port->uartclk	= ipb_freq / 2;
+	port->uartclk = uartclk;
 	port->fifosize	= 512;
 	port->iotype	= UPIO_MEM;
 	port->flags	= UPF_BOOT_AUTOCONF |