]> Pileus Git - ~andy/linux/blobdiff - drivers/serial/mpc52xx_uart.c
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
[~andy/linux] / drivers / serial / mpc52xx_uart.c
index 02469c31bf0b6939f37e96e03ac7e1af98a45a14..1a88b363005c1ceb81cd589b9f0ee8bd4eeb41f5 100644 (file)
@@ -113,7 +113,9 @@ struct psc_ops {
        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);
+       unsigned int    (*set_baudrate)(struct uart_port *port,
+                                       struct ktermios *new,
+                                       struct ktermios *old);
        int             (*clock)(struct uart_port *port, int enable);
        int             (*fifoc_init)(void);
        void            (*fifoc_uninit)(void);
@@ -121,6 +123,16 @@ struct psc_ops {
        irqreturn_t     (*handle_irq)(struct uart_port *port);
 };
 
+/* setting the prescaler and divisor reg is common for all chips */
+static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
+                                      u16 prescaler, unsigned int divisor)
+{
+       /* select prescaler */
+       out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
+       out_8(&psc->ctur, divisor >> 8);
+       out_8(&psc->ctlr, divisor & 0xff);
+}
+
 #ifdef CONFIG_PPC_MPC52xx
 #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
 static void mpc52xx_psc_fifo_init(struct uart_port *port)
@@ -128,9 +140,6 @@ 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);
@@ -219,15 +228,47 @@ 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)
+static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
+                                            struct ktermios *new,
+                                            struct ktermios *old)
 {
-       /*
-        * 5200 UARTs have a / 32 prescaler
-        * but the generic serial code assumes 16
-        * so return ipb freq / 2
-        */
-       return mpc5xxx_get_bus_frequency(p) / 2;
+       unsigned int baud;
+       unsigned int divisor;
+
+       /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (32 * 0xffff) + 1,
+                                 port->uartclk / 32);
+       divisor = (port->uartclk + 16 * baud) / (32 * baud);
+
+       /* enable the /32 prescaler and set the divisor */
+       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+       return baud;
+}
+
+static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
+                                             struct ktermios *new,
+                                             struct ktermios *old)
+{
+       unsigned int baud;
+       unsigned int divisor;
+       u16 prescaler;
+
+       /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
+        * ipb freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (32 * 0xffff) + 1,
+                                 port->uartclk / 4);
+       divisor = (port->uartclk + 2 * baud) / (4 * baud);
+
+       /* select the proper prescaler and set the divisor */
+       if (divisor > 0xffff) {
+               divisor = (divisor + 4) / 8;
+               prescaler = 0xdd00; /* /32 */
+       } else
+               prescaler = 0xff00; /* /4 */
+       mpc52xx_set_divisor(PSC(port), prescaler, divisor);
+       return baud;
 }
 
 static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
@@ -258,7 +299,28 @@ static struct psc_ops mpc52xx_psc_ops = {
        .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,
+       .set_baudrate = mpc5200_psc_set_baudrate,
+       .get_irq = mpc52xx_psc_get_irq,
+       .handle_irq = mpc52xx_psc_handle_irq,
+};
+
+static struct psc_ops mpc5200b_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,
+       .set_baudrate = mpc5200b_psc_set_baudrate,
        .get_irq = mpc52xx_psc_get_irq,
        .handle_irq = mpc52xx_psc_handle_irq,
 };
@@ -392,39 +454,41 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
        out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
 }
 
-static unsigned long mpc512x_getuartclk(void *p)
-{
-       return mpc5xxx_get_bus_frequency(p);
-}
-
-#define DEFAULT_FIFO_SIZE 16
-
-static unsigned int __init get_fifo_size(struct device_node *np,
-                                        char *fifo_name)
+static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
+                                            struct ktermios *new,
+                                            struct ktermios *old)
 {
-       const unsigned int *fp;
+       unsigned int baud;
+       unsigned int divisor;
 
-       fp = of_get_property(np, fifo_name, NULL);
-       if (fp)
-               return *fp;
+       /*
+        * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
+        * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
+        * Furthermore, it states that "After reset, the prescaler by 10
+        * for the UART mode is selected", but the reset register value is
+        * 0x0000 which means a /32 prescaler. This is wrong.
+        *
+        * In reality using /32 prescaler doesn't work, as it is not supported!
+        * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
+        * Chapter 4.1 PSC in UART Mode.
+        * Calculate with a /16 prescaler here.
+        */
 
-       pr_warning("no %s property in %s node, defaulting to %d\n",
-                  fifo_name, np->full_name, DEFAULT_FIFO_SIZE);
+       /* uartclk contains the ips freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (16 * 0xffff) + 1,
+                                 port->uartclk / 16);
+       divisor = (port->uartclk + 8 * baud) / (16 * baud);
 
-       return DEFAULT_FIFO_SIZE;
+       /* enable the /16 prescaler and set the divisor */
+       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+       return baud;
 }
 
-#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
-                   ((u32)(_base) + sizeof(struct mpc52xx_psc)))
-
 /* Init PSC FIFO Controller */
 static int __init mpc512x_psc_fifoc_init(void)
 {
        struct device_node *np;
-       void __iomem *psc;
-       unsigned int tx_fifo_size;
-       unsigned int rx_fifo_size;
-       int fifobase = 0; /* current fifo address in 32 bit words */
 
        np = of_find_compatible_node(NULL, NULL,
                                     "fsl,mpc5121-psc-fifo");
@@ -447,51 +511,6 @@ static int __init mpc512x_psc_fifoc_init(void)
                return -ENODEV;
        }
 
-       for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-uart") {
-               tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
-               rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
-
-               /* size in register is in 4 byte units */
-               tx_fifo_size /= 4;
-               rx_fifo_size /= 4;
-               if (!tx_fifo_size)
-                       tx_fifo_size = 1;
-               if (!rx_fifo_size)
-                       rx_fifo_size = 1;
-
-               psc = of_iomap(np, 0);
-               if (!psc) {
-                       pr_err("%s: Can't map %s device\n",
-                               __func__, np->full_name);
-                       continue;
-               }
-
-               /* FIFO space is 4KiB, check if requested size is available */
-               if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
-                       pr_err("%s: no fifo space available for %s\n",
-                               __func__, np->full_name);
-                       iounmap(psc);
-                       /*
-                        * chances are that another device requests less
-                        * fifo space, so we continue.
-                        */
-                       continue;
-               }
-               /* set tx and rx fifo size registers */
-               out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
-               fifobase += tx_fifo_size;
-               out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
-               fifobase += rx_fifo_size;
-
-               /* reset and enable the slices */
-               out_be32(&FIFOC(psc)->txcmd, 0x80);
-               out_be32(&FIFOC(psc)->txcmd, 0x01);
-               out_be32(&FIFOC(psc)->rxcmd, 0x80);
-               out_be32(&FIFOC(psc)->rxcmd, 0x01);
-
-               iounmap(psc);
-       }
-
        return 0;
 }
 
@@ -567,7 +586,7 @@ static struct psc_ops mpc512x_psc_ops = {
        .read_char = mpc512x_psc_read_char,
        .cw_disable_ints = mpc512x_psc_cw_disable_ints,
        .cw_restore_ints = mpc512x_psc_cw_restore_ints,
-       .getuartclk = mpc512x_getuartclk,
+       .set_baudrate = mpc512x_psc_set_baudrate,
        .clock = mpc512x_psc_clock,
        .fifoc_init = mpc512x_psc_fifoc_init,
        .fifoc_uninit = mpc512x_psc_fifoc_uninit,
@@ -735,8 +754,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
        struct mpc52xx_psc __iomem *psc = PSC(port);
        unsigned long flags;
        unsigned char mr1, mr2;
-       unsigned short ctr;
-       unsigned int j, baud, quot;
+       unsigned int j;
+       unsigned int baud;
 
        /* Prepare what we're gonna write */
        mr1 = 0;
@@ -773,16 +792,9 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
                mr2 |= MPC52xx_PSC_MODE_TXCTS;
        }
 
-       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-       ctr = quot & 0xffff;
-
        /* Get the lock */
        spin_lock_irqsave(&port->lock, flags);
 
-       /* Update the per-port timeout */
-       uart_update_timeout(port, new->c_cflag, baud);
-
        /* Do our best to flush TX & RX, so we don't lose anything */
        /* But we don't wait indefinitely ! */
        j = 5000000;    /* Maximum wait */
@@ -806,8 +818,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
        out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
        out_8(&psc->mode, mr1);
        out_8(&psc->mode, mr2);
-       out_8(&psc->ctur, ctr >> 8);
-       out_8(&psc->ctlr, ctr & 0xff);
+       baud = psc_ops->set_baudrate(port, new, old);
+
+       /* Update the per-port timeout */
+       uart_update_timeout(port, new->c_cflag, baud);
 
        if (UART_ENABLE_MS(port, new->c_cflag))
                mpc52xx_uart_enable_ms(port);
@@ -1187,7 +1201,7 @@ mpc52xx_console_setup(struct console *co, char *options)
                return ret;
        }
 
-       uartclk = psc_ops->getuartclk(np);
+       uartclk = mpc5xxx_get_bus_frequency(np);
        if (uartclk == 0) {
                pr_debug("Could not find uart clock frequency!\n");
                return -EINVAL;
@@ -1270,6 +1284,7 @@ static struct uart_driver mpc52xx_uart_driver = {
 
 static struct of_device_id mpc52xx_uart_of_match[] = {
 #ifdef CONFIG_PPC_MPC52xx
+       { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
        { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
        /* binding used by old lite5200 device trees: */
        { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
@@ -1295,14 +1310,17 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
 
        /* Check validity & presence */
        for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
-               if (mpc52xx_uart_nodes[idx] == op->node)
+               if (mpc52xx_uart_nodes[idx] == op->dev.of_node)
                        break;
        if (idx >= MPC52xx_PSC_MAXNUM)
                return -EINVAL;
        pr_debug("Found %s assigned to ttyPSC%x\n",
                 mpc52xx_uart_nodes[idx]->full_name, idx);
 
-       uartclk = psc_ops->getuartclk(op->node);
+       /* set the uart clock to the input clock of the psc, the different
+        * prescalers are taken into account in the set_baudrate() methods
+        * of the respective chip */
+       uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
        if (uartclk == 0) {
                dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
                return -EINVAL;
@@ -1322,7 +1340,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
        port->dev       = &op->dev;
 
        /* Search for IRQ and mapbase */
-       ret = of_address_to_resource(op->node, 0, &res);
+       ret = of_address_to_resource(op->dev.of_node, 0, &res);
        if (ret)
                return ret;
 
@@ -1332,7 +1350,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
                return -EINVAL;
        }
 
-       psc_ops->get_irq(port, op->node);
+       psc_ops->get_irq(port, op->dev.of_node);
        if (port->irq == NO_IRQ) {
                dev_dbg(&op->dev, "Could not get irq\n");
                return -EINVAL;
@@ -1431,15 +1449,16 @@ mpc52xx_uart_of_enumerate(void)
 MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
 
 static struct of_platform_driver mpc52xx_uart_of_driver = {
-       .match_table    = mpc52xx_uart_of_match,
        .probe          = mpc52xx_uart_of_probe,
        .remove         = mpc52xx_uart_of_remove,
 #ifdef CONFIG_PM
        .suspend        = mpc52xx_uart_of_suspend,
        .resume         = mpc52xx_uart_of_resume,
 #endif
-       .driver         = {
-               .name   = "mpc52xx-psc-uart",
+       .driver = {
+               .name = "mpc52xx-psc-uart",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_uart_of_match,
        },
 };