File Index
Files and directories
Sign in
FILE

rn5t618_power.c

File preview with syntax highlighting.

linux-6.19.14/drivers/power/supply/rn5t618_power.c C
  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/iio/consumer.h>
 13#include <linux/init.h>
 14#include <linux/interrupt.h>
 15#include <linux/module.h>
 16#include <linux/mfd/rn5t618.h>
 17#include <linux/platform_device.h>
 18#include <linux/power_supply.h>
 19#include <linux/regmap.h>
 20#include <linux/slab.h>
 21
 22#define CHG_STATE_ADP_INPUT 0x40
 23#define CHG_STATE_USB_INPUT 0x80
 24#define CHG_STATE_MASK	0x1f
 25#define CHG_STATE_CHG_OFF	0
 26#define CHG_STATE_CHG_READY_VADP	1
 27#define CHG_STATE_CHG_TRICKLE	2
 28#define CHG_STATE_CHG_RAPID	3
 29#define CHG_STATE_CHG_COMPLETE	4
 30#define CHG_STATE_SUSPEND	5
 31#define CHG_STATE_VCHG_OVER_VOL	6
 32#define CHG_STATE_BAT_ERROR	7
 33#define CHG_STATE_NO_BAT	8
 34#define CHG_STATE_BAT_OVER_VOL	9
 35#define CHG_STATE_BAT_TEMP_ERR	10
 36#define CHG_STATE_DIE_ERR	11
 37#define CHG_STATE_DIE_SHUTDOWN	12
 38#define CHG_STATE_NO_BAT2	13
 39#define CHG_STATE_CHG_READY_VUSB	14
 40
 41#define GCHGDET_TYPE_MASK 0x30
 42#define GCHGDET_TYPE_SDP 0x00
 43#define GCHGDET_TYPE_CDP 0x10
 44#define GCHGDET_TYPE_DCP 0x20
 45
 46#define FG_ENABLE 1
 47
 48/*
 49 * Formula seems accurate for battery current, but for USB current around 70mA
 50 * per step was seen on Kobo Clara HD but all sources show the same formula
 51 * also fur USB current. To avoid accidentially unwanted high currents we stick
 52 * to that formula
 53 */
 54#define TO_CUR_REG(x) ((x) / 100000 - 1)
 55#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)
 56#define CHG_MIN_CUR 100000
 57#define CHG_MAX_CUR 1800000
 58#define ADP_MAX_CUR 2500000
 59#define USB_MAX_CUR 1400000
 60
 61
 62struct rn5t618_power_info {
 63	struct rn5t618 *rn5t618;
 64	struct platform_device *pdev;
 65	struct power_supply *battery;
 66	struct power_supply *usb;
 67	struct power_supply *adp;
 68	struct iio_channel *channel_vusb;
 69	struct iio_channel *channel_vadp;
 70	int irq;
 71};
 72
 73static enum power_supply_property rn5t618_usb_props[] = {
 74	/* input current limit is not very accurate */
 75	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
 76	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 77	POWER_SUPPLY_PROP_STATUS,
 78	POWER_SUPPLY_PROP_USB_TYPE,
 79	POWER_SUPPLY_PROP_ONLINE,
 80};
 81
 82static enum power_supply_property rn5t618_adp_props[] = {
 83	/* input current limit is not very accurate */
 84	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
 85	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 86	POWER_SUPPLY_PROP_STATUS,
 87	POWER_SUPPLY_PROP_ONLINE,
 88};
 89
 90
 91static enum power_supply_property rn5t618_battery_props[] = {
 92	POWER_SUPPLY_PROP_STATUS,
 93	POWER_SUPPLY_PROP_PRESENT,
 94	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 95	POWER_SUPPLY_PROP_CURRENT_NOW,
 96	POWER_SUPPLY_PROP_CAPACITY,
 97	POWER_SUPPLY_PROP_TEMP,
 98	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
 99	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
100	POWER_SUPPLY_PROP_TECHNOLOGY,
101	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
102	POWER_SUPPLY_PROP_CHARGE_FULL,
103	POWER_SUPPLY_PROP_CHARGE_NOW,
104};
105
106static int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info,
107					  u8 reg, u16 *result)
108{
109	int ret, i;
110	u8 data[2];
111	u16 old, new;
112
113	old = 0;
114	/* Prevent races when registers are changing. */
115	for (i = 0; i < 3; i++) {
116		ret = regmap_bulk_read(info->rn5t618->regmap,
117				       reg, data, sizeof(data));
118		if (ret)
119			return ret;
120
121		new = data[0] << 8;
122		new |= data[1];
123		if (new == old)
124			break;
125
126		old = new;
127	}
128
129	*result = new;
130
131	return 0;
132}
133
134static int rn5t618_decode_status(unsigned int status)
135{
136	switch (status & CHG_STATE_MASK) {
137	case CHG_STATE_CHG_OFF:
138	case CHG_STATE_SUSPEND:
139	case CHG_STATE_VCHG_OVER_VOL:
140	case CHG_STATE_DIE_SHUTDOWN:
141		return POWER_SUPPLY_STATUS_DISCHARGING;
142
143	case CHG_STATE_CHG_TRICKLE:
144	case CHG_STATE_CHG_RAPID:
145		return POWER_SUPPLY_STATUS_CHARGING;
146
147	case CHG_STATE_CHG_COMPLETE:
148		return POWER_SUPPLY_STATUS_FULL;
149
150	default:
151		return POWER_SUPPLY_STATUS_NOT_CHARGING;
152	}
153}
154
155static int rn5t618_battery_status(struct rn5t618_power_info *info,
156				  union power_supply_propval *val)
157{
158	unsigned int v;
159	int ret;
160
161	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
162	if (ret)
163		return ret;
164
165	val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
166
167	if (v & 0xc0) { /* USB or ADP plugged */
168		val->intval = rn5t618_decode_status(v);
169	} else
170		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
171
172	return ret;
173}
174
175static int rn5t618_battery_present(struct rn5t618_power_info *info,
176				   union power_supply_propval *val)
177{
178	unsigned int v;
179	int ret;
180
181	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
182	if (ret)
183		return ret;
184
185	v &= CHG_STATE_MASK;
186	if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2))
187		val->intval = 0;
188	else
189		val->intval = 1;
190
191	return ret;
192}
193
194static int rn5t618_battery_voltage_now(struct rn5t618_power_info *info,
195				       union power_supply_propval *val)
196{
197	u16 res;
198	int ret;
199
200	ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res);
201	if (ret)
202		return ret;
203
204	val->intval = res * 2 * 2500 / 4095 * 1000;
205
206	return 0;
207}
208
209static int rn5t618_battery_current_now(struct rn5t618_power_info *info,
210				       union power_supply_propval *val)
211{
212	u16 res;
213	int ret;
214
215	ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res);
216	if (ret)
217		return ret;
218
219	/* current is negative when discharging */
220	val->intval = sign_extend32(res, 13) * 1000;
221
222	return 0;
223}
224
225static int rn5t618_battery_capacity(struct rn5t618_power_info *info,
226				    union power_supply_propval *val)
227{
228	unsigned int v;
229	int ret;
230
231	ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v);
232	if (ret)
233		return ret;
234
235	val->intval = v;
236
237	return 0;
238}
239
240static int rn5t618_battery_temp(struct rn5t618_power_info *info,
241				union power_supply_propval *val)
242{
243	u16 res;
244	int ret;
245
246	ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res);
247	if (ret)
248		return ret;
249
250	val->intval = sign_extend32(res, 11) * 10 / 16;
251
252	return 0;
253}
254
255static int rn5t618_battery_tte(struct rn5t618_power_info *info,
256			       union power_supply_propval *val)
257{
258	u16 res;
259	int ret;
260
261	ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res);
262	if (ret)
263		return ret;
264
265	if (res == 65535)
266		return -ENODATA;
267
268	val->intval = res * 60;
269
270	return 0;
271}
272
273static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
274			       union power_supply_propval *val)
275{
276	u16 res;
277	int ret;
278
279	ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res);
280	if (ret)
281		return ret;
282
283	if (res == 65535)
284		return -ENODATA;
285
286	val->intval = res * 60;
287
288	return 0;
289}
290
291static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,
292				const union power_supply_propval *val)
293{
294	if (val->intval < CHG_MIN_CUR)
295		return -EINVAL;
296
297	if (val->intval >= CHG_MAX_CUR)
298		return -EINVAL;
299
300	return regmap_update_bits(info->rn5t618->regmap,
301				  RN5T618_CHGISET,
302				  0x1F, TO_CUR_REG(val->intval));
303}
304
305static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,
306					     union power_supply_propval *val)
307{
308	unsigned int regval;
309	int ret;
310
311	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,
312			  &regval);
313	if (ret < 0)
314		return ret;
315
316	val->intval = FROM_CUR_REG(regval);
317
318	return 0;
319}
320
321static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
322				       union power_supply_propval *val)
323{
324	u16 res;
325	int ret;
326
327	ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res);
328	if (ret)
329		return ret;
330
331	val->intval = res * 1000;
332
333	return 0;
334}
335
336static int rn5t618_battery_charge_now(struct rn5t618_power_info *info,
337				      union power_supply_propval *val)
338{
339	u16 res;
340	int ret;
341
342	ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res);
343	if (ret)
344		return ret;
345
346	val->intval = res * 1000;
347
348	return 0;
349}
350
351static int rn5t618_battery_get_property(struct power_supply *psy,
352					enum power_supply_property psp,
353					union power_supply_propval *val)
354{
355	int ret = 0;
356	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
357
358	switch (psp) {
359	case POWER_SUPPLY_PROP_STATUS:
360		ret = rn5t618_battery_status(info, val);
361		break;
362	case POWER_SUPPLY_PROP_PRESENT:
363		ret = rn5t618_battery_present(info, val);
364		break;
365	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
366		ret = rn5t618_battery_voltage_now(info, val);
367		break;
368	case POWER_SUPPLY_PROP_CURRENT_NOW:
369		ret = rn5t618_battery_current_now(info, val);
370		break;
371	case POWER_SUPPLY_PROP_CAPACITY:
372		ret = rn5t618_battery_capacity(info, val);
373		break;
374	case POWER_SUPPLY_PROP_TEMP:
375		ret = rn5t618_battery_temp(info, val);
376		break;
377	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
378		ret = rn5t618_battery_tte(info, val);
379		break;
380	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
381		ret = rn5t618_battery_ttf(info, val);
382		break;
383	case POWER_SUPPLY_PROP_TECHNOLOGY:
384		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
385		break;
386	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
387		ret = rn5t618_battery_get_current_limit(info, val);
388		break;
389	case POWER_SUPPLY_PROP_CHARGE_FULL:
390		ret = rn5t618_battery_charge_full(info, val);
391		break;
392	case POWER_SUPPLY_PROP_CHARGE_NOW:
393		ret = rn5t618_battery_charge_now(info, val);
394		break;
395	default:
396		return -EINVAL;
397	}
398
399	return ret;
400}
401
402static int rn5t618_battery_set_property(struct power_supply *psy,
403					enum power_supply_property psp,
404					const union power_supply_propval *val)
405{
406	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
407
408	switch (psp) {
409	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
410		return rn5t618_battery_set_current_limit(info, val);
411	default:
412		return -EINVAL;
413	}
414}
415
416static int rn5t618_battery_property_is_writeable(struct power_supply *psy,
417						enum power_supply_property psp)
418{
419	switch (psp) {
420	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
421		return true;
422	default:
423		return false;
424	}
425}
426
427static int rn5t618_adp_get_property(struct power_supply *psy,
428				    enum power_supply_property psp,
429				    union power_supply_propval *val)
430{
431	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
432	unsigned int chgstate;
433	unsigned int regval;
434	bool online;
435	int ret;
436
437	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
438	if (ret)
439		return ret;
440
441	online = !!(chgstate & CHG_STATE_ADP_INPUT);
442
443	switch (psp) {
444	case POWER_SUPPLY_PROP_ONLINE:
445		val->intval = online;
446		break;
447	case POWER_SUPPLY_PROP_STATUS:
448		if (!online) {
449			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
450			break;
451		}
452		val->intval = rn5t618_decode_status(chgstate);
453		if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
454			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
455
456		break;
457	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
458		ret = regmap_read(info->rn5t618->regmap,
459				  RN5T618_REGISET1, &regval);
460		if (ret < 0)
461			return ret;
462
463		val->intval = FROM_CUR_REG(regval);
464		break;
465	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
466		if (!info->channel_vadp)
467			return -ENODATA;
468
469		ret = iio_read_channel_processed_scale(info->channel_vadp, &val->intval, 1000);
470		if (ret < 0)
471			return ret;
472
473		break;
474	default:
475		return -EINVAL;
476	}
477
478	return 0;
479}
480
481static int rn5t618_adp_set_property(struct power_supply *psy,
482				    enum power_supply_property psp,
483				    const union power_supply_propval *val)
484{
485	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
486	int ret;
487
488	switch (psp) {
489	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
490		if (val->intval > ADP_MAX_CUR)
491			return -EINVAL;
492
493		if (val->intval < CHG_MIN_CUR)
494			return -EINVAL;
495
496		ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,
497				   TO_CUR_REG(val->intval));
498		if (ret < 0)
499			return ret;
500
501		break;
502	default:
503		return -EINVAL;
504	}
505
506	return 0;
507}
508
509static int rn5t618_adp_property_is_writeable(struct power_supply *psy,
510					     enum power_supply_property psp)
511{
512	switch (psp) {
513	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
514		return true;
515	default:
516		return false;
517	}
518}
519
520static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
521				union power_supply_propval *val)
522{
523	unsigned int regval;
524	int ret;
525
526	ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, &regval);
527	if (ret < 0)
528		return ret;
529
530	switch (regval & GCHGDET_TYPE_MASK) {
531	case GCHGDET_TYPE_SDP:
532		val->intval = POWER_SUPPLY_USB_TYPE_SDP;
533		break;
534	case GCHGDET_TYPE_CDP:
535		val->intval = POWER_SUPPLY_USB_TYPE_CDP;
536		break;
537	case GCHGDET_TYPE_DCP:
538		val->intval = POWER_SUPPLY_USB_TYPE_DCP;
539		break;
540	default:
541		val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
542	}
543
544	return 0;
545}
546
547static int rn5t618_usb_get_property(struct power_supply *psy,
548				    enum power_supply_property psp,
549				    union power_supply_propval *val)
550{
551	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
552	unsigned int chgstate;
553	unsigned int regval;
554	bool online;
555	int ret;
556
557	ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
558	if (ret)
559		return ret;
560
561	online = !!(chgstate & CHG_STATE_USB_INPUT);
562
563	switch (psp) {
564	case POWER_SUPPLY_PROP_ONLINE:
565		val->intval = online;
566		break;
567	case POWER_SUPPLY_PROP_STATUS:
568		if (!online) {
569			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
570			break;
571		}
572		val->intval = rn5t618_decode_status(chgstate);
573		if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
574			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
575
576		break;
577	case POWER_SUPPLY_PROP_USB_TYPE:
578		if (!online || (info->rn5t618->variant != RC5T619))
579			return -ENODATA;
580
581		return rc5t619_usb_get_type(info, val);
582	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
583		ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,
584				  &regval);
585		if (ret < 0)
586			return ret;
587
588		val->intval = 0;
589		if (regval & 2) {
590			ret = regmap_read(info->rn5t618->regmap,
591					  RN5T618_REGISET2,
592					  &regval);
593			if (ret < 0)
594				return ret;
595
596			val->intval = FROM_CUR_REG(regval);
597		}
598		break;
599	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
600		if (!info->channel_vusb)
601			return -ENODATA;
602
603		ret = iio_read_channel_processed_scale(info->channel_vusb, &val->intval, 1000);
604		if (ret < 0)
605			return ret;
606
607		break;
608	default:
609		return -EINVAL;
610	}
611
612	return 0;
613}
614
615static int rn5t618_usb_set_property(struct power_supply *psy,
616				    enum power_supply_property psp,
617				    const union power_supply_propval *val)
618{
619	struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
620	int ret;
621
622	switch (psp) {
623	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
624		if (val->intval > USB_MAX_CUR)
625			return -EINVAL;
626
627		if (val->intval < CHG_MIN_CUR)
628			return -EINVAL;
629
630		ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,
631				   0xE0 | TO_CUR_REG(val->intval));
632		if (ret < 0)
633			return ret;
634
635		break;
636	default:
637		return -EINVAL;
638	}
639
640	return 0;
641}
642
643static int rn5t618_usb_property_is_writeable(struct power_supply *psy,
644					     enum power_supply_property psp)
645{
646	switch (psp) {
647	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
648		return true;
649	default:
650		return false;
651	}
652}
653
654static const struct power_supply_desc rn5t618_battery_desc = {
655	.name                   = "rn5t618-battery",
656	.type                   = POWER_SUPPLY_TYPE_BATTERY,
657	.properties             = rn5t618_battery_props,
658	.num_properties         = ARRAY_SIZE(rn5t618_battery_props),
659	.get_property           = rn5t618_battery_get_property,
660	.set_property           = rn5t618_battery_set_property,
661	.property_is_writeable  = rn5t618_battery_property_is_writeable,
662};
663
664static const struct power_supply_desc rn5t618_adp_desc = {
665	.name                   = "rn5t618-adp",
666	.type                   = POWER_SUPPLY_TYPE_MAINS,
667	.properties             = rn5t618_adp_props,
668	.num_properties         = ARRAY_SIZE(rn5t618_adp_props),
669	.get_property           = rn5t618_adp_get_property,
670	.set_property           = rn5t618_adp_set_property,
671	.property_is_writeable  = rn5t618_adp_property_is_writeable,
672};
673
674static const struct power_supply_desc rn5t618_usb_desc = {
675	.name                   = "rn5t618-usb",
676	.type                   = POWER_SUPPLY_TYPE_USB,
677	.usb_types		= BIT(POWER_SUPPLY_USB_TYPE_SDP) |
678				  BIT(POWER_SUPPLY_USB_TYPE_CDP) |
679				  BIT(POWER_SUPPLY_USB_TYPE_DCP) |
680				  BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
681	.properties             = rn5t618_usb_props,
682	.num_properties         = ARRAY_SIZE(rn5t618_usb_props),
683	.get_property           = rn5t618_usb_get_property,
684	.set_property           = rn5t618_usb_set_property,
685	.property_is_writeable  = rn5t618_usb_property_is_writeable,
686};
687
688static irqreturn_t rn5t618_charger_irq(int irq, void *data)
689{
690	struct device *dev = data;
691	struct rn5t618_power_info *info = dev_get_drvdata(dev);
692
693	unsigned int ctrl, stat1, stat2, err;
694
695	regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err);
696	regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl);
697	regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1);
698	regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2);
699
700	regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0);
701	regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0);
702	regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0);
703	regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0);
704
705	dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n",
706		err, ctrl, stat1, stat2);
707
708	power_supply_changed(info->usb);
709	power_supply_changed(info->adp);
710	power_supply_changed(info->battery);
711
712	return IRQ_HANDLED;
713}
714
715static int rn5t618_power_probe(struct platform_device *pdev)
716{
717	int ret = 0;
718	unsigned int v;
719	struct power_supply_config psy_cfg = {};
720	struct rn5t618_power_info *info;
721
722	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
723	if (!info)
724		return -ENOMEM;
725
726	info->pdev = pdev;
727	info->rn5t618 = dev_get_drvdata(pdev->dev.parent);
728	info->irq = -1;
729
730	platform_set_drvdata(pdev, info);
731
732	info->channel_vusb = devm_iio_channel_get(&pdev->dev, "vusb");
733	if (IS_ERR(info->channel_vusb)) {
734		if (PTR_ERR(info->channel_vusb) == -ENODEV)
735			return -EPROBE_DEFER;
736		return PTR_ERR(info->channel_vusb);
737	}
738
739	info->channel_vadp = devm_iio_channel_get(&pdev->dev, "vadp");
740	if (IS_ERR(info->channel_vadp)) {
741		if (PTR_ERR(info->channel_vadp) == -ENODEV)
742			return -EPROBE_DEFER;
743		return PTR_ERR(info->channel_vadp);
744	}
745
746	ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v);
747	if (ret)
748		return ret;
749
750	if (!(v & FG_ENABLE)) {
751		/* E.g. the vendor kernels of various Kobo and Tolino Ebook
752		 * readers disable the fuel gauge on shutdown. If a kernel
753		 * without fuel gauge support is booted after that, the fuel
754		 * gauge will get decalibrated.
755		 */
756		dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n");
757		dev_info(&pdev->dev, "Expect imprecise results\n");
758		regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL,
759				   FG_ENABLE, FG_ENABLE);
760	}
761
762	psy_cfg.drv_data = info;
763	info->battery = devm_power_supply_register(&pdev->dev,
764						   &rn5t618_battery_desc,
765						   &psy_cfg);
766	if (IS_ERR(info->battery)) {
767		ret = PTR_ERR(info->battery);
768		dev_err(&pdev->dev, "failed to register battery: %d\n", ret);
769		return ret;
770	}
771
772	info->adp = devm_power_supply_register(&pdev->dev,
773					       &rn5t618_adp_desc,
774					       &psy_cfg);
775	if (IS_ERR(info->adp)) {
776		ret = PTR_ERR(info->adp);
777		dev_err(&pdev->dev, "failed to register adp: %d\n", ret);
778		return ret;
779	}
780
781	info->usb = devm_power_supply_register(&pdev->dev,
782					       &rn5t618_usb_desc,
783					       &psy_cfg);
784	if (IS_ERR(info->usb)) {
785		ret = PTR_ERR(info->usb);
786		dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
787		return ret;
788	}
789
790	if (info->rn5t618->irq_data)
791		info->irq = regmap_irq_get_virq(info->rn5t618->irq_data,
792						RN5T618_IRQ_CHG);
793
794	if (info->irq < 0)
795		info->irq = -1;
796	else {
797		ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
798						rn5t618_charger_irq,
799						IRQF_ONESHOT,
800						"rn5t618_power",
801						&pdev->dev);
802
803		if (ret < 0) {
804			dev_err(&pdev->dev, "request IRQ:%d fail\n",
805				info->irq);
806			info->irq = -1;
807		}
808	}
809
810	return 0;
811}
812
813static struct platform_driver rn5t618_power_driver = {
814	.driver = {
815		.name   = "rn5t618-power",
816	},
817	.probe = rn5t618_power_probe,
818};
819
820module_platform_driver(rn5t618_power_driver);
821MODULE_ALIAS("platform:rn5t618-power");
822MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618");
823MODULE_LICENSE("GPL");
~/ Read-only file preview.