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