265 lines
7.6 KiB
C
265 lines
7.6 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation.
|
|
* Copyright (c) 2013-2015 Wind River Systems, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @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 <nanokernel.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) \
|
|
((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 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);
|
|
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 */
|
|
|
|
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;
|
|
|
|
dev->driver_api = &uart_sam3_driver_api;
|
|
|
|
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 struct uart_driver_api uart_sam3_driver_api = {
|
|
.poll_in = uart_sam3_poll_in,
|
|
.poll_out = uart_sam3_poll_out,
|
|
};
|
|
|
|
static 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_INIT(uart_sam3_0, CONFIG_UART_ATMEL_SAM3_NAME, &uart_sam3_init,
|
|
&uart_sam3_dev_data_0, &uart_sam3_dev_cfg_0,
|
|
PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|