mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-30 10:31:02 +00:00
Add a driver for the GPIO controller. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=chrome-os-partner:33816 TEST=press the push buttons on the board and see the console text message and the LEDs lighting up. Change-Id: Idb408fe1c341beb8a97f2047ba6740e0d40cedf5 Reviewed-on: https://chromium-review.googlesource.com/233307 Trybot-Ready: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org> Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
162 lines
3.6 KiB
C
162 lines
3.6 KiB
C
/* 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.
|
|
*/
|
|
|
|
#include "clock.h"
|
|
#include "common.h"
|
|
#include "gpio.h"
|
|
#include "registers.h"
|
|
#include "system.h"
|
|
#include "task.h"
|
|
#include "uart.h"
|
|
#include "util.h"
|
|
|
|
static int done_uart_init_yet;
|
|
|
|
int uart_init_done(void)
|
|
{
|
|
return done_uart_init_yet;
|
|
}
|
|
|
|
void uart_tx_start(void)
|
|
{
|
|
/* If interrupt is already enabled, nothing to do */
|
|
if (GR_UART_ICTRL(0) & GC_UART_ICTRL_TX_MASK)
|
|
return;
|
|
|
|
/* Do not allow deep sleep while transmit in progress */
|
|
disable_sleep(SLEEP_MASK_UART);
|
|
|
|
/*
|
|
* Re-enable the transmit interrupt, then forcibly trigger the
|
|
* interrupt. This works around a hardware problem with the
|
|
* UART where the FIFO only triggers the interrupt when its
|
|
* threshold is _crossed_, not just met.
|
|
*/
|
|
/* TODO(crosbug.com/p/33819): Do we need this hack here? Find out. */
|
|
REG_WRITE_MLV(GR_UART_ICTRL(0), GC_UART_ICTRL_TX_MASK,
|
|
GC_UART_ICTRL_TX_LSB, 1);
|
|
task_trigger_irq(GC_IRQNUM_UART0_TXINT);
|
|
}
|
|
|
|
void uart_tx_stop(void)
|
|
{
|
|
/* Disable the TX interrupt */
|
|
REG_WRITE_MLV(GR_UART_ICTRL(0), GC_UART_ICTRL_TX_MASK,
|
|
GC_UART_ICTRL_TX_LSB, 0);
|
|
|
|
/* Re-allow deep sleep */
|
|
enable_sleep(SLEEP_MASK_UART);
|
|
}
|
|
|
|
int uart_tx_in_progress(void)
|
|
{
|
|
/* Transmit is in progress if the TX idle bit is not set */
|
|
return !(GR_UART_STATE(0) & GC_UART_STATE_TXIDLE_MASK);
|
|
}
|
|
|
|
void uart_tx_flush(void)
|
|
{
|
|
/* Wait until TX FIFO is idle. */
|
|
while (uart_tx_in_progress())
|
|
;
|
|
}
|
|
|
|
int uart_tx_ready(void)
|
|
{
|
|
/* True if the TX buffer is not completely full */
|
|
return !(GR_UART_STATE(0) & GC_UART_STATE_TX_MASK);
|
|
}
|
|
|
|
int uart_rx_available(void)
|
|
{
|
|
/* True if the RX buffer is not completely empty. */
|
|
return !(GR_UART_STATE(0) & GC_UART_STATE_RXEMPTY_MASK);
|
|
}
|
|
|
|
void uart_write_char(char c)
|
|
{
|
|
/* Wait for space in transmit FIFO. */
|
|
while (!uart_tx_ready())
|
|
;
|
|
|
|
GR_UART_WDATA(0) = c;
|
|
}
|
|
|
|
int uart_read_char(void)
|
|
{
|
|
return GR_UART_RDATA(0);
|
|
}
|
|
|
|
void uart_disable_interrupt(void)
|
|
{
|
|
task_disable_irq(GC_IRQNUM_UART0_TXINT);
|
|
task_disable_irq(GC_IRQNUM_UART0_RXINT);
|
|
}
|
|
|
|
void uart_enable_interrupt(void)
|
|
{
|
|
task_enable_irq(GC_IRQNUM_UART0_TXINT);
|
|
task_enable_irq(GC_IRQNUM_UART0_RXINT);
|
|
}
|
|
|
|
/**
|
|
* Interrupt handlers for UART0
|
|
*/
|
|
void uart_ec_tx_interrupt(void)
|
|
{
|
|
/* Clear transmit interrupt status */
|
|
GR_UART_ISTATECLR(0) = GC_UART_ISTATECLR_TX_MASK;
|
|
|
|
/* Fill output FIFO */
|
|
uart_process_output();
|
|
}
|
|
DECLARE_IRQ(GC_IRQNUM_UART0_TXINT, uart_ec_tx_interrupt, 1);
|
|
|
|
void uart_ec_rx_interrupt(void)
|
|
{
|
|
/* Clear receive interrupt status */
|
|
GR_UART_ISTATECLR(0) = GC_UART_ISTATECLR_RX_MASK;
|
|
|
|
/* Read input FIFO until empty */
|
|
uart_process_input();
|
|
}
|
|
DECLARE_IRQ(GC_IRQNUM_UART0_RXINT, uart_ec_rx_interrupt, 1);
|
|
|
|
/* Constants for setting baud rate */
|
|
#define PCLK_FREQ 30000000
|
|
#define DEFAULT_UART_FREQ 1000000
|
|
#define UART_NCO_WIDTH 16
|
|
|
|
void uart_init(void)
|
|
{
|
|
long long setting = (16 * (1 << UART_NCO_WIDTH) *
|
|
(long long)CONFIG_UART_BAUD_RATE / PCLK_FREQ);
|
|
|
|
/* turn on uart clock */
|
|
clock_enable_module(MODULE_UART, 1);
|
|
|
|
/* set up pinmux */
|
|
gpio_config_module(MODULE_UART, 1);
|
|
|
|
/* set frequency */
|
|
GR_UART_NCO(0) = setting;
|
|
|
|
/* Interrupt when RX fifo has anything, when TX fifo <= half empty */
|
|
/* Also reset (clear) both FIFOs */
|
|
GR_UART_FIFO(0) = 0x63;
|
|
|
|
/* TX enable, RX enable, HW flow control disabled, no loopback */
|
|
GR_UART_CTRL(0) = 0x03;
|
|
|
|
/* enable RX interrupts in block */
|
|
/* Note: doesn't do anything unless turned on in NVIC */
|
|
GR_UART_ICTRL(0) = 0x02;
|
|
|
|
/* Enable interrupts for UART0 only */
|
|
uart_enable_interrupt();
|
|
|
|
done_uart_init_yet = 1;
|
|
}
|