1 /*
2  * Copyright (c) 2022 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_
8 #define ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_
9 
10 #include <stdint.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/smbus.h>
13 #include <zephyr/sys/slist.h>
14 
15 /**
16  * @brief Generic function to insert a callback to a callback list
17  *
18  * @param callbacks A pointer to the original list of callbacks (can be NULL)
19  * @param callback A pointer of the callback to insert to the list
20  *
21  * @return 0 on success, negative errno otherwise.
22  */
smbus_callback_set(sys_slist_t * callbacks,struct smbus_callback * callback)23 static inline int smbus_callback_set(sys_slist_t *callbacks,
24 				     struct smbus_callback *callback)
25 {
26 	__ASSERT(callback, "No callback!");
27 	__ASSERT(callback->handler, "No callback handler!");
28 
29 	if (!sys_slist_is_empty(callbacks)) {
30 		sys_slist_find_and_remove(callbacks, &callback->node);
31 	}
32 
33 	sys_slist_prepend(callbacks, &callback->node);
34 
35 	return 0;
36 }
37 
38 /**
39  * @brief Generic function to remove a callback from a callback list
40  *
41  * @param callbacks A pointer to the original list of callbacks (can be NULL)
42  * @param callback A pointer of the callback to remove from the list
43  *
44  * @return 0 on success, negative errno otherwise.
45  */
smbus_callback_remove(sys_slist_t * callbacks,struct smbus_callback * callback)46 static inline int smbus_callback_remove(sys_slist_t *callbacks,
47 					struct smbus_callback *callback)
48 {
49 	__ASSERT(callback, "No callback!");
50 	__ASSERT(callback->handler, "No callback handler!");
51 
52 	if (sys_slist_is_empty(callbacks) ||
53 	    !sys_slist_find_and_remove(callbacks, &callback->node)) {
54 		return -ENOENT;
55 	}
56 
57 	return 0;
58 }
59 
60 /**
61  * @brief Generic function to go through and fire callback from a callback list
62  *
63  * @param list A pointer on the SMBus callback list
64  * @param dev A pointer on the SMBus device instance
65  * @param addr A SMBus peripheral device address.
66  */
smbus_fire_callbacks(sys_slist_t * list,const struct device * dev,uint8_t addr)67 static inline void smbus_fire_callbacks(sys_slist_t *list,
68 					const struct device *dev,
69 					uint8_t addr)
70 {
71 	struct smbus_callback *cb, *tmp;
72 
73 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(list, cb, tmp, node) {
74 		if (cb->addr == addr) {
75 			__ASSERT(cb->handler, "No callback handler!");
76 			cb->handler(dev, cb, addr);
77 		}
78 	}
79 }
80 
81 /**
82  * @brief Helper to initialize a struct smbus_callback properly
83  *
84  * @param callback A valid Application's callback structure pointer.
85  * @param handler A valid handler function pointer.
86  * @param addr A SMBus peripheral device address.
87  */
smbus_init_callback(struct smbus_callback * callback,smbus_callback_handler_t handler,uint8_t addr)88 static inline void smbus_init_callback(struct smbus_callback *callback,
89 				       smbus_callback_handler_t handler,
90 				       uint8_t addr)
91 {
92 	__ASSERT(callback, "Callback pointer should not be NULL");
93 	__ASSERT(handler, "Callback handler pointer should not be NULL");
94 
95 	callback->handler = handler;
96 	callback->addr = addr;
97 }
98 
99 /**
100  * @brief Helper for handling an SMB alert
101  *
102  * This loops through all devices which triggered the SMB alert and
103  * fires the callbacks.
104  *
105  * @param dev SMBus device
106  * @param callbacks list of SMB alert callbacks
107  */
108 void smbus_loop_alert_devices(const struct device *dev, sys_slist_t *callbacks);
109 
110 #endif /*  ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ */
111