Skip to content

Commit

Permalink
serial: adds UART driver for SAM3X8E
Browse files Browse the repository at this point in the history
This adds driver for the UART controller on Atmel SAM3X8E.
This UART controller only has two wires for RX and TX, and
does not have flow control (e.g. CTS, RTS) or FIFO.

Currently, the driver does not support any interrupt driven
operations.

Change-Id: I63720bccfb70a89888353b8ee3dfc4b80793dc01
Signed-off-by: Daniel Leung <[email protected]>
  • Loading branch information
dcpleung authored and nashif committed Feb 6, 2016
1 parent 945ebd7 commit 21c3118
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 0 deletions.
24 changes: 24 additions & 0 deletions arch/arm/soc/atmel_sam3/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,28 @@ config KERNEL_INIT_PRIORITY_DEFAULT
config KERNEL_INIT_PRIORITY_DEVICE
default 50

config UART_CONSOLE_PRIORITY
default 60

if UART_ATMEL_SAM3

config UART_ATMEL_SAM3_BAUD_RATE
default 115200

config UART_ATMEL_SAM3_CLK_FREQ
default 84000000

endif # UART_ATMEL_SAM3

if UART_CONSOLE

config UART_CONSOLE_ON_DEV_NAME
default "UART_0"
config UART_CONSOLE_IRQ
default 8
config UART_CONSOLE_IRQ_PRI
default 3

endif # UART_CONSOLE

endif # SOC_ATMEL_SAM3
2 changes: 2 additions & 0 deletions drivers/serial/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,6 @@ source "drivers/serial/Kconfig.stellaris"

source "drivers/serial/Kconfig.nsim"

source "drivers/serial/Kconfig.atmel_sam3"

endif
40 changes: 40 additions & 0 deletions drivers/serial/Kconfig.atmel_sam3
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
config UART_ATMEL_SAM3
bool "Atmel SAM3 family processor UART driver"
default n
select SERIAL_HAS_DRIVER
depends on SOC_ATMEL_SAM3
help
This option enables the UART driver for Atmel SAM3
family processors. Note that there is only one
UART controller on SAM3. It has only two wires
for RX and TX, and does not have other pins
(such as CTS and RTS).

config UART_ATMEL_SAM3_NAME
string "Device Name for Atmel SAM3 UART"
default "UART_0"
depends on UART_ATMEL_SAM3
help
This is the device name for UART, and is included in the device
struct.

config UART_ATMEL_SAM3_IRQ_PRI
int "Atmel SAM3 UART Interrupt Priority"
default 0
depends on UART_ATMEL_SAM3
help
The interrupt priority for UART port.

config UART_ATMEL_SAM3_BAUD_RATE
int "Atmel SAM3 UART Baud Rate"
default 0
depends on UART_ATMEL_SAM3
help
The baud rate for UART port to be set to at boot.

config UART_ATMEL_SAM3_CLK_FREQ
int "Atmel SAM3 UART Clock Frequency"
default 0
depends on UART_ATMEL_SAM3
help
The clock frequency for UART port.
1 change: 1 addition & 0 deletions drivers/serial/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ obj-$(CONFIG_UART_NS16550) += uart_ns16550.o
obj-$(CONFIG_UART_K20) += uart_k20.o
obj-$(CONFIG_UART_STELLARIS) += uart_stellaris.o
obj-$(CONFIG_UART_NSIM) += uart_nsim.o
obj-$(CONFIG_UART_ATMEL_SAM3) += uart_atmel_sam3.o
268 changes: 268 additions & 0 deletions drivers/serial/uart_atmel_sam3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
/*
* 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 (of type struct uart_device_config)
* @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 (of type struct uart_device_config)
*
* @return DEV_OK
*/
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 DEV_OK;
}

/**
* @brief Poll the device for input.
*
* @param dev UART device struct (of type struct uart_device_config)
* @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 (of type struct uart_device_config)
* @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,
};

DECLARE_DEVICE_INIT_CONFIG(uart_sam3_0,
CONFIG_UART_ATMEL_SAM3_NAME,
&uart_sam3_init,
&uart_sam3_dev_cfg_0);

SYS_DEFINE_DEVICE(uart_sam3_0, &uart_sam3_dev_data_0,
PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);

0 comments on commit 21c3118

Please sign in to comment.