xref: /openbmc/u-boot/drivers/power/fuel_gauge/fg_max17042.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1  // SPDX-License-Identifier: GPL-2.0+
2  /*
3   *  Copyright (C) 2012 Samsung Electronics
4   *  Lukasz Majewski <l.majewski@samsung.com>
5   */
6  
7  #include <common.h>
8  #include <power/pmic.h>
9  #include <power/max17042_fg.h>
10  #include <i2c.h>
11  #include <power/max8997_pmic.h>
12  #include <power/power_chrg.h>
13  #include <power/battery.h>
14  #include <power/fg_battery_cell_params.h>
15  #include <errno.h>
16  
fg_write_regs(struct pmic * p,u8 addr,u16 * data,int num)17  static int fg_write_regs(struct pmic *p, u8 addr, u16 *data, int num)
18  {
19  	int ret = 0;
20  	int i;
21  
22  	for (i = 0; i < num; i++, addr++) {
23  		ret = pmic_reg_write(p, addr, *(data + i));
24  		if (ret)
25  			return ret;
26  	}
27  
28  	return 0;
29  }
30  
fg_read_regs(struct pmic * p,u8 addr,u16 * data,int num)31  static int fg_read_regs(struct pmic *p, u8 addr, u16 *data, int num)
32  {
33  	unsigned int dat;
34  	int ret = 0;
35  	int i;
36  
37  	for (i = 0; i < num; i++, addr++) {
38  		ret = pmic_reg_read(p, addr, &dat);
39  		if (ret)
40  			return ret;
41  
42  		*(data + i) = (u16)dat;
43  	}
44  
45  	return 0;
46  }
47  
fg_write_and_verify(struct pmic * p,u8 addr,u16 data)48  static int fg_write_and_verify(struct pmic *p, u8 addr, u16 data)
49  {
50  	unsigned int val = data;
51  	int ret = 0;
52  
53  	ret |= pmic_reg_write(p, addr, val);
54  	ret |= pmic_reg_read(p, addr, &val);
55  
56  	if (ret)
57  		return ret;
58  
59  	if (((u16) val) == data)
60  		return 0;
61  
62  	return -1;
63  }
64  
por_fuelgauge_init(struct pmic * p)65  static void por_fuelgauge_init(struct pmic *p)
66  {
67  	u16 r_data0[16], r_data1[16], r_data2[16];
68  	u32 rewrite_count = 5;
69  	u32 check_count;
70  	u32 lock_count;
71  	u32 i = 0;
72  	u32 val;
73  	s32 ret = 0;
74  	char *status_msg;
75  
76  	/* Delay 500 ms */
77  	mdelay(500);
78  	/* Initilize Configuration */
79  	pmic_reg_write(p, MAX17042_CONFIG, 0x2310);
80  
81  rewrite_model:
82  	check_count = 5;
83  	lock_count = 5;
84  
85  	if (!rewrite_count--) {
86  		status_msg = "init failed!";
87  		goto error;
88  	}
89  
90  	/* Unlock Model Access */
91  	pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
92  	pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
93  
94  	/* Write/Read/Verify the Custom Model */
95  	ret = fg_write_regs(p, MAX17042_MODEL1, cell_character0,
96  			     ARRAY_SIZE(cell_character0));
97  	if (ret)
98  		goto rewrite_model;
99  
100  	ret = fg_write_regs(p, MAX17042_MODEL2, cell_character1,
101  			     ARRAY_SIZE(cell_character1));
102  	if (ret)
103  		goto rewrite_model;
104  
105  	ret = fg_write_regs(p, MAX17042_MODEL3, cell_character2,
106  			     ARRAY_SIZE(cell_character2));
107  	if (ret)
108  		goto rewrite_model;
109  
110  check_model:
111  	if (!check_count--) {
112  		if (rewrite_count)
113  			goto rewrite_model;
114  		else
115  			status_msg = "check failed!";
116  
117  		goto error;
118  	}
119  
120  	ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
121  	if (ret)
122  		goto check_model;
123  
124  	ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
125  	if (ret)
126  		goto check_model;
127  
128  	ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
129  	if (ret)
130  		goto check_model;
131  
132  	for (i = 0; i < 16; i++) {
133  		if ((cell_character0[i] != r_data0[i])
134  		    || (cell_character1[i] != r_data1[i])
135  		    || (cell_character2[i] != r_data2[i]))
136  			goto rewrite_model;
137  		}
138  
139  lock_model:
140  	if (!lock_count--) {
141  		if (rewrite_count)
142  			goto rewrite_model;
143  		else
144  			status_msg = "lock failed!";
145  
146  		goto error;
147  	}
148  
149  	/* Lock model access */
150  	pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_LOCK1);
151  	pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_LOCK2);
152  
153  	/* Verify the model access is locked */
154  	ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
155  	if (ret)
156  		goto lock_model;
157  
158  	ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
159  	if (ret)
160  		goto lock_model;
161  
162  	ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
163  	if (ret)
164  		goto lock_model;
165  
166  	for (i = 0; i < ARRAY_SIZE(r_data0); i++) {
167  		/* Check if model locked */
168  		if (r_data0[i] || r_data1[i] || r_data2[i])
169  			goto lock_model;
170  	}
171  
172  	/* Write Custom Parameters */
173  	fg_write_and_verify(p, MAX17042_RCOMP0, RCOMP0);
174  	fg_write_and_verify(p, MAX17042_TEMPCO, TempCo);
175  
176  	/* Delay at least 350mS */
177  	mdelay(350);
178  
179  	/* Initialization Complete */
180  	pmic_reg_read(p, MAX17042_STATUS, &val);
181  	/* Write and Verify Status with POR bit Cleared */
182  	fg_write_and_verify(p, MAX17042_STATUS, val & ~MAX17042_POR);
183  
184  	/* Delay at least 350 ms */
185  	mdelay(350);
186  
187  	status_msg = "OK!";
188  error:
189  	debug("%s: model init status: %s\n", p->name, status_msg);
190  	return;
191  }
192  
power_update_battery(struct pmic * p,struct pmic * bat)193  static int power_update_battery(struct pmic *p, struct pmic *bat)
194  {
195  	struct power_battery *pb = bat->pbat;
196  	unsigned int val;
197  	int ret = 0;
198  
199  	if (pmic_probe(p)) {
200  		puts("Can't find max17042 fuel gauge\n");
201  		return -ENODEV;
202  	}
203  
204  	ret |= pmic_reg_read(p, MAX17042_VFSOC, &val);
205  	pb->bat->state_of_chrg = (val >> 8);
206  
207  	pmic_reg_read(p, MAX17042_VCELL, &val);
208  	debug("vfsoc: 0x%x\n", val);
209  	pb->bat->voltage_uV = ((val & 0xFFUL) >> 3) + ((val & 0xFF00) >> 3);
210  	pb->bat->voltage_uV = (pb->bat->voltage_uV * 625);
211  
212  	pmic_reg_read(p, 0x05, &val);
213  	pb->bat->capacity = val >> 2;
214  
215  	return ret;
216  }
217  
power_check_battery(struct pmic * p,struct pmic * bat)218  static int power_check_battery(struct pmic *p, struct pmic *bat)
219  {
220  	struct power_battery *pb = bat->pbat;
221  	unsigned int val;
222  	int ret = 0;
223  
224  	if (pmic_probe(p)) {
225  		puts("Can't find max17042 fuel gauge\n");
226  		return -ENODEV;
227  	}
228  
229  	ret |= pmic_reg_read(p, MAX17042_STATUS, &val);
230  	debug("fg status: 0x%x\n", val);
231  
232  	if (val & MAX17042_POR)
233  		por_fuelgauge_init(p);
234  
235  	ret |= pmic_reg_read(p, MAX17042_VERSION, &val);
236  	pb->bat->version = val;
237  
238  	power_update_battery(p, bat);
239  	debug("fg ver: 0x%x\n", pb->bat->version);
240  	printf("BAT: state_of_charge(SOC):%d%%\n",
241  	       pb->bat->state_of_chrg);
242  
243  	printf("     voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
244  	       pb->bat->voltage_uV / 1000000,
245  	       pb->bat->voltage_uV % 1000000,
246  	       pb->bat->capacity);
247  
248  	if (pb->bat->voltage_uV > 3850000)
249  		pb->bat->state = EXT_SOURCE;
250  	else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5)
251  		pb->bat->state = CHARGE;
252  	else
253  		pb->bat->state = NORMAL;
254  
255  	return ret;
256  }
257  
258  static struct power_fg power_fg_ops = {
259  	.fg_battery_check = power_check_battery,
260  	.fg_battery_update = power_update_battery,
261  };
262  
power_fg_init(unsigned char bus)263  int power_fg_init(unsigned char bus)
264  {
265  	static const char name[] = "MAX17042_FG";
266  	struct pmic *p = pmic_alloc();
267  
268  	if (!p) {
269  		printf("%s: POWER allocation error!\n", __func__);
270  		return -ENOMEM;
271  	}
272  
273  	debug("Board Fuel Gauge init\n");
274  
275  	p->name = name;
276  	p->interface = PMIC_I2C;
277  	p->number_of_regs = FG_NUM_OF_REGS;
278  	p->hw.i2c.addr = MAX17042_I2C_ADDR;
279  	p->hw.i2c.tx_num = 2;
280  	p->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG;
281  	p->bus = bus;
282  
283  	p->fg = &power_fg_ops;
284  	return 0;
285  }
286