drivers: uart_gecko: added support for hardware flow control

Added support for hardware flow control in EFM32 UART driver.

Signed-off-by: Timo Dammes <timo.dammes@lemonbeat.com>
Signed-off-by: Christian Taedcke <christian.taedcke@lemonbeat.com>
This commit is contained in:
Timo Dammes 2019-12-09 15:46:24 +01:00 committed by Maureen Helm
commit 751efe1f6d
2 changed files with 198 additions and 17 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Christian Taedcke
* Copyright (c) 2020 Lemonbeat GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -18,18 +19,71 @@
#define CLOCK_USART(id) CLOCK_ID_PRFX(USART_PREFIX, id)
#define CLOCK_UART(id) CLOCK_ID_PRFX(UART_PREFIX, id)
/* Helper define to determine if SOC supports hardware flow control */
#if ((_SILICON_LABS_32B_SERIES > 0) || \
(defined(_USART_ROUTEPEN_RTSPEN_MASK) && \
defined(_USART_ROUTEPEN_CTSPEN_MASK)))
#define HW_FLOWCONTROL_IS_SUPPORTED_BY_SOC
#endif
#define HAS_HFC_OR(inst) DT_INST_PROP(inst, hw_flow_control) ||
#define DT_DRV_COMPAT silabs_gecko_uart
/* Has any enabled uart instance hw-flow-control enabled? */
#define UART_GECKO_UART_HW_FLOW_CONTROL_ENABLED \
DT_INST_FOREACH_STATUS_OKAY(HAS_HFC_OR) 0
#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT silabs_gecko_usart
/* Has any enabled usart instance hw-flow-control enabled? */
#define UART_GECKO_USART_HW_FLOW_CONTROL_ENABLED \
DT_INST_FOREACH_STATUS_OKAY(HAS_HFC_OR) 0
#if UART_GECKO_USART_HW_FLOW_CONTROL_ENABLED || \
UART_GECKO_UART_HW_FLOW_CONTROL_ENABLED
#define UART_GECKO_HW_FLOW_CONTROL
#endif
/* Sanity check for hardware flow control */
#if defined(UART_GECKO_HW_FLOW_CONTROL) && \
(!(defined(HW_FLOWCONTROL_IS_SUPPORTED_BY_SOC)))
#error "Hardware flow control is activated for at least one UART/USART, \
but not supported by this SOC"
#endif
#if defined(UART_GECKO_HW_FLOW_CONTROL) && \
(!defined(CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION))
#error "Driver not supporting hardware flow control for this SOC"
#endif
/**
* @brief Config struct for UART
*/
struct uart_gecko_config {
USART_TypeDef *base;
CMU_Clock_TypeDef clock;
uint32_t baud_rate;
#ifdef UART_GECKO_HW_FLOW_CONTROL
bool hw_flowcontrol;
#endif
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
void (*irq_config_func)(struct device *dev);
#endif
struct soc_gpio_pin pin_rx;
struct soc_gpio_pin pin_tx;
#ifdef UART_GECKO_HW_FLOW_CONTROL
struct soc_gpio_pin pin_rts;
struct soc_gpio_pin pin_cts;
#endif
#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION
uint8_t loc_rx;
uint8_t loc_tx;
#ifdef UART_GECKO_HW_FLOW_CONTROL
uint8_t loc_rts;
uint8_t loc_cts;
#endif
#else
uint8_t loc;
#endif
@ -234,19 +288,28 @@ static void uart_gecko_isr(void *arg)
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
/**
* @brief Subroutine initializer of UART pins
*
* @param dev UART device to configure
*/
static void uart_gecko_init_pins(struct device *dev)
{
const struct uart_gecko_config *config = dev->config;
/* Configure RX and TX */
soc_gpio_configure(&config->pin_rx);
soc_gpio_configure(&config->pin_tx);
#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION
/* For SOCs with configurable pin locations (set in SOC Kconfig) */
config->base->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
config->base->ROUTELOC0 =
(config->loc_tx << _USART_ROUTELOC0_TXLOC_SHIFT) |
(config->loc_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
config->base->ROUTELOC1 = _USART_ROUTELOC1_RESETVALUE;
#elif defined(USART_ROUTE_RXPEN) && defined(USART_ROUTE_TXPEN)
/* For olders SOCs with only one pin location */
config->base->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN
| (config->loc << 8);
#elif defined(GPIO_USART_ROUTEEN_RXPEN) && defined(GPIO_USART_ROUTEEN_TXPEN)
@ -258,9 +321,48 @@ static void uart_gecko_init_pins(struct device *dev)
GPIO->USARTROUTE[USART_NUM(config->base)].RXROUTE =
(config->pin_rx.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) |
(config->pin_rx.port << _GPIO_USART_RXROUTE_PORT_SHIFT);
#endif
#endif /* CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION */
#ifdef UART_GECKO_HW_FLOW_CONTROL
/* Configure HW flow control (RTS, CTS) */
if (config->hw_flowcontrol) {
soc_gpio_configure(&config->pin_rts);
soc_gpio_configure(&config->pin_cts);
#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION
config->base->ROUTEPEN =
USART_ROUTEPEN_RXPEN |
USART_ROUTEPEN_TXPEN |
USART_ROUTEPEN_RTSPEN |
USART_ROUTEPEN_CTSPEN;
config->base->ROUTELOC1 =
(config->loc_rts << _USART_ROUTELOC1_RTSLOC_SHIFT) |
(config->loc_cts << _USART_ROUTELOC1_CTSLOC_SHIFT);
#elif defined(GPIO_USART_ROUTEEN_RTSPEN) && defined(GPIO_USART_ROUTEEN_CTSPEN)
GPIO->USARTROUTE[USART_NUM(config->base)].ROUTEEN =
GPIO_USART_ROUTEEN_TXPEN |
GPIO_USART_ROUTEEN_RXPEN |
GPIO_USART_ROUTEPEN_RTSPEN |
GPIO_USART_ROUTEPEN_CTSPEN;
GPIO->USARTROUTE[USART_NUM(config->base)].RTSROUTE =
(config->pin_rts.pin << _GPIO_USART_RTSROUTE_PIN_SHIFT) |
(config->pin_rts.port << _GPIO_USART_RTSROUTE_PORT_SHIFT);
GPIO->USARTROUTE[USART_NUM(config->base)].CTSROUTE =
(config->pin_cts.pin << _GPIO_USART_CTSROUTE_PIN_SHIFT) |
(config->pin_cts.port << _GPIO_USART_CTSROUTE_PORT_SHIFT);
#endif /* CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION */
}
#endif /* UART_GECKO_HW_FLOW_CONTROL */
}
/**
* @brief Main initializer for UART
*
* @param dev UART device to be initialized
* @return int 0
*/
static int uart_gecko_init(struct device *dev)
{
const struct uart_gecko_config *config = dev->config;
@ -270,12 +372,15 @@ static int uart_gecko_init(struct device *dev)
* driver
*/
usartInit.baudrate = config->baud_rate;
/* Enable USART clock */
CMU_ClockEnable(config->clock, true);
/* Init USART */
usartInit.baudrate = config->baud_rate;
#ifdef UART_GECKO_HW_FLOW_CONTROL
usartInit.hwFlowControl = config->hw_flowcontrol ?
usartHwFlowControlCtsAndRts : usartHwFlowControlNone;
#endif
USART_InitAsync(config->base, &usartInit);
/* Initialize USART pins */
@ -310,6 +415,7 @@ static const struct uart_driver_api uart_gecko_driver_api = {
#endif
};
#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT silabs_gecko_uart
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
@ -330,21 +436,21 @@ static const struct uart_driver_api uart_gecko_driver_api = {
irq_enable(DT_INST_IRQ_BY_NAME(idx, rx, irq)); \
irq_enable(DT_INST_IRQ_BY_NAME(idx, tx, irq)); \
}
#else
#else /* CONFIG_UART_INTERRUPT_DRIVEN */
#define GECKO_UART_IRQ_HANDLER_DECL(idx)
#define GECKO_UART_IRQ_HANDLER_FUNC(idx)
#define GECKO_UART_IRQ_HANDLER(idx)
#endif
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION
#define GECKO_UART_PIN_LOCATIONS(idx) \
#define GECKO_UART_RX_TX_PIN_LOCATIONS(idx) \
.loc_rx = DT_INST_PROP_BY_IDX(idx, location_rx, 0), \
.loc_tx = DT_INST_PROP_BY_IDX(idx, location_tx, 0),
#define VALIDATE_GECKO_UART_PIN_LOCATIONS(idx)
#define VALIDATE_GECKO_UART_RX_TX_PIN_LOCATIONS(idx)
#else
#define GECKO_UART_PIN_LOCATIONS(idx) \
#define GECKO_UART_RX_TX_PIN_LOCATIONS(idx) \
.loc = DT_INST_PROP_BY_IDX(idx, location_rx, 0),
#define VALIDATE_GECKO_UART_PIN_LOCATIONS(idx) \
#define VALIDATE_GECKO_UART_RX_TX_PIN_LOCATIONS(idx) \
BUILD_ASSERT(DT_INST_PROP_BY_IDX(idx, location_rx, 0) == \
DT_INST_PROP_BY_IDX(idx, location_tx, 0), \
"DTS location-* properties must have identical value")
@ -363,19 +469,81 @@ static const struct uart_driver_api uart_gecko_driver_api = {
gpioModePushPull, 1 \
}
#define GECKO_UART_PINS(idx) \
#define GECKO_UART_RX_TX_PINS(idx) \
.pin_rx = PIN_UART_RXD(idx), \
.pin_tx = PIN_UART_TXD(idx),
#ifdef UART_GECKO_HW_FLOW_CONTROL
#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION
#define GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx) \
.loc_rts = COND_CODE_1(DT_INST_PROP(idx, hw_flow_control), \
(DT_INST_PROP_BY_IDX(idx, location_rts, 0)), \
(0)), \
.loc_cts = COND_CODE_1(DT_INST_PROP(idx, hw_flow_control), \
(DT_INST_PROP_BY_IDX(idx, location_cts, 0)), \
(0)),
#define VALIDATE_GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx) \
COND_CODE_1(DT_INST_PROP(idx, hw_flow_control), \
(BUILD_ASSERT(DT_INST_NODE_HAS_PROP(idx, location_rts) && \
DT_INST_NODE_HAS_PROP(idx, location_cts), \
"DTS location-rts and location-cts are mandatory")), \
())
#else /* CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION */
/* Hardware flow control not supported for these SOCs */
#define GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx)
#define VALIDATE_GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx)
#endif /* CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION */
#define PIN_UART_RTS(idx) \
COND_CODE_1(DT_INST_PROP(idx, hw_flow_control), \
({ \
DT_INST_PROP_BY_IDX(idx, location_rts, 1), \
DT_INST_PROP_BY_IDX(idx, location_rts, 2), \
gpioModePushPull, 1 \
}), \
({0}))
#define PIN_UART_CTS(idx) \
COND_CODE_1(DT_INST_PROP(idx, hw_flow_control), \
({ \
DT_INST_PROP_BY_IDX(idx, location_cts, 1), \
DT_INST_PROP_BY_IDX(idx, location_cts, 2), \
gpioModeInput, 1 \
}), \
({0}))
#define GECKO_UART_RTS_CTS_PINS(idx) \
.pin_rts = PIN_UART_RTS(idx), \
.pin_cts = PIN_UART_CTS(idx),
#define GECKO_UART_HW_FLOW_CONTROL(idx) \
.hw_flowcontrol = DT_INST_PROP(idx, hw_flow_control),
#else /* UART_GECKO_HW_FLOW_CONTROL */
#define GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx)
#define VALIDATE_GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx)
#define GECKO_UART_RTS_CTS_PINS(idx)
#define GECKO_UART_HW_FLOW_CONTROL(idx)
#endif /* UART_GECKO_HW_FLOW_CONTROL */
#define GECKO_UART_INIT(idx) \
VALIDATE_GECKO_UART_RX_TX_PIN_LOCATIONS(idx); \
VALIDATE_GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx); \
\
GECKO_UART_IRQ_HANDLER_DECL(idx); \
\
static const struct uart_gecko_config uart_gecko_cfg_##idx = { \
.base = (USART_TypeDef *)DT_INST_REG_ADDR(idx), \
.clock = CLOCK_UART(DT_INST_PROP(idx, peripheral_id)), \
.baud_rate = DT_INST_PROP(idx, current_speed), \
GECKO_UART_PINS(idx) \
GECKO_UART_PIN_LOCATIONS(idx) \
GECKO_UART_HW_FLOW_CONTROL(idx) \
GECKO_UART_RX_TX_PINS(idx) \
GECKO_UART_RTS_CTS_PINS(idx) \
GECKO_UART_RX_TX_PIN_LOCATIONS(idx) \
GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx) \
GECKO_UART_IRQ_HANDLER_FUNC(idx) \
}; \
\
@ -387,7 +555,6 @@ static const struct uart_driver_api uart_gecko_driver_api = {
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
&uart_gecko_driver_api); \
\
VALIDATE_GECKO_UART_PIN_LOCATIONS(idx); \
\
GECKO_UART_IRQ_HANDLER(idx)
@ -421,14 +588,20 @@ DT_INST_FOREACH_STATUS_OKAY(GECKO_UART_INIT)
#endif
#define GECKO_USART_INIT(idx) \
VALIDATE_GECKO_UART_RX_TX_PIN_LOCATIONS(idx); \
VALIDATE_GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx); \
\
GECKO_USART_IRQ_HANDLER_DECL(idx); \
\
static const struct uart_gecko_config usart_gecko_cfg_##idx = { \
.base = (USART_TypeDef *)DT_INST_REG_ADDR(idx), \
.clock = CLOCK_USART(DT_INST_PROP(idx, peripheral_id)), \
.baud_rate = DT_INST_PROP(idx, current_speed), \
GECKO_UART_PINS(idx) \
GECKO_UART_PIN_LOCATIONS(idx) \
GECKO_UART_HW_FLOW_CONTROL(idx) \
GECKO_UART_RX_TX_PINS(idx) \
GECKO_UART_RTS_CTS_PINS(idx) \
GECKO_UART_RX_TX_PIN_LOCATIONS(idx) \
GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx) \
GECKO_USART_IRQ_HANDLER_FUNC(idx) \
}; \
\
@ -440,8 +613,6 @@ DT_INST_FOREACH_STATUS_OKAY(GECKO_UART_INIT)
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
&uart_gecko_driver_api); \
\
VALIDATE_GECKO_UART_PIN_LOCATIONS(idx); \
\
GECKO_USART_IRQ_HANDLER(idx)
DT_INST_FOREACH_STATUS_OKAY(GECKO_USART_INIT)

View file

@ -28,3 +28,13 @@ properties:
type: array
required: true
description: TX pin configuration defined as <location port pin>
location-rts:
type: array
required: false
description: RTS pin configuration defined as <location port pin>
location-cts:
type: array
required: false
description: CTS pin configuration defined as <location port pin>