summaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2018-03-02 11:07:28 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-03-09 10:21:02 -0800
commit1866541492641c02874bf51f9d8712b5510f2c64 (patch)
treefeb187466672f25f8fcf9213334eec096b2582f3 /drivers/tty/serial
parent81ca8e8286c48df22eb798879d99aabac663b5f1 (diff)
downloadop-kernel-dev-1866541492641c02874bf51f9d8712b5510f2c64.zip
op-kernel-dev-1866541492641c02874bf51f9d8712b5510f2c64.tar.gz
serial: imx: Fix handling of TC irq in combination with DMA
When using RS485 half duplex the Transmitter Complete irq is needed to determine the moment when the transmitter can be disabled. When using DMA this irq must only be enabled when DMA has completed to transfer all data. Otherwise the CPU might busily trigger this irq which is not properly handled and so the also pending irq for the DMA transfer cannot trigger. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/imx.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e1f00d5..80456ea 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -575,6 +575,11 @@ static void dma_tx_callback(void *data)
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
imx_dma_tx(sport);
+ else if (sport->port.rs485.flags & SER_RS485_ENABLED) {
+ u32 ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 |= UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
+ }
spin_unlock_irqrestore(&sport->port.lock, flags);
}
@@ -587,12 +592,16 @@ static void imx_dma_tx(struct imx_port *sport)
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = sport->dma_chan_tx;
struct device *dev = sport->port.dev;
- u32 ucr1;
+ u32 ucr1, ucr4;
int ret;
if (sport->dma_is_txing)
return;
+ ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 &= ~UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
+
sport->tx_bytes = uart_circ_chars_pending(xmit);
if (xmit->tail < xmit->head) {
@@ -643,7 +652,7 @@ static void imx_start_tx(struct uart_port *port)
u32 ucr1;
if (port->rs485.flags & SER_RS485_ENABLED) {
- u32 ucr2, ucr4;
+ u32 ucr2;
ucr2 = imx_uart_readl(sport, UCR2);
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
@@ -655,10 +664,15 @@ static void imx_start_tx(struct uart_port *port)
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
imx_stop_rx(port);
- /* enable transmitter and shifter empty irq */
- ucr4 = imx_uart_readl(sport, UCR4);
- ucr4 |= UCR4_TCEN;
- imx_uart_writel(sport, ucr4, UCR4);
+ /*
+ * Enable transmitter and shifter empty irq only if DMA is off.
+ * In the DMA case this is done in the tx-callback.
+ */
+ if (!sport->dma_is_enabled) {
+ u32 ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 |= UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
+ }
}
if (!sport->dma_is_enabled) {
OpenPOWER on IntegriCloud