| /* 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. |
| */ |
| |
| /* USART driver for Chrome EC */ |
| |
| #include "clock.h" |
| #include "console.h" |
| #include "common.h" |
| #include "dma.h" |
| #include "hooks.h" |
| #include "registers.h" |
| #include "system.h" |
| #include "task.h" |
| #include "uart.h" |
| #include "util.h" |
| |
| #define CPUTS(outstr) cputs(CC_SYSTEM, outstr) |
| #define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) |
| #define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) |
| |
| |
| static int ever_sent; /* if we ever sent byte to TXD? */ |
| static int init_done; /* Initialization done? */ |
| static int should_stop; /* Last TX control action */ |
| |
| int uart_init_done(void) |
| { |
| return init_done; |
| } |
| |
| void uart_tx_start(void) |
| { |
| disable_sleep(SLEEP_MASK_UART); |
| should_stop = 0; |
| NRF51_UART_INTENSET = (1 << NRF55_UART_TXDRDY_BIT); |
| task_trigger_irq(NRF51_PERID_USART); |
| } |
| |
| void uart_tx_stop(void) |
| { |
| NRF51_UART_INTENCLR = (1 << NRF55_UART_TXDRDY_BIT); |
| should_stop = 1; |
| enable_sleep(SLEEP_MASK_UART); |
| } |
| |
| int uart_tx_ready(void) |
| { |
| /* |
| * nRF51 design is NOT tx-empty style. Instead, it is if a byte is |
| * ever transmitted from TxD. This means NRF51_UART_TXDRDY is always |
| * 0 after reset. So, we use 'ever_sent' to send the first byte. |
| */ |
| return NRF51_UART_TXDRDY || (!ever_sent); |
| } |
| |
| int uart_rx_available(void) |
| { |
| return NRF51_UART_RXDRDY; |
| } |
| |
| void uart_tx_flush(void) |
| { |
| while (!uart_tx_ready()) |
| ; |
| } |
| |
| void uart_write_char(char c) |
| { |
| ever_sent = 1; |
| NRF51_UART_TXDRDY = 0; |
| NRF51_UART_TXD = c; |
| NRF51_UART_STARTTX = 1; |
| } |
| |
| int uart_read_char(void) |
| { |
| NRF51_UART_RXDRDY = 0; |
| return NRF51_UART_RXD; |
| } |
| |
| void uart_disable_interrupt(void) |
| { |
| task_disable_irq(NRF51_PERID_USART); |
| } |
| |
| void uart_enable_interrupt(void) |
| { |
| task_enable_irq(NRF51_PERID_USART); |
| } |
| |
| |
| /* Interrupt handler for console USART */ |
| void uart_interrupt(void) |
| { |
| #ifndef CONFIG_UART_RX_DMA |
| /* |
| * Read input FIFO until empty. DMA-based receive does this from a |
| * hook in the UART buffering module. |
| */ |
| uart_process_input(); |
| #endif |
| |
| /* Fill output FIFO */ |
| uart_process_output(); |
| |
| #ifndef CONFIG_UART_TX_DMA |
| if (!should_stop) |
| NRF51_UART_INTENSET = (1 << NRF55_UART_TXDRDY_BIT); |
| #endif /* CONFIG_UART_TX_DMA */ |
| |
| } |
| DECLARE_IRQ(NRF51_PERID_USART, uart_interrupt, 2); |
| |
| |
| void uart_init(void) |
| { |
| NRF51_UART_PSELTXD = NRF51_UART_TX_PIN; /* GPIO Port for Tx */ |
| NRF51_UART_PSELRXD = NRF51_UART_RX_PIN; /* GPIO Port for Rx */ |
| NRF51_UART_CONFIG = 0; /* disable HW flow control, no parity bit */ |
| NRF51_UART_BAUDRATE = 0x01d7e000; /* 115200 */ |
| NRF51_UART_ENABLE = 0x4; /* Enable UART */ |
| |
| uart_enable_interrupt(); |
| NRF51_UART_INTENSET = (1 << NRF55_UART_RXDRDY_BIT); |
| NRF51_UART_STARTRX = 1; |
| |
| init_done = 1; |
| } |