xref: /rk3399_rockchip-uboot/drivers/power/charge/cps5601x_charger.c (revision eb1192571a2b484fac8c2800cbb59ca145637fa2)
1*eb119257SChen Shunqing /*
2*eb119257SChen Shunqing  * (C) Copyright 2025 Rockchip Electronics Co., Ltd
3*eb119257SChen Shunqing  *
4*eb119257SChen Shunqing  * SPDX-License-Identifier:	GPL-2.0+
5*eb119257SChen Shunqing  */
6*eb119257SChen Shunqing 
7*eb119257SChen Shunqing #include <common.h>
8*eb119257SChen Shunqing #include <dm.h>
9*eb119257SChen Shunqing #include <i2c.h>
10*eb119257SChen Shunqing #include <irq-generic.h>
11*eb119257SChen Shunqing #include <power/fuel_gauge.h>
12*eb119257SChen Shunqing #include <linux/usb/phy-rockchip-usb2.h>
13*eb119257SChen Shunqing #include <power/power_delivery/power_delivery.h>
14*eb119257SChen Shunqing 
15*eb119257SChen Shunqing DECLARE_GLOBAL_DATA_PTR;
16*eb119257SChen Shunqing 
17*eb119257SChen Shunqing static int dbg_enable;
18*eb119257SChen Shunqing 
19*eb119257SChen Shunqing #define CPS_DBG(args...) \
20*eb119257SChen Shunqing 	do { \
21*eb119257SChen Shunqing 		if (dbg_enable) { \
22*eb119257SChen Shunqing 			printf(args); \
23*eb119257SChen Shunqing 		} \
24*eb119257SChen Shunqing 	} while (0)
25*eb119257SChen Shunqing 
26*eb119257SChen Shunqing #define UPDATE(x, h, l)			(((x) << (l)) & GENMASK((h), (l)))
27*eb119257SChen Shunqing 
28*eb119257SChen Shunqing /* Register 00h */
29*eb119257SChen Shunqing #define CPS5601X_REG_00			0x00
30*eb119257SChen Shunqing #define CPS5601X_PRODUCT_ID_MASK	GENMASK(7, 0)
31*eb119257SChen Shunqing /* default 0xA9=CPS5601 */
32*eb119257SChen Shunqing 
33*eb119257SChen Shunqing /* Register 01h */
34*eb119257SChen Shunqing #define CPS5601X_REG_01			0x01
35*eb119257SChen Shunqing 
36*eb119257SChen Shunqing /* Register 02h */
37*eb119257SChen Shunqing #define CPS5601X_REG_02			0x02
38*eb119257SChen Shunqing 
39*eb119257SChen Shunqing /* Register 03h */
40*eb119257SChen Shunqing #define CPS5601X_REG_03			0x03
41*eb119257SChen Shunqing #define VREG_MASK			GENMASK(6, 0)
42*eb119257SChen Shunqing #define VREG_BASE			3600000
43*eb119257SChen Shunqing #define VREG_LSB			10000
44*eb119257SChen Shunqing #define VREG_MAXVAL			0x6e
45*eb119257SChen Shunqing 
46*eb119257SChen Shunqing /* Register 04h */
47*eb119257SChen Shunqing #define CPS5601X_REG_04			0x04
48*eb119257SChen Shunqing #define ICHG_MASK			GENMASK(6, 0)
49*eb119257SChen Shunqing #define ICHG_BASE			0
50*eb119257SChen Shunqing #define ICHG_LSB			25000
51*eb119257SChen Shunqing #define ICHG_MINVAL			0x4
52*eb119257SChen Shunqing #define ICHG_MAXVAL			0x78
53*eb119257SChen Shunqing 
54*eb119257SChen Shunqing /* Register 05h */
55*eb119257SChen Shunqing #define CPS5601X_REG_05			0x05
56*eb119257SChen Shunqing #define EN_TERM_MASK			BIT(6)
57*eb119257SChen Shunqing #define EN_TERM_ENABLE(x)		UPDATE(x, 6, 6)
58*eb119257SChen Shunqing #define IPRECHG_MASK			GENMASK(5, 0)
59*eb119257SChen Shunqing #define IPRECHG_BASE			0
60*eb119257SChen Shunqing #define IPRECHG_LSB			12500
61*eb119257SChen Shunqing #define IPRECHG_MINVAL			0x1
62*eb119257SChen Shunqing #define IPRECHG_MAXVAL			0x3c
63*eb119257SChen Shunqing 
64*eb119257SChen Shunqing /* Register 06h */
65*eb119257SChen Shunqing #define CPS5601X_REG_06			0x06
66*eb119257SChen Shunqing #define ITERM_MASK			GENMASK(5, 0)
67*eb119257SChen Shunqing #define ITERM_BASE			0
68*eb119257SChen Shunqing #define ITERM_LSB			10000
69*eb119257SChen Shunqing #define ITERM_MINVAL			0x5
70*eb119257SChen Shunqing #define ITERM_MAXVAL			0x3c
71*eb119257SChen Shunqing 
72*eb119257SChen Shunqing /* Register 07h */
73*eb119257SChen Shunqing #define CPS5601X_REG_07			0x07
74*eb119257SChen Shunqing #define VINDPM_MASK			GENMASK(5, 0)
75*eb119257SChen Shunqing #define VINDPM_BASE			3400000
76*eb119257SChen Shunqing #define VINDPM_LSB			100000
77*eb119257SChen Shunqing #define VINDPM_MINVAL			0x4
78*eb119257SChen Shunqing #define VINDPM_MAXVAL			0x3e
79*eb119257SChen Shunqing 
80*eb119257SChen Shunqing /* Register 08h */
81*eb119257SChen Shunqing #define CPS5601X_REG_08			0x08
82*eb119257SChen Shunqing #define IINDPM_MASK			GENMASK(5, 0)
83*eb119257SChen Shunqing #define IINDPM_BASE			50000
84*eb119257SChen Shunqing #define IINDPM_LSB			50000
85*eb119257SChen Shunqing #define IINDPM_MINVAL			0x1
86*eb119257SChen Shunqing 
87*eb119257SChen Shunqing /* Register 09h */
88*eb119257SChen Shunqing #define CPS5601X_REG_09			0x09
89*eb119257SChen Shunqing #define VOTG_MASK			GENMASK(5, 0)
90*eb119257SChen Shunqing #define VOTG_BASE			3400000
91*eb119257SChen Shunqing #define VOTG_LSB			100000
92*eb119257SChen Shunqing #define VOTG_MAXVAL			0x3e
93*eb119257SChen Shunqing 
94*eb119257SChen Shunqing /* Register 0Ah */
95*eb119257SChen Shunqing #define CPS5601X_REG_0A			0x0A
96*eb119257SChen Shunqing #define IOTG_MASK			GENMASK(5, 0)
97*eb119257SChen Shunqing #define IOTG_BASE			50000
98*eb119257SChen Shunqing #define IOTG_LSB			50000
99*eb119257SChen Shunqing #define IOTG_MINVAL			0x1
100*eb119257SChen Shunqing 
101*eb119257SChen Shunqing /* Register 0Bh */
102*eb119257SChen Shunqing #define CPS5601X_REG_0B			0x0B
103*eb119257SChen Shunqing #define WATCHDOG_MASK			GENMASK(7, 6)
104*eb119257SChen Shunqing #define WATCHDOG_TIME(x)		UPDATE(x, 7, 6)
105*eb119257SChen Shunqing #define WATCHDOG_BASE			0
106*eb119257SChen Shunqing #define WATCHDOG_LSB			40
107*eb119257SChen Shunqing #define WD_RST_MASK			BIT(5)
108*eb119257SChen Shunqing #define WD_RST(x)			UPDATE(x, 5, 5)
109*eb119257SChen Shunqing #define EN_CHG_MASK			BIT(3)
110*eb119257SChen Shunqing #define EN_CHG(x)			UPDATE(x, 3, 3)
111*eb119257SChen Shunqing 
112*eb119257SChen Shunqing /* Register 0Ch */
113*eb119257SChen Shunqing #define CPS5601X_REG_0C			0x0C
114*eb119257SChen Shunqing #define EN_OTG_MASK			BIT(3)
115*eb119257SChen Shunqing #define EN_OTG(x)			UPDATE(x, 3, 3)
116*eb119257SChen Shunqing 
117*eb119257SChen Shunqing /* Register 0Dh */
118*eb119257SChen Shunqing #define CPS5601X_REG_0D			0x0D
119*eb119257SChen Shunqing 
120*eb119257SChen Shunqing /* Register 0Eh */
121*eb119257SChen Shunqing #define CPS5601X_REG_0E			0x0E
122*eb119257SChen Shunqing #define TS_IGNORE_MASK			BIT(0)
123*eb119257SChen Shunqing #define EN_TS_IGNORE(x)			UPDATE(x, 0, 0)
124*eb119257SChen Shunqing 
125*eb119257SChen Shunqing /* Register 0Fh */
126*eb119257SChen Shunqing #define CPS5601X_REG_0F			0x0F
127*eb119257SChen Shunqing #define PG_STAT_MASK			BIT(3)
128*eb119257SChen Shunqing 
129*eb119257SChen Shunqing /* Register 10h */
130*eb119257SChen Shunqing #define CPS5601X_REG_10			0x10
131*eb119257SChen Shunqing #define CHG_STAT_MASK			GENMASK(7, 5)
132*eb119257SChen Shunqing #define CHG_STAT_SHIFT			5
133*eb119257SChen Shunqing #define CHG_STAT_NOTCHG			0
134*eb119257SChen Shunqing #define CHG_STAT_TRICKLECHG		1
135*eb119257SChen Shunqing #define CHG_STAT_PRECHG			2
136*eb119257SChen Shunqing #define CHG_STAT_FASTCHG		3
137*eb119257SChen Shunqing #define CHG_STAT_TAPERCHG		4
138*eb119257SChen Shunqing #define CHG_STAT_RESERVED		5
139*eb119257SChen Shunqing #define CHG_STAT_TOTACHG		6
140*eb119257SChen Shunqing #define CHG_STAT_CHGTERM		7
141*eb119257SChen Shunqing #define VBUS_STAT_MASK			GENMASK(4, 1)
142*eb119257SChen Shunqing #define VBUS_STAT_SHIFT			1
143*eb119257SChen Shunqing #define VBUS_STAT_NOT			0
144*eb119257SChen Shunqing #define VBUS_STAT_USBSDP		1
145*eb119257SChen Shunqing #define VBUS_STAT_USBCDP		2
146*eb119257SChen Shunqing #define VBUS_STAT_USBDCP		3
147*eb119257SChen Shunqing #define VBUS_STAT_HVDCP			4
148*eb119257SChen Shunqing #define VBUS_STAT_UNKNOWN		5
149*eb119257SChen Shunqing #define VBUS_STAT_NONSTANDARD		6
150*eb119257SChen Shunqing #define VBUS_STAT_OTGMODE		7
151*eb119257SChen Shunqing #define VBUS_STAT_NOTQUALIFIED		8
152*eb119257SChen Shunqing 
153*eb119257SChen Shunqing /* Register 11h */
154*eb119257SChen Shunqing #define CPS5601X_REG_11			0x11
155*eb119257SChen Shunqing 
156*eb119257SChen Shunqing /* Register 12h */
157*eb119257SChen Shunqing #define CPS5601X_REG_12			0x12
158*eb119257SChen Shunqing 
159*eb119257SChen Shunqing /* Register 13h */
160*eb119257SChen Shunqing #define CPS5601X_REG_13			0x13
161*eb119257SChen Shunqing 
162*eb119257SChen Shunqing /* Register 14h */
163*eb119257SChen Shunqing #define CPS5601X_REG_14			0x14
164*eb119257SChen Shunqing 
165*eb119257SChen Shunqing /* Register 15h */
166*eb119257SChen Shunqing #define CPS5601X_REG_15			0x15
167*eb119257SChen Shunqing 
168*eb119257SChen Shunqing /* Register 16h */
169*eb119257SChen Shunqing #define CPS5601X_REG_16			0x16
170*eb119257SChen Shunqing 
171*eb119257SChen Shunqing /* Register 17h */
172*eb119257SChen Shunqing #define CPS5601X_REG_17			0x17
173*eb119257SChen Shunqing 
174*eb119257SChen Shunqing /* Register 18h */
175*eb119257SChen Shunqing #define CPS5601X_REG_18			0x18
176*eb119257SChen Shunqing 
177*eb119257SChen Shunqing /* Register 19h */
178*eb119257SChen Shunqing #define CPS5601X_REG_19			0x19
179*eb119257SChen Shunqing #define TREG_MK_MASK			BIT(7)
180*eb119257SChen Shunqing 
181*eb119257SChen Shunqing /* Register 1Ah */
182*eb119257SChen Shunqing #define CPS5601X_REG_1A			0x1A
183*eb119257SChen Shunqing 
184*eb119257SChen Shunqing /* Register 1Bh */
185*eb119257SChen Shunqing #define CPS5601X_REG_1B			0x1B
186*eb119257SChen Shunqing 
187*eb119257SChen Shunqing #define CPS5601X_ICHRG_I_DEF_uA		2040000
188*eb119257SChen Shunqing #define CPS5601X_VREG_V_DEF_uV		4208000
189*eb119257SChen Shunqing #define CPS5601X_PRECHRG_I_DEF_uA	180000
190*eb119257SChen Shunqing #define CPS5601X_TERMCHRG_I_DEF_uA	180000
191*eb119257SChen Shunqing #define CPS5601X_ICHRG_I_MIN_uA		100000
192*eb119257SChen Shunqing #define CPS5601X_ICHRG_I_MAX_uA		3000000
193*eb119257SChen Shunqing #define CPS5601X_VINDPM_DEF_uV		4500000
194*eb119257SChen Shunqing #define CPS5601X_VINDPM_V_MIN_uV	3800000
195*eb119257SChen Shunqing #define CPS5601X_VINDPM_V_MAX_uV	9600000
196*eb119257SChen Shunqing #define CPS5601X_IINDPM_DEF_uA		2400000
197*eb119257SChen Shunqing #define CPS5601X_IINDPM_I_MIN_uA	100000
198*eb119257SChen Shunqing #define CPS5601X_IINDPM_I_MAX_uA	3200000
199*eb119257SChen Shunqing #define DEFAULT_INPUT_CURRENT		(500 * 1000)
200*eb119257SChen Shunqing 
201*eb119257SChen Shunqing struct cps5601x {
202*eb119257SChen Shunqing 	struct udevice *dev;
203*eb119257SChen Shunqing 	struct udevice *pd;
204*eb119257SChen Shunqing 	bool pd_online;
205*eb119257SChen Shunqing 	u32 init_count;
206*eb119257SChen Shunqing 	u32 ichg;
207*eb119257SChen Shunqing 	u32 vchg;
208*eb119257SChen Shunqing 	int irq;
209*eb119257SChen Shunqing };
210*eb119257SChen Shunqing 
211*eb119257SChen Shunqing enum power_supply_type {
212*eb119257SChen Shunqing 	POWER_SUPPLY_TYPE_UNKNOWN = 0,
213*eb119257SChen Shunqing 	POWER_SUPPLY_TYPE_USB,          /* Standard Downstream Port */
214*eb119257SChen Shunqing 	POWER_SUPPLY_TYPE_USB_DCP,      /* Dedicated Charging Port */
215*eb119257SChen Shunqing 	POWER_SUPPLY_TYPE_USB_CDP,      /* Charging Downstream Port */
216*eb119257SChen Shunqing 	POWER_SUPPLY_TYPE_USB_FLOATING, /* DCP without shorting D+/D- */
217*eb119257SChen Shunqing };
218*eb119257SChen Shunqing 
cps5601x_read(struct cps5601x * charger,uint reg,u8 * buffer)219*eb119257SChen Shunqing static int cps5601x_read(struct cps5601x *charger, uint reg, u8 *buffer)
220*eb119257SChen Shunqing {
221*eb119257SChen Shunqing 	u8 val;
222*eb119257SChen Shunqing 	int ret;
223*eb119257SChen Shunqing 
224*eb119257SChen Shunqing 	ret = dm_i2c_read(charger->dev, reg, &val, 1);
225*eb119257SChen Shunqing 	if (ret) {
226*eb119257SChen Shunqing 		printf("cps5601x: read %#x error, ret=%d", reg, ret);
227*eb119257SChen Shunqing 		return ret;
228*eb119257SChen Shunqing 	}
229*eb119257SChen Shunqing 
230*eb119257SChen Shunqing 	*buffer = val;
231*eb119257SChen Shunqing 
232*eb119257SChen Shunqing 	return 0;
233*eb119257SChen Shunqing }
234*eb119257SChen Shunqing 
cps5601x_write(struct cps5601x * charger,uint reg,u8 val)235*eb119257SChen Shunqing static int cps5601x_write(struct cps5601x *charger, uint reg, u8 val)
236*eb119257SChen Shunqing {
237*eb119257SChen Shunqing 	int ret;
238*eb119257SChen Shunqing 
239*eb119257SChen Shunqing 	ret = dm_i2c_write(charger->dev, reg, &val, 1);
240*eb119257SChen Shunqing 	if (ret)
241*eb119257SChen Shunqing 		printf("cps5601x: write %#x error, ret=%d", reg, ret);
242*eb119257SChen Shunqing 
243*eb119257SChen Shunqing 	return ret;
244*eb119257SChen Shunqing }
245*eb119257SChen Shunqing 
cps5601x_update_bits(struct cps5601x * charger,u8 offset,u8 mask,u8 val)246*eb119257SChen Shunqing static int cps5601x_update_bits(struct cps5601x *charger,
247*eb119257SChen Shunqing 				u8 offset,
248*eb119257SChen Shunqing 				u8 mask,
249*eb119257SChen Shunqing 				u8 val)
250*eb119257SChen Shunqing {
251*eb119257SChen Shunqing 	u8 reg;
252*eb119257SChen Shunqing 	int ret;
253*eb119257SChen Shunqing 
254*eb119257SChen Shunqing 	ret = cps5601x_read(charger, offset, &reg);
255*eb119257SChen Shunqing 	if (ret)
256*eb119257SChen Shunqing 		return ret;
257*eb119257SChen Shunqing 
258*eb119257SChen Shunqing 	reg &= ~mask;
259*eb119257SChen Shunqing 
260*eb119257SChen Shunqing 	return cps5601x_write(charger, offset, reg | val);
261*eb119257SChen Shunqing }
262*eb119257SChen Shunqing 
cps5601x_set_input_current_limit(struct cps5601x * cps,int curr)263*eb119257SChen Shunqing static int cps5601x_set_input_current_limit(struct cps5601x *cps, int curr)
264*eb119257SChen Shunqing {
265*eb119257SChen Shunqing 	u8 val;
266*eb119257SChen Shunqing 
267*eb119257SChen Shunqing 	if (curr < IINDPM_BASE + (IINDPM_MINVAL * IINDPM_LSB))
268*eb119257SChen Shunqing 		curr = IINDPM_BASE + (IINDPM_MINVAL * IINDPM_LSB);
269*eb119257SChen Shunqing 
270*eb119257SChen Shunqing 	val = (curr - IINDPM_BASE) / IINDPM_LSB;
271*eb119257SChen Shunqing 
272*eb119257SChen Shunqing 	return cps5601x_update_bits(cps, CPS5601X_REG_08, IINDPM_MASK, val);
273*eb119257SChen Shunqing }
274*eb119257SChen Shunqing 
cps5601x_get_usb_type(void)275*eb119257SChen Shunqing static int cps5601x_get_usb_type(void)
276*eb119257SChen Shunqing {
277*eb119257SChen Shunqing #ifdef CONFIG_PHY_ROCKCHIP_INNO_USB2
278*eb119257SChen Shunqing 	return rockchip_chg_get_type();
279*eb119257SChen Shunqing #else
280*eb119257SChen Shunqing 	return 0;
281*eb119257SChen Shunqing #endif
282*eb119257SChen Shunqing }
283*eb119257SChen Shunqing 
cps5601x_charger_capability(struct udevice * dev)284*eb119257SChen Shunqing static int cps5601x_charger_capability(struct udevice *dev)
285*eb119257SChen Shunqing {
286*eb119257SChen Shunqing 	return FG_CAP_CHARGER;
287*eb119257SChen Shunqing }
288*eb119257SChen Shunqing 
cps5601x_set_chargecurrent(struct cps5601x * cps,int curr)289*eb119257SChen Shunqing static int cps5601x_set_chargecurrent(struct cps5601x *cps, int curr)
290*eb119257SChen Shunqing {
291*eb119257SChen Shunqing 	u8 ichg;
292*eb119257SChen Shunqing 
293*eb119257SChen Shunqing 	if (curr < (ICHG_BASE + (ICHG_MINVAL * ICHG_LSB)))
294*eb119257SChen Shunqing 		curr = ICHG_BASE + (ICHG_MINVAL * ICHG_LSB);
295*eb119257SChen Shunqing 	else if (curr > (ICHG_BASE + (ICHG_MAXVAL * ICHG_LSB)))
296*eb119257SChen Shunqing 		curr = ICHG_BASE + (ICHG_MAXVAL * ICHG_LSB);
297*eb119257SChen Shunqing 
298*eb119257SChen Shunqing 	ichg = (curr - ICHG_BASE) / ICHG_LSB;
299*eb119257SChen Shunqing 
300*eb119257SChen Shunqing 	return cps5601x_update_bits(cps, CPS5601X_REG_04, ICHG_MASK, ichg);
301*eb119257SChen Shunqing }
302*eb119257SChen Shunqing 
cps5601x_set_iprechg(struct cps5601x * cps,int curr)303*eb119257SChen Shunqing static int cps5601x_set_iprechg(struct cps5601x *cps, int curr)
304*eb119257SChen Shunqing {
305*eb119257SChen Shunqing 	u8 iprechg;
306*eb119257SChen Shunqing 
307*eb119257SChen Shunqing 	if (curr < (IPRECHG_BASE + (IPRECHG_MINVAL * IPRECHG_LSB)))
308*eb119257SChen Shunqing 		curr = IPRECHG_BASE + (IPRECHG_MINVAL * IPRECHG_LSB);
309*eb119257SChen Shunqing 	else if (curr > (IPRECHG_BASE + (IPRECHG_MAXVAL * IPRECHG_LSB)))
310*eb119257SChen Shunqing 		curr = IPRECHG_BASE + (IPRECHG_MAXVAL * IPRECHG_LSB);
311*eb119257SChen Shunqing 
312*eb119257SChen Shunqing 	iprechg = (curr - IPRECHG_BASE) / IPRECHG_LSB;
313*eb119257SChen Shunqing 
314*eb119257SChen Shunqing 	return cps5601x_update_bits(cps, CPS5601X_REG_05, IPRECHG_MASK,
315*eb119257SChen Shunqing 				    iprechg);
316*eb119257SChen Shunqing }
317*eb119257SChen Shunqing 
cps5601x_set_chargevolt(struct cps5601x * cps,int volt)318*eb119257SChen Shunqing static int cps5601x_set_chargevolt(struct cps5601x *cps, int volt)
319*eb119257SChen Shunqing {
320*eb119257SChen Shunqing 	u8 val;
321*eb119257SChen Shunqing 
322*eb119257SChen Shunqing 	if (volt < VREG_BASE)
323*eb119257SChen Shunqing 		volt = VREG_BASE;
324*eb119257SChen Shunqing 	else if (volt > (VREG_BASE + (VREG_MAXVAL * VREG_LSB)))
325*eb119257SChen Shunqing 		volt = VREG_BASE + (VREG_MAXVAL * VREG_LSB);
326*eb119257SChen Shunqing 
327*eb119257SChen Shunqing 	val = (volt - VREG_BASE) / VREG_LSB;
328*eb119257SChen Shunqing 
329*eb119257SChen Shunqing 	return cps5601x_update_bits(cps, CPS5601X_REG_03, VREG_MASK, val);
330*eb119257SChen Shunqing }
331*eb119257SChen Shunqing 
cps5601x_set_charger_voltage(struct udevice * dev,int uV)332*eb119257SChen Shunqing static int cps5601x_set_charger_voltage(struct udevice *dev, int uV)
333*eb119257SChen Shunqing {
334*eb119257SChen Shunqing 	struct cps5601x *charger = dev_get_priv(dev);
335*eb119257SChen Shunqing 
336*eb119257SChen Shunqing 	CPS_DBG("CPS5601X: charger voltage %d\n", uV);
337*eb119257SChen Shunqing 	return cps5601x_set_chargevolt(charger, uV);
338*eb119257SChen Shunqing }
339*eb119257SChen Shunqing 
cps5601x_charger_enable(struct udevice * dev)340*eb119257SChen Shunqing static int cps5601x_charger_enable(struct udevice *dev)
341*eb119257SChen Shunqing {
342*eb119257SChen Shunqing 	struct cps5601x *charger = dev_get_priv(dev);
343*eb119257SChen Shunqing 
344*eb119257SChen Shunqing 	CPS_DBG("CPS5601X: charger enable\n");
345*eb119257SChen Shunqing 	return cps5601x_update_bits(charger, CPS5601X_REG_0B, EN_CHG_MASK,
346*eb119257SChen Shunqing 				    EN_CHG(1));
347*eb119257SChen Shunqing }
348*eb119257SChen Shunqing 
cps5601x_charger_disable(struct udevice * dev)349*eb119257SChen Shunqing static int cps5601x_charger_disable(struct udevice *dev)
350*eb119257SChen Shunqing {
351*eb119257SChen Shunqing 	struct cps5601x *charger = dev_get_priv(dev);
352*eb119257SChen Shunqing 
353*eb119257SChen Shunqing 	CPS_DBG("CPS5601X: charger disable\n");
354*eb119257SChen Shunqing 	return cps5601x_update_bits(charger, CPS5601X_REG_0B, EN_CHG_MASK,
355*eb119257SChen Shunqing 				    EN_CHG(0));
356*eb119257SChen Shunqing }
357*eb119257SChen Shunqing 
cps5601x_iprechg_current(struct udevice * dev,int iprechrg_uA)358*eb119257SChen Shunqing static int cps5601x_iprechg_current(struct udevice *dev, int iprechrg_uA)
359*eb119257SChen Shunqing {
360*eb119257SChen Shunqing 	struct cps5601x *charger = dev_get_priv(dev);
361*eb119257SChen Shunqing 
362*eb119257SChen Shunqing 	CPS_DBG("CPS5601x: charger current:iprechrg_uA: %d\n",
363*eb119257SChen Shunqing 		iprechrg_uA);
364*eb119257SChen Shunqing 
365*eb119257SChen Shunqing 	return cps5601x_set_iprechg(charger, iprechrg_uA);
366*eb119257SChen Shunqing }
367*eb119257SChen Shunqing 
cps5601x_charger_current(struct udevice * dev,int ichrg_uA)368*eb119257SChen Shunqing static int cps5601x_charger_current(struct udevice *dev, int ichrg_uA)
369*eb119257SChen Shunqing {
370*eb119257SChen Shunqing 	struct cps5601x *charger = dev_get_priv(dev);
371*eb119257SChen Shunqing 
372*eb119257SChen Shunqing 	CPS_DBG("CPS5601X: charger current:ichrg_uA%d\n",
373*eb119257SChen Shunqing 		ichrg_uA);
374*eb119257SChen Shunqing 
375*eb119257SChen Shunqing 	return cps5601x_set_chargecurrent(charger, ichrg_uA);
376*eb119257SChen Shunqing }
377*eb119257SChen Shunqing 
cps5601x_get_pd_output_val(struct cps5601x * charger,int * vol,int * cur)378*eb119257SChen Shunqing static int cps5601x_get_pd_output_val(struct cps5601x *charger,
379*eb119257SChen Shunqing 				      int *vol,
380*eb119257SChen Shunqing 				      int *cur)
381*eb119257SChen Shunqing {
382*eb119257SChen Shunqing 	struct power_delivery_data pd_data;
383*eb119257SChen Shunqing 	int ret;
384*eb119257SChen Shunqing 
385*eb119257SChen Shunqing 	if (!charger->pd)
386*eb119257SChen Shunqing 		return -EINVAL;
387*eb119257SChen Shunqing 
388*eb119257SChen Shunqing 	memset(&pd_data, 0, sizeof(pd_data));
389*eb119257SChen Shunqing 	ret = power_delivery_get_data(charger->pd, &pd_data);
390*eb119257SChen Shunqing 	if (ret)
391*eb119257SChen Shunqing 		return ret;
392*eb119257SChen Shunqing 	if (!pd_data.online || !pd_data.voltage || !pd_data.current)
393*eb119257SChen Shunqing 		return -EINVAL;
394*eb119257SChen Shunqing 
395*eb119257SChen Shunqing 	*vol = pd_data.voltage;
396*eb119257SChen Shunqing 	*cur = pd_data.current;
397*eb119257SChen Shunqing 	charger->pd_online = pd_data.online;
398*eb119257SChen Shunqing 
399*eb119257SChen Shunqing 	return 0;
400*eb119257SChen Shunqing }
401*eb119257SChen Shunqing 
cps5601x_charger_input_current_init(struct cps5601x * charger)402*eb119257SChen Shunqing static void cps5601x_charger_input_current_init(struct cps5601x *charger)
403*eb119257SChen Shunqing {
404*eb119257SChen Shunqing 	int sdp_inputcurrent = 500 * 1000;
405*eb119257SChen Shunqing 	int dcp_inputcurrent = 2000 * 1000;
406*eb119257SChen Shunqing 	int pd_inputvol, pd_inputcurrent;
407*eb119257SChen Shunqing 	int ret;
408*eb119257SChen Shunqing 
409*eb119257SChen Shunqing 	if (!charger->pd) {
410*eb119257SChen Shunqing 		ret = uclass_get_device(UCLASS_PD, 0, &charger->pd);
411*eb119257SChen Shunqing 		if (ret) {
412*eb119257SChen Shunqing 			if (ret == -ENODEV)
413*eb119257SChen Shunqing 				printf("cps5601x: Can't find PD\n");
414*eb119257SChen Shunqing 			else
415*eb119257SChen Shunqing 				printf("cps5601x: Get UCLASS PD failed: %d\n", ret);
416*eb119257SChen Shunqing 			charger->pd = NULL;
417*eb119257SChen Shunqing 		}
418*eb119257SChen Shunqing 	}
419*eb119257SChen Shunqing 
420*eb119257SChen Shunqing 	if (!cps5601x_get_pd_output_val(charger, &pd_inputvol, &pd_inputcurrent)) {
421*eb119257SChen Shunqing 		CPS_DBG("pd adapter\n");
422*eb119257SChen Shunqing 		cps5601x_set_input_current_limit(charger, pd_inputcurrent);
423*eb119257SChen Shunqing 	} else {
424*eb119257SChen Shunqing 		CPS_DBG("normal adapter: %d\n", cps5601x_get_usb_type());
425*eb119257SChen Shunqing 		if (cps5601x_get_usb_type() == POWER_SUPPLY_TYPE_USB_DCP)
426*eb119257SChen Shunqing 			cps5601x_set_input_current_limit(charger, dcp_inputcurrent);
427*eb119257SChen Shunqing 		else if (cps5601x_get_usb_type() == POWER_SUPPLY_TYPE_USB_CDP)
428*eb119257SChen Shunqing 			cps5601x_set_input_current_limit(charger, dcp_inputcurrent);
429*eb119257SChen Shunqing 		else if (cps5601x_get_usb_type() == POWER_SUPPLY_TYPE_USB_FLOATING)
430*eb119257SChen Shunqing 			cps5601x_set_input_current_limit(charger, dcp_inputcurrent);
431*eb119257SChen Shunqing 		else
432*eb119257SChen Shunqing 			cps5601x_set_input_current_limit(charger, sdp_inputcurrent);
433*eb119257SChen Shunqing 	}
434*eb119257SChen Shunqing }
435*eb119257SChen Shunqing 
cps5601x_charger_status(struct udevice * dev)436*eb119257SChen Shunqing static bool cps5601x_charger_status(struct udevice *dev)
437*eb119257SChen Shunqing {
438*eb119257SChen Shunqing 	struct cps5601x *charger = dev_get_priv(dev);
439*eb119257SChen Shunqing 	int state_of_charger;
440*eb119257SChen Shunqing 	u8 value;
441*eb119257SChen Shunqing 	int i = 0;
442*eb119257SChen Shunqing 
443*eb119257SChen Shunqing __retry:
444*eb119257SChen Shunqing 	cps5601x_read(charger, CPS5601X_REG_0F, &value);
445*eb119257SChen Shunqing 	state_of_charger = !!(value & PG_STAT_MASK);
446*eb119257SChen Shunqing 	if (!state_of_charger && charger->pd_online) {
447*eb119257SChen Shunqing 		if (i < 3) {
448*eb119257SChen Shunqing 			i++;
449*eb119257SChen Shunqing 			mdelay(20);
450*eb119257SChen Shunqing 			goto __retry;
451*eb119257SChen Shunqing 		}
452*eb119257SChen Shunqing 	}
453*eb119257SChen Shunqing 
454*eb119257SChen Shunqing 	if ((state_of_charger) && (charger->init_count < 5)) {
455*eb119257SChen Shunqing 		cps5601x_charger_input_current_init(charger);
456*eb119257SChen Shunqing 		cps5601x_charger_enable(dev);
457*eb119257SChen Shunqing 		charger->init_count++;
458*eb119257SChen Shunqing 	}
459*eb119257SChen Shunqing 
460*eb119257SChen Shunqing 	if (!state_of_charger)
461*eb119257SChen Shunqing 		cps5601x_set_iprechg(charger, CPS5601X_PRECHRG_I_DEF_uA);
462*eb119257SChen Shunqing 
463*eb119257SChen Shunqing 	CPS_DBG("dump register:\n");
464*eb119257SChen Shunqing 	for (i = CPS5601X_REG_00; i < CPS5601X_REG_1B; i++) {
465*eb119257SChen Shunqing 		cps5601x_read(charger, i, &value);
466*eb119257SChen Shunqing 		CPS_DBG("[%d]: 0x%x\n", i, value);
467*eb119257SChen Shunqing 	}
468*eb119257SChen Shunqing 	return state_of_charger;
469*eb119257SChen Shunqing }
470*eb119257SChen Shunqing 
cps5601x_irq_handler(int irq,void * data)471*eb119257SChen Shunqing static void cps5601x_irq_handler(int irq, void *data)
472*eb119257SChen Shunqing {
473*eb119257SChen Shunqing }
474*eb119257SChen Shunqing 
cps5601x_ofdata_to_platdata(struct udevice * dev)475*eb119257SChen Shunqing static int cps5601x_ofdata_to_platdata(struct udevice *dev)
476*eb119257SChen Shunqing {
477*eb119257SChen Shunqing 	struct cps5601x *charger = dev_get_priv(dev);
478*eb119257SChen Shunqing 	u32 interrupt, phandle;
479*eb119257SChen Shunqing 	int ret;
480*eb119257SChen Shunqing 
481*eb119257SChen Shunqing 	charger->dev = dev;
482*eb119257SChen Shunqing 	charger->ichg = dev_read_u32_default(dev,
483*eb119257SChen Shunqing 					     "vbat-current-limit-microamp",
484*eb119257SChen Shunqing 					     0);
485*eb119257SChen Shunqing 	if (charger->ichg == 0)
486*eb119257SChen Shunqing 		charger->ichg = 3000 * 1000;
487*eb119257SChen Shunqing 	charger->vchg = dev_read_u32_default(dev,
488*eb119257SChen Shunqing 					     "vbat-voltage-limit-microamp",
489*eb119257SChen Shunqing 					     0);
490*eb119257SChen Shunqing 	if (charger->vchg == 0)
491*eb119257SChen Shunqing 		charger->vchg = 4400 * 1000;
492*eb119257SChen Shunqing 	CPS_DBG("charger->ichg: %d\n", charger->ichg);
493*eb119257SChen Shunqing 	CPS_DBG("charger->vchg: %d\n", charger->vchg);
494*eb119257SChen Shunqing 
495*eb119257SChen Shunqing 	phandle = dev_read_u32_default(dev, "interrupt-parent", -ENODATA);
496*eb119257SChen Shunqing 	if (phandle == -ENODATA) {
497*eb119257SChen Shunqing 		printf("cps5601x: read 'interrupt-parent' failed, ret=%d\n",
498*eb119257SChen Shunqing 		       phandle);
499*eb119257SChen Shunqing 		return phandle;
500*eb119257SChen Shunqing 	}
501*eb119257SChen Shunqing 
502*eb119257SChen Shunqing 	ret = dev_read_u32_array(dev, "interrupts", &interrupt, 1);
503*eb119257SChen Shunqing 	if (ret) {
504*eb119257SChen Shunqing 		printf("cps5601x: read 'interrupts' failed, ret=%d\n", ret);
505*eb119257SChen Shunqing 		return ret;
506*eb119257SChen Shunqing 	}
507*eb119257SChen Shunqing 
508*eb119257SChen Shunqing 	charger->irq = phandle_gpio_to_irq(phandle, interrupt);
509*eb119257SChen Shunqing 	if (charger->irq < 0)
510*eb119257SChen Shunqing 		printf("cps5601x: failed to request irq: %d\n", charger->irq);
511*eb119257SChen Shunqing 
512*eb119257SChen Shunqing 	return 0;
513*eb119257SChen Shunqing }
514*eb119257SChen Shunqing 
cps5601x_probe(struct udevice * dev)515*eb119257SChen Shunqing static int cps5601x_probe(struct udevice *dev)
516*eb119257SChen Shunqing {
517*eb119257SChen Shunqing 	struct cps5601x *charger = dev_get_priv(dev);
518*eb119257SChen Shunqing 	u8 value;
519*eb119257SChen Shunqing 	int i;
520*eb119257SChen Shunqing 
521*eb119257SChen Shunqing 	CPS_DBG("cps5601x: driver version-202502024\n");
522*eb119257SChen Shunqing 	CPS_DBG("cps5601x: dump register:\n");
523*eb119257SChen Shunqing 	for (i = CPS5601X_REG_00; i < CPS5601X_REG_1B; i++) {
524*eb119257SChen Shunqing 		cps5601x_read(charger, i, &value);
525*eb119257SChen Shunqing 		CPS_DBG("cps5601x: [%d]: 0x%x\n", i, value);
526*eb119257SChen Shunqing 	}
527*eb119257SChen Shunqing 
528*eb119257SChen Shunqing 	charger->dev = dev;
529*eb119257SChen Shunqing 	/* disable watchdog */
530*eb119257SChen Shunqing 	cps5601x_update_bits(charger, CPS5601X_REG_0B, WATCHDOG_MASK, WATCHDOG_TIME(0));
531*eb119257SChen Shunqing 
532*eb119257SChen Shunqing 	cps5601x_update_bits(charger, CPS5601X_REG_0E, TS_IGNORE_MASK, EN_TS_IGNORE(1));
533*eb119257SChen Shunqing 
534*eb119257SChen Shunqing 	cps5601x_set_chargecurrent(charger, charger->ichg);
535*eb119257SChen Shunqing 	cps5601x_set_chargevolt(charger, charger->vchg);
536*eb119257SChen Shunqing 
537*eb119257SChen Shunqing 	if (0 && charger->irq) {
538*eb119257SChen Shunqing 		CPS_DBG("cps5601x: enable cps5601x irq\n");
539*eb119257SChen Shunqing 		irq_install_handler(charger->irq, cps5601x_irq_handler, dev);
540*eb119257SChen Shunqing 		irq_handler_enable(charger->irq);
541*eb119257SChen Shunqing 	}
542*eb119257SChen Shunqing 
543*eb119257SChen Shunqing 	return 0;
544*eb119257SChen Shunqing }
545*eb119257SChen Shunqing 
546*eb119257SChen Shunqing static const struct udevice_id charger_ids[] = {
547*eb119257SChen Shunqing 	{ .compatible = "cps,cps5601x" },
548*eb119257SChen Shunqing 	{ },
549*eb119257SChen Shunqing };
550*eb119257SChen Shunqing 
551*eb119257SChen Shunqing static struct dm_fuel_gauge_ops charger_ops = {
552*eb119257SChen Shunqing 	.get_chrg_online = cps5601x_charger_status,
553*eb119257SChen Shunqing 	.capability = cps5601x_charger_capability,
554*eb119257SChen Shunqing 	.set_charger_voltage = cps5601x_set_charger_voltage,
555*eb119257SChen Shunqing 	.set_charger_enable = cps5601x_charger_enable,
556*eb119257SChen Shunqing 	.set_charger_disable = cps5601x_charger_disable,
557*eb119257SChen Shunqing 	.set_charger_current = cps5601x_charger_current,
558*eb119257SChen Shunqing 	.set_iprechg_current = cps5601x_iprechg_current,
559*eb119257SChen Shunqing 
560*eb119257SChen Shunqing };
561*eb119257SChen Shunqing 
562*eb119257SChen Shunqing U_BOOT_DRIVER(cps5601x_charger) = {
563*eb119257SChen Shunqing 	.name = "cps5601x_charger",
564*eb119257SChen Shunqing 	.id = UCLASS_FG,
565*eb119257SChen Shunqing 	.probe = cps5601x_probe,
566*eb119257SChen Shunqing 	.of_match = charger_ids,
567*eb119257SChen Shunqing 	.ops = &charger_ops,
568*eb119257SChen Shunqing 	.ofdata_to_platdata = cps5601x_ofdata_to_platdata,
569*eb119257SChen Shunqing 	.priv_auto_alloc_size = sizeof(struct cps5601x),
570*eb119257SChen Shunqing };
571