drivers: uart: npcx: use PM constraint for the receiving

In this commit, the driver sets the PM constraint to prevent the system
from entering the suspend state for a CONFIG_UART_CONSOLE_INPUT_EXPIRED
period when data come in. The constraint releases after the
CONFIG_UART_CONSOLE_INPUT_EXPIRED time expires, .

With this change, the PM policy doesn't have to check the timestamp
by calling npcx_power_console_is_in_use() explictly. So the related
npcx_power_console_is_in_use*() functions can be removed.

Signed-off-by: Jun Lin <CHLin56@nuvoton.com>
Signed-off-by: Wealian Liao <WHLIAO@nuvoton.com>
This commit is contained in:
Jun Lin 2021-12-03 14:52:27 +08:00 committed by Carles Cufí
commit db74010cc7
3 changed files with 59 additions and 65 deletions

View file

@ -32,6 +32,13 @@ struct uart_npcx_config {
const struct npcx_alt *alts_list;
};
enum uart_pm_constraint_flag {
UART_PM_CONSTRAINT_TX_FLAG,
UART_PM_CONSTRAINT_RX_FLAG,
UART_PM_CONSTRAINT_FLAG_COUNT,
};
/* Driver data */
struct uart_npcx_data {
/* Baud rate */
@ -42,7 +49,10 @@ struct uart_npcx_data {
void *user_data;
#endif
#ifdef CONFIG_PM
atomic_t pm_constraint_on;
ATOMIC_DEFINE(pm_constraint_flag, UART_PM_CONSTRAINT_FLAG_COUNT);
#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
struct k_work_delayable rx_refresh_timeout_work;
#endif
#endif
};
@ -57,20 +67,18 @@ struct uart_npcx_data {
(struct uart_reg *)(DRV_CONFIG(dev)->uconf.base)
#if defined(CONFIG_PM) && defined(CONFIG_UART_INTERRUPT_DRIVEN)
static void uart_npcx_pm_constraint_set(const struct device *dev)
static void uart_npcx_pm_constraint_set(struct uart_npcx_data *data,
enum uart_pm_constraint_flag flag)
{
struct uart_npcx_data *data = DRV_DATA(dev);
if (atomic_set(&data->pm_constraint_on, 1) == 0) {
if (atomic_test_and_set_bit(data->pm_constraint_flag, flag) == 0) {
pm_constraint_set(PM_STATE_SUSPEND_TO_IDLE);
}
}
static void uart_npcx_pm_constraint_release(const struct device *dev)
static void uart_npcx_pm_constraint_rel(struct uart_npcx_data *data,
enum uart_pm_constraint_flag flag)
{
struct uart_npcx_data *data = DRV_DATA(dev);
if (atomic_clear(&data->pm_constraint_on) == 1) {
if (atomic_test_and_clear_bit(data->pm_constraint_flag, flag) == 1) {
pm_constraint_release(PM_STATE_SUSPEND_TO_IDLE);
}
}
@ -146,7 +154,9 @@ static int uart_npcx_fifo_fill(const struct device *dev,
while ((size - tx_bytes > 0) && uart_npcx_tx_fifo_ready(dev)) {
/* Put a character into Tx FIFO */
#ifdef CONFIG_PM
uart_npcx_pm_constraint_set(dev);
struct uart_npcx_data *data = DRV_DATA(dev);
uart_npcx_pm_constraint_set(data, UART_PM_CONSTRAINT_TX_FLAG);
inst->UTBUF = tx_data[tx_bytes++];
inst->UFTCTL |= BIT(NPCX_UFTCTL_NXMIP_EN);
#else
@ -259,11 +269,19 @@ static void uart_npcx_isr(const struct device *dev)
{
struct uart_npcx_data *data = DRV_DATA(dev);
/* Refresh console expired time if got UART Rx event */
if (IS_ENABLED(CONFIG_UART_CONSOLE_INPUT_EXPIRED) &&
uart_npcx_irq_rx_ready(dev)) {
npcx_power_console_is_in_use_refresh();
/*
* Set pm constraint to prevent the system enter suspend state within
* the CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT period.
*/
#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
if (uart_npcx_irq_rx_ready(dev)) {
k_timeout_t delay =
K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT);
uart_npcx_pm_constraint_set(data, UART_PM_CONSTRAINT_RX_FLAG);
k_work_reschedule(&data->rx_refresh_timeout_work, delay);
}
#endif
if (data->user_cb) {
data->user_cb(dev, data->user_data);
@ -273,7 +291,7 @@ static void uart_npcx_isr(const struct device *dev)
if (IS_BIT_SET(inst->UFTCTL, NPCX_UFTCTL_NXMIP_EN) &&
IS_BIT_SET(inst->UFTSTS, NPCX_UFTSTS_NXMIP)) {
uart_npcx_pm_constraint_release(dev);
uart_npcx_pm_constraint_rel(data, UART_PM_CONSTRAINT_TX_FLAG);
inst->UFTCTL &= ~BIT(NPCX_UFTCTL_NXMIP_EN);
}
#endif /* CONFIG_PM */
@ -353,10 +371,17 @@ static int uart_npcx_err_check(const struct device *dev)
static __unused void uart_npcx_rx_wk_isr(const struct device *dev,
struct npcx_wui *wui)
{
/* Refresh console expired time if got UART Rx wake-up event */
if (IS_ENABLED(CONFIG_UART_CONSOLE_INPUT_EXPIRED)) {
npcx_power_console_is_in_use_refresh();
}
/*
* Set pm constraint to prevent the system enter suspend state within
* the CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT period.
*/
#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
struct uart_npcx_data *data = DRV_DATA(dev);
k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT);
uart_npcx_pm_constraint_set(data, UART_PM_CONSTRAINT_RX_FLAG);
k_work_reschedule(&data->rx_refresh_timeout_work, delay);
#endif
/*
* Disable MIWU CR_SIN interrupt to avoid the other redundant interrupts
@ -365,6 +390,16 @@ static __unused void uart_npcx_rx_wk_isr(const struct device *dev,
npcx_uart_disable_access_interrupt();
}
#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
static void uart_npcx_rx_refresh_timeout(struct k_work *work)
{
struct uart_npcx_data *data = CONTAINER_OF(work, struct uart_npcx_data,
rx_refresh_timeout_work);
uart_npcx_pm_constraint_rel(data, UART_PM_CONSTRAINT_RX_FLAG);
}
#endif
/* UART driver registration */
static const struct uart_driver_api uart_npcx_driver_api = {
.poll_in = uart_npcx_poll_in,
@ -457,6 +492,11 @@ static int uart_npcx_init(const struct device *dev)
*/
npcx_miwu_interrupt_configure(&config->uart_rx_wui,
NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_LOW);
#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
k_work_init_delayable(&data->rx_refresh_timeout_work,
uart_npcx_rx_refresh_timeout);
#endif
}
/* Configure pin-mux for uart device */

View file

@ -84,27 +84,6 @@ enum {
NPCX_STANDARD_WAKE_UP,
};
#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
static int64_t expired_timeout = CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT;
static int64_t console_expired_time = CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT;
/* Platform specific power control functions */
bool npcx_power_console_is_in_use(void)
{
return (k_uptime_get() < console_expired_time);
}
void npcx_power_console_is_in_use_refresh(void)
{
console_expired_time = k_uptime_get() + expired_timeout;
}
void npcx_power_set_console_in_use_timeout(int64_t timeout)
{
expired_timeout = timeout;
}
#endif
static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode)
{
/* Disable interrupts */

View file

@ -11,31 +11,6 @@
extern "C" {
#endif
/**
* @brief Receive whether the module for the console is in use.
*
* @return 1 if console is in use. Otherwise
* @return
* - True if the console is in use.
* - False otherwise, the module for console is reday to enter low power mode.
*/
bool npcx_power_console_is_in_use(void);
/**
* @brief Notify the power module that the module for the console is in use.
*
* Notify the power module that the module for the console is in use. It also
* extends expired time by CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT.
*/
void npcx_power_console_is_in_use_refresh(void);
/**
* @brief Set expired time-out directly for the console is in use.
*
* @param timeout Expired time-out for the console is in use.
*/
void npcx_power_set_console_in_use_timeout(int64_t timeout);
/**
* @brief Disable UART RX wake-up interrupt.
*/