diff options
author | Vitaly Chernooky <vitaly.chernooky@ti.com> | 2012-10-31 16:58:27 +0200 |
---|---|---|
committer | Ziyann <jaraidaniel@gmail.com> | 2014-11-26 11:18:20 +0100 |
commit | da82942bbd6a40cf7ddd3edc52352610905137ce (patch) | |
tree | 598911eb9a0cfa1a5ecee50f58b6638ace196aa5 | |
parent | 8e55657b47cc5266af30525c58a7fa0a3d6f0160 (diff) | |
download | kernel_samsung_tuna-da82942bbd6a40cf7ddd3edc52352610905137ce.zip kernel_samsung_tuna-da82942bbd6a40cf7ddd3edc52352610905137ce.tar.gz kernel_samsung_tuna-da82942bbd6a40cf7ddd3edc52352610905137ce.tar.bz2 |
tty: omap-serial: Disabling DMA on suspend path
In case of bug UART can't suspend with TX DMA enabled. So here is
implemented WA: TX DMA is disabled on runtime suspend path and
re-enabled on runtime resume path.
Change-Id: Iabc726ca93a5e354eb53efdacedf3261d4e02763
Signed-off-by: Vitaly Chernooky <vitaly.chernooky@ti.com>
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 43 | ||||
-rw-r--r-- | include/linux/serial_reg.h | 2 |
2 files changed, 45 insertions, 0 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 71b73a3..7de7589 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1825,8 +1825,37 @@ static int omap_serial_runtime_suspend(struct device *dev) udelay(300); } if (up->use_dma) { + u32 iscr, ifcr, ilsr; struct omap_device *od; + /* Stop baud clock */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_DLL, 0); + serial_out(up, UART_DLM, 0); + + /* A DMA disabling sequence for DMA mode 1 set by FCR[3] = 1, SCR[0] = 0 */ + iscr = serial_in(up, UART_OMAP_SCR) & UART_OMAP_SCR_DMA_MODE_MASK; + serial_out(up, UART_OMAP_SCR, iscr | 0x02); + serial_out(up, UART_OMAP_SCR, iscr | 0x03); + ifcr = up->fcr & ~UART_FCR_DMA_SELECT; + serial_out(up, UART_FCR, ifcr); + ilsr = serial_in(up, UART_LSR); + while ((ilsr & 0x01) == 1) { + serial_in(up, UART_RX); + ilsr = serial_in(up, UART_LSR); + } + serial_out(up, UART_FCR, ifcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + iscr = serial_in(up, UART_OMAP_SCR) & UART_OMAP_SCR_DMA_MODE_MASK; + serial_out(up, UART_OMAP_SCR, iscr | 0x04); + serial_out(up, UART_FCR, ifcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + iscr = serial_in(up, UART_OMAP_SCR) & UART_OMAP_SCR_DMA_MODE_MASK; + serial_out(up, UART_OMAP_SCR, iscr); + + /* Restart baud clock */ + serial_out(up, UART_DLL, up->dll); /* LS of divisor */ + serial_out(up, UART_DLM, up->dlh); /* MS of divisor */ + serial_out(up, UART_LCR, up->lcr); + /* ENABLE IDLE MODE */ od = to_omap_device(up->pdev); omap_hwmod_set_slave_idlemode(od->hwmods[0], @@ -1855,6 +1884,20 @@ static int omap_serial_runtime_resume(struct device *dev) od = to_omap_device(up->pdev); omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_NO); + + /* Stop baud clock */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_DLL, 0); + serial_out(up, UART_DLM, 0); + + /* re-enable DMA */ + serial_out(up, UART_OMAP_SCR, up->scr); + serial_out(up, UART_FCR, up->fcr); + + /* re-start baud clock */ + serial_out(up, UART_DLL, up->dll); /* LS of divisor */ + serial_out(up, UART_DLM, up->dlh); /* MS of divisor */ + serial_out(up, UART_LCR, up->lcr); } if (up->rts_mux_driver_control && (!up->rts_pullup_in_suspend)) omap_rts_mux_write(0, up->port.line); diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h index c75bda3..e8046c7 100644 --- a/include/linux/serial_reg.h +++ b/include/linux/serial_reg.h @@ -362,5 +362,7 @@ #define UART_OMAP_MDR1_CIR_MODE 0x06 /* CIR mode */ #define UART_OMAP_MDR1_DISABLE 0x07 /* Disable (default state) */ +#define UART_OMAP_SCR_DMA_MODE_MASK 0xF9 + #endif /* _LINUX_SERIAL_REG_H */ |