xref: /linux/drivers/power/supply/bq257xx_charger.c (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
1*1cc017b7SChris Morgan // SPDX-License-Identifier: GPL-2.0
2*1cc017b7SChris Morgan /*
3*1cc017b7SChris Morgan  * BQ257XX Battery Charger Driver
4*1cc017b7SChris Morgan  * Copyright (C) 2025 Chris Morgan <macromorgan@hotmail.com>
5*1cc017b7SChris Morgan  */
6*1cc017b7SChris Morgan 
7*1cc017b7SChris Morgan #include <linux/bitfield.h>
8*1cc017b7SChris Morgan #include <linux/i2c.h>
9*1cc017b7SChris Morgan #include <linux/interrupt.h>
10*1cc017b7SChris Morgan #include <linux/mfd/bq257xx.h>
11*1cc017b7SChris Morgan #include <linux/platform_device.h>
12*1cc017b7SChris Morgan #include <linux/power_supply.h>
13*1cc017b7SChris Morgan #include <linux/property.h>
14*1cc017b7SChris Morgan #include <linux/regmap.h>
15*1cc017b7SChris Morgan 
16*1cc017b7SChris Morgan /* Forward declaration of driver data. */
17*1cc017b7SChris Morgan struct bq257xx_chg;
18*1cc017b7SChris Morgan 
19*1cc017b7SChris Morgan /**
20*1cc017b7SChris Morgan  * struct bq257xx_chip_info - chip specific routines
21*1cc017b7SChris Morgan  * @bq257xx_hw_init: init function for hw
22*1cc017b7SChris Morgan  * @bq257xx_hw_shutdown: shutdown function for hw
23*1cc017b7SChris Morgan  * @bq257xx_get_state: get and update state of hardware
24*1cc017b7SChris Morgan  * @bq257xx_set_ichg: set maximum charge current (in uA)
25*1cc017b7SChris Morgan  * @bq257xx_set_vbatreg: set maximum charge voltage (in uV)
26*1cc017b7SChris Morgan  * @bq257xx_set_iindpm: set maximum input current (in uA)
27*1cc017b7SChris Morgan  */
28*1cc017b7SChris Morgan struct bq257xx_chip_info {
29*1cc017b7SChris Morgan 	int (*bq257xx_hw_init)(struct bq257xx_chg *pdata);
30*1cc017b7SChris Morgan 	void (*bq257xx_hw_shutdown)(struct bq257xx_chg *pdata);
31*1cc017b7SChris Morgan 	int (*bq257xx_get_state)(struct bq257xx_chg *pdata);
32*1cc017b7SChris Morgan 	int (*bq257xx_set_ichg)(struct bq257xx_chg *pdata, int ichg);
33*1cc017b7SChris Morgan 	int (*bq257xx_set_vbatreg)(struct bq257xx_chg *pdata, int vbatreg);
34*1cc017b7SChris Morgan 	int (*bq257xx_set_iindpm)(struct bq257xx_chg *pdata, int iindpm);
35*1cc017b7SChris Morgan };
36*1cc017b7SChris Morgan 
37*1cc017b7SChris Morgan /**
38*1cc017b7SChris Morgan  * struct bq257xx_chg - driver data for charger
39*1cc017b7SChris Morgan  * @chip: hw specific functions
40*1cc017b7SChris Morgan  * @bq: parent MFD device
41*1cc017b7SChris Morgan  * @charger: power supply device
42*1cc017b7SChris Morgan  * @online: charger input is present
43*1cc017b7SChris Morgan  * @fast_charge: charger is in fast charge mode
44*1cc017b7SChris Morgan  * @pre_charge: charger is in pre-charge mode
45*1cc017b7SChris Morgan  * @ov_fault: charger reports over voltage fault
46*1cc017b7SChris Morgan  * @batoc_fault: charger reports battery over current fault
47*1cc017b7SChris Morgan  * @oc_fault: charger reports over current fault
48*1cc017b7SChris Morgan  * @usb_type: USB type reported from parent power supply
49*1cc017b7SChris Morgan  * @supplied: Status of parent power supply
50*1cc017b7SChris Morgan  * @iindpm_max: maximum input current limit (uA)
51*1cc017b7SChris Morgan  * @vbat_max: maximum charge voltage (uV)
52*1cc017b7SChris Morgan  * @ichg_max: maximum charge current (uA)
53*1cc017b7SChris Morgan  * @vsys_min: minimum system voltage (uV)
54*1cc017b7SChris Morgan  */
55*1cc017b7SChris Morgan struct bq257xx_chg {
56*1cc017b7SChris Morgan 	const struct bq257xx_chip_info *chip;
57*1cc017b7SChris Morgan 	struct bq257xx_device *bq;
58*1cc017b7SChris Morgan 	struct power_supply *charger;
59*1cc017b7SChris Morgan 	bool online;
60*1cc017b7SChris Morgan 	bool fast_charge;
61*1cc017b7SChris Morgan 	bool pre_charge;
62*1cc017b7SChris Morgan 	bool ov_fault;
63*1cc017b7SChris Morgan 	bool batoc_fault;
64*1cc017b7SChris Morgan 	bool oc_fault;
65*1cc017b7SChris Morgan 	int usb_type;
66*1cc017b7SChris Morgan 	int supplied;
67*1cc017b7SChris Morgan 	u32 iindpm_max;
68*1cc017b7SChris Morgan 	u32 vbat_max;
69*1cc017b7SChris Morgan 	u32 ichg_max;
70*1cc017b7SChris Morgan 	u32 vsys_min;
71*1cc017b7SChris Morgan };
72*1cc017b7SChris Morgan 
73*1cc017b7SChris Morgan /**
74*1cc017b7SChris Morgan  * bq25703_get_state() - Get the current state of the device
75*1cc017b7SChris Morgan  * @pdata: driver platform data
76*1cc017b7SChris Morgan  *
77*1cc017b7SChris Morgan  * Get the current state of the charger. Check if the charger is
78*1cc017b7SChris Morgan  * powered, what kind of charge state (if any) the device is in,
79*1cc017b7SChris Morgan  * and if there are any active faults.
80*1cc017b7SChris Morgan  *
81*1cc017b7SChris Morgan  * Return: Returns 0 on success, or error on failure to read device.
82*1cc017b7SChris Morgan  */
83*1cc017b7SChris Morgan static int bq25703_get_state(struct bq257xx_chg *pdata)
84*1cc017b7SChris Morgan {
85*1cc017b7SChris Morgan 	unsigned int reg;
86*1cc017b7SChris Morgan 	int ret;
87*1cc017b7SChris Morgan 
88*1cc017b7SChris Morgan 	ret = regmap_read(pdata->bq->regmap, BQ25703_CHARGER_STATUS, &reg);
89*1cc017b7SChris Morgan 	if (ret)
90*1cc017b7SChris Morgan 		return ret;
91*1cc017b7SChris Morgan 
92*1cc017b7SChris Morgan 	pdata->online = reg & BQ25703_STS_AC_STAT;
93*1cc017b7SChris Morgan 	pdata->fast_charge = reg & BQ25703_STS_IN_FCHRG;
94*1cc017b7SChris Morgan 	pdata->pre_charge = reg & BQ25703_STS_IN_PCHRG;
95*1cc017b7SChris Morgan 	pdata->ov_fault = reg & BQ25703_STS_FAULT_ACOV;
96*1cc017b7SChris Morgan 	pdata->batoc_fault = reg & BQ25703_STS_FAULT_BATOC;
97*1cc017b7SChris Morgan 	pdata->oc_fault = reg & BQ25703_STS_FAULT_ACOC;
98*1cc017b7SChris Morgan 
99*1cc017b7SChris Morgan 	return 0;
100*1cc017b7SChris Morgan }
101*1cc017b7SChris Morgan 
102*1cc017b7SChris Morgan /**
103*1cc017b7SChris Morgan  * bq25703_get_min_vsys() - Get the minimum system voltage
104*1cc017b7SChris Morgan  * @pdata: driver platform data
105*1cc017b7SChris Morgan  * @intval: value for minimum voltage
106*1cc017b7SChris Morgan  *
107*1cc017b7SChris Morgan  * Return: Returns 0 on success or error on failure to read.
108*1cc017b7SChris Morgan  */
109*1cc017b7SChris Morgan static int bq25703_get_min_vsys(struct bq257xx_chg *pdata, int *intval)
110*1cc017b7SChris Morgan {
111*1cc017b7SChris Morgan 	unsigned int reg;
112*1cc017b7SChris Morgan 	int ret;
113*1cc017b7SChris Morgan 
114*1cc017b7SChris Morgan 	ret = regmap_read(pdata->bq->regmap, BQ25703_MIN_VSYS,
115*1cc017b7SChris Morgan 			  &reg);
116*1cc017b7SChris Morgan 	if (ret)
117*1cc017b7SChris Morgan 		return ret;
118*1cc017b7SChris Morgan 
119*1cc017b7SChris Morgan 	reg = FIELD_GET(BQ25703_MINVSYS_MASK, reg);
120*1cc017b7SChris Morgan 	*intval = (reg * BQ25703_MINVSYS_STEP_UV) + BQ25703_MINVSYS_MIN_UV;
121*1cc017b7SChris Morgan 
122*1cc017b7SChris Morgan 	return ret;
123*1cc017b7SChris Morgan }
124*1cc017b7SChris Morgan 
125*1cc017b7SChris Morgan /**
126*1cc017b7SChris Morgan  * bq25703_set_min_vsys() - Set the minimum system voltage
127*1cc017b7SChris Morgan  * @pdata: driver platform data
128*1cc017b7SChris Morgan  * @vsys: voltage value to set in uV.
129*1cc017b7SChris Morgan  *
130*1cc017b7SChris Morgan  * This function takes a requested minimum system voltage value, clamps
131*1cc017b7SChris Morgan  * it between the minimum supported value by the charger and a user
132*1cc017b7SChris Morgan  * defined minimum system value, and then writes the value to the
133*1cc017b7SChris Morgan  * appropriate register.
134*1cc017b7SChris Morgan  *
135*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if an error occurs.
136*1cc017b7SChris Morgan  */
137*1cc017b7SChris Morgan static int bq25703_set_min_vsys(struct bq257xx_chg *pdata, int vsys)
138*1cc017b7SChris Morgan {
139*1cc017b7SChris Morgan 	unsigned int reg;
140*1cc017b7SChris Morgan 	int vsys_min = pdata->vsys_min;
141*1cc017b7SChris Morgan 
142*1cc017b7SChris Morgan 	vsys = clamp(vsys, BQ25703_MINVSYS_MIN_UV, vsys_min);
143*1cc017b7SChris Morgan 	reg = ((vsys - BQ25703_MINVSYS_MIN_UV) / BQ25703_MINVSYS_STEP_UV);
144*1cc017b7SChris Morgan 	reg = FIELD_PREP(BQ25703_MINVSYS_MASK, reg);
145*1cc017b7SChris Morgan 
146*1cc017b7SChris Morgan 	return regmap_write(pdata->bq->regmap, BQ25703_MIN_VSYS,
147*1cc017b7SChris Morgan 			    reg);
148*1cc017b7SChris Morgan }
149*1cc017b7SChris Morgan 
150*1cc017b7SChris Morgan /**
151*1cc017b7SChris Morgan  * bq25703_get_cur() - Get the reported current from the battery
152*1cc017b7SChris Morgan  * @pdata: driver platform data
153*1cc017b7SChris Morgan  * @intval: value of reported battery current
154*1cc017b7SChris Morgan  *
155*1cc017b7SChris Morgan  * Read the reported current from the battery. Since value is always
156*1cc017b7SChris Morgan  * positive set sign to negative if discharging.
157*1cc017b7SChris Morgan  *
158*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if unable to read value.
159*1cc017b7SChris Morgan  */
160*1cc017b7SChris Morgan static int bq25703_get_cur(struct bq257xx_chg *pdata, int *intval)
161*1cc017b7SChris Morgan {
162*1cc017b7SChris Morgan 	unsigned int reg;
163*1cc017b7SChris Morgan 	int ret;
164*1cc017b7SChris Morgan 
165*1cc017b7SChris Morgan 	ret = regmap_read(pdata->bq->regmap, BQ25703_ADCIBAT_CHG, &reg);
166*1cc017b7SChris Morgan 	if (ret < 0)
167*1cc017b7SChris Morgan 		return ret;
168*1cc017b7SChris Morgan 
169*1cc017b7SChris Morgan 	if (pdata->online)
170*1cc017b7SChris Morgan 		*intval = FIELD_GET(BQ25703_ADCIBAT_CHG_MASK, reg) *
171*1cc017b7SChris Morgan 			  BQ25703_ADCIBAT_CHG_STEP_UA;
172*1cc017b7SChris Morgan 	else
173*1cc017b7SChris Morgan 		*intval = -(FIELD_GET(BQ25703_ADCIBAT_DISCHG_MASK, reg) *
174*1cc017b7SChris Morgan 			    BQ25703_ADCIBAT_DIS_STEP_UA);
175*1cc017b7SChris Morgan 
176*1cc017b7SChris Morgan 	return ret;
177*1cc017b7SChris Morgan }
178*1cc017b7SChris Morgan 
179*1cc017b7SChris Morgan /**
180*1cc017b7SChris Morgan  * bq25703_get_ichg_cur() - Get the maximum reported charge current
181*1cc017b7SChris Morgan  * @pdata: driver platform data
182*1cc017b7SChris Morgan  * @intval: value of maximum reported charge current
183*1cc017b7SChris Morgan  *
184*1cc017b7SChris Morgan  * Get the maximum reported charge current from the battery.
185*1cc017b7SChris Morgan  *
186*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if unable to read value.
187*1cc017b7SChris Morgan  */
188*1cc017b7SChris Morgan static int bq25703_get_ichg_cur(struct bq257xx_chg *pdata, int *intval)
189*1cc017b7SChris Morgan {
190*1cc017b7SChris Morgan 	unsigned int reg;
191*1cc017b7SChris Morgan 	int ret;
192*1cc017b7SChris Morgan 
193*1cc017b7SChris Morgan 	ret = regmap_read(pdata->bq->regmap, BQ25703_CHARGE_CURRENT, &reg);
194*1cc017b7SChris Morgan 	if (ret)
195*1cc017b7SChris Morgan 		return ret;
196*1cc017b7SChris Morgan 
197*1cc017b7SChris Morgan 	*intval = FIELD_GET(BQ25703_ICHG_MASK, reg) * BQ25703_ICHG_STEP_UA;
198*1cc017b7SChris Morgan 
199*1cc017b7SChris Morgan 	return ret;
200*1cc017b7SChris Morgan }
201*1cc017b7SChris Morgan 
202*1cc017b7SChris Morgan /**
203*1cc017b7SChris Morgan  * bq25703_set_ichg_cur() - Set the maximum charge current
204*1cc017b7SChris Morgan  * @pdata: driver platform data
205*1cc017b7SChris Morgan  * @ichg: current value to set in uA.
206*1cc017b7SChris Morgan  *
207*1cc017b7SChris Morgan  * This function takes a requested maximum charge current value, clamps
208*1cc017b7SChris Morgan  * it between the minimum supported value by the charger and a user
209*1cc017b7SChris Morgan  * defined maximum charging value, and then writes the value to the
210*1cc017b7SChris Morgan  * appropriate register.
211*1cc017b7SChris Morgan  *
212*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if an error occurs.
213*1cc017b7SChris Morgan  */
214*1cc017b7SChris Morgan static int bq25703_set_ichg_cur(struct bq257xx_chg *pdata, int ichg)
215*1cc017b7SChris Morgan {
216*1cc017b7SChris Morgan 	unsigned int reg;
217*1cc017b7SChris Morgan 	int ichg_max = pdata->ichg_max;
218*1cc017b7SChris Morgan 
219*1cc017b7SChris Morgan 	ichg = clamp(ichg, BQ25703_ICHG_MIN_UA, ichg_max);
220*1cc017b7SChris Morgan 	reg = FIELD_PREP(BQ25703_ICHG_MASK, (ichg / BQ25703_ICHG_STEP_UA));
221*1cc017b7SChris Morgan 
222*1cc017b7SChris Morgan 	return regmap_write(pdata->bq->regmap, BQ25703_CHARGE_CURRENT,
223*1cc017b7SChris Morgan 			    reg);
224*1cc017b7SChris Morgan }
225*1cc017b7SChris Morgan 
226*1cc017b7SChris Morgan /**
227*1cc017b7SChris Morgan  * bq25703_get_chrg_volt() - Get the maximum set charge voltage
228*1cc017b7SChris Morgan  * @pdata: driver platform data
229*1cc017b7SChris Morgan  * @intval: maximum charge voltage value
230*1cc017b7SChris Morgan  *
231*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if unable to read value.
232*1cc017b7SChris Morgan  */
233*1cc017b7SChris Morgan static int bq25703_get_chrg_volt(struct bq257xx_chg *pdata, int *intval)
234*1cc017b7SChris Morgan {
235*1cc017b7SChris Morgan 	unsigned int reg;
236*1cc017b7SChris Morgan 	int ret;
237*1cc017b7SChris Morgan 
238*1cc017b7SChris Morgan 	ret = regmap_read(pdata->bq->regmap, BQ25703_MAX_CHARGE_VOLT,
239*1cc017b7SChris Morgan 			  &reg);
240*1cc017b7SChris Morgan 	if (ret)
241*1cc017b7SChris Morgan 		return ret;
242*1cc017b7SChris Morgan 
243*1cc017b7SChris Morgan 	*intval = FIELD_GET(BQ25703_MAX_CHARGE_VOLT_MASK, reg) *
244*1cc017b7SChris Morgan 		  BQ25703_VBATREG_STEP_UV;
245*1cc017b7SChris Morgan 
246*1cc017b7SChris Morgan 	return ret;
247*1cc017b7SChris Morgan }
248*1cc017b7SChris Morgan 
249*1cc017b7SChris Morgan /**
250*1cc017b7SChris Morgan  * bq25703_set_chrg_volt() - Set the maximum charge voltage
251*1cc017b7SChris Morgan  * @pdata: driver platform data
252*1cc017b7SChris Morgan  * @vbat: voltage value to set in uV.
253*1cc017b7SChris Morgan  *
254*1cc017b7SChris Morgan  * This function takes a requested maximum charge voltage value, clamps
255*1cc017b7SChris Morgan  * it between the minimum supported value by the charger and a user
256*1cc017b7SChris Morgan  * defined maximum charging value, and then writes the value to the
257*1cc017b7SChris Morgan  * appropriate register.
258*1cc017b7SChris Morgan  *
259*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if an error occurs.
260*1cc017b7SChris Morgan  */
261*1cc017b7SChris Morgan static int bq25703_set_chrg_volt(struct bq257xx_chg *pdata, int vbat)
262*1cc017b7SChris Morgan {
263*1cc017b7SChris Morgan 	unsigned int reg;
264*1cc017b7SChris Morgan 	int vbat_max = pdata->vbat_max;
265*1cc017b7SChris Morgan 
266*1cc017b7SChris Morgan 	vbat = clamp(vbat, BQ25703_VBATREG_MIN_UV, vbat_max);
267*1cc017b7SChris Morgan 
268*1cc017b7SChris Morgan 	reg = FIELD_PREP(BQ25703_MAX_CHARGE_VOLT_MASK,
269*1cc017b7SChris Morgan 			 (vbat / BQ25703_VBATREG_STEP_UV));
270*1cc017b7SChris Morgan 
271*1cc017b7SChris Morgan 	return regmap_write(pdata->bq->regmap, BQ25703_MAX_CHARGE_VOLT,
272*1cc017b7SChris Morgan 			    reg);
273*1cc017b7SChris Morgan }
274*1cc017b7SChris Morgan 
275*1cc017b7SChris Morgan /**
276*1cc017b7SChris Morgan  * bq25703_get_iindpm() - Get the maximum set input current
277*1cc017b7SChris Morgan  * @pdata: driver platform data
278*1cc017b7SChris Morgan  * @intval: maximum input current value
279*1cc017b7SChris Morgan  *
280*1cc017b7SChris Morgan  * Read the actual input current limit from the device into intval.
281*1cc017b7SChris Morgan  * This can differ from the value programmed due to some autonomous
282*1cc017b7SChris Morgan  * functions that may be enabled (but are not currently). This is why
283*1cc017b7SChris Morgan  * there is a different register used.
284*1cc017b7SChris Morgan  *
285*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if unable to read register
286*1cc017b7SChris Morgan  * value.
287*1cc017b7SChris Morgan  */
288*1cc017b7SChris Morgan static int bq25703_get_iindpm(struct bq257xx_chg *pdata, int *intval)
289*1cc017b7SChris Morgan {
290*1cc017b7SChris Morgan 	unsigned int reg;
291*1cc017b7SChris Morgan 	int ret;
292*1cc017b7SChris Morgan 
293*1cc017b7SChris Morgan 	ret = regmap_read(pdata->bq->regmap, BQ25703_IIN_DPM, &reg);
294*1cc017b7SChris Morgan 	if (ret)
295*1cc017b7SChris Morgan 		return ret;
296*1cc017b7SChris Morgan 
297*1cc017b7SChris Morgan 	reg = FIELD_GET(BQ25703_IINDPM_MASK, reg);
298*1cc017b7SChris Morgan 	*intval = (reg * BQ25703_IINDPM_STEP_UA) + BQ25703_IINDPM_OFFSET_UA;
299*1cc017b7SChris Morgan 
300*1cc017b7SChris Morgan 	return ret;
301*1cc017b7SChris Morgan }
302*1cc017b7SChris Morgan 
303*1cc017b7SChris Morgan /**
304*1cc017b7SChris Morgan  * bq25703_set_iindpm() - Set the maximum input current
305*1cc017b7SChris Morgan  * @pdata: driver platform data
306*1cc017b7SChris Morgan  * @iindpm: current value in uA.
307*1cc017b7SChris Morgan  *
308*1cc017b7SChris Morgan  * This function takes a requested maximum input current value, clamps
309*1cc017b7SChris Morgan  * it between the minimum supported value by the charger and a user
310*1cc017b7SChris Morgan  * defined maximum input value, and then writes the value to the
311*1cc017b7SChris Morgan  * appropriate register.
312*1cc017b7SChris Morgan  *
313*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if an error occurs.
314*1cc017b7SChris Morgan  */
315*1cc017b7SChris Morgan static int bq25703_set_iindpm(struct bq257xx_chg *pdata, int iindpm)
316*1cc017b7SChris Morgan {
317*1cc017b7SChris Morgan 	unsigned int reg;
318*1cc017b7SChris Morgan 	int iindpm_max = pdata->iindpm_max;
319*1cc017b7SChris Morgan 
320*1cc017b7SChris Morgan 	iindpm = clamp(iindpm, BQ25703_IINDPM_MIN_UA, iindpm_max);
321*1cc017b7SChris Morgan 
322*1cc017b7SChris Morgan 	reg = ((iindpm - BQ25703_IINDPM_OFFSET_UA) / BQ25703_IINDPM_STEP_UA);
323*1cc017b7SChris Morgan 
324*1cc017b7SChris Morgan 	return regmap_write(pdata->bq->regmap, BQ25703_IIN_HOST,
325*1cc017b7SChris Morgan 			    FIELD_PREP(BQ25703_IINDPM_MASK, reg));
326*1cc017b7SChris Morgan }
327*1cc017b7SChris Morgan 
328*1cc017b7SChris Morgan /**
329*1cc017b7SChris Morgan  * bq25703_get_vbat() - Get the reported voltage from the battery
330*1cc017b7SChris Morgan  * @pdata: driver platform data
331*1cc017b7SChris Morgan  * @intval: value of reported battery voltage
332*1cc017b7SChris Morgan  *
333*1cc017b7SChris Morgan  * Read value of battery voltage into intval.
334*1cc017b7SChris Morgan  *
335*1cc017b7SChris Morgan  * Return: Returns 0 on success or error if unable to read value.
336*1cc017b7SChris Morgan  */
337*1cc017b7SChris Morgan static int bq25703_get_vbat(struct bq257xx_chg *pdata, int *intval)
338*1cc017b7SChris Morgan {
339*1cc017b7SChris Morgan 	unsigned int reg;
340*1cc017b7SChris Morgan 	int ret;
341*1cc017b7SChris Morgan 
342*1cc017b7SChris Morgan 	ret = regmap_read(pdata->bq->regmap, BQ25703_ADCVSYSVBAT, &reg);
343*1cc017b7SChris Morgan 	if (ret)
344*1cc017b7SChris Morgan 		return ret;
345*1cc017b7SChris Morgan 
346*1cc017b7SChris Morgan 	reg = FIELD_GET(BQ25703_ADCVBAT_MASK, reg);
347*1cc017b7SChris Morgan 	*intval = (reg * BQ25703_ADCVSYSVBAT_STEP) + BQ25703_ADCVSYSVBAT_OFFSET_UV;
348*1cc017b7SChris Morgan 
349*1cc017b7SChris Morgan 	return ret;
350*1cc017b7SChris Morgan }
351*1cc017b7SChris Morgan 
352*1cc017b7SChris Morgan /**
353*1cc017b7SChris Morgan  * bq25703_hw_init() - Set all the required registers to init the charger
354*1cc017b7SChris Morgan  * @pdata: driver platform data
355*1cc017b7SChris Morgan  *
356*1cc017b7SChris Morgan  * Initialize the BQ25703 by first disabling the watchdog timer (which
357*1cc017b7SChris Morgan  * shuts off the charger in the absence of periodic writes). Then, set
358*1cc017b7SChris Morgan  * the charge current, charge voltage, minimum system voltage, and
359*1cc017b7SChris Morgan  * input current limit. Disable low power mode to allow ADCs and
360*1cc017b7SChris Morgan  * interrupts. Enable the ADC, start the ADC, set the ADC scale to
361*1cc017b7SChris Morgan  * full, and enable each individual ADC channel.
362*1cc017b7SChris Morgan  *
363*1cc017b7SChris Morgan  * Return: Returns 0 on success or error code on error.
364*1cc017b7SChris Morgan  */
365*1cc017b7SChris Morgan static int bq25703_hw_init(struct bq257xx_chg *pdata)
366*1cc017b7SChris Morgan {
367*1cc017b7SChris Morgan 	struct regmap *regmap = pdata->bq->regmap;
368*1cc017b7SChris Morgan 	int ret = 0;
369*1cc017b7SChris Morgan 
370*1cc017b7SChris Morgan 	regmap_update_bits(regmap, BQ25703_CHARGE_OPTION_0,
371*1cc017b7SChris Morgan 			   BQ25703_WDTMR_ADJ_MASK,
372*1cc017b7SChris Morgan 			   FIELD_PREP(BQ25703_WDTMR_ADJ_MASK,
373*1cc017b7SChris Morgan 			   BQ25703_WDTMR_DISABLE));
374*1cc017b7SChris Morgan 
375*1cc017b7SChris Morgan 	ret = pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max);
376*1cc017b7SChris Morgan 	if (ret)
377*1cc017b7SChris Morgan 		return ret;
378*1cc017b7SChris Morgan 
379*1cc017b7SChris Morgan 	ret = pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max);
380*1cc017b7SChris Morgan 	if (ret)
381*1cc017b7SChris Morgan 		return ret;
382*1cc017b7SChris Morgan 
383*1cc017b7SChris Morgan 	ret = bq25703_set_min_vsys(pdata, pdata->vsys_min);
384*1cc017b7SChris Morgan 	if (ret)
385*1cc017b7SChris Morgan 		return ret;
386*1cc017b7SChris Morgan 
387*1cc017b7SChris Morgan 	ret = pdata->chip->bq257xx_set_iindpm(pdata, pdata->iindpm_max);
388*1cc017b7SChris Morgan 	if (ret)
389*1cc017b7SChris Morgan 		return ret;
390*1cc017b7SChris Morgan 
391*1cc017b7SChris Morgan 	/* Disable low power mode by writing 0 to the register. */
392*1cc017b7SChris Morgan 	regmap_update_bits(regmap, BQ25703_CHARGE_OPTION_0,
393*1cc017b7SChris Morgan 			   BQ25703_EN_LWPWR, 0);
394*1cc017b7SChris Morgan 
395*1cc017b7SChris Morgan 	/* Enable the ADC. */
396*1cc017b7SChris Morgan 	regmap_update_bits(regmap, BQ25703_ADC_OPTION,
397*1cc017b7SChris Morgan 			   BQ25703_ADC_CONV_EN, BQ25703_ADC_CONV_EN);
398*1cc017b7SChris Morgan 
399*1cc017b7SChris Morgan 	/* Start the ADC. */
400*1cc017b7SChris Morgan 	regmap_update_bits(regmap, BQ25703_ADC_OPTION,
401*1cc017b7SChris Morgan 			   BQ25703_ADC_START, BQ25703_ADC_START);
402*1cc017b7SChris Morgan 
403*1cc017b7SChris Morgan 	/* Set the scale of the ADC. */
404*1cc017b7SChris Morgan 	regmap_update_bits(regmap, BQ25703_ADC_OPTION,
405*1cc017b7SChris Morgan 			   BQ25703_ADC_FULL_SCALE, BQ25703_ADC_FULL_SCALE);
406*1cc017b7SChris Morgan 
407*1cc017b7SChris Morgan 	/* Enable each of the ADC channels available. */
408*1cc017b7SChris Morgan 	regmap_update_bits(regmap, BQ25703_ADC_OPTION,
409*1cc017b7SChris Morgan 			   BQ25703_ADC_CH_MASK,
410*1cc017b7SChris Morgan 			   (BQ25703_ADC_CMPIN_EN | BQ25703_ADC_VBUS_EN |
411*1cc017b7SChris Morgan 			   BQ25703_ADC_PSYS_EN | BQ25703_ADC_IIN_EN |
412*1cc017b7SChris Morgan 			   BQ25703_ADC_IDCHG_EN | BQ25703_ADC_ICHG_EN |
413*1cc017b7SChris Morgan 			   BQ25703_ADC_VSYS_EN | BQ25703_ADC_VBAT_EN));
414*1cc017b7SChris Morgan 
415*1cc017b7SChris Morgan 	return ret;
416*1cc017b7SChris Morgan }
417*1cc017b7SChris Morgan 
418*1cc017b7SChris Morgan /**
419*1cc017b7SChris Morgan  * bq25703_hw_shutdown() - Set registers for shutdown
420*1cc017b7SChris Morgan  * @pdata: driver platform data
421*1cc017b7SChris Morgan  *
422*1cc017b7SChris Morgan  * Enable low power mode for the device while in shutdown.
423*1cc017b7SChris Morgan  */
424*1cc017b7SChris Morgan static void bq25703_hw_shutdown(struct bq257xx_chg *pdata)
425*1cc017b7SChris Morgan {
426*1cc017b7SChris Morgan 	regmap_update_bits(pdata->bq->regmap, BQ25703_CHARGE_OPTION_0,
427*1cc017b7SChris Morgan 			   BQ25703_EN_LWPWR, BQ25703_EN_LWPWR);
428*1cc017b7SChris Morgan }
429*1cc017b7SChris Morgan 
430*1cc017b7SChris Morgan static int bq257xx_set_charger_property(struct power_supply *psy,
431*1cc017b7SChris Morgan 		enum power_supply_property prop,
432*1cc017b7SChris Morgan 		const union power_supply_propval *val)
433*1cc017b7SChris Morgan {
434*1cc017b7SChris Morgan 	struct bq257xx_chg *pdata = power_supply_get_drvdata(psy);
435*1cc017b7SChris Morgan 
436*1cc017b7SChris Morgan 	switch (prop) {
437*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
438*1cc017b7SChris Morgan 		return pdata->chip->bq257xx_set_iindpm(pdata, val->intval);
439*1cc017b7SChris Morgan 
440*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
441*1cc017b7SChris Morgan 		return pdata->chip->bq257xx_set_vbatreg(pdata, val->intval);
442*1cc017b7SChris Morgan 
443*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
444*1cc017b7SChris Morgan 		return pdata->chip->bq257xx_set_ichg(pdata, val->intval);
445*1cc017b7SChris Morgan 
446*1cc017b7SChris Morgan 	default:
447*1cc017b7SChris Morgan 		break;
448*1cc017b7SChris Morgan 	}
449*1cc017b7SChris Morgan 
450*1cc017b7SChris Morgan 	return -EINVAL;
451*1cc017b7SChris Morgan }
452*1cc017b7SChris Morgan 
453*1cc017b7SChris Morgan static int bq257xx_get_charger_property(struct power_supply *psy,
454*1cc017b7SChris Morgan 				enum power_supply_property psp,
455*1cc017b7SChris Morgan 				union power_supply_propval *val)
456*1cc017b7SChris Morgan {
457*1cc017b7SChris Morgan 	struct bq257xx_chg *pdata = power_supply_get_drvdata(psy);
458*1cc017b7SChris Morgan 	int ret = 0;
459*1cc017b7SChris Morgan 
460*1cc017b7SChris Morgan 	ret = pdata->chip->bq257xx_get_state(pdata);
461*1cc017b7SChris Morgan 	if (ret)
462*1cc017b7SChris Morgan 		return ret;
463*1cc017b7SChris Morgan 
464*1cc017b7SChris Morgan 	switch (psp) {
465*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_STATUS:
466*1cc017b7SChris Morgan 		if (!pdata->online)
467*1cc017b7SChris Morgan 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
468*1cc017b7SChris Morgan 		else if (pdata->fast_charge || pdata->pre_charge)
469*1cc017b7SChris Morgan 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
470*1cc017b7SChris Morgan 		else
471*1cc017b7SChris Morgan 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
472*1cc017b7SChris Morgan 		break;
473*1cc017b7SChris Morgan 
474*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_HEALTH:
475*1cc017b7SChris Morgan 		if (pdata->ov_fault || pdata->batoc_fault)
476*1cc017b7SChris Morgan 			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
477*1cc017b7SChris Morgan 		else if (pdata->oc_fault)
478*1cc017b7SChris Morgan 			val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT;
479*1cc017b7SChris Morgan 		else
480*1cc017b7SChris Morgan 			val->intval = POWER_SUPPLY_HEALTH_GOOD;
481*1cc017b7SChris Morgan 		break;
482*1cc017b7SChris Morgan 
483*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_MANUFACTURER:
484*1cc017b7SChris Morgan 		val->strval = "Texas Instruments";
485*1cc017b7SChris Morgan 		break;
486*1cc017b7SChris Morgan 
487*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_ONLINE:
488*1cc017b7SChris Morgan 		val->intval = pdata->online;
489*1cc017b7SChris Morgan 		break;
490*1cc017b7SChris Morgan 
491*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
492*1cc017b7SChris Morgan 		return bq25703_get_iindpm(pdata, &val->intval);
493*1cc017b7SChris Morgan 
494*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
495*1cc017b7SChris Morgan 		return bq25703_get_chrg_volt(pdata, &val->intval);
496*1cc017b7SChris Morgan 
497*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_CURRENT_NOW:
498*1cc017b7SChris Morgan 		return bq25703_get_cur(pdata, &val->intval);
499*1cc017b7SChris Morgan 
500*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
501*1cc017b7SChris Morgan 		return bq25703_get_vbat(pdata, &val->intval);
502*1cc017b7SChris Morgan 
503*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
504*1cc017b7SChris Morgan 		return bq25703_get_ichg_cur(pdata, &val->intval);
505*1cc017b7SChris Morgan 
506*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
507*1cc017b7SChris Morgan 		return bq25703_get_min_vsys(pdata, &val->intval);
508*1cc017b7SChris Morgan 
509*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_USB_TYPE:
510*1cc017b7SChris Morgan 		val->intval = pdata->usb_type;
511*1cc017b7SChris Morgan 		break;
512*1cc017b7SChris Morgan 
513*1cc017b7SChris Morgan 	default:
514*1cc017b7SChris Morgan 		return -EINVAL;
515*1cc017b7SChris Morgan 	}
516*1cc017b7SChris Morgan 
517*1cc017b7SChris Morgan 	return ret;
518*1cc017b7SChris Morgan }
519*1cc017b7SChris Morgan 
520*1cc017b7SChris Morgan static enum power_supply_property bq257xx_power_supply_props[] = {
521*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_MANUFACTURER,
522*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_STATUS,
523*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_ONLINE,
524*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_HEALTH,
525*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
526*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_CURRENT_NOW,
527*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
528*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
529*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
530*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_VOLTAGE_MIN,
531*1cc017b7SChris Morgan 	POWER_SUPPLY_PROP_USB_TYPE,
532*1cc017b7SChris Morgan };
533*1cc017b7SChris Morgan 
534*1cc017b7SChris Morgan static int bq257xx_property_is_writeable(struct power_supply *psy,
535*1cc017b7SChris Morgan 					 enum power_supply_property prop)
536*1cc017b7SChris Morgan {
537*1cc017b7SChris Morgan 	switch (prop) {
538*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
539*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
540*1cc017b7SChris Morgan 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
541*1cc017b7SChris Morgan 		return true;
542*1cc017b7SChris Morgan 	default:
543*1cc017b7SChris Morgan 		return false;
544*1cc017b7SChris Morgan 	}
545*1cc017b7SChris Morgan }
546*1cc017b7SChris Morgan 
547*1cc017b7SChris Morgan /**
548*1cc017b7SChris Morgan  * bq257xx_external_power_changed() - Handler for external power change
549*1cc017b7SChris Morgan  * @psy: Power supply data
550*1cc017b7SChris Morgan  *
551*1cc017b7SChris Morgan  * When the external power into the charger is changed, check the USB
552*1cc017b7SChris Morgan  * type so that it can be reported. Additionally, update the max input
553*1cc017b7SChris Morgan  * current and max charging current to the value reported if it is a
554*1cc017b7SChris Morgan  * USB PD charger, otherwise use the default value. Note that each time
555*1cc017b7SChris Morgan  * a charger is removed the max charge current register is erased, so
556*1cc017b7SChris Morgan  * it must be set again each time the input changes or the device will
557*1cc017b7SChris Morgan  * not charge.
558*1cc017b7SChris Morgan  */
559*1cc017b7SChris Morgan static void bq257xx_external_power_changed(struct power_supply *psy)
560*1cc017b7SChris Morgan {
561*1cc017b7SChris Morgan 	struct bq257xx_chg *pdata = power_supply_get_drvdata(psy);
562*1cc017b7SChris Morgan 	union power_supply_propval val;
563*1cc017b7SChris Morgan 	int ret;
564*1cc017b7SChris Morgan 	int imax = pdata->iindpm_max;
565*1cc017b7SChris Morgan 
566*1cc017b7SChris Morgan 	pdata->chip->bq257xx_get_state(pdata);
567*1cc017b7SChris Morgan 
568*1cc017b7SChris Morgan 	pdata->supplied = power_supply_am_i_supplied(pdata->charger);
569*1cc017b7SChris Morgan 	if (pdata->supplied < 0)
570*1cc017b7SChris Morgan 		return;
571*1cc017b7SChris Morgan 
572*1cc017b7SChris Morgan 	if (pdata->supplied == 0)
573*1cc017b7SChris Morgan 		goto out;
574*1cc017b7SChris Morgan 
575*1cc017b7SChris Morgan 	ret = power_supply_get_property_from_supplier(psy,
576*1cc017b7SChris Morgan 						      POWER_SUPPLY_PROP_USB_TYPE,
577*1cc017b7SChris Morgan 						      &val);
578*1cc017b7SChris Morgan 	if (ret)
579*1cc017b7SChris Morgan 		return;
580*1cc017b7SChris Morgan 
581*1cc017b7SChris Morgan 	pdata->usb_type = val.intval;
582*1cc017b7SChris Morgan 
583*1cc017b7SChris Morgan 	if ((pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD) ||
584*1cc017b7SChris Morgan 	    (pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD_DRP) ||
585*1cc017b7SChris Morgan 	    (pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD_PPS)) {
586*1cc017b7SChris Morgan 		ret = power_supply_get_property_from_supplier(psy,
587*1cc017b7SChris Morgan 							      POWER_SUPPLY_PROP_CURRENT_MAX,
588*1cc017b7SChris Morgan 							      &val);
589*1cc017b7SChris Morgan 		if (ret)
590*1cc017b7SChris Morgan 			return;
591*1cc017b7SChris Morgan 
592*1cc017b7SChris Morgan 		if (val.intval)
593*1cc017b7SChris Morgan 			imax = val.intval;
594*1cc017b7SChris Morgan 	}
595*1cc017b7SChris Morgan 
596*1cc017b7SChris Morgan 	if (pdata->supplied) {
597*1cc017b7SChris Morgan 		pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max);
598*1cc017b7SChris Morgan 		pdata->chip->bq257xx_set_iindpm(pdata, imax);
599*1cc017b7SChris Morgan 		pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max);
600*1cc017b7SChris Morgan 	}
601*1cc017b7SChris Morgan 
602*1cc017b7SChris Morgan out:
603*1cc017b7SChris Morgan 	power_supply_changed(psy);
604*1cc017b7SChris Morgan }
605*1cc017b7SChris Morgan 
606*1cc017b7SChris Morgan static irqreturn_t bq257xx_irq_handler_thread(int irq, void *private)
607*1cc017b7SChris Morgan {
608*1cc017b7SChris Morgan 	struct bq257xx_chg *pdata = private;
609*1cc017b7SChris Morgan 
610*1cc017b7SChris Morgan 	bq257xx_external_power_changed(pdata->charger);
611*1cc017b7SChris Morgan 	return IRQ_HANDLED;
612*1cc017b7SChris Morgan }
613*1cc017b7SChris Morgan 
614*1cc017b7SChris Morgan static const struct power_supply_desc bq257xx_power_supply_desc = {
615*1cc017b7SChris Morgan 	.name = "bq257xx-charger",
616*1cc017b7SChris Morgan 	.type = POWER_SUPPLY_TYPE_USB,
617*1cc017b7SChris Morgan 	.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) |
618*1cc017b7SChris Morgan 		     BIT(POWER_SUPPLY_USB_TYPE_PD) |
619*1cc017b7SChris Morgan 		     BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) |
620*1cc017b7SChris Morgan 		     BIT(POWER_SUPPLY_USB_TYPE_PD_PPS) |
621*1cc017b7SChris Morgan 		     BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
622*1cc017b7SChris Morgan 	.properties = bq257xx_power_supply_props,
623*1cc017b7SChris Morgan 	.num_properties = ARRAY_SIZE(bq257xx_power_supply_props),
624*1cc017b7SChris Morgan 	.get_property = bq257xx_get_charger_property,
625*1cc017b7SChris Morgan 	.set_property = bq257xx_set_charger_property,
626*1cc017b7SChris Morgan 	.property_is_writeable = bq257xx_property_is_writeable,
627*1cc017b7SChris Morgan 	.external_power_changed = bq257xx_external_power_changed,
628*1cc017b7SChris Morgan };
629*1cc017b7SChris Morgan 
630*1cc017b7SChris Morgan static const struct bq257xx_chip_info bq25703_chip_info = {
631*1cc017b7SChris Morgan 		.bq257xx_hw_init = &bq25703_hw_init,
632*1cc017b7SChris Morgan 		.bq257xx_hw_shutdown = &bq25703_hw_shutdown,
633*1cc017b7SChris Morgan 		.bq257xx_get_state = &bq25703_get_state,
634*1cc017b7SChris Morgan 		.bq257xx_set_ichg = &bq25703_set_ichg_cur,
635*1cc017b7SChris Morgan 		.bq257xx_set_vbatreg = &bq25703_set_chrg_volt,
636*1cc017b7SChris Morgan 		.bq257xx_set_iindpm = &bq25703_set_iindpm,
637*1cc017b7SChris Morgan };
638*1cc017b7SChris Morgan 
639*1cc017b7SChris Morgan /**
640*1cc017b7SChris Morgan  * bq257xx_parse_dt() - Parse the device tree for required properties
641*1cc017b7SChris Morgan  * @pdata: driver platform data
642*1cc017b7SChris Morgan  * @psy_cfg: power supply config data
643*1cc017b7SChris Morgan  * @dev: device struct
644*1cc017b7SChris Morgan  *
645*1cc017b7SChris Morgan  * Read the device tree to identify the minimum system voltage, the
646*1cc017b7SChris Morgan  * maximum charge current, the maximum charge voltage, and the maximum
647*1cc017b7SChris Morgan  * input current.
648*1cc017b7SChris Morgan  *
649*1cc017b7SChris Morgan  * Return: Returns 0 on success or error code on error.
650*1cc017b7SChris Morgan  */
651*1cc017b7SChris Morgan static int bq257xx_parse_dt(struct bq257xx_chg *pdata,
652*1cc017b7SChris Morgan 		struct power_supply_config *psy_cfg, struct device *dev)
653*1cc017b7SChris Morgan {
654*1cc017b7SChris Morgan 	struct power_supply_battery_info *bat_info;
655*1cc017b7SChris Morgan 	int ret;
656*1cc017b7SChris Morgan 
657*1cc017b7SChris Morgan 	ret = power_supply_get_battery_info(pdata->charger,
658*1cc017b7SChris Morgan 					    &bat_info);
659*1cc017b7SChris Morgan 	if (ret)
660*1cc017b7SChris Morgan 		return dev_err_probe(dev, ret,
661*1cc017b7SChris Morgan 				     "Unable to get battery info\n");
662*1cc017b7SChris Morgan 
663*1cc017b7SChris Morgan 	if ((bat_info->voltage_min_design_uv <= 0) ||
664*1cc017b7SChris Morgan 	    (bat_info->constant_charge_voltage_max_uv <= 0) ||
665*1cc017b7SChris Morgan 	    (bat_info->constant_charge_current_max_ua <= 0))
666*1cc017b7SChris Morgan 		return dev_err_probe(dev, -EINVAL,
667*1cc017b7SChris Morgan 				     "Required bat info missing or invalid\n");
668*1cc017b7SChris Morgan 
669*1cc017b7SChris Morgan 	pdata->vsys_min = bat_info->voltage_min_design_uv;
670*1cc017b7SChris Morgan 	pdata->vbat_max = bat_info->constant_charge_voltage_max_uv;
671*1cc017b7SChris Morgan 	pdata->ichg_max = bat_info->constant_charge_current_max_ua;
672*1cc017b7SChris Morgan 
673*1cc017b7SChris Morgan 	power_supply_put_battery_info(pdata->charger, bat_info);
674*1cc017b7SChris Morgan 
675*1cc017b7SChris Morgan 	ret = device_property_read_u32(dev,
676*1cc017b7SChris Morgan 				       "input-current-limit-microamp",
677*1cc017b7SChris Morgan 				       &pdata->iindpm_max);
678*1cc017b7SChris Morgan 	if (ret)
679*1cc017b7SChris Morgan 		pdata->iindpm_max = BQ25703_IINDPM_DEFAULT_UA;
680*1cc017b7SChris Morgan 
681*1cc017b7SChris Morgan 	return 0;
682*1cc017b7SChris Morgan }
683*1cc017b7SChris Morgan 
684*1cc017b7SChris Morgan static int bq257xx_charger_probe(struct platform_device *pdev)
685*1cc017b7SChris Morgan {
686*1cc017b7SChris Morgan 	struct device *dev = &pdev->dev;
687*1cc017b7SChris Morgan 	struct bq257xx_device *bq = dev_get_drvdata(pdev->dev.parent);
688*1cc017b7SChris Morgan 	struct bq257xx_chg *pdata;
689*1cc017b7SChris Morgan 	struct power_supply_config psy_cfg = { };
690*1cc017b7SChris Morgan 	int ret;
691*1cc017b7SChris Morgan 
692*1cc017b7SChris Morgan 	device_set_of_node_from_dev(dev, pdev->dev.parent);
693*1cc017b7SChris Morgan 
694*1cc017b7SChris Morgan 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
695*1cc017b7SChris Morgan 	if (!pdata)
696*1cc017b7SChris Morgan 		return -ENOMEM;
697*1cc017b7SChris Morgan 
698*1cc017b7SChris Morgan 	pdata->bq = bq;
699*1cc017b7SChris Morgan 	pdata->chip = &bq25703_chip_info;
700*1cc017b7SChris Morgan 
701*1cc017b7SChris Morgan 	platform_set_drvdata(pdev, pdata);
702*1cc017b7SChris Morgan 
703*1cc017b7SChris Morgan 	psy_cfg.drv_data = pdata;
704*1cc017b7SChris Morgan 	psy_cfg.fwnode = dev_fwnode(dev);
705*1cc017b7SChris Morgan 
706*1cc017b7SChris Morgan 	pdata->charger = devm_power_supply_register(dev,
707*1cc017b7SChris Morgan 						    &bq257xx_power_supply_desc,
708*1cc017b7SChris Morgan 						    &psy_cfg);
709*1cc017b7SChris Morgan 	if (IS_ERR(pdata->charger))
710*1cc017b7SChris Morgan 		return dev_err_probe(dev, PTR_ERR(pdata->charger),
711*1cc017b7SChris Morgan 				     "Power supply register charger failed\n");
712*1cc017b7SChris Morgan 
713*1cc017b7SChris Morgan 	ret = bq257xx_parse_dt(pdata, &psy_cfg, dev);
714*1cc017b7SChris Morgan 	if (ret)
715*1cc017b7SChris Morgan 		return ret;
716*1cc017b7SChris Morgan 
717*1cc017b7SChris Morgan 	ret = pdata->chip->bq257xx_hw_init(pdata);
718*1cc017b7SChris Morgan 	if (ret)
719*1cc017b7SChris Morgan 		return dev_err_probe(dev, ret, "Cannot initialize the charger\n");
720*1cc017b7SChris Morgan 
721*1cc017b7SChris Morgan 	platform_set_drvdata(pdev, pdata);
722*1cc017b7SChris Morgan 
723*1cc017b7SChris Morgan 	if (bq->client->irq) {
724*1cc017b7SChris Morgan 		ret = devm_request_threaded_irq(dev, bq->client->irq, NULL,
725*1cc017b7SChris Morgan 						bq257xx_irq_handler_thread,
726*1cc017b7SChris Morgan 						IRQF_TRIGGER_RISING |
727*1cc017b7SChris Morgan 						IRQF_TRIGGER_FALLING |
728*1cc017b7SChris Morgan 						IRQF_ONESHOT,
729*1cc017b7SChris Morgan 						dev_name(&bq->client->dev), pdata);
730*1cc017b7SChris Morgan 		if (ret < 0)
731*1cc017b7SChris Morgan 			dev_err_probe(dev, ret, "Charger get irq failed\n");
732*1cc017b7SChris Morgan 	}
733*1cc017b7SChris Morgan 
734*1cc017b7SChris Morgan 	return ret;
735*1cc017b7SChris Morgan }
736*1cc017b7SChris Morgan 
737*1cc017b7SChris Morgan static void bq257xx_charger_shutdown(struct platform_device *pdev)
738*1cc017b7SChris Morgan {
739*1cc017b7SChris Morgan 	struct bq257xx_chg *pdata = platform_get_drvdata(pdev);
740*1cc017b7SChris Morgan 
741*1cc017b7SChris Morgan 	pdata->chip->bq257xx_hw_shutdown(pdata);
742*1cc017b7SChris Morgan }
743*1cc017b7SChris Morgan 
744*1cc017b7SChris Morgan static struct platform_driver bq257xx_chg_driver = {
745*1cc017b7SChris Morgan 	.driver = {
746*1cc017b7SChris Morgan 		.name = "bq257xx-charger",
747*1cc017b7SChris Morgan 	},
748*1cc017b7SChris Morgan 	.probe = bq257xx_charger_probe,
749*1cc017b7SChris Morgan 	.shutdown = bq257xx_charger_shutdown,
750*1cc017b7SChris Morgan };
751*1cc017b7SChris Morgan module_platform_driver(bq257xx_chg_driver);
752*1cc017b7SChris Morgan 
753*1cc017b7SChris Morgan MODULE_DESCRIPTION("bq257xx charger driver");
754*1cc017b7SChris Morgan MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>");
755*1cc017b7SChris Morgan MODULE_LICENSE("GPL");
756