diff options
Diffstat (limited to 'drivers/tty/serial/xilinx_uartps.c')
-rw-r--r-- | drivers/tty/serial/xilinx_uartps.c | 62 |
1 files changed, 55 insertions, 7 deletions
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 9e01fe6c0ab8..2eff7cff57c4 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -2,7 +2,7 @@ /* * Cadence UART driver (found in Xilinx Zynq) * - * 2011 - 2014 (C) Xilinx Inc. + * Copyright (c) 2011 - 2014 Xilinx, Inc. * * This driver has originally been pushed by Xilinx using a Zynq-branding. This * still shows in the naming of this file, the kconfig symbols and some symbols @@ -361,6 +361,8 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) isrstatus &= ~CDNS_UART_IXR_TXEMPTY; } + isrstatus &= port->read_status_mask; + isrstatus &= ~port->ignore_status_mask; /* * Skip RX processing if RX is disabled as RXEMPTY will never be set * as read bytes will not be removed from the FIFO. @@ -675,7 +677,8 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) * @old: Values of the previously saved termios structure */ static void cdns_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { u32 cval = 0; unsigned int baud, minbaud, maxbaud; @@ -1130,8 +1133,35 @@ static struct uart_driver cdns_uart_uart_driver; */ static void cdns_uart_console_putchar(struct uart_port *port, unsigned char ch) { - while (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) + unsigned int ctrl_reg; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(1000); + while (1) { + ctrl_reg = readl(port->membase + CDNS_UART_CR); + if (!(ctrl_reg & CDNS_UART_CR_TX_DIS)) + break; + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, + "timeout waiting for Enable\n"); + return; + } + cpu_relax(); + } + + timeout = jiffies + msecs_to_jiffies(1000); + while (1) { + ctrl_reg = readl(port->membase + CDNS_UART_SR); + + if (!(ctrl_reg & CDNS_UART_SR_TXFULL)) + break; + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, + "timeout waiting for TX fifo\n"); + return; + } cpu_relax(); + } writel(ch, port->membase + CDNS_UART_FIFO); } @@ -1329,12 +1359,20 @@ static int cdns_uart_resume(struct device *device) unsigned long flags; u32 ctrl_reg; int may_wake; + int ret; may_wake = device_may_wakeup(device); if (console_suspend_enabled && uart_console(port) && !may_wake) { - clk_enable(cdns_uart->pclk); - clk_enable(cdns_uart->uartclk); + ret = clk_enable(cdns_uart->pclk); + if (ret) + return ret; + + ret = clk_enable(cdns_uart->uartclk); + if (ret) { + clk_disable(cdns_uart->pclk); + return ret; + } spin_lock_irqsave(&port->lock, flags); @@ -1383,9 +1421,17 @@ static int __maybe_unused cdns_runtime_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); struct cdns_uart *cdns_uart = port->private_data; + int ret; - clk_enable(cdns_uart->pclk); - clk_enable(cdns_uart->uartclk); + ret = clk_enable(cdns_uart->pclk); + if (ret) + return ret; + + ret = clk_enable(cdns_uart->uartclk); + if (ret) { + clk_disable(cdns_uart->pclk); + return ret; + } return 0; }; @@ -1551,6 +1597,8 @@ static int cdns_uart_probe(struct platform_device *pdev) port->dev = &pdev->dev; port->uartclk = clk_get_rate(cdns_uart_data->uartclk); port->private_data = cdns_uart_data; + port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | + CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; cdns_uart_data->port = port; platform_set_drvdata(pdev, port); |