summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorFugang Duan <fugang.duan@nxp.com>2017-07-26 12:51:51 +0800
committerFugang Duan <fugang.duan@nxp.com>2017-07-26 14:50:42 +0800
commit8caf1f5a3efaf0f76f470c338e7727a558ac01bc (patch)
treead4724d6fd4bc0616aeedd365edf66cde3d37b5b /drivers
parent4334e587722ac8a6c9c49f72d307f514db5e2f81 (diff)
MLK-16086 tty: serial: lpuart: add port.lock to protect registers accessing in suspend
Add port.lock to protect register accessing in suspend/resume function. Disable RIE and ILIE before DMA chan is ternminated in suspend function. Signed-off-by: Fugang Duan <fugang.duan@nxp.com> (cherry picked from commit: 51f874a9205cbcbbdb55642f5502bf18aaf245bd)
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/serial/fsl_lpuart.c34
1 files changed, 23 insertions, 11 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index b1357ac800a8..247286c91c66 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -254,6 +254,7 @@ struct lpuart_port {
bool lpuart_dma_tx_use;
bool lpuart_dma_rx_use;
+ bool dma_rx_chan_active;
struct dma_chan *dma_tx_chan;
struct dma_chan *dma_rx_chan;
struct dma_async_tx_descriptor *dma_tx_desc;
@@ -776,7 +777,7 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
if (!sport->lpuart_dma_rx_use ||
(sts & (UARTSTAT_PE | UARTSTAT_NF | UARTSTAT_FE)))
lpuart32_rxint(irq, dev_id);
- else
+ else if (sport->lpuart_dma_rx_use && sport->dma_rx_chan_active)
lpuart_prepare_rx(sport);
}
@@ -809,7 +810,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
sport->port.icount.rx += copied;
}
-static void lpuart_dma_stop(struct lpuart_port *sport)
+static void lpuart_dma_stop(struct lpuart_port *sport, bool enable_pio)
{
unsigned int temp;
unsigned int crdma;
@@ -819,9 +820,11 @@ static void lpuart_dma_stop(struct lpuart_port *sport)
crdma = lpuart32_read(sport->port.membase + UARTBAUD);
lpuart32_write(crdma & ~(UARTBAUD_RDMAE),
sport->port.membase + UARTBAUD);
- temp = lpuart32_read(sport->port.membase + UARTCTRL);
- temp |= (UARTCTRL_RIE | UARTCTRL_ILIE);
- lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ if (enable_pio) {
+ temp = lpuart32_read(sport->port.membase + UARTCTRL);
+ temp |= (UARTCTRL_RIE | UARTCTRL_ILIE);
+ lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ }
} else {
temp = readb(sport->port.membase + UARTCR5);
writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
@@ -847,7 +850,7 @@ static void lpuart_dma_rx_complete(void *arg)
tty_flip_buffer_push(port);
if (count < sport->rxfifo_watermark)
- lpuart_dma_stop(sport);
+ lpuart_dma_stop(sport, true);
else
lpuart_dma_rx(sport);
@@ -874,7 +877,7 @@ static void lpuart_timer_func(unsigned long data)
sport->dma_rx_in_progress = false;
lpuart_copy_rx_to_tty(sport, port, count);
tty_flip_buffer_push(port);
- lpuart_dma_stop(sport);
+ lpuart_dma_stop(sport, true);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
@@ -906,6 +909,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
+ sport->dma_rx_chan_active = false;
dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
sport->rxdma_len, DMA_FROM_DEVICE);
@@ -1188,6 +1192,7 @@ static int lpuart_dma_rx_request(struct uart_port *port)
sport->dma_rx_buf_virt = dma_buf;
sport->dma_rx_buf_bus = dma_bus;
sport->dma_rx_in_progress = false;
+ sport->dma_rx_chan_active = true;
return 0;
}
@@ -2302,6 +2307,7 @@ static int lpuart_suspend(struct device *dev)
struct lpuart_port *sport = dev_get_drvdata(dev);
struct tty_port *port = &sport->port.state->port;
unsigned long temp;
+ unsigned long flags;
int ret;
ret = clk_prepare_enable(sport->ipg_clk);
@@ -2311,12 +2317,10 @@ static int lpuart_suspend(struct device *dev)
uart_suspend_port(&lpuart_reg, &sport->port);
if (sport->lpuart32) {
- /* disable Rx/Tx and interrupts */
temp = lpuart32_read(sport->port.membase + UARTCTRL);
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
lpuart32_write(temp, sport->port.membase + UARTCTRL);
} else {
- /* disable Rx/Tx and interrupts */
temp = readb(sport->port.membase + UARTCR2);
temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
writeb(temp, sport->port.membase + UARTCR2);
@@ -2324,8 +2328,10 @@ static int lpuart_suspend(struct device *dev)
if (sport->lpuart_dma_rx_use && sport->port.irq_wake &&
tty_port_initialized(port)) {
- /* it needs uart interrupt as wakeup source in low power mode */
- lpuart_dma_stop(sport);
+ spin_lock_irqsave(&sport->port.lock, flags);
+ lpuart_dma_stop(sport, false);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
dmaengine_terminate_all(sport->dma_rx_chan);
del_timer_sync(&sport->lpuart_timer);
lpuart_dma_rx_free(&sport->port);
@@ -2353,7 +2359,9 @@ static inline void lpuart32_resume_init(struct lpuart_port *sport)
{
struct tty_port *port = &sport->port.state->port;
unsigned long temp;
+ unsigned long flags;
+ spin_lock_irqsave(&sport->port.lock, flags);
lpuart32_setup_watermark(sport);
temp = lpuart32_read(sport->port.membase + UARTCTRL);
@@ -2367,6 +2375,7 @@ static inline void lpuart32_resume_init(struct lpuart_port *sport)
temp &= ~(UARTCTRL_TIE | UARTCTRL_TE);
lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
if (sport->lpuart_dma_rx_use && sport->port.irq_wake &&
tty_port_initialized(port)) {
@@ -2405,7 +2414,9 @@ static inline void lpuart_resume_init(struct lpuart_port *sport)
{
struct tty_port *port = &sport->port.state->port;
unsigned char temp;
+ unsigned long flags;
+ spin_lock_irqsave(&sport->port.lock, flags);
lpuart_setup_watermark(sport);
temp = readb(sport->port.membase + UARTCR2);
temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
@@ -2417,6 +2428,7 @@ static inline void lpuart_resume_init(struct lpuart_port *sport)
temp &= ~(UARTCR2_TIE | UARTCR2_TE);
writeb(temp, sport->port.membase + UARTCR2);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
if (sport->lpuart_dma_rx_use && sport->port.irq_wake &&
tty_port_initialized(port)) {