drivers: serial: uart_sam0: Fix async tx done event triggering to early.

uart_sam0_dma_tx_done callback triggers when the last byte
is transferred from the tx sram buffer to the sercom DATA register.
However the byte has yet to be transmitted completely which can lead to
incorrect event handling if UART_TX_DONE is expected to signal
the end of transmission.

Signed-off-by: Ron Smith <rockyowl171@gmail.com>
This commit is contained in:
Ron Smith 2021-08-28 19:50:09 -04:00 committed by Christopher Friedt
parent a0d92453d8
commit 683dbc4573

View file

@ -139,28 +139,11 @@ static void uart_sam0_dma_tx_done(const struct device *dma_dev, void *arg,
struct uart_sam0_dev_data *const dev_data =
(struct uart_sam0_dev_data *const) arg;
const struct device *dev = dev_data->dev;
const struct uart_sam0_dev_cfg *const cfg = dev_data->cfg;
k_work_cancel_delayable(&dev_data->tx_timeout_work);
SercomUsart * const regs = cfg->regs;
int key = irq_lock();
struct uart_event evt = {
.type = UART_TX_DONE,
.data.tx = {
.buf = dev_data->tx_buf,
.len = dev_data->tx_len,
},
};
dev_data->tx_buf = NULL;
dev_data->tx_len = 0U;
if (evt.data.tx.len != 0U && dev_data->async_cb) {
dev_data->async_cb(dev, &evt, dev_data->async_cb_data);
}
irq_unlock(key);
regs->INTENSET.reg = SERCOM_USART_INTENSET_TXC;
}
static int uart_sam0_tx_halt(struct uart_sam0_dev_data *dev_data)
@ -729,6 +712,31 @@ static void uart_sam0_isr(const struct device *dev)
const struct uart_sam0_dev_cfg *const cfg = DEV_CFG(dev);
SercomUsart * const regs = cfg->regs;
if (dev_data->tx_len && regs->INTFLAG.bit.TXC) {
regs->INTENCLR.reg = SERCOM_USART_INTENCLR_TXC;
k_work_cancel_delayable(&dev_data->tx_timeout_work);
int key = irq_lock();
struct uart_event evt = {
.type = UART_TX_DONE,
.data.tx = {
.buf = dev_data->tx_buf,
.len = dev_data->tx_len,
},
};
dev_data->tx_buf = NULL;
dev_data->tx_len = 0U;
if (evt.data.tx.len != 0U && dev_data->async_cb) {
dev_data->async_cb(dev, &evt, dev_data->async_cb_data);
}
irq_unlock(key);
}
if (dev_data->rx_len && regs->INTFLAG.bit.RXC &&
dev_data->rx_waiting_for_irq) {
dev_data->rx_waiting_for_irq = false;