summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2014-10-23 16:49:49 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-10-24 21:17:29 +0000
commitbf8335a0a329f8d40fe3c4e911c9f9bb144ca2ad (patch)
tree550e3a4afbb07f34ed2eb4bf7b04ede34e00025d
parent0dd653292c37f75e6b6c56f50af524fea7700b7b (diff)
downloadchrome-ec-bf8335a0a329f8d40fe3c4e911c9f9bb144ca2ad.tar.gz
stm32: Wait for UART Tx to complete before entering STOP mode
Before entering STOP mode, we need to ensure UART Tx has completed. Otherwise, we may lose some characters or some bits within a character. For Tx DMA mode, this is already done as we wait until TC (Tx complete) is set before disabling Tx. However, when not using DMA, we enable sleep when TXE is set. At this moment, the last character is still in the shift register and going into sleep causes loss of the whole or part of the last character. To avoid this, let's enable TC interrupt and enable sleep only if we have no more characters to send and TC is set. BRANCH=None BUG=chrome-os-partner:33219 TEST=Enable low power mode on Ryu P2. Type when the EC is in STOP mode and check there is no broken character. Change-Id: Ife42671882b7f1d1d17734d7d20fb4ba7dffb371 Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/225283 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/stm32/uart.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/chip/stm32/uart.c b/chip/stm32/uart.c
index de4047a1bc..170f30a745 100644
--- a/chip/stm32/uart.c
+++ b/chip/stm32/uart.c
@@ -68,7 +68,8 @@ void uart_tx_start(void)
disable_sleep(SLEEP_MASK_UART);
should_stop = 0;
- STM32_USART_CR1(UARTN_BASE) |= UART_TX_INT_ENABLE;
+ STM32_USART_CR1(UARTN_BASE) |= UART_TX_INT_ENABLE |
+ STM32_USART_CR1_TCIE;
task_trigger_irq(STM32_IRQ_USART(UARTN));
}
@@ -76,7 +77,9 @@ void uart_tx_stop(void)
{
STM32_USART_CR1(UARTN_BASE) &= ~UART_TX_INT_ENABLE;
should_stop = 1;
+#ifdef CONFIG_UART_TX_DMA
enable_sleep(SLEEP_MASK_UART);
+#endif
}
void uart_tx_flush(void)
@@ -163,6 +166,22 @@ void uart_enable_interrupt(void)
/* Interrupt handler for console USART */
void uart_interrupt(void)
{
+#ifndef CONFIG_UART_TX_DMA
+ /*
+ * When trasmission completes, enable sleep if we are done with Tx.
+ * After that, proceed if there is other interrupt to handle.
+ */
+ if (STM32_USART_SR(UARTN_BASE) & STM32_USART_SR_TC) {
+ if (should_stop) {
+ STM32_USART_CR1(UARTN_BASE) &= ~STM32_USART_CR1_TCIE;
+ enable_sleep(SLEEP_MASK_UART);
+ }
+ STM32_USART_ICR(UARTN_BASE) |= STM32_USART_SR_TC;
+ if (!(STM32_USART_SR(UARTN_BASE) & ~STM32_USART_SR_TC))
+ return;
+ }
+#endif
+
#ifdef CONFIG_UART_TX_DMA
/* Disable transmission complete interrupt if DMA done */
if (STM32_USART_SR(UARTN_BASE) & STM32_USART_SR_TC)