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
|
* While waiting at device_sync_sem, kernel can switch to idle
|
||||||
* task which in turn can call pm_system_suspend() hook of Power
|
* task which in turn can call pm_system_suspend() hook of Power
|
||||||
* Management App (PMA).
|
* Management App (PMA).
|
||||||
* device_busy_set() call here, would indicate to PMA that it should not
|
* pm_device_busy_set() call here, would indicate to PMA that it should
|
||||||
* execute PM policies that would turn off this ip block, causing an
|
* not execute PM policies that would turn off this ip block, causing an
|
||||||
* ongoing hw transaction to be left in an inconsistent state.
|
* 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
|
* 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
|
* upto the driver expert to see, if he actually needs it here, or
|
||||||
* somewhere else, or not needed as the driver's suspend()/resume()
|
* somewhere else, or not needed as the driver's suspend()/resume()
|
||||||
* can handle everything
|
* can handle everything
|
||||||
*/
|
*/
|
||||||
device_busy_set(dev);
|
pm_device_busy_set(dev);
|
||||||
|
|
||||||
/* Process all the messages */
|
/* Process all the messages */
|
||||||
while (msg_left > 0) {
|
while (msg_left > 0) {
|
||||||
|
@ -493,7 +493,7 @@ static int i2c_dw_transfer(const struct device *dev,
|
||||||
msg_left--;
|
msg_left--;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_busy_clear(dev);
|
pm_device_busy_clear(dev);
|
||||||
|
|
||||||
dw->state = I2C_DW_STATE_READY;
|
dw->state = I2C_DW_STATE_READY;
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,7 @@ static int bmp388_sample_fetch(const struct device *dev,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
device_busy_set(dev);
|
pm_device_busy_set(dev);
|
||||||
|
|
||||||
/* Wait for status to indicate that data is ready. */
|
/* Wait for status to indicate that data is ready. */
|
||||||
raw[0] = 0U;
|
raw[0] = 0U;
|
||||||
|
@ -382,7 +382,7 @@ static int bmp388_sample_fetch(const struct device *dev,
|
||||||
bmp388->sample.comp_temp = 0;
|
bmp388->sample.comp_temp = 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
device_busy_clear(dev);
|
pm_device_busy_clear(dev);
|
||||||
return ret;
|
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
|
* to transmit using the uart, hence we should no longer go
|
||||||
* into standby.
|
* 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
|
* not impact the PM policy, we specifically disable the
|
||||||
* standby mode instead, since it is the power state that
|
* standby mode instead, since it is the power state that
|
||||||
* would interfere with a transfer.
|
* 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
|
/* Indicate that this device started a transaction that should not be
|
||||||
* interrupted by putting the SoC into the deep sleep mode.
|
* interrupted by putting the SoC into the deep sleep mode.
|
||||||
*/
|
*/
|
||||||
device_busy_set(dev);
|
pm_device_busy_set(dev);
|
||||||
|
|
||||||
/* Activate the transmitter. */
|
/* Activate the transmitter. */
|
||||||
nrf_uart_task_trigger(uart0_addr, NRF_UART_TASK_STARTTX);
|
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
|
/* The transaction is over. It is okay to enter the deep sleep
|
||||||
* mode if needed.
|
* mode if needed.
|
||||||
*/
|
*/
|
||||||
device_busy_clear(dev);
|
pm_device_busy_clear(dev);
|
||||||
|
|
||||||
disable_tx_irq = false;
|
disable_tx_irq = false;
|
||||||
|
|
||||||
|
|
|
@ -344,8 +344,8 @@ static int transceive(const struct device *dev,
|
||||||
spi_context_lock(&spi->ctx, asynchronous, signal, config);
|
spi_context_lock(&spi->ctx, asynchronous, signal, config);
|
||||||
|
|
||||||
#ifdef CONFIG_PM_DEVICE
|
#ifdef CONFIG_PM_DEVICE
|
||||||
if (device_busy_check(dev) != (-EBUSY)) {
|
if (pm_device_busy_check(dev) != (-EBUSY)) {
|
||||||
device_busy_set(dev);
|
pm_device_busy_set(dev);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_DEVICE */
|
#endif /* CONFIG_PM_DEVICE */
|
||||||
|
|
||||||
|
@ -434,7 +434,7 @@ static int transceive(const struct device *dev,
|
||||||
out:
|
out:
|
||||||
spi_context_release(&spi->ctx, ret);
|
spi_context_release(&spi->ctx, ret);
|
||||||
|
|
||||||
device_busy_clear(dev);
|
pm_device_busy_clear(dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -612,52 +612,6 @@ static inline bool device_is_ready(const struct device *dev)
|
||||||
return device_usable_check(dev) == 0;
|
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,
|
int pm_device_state_get(const struct device *dev,
|
||||||
enum pm_device_state *device_power_state);
|
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 */
|
/** Alias for legacy use of device_pm_control_nop */
|
||||||
#define device_pm_control_nop __DEPRECATED_MACRO NULL
|
#define device_pm_control_nop __DEPRECATED_MACRO NULL
|
||||||
|
|
||||||
|
|
|
@ -195,50 +195,3 @@ int device_required_foreach(const struct device *dev,
|
||||||
|
|
||||||
return handle_count;
|
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");
|
printk("Device ready\n");
|
||||||
|
|
||||||
/* Don't let the system power off / low power this device */
|
/* Don't let the system power off / low power this device */
|
||||||
device_busy_set(led.port);
|
pm_device_busy_set(led.port);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
|
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <device.h>
|
#include <device.h>
|
||||||
#include <pm/policy.h>
|
#include <pm/policy.h>
|
||||||
|
|
||||||
#if defined(CONFIG_PM)
|
|
||||||
#define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */
|
#define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
LOG_MODULE_DECLARE(power);
|
LOG_MODULE_DECLARE(power);
|
||||||
|
@ -18,6 +17,7 @@ LOG_MODULE_DECLARE(power);
|
||||||
extern const struct device __device_start[];
|
extern const struct device __device_start[];
|
||||||
extern const struct device __device_end[];
|
extern const struct device __device_end[];
|
||||||
|
|
||||||
|
#if defined(CONFIG_PM)
|
||||||
extern const struct device *__pm_device_slots_start[];
|
extern const struct device *__pm_device_slots_start[];
|
||||||
|
|
||||||
/* Number of devices successfully suspended. */
|
/* Number of devices successfully suspended. */
|
||||||
|
@ -28,7 +28,7 @@ static bool should_suspend(const struct device *dev, enum pm_device_state state)
|
||||||
int rc;
|
int rc;
|
||||||
enum pm_device_state current_state;
|
enum pm_device_state current_state;
|
||||||
|
|
||||||
if (device_busy_check(dev) != 0) {
|
if (pm_device_busy_check(dev) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,3 +149,39 @@ int pm_device_state_get(const struct device *dev,
|
||||||
return dev->pm_control(dev, PM_DEVICE_STATE_GET,
|
return dev->pm_control(dev, PM_DEVICE_STATE_GET,
|
||||||
device_power_state);
|
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
|
* @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()
|
* DEVICE_DEFINE()
|
||||||
*/
|
*/
|
||||||
void test_dummy_device(void)
|
void test_dummy_device(void)
|
||||||
|
@ -66,8 +66,8 @@ void test_dummy_device(void)
|
||||||
dev = device_get_binding(DUMMY_PORT_2);
|
dev = device_get_binding(DUMMY_PORT_2);
|
||||||
zassert_false((dev == NULL), NULL);
|
zassert_false((dev == NULL), NULL);
|
||||||
|
|
||||||
device_busy_set(dev);
|
pm_device_busy_set(dev);
|
||||||
device_busy_clear(dev);
|
pm_device_busy_clear(dev);
|
||||||
|
|
||||||
/* device_get_binding() returns false for device object
|
/* device_get_binding() returns false for device object
|
||||||
* with failed init.
|
* 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,
|
* enabled. It also checks if the device is in the middle of a transaction,
|
||||||
* sets/clears busy status and validates status again.
|
* sets/clears busy status and validates status again.
|
||||||
*
|
*
|
||||||
* @see device_get_binding(), device_busy_set(), device_busy_clear(),
|
* @see device_get_binding(), pm_device_busy_set(), pm_device_busy_clear(),
|
||||||
* device_busy_check(), device_any_busy_check(),
|
* pm_device_busy_check(), pm_device_any_busy_check(),
|
||||||
* pm_device_state_set()
|
* pm_device_state_set()
|
||||||
*/
|
*/
|
||||||
void test_dummy_device_pm(void)
|
void test_dummy_device_pm(void)
|
||||||
|
@ -296,22 +296,22 @@ void test_dummy_device_pm(void)
|
||||||
dev = device_get_binding(DUMMY_PORT_2);
|
dev = device_get_binding(DUMMY_PORT_2);
|
||||||
zassert_false((dev == NULL), NULL);
|
zassert_false((dev == NULL), NULL);
|
||||||
|
|
||||||
busy = device_any_busy_check();
|
busy = pm_device_any_busy_check();
|
||||||
zassert_true((busy == 0), NULL);
|
zassert_true((busy == 0), NULL);
|
||||||
|
|
||||||
/* Set device state to BUSY*/
|
/* 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);
|
zassert_false((busy == 0), NULL);
|
||||||
|
|
||||||
busy = device_busy_check(dev);
|
busy = pm_device_busy_check(dev);
|
||||||
zassert_false((busy == 0), NULL);
|
zassert_false((busy == 0), NULL);
|
||||||
|
|
||||||
/* Clear device BUSY state*/
|
/* 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);
|
zassert_true((busy == 0), NULL);
|
||||||
|
|
||||||
test_build_suspend_device_list();
|
test_build_suspend_device_list();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue