1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT nordic_npm1300_charger
7 
8 #include <math.h>
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/drivers/mfd/npm1300.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/linear_range.h>
13 #include <zephyr/drivers/sensor/npm1300_charger.h>
14 
15 struct npm1300_charger_config {
16 	const struct device *mfd;
17 	int32_t term_microvolt;
18 	int32_t term_warm_microvolt;
19 	int32_t current_microamp;
20 	int32_t dischg_limit_microamp;
21 	int32_t vbus_limit_microamp;
22 	int32_t temp_thresholds[4U];
23 	uint32_t thermistor_ohms;
24 	uint16_t thermistor_beta;
25 	uint8_t thermistor_idx;
26 	uint8_t trickle_sel;
27 	uint8_t iterm_sel;
28 	bool charging_enable;
29 	bool vbatlow_charge_enable;
30 	bool disable_recharge;
31 };
32 
33 struct npm1300_charger_data {
34 	uint16_t voltage;
35 	uint16_t current;
36 	uint16_t temp;
37 	uint8_t status;
38 	uint8_t error;
39 	uint8_t ibat_stat;
40 	uint8_t vbus_stat;
41 };
42 
43 /* nPM1300 base addresses */
44 #define CHGR_BASE 0x03U
45 #define ADC_BASE  0x05U
46 #define VBUS_BASE 0x02U
47 
48 /* nPM1300 charger register offsets */
49 #define CHGR_OFFSET_ERR_CLR     0x00U
50 #define CHGR_OFFSET_EN_SET      0x04U
51 #define CHGR_OFFSET_EN_CLR      0x05U
52 #define CHGR_OFFSET_DIS_SET     0x06U
53 #define CHGR_OFFSET_ISET        0x08U
54 #define CHGR_OFFSET_ISET_DISCHG 0x0AU
55 #define CHGR_OFFSET_VTERM       0x0CU
56 #define CHGR_OFFSET_VTERM_R     0x0DU
57 #define CHGR_OFFSET_TRICKLE_SEL 0x0EU
58 #define CHGR_OFFSET_ITERM_SEL   0x0FU
59 #define CHGR_OFFSET_NTC_TEMPS   0x10U
60 #define CHGR_OFFSET_CHG_STAT    0x34U
61 #define CHGR_OFFSET_ERR_REASON  0x36U
62 #define CHGR_OFFSET_VBATLOW_EN  0x50U
63 
64 /* nPM1300 ADC register offsets */
65 #define ADC_OFFSET_TASK_VBAT 0x00U
66 #define ADC_OFFSET_TASK_TEMP 0x01U
67 #define ADC_OFFSET_CONFIG    0x09U
68 #define ADC_OFFSET_NTCR_SEL  0x0AU
69 #define ADC_OFFSET_TASK_AUTO 0x0CU
70 #define ADC_OFFSET_RESULTS   0x10U
71 #define ADC_OFFSET_IBAT_EN   0x24U
72 
73 /* nPM1300 VBUS register offsets */
74 #define VBUS_OFFSET_ILIMSTARTUP 0x02U
75 #define VBUS_OFFSET_STATUS      0x07U
76 
77 /* Ibat status */
78 #define IBAT_STAT_DISCHARGE      0x04U
79 #define IBAT_STAT_CHARGE_TRICKLE 0x0CU
80 #define IBAT_STAT_CHARGE_COOL    0x0DU
81 #define IBAT_STAT_CHARGE_NORMAL  0x0FU
82 
83 struct adc_results_t {
84 	uint8_t ibat_stat;
85 	uint8_t msb_vbat;
86 	uint8_t msb_ntc;
87 	uint8_t msb_die;
88 	uint8_t msb_vsys;
89 	uint8_t lsb_a;
90 	uint8_t reserved1;
91 	uint8_t reserved2;
92 	uint8_t msb_ibat;
93 	uint8_t msb_vbus;
94 	uint8_t lsb_b;
95 } __packed;
96 
97 /* ADC result masks */
98 #define ADC_MSB_SHIFT      2U
99 #define ADC_LSB_MASK       0x03U
100 #define ADC_LSB_VBAT_SHIFT 0U
101 #define ADC_LSB_NTC_SHIFT  2U
102 #define ADC_LSB_IBAT_SHIFT 4U
103 
104 /* NTC temp masks */
105 #define NTCTEMP_MSB_SHIFT 2U
106 #define NTCTEMP_LSB_MASK  0x03U
107 
108 /* Linear range for charger terminal voltage */
109 static const struct linear_range charger_volt_ranges[] = {
110 	LINEAR_RANGE_INIT(3500000, 50000, 0U, 3U), LINEAR_RANGE_INIT(4000000, 50000, 4U, 13U)};
111 
112 /* Linear range for charger current */
113 static const struct linear_range charger_current_range = LINEAR_RANGE_INIT(32000, 2000, 16U, 400U);
114 
115 /* Linear range for Discharge limit */
116 static const struct linear_range discharge_limit_range = LINEAR_RANGE_INIT(268090, 3230, 83U, 415U);
117 
118 /* Linear range for vbusin current limit */
119 static const struct linear_range vbus_current_ranges[] = {
120 	LINEAR_RANGE_INIT(100000, 0, 1U, 1U), LINEAR_RANGE_INIT(500000, 100000, 5U, 15U)};
121 
calc_temp(const struct npm1300_charger_config * const config,uint16_t code,struct sensor_value * valp)122 static void calc_temp(const struct npm1300_charger_config *const config, uint16_t code,
123 		      struct sensor_value *valp)
124 {
125 	/* Ref: Datasheet Figure 42: Battery temperature (Kelvin) */
126 	float log_result = log((1024.f / (float)code) - 1);
127 	float inv_temp_k = (1.f / 298.15f) - (log_result / (float)config->thermistor_beta);
128 
129 	float temp = (1.f / inv_temp_k) - 273.15f;
130 
131 	valp->val1 = (int32_t)temp;
132 	valp->val2 = (int32_t)(fmodf(temp, 1.f) * 1000000.f);
133 }
134 
calc_ntc_res(const struct npm1300_charger_config * const config,int32_t temp_mdegc)135 static uint32_t calc_ntc_res(const struct npm1300_charger_config *const config, int32_t temp_mdegc)
136 {
137 	float inv_t0 = 1.f / 298.15f;
138 	float temp = (float)temp_mdegc / 1000.f;
139 
140 	float inv_temp_k = 1.f / (temp + 273.15f);
141 
142 	return config->thermistor_ohms *
143 	       exp((float)config->thermistor_beta * (inv_temp_k - inv_t0));
144 }
145 
adc_get_res(uint8_t msb,uint8_t lsb,uint16_t lsb_shift)146 static uint16_t adc_get_res(uint8_t msb, uint8_t lsb, uint16_t lsb_shift)
147 {
148 	return ((uint16_t)msb << ADC_MSB_SHIFT) | ((lsb >> lsb_shift) & ADC_LSB_MASK);
149 }
150 
calc_current(const struct npm1300_charger_config * const config,struct npm1300_charger_data * const data,struct sensor_value * valp)151 static void calc_current(const struct npm1300_charger_config *const config,
152 			 struct npm1300_charger_data *const data, struct sensor_value *valp)
153 {
154 	int32_t full_scale_ma;
155 	int32_t current;
156 
157 	switch (data->ibat_stat) {
158 	case IBAT_STAT_DISCHARGE:
159 		full_scale_ma = config->dischg_limit_microamp / 1000;
160 		break;
161 	case IBAT_STAT_CHARGE_TRICKLE:
162 		full_scale_ma = -config->current_microamp / 10000;
163 		break;
164 	case IBAT_STAT_CHARGE_COOL:
165 		full_scale_ma = -config->current_microamp / 2000;
166 		break;
167 	case IBAT_STAT_CHARGE_NORMAL:
168 		full_scale_ma = -config->current_microamp / 1000;
169 		break;
170 	default:
171 		full_scale_ma = 0;
172 		break;
173 	}
174 
175 	current = (data->current * full_scale_ma) / 1024;
176 
177 	valp->val1 = current / 1000;
178 	valp->val2 = (current % 1000) * 1000;
179 }
180 
npm1300_charger_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * valp)181 int npm1300_charger_channel_get(const struct device *dev, enum sensor_channel chan,
182 				struct sensor_value *valp)
183 {
184 	const struct npm1300_charger_config *const config = dev->config;
185 	struct npm1300_charger_data *const data = dev->data;
186 	int32_t tmp;
187 
188 	switch ((uint32_t)chan) {
189 	case SENSOR_CHAN_GAUGE_VOLTAGE:
190 		tmp = data->voltage * 5000 / 1024;
191 		valp->val1 = tmp / 1000;
192 		valp->val2 = (tmp % 1000) * 1000;
193 		break;
194 	case SENSOR_CHAN_GAUGE_TEMP:
195 		calc_temp(config, data->temp, valp);
196 		break;
197 	case SENSOR_CHAN_GAUGE_AVG_CURRENT:
198 		calc_current(config, data, valp);
199 		break;
200 	case SENSOR_CHAN_NPM1300_CHARGER_STATUS:
201 		valp->val1 = data->status;
202 		valp->val2 = 0;
203 		break;
204 	case SENSOR_CHAN_NPM1300_CHARGER_ERROR:
205 		valp->val1 = data->error;
206 		valp->val2 = 0;
207 		break;
208 	case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT:
209 		valp->val1 = config->current_microamp / 1000000;
210 		valp->val2 = config->current_microamp % 1000000;
211 		break;
212 	case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT:
213 		valp->val1 = config->dischg_limit_microamp / 1000000;
214 		valp->val2 = config->dischg_limit_microamp % 1000000;
215 		break;
216 	default:
217 		return -ENOTSUP;
218 	}
219 
220 	return 0;
221 }
222 
npm1300_charger_sample_fetch(const struct device * dev,enum sensor_channel chan)223 int npm1300_charger_sample_fetch(const struct device *dev, enum sensor_channel chan)
224 {
225 	const struct npm1300_charger_config *const config = dev->config;
226 	struct npm1300_charger_data *data = dev->data;
227 	struct adc_results_t results;
228 	int ret;
229 
230 	/* Read charge status and error reason */
231 	ret = mfd_npm1300_reg_read(config->mfd, CHGR_BASE, CHGR_OFFSET_CHG_STAT, &data->status);
232 	if (ret != 0) {
233 		return ret;
234 	}
235 
236 	ret = mfd_npm1300_reg_read(config->mfd, CHGR_BASE, CHGR_OFFSET_ERR_REASON, &data->error);
237 	if (ret != 0) {
238 		return ret;
239 	}
240 
241 	/* Read adc results */
242 	ret = mfd_npm1300_reg_read_burst(config->mfd, ADC_BASE, ADC_OFFSET_RESULTS, &results,
243 					 sizeof(results));
244 	if (ret != 0) {
245 		return ret;
246 	}
247 
248 	data->voltage = adc_get_res(results.msb_vbat, results.lsb_a, ADC_LSB_VBAT_SHIFT);
249 	data->temp = adc_get_res(results.msb_ntc, results.lsb_a, ADC_LSB_NTC_SHIFT);
250 	data->current = adc_get_res(results.msb_ibat, results.lsb_b, ADC_LSB_IBAT_SHIFT);
251 	data->ibat_stat = results.ibat_stat;
252 
253 	/* Trigger temperature measurement */
254 	ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U);
255 	if (ret != 0) {
256 		return ret;
257 	}
258 
259 	/* Trigger current and voltage measurement */
260 	ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_VBAT, 1U);
261 	if (ret != 0) {
262 		return ret;
263 	}
264 
265 	/* Read vbus status */
266 	ret = mfd_npm1300_reg_read(config->mfd, VBUS_BASE, VBUS_OFFSET_STATUS, &data->vbus_stat);
267 	if (ret != 0) {
268 		return ret;
269 	}
270 
271 	return ret;
272 }
273 
set_ntc_thresholds(const struct npm1300_charger_config * const config)274 static int set_ntc_thresholds(const struct npm1300_charger_config *const config)
275 {
276 	for (uint8_t idx = 0U; idx < 4U; idx++) {
277 		if (config->temp_thresholds[idx] < INT32_MAX) {
278 			uint32_t res = calc_ntc_res(config, config->temp_thresholds[idx]);
279 
280 			/* Ref: Datasheet Figure 14: Equation for battery temperature */
281 			uint16_t code = (1024 * res) / (res + config->thermistor_ohms);
282 
283 			int ret = mfd_npm1300_reg_write2(
284 				config->mfd, CHGR_BASE, CHGR_OFFSET_NTC_TEMPS + (idx * 2U),
285 				code >> NTCTEMP_MSB_SHIFT, code & NTCTEMP_LSB_MASK);
286 
287 			if (ret != 0) {
288 				return ret;
289 			}
290 		}
291 	}
292 
293 	return 0;
294 }
295 
npm1300_charger_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)296 static int npm1300_charger_attr_get(const struct device *dev, enum sensor_channel chan,
297 				    enum sensor_attribute attr, struct sensor_value *val)
298 {
299 	const struct npm1300_charger_config *const config = dev->config;
300 	uint8_t data;
301 	int ret;
302 
303 	switch ((uint32_t)chan) {
304 	case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT:
305 		if (attr != SENSOR_ATTR_CONFIGURATION) {
306 			return -ENOTSUP;
307 		}
308 
309 		ret = mfd_npm1300_reg_read(config->mfd, CHGR_BASE, CHGR_OFFSET_EN_SET, &data);
310 		if (ret == 0) {
311 			val->val1 = data;
312 			val->val2 = 0U;
313 		}
314 		return ret;
315 	default:
316 		return -ENOTSUP;
317 	}
318 }
319 
npm1300_charger_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)320 static int npm1300_charger_attr_set(const struct device *dev, enum sensor_channel chan,
321 				    enum sensor_attribute attr, const struct sensor_value *val)
322 {
323 	const struct npm1300_charger_config *const config = dev->config;
324 	int ret;
325 
326 	switch ((uint32_t)chan) {
327 	case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT:
328 		if (attr != SENSOR_ATTR_CONFIGURATION) {
329 			return -ENOTSUP;
330 		}
331 
332 		if (val->val1 == 0) {
333 			/* Disable charging */
334 			return mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_EN_CLR,
335 						     1U);
336 		}
337 
338 		/* Clear any errors and enable charging */
339 		ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_ERR_CLR, 1U);
340 		if (ret != 0) {
341 			return ret;
342 		}
343 		return mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_EN_SET, 1U);
344 
345 	default:
346 		return -ENOTSUP;
347 	}
348 }
349 
npm1300_charger_init(const struct device * dev)350 int npm1300_charger_init(const struct device *dev)
351 {
352 	const struct npm1300_charger_config *const config = dev->config;
353 	uint16_t idx;
354 	int ret;
355 
356 	if (!device_is_ready(config->mfd)) {
357 		return -ENODEV;
358 	}
359 
360 	/* Configure thermistor */
361 	ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_NTCR_SEL,
362 				    config->thermistor_idx + 1U);
363 	if (ret != 0) {
364 		return ret;
365 	}
366 
367 	ret = set_ntc_thresholds(config);
368 	if (ret != 0) {
369 		return ret;
370 	}
371 
372 	/* Configure termination voltages */
373 	ret = linear_range_group_get_win_index(charger_volt_ranges, ARRAY_SIZE(charger_volt_ranges),
374 					       config->term_microvolt, config->term_microvolt,
375 					       &idx);
376 	if (ret == -EINVAL) {
377 		return ret;
378 	}
379 	ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_VTERM, idx);
380 	if (ret != 0) {
381 		return ret;
382 	}
383 
384 	ret = linear_range_group_get_win_index(charger_volt_ranges, ARRAY_SIZE(charger_volt_ranges),
385 					       config->term_warm_microvolt,
386 					       config->term_warm_microvolt, &idx);
387 	if (ret == -EINVAL) {
388 		return ret;
389 	}
390 
391 	ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_VTERM_R, idx);
392 	if (ret != 0) {
393 		return ret;
394 	}
395 
396 	/* Set current, allow rounding down to closest value */
397 	ret = linear_range_get_win_index(&charger_current_range,
398 					 config->current_microamp - charger_current_range.step,
399 					 config->current_microamp, &idx);
400 	if (ret == -EINVAL) {
401 		return ret;
402 	}
403 
404 	ret = mfd_npm1300_reg_write2(config->mfd, CHGR_BASE, CHGR_OFFSET_ISET, idx / 2U, idx & 1U);
405 	if (ret != 0) {
406 		return ret;
407 	}
408 
409 	/* Set discharge limit, allow rounding down to closest value */
410 	ret = linear_range_get_win_index(&discharge_limit_range,
411 					 config->dischg_limit_microamp - discharge_limit_range.step,
412 					 config->dischg_limit_microamp, &idx);
413 	if (ret == -EINVAL) {
414 		return ret;
415 	}
416 
417 	ret = mfd_npm1300_reg_write2(config->mfd, CHGR_BASE, CHGR_OFFSET_ISET_DISCHG, idx / 2U,
418 				     idx & 1U);
419 	if (ret != 0) {
420 		return ret;
421 	}
422 
423 	/* Configure vbus current limit */
424 	ret = linear_range_group_get_win_index(vbus_current_ranges, ARRAY_SIZE(vbus_current_ranges),
425 					       config->vbus_limit_microamp,
426 					       config->vbus_limit_microamp, &idx);
427 	if (ret == -EINVAL) {
428 		return ret;
429 	}
430 	ret = mfd_npm1300_reg_write(config->mfd, VBUS_BASE, VBUS_OFFSET_ILIMSTARTUP, idx);
431 	if (ret != 0) {
432 		return ret;
433 	}
434 
435 	/* Configure trickle voltage threshold */
436 	ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_TRICKLE_SEL,
437 				    config->trickle_sel);
438 	if (ret != 0) {
439 		return ret;
440 	}
441 
442 	/* Configure termination current */
443 	ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_ITERM_SEL,
444 				    config->iterm_sel);
445 	if (ret != 0) {
446 		return ret;
447 	}
448 
449 	/* Enable current measurement */
450 	ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_IBAT_EN, 1U);
451 	if (ret != 0) {
452 		return ret;
453 	}
454 
455 	/* Trigger current and voltage measurement */
456 	ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_VBAT, 1U);
457 	if (ret != 0) {
458 		return ret;
459 	}
460 
461 	/* Trigger temperature measurement */
462 	ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U);
463 	if (ret != 0) {
464 		return ret;
465 	}
466 
467 	/* Enable automatic temperature measurements during charging */
468 	ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_AUTO, 1U);
469 	if (ret != 0) {
470 		return ret;
471 	}
472 
473 	/* Enable charging at low battery if configured */
474 	if (config->vbatlow_charge_enable) {
475 		ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_VBATLOW_EN, 1U);
476 		if (ret != 0) {
477 			return ret;
478 		}
479 	}
480 
481 	/* Disable automatic recharging if configured */
482 	if (config->disable_recharge) {
483 		ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_DIS_SET, 1U);
484 		if (ret != 0) {
485 			return ret;
486 		}
487 	}
488 
489 	/* Enable charging if configured */
490 	if (config->charging_enable) {
491 		ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_EN_SET, 1U);
492 		if (ret != 0) {
493 			return ret;
494 		}
495 	}
496 
497 	return 0;
498 }
499 
500 static const struct sensor_driver_api npm1300_charger_battery_driver_api = {
501 	.sample_fetch = npm1300_charger_sample_fetch,
502 	.channel_get = npm1300_charger_channel_get,
503 	.attr_set = npm1300_charger_attr_set,
504 	.attr_get = npm1300_charger_attr_get,
505 };
506 
507 #define NPM1300_CHARGER_INIT(n)                                                                    \
508 	static struct npm1300_charger_data npm1300_charger_data_##n;                               \
509                                                                                                    \
510 	static const struct npm1300_charger_config npm1300_charger_config_##n = {                  \
511 		.mfd = DEVICE_DT_GET(DT_INST_PARENT(n)),                                           \
512 		.term_microvolt = DT_INST_PROP(n, term_microvolt),                                 \
513 		.term_warm_microvolt =                                                             \
514 			DT_INST_PROP_OR(n, term_warm_microvolt, DT_INST_PROP(n, term_microvolt)),  \
515 		.current_microamp = DT_INST_PROP(n, current_microamp),                             \
516 		.dischg_limit_microamp = DT_INST_PROP(n, dischg_limit_microamp),                   \
517 		.vbus_limit_microamp = DT_INST_PROP(n, vbus_limit_microamp),                       \
518 		.thermistor_ohms = DT_INST_PROP(n, thermistor_ohms),                               \
519 		.thermistor_idx = DT_INST_ENUM_IDX(n, thermistor_ohms),                            \
520 		.thermistor_beta = DT_INST_PROP(n, thermistor_beta),                               \
521 		.charging_enable = DT_INST_PROP(n, charging_enable),                               \
522 		.trickle_sel = DT_INST_ENUM_IDX(n, trickle_microvolt),                             \
523 		.iterm_sel = DT_INST_ENUM_IDX(n, term_current_percent),                            \
524 		.vbatlow_charge_enable = DT_INST_PROP(n, vbatlow_charge_enable),                   \
525 		.disable_recharge = DT_INST_PROP(n, disable_recharge),                             \
526 		.temp_thresholds = {DT_INST_PROP_OR(n, thermistor_cold_millidegrees, INT32_MAX),   \
527 				    DT_INST_PROP_OR(n, thermistor_cool_millidegrees, INT32_MAX),   \
528 				    DT_INST_PROP_OR(n, thermistor_warm_millidegrees, INT32_MAX),   \
529 				    DT_INST_PROP_OR(n, thermistor_hot_millidegrees, INT32_MAX)}};  \
530                                                                                                    \
531 	SENSOR_DEVICE_DT_INST_DEFINE(n, &npm1300_charger_init, NULL, &npm1300_charger_data_##n,    \
532 				     &npm1300_charger_config_##n, POST_KERNEL,                     \
533 				     CONFIG_SENSOR_INIT_PRIORITY,                                  \
534 				     &npm1300_charger_battery_driver_api);
535 
536 DT_INST_FOREACH_STATUS_OKAY(NPM1300_CHARGER_INIT)
537