diff options
author | Anton Staaf <robotboy@chromium.org> | 2015-06-16 10:34:56 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-07-15 21:57:46 +0000 |
commit | 137959bb88ef381cba67e24943388bd17ae89357 (patch) | |
tree | d4844e76548432b726cf40d57bf0214d92d64634 /chip/stm32/usart_tx_interrupt.c | |
parent | 88a1790bb7d82a30e052f1e10a9c7c88fb5c5c36 (diff) | |
download | chrome-ec-137959bb88ef381cba67e24943388bd17ae89357.tar.gz |
USART: Add flexibility needed to support DMA
In order to support DMA transfers in one or both directions the usart
driver needs to be configurable with producer/consumer operations and
interrupt handler functions. These are now packaged up in the usart_rx
and usart_tx structs, and versions for interrupt driven RX and TX are
provided.
Signed-off-by: Anton Staaf <robotboy@chromium.org>
BRANCH=None
BUG=None
TEST=make buildall -j
Change-Id: I3fd14c675c90873e903195b8e20d2070d2eda5ac
Reviewed-on: https://chromium-review.googlesource.com/285023
Trybot-Ready: Anton Staaf <robotboy@chromium.org>
Tested-by: Anton Staaf <robotboy@chromium.org>
Reviewed-by: Todd Broch <tbroch@chromium.org>
Tested-by: Todd Broch <tbroch@chromium.org>
Commit-Queue: Anton Staaf <robotboy@chromium.org>
Diffstat (limited to 'chip/stm32/usart_tx_interrupt.c')
-rw-r--r-- | chip/stm32/usart_tx_interrupt.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/chip/stm32/usart_tx_interrupt.c b/chip/stm32/usart_tx_interrupt.c new file mode 100644 index 0000000000..60f28d5a1d --- /dev/null +++ b/chip/stm32/usart_tx_interrupt.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Interrupt based USART TX driver for STM32 */ + +#include "usart.h" + +#include "common.h" +#include "registers.h" +#include "system.h" +#include "util.h" + +static void usart_tx_init(struct usart_config const *config) +{ + intptr_t base = config->hw->base; + + STM32_USART_CR1(base) |= STM32_USART_CR1_TE; +} + +static void usart_written(struct consumer const *consumer, size_t count) +{ + struct usart_config const *config = + DOWNCAST(consumer, struct usart_config, consumer); + + /* + * Enable USART interrupt. This causes the USART interrupt handler to + * start fetching from the TX queue if it wasn't already. + */ + if (count) + STM32_USART_CR1(config->hw->base) |= STM32_USART_CR1_TXEIE; +} + +static void usart_flush(struct consumer const *consumer) +{ + struct usart_config const *config = + DOWNCAST(consumer, struct usart_config, consumer); + + /* + * Enable USART interrupt. This causes the USART interrupt handler to + * start fetching from the TX queue if it wasn't already. + */ + STM32_USART_CR1(config->hw->base) |= STM32_USART_CR1_TXEIE; + + while (queue_count(consumer->queue)) + ; +} + +static void usart_tx_interrupt_handler(struct usart_config const *config) +{ + intptr_t base = config->hw->base; + uint8_t byte; + + if (!(STM32_USART_SR(base) & STM32_USART_SR_TXE)) + return; + + if (queue_remove_unit(config->consumer.queue, &byte)) { + STM32_USART_TDR(base) = byte; + + /* + * Make sure the TXE interrupt is enabled and that we won't go + * into deep sleep. This invocation of the USART interrupt + * handler may have been manually triggered to start + * transmission. + */ + disable_sleep(SLEEP_MASK_UART); + + STM32_USART_CR1(base) |= STM32_USART_CR1_TXEIE; + } else { + /* + * The TX queue is empty, disable the TXE interrupt and enable + * deep sleep mode. The TXE interrupt will remain disabled + * until a write call happens. + */ + enable_sleep(SLEEP_MASK_UART); + + STM32_USART_CR1(base) &= ~STM32_USART_CR1_TXEIE; + } +} + +struct usart_tx const usart_tx_interrupt = { + .consumer_ops = { + .written = usart_written, + .flush = usart_flush, + }, + + .init = usart_tx_init, + .interrupt = usart_tx_interrupt_handler, +}; |