pm: device: move device busy APIs to pm subsystem
The following device busy APIs: - device_busy_set() - device_busy_clear() - device_busy_check() - device_any_busy_check() were used for device PM, so they have been moved to the pm subsystem. This means they are now prefixed with `pm_` and are defined in `pm/device.h`. If device PM is not enabled dummy functions are now provided that do nothing or return `-ENOSYS`, meaning that the functionality is not available. Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
parent
775cf55d92
commit
70322853a8
11 changed files with 112 additions and 119 deletions
|
@ -425,15 +425,15 @@ static int i2c_dw_transfer(const struct device *dev,
|
|||
* While waiting at device_sync_sem, kernel can switch to idle
|
||||
* task which in turn can call pm_system_suspend() hook of Power
|
||||
* Management App (PMA).
|
||||
* device_busy_set() call here, would indicate to PMA that it should not
|
||||
* execute PM policies that would turn off this ip block, causing an
|
||||
* pm_device_busy_set() call here, would indicate to PMA that it should
|
||||
* not execute PM policies that would turn off this ip block, causing an
|
||||
* ongoing hw transaction to be left in an inconsistent state.
|
||||
* Note : This is just a sample to show a possible use of the API, it is
|
||||
* upto the driver expert to see, if he actually needs it here, or
|
||||
* somewhere else, or not needed as the driver's suspend()/resume()
|
||||
* can handle everything
|
||||
*/
|
||||
device_busy_set(dev);
|
||||
pm_device_busy_set(dev);
|
||||
|
||||
/* Process all the messages */
|
||||
while (msg_left > 0) {
|
||||
|
@ -493,7 +493,7 @@ static int i2c_dw_transfer(const struct device *dev,
|
|||
msg_left--;
|
||||
}
|
||||
|
||||
device_busy_clear(dev);
|
||||
pm_device_busy_clear(dev);
|
||||
|
||||
dw->state = I2C_DW_STATE_READY;
|
||||
|
||||
|
|
|
@ -353,7 +353,7 @@ static int bmp388_sample_fetch(const struct device *dev,
|
|||
}
|
||||
#endif
|
||||
|
||||
device_busy_set(dev);
|
||||
pm_device_busy_set(dev);
|
||||
|
||||
/* Wait for status to indicate that data is ready. */
|
||||
raw[0] = 0U;
|
||||
|
@ -382,7 +382,7 @@ static int bmp388_sample_fetch(const struct device *dev,
|
|||
bmp388->sample.comp_temp = 0;
|
||||
|
||||
error:
|
||||
device_busy_clear(dev);
|
||||
pm_device_busy_clear(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ static void uart_cc13xx_cc26xx_irq_tx_enable(const struct device *dev)
|
|||
* to transmit using the uart, hence we should no longer go
|
||||
* into standby.
|
||||
*
|
||||
* Instead of using device_busy_set(), which currently does
|
||||
* Instead of using pm_device_busy_set(), which currently does
|
||||
* not impact the PM policy, we specifically disable the
|
||||
* standby mode instead, since it is the power state that
|
||||
* would interfere with a transfer.
|
||||
|
|
|
@ -833,7 +833,7 @@ static void uart_nrfx_irq_tx_enable(const struct device *dev)
|
|||
/* Indicate that this device started a transaction that should not be
|
||||
* interrupted by putting the SoC into the deep sleep mode.
|
||||
*/
|
||||
device_busy_set(dev);
|
||||
pm_device_busy_set(dev);
|
||||
|
||||
/* Activate the transmitter. */
|
||||
nrf_uart_task_trigger(uart0_addr, NRF_UART_TASK_STARTTX);
|
||||
|
@ -956,7 +956,7 @@ static void uart_nrfx_isr(const struct device *dev)
|
|||
/* The transaction is over. It is okay to enter the deep sleep
|
||||
* mode if needed.
|
||||
*/
|
||||
device_busy_clear(dev);
|
||||
pm_device_busy_clear(dev);
|
||||
|
||||
disable_tx_irq = false;
|
||||
|
||||
|
|
|
@ -344,8 +344,8 @@ static int transceive(const struct device *dev,
|
|||
spi_context_lock(&spi->ctx, asynchronous, signal, config);
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
if (device_busy_check(dev) != (-EBUSY)) {
|
||||
device_busy_set(dev);
|
||||
if (pm_device_busy_check(dev) != (-EBUSY)) {
|
||||
pm_device_busy_set(dev);
|
||||
}
|
||||
#endif /* CONFIG_PM_DEVICE */
|
||||
|
||||
|
@ -434,7 +434,7 @@ static int transceive(const struct device *dev,
|
|||
out:
|
||||
spi_context_release(&spi->ctx, ret);
|
||||
|
||||
device_busy_clear(dev);
|
||||
pm_device_busy_clear(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -612,52 +612,6 @@ static inline bool device_is_ready(const struct device *dev)
|
|||
return device_usable_check(dev) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Indicate that the device is in the middle of a transaction
|
||||
*
|
||||
* Called by a device driver to indicate that it is in the middle of a
|
||||
* transaction.
|
||||
*
|
||||
* @param dev Pointer to device structure of the driver instance.
|
||||
*/
|
||||
void device_busy_set(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Indicate that the device has completed its transaction
|
||||
*
|
||||
* Called by a device driver to indicate the end of a transaction.
|
||||
*
|
||||
* @param dev Pointer to device structure of the driver instance.
|
||||
*/
|
||||
void device_busy_clear(const struct device *dev);
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
/**
|
||||
* @brief Check if any device is in the middle of a transaction
|
||||
*
|
||||
* Called by an application to see if any device is in the middle
|
||||
* of a critical transaction that cannot be interrupted.
|
||||
*
|
||||
* @retval 0 if no device is busy
|
||||
* @retval -EBUSY if any device is busy
|
||||
*/
|
||||
int device_any_busy_check(void);
|
||||
|
||||
/**
|
||||
* @brief Check if a specific device is in the middle of a transaction
|
||||
*
|
||||
* Called by an application to see if a particular device is in the
|
||||
* middle of a critical transaction that cannot be interrupted.
|
||||
*
|
||||
* @param chk_dev Pointer to device structure of the specific device driver
|
||||
* the caller is interested in.
|
||||
* @retval 0 if the device is not busy
|
||||
* @retval -EBUSY if the device is busy
|
||||
*/
|
||||
int device_busy_check(const struct device *chk_dev);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -133,6 +133,56 @@ int pm_device_state_set(const struct device *dev,
|
|||
int pm_device_state_get(const struct device *dev,
|
||||
enum pm_device_state *device_power_state);
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
/**
|
||||
* @brief Indicate that the device is in the middle of a transaction
|
||||
*
|
||||
* Called by a device driver to indicate that it is in the middle of a
|
||||
* transaction.
|
||||
*
|
||||
* @param dev Pointer to device structure of the driver instance.
|
||||
*/
|
||||
void pm_device_busy_set(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Indicate that the device has completed its transaction
|
||||
*
|
||||
* Called by a device driver to indicate the end of a transaction.
|
||||
*
|
||||
* @param dev Pointer to device structure of the driver instance.
|
||||
*/
|
||||
void pm_device_busy_clear(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Check if any device is in the middle of a transaction
|
||||
*
|
||||
* Called by an application to see if any device is in the middle
|
||||
* of a critical transaction that cannot be interrupted.
|
||||
*
|
||||
* @retval 0 if no device is busy
|
||||
* @retval -EBUSY if any device is busy
|
||||
*/
|
||||
int pm_device_any_busy_check(void);
|
||||
|
||||
/**
|
||||
* @brief Check if a specific device is in the middle of a transaction
|
||||
*
|
||||
* Called by an application to see if a particular device is in the
|
||||
* middle of a critical transaction that cannot be interrupted.
|
||||
*
|
||||
* @param chk_dev Pointer to device structure of the specific device driver
|
||||
* the caller is interested in.
|
||||
* @retval 0 if the device is not busy
|
||||
* @retval -EBUSY if the device is busy
|
||||
*/
|
||||
int pm_device_busy_check(const struct device *chk_dev);
|
||||
#else
|
||||
static inline void pm_device_busy_set(const struct device *dev) {}
|
||||
static inline void pm_device_busy_clear(const struct device *dev) {}
|
||||
static inline int pm_device_any_busy_check(void) { return -ENOSYS; }
|
||||
static inline int pm_device_busy_check(const struct device *chk_dev) { return -ENOSYS; }
|
||||
#endif
|
||||
|
||||
/** Alias for legacy use of device_pm_control_nop */
|
||||
#define device_pm_control_nop __DEPRECATED_MACRO NULL
|
||||
|
||||
|
|
|
@ -195,50 +195,3 @@ int device_required_foreach(const struct device *dev,
|
|||
|
||||
return handle_count;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
int device_any_busy_check(void)
|
||||
{
|
||||
const struct device *dev = __device_start;
|
||||
|
||||
while (dev < __device_end) {
|
||||
if (atomic_test_bit(&dev->pm->atomic_flags,
|
||||
PM_DEVICE_ATOMIC_FLAGS_BUSY_BIT)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
++dev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int device_busy_check(const struct device *dev)
|
||||
{
|
||||
if (atomic_test_bit(&dev->pm->atomic_flags,
|
||||
PM_DEVICE_ATOMIC_FLAGS_BUSY_BIT)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void device_busy_set(const struct device *dev)
|
||||
{
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
atomic_set_bit(&dev->pm->atomic_flags,
|
||||
PM_DEVICE_ATOMIC_FLAGS_BUSY_BIT);
|
||||
#else
|
||||
ARG_UNUSED(dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
void device_busy_clear(const struct device *dev)
|
||||
{
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
atomic_clear_bit(&dev->pm->atomic_flags,
|
||||
PM_DEVICE_ATOMIC_FLAGS_BUSY_BIT);
|
||||
#else
|
||||
ARG_UNUSED(dev);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ void main(void)
|
|||
printk("Device ready\n");
|
||||
|
||||
/* Don't let the system power off / low power this device */
|
||||
device_busy_set(led.port);
|
||||
pm_device_busy_set(led.port);
|
||||
|
||||
while (true) {
|
||||
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <device.h>
|
||||
#include <pm/policy.h>
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
#define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(power);
|
||||
|
@ -18,6 +17,7 @@ LOG_MODULE_DECLARE(power);
|
|||
extern const struct device __device_start[];
|
||||
extern const struct device __device_end[];
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
extern const struct device *__pm_device_slots_start[];
|
||||
|
||||
/* Number of devices successfully suspended. */
|
||||
|
@ -28,7 +28,7 @@ static bool should_suspend(const struct device *dev, enum pm_device_state state)
|
|||
int rc;
|
||||
enum pm_device_state current_state;
|
||||
|
||||
if (device_busy_check(dev) != 0) {
|
||||
if (pm_device_busy_check(dev) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -149,3 +149,39 @@ int pm_device_state_get(const struct device *dev,
|
|||
return dev->pm_control(dev, PM_DEVICE_STATE_GET,
|
||||
device_power_state);
|
||||
}
|
||||
|
||||
int pm_device_any_busy_check(void)
|
||||
{
|
||||
const struct device *dev = __device_start;
|
||||
|
||||
while (dev < __device_end) {
|
||||
if (atomic_test_bit(&dev->pm->atomic_flags,
|
||||
PM_DEVICE_ATOMIC_FLAGS_BUSY_BIT)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
++dev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pm_device_busy_check(const struct device *dev)
|
||||
{
|
||||
if (atomic_test_bit(&dev->pm->atomic_flags,
|
||||
PM_DEVICE_ATOMIC_FLAGS_BUSY_BIT)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pm_device_busy_set(const struct device *dev)
|
||||
{
|
||||
atomic_set_bit(&dev->pm->atomic_flags,
|
||||
PM_DEVICE_ATOMIC_FLAGS_BUSY_BIT);
|
||||
}
|
||||
|
||||
void pm_device_busy_clear(const struct device *dev)
|
||||
{
|
||||
atomic_clear_bit(&dev->pm->atomic_flags,
|
||||
PM_DEVICE_ATOMIC_FLAGS_BUSY_BIT);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ extern void test_mmio_device_map(void);
|
|||
*
|
||||
* @ingroup kernel_device_tests
|
||||
*
|
||||
* @see device_get_binding(), device_busy_set(), device_busy_clear(),
|
||||
* @see device_get_binding(), pm_device_busy_set(), pm_device_busy_clear(),
|
||||
* DEVICE_DEFINE()
|
||||
*/
|
||||
void test_dummy_device(void)
|
||||
|
@ -66,8 +66,8 @@ void test_dummy_device(void)
|
|||
dev = device_get_binding(DUMMY_PORT_2);
|
||||
zassert_false((dev == NULL), NULL);
|
||||
|
||||
device_busy_set(dev);
|
||||
device_busy_clear(dev);
|
||||
pm_device_busy_set(dev);
|
||||
pm_device_busy_clear(dev);
|
||||
|
||||
/* device_get_binding() returns false for device object
|
||||
* with failed init.
|
||||
|
@ -283,8 +283,8 @@ static void test_enable_and_disable_automatic_runtime_pm(void)
|
|||
* enabled. It also checks if the device is in the middle of a transaction,
|
||||
* sets/clears busy status and validates status again.
|
||||
*
|
||||
* @see device_get_binding(), device_busy_set(), device_busy_clear(),
|
||||
* device_busy_check(), device_any_busy_check(),
|
||||
* @see device_get_binding(), pm_device_busy_set(), pm_device_busy_clear(),
|
||||
* pm_device_busy_check(), pm_device_any_busy_check(),
|
||||
* pm_device_state_set()
|
||||
*/
|
||||
void test_dummy_device_pm(void)
|
||||
|
@ -296,22 +296,22 @@ void test_dummy_device_pm(void)
|
|||
dev = device_get_binding(DUMMY_PORT_2);
|
||||
zassert_false((dev == NULL), NULL);
|
||||
|
||||
busy = device_any_busy_check();
|
||||
busy = pm_device_any_busy_check();
|
||||
zassert_true((busy == 0), NULL);
|
||||
|
||||
/* Set device state to BUSY*/
|
||||
device_busy_set(dev);
|
||||
pm_device_busy_set(dev);
|
||||
|
||||
busy = device_any_busy_check();
|
||||
busy = pm_device_any_busy_check();
|
||||
zassert_false((busy == 0), NULL);
|
||||
|
||||
busy = device_busy_check(dev);
|
||||
busy = pm_device_busy_check(dev);
|
||||
zassert_false((busy == 0), NULL);
|
||||
|
||||
/* Clear device BUSY state*/
|
||||
device_busy_clear(dev);
|
||||
pm_device_busy_clear(dev);
|
||||
|
||||
busy = device_busy_check(dev);
|
||||
busy = pm_device_busy_check(dev);
|
||||
zassert_true((busy == 0), NULL);
|
||||
|
||||
test_build_suspend_device_list();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue