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;
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);
} else if (!(crdma & UARTBAUD_RDMAE) && (sts & UARTSTAT_IDLE)) {
lpuart32_write(UARTSTAT_IDLE, sport->port.membase + UARTSTAT);
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;
crdma = lpuart32_read(sport->port.membase + UARTBAUD);
lpuart32_write(crdma & ~(UARTBAUD_RDMAE | UARTBAUD_RIDMAE),
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);
}
if (!sport->dma_eeop && count < sport->rxfifo_watermark)
- lpuart_dma_stop(sport);
+ lpuart_dma_stop(sport, true);
else
lpuart_dma_rx(sport);
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);
}
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);
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;
}
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);
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);
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);
if (!sport->dma_eeop)
del_timer_sync(&sport->lpuart_timer);
{
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);
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)) {
{
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);
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)) {