blob: 087698afa0953de4444be59854a5522b22f1aa4d [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation.
* Copyright (c) 2013-2015 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Driver for UART on Atmel SAM3 family processor.
*
* Note that there is only one UART controller on the SoC.
* It has two wires for RX and TX, and does not have other such as
* CTS or RTS. Also, the RX and TX are connected directly to
* bit shifters and there is no FIFO.
*
* For full serial function, use the USART controller.
*
* (used uart_stellaris.c as template)
*/
#include <kernel.h>
#include <arch/cpu.h>
#include <misc/__assert.h>
#include <board.h>
#include <init.h>
#include <uart.h>
#include <sections.h>
/* UART registers struct */
struct _uart {
/* UART registers */
uint32_t cr; /* 0x00 Control Register */
uint32_t mr; /* 0x04 Mode Register */
uint32_t ier; /* 0x08 Interrupt Enable Register */
uint32_t idr; /* 0x0C Interrupt Disable Register */
uint32_t imr; /* 0x10 Interrupt Mask Register */
uint32_t sr; /* 0x14 Status Register */
uint32_t rhr; /* 0x18 Receive Holding Register */
uint32_t thr; /* 0x1C Transmit Holding Register */
uint32_t brgr; /* 0x20 Baud Rate Generator Register */
uint32_t reserved[55]; /* 0x24 - 0xFF */
/* PDC related registers */
uint32_t pdc_rpr; /* 0x100 Receive Pointer Reg */
uint32_t pdc_rcr; /* 0x104 Receive Counter Reg */
uint32_t pdc_tpr; /* 0x108 Transmit Pointer Reg */
uint32_t pdc_tcr; /* 0x10C Transmit Counter Reg */
uint32_t pdc_rnpr; /* 0x110 Receive Next Pointer */
uint32_t pdc_rncr; /* 0x114 Receive Next Counter */
uint32_t pdc_tnpr; /* 0x118 Transmit Next Pointer */
uint32_t pdc_tncr; /* 0x11C Transmit Next Counter */
uint32_t pdc_ptcr; /* 0x120 Transfer Control Reg */
uint32_t pdc_ptsr; /* 0x124 Transfer Status Reg */
};
/* Device data structure */
struct uart_sam3_dev_data_t {
uint32_t baud_rate; /* Baud rate */
};
/* convenience defines */
#define DEV_CFG(dev) \
((const struct uart_device_config * const)(dev)->config->config_info)
#define DEV_DATA(dev) \
((struct uart_sam3_dev_data_t * const)(dev)->driver_data)
#define UART_STRUCT(dev) \
((volatile struct _uart *)(DEV_CFG(dev))->base)
/* Registers */
#define UART_CR(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x00)))
#define UART_MR(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x04)))
#define UART_IER(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x08)))
#define UART_IDR(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x0C)))
#define UART_IMR(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x10)))
#define UART_SR(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x14)))
#define UART_RHR(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x18)))
#define UART_THR(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x1C)))
#define UART_BRGR(dev) (*((volatile uint32_t *)(DEV_CFG(dev)->base + 0x20)))
/* bits */
#define UART_CR_RSTRX (1 << 2)
#define UART_CR_RSTTX (1 << 3)
#define UART_CR_RXEN (1 << 4)
#define UART_CR_RXDIS (1 << 5)
#define UART_CR_TXEN (1 << 6)
#define UART_CR_TXDIS (1 << 7)
#define UART_CR_RSTSTA (1 << 8)
#define UART_MR_PARTIY_MASK (0x0E00)
#define UART_MR_PARITY_EVEN (0 << 9)
#define UART_MR_PARITY_ODD (1 << 9)
#define UART_MR_PARITY_SPACE (2 << 9)
#define UART_MR_PARITY_MARK (3 << 9)
#define UART_MR_PARITY_NO (4 << 9)
#define UART_MR_CHMODE_MASK (0xC000)
#define UART_MR_CHMODE_NORMAL (0 << 14)
#define UART_MR_CHMODE_AUTOMATIC (1 << 14)
#define UART_MR_CHMODE_LOCAL_LOOPBACK (2 << 14)
#define UART_MR_CHMODE_REMOTE_LOOPBACK (3 << 14)
#define UART_INT_RXRDY (1 << 0)
#define UART_INT_TXRDY (1 << 1)
#define UART_INT_ENDRX (1 << 3)
#define UART_INT_ENDTX (1 << 4)
#define UART_INT_OVRE (1 << 5)
#define UART_INT_FRAME (1 << 6)
#define UART_INT_PARE (1 << 7)
#define UART_INT_TXEMPTY (1 << 9)
#define UART_INT_TXBUFE (1 << 11)
#define UART_INT_RXBUFF (1 << 12)
#define UART_PDC_PTCR_RXTDIS (1 << 1)
#define UART_PDC_PTCR_TXTDIS (1 << 9)
static const struct uart_driver_api uart_sam3_driver_api;
/**
* @brief Set the baud rate
*
* This routine set the given baud rate for the UART.
*
* @param dev UART device struct
* @param baudrate Baud rate
* @param sys_clk_freq_hz System clock frequency in Hz
*
* @return N/A
*/
static void baudrate_set(struct device *dev,
uint32_t baudrate, uint32_t sys_clk_freq_hz)
{
volatile struct _uart *uart = UART_STRUCT(dev);
const struct uart_device_config * const dev_cfg = DEV_CFG(dev);
struct uart_sam3_dev_data_t * const dev_data = DEV_DATA(dev);
uint32_t divisor; /* baud rate divisor */
ARG_UNUSED(sys_clk_freq_hz);
if ((baudrate != 0) && (dev_cfg->sys_clk_freq != 0)) {
/* calculate baud rate divisor */
divisor = (dev_cfg->sys_clk_freq / baudrate) >> 4;
divisor &= 0xFFFF;
uart->brgr = divisor;
dev_data->baud_rate = baudrate;
}
}
/**
* @brief Initialize UART channel
*
* This routine is called to reset the chip in a quiescent state.
* It is assumed that this function is called only once per UART.
*
* @param dev UART device struct
*
* @return 0
*/
static int uart_sam3_init(struct device *dev)
{
volatile struct _uart *uart = UART_STRUCT(dev);
/* Enable UART clock in PMC */
__PMC->pcer0 = (1 << PID_UART);
/* Detach pins PA8 and PA9 from PIO controller */
__PIOA->pdr = (1 << 8) | (1 << 9);
/* Disable PDC (DMA) */
uart->pdc_ptcr = UART_PDC_PTCR_RXTDIS | UART_PDC_PTCR_TXTDIS;
/* Reset and disable UART */
uart->cr = UART_CR_RSTRX | UART_CR_RSTTX
| UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA;
/* No parity and normal mode */
uart->mr = UART_MR_PARITY_NO | UART_MR_CHMODE_NORMAL;
/* Set baud rate */
baudrate_set(dev, DEV_DATA(dev)->baud_rate,
DEV_CFG(dev)->sys_clk_freq);
/* Enable receiver and transmitter */
uart->cr = UART_CR_RXEN | UART_CR_TXEN;
return 0;
}
/**
* @brief Poll the device for input.
*
* @param dev UART device struct
* @param c Pointer to character
*
* @return 0 if a character arrived, -1 if the input buffer if empty.
*/
static int uart_sam3_poll_in(struct device *dev, unsigned char *c)
{
volatile struct _uart *uart = UART_STRUCT(dev);
if (!(uart->sr & UART_INT_RXRDY))
return (-1);
/* got a character */
*c = (unsigned char)uart->rhr;
return 0;
}
/**
* @brief Output a character in polled mode.
*
* Checks if the transmitter is empty. If empty, a character is written to
* the data register.
*
* @param dev UART device struct
* @param c Character to send
*
* @return Sent character
*/
static unsigned char uart_sam3_poll_out(struct device *dev,
unsigned char c)
{
volatile struct _uart *uart = UART_STRUCT(dev);
/* Wait for transmitter to be ready */
while (!(uart->sr & UART_INT_TXRDY))
;
/* send a character */
uart->thr = (uint32_t)c;
return c;
}
static const struct uart_driver_api uart_sam3_driver_api = {
.poll_in = uart_sam3_poll_in,
.poll_out = uart_sam3_poll_out,
};
static const struct uart_device_config uart_sam3_dev_cfg_0 = {
.base = (uint8_t *)UART_ADDR,
.sys_clk_freq = CONFIG_UART_ATMEL_SAM3_CLK_FREQ,
};
static struct uart_sam3_dev_data_t uart_sam3_dev_data_0 = {
.baud_rate = CONFIG_UART_ATMEL_SAM3_BAUD_RATE,
};
DEVICE_AND_API_INIT(uart_sam3_0, CONFIG_UART_ATMEL_SAM3_NAME, &uart_sam3_init,
&uart_sam3_dev_data_0, &uart_sam3_dev_cfg_0,
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&uart_sam3_driver_api);