xref: /openbmc/linux/drivers/power/supply/rn5t618_power.c (revision 7d76367774d716d28bf003defded61a37b4c83ed)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Power supply driver for the RICOH RN5T618 power management chip family
4  *
5  * Copyright (C) 2020 Andreas Kemnade
6  */
7 
8 #include <linux/kernel.h>
9 #include <linux/device.h>
10 #include <linux/bitops.h>
11 #include <linux/errno.h>
12 #include <linux/init.h>
13 #include <linux/interrupt.h>
14 #include <linux/module.h>
15 #include <linux/mfd/rn5t618.h>
16 #include <linux/platform_device.h>
17 #include <linux/power_supply.h>
18 #include <linux/regmap.h>
19 #include <linux/slab.h>
20 
21 #define CHG_STATE_ADP_INPUT 0x40
22 #define CHG_STATE_USB_INPUT 0x80
23 #define CHG_STATE_MASK	0x1f
24 #define CHG_STATE_CHG_OFF	0
25 #define CHG_STATE_CHG_READY_VADP	1
26 #define CHG_STATE_CHG_TRICKLE	2
27 #define CHG_STATE_CHG_RAPID	3
28 #define CHG_STATE_CHG_COMPLETE	4
29 #define CHG_STATE_SUSPEND	5
30 #define CHG_STATE_VCHG_OVER_VOL	6
31 #define CHG_STATE_BAT_ERROR	7
32 #define CHG_STATE_NO_BAT	8
33 #define CHG_STATE_BAT_OVER_VOL	9
34 #define CHG_STATE_BAT_TEMP_ERR	10
35 #define CHG_STATE_DIE_ERR	11
36 #define CHG_STATE_DIE_SHUTDOWN	12
37 #define CHG_STATE_NO_BAT2	13
38 #define CHG_STATE_CHG_READY_VUSB	14
39 
40 #define GCHGDET_TYPE_MASK 0x30
41 #define GCHGDET_TYPE_SDP 0x00
42 #define GCHGDET_TYPE_CDP 0x10
43 #define GCHGDET_TYPE_DCP 0x20
44 
45 #define FG_ENABLE 1
46 
47 struct rn5t618_power_info {
48 	struct rn5t618 *rn5t618;
49 	struct platform_device *pdev;
50 	struct power_supply *battery;
51 	struct power_supply *usb;
52 	struct power_supply *adp;
53 	int irq;
54 };
55 
56 static enum power_supply_usb_type rn5t618_usb_types[] = {
57 	POWER_SUPPLY_USB_TYPE_SDP,
58 	POWER_SUPPLY_USB_TYPE_DCP,
59 	POWER_SUPPLY_USB_TYPE_CDP,
60 	POWER_SUPPLY_USB_TYPE_UNKNOWN
61 };
62 
63 static enum power_supply_property rn5t618_usb_props[] = {
64 	POWER_SUPPLY_PROP_STATUS,
65 	POWER_SUPPLY_PROP_USB_TYPE,
66 	POWER_SUPPLY_PROP_ONLINE,
67 };
68 
69 static enum power_supply_property rn5t618_adp_props[] = {
70 	POWER_SUPPLY_PROP_STATUS,
71 	POWER_SUPPLY_PROP_ONLINE,
72 };
73 
74 
75 static enum power_supply_property rn5t618_battery_props[] = {
76 	POWER_SUPPLY_PROP_STATUS,
77 	POWER_SUPPLY_PROP_PRESENT,
78 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
79 	POWER_SUPPLY_PROP_CURRENT_NOW,
80 	POWER_SUPPLY_PROP_CAPACITY,
81 	POWER_SUPPLY_PROP_TEMP,
82 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
83 	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
84 	POWER_SUPPLY_PROP_TECHNOLOGY,
85 	POWER_SUPPLY_PROP_CHARGE_FULL,
86 	POWER_SUPPLY_PROP_CHARGE_NOW,
87 };
88 
89 static int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info,
90 					  u8 reg, u16 *result)
91 {
92 	int ret, i;
93 	u8 data[2];
94 	u16 old, new;
95 
96 	old = 0;
97 	/* Prevent races when registers are changing. */
98 	for (i = 0; i < 3; i++) {
99 		ret = regmap_bulk_read(info->rn5t618->regmap,
100 				       reg, data, sizeof(data));
101 		if (ret)
102 			return ret;
103 
104 		new = data[0] << 8;
105 		new |= data[1];
106 		if (new == old)
107 			break;
108 
109 		old = new;
110 	}
111 
112 	*result = new;
113 
114 	return 0;
115 }
116 
117 static int rn5t618_decode_status(unsigned int status)
118 {
119 	switch (status & CHG_STATE_MASK) {
120 	case CHG_STATE_CHG_OFF:
121 	case CHG_STATE_SUSPEND:
122 	case CHG_STATE_VCHG_OVER_VOL:
123 	case CHG_STATE_DIE_SHUTDOWN:
124 		return POWER_SUPPLY_STATUS_DISCHARGING;
125 
126 	case CHG_STATE_CHG_TRICKLE:
127 	case CHG_STATE_CHG_RAPID:
128 		return POWER_SUPPLY_STATUS_CHARGING;
129 
130 	case CHG_STATE_CHG_COMPLETE:
131 		return POWER_SUPPLY_STATUS_FULL;
132 
133 	default:
134 		return POWER_SUPPLY_STATUS_NOT_CHARGING;
135 	}
136 }
137 
138 static int rn5t618_battery_status(struct rn5t618_power_info *info,
139 				  union power_supply_propval *val)
140 {
141 	unsigned int v;
142 	int ret;
143 
144 	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
145 	if (ret)
146 		return ret;
147 
148 	val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
149 
150 	if (v & 0xc0) { /* USB or ADP plugged */
151 		val->intval = rn5t618_decode_status(v);
152 	} else
153 		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
154 
155 	return ret;
156 }
157 
158 static int rn5t618_battery_present(struct rn5t618_power_info *info,
159 				   union power_supply_propval *val)
160 {
161 	unsigned int v;
162 	int ret;
163 
164 	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
165 	if (ret)
166 		return ret;
167 
168 	v &= CHG_STATE_MASK;
169 	if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2))
170 		val->intval = 0;
171 	else
172 		val->intval = 1;
173 
174 	return ret;
175 }
176 
177 static int rn5t618_battery_voltage_now(struct rn5t618_power_info *info,
178 				       union power_supply_propval *val)
179 {
180 	u16 res;
181 	int ret;
182 
183 	ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res);
184 	if (ret)
185 		return ret;
186 
187 	val->intval = res * 2 * 2500 / 4095 * 1000;
188 
189 	return 0;
190 }
191 
192 static int rn5t618_battery_current_now(struct rn5t618_power_info *info,
193 				       union power_supply_propval *val)
194 {
195 	u16 res;
196 	int ret;
197 
198 	ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res);
199 	if (ret)
200 		return ret;
201 
202 	/* current is negative when discharging */
203 	val->intval = sign_extend32(res, 13) * 1000;
204 
205 	return 0;
206 }
207 
208 static int rn5t618_battery_capacity(struct rn5t618_power_info *info,
209 				    union power_supply_propval *val)
210 {
211 	unsigned int v;
212 	int ret;
213 
214 	ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v);
215 	if (ret)
216 		return ret;
217 
218 	val->intval = v;
219 
220 	return 0;
221 }
222 
223 static int rn5t618_battery_temp(struct rn5t618_power_info *info,
224 				union power_supply_propval *val)
225 {
226 	u16 res;
227 	int ret;
228 
229 	ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res);
230 	if (ret)
231 		return ret;
232 
233 	val->intval = sign_extend32(res, 11) * 10 / 16;
234 
235 	return 0;
236 }
237 
238 static int rn5t618_battery_tte(struct rn5t618_power_info *info,
239 			       union power_supply_propval *val)
240 {
241 	u16 res;
242 	int ret;
243 
244 	ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res);
245 	if (ret)
246 		return ret;
247 
248 	if (res == 65535)
249 		return -ENODATA;
250 
251 	val->intval = res * 60;
252 
253 	return 0;
254 }
255 
256 static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
257 			       union power_supply_propval *val)
258 {
259 	u16 res;
260 	int ret;
261 
262 	ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res);
263 	if (ret)
264 		return ret;
265 
266 	if (res == 65535)
267 		return -ENODATA;
268 
269 	val->intval = res * 60;
270 
271 	return 0;
272 }
273 
274 static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
275 				       union power_supply_propval *val)
276 {
277 	u16 res;
278 	int ret;
279 
280 	ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res);
281 	if (ret)
282 		return ret;
283 
284 	val->intval = res * 1000;
285 
286 	return 0;
287 }
288 
289 static int rn5t618_battery_charge_now(struct rn5t618_power_info *info,
290 				      union power_supply_propval *val)
291 {
292 	u16 res;
293 	int ret;
294 
295 	ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res);
296 	if (ret)
297 		return ret;
298 
299 	val->intval = res * 1000;
300 
301 	return 0;
302 }
303 
304 static int rn5t618_battery_get_property(struct power_supply *psy,
305 					enum power_supply_property psp,
306 					union power_supply_propval *val)
307 {
308 	int ret = 0;
309 	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
310 
311 	switch (psp) {
312 	case POWER_SUPPLY_PROP_STATUS:
313 		ret = rn5t618_battery_status(info, val);
314 		break;
315 	case POWER_SUPPLY_PROP_PRESENT:
316 		ret = rn5t618_battery_present(info, val);
317 		break;
318 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
319 		ret = rn5t618_battery_voltage_now(info, val);
320 		break;
321 	case POWER_SUPPLY_PROP_CURRENT_NOW:
322 		ret = rn5t618_battery_current_now(info, val);
323 		break;
324 	case POWER_SUPPLY_PROP_CAPACITY:
325 		ret = rn5t618_battery_capacity(info, val);
326 		break;
327 	case POWER_SUPPLY_PROP_TEMP:
328 		ret = rn5t618_battery_temp(info, val);
329 		break;
330 	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
331 		ret = rn5t618_battery_tte(info, val);
332 		break;
333 	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
334 		ret = rn5t618_battery_ttf(info, val);
335 		break;
336 	case POWER_SUPPLY_PROP_TECHNOLOGY:
337 		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
338 		break;
339 	case POWER_SUPPLY_PROP_CHARGE_FULL:
340 		ret = rn5t618_battery_charge_full(info, val);
341 		break;
342 	case POWER_SUPPLY_PROP_CHARGE_NOW:
343 		ret = rn5t618_battery_charge_now(info, val);
344 		break;
345 	default:
346 		return -EINVAL;
347 	}
348 
349 	return ret;
350 }
351 
352 static int rn5t618_adp_get_property(struct power_supply *psy,
353 				    enum power_supply_property psp,
354 				    union power_supply_propval *val)
355 {
356 	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
357 	unsigned int chgstate;
358 	bool online;
359 	int ret;
360 
361 	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
362 	if (ret)
363 		return ret;
364 
365 	online = !!(chgstate & CHG_STATE_ADP_INPUT);
366 
367 	switch (psp) {
368 	case POWER_SUPPLY_PROP_ONLINE:
369 		val->intval = online;
370 		break;
371 	case POWER_SUPPLY_PROP_STATUS:
372 		if (!online) {
373 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
374 			break;
375 		}
376 		val->intval = rn5t618_decode_status(chgstate);
377 		if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
378 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
379 
380 		break;
381 	default:
382 		return -EINVAL;
383 	}
384 
385 	return 0;
386 }
387 
388 static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
389 				union power_supply_propval *val)
390 {
391 	unsigned int regval;
392 	int ret;
393 
394 	ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, &regval);
395 	if (ret < 0)
396 		return ret;
397 
398 	switch (regval & GCHGDET_TYPE_MASK) {
399 	case GCHGDET_TYPE_SDP:
400 		val->intval = POWER_SUPPLY_USB_TYPE_SDP;
401 		break;
402 	case GCHGDET_TYPE_CDP:
403 		val->intval = POWER_SUPPLY_USB_TYPE_CDP;
404 		break;
405 	case GCHGDET_TYPE_DCP:
406 		val->intval = POWER_SUPPLY_USB_TYPE_DCP;
407 		break;
408 	default:
409 		val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
410 	}
411 
412 	return 0;
413 }
414 
415 static int rn5t618_usb_get_property(struct power_supply *psy,
416 				    enum power_supply_property psp,
417 				    union power_supply_propval *val)
418 {
419 	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
420 	unsigned int chgstate;
421 	bool online;
422 	int ret;
423 
424 	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
425 	if (ret)
426 		return ret;
427 
428 	online = !!(chgstate & CHG_STATE_USB_INPUT);
429 
430 	switch (psp) {
431 	case POWER_SUPPLY_PROP_ONLINE:
432 		val->intval = online;
433 		break;
434 	case POWER_SUPPLY_PROP_STATUS:
435 		if (!online) {
436 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
437 			break;
438 		}
439 		val->intval = rn5t618_decode_status(chgstate);
440 		if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
441 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
442 
443 		break;
444 	case POWER_SUPPLY_PROP_USB_TYPE:
445 		if (!online || (info->rn5t618->variant != RC5T619))
446 			return -ENODATA;
447 
448 		return rc5t619_usb_get_type(info, val);
449 	default:
450 		return -EINVAL;
451 	}
452 
453 	return 0;
454 }
455 
456 static const struct power_supply_desc rn5t618_battery_desc = {
457 	.name                   = "rn5t618-battery",
458 	.type                   = POWER_SUPPLY_TYPE_BATTERY,
459 	.properties             = rn5t618_battery_props,
460 	.num_properties         = ARRAY_SIZE(rn5t618_battery_props),
461 	.get_property           = rn5t618_battery_get_property,
462 };
463 
464 static const struct power_supply_desc rn5t618_adp_desc = {
465 	.name                   = "rn5t618-adp",
466 	.type                   = POWER_SUPPLY_TYPE_MAINS,
467 	.properties             = rn5t618_adp_props,
468 	.num_properties         = ARRAY_SIZE(rn5t618_adp_props),
469 	.get_property           = rn5t618_adp_get_property,
470 };
471 
472 static const struct power_supply_desc rn5t618_usb_desc = {
473 	.name                   = "rn5t618-usb",
474 	.type                   = POWER_SUPPLY_TYPE_USB,
475 	.usb_types		= rn5t618_usb_types,
476 	.num_usb_types		= ARRAY_SIZE(rn5t618_usb_types),
477 	.properties             = rn5t618_usb_props,
478 	.num_properties         = ARRAY_SIZE(rn5t618_usb_props),
479 	.get_property           = rn5t618_usb_get_property,
480 };
481 
482 static irqreturn_t rn5t618_charger_irq(int irq, void *data)
483 {
484 	struct device *dev = data;
485 	struct rn5t618_power_info *info = dev_get_drvdata(dev);
486 
487 	unsigned int ctrl, stat1, stat2, err;
488 
489 	regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err);
490 	regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl);
491 	regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1);
492 	regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2);
493 
494 	regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0);
495 	regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0);
496 	regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0);
497 	regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0);
498 
499 	dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n",
500 		err, ctrl, stat1, stat2);
501 
502 	power_supply_changed(info->usb);
503 	power_supply_changed(info->adp);
504 	power_supply_changed(info->battery);
505 
506 	return IRQ_HANDLED;
507 }
508 
509 static int rn5t618_power_probe(struct platform_device *pdev)
510 {
511 	int ret = 0;
512 	unsigned int v;
513 	struct power_supply_config psy_cfg = {};
514 	struct rn5t618_power_info *info;
515 
516 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
517 	if (!info)
518 		return -ENOMEM;
519 
520 	info->pdev = pdev;
521 	info->rn5t618 = dev_get_drvdata(pdev->dev.parent);
522 	info->irq = -1;
523 
524 	platform_set_drvdata(pdev, info);
525 
526 	ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v);
527 	if (ret)
528 		return ret;
529 
530 	if (!(v & FG_ENABLE)) {
531 		/* E.g. the vendor kernels of various Kobo and Tolino Ebook
532 		 * readers disable the fuel gauge on shutdown. If a kernel
533 		 * without fuel gauge support is booted after that, the fuel
534 		 * gauge will get decalibrated.
535 		 */
536 		dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n");
537 		dev_info(&pdev->dev, "Expect imprecise results\n");
538 		regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL,
539 				   FG_ENABLE, FG_ENABLE);
540 	}
541 
542 	psy_cfg.drv_data = info;
543 	info->battery = devm_power_supply_register(&pdev->dev,
544 						   &rn5t618_battery_desc,
545 						   &psy_cfg);
546 	if (IS_ERR(info->battery)) {
547 		ret = PTR_ERR(info->battery);
548 		dev_err(&pdev->dev, "failed to register battery: %d\n", ret);
549 		return ret;
550 	}
551 
552 	info->adp = devm_power_supply_register(&pdev->dev,
553 					       &rn5t618_adp_desc,
554 					       &psy_cfg);
555 	if (IS_ERR(info->adp)) {
556 		ret = PTR_ERR(info->adp);
557 		dev_err(&pdev->dev, "failed to register adp: %d\n", ret);
558 		return ret;
559 	}
560 
561 	info->usb = devm_power_supply_register(&pdev->dev,
562 					       &rn5t618_usb_desc,
563 					       &psy_cfg);
564 	if (IS_ERR(info->usb)) {
565 		ret = PTR_ERR(info->usb);
566 		dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
567 		return ret;
568 	}
569 
570 	if (info->rn5t618->irq_data)
571 		info->irq = regmap_irq_get_virq(info->rn5t618->irq_data,
572 						RN5T618_IRQ_CHG);
573 
574 	if (info->irq < 0)
575 		info->irq = -1;
576 	else {
577 		ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
578 						rn5t618_charger_irq,
579 						IRQF_ONESHOT,
580 						"rn5t618_power",
581 						&pdev->dev);
582 
583 		if (ret < 0) {
584 			dev_err(&pdev->dev, "request IRQ:%d fail\n",
585 				info->irq);
586 			info->irq = -1;
587 		}
588 	}
589 
590 	return 0;
591 }
592 
593 static struct platform_driver rn5t618_power_driver = {
594 	.driver = {
595 		.name   = "rn5t618-power",
596 	},
597 	.probe = rn5t618_power_probe,
598 };
599 
600 module_platform_driver(rn5t618_power_driver);
601 MODULE_ALIAS("platform:rn5t618-power");
602 MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618");
603 MODULE_LICENSE("GPL");
604