@@ -26,12 +26,121 @@ static bool set_pm;
2626static bool leave_idle ;
2727static bool idle_entered ;
2828static bool testing_device_runtime ;
29+ static bool testing_device_order ;
2930
3031static const struct device * device_dummy ;
3132static struct dummy_driver_api * api ;
3233
34+ static const struct device * device_a ;
35+ static const struct device * device_c ;
36+
37+
38+ /*
39+ * According with the initialization level, devices A, B and C are
40+ * initialized in the following order A -> B -> C.
41+ *
42+ * The power management subsystem uses this order to suspend and resume
43+ * devices. Devices are suspended in the reverse order:
44+ *
45+ * C -> B -> A
46+ *
47+ * While resuming uses the initialization order:
48+ *
49+ * A -> B -> C
50+ *
51+ * This test checks if these order is correct checking devices A and C states
52+ * when suspending / resuming device B.
53+ */
54+
55+
56+ /* Common init function for devices A,B and C */
57+ static int device_init (const struct device * dev )
58+ {
59+ ARG_UNUSED (dev );
60+
61+ return 0 ;
62+ }
63+
64+ static int device_a_pm_action (const struct device * dev ,
65+ enum pm_device_action pm_action )
66+ {
67+ ARG_UNUSED (dev );
68+ ARG_UNUSED (pm_action );
69+
70+ return 0 ;
71+ }
72+
73+ DEVICE_DT_DEFINE (DT_INST (0 , test_device_pm ), device_init ,
74+ device_a_pm_action , NULL , NULL ,
75+ PRE_KERNEL_1 , CONFIG_KERNEL_INIT_PRIORITY_DEVICE ,
76+ NULL );
77+
78+
79+ static int device_b_pm_action (const struct device * dev ,
80+ enum pm_device_action pm_action )
81+ {
82+ enum pm_device_state state_a ;
83+ enum pm_device_state state_c ;
84+
85+ if (!testing_device_order ) {
86+ return 0 ;
87+ }
88+
89+ (void )pm_device_state_get (device_a , & state_a );
90+ (void )pm_device_state_get (device_c , & state_c );
91+
92+ switch (pm_action ) {
93+ case PM_DEVICE_ACTION_RESUME :
94+ /* Check if device C is still suspended */
95+ zassert_equal (state_c , PM_DEVICE_STATE_SUSPENDED ,
96+ "Inconsistent states" );
97+ /* Check if device A is already active */
98+ zassert_equal (state_a , PM_DEVICE_STATE_ACTIVE ,
99+ "Inconsistent states" );
100+ break ;
101+ case PM_DEVICE_ACTION_SUSPEND :
102+ /* Check if device C is already suspended */
103+ zassert_equal (state_c , PM_DEVICE_STATE_SUSPENDED ,
104+ "Inconsistent states" );
105+ /* Check if device A is still active */
106+ zassert_equal (state_a , PM_DEVICE_STATE_ACTIVE ,
107+ "Inconsistent states" );
108+ break ;
109+ default :
110+ break ;
111+ }
112+
113+ return 0 ;
114+ }
115+
116+ DEVICE_DT_DEFINE (DT_INST (1 , test_device_pm ), device_init ,
117+ device_b_pm_action , NULL , NULL ,
118+ PRE_KERNEL_2 , CONFIG_KERNEL_INIT_PRIORITY_DEVICE ,
119+ NULL );
120+
121+ static int device_c_pm_action (const struct device * dev ,
122+ enum pm_device_action pm_action )
123+ {
124+ ARG_UNUSED (dev );
125+ ARG_UNUSED (pm_action );
126+
127+ return 0 ;
128+ }
129+
130+ DEVICE_DT_DEFINE (DT_INST (2 , test_device_pm ), device_init ,
131+ device_c_pm_action , NULL , NULL ,
132+ POST_KERNEL , CONFIG_KERNEL_INIT_PRIORITY_DEVICE ,
133+ NULL );
134+
135+
136+
33137void pm_power_state_set (struct pm_state_info info )
34138{
139+ /* If testing device order this function does not need to anything */
140+ if (testing_device_order ) {
141+ return ;
142+ }
143+
35144 /* at this point, notify_pm_state_entry() implemented in
36145 * this file has been called and set_pm should have been set
37146 */
@@ -157,6 +266,11 @@ void test_power_idle(void)
157266 zassert_true (idle_entered , "Never entered idle thread" );
158267}
159268
269+ static struct pm_notifier notifier = {
270+ .state_entry = notify_pm_state_entry ,
271+ .state_exit = notify_pm_state_exit ,
272+ };
273+
160274/*
161275 * @brief test power state transition
162276 *
@@ -174,16 +288,19 @@ void test_power_state_trans(void)
174288{
175289 int ret ;
176290
291+ pm_notifier_register (& notifier );
177292 enter_low_power = true;
178293
179- ret = pm_device_runtime_disable (dev );
294+ ret = pm_device_runtime_disable (device_dummy );
180295 zassert_true (ret == 0 , "Failed to disable device runtime PM" );
181296
182297 /* give way to idle thread */
183298 k_sleep (SLEEP_TIMEOUT );
184299 zassert_true (leave_idle , NULL );
185300
186- pm_device_runtime_enable (dev );
301+ pm_device_runtime_enable (device_dummy );
302+
303+ pm_notifier_unregister (& notifier );
187304}
188305
189306/*
@@ -205,6 +322,7 @@ void test_power_state_notification(void)
205322 int ret ;
206323 enum pm_device_state device_power_state ;
207324
325+ pm_notifier_register (& notifier );
208326 enter_low_power = true;
209327
210328 ret = api -> open (device_dummy );
@@ -223,22 +341,35 @@ void test_power_state_notification(void)
223341 api -> close (device_dummy );
224342 pm_device_state_get (device_dummy , & device_power_state );
225343 zassert_equal (device_power_state , PM_DEVICE_STATE_SUSPENDED , NULL );
344+ pm_notifier_unregister (& notifier );
226345}
227346
228- void test_main (void )
347+ void test_device_order (void )
229348{
230- struct pm_notifier notifier = {
231- .state_entry = notify_pm_state_entry ,
232- .state_exit = notify_pm_state_exit ,
233- };
349+ device_a = DEVICE_DT_GET (DT_INST (0 , test_device_pm ));
350+ zassert_not_null (device_a , "Failed to get device" );
234351
235- pm_notifier_register (& notifier );
352+ device_c = DEVICE_DT_GET (DT_INST (2 , test_device_pm ));
353+ zassert_not_null (device_c , "Failed to get device" );
354+
355+ testing_device_order = true;
356+ enter_low_power = true;
357+
358+ k_sleep (SLEEP_TIMEOUT );
359+
360+ testing_device_order = false;
361+ }
362+
363+
364+ void test_main (void )
365+ {
236366 device_dummy = device_get_binding (DUMMY_DRIVER_NAME );
237367 api = (struct dummy_driver_api * )device_dummy -> api ;
238368
239369 ztest_test_suite (power_management_test ,
240370 ztest_1cpu_unit_test (test_power_idle ),
241371 ztest_1cpu_unit_test (test_power_state_trans ),
372+ ztest_1cpu_unit_test (test_device_order ),
242373 ztest_1cpu_unit_test (test_power_state_notification ));
243374 ztest_run_test_suite (power_management_test );
244375 pm_notifier_unregister (& notifier );
0 commit comments