1 /*
2  * Copyright 2020 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/i2c.h>
8 #include <zephyr/drivers/sensor.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/sys/byteorder.h>
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(max17055, CONFIG_SENSOR_LOG_LEVEL);
14 
15 #include "max17055.h"
16 #include <zephyr/drivers/sensor/max17055.h>
17 
18 #define DT_DRV_COMPAT maxim_max17055
19 
20 /**
21  * @brief Read a register value
22  *
23  * Registers have an address and a 16-bit value
24  *
25  * @param priv Private data for the driver
26  * @param reg_addr Register address to read
27  * @param valp Place to put the value on success
28  * @return 0 if successful, or negative error code from I2C API
29  */
max17055_reg_read(const struct device * dev,uint8_t reg_addr,int16_t * valp)30 static int max17055_reg_read(const struct device *dev, uint8_t reg_addr,
31 			     int16_t *valp)
32 {
33 	const struct max17055_config *config = dev->config;
34 	uint8_t i2c_data[2];
35 	int rc;
36 
37 	rc = i2c_burst_read_dt(&config->i2c, reg_addr, i2c_data, 2);
38 	if (rc < 0) {
39 		LOG_ERR("Unable to read register");
40 		return rc;
41 	}
42 	*valp = sys_get_le16(i2c_data);
43 
44 	return 0;
45 }
46 
max17055_reg_write(const struct device * dev,uint8_t reg_addr,uint16_t val)47 static int max17055_reg_write(const struct device *dev, uint8_t reg_addr,
48 			      uint16_t val)
49 {
50 	const struct max17055_config *config = dev->config;
51 	uint8_t buf[3];
52 
53 	buf[0] = reg_addr;
54 	sys_put_le16(val, &buf[1]);
55 
56 	return i2c_write_dt(&config->i2c, buf, sizeof(buf));
57 }
58 
59 /**
60  * @brief Convert current in MAX17055 units to milliamps
61  *
62  * @param rsense_mohms Value of Rsense in milliohms
63  * @param val Value to convert (taken from a MAX17055 register)
64  * @return corresponding value in milliamps
65  */
current_to_ma(uint16_t rsense_mohms,int16_t val)66 static int current_to_ma(uint16_t rsense_mohms, int16_t val)
67 {
68 	return (int32_t)val * 25 / rsense_mohms / 16; /* * 1.5625 */
69 }
70 
71 /**
72  * @brief Convert current in milliamps to MAX17055 units
73  *
74  * @param rsense_mohms Value of Rsense in milliohms
75  * @param val Value in mA to convert
76  * @return corresponding value in MAX17055 units, ready to write to a register
77  */
current_ma_to_max17055(uint16_t rsense_mohms,uint16_t val)78 static int current_ma_to_max17055(uint16_t rsense_mohms, uint16_t val)
79 {
80 	return (int32_t)val * rsense_mohms * 16 / 25; /* / 1.5625 */
81 }
82 
83 /**
84  * @brief Convert capacity in MAX17055 units to milliamps
85  *
86  * @param rsense_mohms Value of Rsense in milliohms
87  * @param val Value to convert (taken from a MAX17055 register)
88  * @return corresponding value in milliamps
89  */
capacity_to_ma(unsigned int rsense_mohms,int16_t val)90 static int capacity_to_ma(unsigned int rsense_mohms, int16_t val)
91 {
92 	int lsb_units, rem;
93 
94 	/* Get units for the LSB in uA */
95 	lsb_units = 5 * 1000 / rsense_mohms;
96 	/* Get remaining capacity in uA */
97 	rem = val * lsb_units;
98 
99 	return rem;
100 }
101 
102 /**
103  * @brief Convert capacity in milliamphours to MAX17055 units
104  *
105  * @param rsense_mohms Value of Rsense in milliohms
106  * @param val_mha Value in milliamphours to convert
107  * @return corresponding value in MAX17055 units, ready to write to a register
108  */
capacity_to_max17055(unsigned int rsense_mohms,uint16_t val_mha)109 static int capacity_to_max17055(unsigned int rsense_mohms, uint16_t val_mha)
110 {
111 	return val_mha * rsense_mohms / 5;
112 }
113 
114 /**
115  * @brief Update empty voltage target in v_empty
116  *
117  * @param v_empty The register value to update
118  * @param val_mv Value in millivolts to convert
119  * @return 0 on success, -EINVAL on invalid val_mv
120  */
max17055_update_vempty(uint16_t * v_empty,uint16_t val_mv)121 static int max17055_update_vempty(uint16_t *v_empty, uint16_t val_mv)
122 {
123 	uint32_t val = (val_mv / 10) << 7;
124 
125 	if (val & ~VEMPTY_VE) {
126 		return -EINVAL;
127 	}
128 
129 	*v_empty = (*v_empty & ~VEMPTY_VE) | (uint16_t)val;
130 
131 	return 0;
132 }
133 
set_millis(struct sensor_value * val,int val_millis)134 static void set_millis(struct sensor_value *val, int val_millis)
135 {
136 	val->val1 = val_millis / 1000;
137 	val->val2 = (val_millis % 1000) * 1000;
138 }
139 
140 /**
141  * @brief sensor value get
142  *
143  * @param dev MAX17055 device to access
144  * @param chan Channel number to read
145  * @param valp Returns the sensor value read on success
146  * @return 0 if successful
147  * @return -ENOTSUP for unsupported channels
148  */
max17055_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * valp)149 static int max17055_channel_get(const struct device *dev,
150 				enum sensor_channel chan,
151 				struct sensor_value *valp)
152 {
153 	const struct max17055_config *const config = dev->config;
154 	struct max17055_data *const priv = dev->data;
155 	unsigned int tmp;
156 
157 	switch (chan) {
158 	case SENSOR_CHAN_GAUGE_VOLTAGE:
159 		/* Get voltage in uV */
160 		tmp = priv->voltage * 1250 / 16;
161 		valp->val1 = tmp / 1000000;
162 		valp->val2 = tmp % 1000000;
163 		break;
164 	case SENSOR_CHAN_MAX17055_VFOCV:
165 		tmp = priv->ocv * 1250 / 16;
166 		valp->val1 = tmp / 1000000;
167 		valp->val2 = tmp % 1000000;
168 		break;
169 	case SENSOR_CHAN_GAUGE_AVG_CURRENT: {
170 		int current_ma;
171 
172 		current_ma = current_to_ma(config->rsense_mohms, priv->avg_current);
173 		set_millis(valp, current_ma);
174 		break;
175 	}
176 	case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
177 		valp->val1 = priv->state_of_charge / 256;
178 		valp->val2 = priv->state_of_charge % 256 * 1000000 / 256;
179 		break;
180 	case SENSOR_CHAN_GAUGE_TEMP:
181 		valp->val1 = priv->internal_temp / 256;
182 		valp->val2 = priv->internal_temp % 256 * 1000000 / 256;
183 		break;
184 	case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY:
185 		tmp = capacity_to_ma(config->rsense_mohms, priv->full_cap);
186 		set_millis(valp, tmp);
187 		break;
188 	case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY:
189 		tmp = capacity_to_ma(config->rsense_mohms, priv->remaining_cap);
190 		set_millis(valp, tmp);
191 		break;
192 	case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY:
193 		if (priv->time_to_empty == 0xffff) {
194 			valp->val1 = 0;
195 			valp->val2 = 0;
196 		} else {
197 			/* Get time in milli-minutes */
198 			tmp = priv->time_to_empty * 5625 / 60;
199 			set_millis(valp, tmp);
200 		}
201 		break;
202 	case SENSOR_CHAN_GAUGE_TIME_TO_FULL:
203 		if (priv->time_to_full == 0xffff) {
204 			valp->val1 = 0;
205 			valp->val2 = 0;
206 		} else {
207 			/* Get time in milli-minutes */
208 			tmp = priv->time_to_full * 5625 / 60;
209 			set_millis(valp, tmp);
210 		}
211 		break;
212 	case SENSOR_CHAN_GAUGE_CYCLE_COUNT:
213 		valp->val1 = priv->cycle_count / 100;
214 		valp->val2 = priv->cycle_count % 100 * 10000;
215 		break;
216 	case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY:
217 		tmp = capacity_to_ma(config->rsense_mohms, priv->design_cap);
218 		set_millis(valp, tmp);
219 		break;
220 	case SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE:
221 		set_millis(valp, config->design_voltage);
222 		break;
223 	case SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE:
224 		set_millis(valp, config->desired_voltage);
225 		break;
226 	case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT:
227 		valp->val1 = config->desired_charging_current;
228 		valp->val2 = 0;
229 		break;
230 	default:
231 		return -ENOTSUP;
232 	}
233 
234 	return 0;
235 }
236 
max17055_sample_fetch(const struct device * dev,enum sensor_channel chan)237 static int max17055_sample_fetch(const struct device *dev,
238 				 enum sensor_channel chan)
239 {
240 	struct max17055_data *priv = dev->data;
241 	int ret = -ENOTSUP;
242 
243 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_VOLTAGE) {
244 		ret = max17055_reg_read(dev, VCELL, &priv->voltage);
245 		if (ret < 0) {
246 			return ret;
247 		}
248 	}
249 
250 	if (chan == SENSOR_CHAN_ALL ||
251 	    (enum sensor_channel_max17055)chan == SENSOR_CHAN_MAX17055_VFOCV) {
252 		ret = max17055_reg_read(dev, VFOCV, &priv->ocv);
253 		if (ret < 0) {
254 			return ret;
255 		}
256 	}
257 
258 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_AVG_CURRENT) {
259 		ret = max17055_reg_read(dev, AVG_CURRENT, &priv->avg_current);
260 		if (ret < 0) {
261 			return ret;
262 		}
263 	}
264 
265 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_STATE_OF_CHARGE) {
266 		ret = max17055_reg_read(dev, REP_SOC, &priv->state_of_charge);
267 		if (ret < 0) {
268 			return ret;
269 		}
270 	}
271 
272 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_TEMP) {
273 		ret = max17055_reg_read(dev, INT_TEMP, &priv->internal_temp);
274 		if (ret < 0) {
275 			return ret;
276 		}
277 	}
278 
279 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY) {
280 		ret = max17055_reg_read(dev, REP_CAP, &priv->remaining_cap);
281 		if (ret < 0) {
282 			return ret;
283 		}
284 	}
285 
286 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY) {
287 		ret = max17055_reg_read(dev, FULL_CAP_REP, &priv->full_cap);
288 		if (ret < 0) {
289 			return ret;
290 		}
291 	}
292 
293 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_TIME_TO_EMPTY) {
294 		ret = max17055_reg_read(dev, TTE, &priv->time_to_empty);
295 		if (ret < 0) {
296 			return ret;
297 		}
298 	}
299 
300 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_TIME_TO_FULL) {
301 		ret = max17055_reg_read(dev, TTF, &priv->time_to_full);
302 		if (ret < 0) {
303 			return ret;
304 		}
305 	}
306 
307 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_CYCLE_COUNT) {
308 		ret = max17055_reg_read(dev, CYCLES, &priv->cycle_count);
309 		if (ret < 0) {
310 			return ret;
311 		}
312 	}
313 
314 	if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY) {
315 		ret = max17055_reg_read(dev, DESIGN_CAP, &priv->design_cap);
316 		if (ret < 0) {
317 			return ret;
318 		}
319 	}
320 
321 	return ret;
322 }
323 
max17055_exit_hibernate(const struct device * dev)324 static int max17055_exit_hibernate(const struct device *dev)
325 {
326 	LOG_DBG("Exit hibernate");
327 
328 	if (max17055_reg_write(dev, SOFT_WAKEUP, SOFT_WAKEUP_WAKEUP)) {
329 		return -EIO;
330 	}
331 	if (max17055_reg_write(dev, HIB_CFG, HIB_CFG_CLEAR)) {
332 		return -EIO;
333 	}
334 	if (max17055_reg_write(dev, SOFT_WAKEUP, SOFT_WAKEUP_CLEAR)) {
335 		return -EIO;
336 	}
337 
338 	return 0;
339 }
340 
max17055_write_config(const struct device * dev)341 static int max17055_write_config(const struct device *dev)
342 {
343 	const struct max17055_config *config = dev->config;
344 
345 	uint16_t design_capacity = capacity_to_max17055(config->rsense_mohms,
346 							config->design_capacity);
347 	uint16_t d_qacc = design_capacity / 32;
348 	uint16_t d_pacc = d_qacc * 44138 / design_capacity;
349 	uint16_t i_chg_term = current_ma_to_max17055(config->rsense_mohms, config->i_chg_term);
350 	uint16_t v_empty;
351 	int ret;
352 
353 	LOG_DBG("Writing configuration parameters");
354 	LOG_DBG("DesignCap: %u, dQAcc: %u, IChgTerm: %u, dPAcc: %u",
355 		design_capacity, d_qacc, i_chg_term, d_pacc);
356 
357 	if (max17055_reg_write(dev, DESIGN_CAP, design_capacity)) {
358 		return -EIO;
359 	}
360 
361 	if (max17055_reg_write(dev, D_QACC, d_qacc)) {
362 		return -EIO;
363 	}
364 
365 	if (max17055_reg_write(dev, ICHG_TERM, i_chg_term)) {
366 		return -EIO;
367 	}
368 
369 	if (max17055_reg_read(dev, V_EMPTY, &v_empty)) {
370 		return -EIO;
371 	}
372 	if (max17055_update_vempty(&v_empty, config->v_empty)) {
373 		return -EINVAL;
374 	}
375 	if (max17055_reg_write(dev, V_EMPTY, v_empty)) {
376 		return -EIO;
377 	}
378 
379 	if (max17055_reg_write(dev, D_PACC, d_pacc)) {
380 		return -EIO;
381 	}
382 
383 	if (max17055_reg_write(dev, MODEL_CFG, MODELCFG_REFRESH)) {
384 		return -EIO;
385 	}
386 
387 	uint16_t model_cfg = MODELCFG_REFRESH;
388 
389 	while (model_cfg & MODELCFG_REFRESH) {
390 		ret = max17055_reg_read(dev, MODEL_CFG, &model_cfg);
391 		if (ret) {
392 			return ret;
393 		}
394 		k_sleep(K_MSEC(10));
395 	}
396 
397 	return 0;
398 }
399 
max17055_init_config(const struct device * dev)400 static int max17055_init_config(const struct device *dev)
401 {
402 	int16_t hib_cfg;
403 
404 	if (max17055_reg_read(dev, HIB_CFG, &hib_cfg)) {
405 		return -EIO;
406 	}
407 
408 	if (max17055_exit_hibernate(dev)) {
409 		return -EIO;
410 	}
411 
412 	if (max17055_write_config(dev)) {
413 		return -EIO;
414 	}
415 
416 	if (max17055_reg_write(dev, HIB_CFG, hib_cfg)) {
417 		return -EIO;
418 	}
419 
420 	return 0;
421 }
422 
423 /**
424  * @brief initialise the fuel gauge
425  *
426  * @return 0 for success
427  * @return -EIO on I2C communication error
428  * @return -EINVAL if the I2C controller could not be found
429  */
max17055_gauge_init(const struct device * dev)430 static int max17055_gauge_init(const struct device *dev)
431 {
432 	int16_t tmp;
433 	const struct max17055_config *const config = dev->config;
434 	int ret;
435 
436 	if (!device_is_ready(config->i2c.bus)) {
437 		LOG_ERR("Bus device is not ready");
438 		return -ENODEV;
439 	}
440 
441 	if (max17055_reg_read(dev, STATUS, &tmp)) {
442 		return -EIO;
443 	}
444 
445 	if (!(tmp & STATUS_POR)) {
446 		LOG_DBG("No POR event detected - skip device configuration");
447 		return 0;
448 	}
449 
450 	/* Wait for FSTAT_DNR to be cleared */
451 	tmp = FSTAT_DNR;
452 	while (tmp & FSTAT_DNR) {
453 		ret = max17055_reg_read(dev, FSTAT, &tmp);
454 		if (ret) {
455 			return ret;
456 		}
457 	}
458 
459 	if (max17055_init_config(dev)) {
460 		return -EIO;
461 	}
462 
463 	/* Clear PowerOnReset bit */
464 	if (max17055_reg_read(dev, STATUS, &tmp)) {
465 		return -EIO;
466 	}
467 
468 	tmp &= ~STATUS_POR;
469 	return max17055_reg_write(dev, STATUS, tmp);
470 }
471 
472 static const struct sensor_driver_api max17055_battery_driver_api = {
473 	.sample_fetch = max17055_sample_fetch,
474 	.channel_get = max17055_channel_get,
475 };
476 
477 #define MAX17055_INIT(index)								   \
478 	static struct max17055_data max17055_driver_##index;				   \
479 											   \
480 	static const struct max17055_config max17055_config_##index = {			   \
481 		.i2c = I2C_DT_SPEC_INST_GET(index),					   \
482 		.design_capacity = DT_INST_PROP(index, design_capacity),		   \
483 		.design_voltage = DT_INST_PROP(index, design_voltage),			   \
484 		.desired_charging_current = DT_INST_PROP(index, desired_charging_current), \
485 		.desired_voltage = DT_INST_PROP(index, desired_voltage),		   \
486 		.i_chg_term = DT_INST_PROP(index, i_chg_term),				   \
487 		.rsense_mohms = DT_INST_PROP(index, rsense_mohms),			   \
488 		.v_empty = DT_INST_PROP(index, v_empty),				   \
489 	};										   \
490 											   \
491 	SENSOR_DEVICE_DT_INST_DEFINE(index, &max17055_gauge_init,			   \
492 			      NULL,							   \
493 			      &max17055_driver_##index,					   \
494 			      &max17055_config_##index, POST_KERNEL,			   \
495 			      CONFIG_SENSOR_INIT_PRIORITY,				   \
496 			      &max17055_battery_driver_api)
497 
498 DT_INST_FOREACH_STATUS_OKAY(MAX17055_INIT);
499