diff options
Diffstat (limited to 'drivers/tty/serial/imx.c')
-rw-r--r-- | drivers/tty/serial/imx.c | 103 |
1 files changed, 48 insertions, 55 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index dfeff3951f93..a67a606c38eb 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Driver for Motorola/Freescale IMX serial ports * @@ -5,16 +6,6 @@ * * Author: Sascha Hauer <sascha@saschahauer.de> * Copyright (C) 2004 Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -334,7 +325,8 @@ static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2) { *ucr2 &= ~(UCR2_CTSC | UCR2_CTS); - mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS); + sport->port.mctrl |= TIOCM_RTS; + mctrl_gpio_set(sport->gpios, sport->port.mctrl); } static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2) @@ -342,7 +334,8 @@ static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2) *ucr2 &= ~UCR2_CTSC; *ucr2 |= UCR2_CTS; - mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS); + sport->port.mctrl &= ~TIOCM_RTS; + mctrl_gpio_set(sport->gpios, sport->port.mctrl); } static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2) @@ -714,8 +707,6 @@ static void imx_disable_rx_int(struct imx_port *sport) { unsigned long temp; - sport->dma_is_rxing = 1; - /* disable the receiver ready and aging timer interrupts */ temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_RRDYEN); @@ -732,29 +723,6 @@ static void imx_disable_rx_int(struct imx_port *sport) } static void clear_rx_errors(struct imx_port *sport); -static int start_rx_dma(struct imx_port *sport); -/* - * If the RXFIFO is filled with some data, and then we - * arise a DMA operation to receive them. - */ -static void imx_dma_rxint(struct imx_port *sport) -{ - unsigned long temp; - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); - - temp = readl(sport->port.membase + USR2); - if ((temp & USR2_RDR) && !sport->dma_is_rxing) { - - imx_disable_rx_int(sport); - - /* tell the DMA to receive the data. */ - start_rx_dma(sport); - } - - spin_unlock_irqrestore(&sport->port.lock, flags); -} /* * We have a modem side uart, so the meanings of RTS and CTS are inverted. @@ -816,11 +784,8 @@ static irqreturn_t imx_int(int irq, void *dev_id) sts = readl(sport->port.membase + USR1); sts2 = readl(sport->port.membase + USR2); - if (sts & (USR1_RRDY | USR1_AGTIM)) { - if (sport->dma_is_enabled) - imx_dma_rxint(sport); - else - imx_rxint(irq, dev_id); + if (!sport->dma_is_enabled && (sts & (USR1_RRDY | USR1_AGTIM))) { + imx_rxint(irq, dev_id); ret = IRQ_HANDLED; } @@ -1074,6 +1039,7 @@ static int start_rx_dma(struct imx_port *sport) desc->callback_param = sport; dev_dbg(dev, "RX: prepare for the DMA.\n"); + sport->dma_is_rxing = 1; sport->rx_cookie = dmaengine_submit(desc); dma_async_issue_pending(chan); return 0; @@ -1165,7 +1131,7 @@ static int imx_uart_dma_init(struct imx_port *sport) goto err; } - sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + sport->rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL); if (!sport->rx_buf) { ret = -ENOMEM; goto err; @@ -1207,10 +1173,6 @@ static void imx_enable_dma(struct imx_port *sport) temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN; writel(temp, sport->port.membase + UCR1); - temp = readl(sport->port.membase + UCR2); - temp |= UCR2_ATEN; - writel(temp, sport->port.membase + UCR2); - imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); sport->dma_is_enabled = 1; @@ -1411,15 +1373,19 @@ static void imx_flush_buffer(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp &= ~UCR1_TDMAEN; writel(temp, sport->port.membase + UCR1); - sport->dma_is_txing = false; + sport->dma_is_txing = 0; } /* * According to the Reference Manual description of the UART SRST bit: + * * "Reset the transmit and receive state machines, * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD - * and UTS[6-3]". As we don't need to restore the old values from - * USR1, USR2, URXD, UTXD, only save/restore the other four registers + * and UTS[6-3]". + * + * We don't need to restore the old values from USR1, USR2, URXD and + * UTXD. UBRC is read only, so only save/restore the other three + * registers. */ ubir = readl(sport->port.membase + UBIR); ubmr = readl(sport->port.membase + UBMR); @@ -2051,6 +2017,8 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "rts-gpios", NULL)) sport->have_rtsgpio = 1; + of_get_rs485_mode(np, &sport->port.rs485); + return 0; } #else @@ -2112,12 +2080,9 @@ static int serial_imx_probe(struct platform_device *pdev) sport->port.fifosize = 32; sport->port.ops = &imx_pops; sport->port.rs485_config = imx_rs485_config; - sport->port.rs485.flags = - SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX; + sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND; sport->port.flags = UPF_BOOT_AUTOCONF; - init_timer(&sport->timer); - sport->timer.function = imx_timeout; - sport->timer.data = (unsigned long)sport; + setup_timer(&sport->timer, imx_timeout, (unsigned long)sport); sport->gpios = mctrl_gpio_init(&sport->port, 0); if (IS_ERR(sport->gpios)) @@ -2346,11 +2311,39 @@ static int imx_serial_port_resume(struct device *dev) return 0; } +static int imx_serial_port_freeze(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + + uart_suspend_port(&imx_reg, &sport->port); + + /* Needed to enable clock in suspend_noirq */ + return clk_prepare(sport->clk_ipg); +} + +static int imx_serial_port_thaw(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + + uart_resume_port(&imx_reg, &sport->port); + + clk_unprepare(sport->clk_ipg); + + return 0; +} + static const struct dev_pm_ops imx_serial_port_pm_ops = { .suspend_noirq = imx_serial_port_suspend_noirq, .resume_noirq = imx_serial_port_resume_noirq, + .freeze_noirq = imx_serial_port_suspend_noirq, + .restore_noirq = imx_serial_port_resume_noirq, .suspend = imx_serial_port_suspend, .resume = imx_serial_port_resume, + .freeze = imx_serial_port_freeze, + .thaw = imx_serial_port_thaw, + .restore = imx_serial_port_thaw, }; static struct platform_driver serial_imx_driver = { |