1 /*
2  * Copyright 2022 Google LLC
3  * Copyright 2023 Microsoft Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #ifndef ZEPHYR_INCLUDE_DRIVERS_BATTERY_H_
9 #define ZEPHYR_INCLUDE_DRIVERS_BATTERY_H_
10 
11 /**
12  * @brief Fuel Gauge Interface
13  * @defgroup fuel_gauge_interface Fuel Gauge Interface
14  * @since 3.3
15  * @version 0.1.0
16  * @ingroup io_interfaces
17  * @{
18  */
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif /* __cplusplus */
23 
24 #include <errno.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <stdint.h>
28 
29 #include <zephyr/device.h>
30 
31 enum fuel_gauge_prop_type {
32 	/** Runtime Dynamic Battery Parameters */
33 	/**
34 	 * Provide a 1 minute average of the current on the battery.
35 	 * Does not check for flags or whether those values are bad readings.
36 	 * See driver instance header for details on implementation and
37 	 * how the average is calculated. Units in uA negative=discharging
38 	 */
39 	FUEL_GAUGE_AVG_CURRENT = 0,
40 
41 	/** Used to cutoff the battery from the system - useful for storage/shipping of devices */
42 	FUEL_GAUGE_BATTERY_CUTOFF,
43 	/** Battery current (uA); negative=discharging */
44 	FUEL_GAUGE_CURRENT,
45 	/** Whether the battery underlying the fuel-gauge is cut off from charge */
46 	FUEL_GAUGE_CHARGE_CUTOFF,
47 	/** Cycle count in 1/100ths (number of charge/discharge cycles) */
48 	FUEL_GAUGE_CYCLE_COUNT,
49 	/** Connect state of battery */
50 	FUEL_GAUGE_CONNECT_STATE,
51 	/** General Error/Runtime Flags */
52 	FUEL_GAUGE_FLAGS,
53 	/** Full Charge Capacity in uAh (might change in some implementations to determine wear) */
54 	FUEL_GAUGE_FULL_CHARGE_CAPACITY,
55 	/** Is the battery physically present */
56 	FUEL_GAUGE_PRESENT_STATE,
57 	/** Remaining capacity in uAh */
58 	FUEL_GAUGE_REMAINING_CAPACITY,
59 	/** Remaining battery life time in minutes */
60 	FUEL_GAUGE_RUNTIME_TO_EMPTY,
61 	/** Remaining time in minutes until battery reaches full charge */
62 	FUEL_GAUGE_RUNTIME_TO_FULL,
63 	/** Retrieve word from SBS1.1 ManufactuerAccess */
64 	FUEL_GAUGE_SBS_MFR_ACCESS,
65 	/** Absolute state of charge (percent, 0-100) - expressed as % of design capacity */
66 	FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE,
67 	/** Relative state of charge (percent, 0-100) - expressed as % of full charge capacity */
68 	FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE,
69 	/** Temperature in 0.1 K */
70 	FUEL_GAUGE_TEMPERATURE,
71 	/** Battery voltage (uV) */
72 	FUEL_GAUGE_VOLTAGE,
73 	/** Battery Mode (flags) */
74 	FUEL_GAUGE_SBS_MODE,
75 	/** Battery desired Max Charging Current (uA) */
76 	FUEL_GAUGE_CHARGE_CURRENT,
77 	/** Battery desired Max Charging Voltage (uV) */
78 	FUEL_GAUGE_CHARGE_VOLTAGE,
79 	/** Alarm, Status and Error codes (flags) */
80 	FUEL_GAUGE_STATUS,
81 	/** Design Capacity (mAh or 10mWh) */
82 	FUEL_GAUGE_DESIGN_CAPACITY,
83 	/** Design Voltage (mV) */
84 	FUEL_GAUGE_DESIGN_VOLTAGE,
85 	/** AtRate (mA or 10 mW) */
86 	FUEL_GAUGE_SBS_ATRATE,
87 	/** AtRateTimeToFull (minutes) */
88 	FUEL_GAUGE_SBS_ATRATE_TIME_TO_FULL,
89 	/** AtRateTimeToEmpty (minutes) */
90 	FUEL_GAUGE_SBS_ATRATE_TIME_TO_EMPTY,
91 	/** AtRateOK (boolean) */
92 	FUEL_GAUGE_SBS_ATRATE_OK,
93 	/** Remaining Capacity Alarm (mAh or 10mWh) */
94 	FUEL_GAUGE_SBS_REMAINING_CAPACITY_ALARM,
95 	/** Remaining Time Alarm (minutes) */
96 	FUEL_GAUGE_SBS_REMAINING_TIME_ALARM,
97 	/** Manufacturer of pack (1 byte length + 20 bytes data) */
98 	FUEL_GAUGE_MANUFACTURER_NAME,
99 	/** Name of pack (1 byte length + 20 bytes data) */
100 	FUEL_GAUGE_DEVICE_NAME,
101 	/** Chemistry (1 byte length + 4 bytes data) */
102 	FUEL_GAUGE_DEVICE_CHEMISTRY,
103 
104 	/** Reserved to demark end of common fuel gauge properties */
105 	FUEL_GAUGE_COMMON_COUNT,
106 	/**
107 	 * Reserved to demark downstream custom properties - use this value as the actual value may
108 	 * change over future versions of this API
109 	 */
110 	FUEL_GAUGE_CUSTOM_BEGIN,
111 
112 	/** Reserved to demark end of valid enum properties */
113 	FUEL_GAUGE_PROP_MAX = UINT16_MAX,
114 };
115 
116 typedef uint16_t fuel_gauge_prop_t;
117 
118 /** Property field to value/type union */
119 union fuel_gauge_prop_val {
120 	/* Fields have the format: */
121 	/* FUEL_GAUGE_PROPERTY_FIELD */
122 	/* type property_field; */
123 
124 	/* Dynamic Battery Info */
125 	/** FUEL_GAUGE_AVG_CURRENT */
126 	int avg_current;
127 	/** FUEL_GAUGE_CHARGE_CUTOFF */
128 	bool cutoff;
129 	/** FUEL_GAUGE_CURRENT */
130 	int current;
131 	/** FUEL_GAUGE_CYCLE_COUNT */
132 	uint32_t cycle_count;
133 	/** FUEL_GAUGE_FLAGS */
134 	uint32_t flags;
135 	/** FUEL_GAUGE_FULL_CHARGE_CAPACITY */
136 	uint32_t full_charge_capacity;
137 	/** FUEL_GAUGE_REMAINING_CAPACITY */
138 	uint32_t remaining_capacity;
139 	/** FUEL_GAUGE_RUNTIME_TO_EMPTY */
140 	uint32_t runtime_to_empty;
141 	/** FUEL_GAUGE_RUNTIME_TO_FULL */
142 	uint32_t runtime_to_full;
143 	/** FUEL_GAUGE_SBS_MFR_ACCESS */
144 	uint16_t sbs_mfr_access_word;
145 	/** FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE */
146 	uint8_t absolute_state_of_charge;
147 	/** FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE */
148 	uint8_t relative_state_of_charge;
149 	/** FUEL_GAUGE_TEMPERATURE */
150 	uint16_t temperature;
151 	/** FUEL_GAUGE_VOLTAGE */
152 	int voltage;
153 	/** FUEL_GAUGE_SBS_MODE */
154 	uint16_t sbs_mode;
155 	/** FUEL_GAUGE_CHARGE_CURRENT */
156 	uint32_t chg_current;
157 	/** FUEL_GAUGE_CHARGE_VOLTAGE */
158 	uint32_t chg_voltage;
159 	/** FUEL_GAUGE_STATUS */
160 	uint16_t fg_status;
161 	/** FUEL_GAUGE_DESIGN_CAPACITY */
162 	uint16_t design_cap;
163 	/** FUEL_GAUGE_DESIGN_VOLTAGE */
164 	uint16_t design_volt;
165 	/** FUEL_GAUGE_SBS_ATRATE */
166 	int16_t sbs_at_rate;
167 	/** FUEL_GAUGE_SBS_ATRATE_TIME_TO_FULL */
168 	uint16_t sbs_at_rate_time_to_full;
169 	/** FUEL_GAUGE_SBS_ATRATE_TIME_TO_EMPTY	*/
170 	uint16_t sbs_at_rate_time_to_empty;
171 	/** FUEL_GAUGE_SBS_ATRATE_OK */
172 	bool sbs_at_rate_ok;
173 	/** FUEL_GAUGE_SBS_REMAINING_CAPACITY_ALARM */
174 	uint16_t sbs_remaining_capacity_alarm;
175 	/** FUEL_GAUGE_SBS_REMAINING_TIME_ALARM */
176 	uint16_t sbs_remaining_time_alarm;
177 };
178 
179 /**
180  * Data structures for reading SBS buffer properties
181  */
182 #define SBS_GAUGE_MANUFACTURER_NAME_MAX_SIZE 20
183 #define SBS_GAUGE_DEVICE_NAME_MAX_SIZE       20
184 #define SBS_GAUGE_DEVICE_CHEMISTRY_MAX_SIZE  4
185 
186 struct sbs_gauge_manufacturer_name {
187 	uint8_t manufacturer_name_length;
188 	char manufacturer_name[SBS_GAUGE_MANUFACTURER_NAME_MAX_SIZE];
189 } __packed;
190 
191 struct sbs_gauge_device_name {
192 	uint8_t device_name_length;
193 	char device_name[SBS_GAUGE_DEVICE_NAME_MAX_SIZE];
194 } __packed;
195 
196 struct sbs_gauge_device_chemistry {
197 	uint8_t device_chemistry_length;
198 	char device_chemistry[SBS_GAUGE_DEVICE_CHEMISTRY_MAX_SIZE];
199 } __packed;
200 
201 /**
202  * @typedef fuel_gauge_get_property_t
203  * @brief Callback API for getting a fuel_gauge property.
204  *
205  * See fuel_gauge_get_property() for argument description
206  */
207 typedef int (*fuel_gauge_get_property_t)(const struct device *dev, fuel_gauge_prop_t prop,
208 					 union fuel_gauge_prop_val *val);
209 
210 /**
211  * @typedef fuel_gauge_set_property_t
212  * @brief Callback API for setting a fuel_gauge property.
213  *
214  * See fuel_gauge_set_property() for argument description
215  */
216 typedef int (*fuel_gauge_set_property_t)(const struct device *dev, fuel_gauge_prop_t prop,
217 					 union fuel_gauge_prop_val val);
218 
219 /**
220  * @typedef fuel_gauge_get_buffer_property_t
221  * @brief Callback API for getting a fuel_gauge buffer property.
222  *
223  * See fuel_gauge_get_buffer_property() for argument description
224  */
225 typedef int (*fuel_gauge_get_buffer_property_t)(const struct device *dev,
226 					       fuel_gauge_prop_t prop_type,
227 					       void *dst, size_t dst_len);
228 
229 /**
230  * @typedef fuel_gauge_battery_cutoff_t
231  * @brief Callback API for doing a battery cutoff.
232  *
233  * See fuel_gauge_battery_cutoff() for argument description
234  */
235 typedef int (*fuel_gauge_battery_cutoff_t)(const struct device *dev);
236 
237 /* Caching is entirely on the onus of the client */
238 
239 __subsystem struct fuel_gauge_driver_api {
240 	/**
241 	 * Note: Historically this API allowed drivers to implement a custom multi-get/set property
242 	 * function, this was added so drivers could potentially optimize batch read with their
243 	 * specific chip. However, it was removed because of no existing concrete case upstream.
244 	 * If this need is demonstrated, we can add this back in as an API field.
245 	 */
246 	fuel_gauge_get_property_t get_property;
247 	fuel_gauge_set_property_t set_property;
248 	fuel_gauge_get_buffer_property_t get_buffer_property;
249 	fuel_gauge_battery_cutoff_t battery_cutoff;
250 };
251 
252 /**
253  * @brief Fetch a battery fuel-gauge property
254  *
255  * @param dev Pointer to the battery fuel-gauge device
256  * @param prop Type of property to be fetched from device
257  * @param val pointer to a union fuel_gauge_prop_val where the property is read into from the
258  * fuel gauge device.
259  * @return 0 if successful, negative errno code if failure.
260  */
261 __syscall int fuel_gauge_get_prop(const struct device *dev, fuel_gauge_prop_t prop,
262 				  union fuel_gauge_prop_val *val);
263 
z_impl_fuel_gauge_get_prop(const struct device * dev,fuel_gauge_prop_t prop,union fuel_gauge_prop_val * val)264 static inline int z_impl_fuel_gauge_get_prop(const struct device *dev, fuel_gauge_prop_t prop,
265 					     union fuel_gauge_prop_val *val)
266 {
267 	const struct fuel_gauge_driver_api *api = (const struct fuel_gauge_driver_api *)dev->api;
268 
269 	if (api->get_property == NULL) {
270 		return -ENOSYS;
271 	}
272 
273 	return api->get_property(dev, prop, val);
274 }
275 
276 /**
277  * @brief Fetch multiple battery fuel-gauge properties. The default implementation is the same as
278  * calling fuel_gauge_get_prop() multiple times. A driver may implement the `get_properties` field
279  * of the fuel gauge driver APIs struct to override this implementation.
280  *
281  * @param dev Pointer to the battery fuel-gauge device
282  * @param props Array of the type of property to be fetched from device, each index corresponds
283  * to the same index of the vals input array.
284  * @param vals Pointer to array of union fuel_gauge_prop_val where the property is read into from
285  * the fuel gauge device. The vals array is not permuted.
286  * @param len number of properties in props & vals array
287  *
288  * @return 0 if successful, negative errno code of first failing property
289  */
290 
291 __syscall int fuel_gauge_get_props(const struct device *dev, fuel_gauge_prop_t *props,
292 				   union fuel_gauge_prop_val *vals, size_t len);
z_impl_fuel_gauge_get_props(const struct device * dev,fuel_gauge_prop_t * props,union fuel_gauge_prop_val * vals,size_t len)293 static inline int z_impl_fuel_gauge_get_props(const struct device *dev,
294 					      fuel_gauge_prop_t *props,
295 					      union fuel_gauge_prop_val *vals, size_t len)
296 {
297 	const struct fuel_gauge_driver_api *api = dev->api;
298 
299 	for (int i = 0; i < len; i++) {
300 		int ret = api->get_property(dev, props[i], vals + i);
301 
302 		if (ret) {
303 			return ret;
304 		}
305 	}
306 
307 	return 0;
308 }
309 
310 /**
311  * @brief Set a battery fuel-gauge property
312  *
313  * @param dev Pointer to the battery fuel-gauge device
314  * @param prop Type of property that's being set
315  * @param val Value to set associated prop property.
316  *
317  * @return 0 if successful, negative errno code of first failing property
318  */
319 __syscall int fuel_gauge_set_prop(const struct device *dev, fuel_gauge_prop_t prop,
320 				  union fuel_gauge_prop_val val);
321 
z_impl_fuel_gauge_set_prop(const struct device * dev,fuel_gauge_prop_t prop,union fuel_gauge_prop_val val)322 static inline int z_impl_fuel_gauge_set_prop(const struct device *dev, fuel_gauge_prop_t prop,
323 					     union fuel_gauge_prop_val val)
324 {
325 	const struct fuel_gauge_driver_api *api = dev->api;
326 
327 	if (api->set_property == NULL) {
328 		return -ENOSYS;
329 	}
330 
331 	return api->set_property(dev, prop, val);
332 }
333 /**
334  * @brief Set a battery fuel-gauge property
335  *
336  * @param dev Pointer to the battery fuel-gauge device
337  * @param props Array of the type of property to be set, each index corresponds
338  * to the same index of the vals input array.
339  * @param vals Pointer to array of union fuel_gauge_prop_val where the property is written
340  * the fuel gauge device. The vals array is not permuted.
341  * @param len number of properties in props array
342  *
343  * @return return=0 if successful. Otherwise, return array index of failing property.
344  */
345 __syscall int fuel_gauge_set_props(const struct device *dev, fuel_gauge_prop_t *props,
346 				   union fuel_gauge_prop_val *vals, size_t len);
347 
z_impl_fuel_gauge_set_props(const struct device * dev,fuel_gauge_prop_t * props,union fuel_gauge_prop_val * vals,size_t len)348 static inline int z_impl_fuel_gauge_set_props(const struct device *dev,
349 					      fuel_gauge_prop_t *props,
350 					      union fuel_gauge_prop_val *vals, size_t len)
351 {
352 	for (int i = 0; i < len; i++) {
353 		int ret = fuel_gauge_set_prop(dev, props[i], vals[i]);
354 
355 		if (ret) {
356 			return ret;
357 		}
358 	}
359 
360 	return 0;
361 }
362 
363 /**
364  * @brief Fetch a battery fuel-gauge buffer property
365  *
366  * @param dev Pointer to the battery fuel-gauge device
367  * @param prop_type Type of property to be fetched from device
368  * @param dst byte array or struct that will hold the buffer data that is read from the fuel gauge
369  * @param dst_len the length of the destination array in bytes
370  *
371  * @return return=0 if successful, return < 0 if getting property failed, return 0 on success
372  */
373 
374 __syscall int fuel_gauge_get_buffer_prop(const struct device *dev, fuel_gauge_prop_t prop_type,
375 					 void *dst, size_t dst_len);
376 
z_impl_fuel_gauge_get_buffer_prop(const struct device * dev,fuel_gauge_prop_t prop_type,void * dst,size_t dst_len)377 static inline int z_impl_fuel_gauge_get_buffer_prop(const struct device *dev,
378 						   fuel_gauge_prop_t prop_type,
379 						   void *dst, size_t dst_len)
380 {
381 	const struct fuel_gauge_driver_api *api = (const struct fuel_gauge_driver_api *)dev->api;
382 
383 	if (api->get_buffer_property == NULL) {
384 		return -ENOSYS;
385 	}
386 
387 	return api->get_buffer_property(dev, prop_type, dst, dst_len);
388 }
389 
390 /**
391  * @brief Have fuel gauge cutoff its associated battery.
392  *
393  * @param dev Pointer to the battery fuel-gauge device
394  *
395  * @return return=0 if successful and battery cutoff is now in process, return < 0 if failed to do
396  * battery cutoff.
397  */
398 __syscall int fuel_gauge_battery_cutoff(const struct device *dev);
399 
z_impl_fuel_gauge_battery_cutoff(const struct device * dev)400 static inline int z_impl_fuel_gauge_battery_cutoff(const struct device *dev)
401 {
402 	const struct fuel_gauge_driver_api *api = (const struct fuel_gauge_driver_api *)dev->api;
403 
404 	if (api->battery_cutoff == NULL) {
405 		return -ENOSYS;
406 	}
407 
408 	return api->battery_cutoff(dev);
409 }
410 
411 /**
412  * @}
413  */
414 
415 #ifdef __cplusplus
416 }
417 #endif /* __cplusplus */
418 
419 #include <zephyr/syscalls/fuel_gauge.h>
420 
421 #endif /* ZEPHYR_INCLUDE_DRIVERS_BATTERY_H_ */
422