xref: /OK3568_Linux_fs/u-boot/drivers/power/charge/bq25700_charger.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * (C) Copyright 2019 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <asm/gpio.h>
9 #include <dm/device.h>
10 #include <dm/uclass.h>
11 #include <power/fuel_gauge.h>
12 #include <power/pmic.h>
13 #include <power/power_delivery/power_delivery.h>
14 #include <linux/usb/phy-rockchip-usb2.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 #define BQ25700_ID				0x25700
19 #define BQ25703_ID				0x25703
20 
21 #define COMPAT_BQ25700				"ti,bq25700"
22 #define COMPAT_BQ25703				"ti,bq25703"
23 
24 #define BQ25700_I2C_SPEED			100000
25 #define BQ25700_CHARGE_CURRENT_1500MA		0x5C0
26 #define BQ25700_SDP_INPUT_CURRENT_500MA		0xA00
27 #define BQ25700_DCP_INPUT_CURRENT_1500MA	0x1E00
28 #define BQ25700_DCP_INPUT_CURRENT_2000MA	0x2800
29 #define BQ25700_DCP_INPUT_CURRENT_3000MA	0x3C00
30 
31 #define WATCHDOG_ENSABLE			(0x03 << 13)
32 
33 #define BQ25700_CHARGEOPTION0_REG		0x12
34 #define BQ25700_CHARGECURREN_REG		0x14
35 #define BQ25700_CHARGERSTAUS_REG		0x20
36 #define BQ25700_INPUTVOLTAGE_REG		0x3D
37 #define BQ25700_INPUTCURREN_REG			0x3F
38 
39 #define BQ25703_CHARGEOPTION0_REG		0x00
40 #define BQ25703_CHARGECURREN_REG		0x02
41 #define BQ25703_CHARGERSTAUS_REG		0x20
42 #define BQ25703_INPUTVOLTAGE_REG		0x0A
43 #define BQ25703_INPUTCURREN_REG			0x0E
44 
45 enum bq25700_table_ids {
46 	/* range tables */
47 	TBL_ICHG,
48 	TBL_CHGMAX,
49 	TBL_INPUTVOL,
50 	TBL_INPUTCUR,
51 	TBL_SYSVMIN,
52 	TBL_OTGVOL,
53 	TBL_OTGCUR,
54 	TBL_EXTCON,
55 };
56 
57 struct bq25700 {
58 	struct udevice *dev;
59 	u32 ichg;
60 	u32 chip_id;
61 	struct udevice *pd;
62 };
63 
64 struct bq25700_range {
65 	u32 min;
66 	u32 max;
67 	u32 step;
68 };
69 
bq25700_read(struct bq25700 * charger,uint reg)70 static int bq25700_read(struct bq25700 *charger, uint reg)
71 {
72 	u16 val;
73 	int ret;
74 
75 	ret = dm_i2c_read(charger->dev, reg, (u8 *)&val, 2);
76 	if (ret) {
77 		debug("write error to device: %p register: %#x!",
78 		      charger->dev, reg);
79 		return ret;
80 	}
81 
82 	return val;
83 }
84 
bq25700_write(struct bq25700 * charger,uint reg,u16 val)85 static int bq25700_write(struct bq25700 *charger, uint reg, u16 val)
86 {
87 	int ret;
88 
89 	ret = dm_i2c_write(charger->dev, reg, (u8 *)&val, 2);
90 	if (ret) {
91 		debug("write error to device: %p register: %#x!",
92 		      charger->dev, reg);
93 		return ret;
94 	}
95 
96 	return 0;
97 }
98 
99 static const union {
100 	struct bq25700_range  rt;
101 } bq25700_tables[] = {
102 	/* range tables */
103 	[TBL_ICHG] = { .rt = {0, 8128000, 64000} },
104 	/* uV */
105 	[TBL_CHGMAX] = { .rt = {0, 19200000, 16000} },
106 	/* uV  max charge voltage*/
107 	[TBL_INPUTVOL] = { .rt = {3200000, 19520000, 64000} },
108 	/* uV  input charge voltage*/
109 	[TBL_INPUTCUR] = {.rt = {0, 6350000, 50000} },
110 	/*uA input current*/
111 	[TBL_SYSVMIN] = { .rt = {1024000, 16182000, 256000} },
112 	/* uV min system voltage*/
113 	[TBL_OTGVOL] = {.rt = {4480000, 20800000, 64000} },
114 	/*uV OTG volage*/
115 	[TBL_OTGCUR] = {.rt = {0, 6350000, 50000} },
116 };
117 
bq25700_find_idx(u32 value,enum bq25700_table_ids id)118 static u32 bq25700_find_idx(u32 value, enum bq25700_table_ids id)
119 {
120 	const struct bq25700_range *rtbl = &bq25700_tables[id].rt;
121 	u32 rtbl_size;
122 	u32 idx;
123 
124 	rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1;
125 
126 	for (idx = 1;
127 	     idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value);
128 	     idx++)
129 		;
130 
131 	return idx - 1;
132 }
133 
bq25700_charger_status(struct bq25700 * charger)134 static bool bq25700_charger_status(struct bq25700 *charger)
135 {
136 	int state_of_charger;
137 	u16 value;
138 
139 	value = bq25700_read(charger, BQ25700_CHARGERSTAUS_REG);
140 	state_of_charger = value >> 15;
141 
142 	return state_of_charger;
143 }
144 
bq25703_charger_status(struct bq25700 * charger)145 static bool bq25703_charger_status(struct bq25700 *charger)
146 {
147 	int state_of_charger;
148 	u16 value;
149 
150 	value = bq25700_read(charger, BQ25703_CHARGERSTAUS_REG);
151 	state_of_charger = value >> 15;
152 
153 	return state_of_charger;
154 }
155 
bq257xx_charger_status(struct udevice * dev)156 static bool bq257xx_charger_status(struct udevice *dev)
157 {
158 	struct bq25700 *charger = dev_get_priv(dev);
159 
160 	if (charger->chip_id == BQ25700_ID)
161 		return bq25700_charger_status(charger);
162 	else
163 		return bq25703_charger_status(charger);
164 }
165 
bq25700_charger_capability(struct udevice * dev)166 static int bq25700_charger_capability(struct udevice *dev)
167 {
168 	return FG_CAP_CHARGER;
169 }
170 
bq25700_get_usb_type(void)171 static int bq25700_get_usb_type(void)
172 {
173 #ifdef CONFIG_PHY_ROCKCHIP_INNO_USB2
174 	return rockchip_chg_get_type();
175 #else
176 	return 0;
177 #endif
178 }
179 
bq25700_get_pd_output_val(struct bq25700 * charger,int * vol,int * cur)180 static int bq25700_get_pd_output_val(struct bq25700 *charger,
181 				     int *vol, int *cur)
182 {
183 	struct power_delivery_data pd_data;
184 	int ret;
185 
186 	if (!charger->pd)
187 		return -EINVAL;
188 
189 	memset(&pd_data, 0, sizeof(pd_data));
190 	ret = power_delivery_get_data(charger->pd, &pd_data);
191 	if (ret)
192 		return ret;
193 	if (!pd_data.online || !pd_data.voltage || !pd_data.current)
194 		return -EINVAL;
195 
196 	*vol = pd_data.voltage;
197 	*cur = pd_data.current;
198 
199 	return 0;
200 }
201 
bq25700_charger_current_init(struct bq25700 * charger)202 static void bq25700_charger_current_init(struct bq25700 *charger)
203 {
204 	u16 charge_current = BQ25700_CHARGE_CURRENT_1500MA;
205 	u16 sdp_inputcurrent = BQ25700_SDP_INPUT_CURRENT_500MA;
206 	u16 dcp_inputcurrent = BQ25700_DCP_INPUT_CURRENT_1500MA;
207 	int pd_inputvol, pd_inputcurrent;
208 	u16 vol_idx = 0, cur_idx;
209 	u16 temp;
210 
211 	temp = bq25700_read(charger, BQ25700_CHARGEOPTION0_REG);
212 	temp &= (~WATCHDOG_ENSABLE);
213 	bq25700_write(charger, BQ25700_CHARGEOPTION0_REG, temp);
214 
215 	if (!bq25700_get_pd_output_val(charger, &pd_inputvol,
216 				       &pd_inputcurrent)) {
217 		printf("%s pd charge input vol:%duv current:%dua\n",
218 		       __func__, pd_inputvol, pd_inputcurrent);
219 		if (pd_inputvol > 5000000) {
220 			vol_idx = bq25700_find_idx((pd_inputvol - 1280000 - 3200000),
221 						   TBL_INPUTVOL);
222 			vol_idx = vol_idx << 6;
223 		}
224 		cur_idx = bq25700_find_idx(pd_inputcurrent,
225 					   TBL_INPUTCUR);
226 		cur_idx  = cur_idx << 8;
227 		if (pd_inputcurrent != 0) {
228 			bq25700_write(charger, BQ25700_INPUTCURREN_REG,
229 				      cur_idx);
230 			if (vol_idx)
231 				bq25700_write(charger, BQ25700_INPUTVOLTAGE_REG,
232 					      vol_idx);
233 			charge_current = bq25700_find_idx(charger->ichg,
234 							  TBL_ICHG);
235 			charge_current = charge_current << 8;
236 		}
237 	} else {
238 		if (bq25700_get_usb_type() > 1)
239 			bq25700_write(charger, BQ25700_INPUTCURREN_REG,
240 				      dcp_inputcurrent);
241 		else
242 			bq25700_write(charger, BQ25700_INPUTCURREN_REG,
243 				      sdp_inputcurrent);
244 	}
245 
246 	if (bq25700_charger_status(charger))
247 		bq25700_write(charger, BQ25700_CHARGECURREN_REG,
248 			      charge_current);
249 }
250 
bq25703_charger_current_init(struct bq25700 * charger)251 static void bq25703_charger_current_init(struct bq25700 *charger)
252 {
253 	u16 charge_current = BQ25700_CHARGE_CURRENT_1500MA;
254 	u16 sdp_inputcurrent = BQ25700_SDP_INPUT_CURRENT_500MA;
255 	u16 dcp_inputcurrent = BQ25700_DCP_INPUT_CURRENT_1500MA;
256 	int pd_inputvol,  pd_inputcurrent;
257 	u16 vol_idx = 0, cur_idx;
258 	u16 temp;
259 
260 	temp = bq25700_read(charger, BQ25703_CHARGEOPTION0_REG);
261 	temp &= (~WATCHDOG_ENSABLE);
262 	bq25700_write(charger, BQ25703_CHARGEOPTION0_REG, temp);
263 
264 	if (!bq25700_get_pd_output_val(charger, &pd_inputvol,
265 				       &pd_inputcurrent)) {
266 		printf("%s pd charge input vol:%duv current:%dua\n",
267 		       __func__, pd_inputvol, pd_inputcurrent);
268 		if (pd_inputvol > 5000000) {
269 			vol_idx = bq25700_find_idx(pd_inputvol - 1280000 - 3200000,
270 						   TBL_INPUTVOL);
271 			vol_idx = vol_idx << 6;
272 		}
273 		cur_idx = bq25700_find_idx(pd_inputcurrent,
274 					   TBL_INPUTCUR);
275 		cur_idx  = cur_idx << 8;
276 		if (pd_inputcurrent != 0) {
277 			bq25700_write(charger, BQ25703_INPUTCURREN_REG,
278 				      cur_idx);
279 			if (vol_idx)
280 				bq25700_write(charger, BQ25703_INPUTVOLTAGE_REG,
281 					      vol_idx);
282 			charge_current = bq25700_find_idx(charger->ichg,
283 							  TBL_ICHG);
284 			charge_current = charge_current << 8;
285 		}
286 	} else {
287 		if (bq25700_get_usb_type() > 1)
288 			bq25700_write(charger, BQ25703_INPUTCURREN_REG,
289 				      dcp_inputcurrent);
290 		else
291 			bq25700_write(charger, BQ25703_INPUTCURREN_REG,
292 				      sdp_inputcurrent);
293 	}
294 
295 	if (bq25703_charger_status(charger))
296 		bq25700_write(charger, BQ25703_CHARGECURREN_REG,
297 			      charge_current);
298 }
299 
bq25700_ofdata_to_platdata(struct udevice * dev)300 static int bq25700_ofdata_to_platdata(struct udevice *dev)
301 {
302 	struct bq25700 *charger = dev_get_priv(dev);
303 	const void *blob = gd->fdt_blob;
304 	int node, node1;
305 
306 	charger->dev = dev;
307 
308 	node = fdt_node_offset_by_compatible(blob, 0, COMPAT_BQ25700);
309 	node1 = fdt_node_offset_by_compatible(blob, 0, COMPAT_BQ25703);
310 	if ((node < 0) && (node1 < 0)) {
311 		printf("Can't find dts node for charger bq25700\n");
312 		return -ENODEV;
313 	}
314 
315 	if (node < 0) {
316 		node = node1;
317 		charger->chip_id = BQ25703_ID;
318 	} else {
319 		charger->chip_id = BQ25700_ID;
320 	}
321 
322 	charger->ichg = fdtdec_get_int(blob, node, "ti,charge-current", 0);
323 
324 	return 0;
325 }
326 
bq25700_probe(struct udevice * dev)327 static int bq25700_probe(struct udevice *dev)
328 {
329 	struct bq25700 *charger = dev_get_priv(dev);
330 	int ret;
331 
332 	ret = uclass_get_device(UCLASS_PD, 0, &charger->pd);
333 	if (ret) {
334 		if (ret == -ENODEV)
335 			printf("Can't find PMIC\n");
336 		else
337 			printf("Get UCLASS PMIC failed: %d\n", ret);
338 
339 		charger->pd = NULL;
340 	}
341 
342 	if (charger->chip_id == BQ25700_ID)
343 		bq25700_charger_current_init(charger);
344 	else
345 		bq25703_charger_current_init(charger);
346 
347 	return 0;
348 }
349 
350 static const struct udevice_id charger_ids[] = {
351 	{ .compatible = "ti,bq25700" },
352 	{ .compatible = "ti,bq25703" },
353 	{ },
354 };
355 
356 static struct dm_fuel_gauge_ops charger_ops = {
357 	.get_chrg_online = bq257xx_charger_status,
358 	.capability = bq25700_charger_capability,
359 };
360 
361 U_BOOT_DRIVER(bq25700_charger) = {
362 	.name = "bq25700_charger",
363 	.id = UCLASS_FG,
364 	.probe = bq25700_probe,
365 	.of_match = charger_ids,
366 	.ops = &charger_ops,
367 	.ofdata_to_platdata = bq25700_ofdata_to_platdata,
368 	.priv_auto_alloc_size = sizeof(struct bq25700),
369 };
370