drivers: serial: gecko: Add device power management

Add basic device power management to USART driver. The initial
implementation only ensures that the TX FIFO is flushed before
allowing the system to go to sleep by polling the TXIDLE status
register.

This fixes an issue where the last 1-2 characters would be lost
if transmitted immediately before going to deep sleep.

Signed-off-by: Aksel Skauge Mellbye <aksel.mellbye@silabs.com>
This commit is contained in:
Aksel Skauge Mellbye 2024-10-21 17:54:06 +02:00 committed by Alberto Escolar
parent e0b748e1ab
commit 00378b56ec
2 changed files with 29 additions and 2 deletions

View File

@ -12,5 +12,6 @@ config UART_GECKO
select SOC_GECKO_USART
select PINCTRL if SOC_FAMILY_SILABS_S1
select CLOCK_CONTROL if SOC_FAMILY_SILABS_S2
select PM_DEVICE if PM && SOC_FAMILY_SILABS_S2
help
Enable the Gecko uart driver.

View File

@ -8,6 +8,7 @@
#include <errno.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/irq.h>
#include <zephyr/pm/device.h>
#include <em_usart.h>
#include <em_cmu.h>
#include <soc.h>
@ -488,6 +489,29 @@ static int uart_gecko_init(const struct device *dev)
return 0;
}
#ifdef CONFIG_PM_DEVICE
static int uart_gecko_pm_action(const struct device *dev, enum pm_device_action action)
{
const struct uart_gecko_config *config = dev->config;
switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
/* Wait for TX FIFO to flush before suspending */
while (!(USART_StatusGet(config->base) & USART_STATUS_TXIDLE)) {
}
break;
case PM_DEVICE_ACTION_RESUME:
break;
default:
return -ENOTSUP;
}
return 0;
}
#endif
static const struct uart_driver_api uart_gecko_driver_api = {
.poll_in = uart_gecko_poll_in,
.poll_out = uart_gecko_poll_out,
@ -686,6 +710,7 @@ DT_INST_FOREACH_STATUS_OKAY(GECKO_UART_INIT)
#define GECKO_USART_INIT(idx) \
PINCTRL_DT_INST_DEFINE(idx); \
GECKO_USART_IRQ_HANDLER_DECL(idx); \
PM_DEVICE_DT_INST_DEFINE(idx, uart_gecko_pm_action); \
\
static const struct uart_gecko_config usart_gecko_cfg_##idx = { \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
@ -697,7 +722,7 @@ DT_INST_FOREACH_STATUS_OKAY(GECKO_UART_INIT)
\
static struct uart_gecko_data usart_gecko_data_##idx; \
\
DEVICE_DT_INST_DEFINE(idx, uart_gecko_init, NULL, \
DEVICE_DT_INST_DEFINE(idx, uart_gecko_init, PM_DEVICE_DT_INST_GET(idx),\
&usart_gecko_data_##idx, \
&usart_gecko_cfg_##idx, PRE_KERNEL_1, \
CONFIG_SERIAL_INIT_PRIORITY, \
@ -710,6 +735,7 @@ DT_INST_FOREACH_STATUS_OKAY(GECKO_UART_INIT)
VALIDATE_GECKO_UART_RTS_CTS_PIN_LOCATIONS(idx); \
\
GECKO_USART_IRQ_HANDLER_DECL(idx); \
PM_DEVICE_DT_INST_DEFINE(idx, uart_gecko_pm_action); \
\
static const struct uart_gecko_config usart_gecko_cfg_##idx = { \
.base = (USART_TypeDef *)DT_INST_REG_ADDR(idx), \
@ -725,7 +751,7 @@ DT_INST_FOREACH_STATUS_OKAY(GECKO_UART_INIT)
\
static struct uart_gecko_data usart_gecko_data_##idx; \
\
DEVICE_DT_INST_DEFINE(idx, uart_gecko_init, NULL, \
DEVICE_DT_INST_DEFINE(idx, uart_gecko_init, PM_DEVICE_DT_INST_GET(idx),\
&usart_gecko_data_##idx, \
&usart_gecko_cfg_##idx, PRE_KERNEL_1, \
CONFIG_SERIAL_INIT_PRIORITY, \