You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
9.0 KiB
356 lines
9.0 KiB
/* |
|
* Copyright (c) 2017, Linaro Ltd |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#define DT_DRV_COMPAT ti_msp432p4xx_uart |
|
|
|
/* See www.ti.com/lit/pdf/slau356f, Chapter 22, for MSP432P4XX UART info. */ |
|
|
|
/* include driverlib/gpio.h (from the msp432p4xx SDK) before Z's uart.h so |
|
* that the definition of BIT is not overridden */ |
|
#include <driverlib/gpio.h> |
|
|
|
#include <zephyr/drivers/uart.h> |
|
|
|
/* Driverlib includes */ |
|
#include <driverlib/rom.h> |
|
#include <driverlib/rom_map.h> |
|
#include <driverlib/uart.h> |
|
#include <zephyr/irq.h> |
|
|
|
struct uart_msp432p4xx_config { |
|
unsigned long base; |
|
}; |
|
|
|
struct uart_msp432p4xx_dev_data_t { |
|
/* UART config structure */ |
|
eUSCI_UART_Config uartConfig; |
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN |
|
uart_irq_callback_user_data_t cb; /**< Callback function pointer */ |
|
void *cb_data; /**< Callback function arg */ |
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ |
|
}; |
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN |
|
static void uart_msp432p4xx_isr(const struct device *dev); |
|
#endif |
|
|
|
static const struct uart_msp432p4xx_config uart_msp432p4xx_dev_cfg_0 = { |
|
.base = DT_INST_REG_ADDR(0), |
|
}; |
|
|
|
static struct uart_msp432p4xx_dev_data_t uart_msp432p4xx_dev_data_0 = { |
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN |
|
.cb = NULL, |
|
#endif |
|
}; |
|
|
|
static int baudrate_set(eUSCI_UART_Config *config, uint32_t baudrate) |
|
{ |
|
uint16_t prescalar; |
|
uint8_t first_mod_reg, second_mod_reg; |
|
|
|
switch (baudrate) { |
|
case 1200: |
|
prescalar = 2500U; |
|
first_mod_reg = 0U; |
|
second_mod_reg = 0U; |
|
break; |
|
case 2400: |
|
prescalar = 1250U; |
|
first_mod_reg = 0U; |
|
second_mod_reg = 0U; |
|
break; |
|
case 4800: |
|
prescalar = 625U; |
|
first_mod_reg = 0U; |
|
second_mod_reg = 0U; |
|
break; |
|
case 9600: |
|
prescalar = 312U; |
|
first_mod_reg = 8U; |
|
second_mod_reg = 0U; |
|
break; |
|
case 19200: |
|
prescalar = 156U; |
|
first_mod_reg = 4U; |
|
second_mod_reg = 0U; |
|
break; |
|
case 38400: |
|
prescalar = 78U; |
|
first_mod_reg = 2U; |
|
second_mod_reg = 0U; |
|
break; |
|
case 57600: |
|
prescalar = 52U; |
|
first_mod_reg = 1U; |
|
second_mod_reg = 37U; |
|
break; |
|
case 115200: |
|
prescalar = 26U; |
|
first_mod_reg = 0U; |
|
second_mod_reg = 111U; |
|
break; |
|
case 230400: |
|
prescalar = 13U; |
|
first_mod_reg = 0U; |
|
second_mod_reg = 37U; |
|
break; |
|
case 460800: |
|
prescalar = 6U; |
|
first_mod_reg = 8U; |
|
second_mod_reg = 32U; |
|
break; |
|
default: |
|
return -EINVAL; |
|
} |
|
|
|
config->clockPrescalar = prescalar; |
|
config->firstModReg = first_mod_reg; |
|
config->secondModReg = second_mod_reg; |
|
|
|
return 0; |
|
} |
|
|
|
static int uart_msp432p4xx_init(const struct device *dev) |
|
{ |
|
int err; |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
eUSCI_UART_Config UartConfig; |
|
|
|
/* Select P1.2 and P1.3 in UART mode */ |
|
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, |
|
(GPIO_PIN2 | GPIO_PIN3), GPIO_PRIMARY_MODULE_FUNCTION); |
|
|
|
UartConfig.selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK; |
|
UartConfig.parity = EUSCI_A_UART_NO_PARITY; |
|
UartConfig.msborLsbFirst = EUSCI_A_UART_LSB_FIRST; |
|
UartConfig.numberofStopBits = EUSCI_A_UART_ONE_STOP_BIT; |
|
UartConfig.uartMode = EUSCI_A_UART_MODE; |
|
UartConfig.overSampling = EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION; |
|
|
|
/* Baud rate settings calculated for 48MHz */ |
|
err = baudrate_set(&UartConfig, DT_INST_PROP(0, current_speed)); |
|
if (err) { |
|
return err; |
|
} |
|
/* Configure UART Module */ |
|
MAP_UART_initModule(config->base, &UartConfig); |
|
|
|
/* Enable UART module */ |
|
MAP_UART_enableModule(config->base); |
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN |
|
IRQ_CONNECT(DT_INST_IRQN(0), |
|
DT_INST_IRQ(0, priority), |
|
uart_msp432p4xx_isr, DEVICE_DT_INST_GET(0), |
|
0); |
|
irq_enable(DT_INST_IRQN(0)); |
|
|
|
#endif |
|
return 0; |
|
} |
|
|
|
static int uart_msp432p4xx_poll_in(const struct device *dev, unsigned char *c) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
|
|
*c = MAP_UART_receiveData(config->base); |
|
|
|
return 0; |
|
} |
|
|
|
static void uart_msp432p4xx_poll_out(const struct device *dev, |
|
unsigned char c) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
|
|
MAP_UART_transmitData(config->base, c); |
|
} |
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN |
|
static int uart_msp432p4xx_fifo_fill(const struct device *dev, |
|
const uint8_t *tx_data, int size) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
unsigned int num_tx = 0U; |
|
|
|
while ((size - num_tx) > 0) { |
|
MAP_UART_transmitData(config->base, tx_data[num_tx]); |
|
if (MAP_UART_getInterruptStatus(config->base, |
|
EUSCI_A_UART_TRANSMIT_COMPLETE_INTERRUPT_FLAG)) { |
|
num_tx++; |
|
} else { |
|
break; |
|
} |
|
} |
|
|
|
return (int)num_tx; |
|
} |
|
|
|
static int uart_msp432p4xx_fifo_read(const struct device *dev, |
|
uint8_t *rx_data, |
|
const int size) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
unsigned int num_rx = 0U; |
|
|
|
while (((size - num_rx) > 0) && |
|
MAP_UART_getInterruptStatus( |
|
config->base, EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)) { |
|
|
|
rx_data[num_rx++] = MAP_UART_receiveData(config->base); |
|
} |
|
|
|
return num_rx; |
|
} |
|
|
|
static void uart_msp432p4xx_irq_tx_enable(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
|
|
MAP_UART_enableInterrupt(config->base, EUSCI_A_UART_TRANSMIT_INTERRUPT); |
|
} |
|
|
|
static void uart_msp432p4xx_irq_tx_disable(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
|
|
MAP_UART_disableInterrupt(config->base, |
|
EUSCI_A_UART_TRANSMIT_INTERRUPT); |
|
} |
|
|
|
static int uart_msp432p4xx_irq_tx_ready(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
unsigned int int_status; |
|
|
|
int_status = MAP_UART_getInterruptStatus( |
|
config->base, EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG); |
|
|
|
return (int_status & EUSCI_A_IE_TXIE); |
|
} |
|
|
|
static void uart_msp432p4xx_irq_rx_enable(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
|
|
MAP_UART_enableInterrupt(config->base, EUSCI_A_UART_RECEIVE_INTERRUPT); |
|
} |
|
|
|
static void uart_msp432p4xx_irq_rx_disable(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
|
|
MAP_UART_disableInterrupt(config->base, EUSCI_A_UART_RECEIVE_INTERRUPT); |
|
} |
|
|
|
static int uart_msp432p4xx_irq_tx_complete(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
|
|
return MAP_UART_getInterruptStatus( |
|
config->base, EUSCI_A_UART_TRANSMIT_COMPLETE_INTERRUPT_FLAG); |
|
} |
|
|
|
static int uart_msp432p4xx_irq_rx_ready(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
unsigned int int_status; |
|
|
|
int_status = MAP_UART_getInterruptStatus( |
|
config->base, EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG); |
|
|
|
return (int_status & EUSCI_A_IE_RXIE); |
|
} |
|
|
|
static void uart_msp432p4xx_irq_err_enable(const struct device *dev) |
|
{ |
|
/* Not yet used in zephyr */ |
|
} |
|
|
|
static void uart_msp432p4xx_irq_err_disable(const struct device *dev) |
|
{ |
|
/* Not yet used in zephyr */ |
|
} |
|
|
|
static int uart_msp432p4xx_irq_is_pending(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
unsigned int int_status; |
|
|
|
int_status = MAP_UART_getEnabledInterruptStatus(config->base); |
|
|
|
return (int_status & (EUSCI_A_IE_TXIE | EUSCI_A_IE_RXIE)); |
|
} |
|
|
|
static int uart_msp432p4xx_irq_update(const struct device *dev) |
|
{ |
|
return 1; |
|
} |
|
|
|
static void uart_msp432p4xx_irq_callback_set(const struct device *dev, |
|
uart_irq_callback_user_data_t cb, |
|
void *cb_data) |
|
{ |
|
struct uart_msp432p4xx_dev_data_t * const dev_data = dev->data; |
|
|
|
dev_data->cb = cb; |
|
dev_data->cb_data = cb_data; |
|
} |
|
|
|
/** |
|
* @brief Interrupt service routine. |
|
* |
|
* This simply calls the callback function, if one exists. |
|
* |
|
* @param arg Argument to ISR. |
|
*/ |
|
static void uart_msp432p4xx_isr(const struct device *dev) |
|
{ |
|
const struct uart_msp432p4xx_config *config = dev->config; |
|
struct uart_msp432p4xx_dev_data_t * const dev_data = dev->data; |
|
unsigned int int_status; |
|
|
|
int_status = MAP_UART_getEnabledInterruptStatus(config->base); |
|
|
|
if (dev_data->cb) { |
|
dev_data->cb(dev, dev_data->cb_data); |
|
} |
|
/* |
|
* Clear interrupts only after cb called, as Zephyr UART clients expect |
|
* to check interrupt status during the callback. |
|
*/ |
|
MAP_UART_disableInterrupt(config->base, int_status); |
|
} |
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ |
|
|
|
static DEVICE_API(uart, uart_msp432p4xx_driver_api) = { |
|
.poll_in = uart_msp432p4xx_poll_in, |
|
.poll_out = uart_msp432p4xx_poll_out, |
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN |
|
.fifo_fill = uart_msp432p4xx_fifo_fill, |
|
.fifo_read = uart_msp432p4xx_fifo_read, |
|
.irq_tx_enable = uart_msp432p4xx_irq_tx_enable, |
|
.irq_tx_disable = uart_msp432p4xx_irq_tx_disable, |
|
.irq_tx_ready = uart_msp432p4xx_irq_tx_ready, |
|
.irq_rx_enable = uart_msp432p4xx_irq_rx_enable, |
|
.irq_rx_disable = uart_msp432p4xx_irq_rx_disable, |
|
.irq_tx_complete = uart_msp432p4xx_irq_tx_complete, |
|
.irq_rx_ready = uart_msp432p4xx_irq_rx_ready, |
|
.irq_err_enable = uart_msp432p4xx_irq_err_enable, |
|
.irq_err_disable = uart_msp432p4xx_irq_err_disable, |
|
.irq_is_pending = uart_msp432p4xx_irq_is_pending, |
|
.irq_update = uart_msp432p4xx_irq_update, |
|
.irq_callback_set = uart_msp432p4xx_irq_callback_set, |
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ |
|
}; |
|
|
|
DEVICE_DT_INST_DEFINE(0, |
|
uart_msp432p4xx_init, NULL, |
|
&uart_msp432p4xx_dev_data_0, |
|
&uart_msp432p4xx_dev_cfg_0, |
|
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, |
|
(void *)&uart_msp432p4xx_driver_api);
|
|
|