aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Borleis <jbe@pengutronix.de>2015-08-07 06:47:04 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-14 20:08:48 -0400
commit17dc72cf3d8c6284cc34f29627f891268af07a55 (patch)
tree8b6b1a634f077ce2b9b5465da95556f92bab6654
parent3fa30ac3b9a9220fa953eeb6d21b9ca578c67885 (diff)
serial: mxs-auart: keep the AUART unit in reset state when not in use
Whenever the UART device driver gets closed from userland, the driver disables the UART unit and then stops the clocks to save power. The bit which disabled the UART unit is described as:  "UART Enable. If this bit is set to 1, the UART is enabled. Data transmission and reception occurs for the UART signals. When the UART is disabled in the middle of transmission or reception, it completes the current character before stopping." The important part is the "it completes the current character". Whenever a reception is ongoing when the UART gets disabled (including the clock off) the statemachine freezes and "remembers" this state on the next open() when re-enabling the unit's clock. In this case we end up receiving an additional bogus character immediately. The solution in this change is to switch the AUART unit into its reset state on close() and only release it from its reset state on the next open(). Note: when the unit is also used as system console it is always 'in use', so we cannot reset it on close(). Signed-off-by: Juergen Borleis <jbe@pengutronix.de> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/mxs-auart.c46
1 files changed, 39 insertions, 7 deletions
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 7dc87a9e4bff..8d1cd158ca24 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -858,6 +858,30 @@ static void mxs_auart_reset_deassert(struct uart_port *u)
858 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); 858 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
859} 859}
860 860
861static void mxs_auart_reset_assert(struct uart_port *u)
862{
863 int i;
864 u32 reg;
865
866 reg = readl(u->membase + AUART_CTRL0);
867 /* if already in reset state, keep it untouched */
868 if (reg & AUART_CTRL0_SFTRST)
869 return;
870
871 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
872 writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_SET);
873
874 for (i = 0; i < 1000; i++) {
875 reg = readl(u->membase + AUART_CTRL0);
876 /* reset is finished when the clock is gated */
877 if (reg & AUART_CTRL0_CLKGATE)
878 return;
879 udelay(10);
880 }
881
882 dev_err(u->dev, "Failed to reset the unit.");
883}
884
861static int mxs_auart_startup(struct uart_port *u) 885static int mxs_auart_startup(struct uart_port *u)
862{ 886{
863 int ret; 887 int ret;
@@ -867,7 +891,13 @@ static int mxs_auart_startup(struct uart_port *u)
867 if (ret) 891 if (ret)
868 return ret; 892 return ret;
869 893
870 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); 894 if (uart_console(u)) {
895 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
896 } else {
897 /* reset the unit to a well known state */
898 mxs_auart_reset_assert(u);
899 mxs_auart_reset_deassert(u);
900 }
871 901
872 writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET); 902 writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET);
873 903
@@ -899,12 +929,14 @@ static void mxs_auart_shutdown(struct uart_port *u)
899 if (auart_dma_enabled(s)) 929 if (auart_dma_enabled(s))
900 mxs_auart_dma_exit(s); 930 mxs_auart_dma_exit(s);
901 931
902 writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR); 932 if (uart_console(u)) {
903 933 writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR);
904 writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, 934 writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
905 u->membase + AUART_INTR_CLR); 935 u->membase + AUART_INTR_CLR);
906 936 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
907 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); 937 } else {
938 mxs_auart_reset_assert(u);
939 }
908 940
909 clk_disable_unprepare(s->clk); 941 clk_disable_unprepare(s->clk);
910} 942}