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:
parent
7ecc55ac84
commit
751efe1f6d
2 changed files with 198 additions and 17 deletions
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue