| /* |
| * Copyright (c) 2018 Intel Corporation. |
| * Copyright (c) 2022 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/pm/policy.h> |
| #include <zephyr/pm/state.h> |
| #include <zephyr/sys/util_macro.h> |
| #include <zephyr/pm/device.h> |
| |
| struct pm_state_device_constraint { |
| const struct device *const dev; |
| size_t pm_constraints_size; |
| struct pm_state_constraint *constraints; |
| }; |
| |
| /** |
| * @brief Synthesize the name of the object that holds a device pm constraint. |
| * |
| * @param dev_id Device identifier. |
| */ |
| #define PM_CONSTRAINTS_NAME(node_id) _CONCAT(__devicepmconstraints_, node_id) |
| |
| /** |
| * @brief initialize a device pm constraint with information from devicetree. |
| * |
| * @param node_id Node identifier. |
| */ |
| #define PM_STATE_CONSTRAINT_INIT(node_id) \ |
| { \ |
| .state = PM_STATE_DT_INIT(node_id), \ |
| .substate_id = DT_PROP_OR(node_id, substate_id, 0), \ |
| } |
| |
| /** |
| * @brief Helper macro to define a device pm constraints. |
| */ |
| #define PM_STATE_CONSTRAINT_DEFINE(i, node_id) \ |
| COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, \ |
| zephyr_disabling_power_states, i)), \ |
| (PM_STATE_CONSTRAINT_INIT(DT_PHANDLE_BY_IDX(node_id, \ |
| zephyr_disabling_power_states, i)),), ()) |
| |
| /** |
| * @brief Helper macro to generate a list of device pm constraints. |
| */ |
| #define PM_STATE_CONSTRAINTS_DEFINE(node_id) \ |
| { \ |
| LISTIFY(DT_PROP_LEN_OR(node_id, zephyr_disabling_power_states, 0), \ |
| PM_STATE_CONSTRAINT_DEFINE, (), node_id) \ |
| } |
| |
| /** |
| * @brief Helper macro to define an array of device pm constraints. |
| */ |
| #define CONSTRAINTS_DEFINE(node_id) \ |
| Z_DECL_ALIGN(struct pm_state_constraint) \ |
| PM_CONSTRAINTS_NAME(node_id)[] = \ |
| PM_STATE_CONSTRAINTS_DEFINE(node_id); |
| |
| #define DEVICE_CONSTRAINTS_DEFINE(node_id) \ |
| COND_CODE_0(DT_NODE_HAS_PROP(node_id, zephyr_disabling_power_states), (), \ |
| (CONSTRAINTS_DEFINE(node_id))) |
| |
| DT_FOREACH_STATUS_OKAY_NODE(DEVICE_CONSTRAINTS_DEFINE) |
| |
| /** |
| * @brief Helper macro to initialize a pm state device constraint |
| */ |
| #define PM_STATE_DEVICE_CONSTRAINT_INIT(node_id) \ |
| { \ |
| .dev = DEVICE_DT_GET(node_id), \ |
| .pm_constraints_size = DT_PROP_LEN(node_id, zephyr_disabling_power_states), \ |
| .constraints = PM_CONSTRAINTS_NAME(node_id), \ |
| }, |
| |
| /** |
| * @brief Helper macro to initialize a pm state device constraint |
| */ |
| #define PM_STATE_DEVICE_CONSTRAINT_DEFINE(node_id) \ |
| COND_CODE_0(DT_NODE_HAS_PROP(node_id, zephyr_disabling_power_states), (), \ |
| (PM_STATE_DEVICE_CONSTRAINT_INIT(node_id))) |
| |
| static struct pm_state_device_constraint _devices_constraints[] = { |
| DT_FOREACH_STATUS_OKAY_NODE(PM_STATE_DEVICE_CONSTRAINT_DEFINE) |
| }; |
| |
| void pm_policy_device_power_lock_get(const struct device *dev) |
| { |
| #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) |
| for (size_t i = 0; i < ARRAY_SIZE(_devices_constraints); i++) { |
| if (_devices_constraints[i].dev == dev) { |
| for (size_t j = 0; j < _devices_constraints[i].pm_constraints_size; j++) { |
| pm_policy_state_lock_get( |
| _devices_constraints[i].constraints[j].state, |
| _devices_constraints[i].constraints[j].substate_id); |
| } |
| break; |
| } |
| } |
| #endif |
| } |
| |
| void pm_policy_device_power_lock_put(const struct device *dev) |
| { |
| #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) |
| for (size_t i = 0; i < ARRAY_SIZE(_devices_constraints); i++) { |
| if (_devices_constraints[i].dev == dev) { |
| for (size_t j = 0; j < _devices_constraints[i].pm_constraints_size; j++) { |
| pm_policy_state_lock_put( |
| _devices_constraints[i].constraints[j].state, |
| _devices_constraints[i].constraints[j].substate_id); |
| } |
| break; |
| } |
| } |
| #endif |
| } |