xref: /rk3399_rockchip-uboot/drivers/power/charge/bq25700_charger.c (revision e8c34540a61ba8ec3ef255e3e8a72e7d3409f5f5)
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 <power/fuel_gauge.h>
11 #include <power/pmic.h>
12 #include <linux/usb/phy-rockchip-inno-usb2.h>
13 
14 DECLARE_GLOBAL_DATA_PTR;
15 
16 #define BQ25700_ID				0x25700
17 #define BQ25703_ID				0x25703
18 
19 #define COMPAT_BQ25700				"ti,bq25700"
20 #define COMPAT_BQ25703				"ti,bq25703"
21 
22 #define BQ25700_I2C_SPEED			100000
23 #define BQ25700_CHARGE_CURRENT_1500MA		0x5C0
24 #define BQ25700_SDP_INPUT_CURRENT_500MA		0xA00
25 #define BQ25700_DCP_INPUT_CURRENT_1500MA	0x1E00
26 #define BQ25700_DCP_INPUT_CURRENT_2000MA	0x2800
27 #define BQ25700_DCP_INPUT_CURRENT_3000MA	0x3C00
28 
29 #define WATCHDOG_ENSABLE			(0x03 << 13)
30 
31 #define BQ25700_CHARGEOPTION0_REG		0x12
32 #define BQ25700_CHARGECURREN_REG		0x14
33 #define BQ25700_CHARGERSTAUS_REG		0x20
34 #define BQ25700_INPUTVOLTAGE_REG		0x3D
35 #define BQ25700_INPUTCURREN_REG			0x3F
36 
37 #define BQ25703_CHARGEOPTION0_REG		0x00
38 #define BQ25703_CHARGECURREN_REG		0x02
39 #define BQ25703_CHARGERSTAUS_REG		0x20
40 #define BQ25703_INPUTVOLTAGE_REG		0x0A
41 #define BQ25703_INPUTCURREN_REG			0x0E
42 
43 enum bq25700_table_ids {
44 	/* range tables */
45 	TBL_ICHG,
46 	TBL_CHGMAX,
47 	TBL_INPUTVOL,
48 	TBL_INPUTCUR,
49 	TBL_SYSVMIN,
50 	TBL_OTGVOL,
51 	TBL_OTGCUR,
52 	TBL_EXTCON,
53 };
54 
55 struct bq25700 {
56 	struct udevice *dev;
57 	struct gpio_desc typec0_enable_gpio;
58 	struct gpio_desc typec1_enable_gpio;
59 	u32 ichg;
60 	u32 chip_id;
61 };
62 
63 struct bq25700_range {
64 	u32 min;
65 	u32 max;
66 	u32 step;
67 };
68 
69 static int bq25700_read(struct bq25700 *charger, uint reg)
70 {
71 	u16 val;
72 	int ret;
73 
74 	ret = dm_i2c_read(charger->dev, reg, (u8 *)&val, 2);
75 	if (ret) {
76 		debug("write error to device: %p register: %#x!",
77 		      charger->dev, reg);
78 		return ret;
79 	}
80 
81 	return val;
82 }
83 
84 static int bq25700_write(struct bq25700 *charger, uint reg, u16 val)
85 {
86 	int ret;
87 
88 	ret = dm_i2c_write(charger->dev, reg, (u8 *)&val, 2);
89 	if (ret) {
90 		debug("write error to device: %p register: %#x!",
91 		      charger->dev, reg);
92 		return ret;
93 	}
94 
95 	return 0;
96 }
97 
98 #if defined(CONFIG_POWER_FUSB302)
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 
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 #endif
134 
135 static bool bq25700_charger_status(struct bq25700 *charger)
136 {
137 #if defined(CONFIG_POWER_FUSB302)
138 	static u16 charge_flag;
139 #endif
140 	int state_of_charger;
141 	u16 value;
142 
143 	value = bq25700_read(charger, BQ25700_CHARGERSTAUS_REG);
144 	state_of_charger = value >> 15;
145 
146 #if defined(CONFIG_POWER_FUSB302)
147 	if (state_of_charger) {
148 		charge_flag = 1;
149 	} else if (!state_of_charger && charge_flag == 1) {
150 		typec_discharge();
151 		charge_flag = 0;
152 	}
153 #endif
154 
155 	return state_of_charger;
156 }
157 
158 static bool bq25703_charger_status(struct bq25700 *charger)
159 {
160 #if defined(CONFIG_POWER_FUSB302)
161 	static u16 charge_flag;
162 #endif
163 	int state_of_charger;
164 	u16 value;
165 
166 	value = bq25700_read(charger, BQ25703_CHARGERSTAUS_REG);
167 	state_of_charger = value >> 15;
168 
169 #if defined(CONFIG_POWER_FUSB302)
170 	if (state_of_charger) {
171 		charge_flag = 1;
172 	} else if (!state_of_charger && charge_flag == 1) {
173 		typec_discharge();
174 		charge_flag = 0;
175 	}
176 #endif
177 
178 	return state_of_charger;
179 }
180 
181 static bool bq257xx_charger_status(struct udevice *dev)
182 {
183 	struct bq25700 *charger = dev_get_priv(dev);
184 
185 	if (charger->chip_id == BQ25700_ID)
186 		return bq25700_charger_status(charger);
187 	else
188 		return bq25703_charger_status(charger);
189 }
190 
191 static int bq25700_charger_capability(struct udevice *dev)
192 {
193 	return FG_CAP_CHARGER;
194 }
195 
196 static int bq25700_get_usb_type(void)
197 {
198 #ifdef CONFIG_PHY_ROCKCHIP_INNO_USB2
199 	return rockchip_chg_get_type();
200 #else
201 	return 0;
202 #endif
203 }
204 
205 static void bq25700_charger_current_init(struct bq25700 *charger)
206 {
207 	u16 charge_current = BQ25700_CHARGE_CURRENT_1500MA;
208 	u16 sdp_inputcurrent = BQ25700_SDP_INPUT_CURRENT_500MA;
209 	u16 dcp_inputcurrent = BQ25700_DCP_INPUT_CURRENT_1500MA;
210 	u32 pd_inputcurrent = 0;
211 #if defined(CONFIG_POWER_FUSB302)
212 	u16 vol_idx, cur_idx, pd_inputvol;
213 #endif
214 	u16 temp;
215 
216 	temp = bq25700_read(charger, BQ25700_CHARGEOPTION0_REG);
217 	temp &= (~WATCHDOG_ENSABLE);
218 	bq25700_write(charger, BQ25700_CHARGEOPTION0_REG, temp);
219 
220 #if defined(CONFIG_POWER_FUSB302)
221 	if (!get_pd_output_val(&pd_inputvol, &pd_inputcurrent)) {
222 		printf("%s pd charge input vol:%dmv current:%dma\n",
223 		       __func__, pd_inputvol, pd_inputcurrent);
224 		vol_idx = bq25700_find_idx((pd_inputvol - 1280) * 1000,
225 					   TBL_INPUTVOL);
226 		cur_idx = bq25700_find_idx(pd_inputcurrent * 1000,
227 					   TBL_INPUTCUR);
228 		cur_idx  = cur_idx << 8;
229 		vol_idx = vol_idx << 6;
230 		if (pd_inputcurrent != 0) {
231 			bq25700_write(charger, BQ25700_INPUTCURREN_REG,
232 				      cur_idx);
233 			bq25700_write(charger, BQ25700_INPUTVOLTAGE_REG,
234 				      vol_idx);
235 			charge_current = bq25700_find_idx(charger.ichg,
236 							  TBL_ICHG);
237 			charge_current = charge_current << 8;
238 		}
239 	}
240 #endif
241 
242 	if (pd_inputcurrent == 0) {
243 		if (bq25700_get_usb_type() > 1)
244 			bq25700_write(charger, BQ25700_INPUTCURREN_REG,
245 				      dcp_inputcurrent);
246 		else
247 			bq25700_write(charger, BQ25700_INPUTCURREN_REG,
248 				      sdp_inputcurrent);
249 	}
250 
251 	if (bq25700_charger_status(charger))
252 		bq25700_write(charger, BQ25700_CHARGECURREN_REG,
253 			      charge_current);
254 }
255 
256 static void bq25703_charger_current_init(struct bq25700 *charger)
257 {
258 	u16 charge_current = BQ25700_CHARGE_CURRENT_1500MA;
259 	u16 sdp_inputcurrent = BQ25700_SDP_INPUT_CURRENT_500MA;
260 	u16 dcp_inputcurrent = BQ25700_DCP_INPUT_CURRENT_1500MA;
261 	u32 pd_inputcurrent = 0;
262 #if defined(CONFIG_POWER_FUSB302)
263 	u16 vol_idx, cur_idx, pd_inputvol;
264 #endif
265 	u16 temp;
266 
267 	temp = bq25700_read(charger, BQ25703_CHARGEOPTION0_REG);
268 	temp &= (~WATCHDOG_ENSABLE);
269 	bq25700_write(charger, BQ25703_CHARGEOPTION0_REG, temp);
270 
271 #if defined(CONFIG_POWER_FUSB302)
272 	if (!get_pd_output_val(&pd_inputvol, &pd_inputcurrent)) {
273 		printf("%s pd charge input vol:%dmv current:%dma\n",
274 		       __func__, pd_inputvol, pd_inputcurrent);
275 		vol_idx = bq25700_find_idx((pd_inputvol - 1280) * 1000,
276 					   TBL_INPUTVOL);
277 		cur_idx = bq25700_find_idx(pd_inputcurrent * 1000,
278 					   TBL_INPUTCUR);
279 		cur_idx  = cur_idx << 8;
280 		vol_idx = vol_idx << 6;
281 		if (pd_inputcurrent != 0) {
282 			bq25700_write(charger, BQ25703_INPUTCURREN_REG,
283 				      cur_idx);
284 			bq25700_write(charger, BQ25703_INPUTVOLTAGE_REG,
285 				      vol_idx);
286 			charge_current = bq25700_find_idx(charger.ichg,
287 							  TBL_ICHG);
288 			charge_current = charge_current << 8;
289 		}
290 	}
291 #endif
292 
293 	if (pd_inputcurrent == 0) {
294 		if (bq25700_get_usb_type() > 1)
295 			bq25700_write(charger, BQ25703_INPUTCURREN_REG,
296 				      dcp_inputcurrent);
297 		else
298 			bq25700_write(charger, BQ25703_INPUTCURREN_REG,
299 				      sdp_inputcurrent);
300 	}
301 
302 	if (bq25703_charger_status(charger))
303 		bq25700_write(charger, BQ25703_CHARGECURREN_REG,
304 			      charge_current);
305 }
306 
307 static int bq25700_ofdata_to_platdata(struct udevice *dev)
308 {
309 	struct bq25700 *charger = dev_get_priv(dev);
310 	const void *blob = gd->fdt_blob;
311 	int node, node1;
312 #if defined(CONFIG_POWER_FUSB302)
313 	int port_num;
314 #endif
315 
316 	charger->dev = dev;
317 
318 	node = fdt_node_offset_by_compatible(blob, 0, COMPAT_BQ25700);
319 	node1 = fdt_node_offset_by_compatible(blob, 0, COMPAT_BQ25703);
320 	if ((node < 0) && (node1 < 0)) {
321 		printf("Can't find dts node for charger bq25700\n");
322 		return -ENODEV;
323 	}
324 
325 	if (node < 0) {
326 		node = node1;
327 		charger->chip_id = BQ25703_ID;
328 	} else {
329 		charger->chip_id = BQ25700_ID;
330 	}
331 
332 	charger->ichg = fdtdec_get_int(blob, node, "ti,charge-current", 0);
333 
334 #if defined(CONFIG_POWER_FUSB302)
335 	gpio_request_by_name(dev, "typec0-enable-gpios", 0,
336 			     &charger.typec0_enable_gpio);
337 	gpio_request_by_name(dev, "typec1-enable-gpios", 0,
338 			     &charger.typec1_enable_gpio);
339 
340 	if (dm_gpio_is_valid(charger.typec1_enable_gpio.gpio) &&
341 	    dm_gpio_is_valid(charger.typec0_enable_gpio.gpio)) {
342 		port_num = get_pd_port_num();
343 		if (port_num == 0) {
344 			printf("fusb0 charge typec0:1 typec1:0\n");
345 			dm_gpio_set_value(&charger.typec0_enable_gpio.gpio, 1);
346 			dm_gpio_set_value(&charger.typec1_enable_gpio.gpio, 0);
347 		} else if (port_num == 1) {
348 			printf("fusb1 charge typec0:0 typec1:1\n");
349 			dm_gpio_set_value(&charger.typec0_enable_gpio.gpio, 0);
350 			dm_gpio_set_value(&charger.typec1_enable_gpio.gpio, 1);
351 		}
352 		udelay(1000 * 200);
353 	}
354 #endif
355 
356 	return 0;
357 }
358 
359 static int bq25700_probe(struct udevice *dev)
360 {
361 	struct bq25700 *charger = dev_get_priv(dev);
362 
363 	if (charger->chip_id == BQ25700_ID)
364 		bq25700_charger_current_init(charger);
365 	else
366 		bq25703_charger_current_init(charger);
367 
368 	return 0;
369 }
370 
371 static const struct udevice_id charger_ids[] = {
372 	{ .compatible = "ti,bq25700" },
373 	{ .compatible = "ti,bq25703" },
374 	{ },
375 };
376 
377 static struct dm_fuel_gauge_ops charger_ops = {
378 	.get_chrg_online = bq257xx_charger_status,
379 	.capability = bq25700_charger_capability,
380 };
381 
382 U_BOOT_DRIVER(bq25700_charger) = {
383 	.name = "bq25700_charger",
384 	.id = UCLASS_FG,
385 	.probe = bq25700_probe,
386 	.of_match = charger_ids,
387 	.ops = &charger_ops,
388 	.ofdata_to_platdata = bq25700_ofdata_to_platdata,
389 	.priv_auto_alloc_size = sizeof(struct bq25700),
390 };
391