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 <stdint.h>
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/pm/policy.h>
12 #include <zephyr/spinlock.h>
13 #include <zephyr/sys_clock.h>
14 #include <zephyr/sys/time_units.h>
15 
16 /** Lock to synchronize access to the events list. */
17 static struct k_spinlock events_lock;
18 /** List of events. */
19 static sys_slist_t events_list;
20 /** Pointer to Next Event. */
21 struct pm_policy_event *next_event;
22 
update_next_event(void)23 static void update_next_event(void)
24 {
25 	struct pm_policy_event *evt;
26 
27 	next_event = NULL;
28 
29 	SYS_SLIST_FOR_EACH_CONTAINER(&events_list, evt, node) {
30 		if (next_event == NULL) {
31 			next_event = evt;
32 			continue;
33 		}
34 
35 		if (next_event->uptime_ticks <= evt->uptime_ticks) {
36 			continue;
37 		}
38 
39 		next_event = evt;
40 	}
41 }
42 
pm_policy_next_event_ticks(void)43 int64_t pm_policy_next_event_ticks(void)
44 {
45 	int64_t ticks = -1;
46 
47 	K_SPINLOCK(&events_lock) {
48 		if (next_event == NULL) {
49 			K_SPINLOCK_BREAK;
50 		}
51 
52 		ticks = next_event->uptime_ticks - k_uptime_ticks();
53 
54 		if (ticks < 0) {
55 			ticks = 0;
56 		}
57 	}
58 
59 	return ticks;
60 }
61 
pm_policy_event_register(struct pm_policy_event * evt,int64_t uptime_ticks)62 void pm_policy_event_register(struct pm_policy_event *evt, int64_t uptime_ticks)
63 {
64 	K_SPINLOCK(&events_lock) {
65 		evt->uptime_ticks = uptime_ticks;
66 		sys_slist_append(&events_list, &evt->node);
67 		update_next_event();
68 	}
69 }
70 
pm_policy_event_update(struct pm_policy_event * evt,int64_t uptime_ticks)71 void pm_policy_event_update(struct pm_policy_event *evt, int64_t uptime_ticks)
72 {
73 	K_SPINLOCK(&events_lock) {
74 		evt->uptime_ticks = uptime_ticks;
75 		update_next_event();
76 	}
77 }
78 
pm_policy_event_unregister(struct pm_policy_event * evt)79 void pm_policy_event_unregister(struct pm_policy_event *evt)
80 {
81 	K_SPINLOCK(&events_lock) {
82 		(void)sys_slist_find_and_remove(&events_list, &evt->node);
83 		update_next_event();
84 	}
85 }
86