/*
 * This work is part of the White Rabbit project
 *
 * Copyright (C) 2011 CERN (www.cern.ch)
 * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
 *
 * Released according to the GNU GPL, version 2 or any later version.
 */

#include <stdint.h>

#include "board.h"
#include "uart.h"

#include <hw/wb_uart.h>

#define CALC_BAUD(baudrate) \
    ( ((( (unsigned long long)baudrate * 8ULL) << (16 - 7)) + \
      (CPU_CLOCK >> 8)) / (CPU_CLOCK >> 7) )

void suart_init(struct simple_uart_device *dev, uint32_t base_addr, int baudrate)
{
	dev->base = (void*) base_addr;
	dev->crlf_mode = 0;
	writel( CALC_BAUD(baudrate), dev->base + UART_REG_BCR );
}

void suart_write_byte(struct simple_uart_device *dev, int b)
{
	if (b == '\n' && dev->crlf_mode)
		suart_write_byte(dev, '\r');

	while (readl(dev->base + UART_REG_SR) & UART_SR_TX_BUSY)
		;

	writel( b, dev->base + UART_REG_TDR );
}

int suart_write_string(struct simple_uart_device *dev, const char *s)
{
	const char *t = s;
	while (*s)
		suart_write_byte(dev, *(s++));
	return s - t;
}

int suart_poll(struct simple_uart_device *dev)
{
	return readl( dev->base + UART_REG_SR) & UART_SR_RX_RDY;
}

int suart_read_byte(struct simple_uart_device *dev)
{
	if (!suart_poll(dev))
		return -1;

	return readl(dev->base + UART_REG_RDR) & 0xff;
}

