1 /*
2  * Copyright 2023 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 /**
7  * @file
8  * @brief USB Type-C Power Path Controller device API
9  *
10  */
11 
12 #ifndef ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_
13 #define ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_
14 
15 #include <zephyr/types.h>
16 #include <zephyr/device.h>
17 #include <errno.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 /** Type of event being notified by Power Path Controller */
24 enum usbc_ppc_event {
25 	/** Exit from dead-battery mode failed */
26 	USBC_PPC_EVENT_DEAD_BATTERY_ERROR = 0,
27 
28 	/** Overvoltage detected while being in a source role */
29 	USBC_PPC_EVENT_SRC_OVERVOLTAGE,
30 	/** Reverse current detected while being in a source role */
31 	USBC_PPC_EVENT_SRC_REVERSE_CURRENT,
32 	/** Overcurrent detected while being in a source role */
33 	USBC_PPC_EVENT_SRC_OVERCURRENT,
34 	/** VBUS short detected while being in a source role */
35 	USBC_PPC_EVENT_SRC_SHORT,
36 
37 	/** Chip over temperature detected  */
38 	USBC_PPC_EVENT_OVER_TEMPERATURE,
39 	/** Sink and source paths enabled simultaneously */
40 	USBC_PPC_EVENT_BOTH_SNKSRC_ENABLED,
41 
42 	/** Reverse current detected while being in a sink role */
43 	USBC_PPC_EVENT_SNK_REVERSE_CURRENT,
44 	/** VBUS short detected while being in a sink role */
45 	USBC_PPC_EVENT_SNK_SHORT,
46 	/** Overvoltage detected while being in a sink role */
47 	USBC_PPC_EVENT_SNK_OVERVOLTAGE,
48 };
49 
50 typedef void (*usbc_ppc_event_cb_t)(const struct device *dev, void *data, enum usbc_ppc_event ev);
51 
52 /** Structure with pointers to the functions implemented by driver */
53 __subsystem struct usbc_ppc_driver_api {
54 	int (*is_dead_battery_mode)(const struct device *dev);
55 	int (*exit_dead_battery_mode)(const struct device *dev);
56 	int (*is_vbus_source)(const struct device *dev);
57 	int (*is_vbus_sink)(const struct device *dev);
58 	int (*set_snk_ctrl)(const struct device *dev, bool enable);
59 	int (*set_src_ctrl)(const struct device *dev, bool enable);
60 	int (*set_vbus_discharge)(const struct device *dev, bool enable);
61 	int (*is_vbus_present)(const struct device *dev);
62 	int (*set_event_handler)(const struct device *dev, usbc_ppc_event_cb_t handler, void *data);
63 	int (*dump_regs)(const struct device *dev);
64 };
65 
66 /*
67  * API functions
68  */
69 
70 /**
71  * @brief Check if PPC is in the dead battery mode
72  *
73  * @param dev PPC device structure
74  * @retval 1 if PPC is in the dead battery mode
75  * @retval 0 if PPC is not in the dead battery mode
76  * @retval -EIO if I2C communication failed
77  * @retval -ENOSYS if this function is not supported by the driver
78  */
ppc_is_dead_battery_mode(const struct device * dev)79 static inline int ppc_is_dead_battery_mode(const struct device *dev)
80 {
81 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
82 
83 	if (api->is_dead_battery_mode == NULL) {
84 		return -ENOSYS;
85 	}
86 
87 	return api->is_dead_battery_mode(dev);
88 }
89 
90 /**
91  * @brief Request the PPC to exit from the dead battery mode
92  * Return from this call doesn't mean that the PPC is not in the dead battery anymore.
93  * In the case of error, the driver should execute the callback with
94  * USBC_PPC_EVENT_DEAD_BATTERY_ERROR enum. To check if the PPC disabled the dead battery mode,
95  * the call to ppc_is_dead_battery_mode should be done.
96  *
97  * @param dev PPC device structure
98  * @retval 0 if request was successfully sent
99  * @retval -EIO if I2C communication failed
100  * @retval -ENOSYS if this function is not supported by the driver
101  */
ppc_exit_dead_battery_mode(const struct device * dev)102 static inline int ppc_exit_dead_battery_mode(const struct device *dev)
103 {
104 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
105 
106 	if (api->exit_dead_battery_mode == NULL) {
107 		return -ENOSYS;
108 	}
109 
110 	return api->exit_dead_battery_mode(dev);
111 }
112 
113 /**
114  * @brief Check if the PPC is sourcing the VBUS
115  *
116  * @param dev PPC device structure
117  * @retval 1 if the PPC is sourcing the VBUS
118  * @retval 0 if the PPC is not sourcing the VBUS
119  * @retval -EIO if I2C communication failed
120  * @retval -ENOSYS if this function is not supported by the driver
121  */
ppc_is_vbus_source(const struct device * dev)122 static inline int ppc_is_vbus_source(const struct device *dev)
123 {
124 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
125 
126 	if (api->is_vbus_source == NULL) {
127 		return -ENOSYS;
128 	}
129 
130 	return api->is_vbus_source(dev);
131 }
132 
133 /**
134  * @brief Check if the PPC is sinking the VBUS
135  *
136  * @param dev PPC device structure
137  * @retval 1 if the PPC is sinking the VBUS
138  * @retval 0 if the PPC is not sinking the VBUS
139  * @retval -EIO if I2C communication failed
140  * @retval -ENOSYS if this function is not supported by the driver
141  */
ppc_is_vbus_sink(const struct device * dev)142 static inline int ppc_is_vbus_sink(const struct device *dev)
143 {
144 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
145 
146 	if (api->is_vbus_sink == NULL) {
147 		return -ENOSYS;
148 	}
149 
150 	return api->is_vbus_sink(dev);
151 }
152 
153 /**
154  * @brief Set the state of VBUS sinking
155  *
156  * @param dev PPC device structure
157  * @param enable True if sinking VBUS should be enabled, false if should be disabled
158  * @retval 0 if success
159  * @retval -EIO if I2C communication failed
160  * @retval -ENOSYS if this function is not supported by the driver
161  */
ppc_set_snk_ctrl(const struct device * dev,bool enable)162 static inline int ppc_set_snk_ctrl(const struct device *dev, bool enable)
163 {
164 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
165 
166 	if (api->set_snk_ctrl == NULL) {
167 		return -ENOSYS;
168 	}
169 
170 	return api->set_snk_ctrl(dev, enable);
171 }
172 
173 /**
174  * @brief Set the state of VBUS sourcing
175  *
176  * @param dev PPC device structure
177  * @param enable True if sourcing VBUS should be enabled, false if should be disabled
178  * @retval 0 if success
179  * @retval -EIO if I2C communication failed
180  * @retval -ENOSYS if this function is not supported by the driver
181  */
ppc_set_src_ctrl(const struct device * dev,bool enable)182 static inline int ppc_set_src_ctrl(const struct device *dev, bool enable)
183 {
184 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
185 
186 	if (api->set_src_ctrl == NULL) {
187 		return -ENOSYS;
188 	}
189 
190 	return api->set_src_ctrl(dev, enable);
191 }
192 
193 /**
194  * @brief Set the state of VBUS discharging
195  *
196  * @param dev PPC device structure
197  * @param enable True if VBUS discharging should be enabled, false if should be disabled
198  * @retval 0 if success
199  * @retval -EIO if I2C communication failed
200  * @retval -ENOSYS if this function is not supported by the driver
201  */
ppc_set_vbus_discharge(const struct device * dev,bool enable)202 static inline int ppc_set_vbus_discharge(const struct device *dev, bool enable)
203 {
204 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
205 
206 	if (api->set_vbus_discharge == NULL) {
207 		return -ENOSYS;
208 	}
209 
210 	return api->set_vbus_discharge(dev, enable);
211 }
212 
213 /**
214  * @brief Check if VBUS is present
215  *
216  * @param dev PPC device structure
217  * @retval 1 if VBUS voltage is present
218  * @retval 0 if no VBUS voltage is detected
219  * @retval -EIO if I2C communication failed
220  * @retval -ENOSYS if this function is not supported by the driver
221  */
ppc_is_vbus_present(const struct device * dev)222 static inline int ppc_is_vbus_present(const struct device *dev)
223 {
224 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
225 
226 	if (api->is_vbus_present == NULL) {
227 		return -ENOSYS;
228 	}
229 
230 	return api->is_vbus_present(dev);
231 }
232 
233 /**
234  * @brief Set the callback used to notify about PPC events
235  *
236  * @param dev PPC device structure
237  * @param handler Handler that will be called with events notifications
238  * @param data Pointer used as an argument to the callback
239  * @retval 0 if success
240  * @retval -ENOSYS if this function is not supported by the driver
241  */
ppc_set_event_handler(const struct device * dev,usbc_ppc_event_cb_t handler,void * data)242 static inline int ppc_set_event_handler(const struct device *dev,
243 	usbc_ppc_event_cb_t handler, void *data)
244 {
245 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
246 
247 	if (api->set_event_handler == NULL) {
248 		return -ENOSYS;
249 	}
250 
251 	return api->set_event_handler(dev, handler, data);
252 }
253 
254 /**
255  * @brief Print the values or PPC registers
256  *
257  * @param dev PPC device structure
258  * @retval 0 if success
259  * @retval -EIO if I2C communication failed
260  * @retval -ENOSYS if this function is not supported by the driver
261  */
ppc_dump_regs(const struct device * dev)262 static inline int ppc_dump_regs(const struct device *dev)
263 {
264 	const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api;
265 
266 	if (api->dump_regs == NULL) {
267 		return -ENOSYS;
268 	}
269 
270 	return api->dump_regs(dev);
271 }
272 
273 #ifdef __cplusplus
274 }
275 #endif
276 
277 #endif /* ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_ */
278