drivers: uart_sam0: add error support

Adds support for enabling and detecting errors to uart.

Signed-off-by: Arvin Farahmand <arvinf@ip-logix.com>
This commit is contained in:
Arvin Farahmand 2021-04-16 22:03:29 -04:00 committed by Anas Nashif
commit 008bfeb43e

View file

@ -19,6 +19,14 @@
#define SERCOM_USART_CTRLA_MODE_USART_INT_CLK SERCOM_USART_CTRLA_MODE(0x1)
#endif
/*
* Interrupt error flag is only supported in devices with
* SERCOM revision 0x500
*/
#if defined(SERCOM_U2201) && (REV_SERCOM == 0x500)
#define SERCOM_REV500
#endif
/* Device constant configuration parameters */
struct uart_sam0_dev_cfg {
SercomUsart *regs;
@ -718,42 +726,42 @@ static int uart_sam0_fifo_fill(const struct device *dev,
static void uart_sam0_irq_tx_enable(const struct device *dev)
{
SercomUsart *regs = DEV_CFG(dev)->regs;
SercomUsart * const regs = DEV_CFG(dev)->regs;
regs->INTENSET.reg = SERCOM_USART_INTENCLR_DRE;
}
static void uart_sam0_irq_tx_disable(const struct device *dev)
{
SercomUsart *const regs = DEV_CFG(dev)->regs;
SercomUsart * const regs = DEV_CFG(dev)->regs;
regs->INTENCLR.reg = SERCOM_USART_INTENCLR_DRE;
}
static int uart_sam0_irq_tx_ready(const struct device *dev)
{
SercomUsart *const regs = DEV_CFG(dev)->regs;
SercomUsart * const regs = DEV_CFG(dev)->regs;
return regs->INTFLAG.bit.DRE != 0;
}
static void uart_sam0_irq_rx_enable(const struct device *dev)
{
SercomUsart *const regs = DEV_CFG(dev)->regs;
SercomUsart * const regs = DEV_CFG(dev)->regs;
regs->INTENSET.reg = SERCOM_USART_INTENSET_RXC;
}
static void uart_sam0_irq_rx_disable(const struct device *dev)
{
SercomUsart *const regs = DEV_CFG(dev)->regs;
SercomUsart * const regs = DEV_CFG(dev)->regs;
regs->INTENCLR.reg = SERCOM_USART_INTENCLR_RXC;
}
static int uart_sam0_irq_rx_ready(const struct device *dev)
{
SercomUsart *const regs = DEV_CFG(dev)->regs;
SercomUsart * const regs = DEV_CFG(dev)->regs;
return regs->INTFLAG.bit.RXC != 0;
}
@ -761,7 +769,7 @@ static int uart_sam0_irq_rx_ready(const struct device *dev)
static int uart_sam0_fifo_read(const struct device *dev, uint8_t *rx_data,
const int size)
{
SercomUsart *const regs = DEV_CFG(dev)->regs;
SercomUsart * const regs = DEV_CFG(dev)->regs;
if (regs->INTFLAG.bit.RXC) {
uint8_t ch = regs->DATA.reg;
@ -778,12 +786,79 @@ static int uart_sam0_fifo_read(const struct device *dev, uint8_t *rx_data,
static int uart_sam0_irq_is_pending(const struct device *dev)
{
SercomUsart *const regs = DEV_CFG(dev)->regs;
SercomUsart * const regs = DEV_CFG(dev)->regs;
return (regs->INTENSET.reg & regs->INTFLAG.reg) != 0;
}
static int uart_sam0_irq_update(const struct device *dev) { return 1; }
#if defined(SERCOM_REV500)
static void uart_sam0_irq_err_enable(const struct device *dev)
{
SercomUsart * const regs = DEV_CFG(dev)->regs;
regs->INTENSET.reg |= SERCOM_USART_INTENCLR_ERROR;
wait_synchronization(regs);
}
static void uart_sam0_irq_err_disable(const struct device *dev)
{
SercomUsart * const regs = DEV_CFG(dev)->regs;
regs->INTENCLR.reg |= SERCOM_USART_INTENSET_ERROR;
wait_synchronization(regs);
}
#endif
static int uart_sam0_irq_update(const struct device *dev)
{
/* Clear sticky interrupts */
SercomUsart * const regs = DEV_CFG(dev)->regs;
#if defined(SERCOM_REV500)
regs->INTFLAG.reg |= SERCOM_USART_INTENCLR_ERROR
| SERCOM_USART_INTENCLR_RXBRK
| SERCOM_USART_INTENCLR_CTSIC
| SERCOM_USART_INTENCLR_RXS;
#else
regs->INTFLAG.reg |= SERCOM_USART_INTENCLR_RXS;
#endif
return 1;
}
static int uart_sam0_err_check(const struct device *dev)
{
SercomUsart * const regs = DEV_CFG(dev)->regs;
uint32_t err = 0U;
if (regs->STATUS.reg & SERCOM_USART_STATUS_BUFOVF) {
err |= UART_ERROR_OVERRUN;
}
if (regs->STATUS.reg & SERCOM_USART_STATUS_FERR) {
err |= UART_ERROR_PARITY;
}
if (regs->STATUS.reg & SERCOM_USART_STATUS_PERR) {
err |= UART_ERROR_FRAMING;
}
#if defined(SERCOM_REV500)
if (regs->STATUS.reg & SERCOM_USART_STATUS_ISF) {
err |= UART_BREAK;
}
regs->STATUS.reg |= SERCOM_USART_STATUS_BUFOVF
| SERCOM_USART_STATUS_FERR
| SERCOM_USART_STATUS_PERR
| SERCOM_USART_STATUS_ISF;
#else
regs->STATUS.reg |= SERCOM_USART_STATUS_BUFOVF
| SERCOM_USART_STATUS_FERR
| SERCOM_USART_STATUS_PERR;
#endif
wait_synchronization(regs);
return err;
}
static void uart_sam0_irq_callback_set(const struct device *dev,
uart_irq_callback_user_data_t cb,
@ -962,7 +1037,7 @@ static int uart_sam0_rx_disable(const struct device *dev)
{
struct uart_sam0_dev_data *const dev_data = DEV_DATA(dev);
const struct uart_sam0_dev_cfg *const cfg = DEV_CFG(dev);
SercomUsart *const regs = cfg->regs;
SercomUsart * const regs = cfg->regs;
struct dma_status st;
k_work_cancel_delayable(&dev_data->rx_timeout_work);
@ -1032,6 +1107,7 @@ static const struct uart_driver_api uart_sam0_driver_api = {
.poll_out = uart_sam0_poll_out,
.configure = uart_sam0_configure,
.config_get = uart_sam0_config_get,
.err_check = uart_sam0_err_check,
#if CONFIG_UART_INTERRUPT_DRIVEN
.fifo_fill = uart_sam0_fifo_fill,
.fifo_read = uart_sam0_fifo_read,
@ -1042,6 +1118,10 @@ static const struct uart_driver_api uart_sam0_driver_api = {
.irq_rx_disable = uart_sam0_irq_rx_disable,
.irq_rx_ready = uart_sam0_irq_rx_ready,
.irq_is_pending = uart_sam0_irq_is_pending,
#if defined(SERCOM_REV500)
.irq_err_enable = uart_sam0_irq_err_enable,
.irq_err_disable = uart_sam0_irq_err_disable,
#endif
.irq_update = uart_sam0_irq_update,
.irq_callback_set = uart_sam0_irq_callback_set,
#endif