1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2022 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/pm/policy.h>
9 #include <zephyr/pm/state.h>
10 #include <zephyr/sys/util_macro.h>
11 #include <zephyr/pm/device.h>
12
13 struct pm_state_device_constraint {
14 const struct device *const dev;
15 size_t pm_constraints_size;
16 struct pm_state_constraint *constraints;
17 };
18
19 /**
20 * @brief Synthesize the name of the object that holds a device pm constraint.
21 *
22 * @param dev_id Device identifier.
23 */
24 #define PM_CONSTRAINTS_NAME(node_id) _CONCAT(__devicepmconstraints_, node_id)
25
26 /**
27 * @brief initialize a device pm constraint with information from devicetree.
28 *
29 * @param node_id Node identifier.
30 */
31 #define PM_STATE_CONSTRAINT_INIT(node_id) \
32 { \
33 .state = PM_STATE_DT_INIT(node_id), \
34 .substate_id = DT_PROP_OR(node_id, substate_id, 0), \
35 }
36
37 /**
38 * @brief Helper macro to define a device pm constraints.
39 */
40 #define PM_STATE_CONSTRAINT_DEFINE(i, node_id) \
41 COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, \
42 zephyr_disabling_power_states, i)), \
43 (PM_STATE_CONSTRAINT_INIT(DT_PHANDLE_BY_IDX(node_id, \
44 zephyr_disabling_power_states, i)),), ())
45
46 /**
47 * @brief Helper macro to generate a list of device pm constraints.
48 */
49 #define PM_STATE_CONSTRAINTS_DEFINE(node_id) \
50 { \
51 LISTIFY(DT_PROP_LEN_OR(node_id, zephyr_disabling_power_states, 0), \
52 PM_STATE_CONSTRAINT_DEFINE, (), node_id) \
53 }
54
55 /**
56 * @brief Helper macro to define an array of device pm constraints.
57 */
58 #define CONSTRAINTS_DEFINE(node_id) \
59 Z_DECL_ALIGN(struct pm_state_constraint) \
60 PM_CONSTRAINTS_NAME(node_id)[] = \
61 PM_STATE_CONSTRAINTS_DEFINE(node_id);
62
63 #define DEVICE_CONSTRAINTS_DEFINE(node_id) \
64 COND_CODE_0(DT_NODE_HAS_PROP(node_id, zephyr_disabling_power_states), (), \
65 (CONSTRAINTS_DEFINE(node_id)))
66
67 DT_FOREACH_STATUS_OKAY_NODE(DEVICE_CONSTRAINTS_DEFINE)
68
69 /**
70 * @brief Helper macro to initialize a pm state device constraint
71 */
72 #define PM_STATE_DEVICE_CONSTRAINT_INIT(node_id) \
73 { \
74 .dev = DEVICE_DT_GET(node_id), \
75 .pm_constraints_size = DT_PROP_LEN(node_id, zephyr_disabling_power_states), \
76 .constraints = PM_CONSTRAINTS_NAME(node_id), \
77 },
78
79 /**
80 * @brief Helper macro to initialize a pm state device constraint
81 */
82 #define PM_STATE_DEVICE_CONSTRAINT_DEFINE(node_id) \
83 COND_CODE_0(DT_NODE_HAS_PROP(node_id, zephyr_disabling_power_states), (), \
84 (PM_STATE_DEVICE_CONSTRAINT_INIT(node_id)))
85
86 static struct pm_state_device_constraint _devices_constraints[] = {
87 DT_FOREACH_STATUS_OKAY_NODE(PM_STATE_DEVICE_CONSTRAINT_DEFINE)
88 };
89
pm_policy_device_power_lock_get(const struct device * dev)90 void pm_policy_device_power_lock_get(const struct device *dev)
91 {
92 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
93 for (size_t i = 0; i < ARRAY_SIZE(_devices_constraints); i++) {
94 if (_devices_constraints[i].dev == dev) {
95 for (size_t j = 0; j < _devices_constraints[i].pm_constraints_size; j++) {
96 pm_policy_state_lock_get(
97 _devices_constraints[i].constraints[j].state,
98 _devices_constraints[i].constraints[j].substate_id);
99 }
100 break;
101 }
102 }
103 #endif
104 }
105
pm_policy_device_power_lock_put(const struct device * dev)106 void pm_policy_device_power_lock_put(const struct device *dev)
107 {
108 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state)
109 for (size_t i = 0; i < ARRAY_SIZE(_devices_constraints); i++) {
110 if (_devices_constraints[i].dev == dev) {
111 for (size_t j = 0; j < _devices_constraints[i].pm_constraints_size; j++) {
112 pm_policy_state_lock_put(
113 _devices_constraints[i].constraints[j].state,
114 _devices_constraints[i].constraints[j].substate_id);
115 }
116 break;
117 }
118 }
119 #endif
120 }
121