xref: /rk3399_rockchip-uboot/drivers/power/fuel_gauge/fg_cw201x.c (revision 5ce558eee1d84a2b85f2bbc4c4547c8ea1c1dae4)
1 /*
2  * (C) Copyright 2008-2015 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 #include <common.h>
7 #include <asm/gpio.h>
8 #include <dm.h>
9 #include <dm/device.h>
10 #include <errno.h>
11 #include <fdtdec.h>
12 #include <i2c.h>
13 #include <linux/usb/phy-rockchip-inno-usb2.h>
14 #include <malloc.h>
15 #include <power/battery.h>
16 #include <power/fuel_gauge.h>
17 #include <power/pmic.h>
18 #include "fg_regs.h"
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 #define COMPAT_ROCKCHIP_CW201X "cw201x"
23 
24 #define REG_VERSION		0x0
25 #define REG_VCELL		0x2
26 #define REG_SOC			0x4
27 #define REG_RRT_ALERT		0x6
28 #define REG_CONFIG		0x8
29 #define REG_MODE		0xA
30 #define REG_BATINFO		0x10
31 
32 #define MODE_SLEEP_MASK		(0x3 << 6)
33 #define MODE_SLEEP		(0x3 << 6)
34 #define MODE_NORMAL		(0x0 << 6)
35 #define MODE_QUICK_START	(0x3 << 4)
36 #define MODE_RESTART		(0xf << 0)
37 
38 #define CONFIG_UPDATE_FLG	(0x1 << 1)
39 #define ATHD			(0x0 << 3)
40 
41 enum charger_type {
42 	CHARGER_TYPE_NO = 0,
43 	CHARGER_TYPE_USB,
44 	CHARGER_TYPE_AC,
45 	CHARGER_TYPE_DC,
46 	CHARGER_TYPE_UNDEF,
47 };
48 
49 struct cw201x_info {
50 	struct udevice *dev;
51 	int capacity;
52 	u32 *cw_bat_config_info;
53 	int divider_res1;
54 	int divider_res2;
55 	int hw_id_check;
56 	int hw_id0;
57 	int hw_id1;
58 	int support_dc_adp;
59 	int dc_det_gpio;
60 	int dc_det_flag;
61 };
62 
63 static u8 cw201x_read(struct cw201x_info *cw201x, u8 reg)
64 {
65 	u8 val;
66 	int ret;
67 
68 	ret = dm_i2c_read(cw201x->dev, reg, &val, 1);
69 	if (ret) {
70 		debug("write error to device: %p register: %#x!",
71 		      cw201x->dev, reg);
72 		return ret;
73 	}
74 
75 	return val;
76 }
77 
78 static int cw201x_write(struct cw201x_info *cw201x, u8 reg, u8 val)
79 {
80 	int ret;
81 
82 	ret = dm_i2c_write(cw201x->dev, reg, &val, 1);
83 	if (ret) {
84 		debug("write error to device: %p register: %#x!",
85 		      cw201x->dev, reg);
86 		return ret;
87 	}
88 
89 	return 0;
90 }
91 
92 static u16 cw201x_read_half_word(struct cw201x_info *cw201x, int reg)
93 {
94 	u8 vall, valh;
95 	u16 val;
96 
97 	valh = cw201x_read(cw201x, reg);
98 	vall = cw201x_read(cw201x, reg + 1);
99 	val = ((u16)valh << 8) | vall;
100 
101 	return val;
102 }
103 
104 static int cw201x_ofdata_to_platdata(struct udevice *dev)
105 {
106 	const void *blob = gd->fdt_blob;
107 	int node = dev_of_offset(dev);
108 	struct cw201x_info *cw201x = dev_get_priv(dev);
109 	int ret;
110 	int len, size;
111 	int hw_id0_val, hw_id1_val;
112 
113 	if (fdt_getprop(blob, node, "bat_config_info", &len)) {
114 		len /= sizeof(u32);
115 		size = sizeof(*cw201x->cw_bat_config_info) * len;
116 		cw201x->cw_bat_config_info = calloc(size, 1);
117 		if (!cw201x->cw_bat_config_info) {
118 			debug("calloc cw_bat_config_info fail\n");
119 			return -EINVAL;
120 		}
121 		ret = fdtdec_get_int_array(blob, node,
122 					   "bat_config_info",
123 					   cw201x->cw_bat_config_info, len);
124 		if (ret) {
125 			debug("fdtdec_get cw_bat_config_info fail\n");
126 			return -EINVAL;
127 		}
128 	}
129 
130 	cw201x->support_dc_adp = fdtdec_get_int(blob, node,
131 						"support_dc_adp", 0);
132 	if (cw201x->support_dc_adp) {
133 		cw201x->dc_det_gpio = fdtdec_get_int(blob, node,
134 						     "dc_det_gpio", 0);
135 		if (!cw201x->dc_det_gpio)
136 			return -EINVAL;
137 		gpio_request(cw201x->dc_det_gpio, "dc_det_gpio");
138 		gpio_direction_input(cw201x->dc_det_gpio);
139 
140 		cw201x->dc_det_flag = fdtdec_get_int(blob, node,
141 						     "dc_det_flag", 0);
142 	}
143 
144 	cw201x->hw_id_check = fdtdec_get_int(blob, node, "hw_id_check", 0);
145 	if (cw201x->hw_id_check) {
146 		cw201x->hw_id0 = fdtdec_get_int(blob, node, "hw_id0_gpio", 0);
147 		if (!cw201x->hw_id0)
148 			return -EINVAL;
149 		gpio_request(cw201x->hw_id0, "hw_id0_gpio");
150 		gpio_direction_input(cw201x->hw_id0);
151 		hw_id0_val = gpio_get_value(cw201x->hw_id0);
152 
153 		cw201x->hw_id1 = fdtdec_get_int(blob, node, "hw_id1_gpio", 0);
154 		if (!cw201x->hw_id1)
155 			return -EINVAL;
156 		gpio_request(cw201x->hw_id1, "hw_id1_gpio");
157 		gpio_direction_input(cw201x->hw_id1);
158 		hw_id1_val = gpio_get_value(cw201x->hw_id1);
159 
160 		/* ID1 = 0, ID0 = 1 : Battery */
161 		if (!hw_id0_val || hw_id1_val)
162 			return -EINVAL;
163 	}
164 
165 	cw201x->divider_res1 = fdtdec_get_int(blob, node, "divider_res1", 0);
166 	cw201x->divider_res2 = fdtdec_get_int(blob, node, "divider_res2", 0);
167 
168 	return 0;
169 }
170 
171 static int cw201x_get_vol(struct cw201x_info *cw201x)
172 {
173 	u16 value16, value16_1, value16_2, value16_3;
174 	int voltage;
175 	int res1, res2;
176 
177 	value16 = cw201x_read_half_word(cw201x, REG_VCELL);
178 	if (value16 < 0)
179 		return -1;
180 
181 	value16_1 = cw201x_read_half_word(cw201x, REG_VCELL);
182 	if (value16_1 < 0)
183 		return -1;
184 
185 	value16_2 = cw201x_read_half_word(cw201x, REG_VCELL);
186 	if (value16_2 < 0)
187 		return -1;
188 
189 	if (value16 > value16_1) {
190 		value16_3 = value16;
191 		value16 = value16_1;
192 		value16_1 = value16_3;
193 	}
194 
195 	if (value16_1 > value16_2) {
196 		value16_3 = value16_1;
197 		value16_1 = value16_2;
198 		value16_2 = value16_3;
199 	}
200 
201 	if (value16 > value16_1) {
202 		value16_3 = value16;
203 		value16 = value16_1;
204 		value16_1 = value16_3;
205 	}
206 
207 	voltage = value16_1 * 312 / 1024;
208 
209 	if (cw201x->divider_res1 &&
210 	    cw201x->divider_res2) {
211 		res1 = cw201x->divider_res1;
212 		res2 = cw201x->divider_res2;
213 		voltage = voltage * (res1 + res2) / res2;
214 	}
215 
216 	debug("the cw201x voltage=%d\n", voltage);
217 	return voltage;
218 }
219 
220 static int cw201x_dwc_otg_check_dpdm(void)
221 {
222 #ifdef CONFIG_PHY_ROCKCHIP_INNO_USB2
223 	return rockchip_chg_get_type();
224 #else
225 	debug("rockchip_chg_get_type() is not implement\n");
226 	return CHARGER_TYPE_NO;
227 #endif
228 }
229 
230 static int cw201x_get_usb_state(struct cw201x_info *cw201x)
231 {
232 	int charger_type;
233 
234 	switch (cw201x_dwc_otg_check_dpdm()) {
235 	case 0:
236 		charger_type = CHARGER_TYPE_NO;
237 		break;
238 	case 1:
239 	case 3:
240 		charger_type = CHARGER_TYPE_USB;
241 		break;
242 	case 2:
243 		charger_type = CHARGER_TYPE_AC;
244 		break;
245 	default:
246 		charger_type = CHARGER_TYPE_NO;
247 		break;
248 	}
249 
250 	return charger_type;
251 }
252 
253 static bool cw201x_get_dc_state(struct cw201x_info *cw201x)
254 {
255 	if (gpio_get_value(cw201x->dc_det_gpio) == cw201x->dc_det_flag)
256 		return true;
257 
258 	return false;
259 }
260 
261 static bool cw201x_check_charge(struct cw201x_info *cw201x)
262 {
263 	if (cw201x_get_usb_state(cw201x) != CHARGER_TYPE_NO)
264 		return true;
265 	if (cw201x_get_dc_state(cw201x))
266 		return true;
267 
268 	return false;
269 }
270 
271 static int cw201x_get_soc(struct cw201x_info *cw201x)
272 {
273 	int cap;
274 
275 	cap = cw201x_read(cw201x, REG_SOC);
276 	if ((cap < 0) || (cap > 100))
277 		cap = cw201x->capacity;
278 
279 	cw201x->capacity = cap;
280 	return cw201x->capacity;
281 }
282 
283 static int cw201x_update_get_soc(struct udevice *dev)
284 {
285 	struct cw201x_info *cw201x = dev_get_priv(dev);
286 
287 	return cw201x_get_soc(cw201x);
288 }
289 
290 static int cw201x_update_get_voltage(struct udevice *dev)
291 {
292 	struct cw201x_info *cw201x = dev_get_priv(dev);
293 
294 	return cw201x_get_vol(cw201x);
295 }
296 
297 static bool cw201x_update_get_chrg_online(struct udevice *dev)
298 {
299 	struct cw201x_info *cw201x = dev_get_priv(dev);
300 
301 	return cw201x_check_charge(cw201x);
302 }
303 
304 static struct dm_fuel_gauge_ops cw201x_fg_ops = {
305 	.get_soc = cw201x_update_get_soc,
306 	.get_voltage = cw201x_update_get_voltage,
307 	.get_chrg_online = cw201x_update_get_chrg_online,
308 };
309 
310 static int cw201x_fg_cfg(struct cw201x_info *cw201x)
311 {
312 	u8 val = MODE_SLEEP;
313 	int i;
314 
315 	if ((val & MODE_SLEEP_MASK) == MODE_SLEEP) {
316 		val = MODE_NORMAL;
317 		cw201x_write(cw201x, REG_MODE, val);
318 	}
319 
320 	for (i = 0; i < 64; i++) {
321 		cw201x_write(cw201x, REG_BATINFO + i,
322 			     (u8)cw201x->cw_bat_config_info[i]);
323 	}
324 
325 	return 0;
326 }
327 
328 static int cw201x_fg_probe(struct udevice *dev)
329 {
330 	struct cw201x_info *cw201x = dev_get_priv(dev);
331 
332 	cw201x->dev = dev;
333 	cw201x_fg_cfg(cw201x);
334 
335 	debug("vol: %d, soc: %d\n",
336 	      cw201x_get_vol(cw201x), cw201x_get_soc(cw201x));
337 
338 	return 0;
339 }
340 
341 static const struct udevice_id cw201x_ids[] = {
342 	{ .compatible = "cw201x" },
343 	{ }
344 };
345 
346 U_BOOT_DRIVER(cw201x_fg) = {
347 	.name = "cw201x_fg",
348 	.id = UCLASS_FG,
349 	.of_match = cw201x_ids,
350 	.probe = cw201x_fg_probe,
351 	.ofdata_to_platdata = cw201x_ofdata_to_platdata,
352 	.ops = &cw201x_fg_ops,
353 	.priv_auto_alloc_size = sizeof(struct cw201x_info),
354 };
355