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