From 0bb40e42b6df64976e56ef2b9388f9002e5e2014 Mon Sep 17 00:00:00 2001 From: Kuba Sanak Date: Thu, 16 Apr 2020 13:23:40 +0100 Subject: [PATCH] drivers: uart: samd0: add missing .configure API functionality The UART driver for samd0 was is missing the .configure and .config_get functionality expected from api for serial driver. This commit fixes this by providing basic configuration Signed-off-by: Kuba Sanak --- drivers/serial/uart_sam0.c | 122 +++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/drivers/serial/uart_sam0.c b/drivers/serial/uart_sam0.c index 41d87bf2b9f665..aa20bdede3d022 100644 --- a/drivers/serial/uart_sam0.c +++ b/drivers/serial/uart_sam0.c @@ -11,6 +11,7 @@ #include #include #include +#include #ifndef SERCOM_USART_CTRLA_MODE_USART_INT_CLK #define SERCOM_USART_CTRLA_MODE_USART_INT_CLK SERCOM_USART_CTRLA_MODE(0x1) @@ -42,6 +43,7 @@ struct uart_sam0_dev_cfg { /* Device run time data */ struct uart_sam0_dev_data { + struct uart_config config_cache; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_callback_user_data_t cb; void *cb_data; @@ -111,6 +113,7 @@ static int uart_sam0_set_baudrate(SercomUsart *const usart, u32_t baudrate, return 0; } + #if CONFIG_UART_ASYNC_API static void uart_sam0_dma_tx_done(void *arg, u32_t id, int error_code) @@ -377,10 +380,121 @@ static void uart_sam0_rx_timeout(struct k_work *work) #endif +static int uart_sam0_configure(struct device *dev, + const struct uart_config *new_cfg) +{ + int retval; + + const struct uart_sam0_dev_cfg *const cfg = DEV_CFG(dev); + struct uart_sam0_dev_data *const dev_data = DEV_DATA(dev); + SercomUsart * const usart = cfg->regs; + + wait_synchronization(usart); + + usart->CTRLA.bit.ENABLE = 0; + wait_synchronization(usart); + + if (new_cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) { + /* Flow control not yet supported though in principle possible + * on this soc family. + */ + return -ENOTSUP; + } + + dev_data->config_cache.flow_ctrl = new_cfg->flow_ctrl; + + SERCOM_USART_CTRLA_Type CTRLA_temp = usart->CTRLA; + SERCOM_USART_CTRLB_Type CTRLB_temp = usart->CTRLB; + + switch (new_cfg->parity) { + case UART_CFG_PARITY_NONE: + CTRLA_temp.bit.FORM = 0x0; + break; + case UART_CFG_PARITY_ODD: + CTRLA_temp.bit.FORM = 0x1; + CTRLB_temp.bit.PMODE = 1; + break; + case UART_CFG_PARITY_EVEN: + CTRLA_temp.bit.FORM = 0x1; + CTRLB_temp.bit.PMODE = 0; + break; + default: + return -ENOTSUP; + } + + dev_data->config_cache.parity = new_cfg->parity; + + switch (new_cfg->stop_bits) { + case UART_CFG_STOP_BITS_1: + CTRLB_temp.bit.SBMODE = 0; + break; + case UART_CFG_STOP_BITS_2: + CTRLB_temp.bit.SBMODE = 1; + break; + default: + return -ENOTSUP; + } + + dev_data->config_cache.stop_bits = new_cfg->stop_bits; + + switch (new_cfg->data_bits) { + case UART_CFG_DATA_BITS_5: + CTRLB_temp.bit.CHSIZE = 0x5; + break; + case UART_CFG_DATA_BITS_6: + CTRLB_temp.bit.CHSIZE = 0x6; + break; + case UART_CFG_DATA_BITS_7: + CTRLB_temp.bit.CHSIZE = 0x7; + break; + case UART_CFG_DATA_BITS_8: + CTRLB_temp.bit.CHSIZE = 0x0; + break; + case UART_CFG_DATA_BITS_9: + CTRLB_temp.bit.CHSIZE = 0x1; + break; + default: + return -ENOTSUP; + } + + dev_data->config_cache.data_bits = new_cfg->data_bits; + + usart->CTRLA = CTRLA_temp; + wait_synchronization(usart); + + usart->CTRLB = CTRLB_temp; + wait_synchronization(usart); + + retval = uart_sam0_set_baudrate(usart, new_cfg->baudrate, + SOC_ATMEL_SAM0_GCLK0_FREQ_HZ); + if (retval != 0) { + return retval; + } + + dev_data->config_cache.baudrate = new_cfg->baudrate; + + usart->CTRLA.bit.ENABLE = 1; + wait_synchronization(usart); + + return 0; +} + +static int uart_sam0_config_get(struct device *dev, + struct uart_config *out_cfg) +{ + struct uart_sam0_dev_data *const dev_data = DEV_DATA(dev); + memcpy(out_cfg, &(dev_data->config_cache), + sizeof(dev_data->config_cache)); + + return 0; +} + static int uart_sam0_init(struct device *dev) { int retval; const struct uart_sam0_dev_cfg *const cfg = DEV_CFG(dev); + struct uart_sam0_dev_data *const dev_data = DEV_DATA(dev); + SercomUsart *const usart = cfg->regs; #ifdef MCLK @@ -416,6 +530,11 @@ static int uart_sam0_init(struct device *dev) SERCOM_USART_CTRLA_CPOL | SERCOM_USART_CTRLA_DORD; wait_synchronization(usart); + dev_data->config_cache.flow_ctrl = UART_CFG_FLOW_CTRL_NONE; + dev_data->config_cache.parity = UART_CFG_PARITY_NONE; + dev_data->config_cache.stop_bits = UART_CFG_STOP_BITS_1; + dev_data->config_cache.data_bits = UART_CFG_DATA_BITS_8; + /* Enable receiver and transmitter */ usart->CTRLB.reg = SERCOM_USART_CTRLB_CHSIZE(0) | SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN; @@ -426,6 +545,7 @@ static int uart_sam0_init(struct device *dev) if (retval != 0) { return retval; } + dev_data->config_cache.data_bits = cfg->baudrate; #if CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API cfg->irq_config_func(dev); @@ -900,6 +1020,8 @@ static int uart_sam0_rx_disable(struct device *dev) static const struct uart_driver_api uart_sam0_driver_api = { .poll_in = uart_sam0_poll_in, .poll_out = uart_sam0_poll_out, + .configure = uart_sam0_configure, + .config_get = uart_sam0_config_get, #if CONFIG_UART_INTERRUPT_DRIVEN .fifo_fill = uart_sam0_fifo_fill, .fifo_read = uart_sam0_fifo_read,