diff --git a/arch/arm/soc/atmel_sam/same70/soc_pinmap.h b/arch/arm/soc/atmel_sam/same70/soc_pinmap.h index 98fcae93364..3c0dc44b6fb 100644 --- a/arch/arm/soc/atmel_sam/same70/soc_pinmap.h +++ b/arch/arm/soc/atmel_sam/same70/soc_pinmap.h @@ -25,6 +25,47 @@ #define PINS_GMAC0 {PIN_GMAC_SET1} +/* Universal Asynchronous Receiver Transmitter (UART) */ + +#define PIN_UART0_RXD {PIO_PA9A_UART0_URXD0, PIOA, ID_PIOA, SOC_GPIO_FUNC_A} +#define PIN_UART0_TXD {PIO_PA10A_UART0_UTXD0, PIOA, ID_PIOA, SOC_GPIO_FUNC_A} + +#define PINS_UART0 {PIN_UART0_RXD, PIN_UART0_TXD} + +#define PIN_UART1_RXD {PIO_PA5C_UART1_URXD1, PIOA, ID_PIOA, SOC_GPIO_FUNC_C} +#ifdef CONFIG_UART_SAM_PORT_1_PIN_TX_PA4 +#define PIN_UART1_TXD {PIO_PA4C_UART1_UTXD1, PIOA, ID_PIOA, SOC_GPIO_FUNC_C} +#elif CONFIG_UART_SAM_PORT_1_PIN_TX_PA6 +#define PIN_UART1_TXD {PIO_PA6C_UART1_UTXD1, PIOA, ID_PIOA, SOC_GPIO_FUNC_C} +#elif CONFIG_UART_SAM_PORT_1_PIN_TX_PD26 +#define PIN_UART1_TXD {PIO_PD26D_UART1_UTXD1, PIOD, ID_PIOD, SOC_GPIO_FUNC_D} +#endif + +#define PINS_UART1 {PIN_UART1_RXD, PIN_UART1_TXD} + +#define PIN_UART2_RXD {PIO_PD25C_UART2_URXD2, PIOD, ID_PIOD, SOC_GPIO_FUNC_C} +#define PIN_UART2_TXD {PIO_PD26C_UART2_UTXD2, PIOD, ID_PIOD, SOC_GPIO_FUNC_C} + +#define PINS_UART2 {PIN_UART2_RXD, PIN_UART2_TXD} + +#define PIN_UART3_RXD {PIO_PD28A_UART3_URXD3, PIOD, ID_PIOD, SOC_GPIO_FUNC_A} +#ifdef CONFIG_UART_SAM_PORT_3_PIN_TX_PD30 +#define PIN_UART3_TXD {PIO_PD30A_UART3_UTXD3, PIOD, ID_PIOD, SOC_GPIO_FUNC_A} +#elif CONFIG_UART_SAM_PORT_3_PIN_TX_PD31 +#define PIN_UART3_TXD {PIO_PD31B_UART3_UTXD3, PIOD, ID_PIOD, SOC_GPIO_FUNC_B} +#endif + +#define PINS_UART3 {PIN_UART3_RXD, PIN_UART3_TXD} + +#define PIN_UART4_RXD {PIO_PD18C_UART4_URXD4, PIOD, ID_PIOD, SOC_GPIO_FUNC_C} +#ifdef CONFIG_UART_SAM_PORT_4_PIN_TX_PD3 +#define PIN_UART4_TXD {PIO_PD3C_UART4_UTXD4, PIOD, ID_PIOD, SOC_GPIO_FUNC_C} +#elif CONFIG_UART_SAM_PORT_4_PIN_TX_PD19 +#define PIN_UART4_TXD {PIO_PD19C_UART4_UTXD4, PIOD, ID_PIOD, SOC_GPIO_FUNC_C} +#endif + +#define PINS_UART4 {PIN_UART4_RXD, PIN_UART4_TXD} + /* Universal Synchronous Asynchronous Receiver Transmitter (USART) */ #define PIN_USART0_RXD {PIO_PB0C_USART0_RXD0, PIOB, ID_PIOB, SOC_GPIO_FUNC_C} diff --git a/boards/arm/sam_e70_xplained/doc/sam_e70_xplained.rst b/boards/arm/sam_e70_xplained/doc/sam_e70_xplained.rst index e9d82913145..d0bca06f014 100644 --- a/boards/arm/sam_e70_xplained/doc/sam_e70_xplained.rst +++ b/boards/arm/sam_e70_xplained/doc/sam_e70_xplained.rst @@ -39,6 +39,8 @@ features: +-----------+------------+-------------------------------------+ | SYSTICK | on-chip | systick | +-----------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++-----------+------------+-------------------------------------+ | USART | on-chip | serial port | +-----------+------------+-------------------------------------+ | I2C | on-chip | i2c | diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 51f20bdf570..2f14d814e4d 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -69,6 +69,8 @@ source "drivers/serial/Kconfig.atmel_sam3" source "drivers/serial/Kconfig.usart_sam" +source "drivers/serial/Kconfig.uart_sam" + source "drivers/serial/Kconfig.qmsi" source "drivers/serial/Kconfig.stm32" diff --git a/drivers/serial/Kconfig.uart_sam b/drivers/serial/Kconfig.uart_sam new file mode 100644 index 00000000000..3806bc02fb9 --- /dev/null +++ b/drivers/serial/Kconfig.uart_sam @@ -0,0 +1,176 @@ +# Kconfig - Atmel SAM UART configuration options +# +# Copyright (c) 2017 Piotr Mienkowski +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig UART_SAM + bool "Atmel SAM MCU family UART driver" + depends on SOC_FAMILY_SAM + select SERIAL_HAS_DRIVER + default n + help + This option enables the UARTx driver for Atmel SAM MCUs. + +# ---------- Port 0 ---------- + +config UART_SAM_PORT_0 + bool "Enable UART0" + depends on UART_SAM + default n + help + Configure UART0 at boot depending on the additional options below. + +if UART_SAM_PORT_0 + +config UART_SAM_PORT_0_NAME + string "UART0 Device Name" + default "UART_0" + help + Device name allows user to obtain a handle to the device object + required by all driver API functions. Device name has to be unique. + +config UART_SAM_PORT_0_BAUD_RATE + int "UART0 Baud Rate" + default 115200 + help + UART0 baud rate to be set at boot. + +endif # UART_SAM_PORT_0 + +# ---------- Port 1 ---------- + +config UART_SAM_PORT_1 + bool "Enable UART1" + depends on UART_SAM + default n + help + Configure UART1 at boot depending on the additional options below. + +if UART_SAM_PORT_1 + +config UART_SAM_PORT_1_NAME + string "UART1 Device Name" + default "UART_1" + help + Device name allows user to obtain a handle to the device object + required by all driver API functions. Device name has to be unique. + +config UART_SAM_PORT_1_BAUD_RATE + int "UART1 Baud Rate" + default 115200 + help + UART1 baud rate to be set at boot. + +choice + prompt "TX pin" + + config UART_SAM_PORT_1_PIN_TX_PA4 + bool "PA4" + + config UART_SAM_PORT_1_PIN_TX_PA6 + bool "PA6" + + config UART_SAM_PORT_1_PIN_TX_PD26 + bool "PD26" +endchoice + +endif # UART_SAM_PORT_1 + +# ---------- Port 2 ---------- + +config UART_SAM_PORT_2 + bool "Enable UART2" + depends on UART_SAM + default n + help + Configure UART2 at boot depending on the additional options below. + +if UART_SAM_PORT_2 + +config UART_SAM_PORT_2_NAME + string "UART2 Device Name" + default "UART_2" + help + Device name allows user to obtain a handle to the device object + required by all driver API functions. Device name has to be unique. + +config UART_SAM_PORT_2_BAUD_RATE + int "UART2 Baud Rate" + default 115200 + help + UART2 baud rate to be set at boot. + +endif # UART_SAM_PORT_2 + +# ---------- Port 3 ---------- + +config UART_SAM_PORT_3 + bool "Enable UART3" + depends on UART_SAM + default n + help + Configure UART3 at boot depending on the additional options below. + +if UART_SAM_PORT_3 + +config UART_SAM_PORT_3_NAME + string "UART3 Device Name" + default "UART_3" + help + Device name allows user to obtain a handle to the device object + required by all driver API functions. Device name has to be unique. + +config UART_SAM_PORT_3_BAUD_RATE + int "UART3 Baud Rate" + default 115200 + help + UART3 baud rate to be set at boot. + +choice + prompt "TX pin" + + config UART_SAM_PORT_3_PIN_TX_PD30 + bool "PD30" + + config UART_SAM_PORT_3_PIN_TX_PD31 + bool "PD31" +endchoice + +endif # UART_SAM_PORT_3 + +# ---------- Port 4 ---------- + +config UART_SAM_PORT_4 + bool "Enable UART4" + depends on UART_SAM + default n + help + Configure UART4 at boot depending on the additional options below. + +if UART_SAM_PORT_4 + +config UART_SAM_PORT_4_NAME + string "UART4 Device Name" + default "UART_4" + help + Device name allows user to obtain a handle to the device object + required by all driver API functions. Device name has to be unique. + +config UART_SAM_PORT_4_BAUD_RATE + int "UART4 Baud Rate" + default 115200 + help + UART4 baud rate to be set at boot. + +choice + prompt "TX pin" + + config UART_SAM_PORT_4_PIN_TX_PD3 + bool "PD3" + + config UART_SAM_PORT_4_PIN_TX_PD19 + bool "PD19" +endchoice + +endif # UART_SAM_PORT_4 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 45f45d8011c..1fa9fd5c3be 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_UART_MCUX_LPUART) += uart_mcux_lpuart.o obj-$(CONFIG_UART_STELLARIS) += uart_stellaris.o obj-$(CONFIG_UART_NSIM) += uart_nsim.o obj-$(CONFIG_UART_ATMEL_SAM3) += uart_atmel_sam3.o +obj-$(CONFIG_UART_SAM) += uart_sam.o obj-$(CONFIG_USART_SAM) += usart_sam.o obj-$(CONFIG_UART_QMSI) += uart_qmsi.o obj-$(CONFIG_UART_STM32) += uart_stm32.o diff --git a/drivers/serial/uart_sam.c b/drivers/serial/uart_sam.c new file mode 100644 index 00000000000..d6c7811136a --- /dev/null +++ b/drivers/serial/uart_sam.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2017 Piotr Mienkowski + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief UART driver for Atmel SAM MCU family. + * + * Note: + * - Error handling is not implemented. + * - The driver works only in polling mode, interrupt mode is not implemented. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Verify Kconfig configuration + */ + +#if CONFIG_UART_SAM_PORT_0 == 1 + +#if CONFIG_UART_SAM_PORT_0_BAUD_RATE == 0 +#error "CONFIG_UART_SAM_PORT_0_BAUD_RATE has to be bigger than 0" +#endif + +#endif + +#if CONFIG_UART_SAM_PORT_1 == 1 + +#if CONFIG_UART_SAM_PORT_1_BAUD_RATE == 0 +#error "CONFIG_UART_SAM_PORT_1_BAUD_RATE has to be bigger than 0" +#endif + +#endif + +#if CONFIG_UART_SAM_PORT_2 == 1 + +#if CONFIG_UART_SAM_PORT_2_BAUD_RATE == 0 +#error "CONFIG_UART_SAM_PORT_2_BAUD_RATE has to be bigger than 0" +#endif + +#endif + +#if CONFIG_UART_SAM_PORT_3 == 1 + +#if CONFIG_UART_SAM_PORT_3_BAUD_RATE == 0 +#error "CONFIG_UART_SAM_PORT_3_BAUD_RATE has to be bigger than 0" +#endif + +#endif + +#if CONFIG_UART_SAM_PORT_4 == 1 + +#if CONFIG_UART_SAM_PORT_4_BAUD_RATE == 0 +#error "CONFIG_UART_SAM_PORT_4_BAUD_RATE has to be bigger than 0" +#endif + +#endif + +/* Device constant configuration parameters */ +struct uart_sam_dev_cfg { + Uart *regs; + uint32_t periph_id; + struct soc_gpio_pin pin_rx; + struct soc_gpio_pin pin_tx; +}; + +/* Device run time data */ +struct uart_sam_dev_data { + uint32_t baud_rate; +}; + +#define DEV_CFG(dev) \ + ((const struct uart_sam_dev_cfg *const)(dev)->config->config_info) +#define DEV_DATA(dev) \ + ((struct uart_sam_dev_data *const)(dev)->driver_data) + + +static int baudrate_set(Uart *const uart, uint32_t baudrate, + uint32_t mck_freq_hz); + + +static int uart_sam_init(struct device *dev) +{ + int retval; + const struct uart_sam_dev_cfg *const cfg = DEV_CFG(dev); + struct uart_sam_dev_data *const dev_data = DEV_DATA(dev); + Uart *const uart = cfg->regs; + + /* Enable UART clock in PMC */ + soc_pmc_peripheral_enable(cfg->periph_id); + + /* Connect pins to the peripheral */ + soc_gpio_configure(&cfg->pin_rx); + soc_gpio_configure(&cfg->pin_tx); + + /* Reset and disable UART */ + uart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX + | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA; + + /* Disable Interrupts */ + uart->UART_IDR = 0xFFFFFFFF; + + /* 8 bits of data, no parity, 1 stop bit in normal mode, baud rate + * driven by the peripheral clock, UART does not filter the receive line + */ + uart->UART_MR = UART_MR_PAR_NO + | UART_MR_CHMODE_NORMAL; + + /* Set baud rate */ + retval = baudrate_set(uart, dev_data->baud_rate, + SOC_ATMEL_SAM_MCK_FREQ_HZ); + if (retval != 0) { + return retval; + }; + + /* Enable receiver and transmitter */ + uart->UART_CR = UART_CR_RXEN | UART_CR_TXEN; + + return 0; +} + +static int uart_sam_poll_in(struct device *dev, unsigned char *c) +{ + Uart *const uart = DEV_CFG(dev)->regs; + + if (!(uart->UART_SR & UART_SR_RXRDY)) { + return -EBUSY; + } + + /* got a character */ + *c = (unsigned char)uart->UART_RHR; + + return 0; +} + +static unsigned char uart_sam_poll_out(struct device *dev, unsigned char c) +{ + Uart *const uart = DEV_CFG(dev)->regs; + + /* Wait for transmitter to be ready */ + while (!(uart->UART_SR & UART_SR_TXRDY)) + ; + + /* send a character */ + uart->UART_THR = (uint32_t)c; + return c; +} + +static int baudrate_set(Uart *const uart, uint32_t baudrate, + uint32_t mck_freq_hz) +{ + uint32_t divisor; + + __ASSERT(baudrate, + "baud rate has to be bigger than 0"); + __ASSERT(mck_freq_hz/16 >= baudrate, + "MCK frequency is too small to set required baud rate"); + + divisor = mck_freq_hz / 16 / baudrate; + + if (divisor > 0xFFFF) { + return -EINVAL; + }; + + uart->UART_BRGR = UART_BRGR_CD(divisor); + + return 0; +} + +static const struct uart_driver_api uart_sam_driver_api = { + .poll_in = uart_sam_poll_in, + .poll_out = uart_sam_poll_out, +}; + +/* UART0 */ + +#ifdef CONFIG_UART_SAM_PORT_0 +static const struct uart_sam_dev_cfg uart0_sam_config = { + .regs = UART0, + .periph_id = ID_UART0, + .pin_rx = PIN_UART0_RXD, + .pin_tx = PIN_UART0_TXD, +}; + +static struct uart_sam_dev_data uart0_sam_data = { + .baud_rate = CONFIG_UART_SAM_PORT_0_BAUD_RATE, +}; + +DEVICE_AND_API_INIT(uart0_sam, CONFIG_UART_SAM_PORT_0_NAME, &uart_sam_init, + &uart0_sam_data, &uart0_sam_config, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &uart_sam_driver_api); +#endif + +/* UART1 */ + +#ifdef CONFIG_UART_SAM_PORT_1 +static const struct uart_sam_dev_cfg uart1_sam_config = { + .regs = UART1, + .periph_id = ID_UART1, + .pin_rx = PIN_UART1_RXD, + .pin_tx = PIN_UART1_TXD, +}; + +static struct uart_sam_dev_data uart1_sam_data = { + .baud_rate = CONFIG_UART_SAM_PORT_1_BAUD_RATE, +}; + +DEVICE_AND_API_INIT(uart1_sam, CONFIG_UART_SAM_PORT_1_NAME, &uart_sam_init, + &uart1_sam_data, &uart1_sam_config, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &uart_sam_driver_api); +#endif + +/* UART2 */ + +#ifdef CONFIG_UART_SAM_PORT_2 +static const struct uart_sam_dev_cfg uart2_sam_config = { + .regs = UART2, + .periph_id = ID_UART2, + .pin_rx = PIN_UART2_RXD, + .pin_tx = PIN_UART2_TXD, +}; + +static struct uart_sam_dev_data uart2_sam_data = { + .baud_rate = CONFIG_UART_SAM_PORT_2_BAUD_RATE, +}; + +DEVICE_AND_API_INIT(uart2_sam, CONFIG_UART_SAM_PORT_2_NAME, &uart_sam_init, + &uart2_sam_data, &uart2_sam_config, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &uart_sam_driver_api); +#endif + +/* UART3 */ + +#ifdef CONFIG_UART_SAM_PORT_3 +static const struct uart_sam_dev_cfg uart3_sam_config = { + .regs = UART3, + .periph_id = ID_UART3, + .pin_rx = PIN_UART3_RXD, + .pin_tx = PIN_UART3_TXD, +}; + +static struct uart_sam_dev_data uart3_sam_data = { + .baud_rate = CONFIG_UART_SAM_PORT_3_BAUD_RATE, +}; + +DEVICE_AND_API_INIT(uart3_sam, CONFIG_UART_SAM_PORT_3_NAME, &uart_sam_init, + &uart3_sam_data, &uart3_sam_config, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &uart_sam_driver_api); +#endif + +/* UART4 */ + +#ifdef CONFIG_UART_SAM_PORT_4 +static const struct uart_sam_dev_cfg uart4_sam_config = { + .regs = UART4, + .periph_id = ID_UART4, + .pin_rx = PIN_UART4_RXD, + .pin_tx = PIN_UART4_TXD, +}; + +static struct uart_sam_dev_data uart4_sam_data = { + .baud_rate = CONFIG_UART_SAM_PORT_4_BAUD_RATE, +}; + +DEVICE_AND_API_INIT(uart4_sam, CONFIG_UART_SAM_PORT_4_NAME, &uart_sam_init, + &uart4_sam_data, &uart4_sam_config, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &uart_sam_driver_api); +#endif