]> Pileus Git - ~andy/linux/blobdiff - drivers/tty/serial/amba-pl011.c
Merge tag 'stable/for-linus-3.14-rc0-tag' of git://git.kernel.org/pub/scm/linux/kerne...
[~andy/linux] / drivers / tty / serial / amba-pl011.c
index 7203864992a523509ee0f0f42f47c36714a886aa..d58783d364e3a9443a7c2723e635467e54b014cd 100644 (file)
@@ -112,8 +112,6 @@ static struct vendor_data vendor_st = {
        .get_fifosize           = get_fifosize_st,
 };
 
-static struct uart_amba_port *amba_ports[UART_NR];
-
 /* Deals with DMA transactions */
 
 struct pl011_sgbuf {
@@ -969,6 +967,8 @@ static void pl011_dma_rx_poll(unsigned long args)
 
                spin_lock_irqsave(&uap->port.lock, flags);
                pl011_dma_rx_stop(uap);
+               uap->im |= UART011_RXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
                spin_unlock_irqrestore(&uap->port.lock, flags);
 
                uap->dmarx.running = false;
@@ -1216,8 +1216,8 @@ __acquires(&uap->port.lock)
                        dev_dbg(uap->port.dev, "could not trigger RX DMA job "
                                "fall back to interrupt mode again\n");
                        uap->im |= UART011_RXIM;
+                       writew(uap->im, uap->port.membase + UART011_IMSC);
                } else {
-                       uap->im &= ~UART011_RXIM;
 #ifdef CONFIG_DMA_ENGINE
                        /* Start Rx DMA poll */
                        if (uap->dmarx.poll_rate) {
@@ -1229,8 +1229,6 @@ __acquires(&uap->port.lock)
                        }
 #endif
                }
-
-               writew(uap->im, uap->port.membase + UART011_IMSC);
        }
        spin_lock(&uap->port.lock);
 }
@@ -1513,10 +1511,25 @@ static int pl011_hwinit(struct uart_port *port)
        return retval;
 }
 
+static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
+{
+       writew(lcr_h, uap->port.membase + uap->lcrh_rx);
+       if (uap->lcrh_rx != uap->lcrh_tx) {
+               int i;
+               /*
+                * Wait 10 PCLKs before writing LCRH_TX register,
+                * to get this delay write read only register 10 times
+                */
+               for (i = 0; i < 10; ++i)
+                       writew(0xff, uap->port.membase + UART011_MIS);
+               writew(lcr_h, uap->port.membase + uap->lcrh_tx);
+       }
+}
+
 static int pl011_startup(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
+       unsigned int cr, lcr_h, fbrd, ibrd;
        int retval;
 
        retval = pl011_hwinit(port);
@@ -1535,32 +1548,36 @@ static int pl011_startup(struct uart_port *port)
        writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
 
        /*
-        * Provoke TX FIFO interrupt into asserting.
+        * Provoke TX FIFO interrupt into asserting. Taking care to preserve
+        * baud rate and data format specified by FBRD, IBRD and LCRH as the
+        * UART may already be in use as a console.
         */
+       spin_lock_irq(&uap->port.lock);
+
+       fbrd = readw(uap->port.membase + UART011_FBRD);
+       ibrd = readw(uap->port.membase + UART011_IBRD);
+       lcr_h = readw(uap->port.membase + uap->lcrh_rx);
+
        cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
        writew(cr, uap->port.membase + UART011_CR);
        writew(0, uap->port.membase + UART011_FBRD);
        writew(1, uap->port.membase + UART011_IBRD);
-       writew(0, uap->port.membase + uap->lcrh_rx);
-       if (uap->lcrh_tx != uap->lcrh_rx) {
-               int i;
-               /*
-                * Wait 10 PCLKs before writing LCRH_TX register,
-                * to get this delay write read only register 10 times
-                */
-               for (i = 0; i < 10; ++i)
-                       writew(0xff, uap->port.membase + UART011_MIS);
-               writew(0, uap->port.membase + uap->lcrh_tx);
-       }
+       pl011_write_lcr_h(uap, 0);
        writew(0, uap->port.membase + UART01x_DR);
        while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
                barrier();
 
+       writew(fbrd, uap->port.membase + UART011_FBRD);
+       writew(ibrd, uap->port.membase + UART011_IBRD);
+       pl011_write_lcr_h(uap, lcr_h);
+
        /* restore RTS and DTR */
        cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
        cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
        writew(cr, uap->port.membase + UART011_CR);
 
+       spin_unlock_irq(&uap->port.lock);
+
        /*
         * initialise the old status of the modem signals
         */
@@ -1629,11 +1646,13 @@ static void pl011_shutdown(struct uart_port *port)
         * it during startup().
         */
        uap->autorts = false;
+       spin_lock_irq(&uap->port.lock);
        cr = readw(uap->port.membase + UART011_CR);
        uap->old_cr = cr;
        cr &= UART011_CR_RTS | UART011_CR_DTR;
        cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
        writew(cr, uap->port.membase + UART011_CR);
+       spin_unlock_irq(&uap->port.lock);
 
        /*
         * disable break condition and fifos
@@ -1797,17 +1816,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
         * UART011_FBRD & UART011_IBRD.
         * ----------^----------^----------^----------^-----
         */
-       writew(lcr_h, port->membase + uap->lcrh_rx);
-       if (uap->lcrh_rx != uap->lcrh_tx) {
-               int i;
-               /*
-                * Wait 10 PCLKs before writing LCRH_TX register,
-                * to get this delay write read only register 10 times
-                */
-               for (i = 0; i < 10; ++i)
-                       writew(0xff, uap->port.membase + UART011_MIS);
-               writew(lcr_h, port->membase + uap->lcrh_tx);
-       }
+       pl011_write_lcr_h(uap, lcr_h);
        writew(old_cr, port->membase + UART011_CR);
 
        spin_unlock_irqrestore(&port->lock, flags);
@@ -2169,10 +2178,10 @@ static int pl011_remove(struct amba_device *dev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int pl011_suspend(struct amba_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int pl011_suspend(struct device *dev)
 {
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       struct uart_amba_port *uap = dev_get_drvdata(dev);
 
        if (!uap)
                return -EINVAL;
@@ -2180,9 +2189,9 @@ static int pl011_suspend(struct amba_device *dev, pm_message_t state)
        return uart_suspend_port(&amba_reg, &uap->port);
 }
 
-static int pl011_resume(struct amba_device *dev)
+static int pl011_resume(struct device *dev)
 {
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       struct uart_amba_port *uap = dev_get_drvdata(dev);
 
        if (!uap)
                return -EINVAL;
@@ -2191,6 +2200,8 @@ static int pl011_resume(struct amba_device *dev)
 }
 #endif
 
+static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
+
 static struct amba_id pl011_ids[] = {
        {
                .id     = 0x00041011,
@@ -2210,14 +2221,11 @@ MODULE_DEVICE_TABLE(amba, pl011_ids);
 static struct amba_driver pl011_driver = {
        .drv = {
                .name   = "uart-pl011",
+               .pm     = &pl011_dev_pm_ops,
        },
        .id_table       = pl011_ids,
        .probe          = pl011_probe,
        .remove         = pl011_remove,
-#ifdef CONFIG_PM
-       .suspend        = pl011_suspend,
-       .resume         = pl011_resume,
-#endif
 };
 
 static int __init pl011_init(void)