summaryrefslogtreecommitdiff
path: root/zephyr/subsys/ap_pwrseq/ap_events.c
blob: d5b78c2c330bf1ff91835652f5b3788258b4623b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <zephyr/kernel.h>

#include <ap_power/ap_power.h>
#include <ap_power/ap_power_events.h>

static sys_slist_t callbacks;
/*
 * Contains the accumulated set of events that any
 * callback has registered. This is a hint to detect events that
 * have never had any callbacks registered, in which case the
 * callback list does not have to be run.
 */
static uint32_t cb_set;

static int ap_power_ev_manage_callback(struct ap_power_ev_callback *cb,
				       bool set)
{
	__ASSERT(cb, "No callback!");
	__ASSERT(cb->handler, "No callback handler!");

	if (!sys_slist_is_empty(&callbacks)) {
		if (!sys_slist_find_and_remove(&callbacks, &cb->node)) {
			if (!set) {
				return -EINVAL;
			}
		}
	}
	if (set) {
		sys_slist_prepend(&callbacks, &cb->node);
		cb_set |= cb->events;
	}
	return 0;
}

int ap_power_ev_add_callback(struct ap_power_ev_callback *cb)
{
	return ap_power_ev_manage_callback(cb, true);
}

int ap_power_ev_remove_callback(struct ap_power_ev_callback *cb)
{
	return ap_power_ev_manage_callback(cb, false);
}

void ap_power_ev_add_events(struct ap_power_ev_callback *cb,
			    enum ap_power_events events)
{
	__ASSERT(cb, "Callback pointer should not be NULL");

	cb->events |= events;
	cb_set |= events;
}

/*
 * Run the callback list
 */
void ap_power_ev_send_callbacks(enum ap_power_events event)
{
	struct ap_power_ev_data data;
	struct ap_power_ev_callback *cb, *tmp;

	/*
	 * If no callbacks for this event, don't run the queue.
	 */
	if ((cb_set & event) == 0) {
		return;
	}
	data.event = event;
	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&callbacks, cb, tmp, node) {
		if (cb->events & event) {
			cb->handler(cb, data);
		}
	}
}