2 * Copyright (C) 2012 Samsung Electronics
3 * Lukasz Majewski <l.majewski@samsung.com>
5 * SPDX-License-Identifier: GPL-2.0+
9 #include <power/pmic.h>
10 #include <power/max17042_fg.h>
12 #include <power/max8997_pmic.h>
13 #include <power/power_chrg.h>
14 #include <power/battery.h>
15 #include <power/fg_battery_cell_params.h>
18 static int fg_write_regs(struct pmic
*p
, u8 addr
, u16
*data
, int num
)
23 for (i
= 0; i
< num
; i
++, addr
++) {
24 ret
= pmic_reg_write(p
, addr
, *(data
+ i
));
32 static int fg_read_regs(struct pmic
*p
, u8 addr
, u16
*data
, int num
)
38 for (i
= 0; i
< num
; i
++, addr
++) {
39 ret
= pmic_reg_read(p
, addr
, &dat
);
43 *(data
+ i
) = (u16
)dat
;
49 static int fg_write_and_verify(struct pmic
*p
, u8 addr
, u16 data
)
51 unsigned int val
= data
;
54 ret
|= pmic_reg_write(p
, addr
, val
);
55 ret
|= pmic_reg_read(p
, addr
, &val
);
60 if (((u16
) val
) == data
)
66 static void por_fuelgauge_init(struct pmic
*p
)
68 u16 r_data0
[16], r_data1
[16], r_data2
[16];
69 u32 rewrite_count
= 5;
79 /* Initilize Configuration */
80 pmic_reg_write(p
, MAX17042_CONFIG
, 0x2310);
86 if (!rewrite_count
--) {
87 status_msg
= "init failed!";
91 /* Unlock Model Access */
92 pmic_reg_write(p
, MAX17042_MLOCKReg1
, MODEL_UNLOCK1
);
93 pmic_reg_write(p
, MAX17042_MLOCKReg2
, MODEL_UNLOCK2
);
95 /* Write/Read/Verify the Custom Model */
96 ret
= fg_write_regs(p
, MAX17042_MODEL1
, cell_character0
,
97 ARRAY_SIZE(cell_character0
));
101 ret
= fg_write_regs(p
, MAX17042_MODEL2
, cell_character1
,
102 ARRAY_SIZE(cell_character1
));
106 ret
= fg_write_regs(p
, MAX17042_MODEL3
, cell_character2
,
107 ARRAY_SIZE(cell_character2
));
112 if (!check_count
--) {
116 status_msg
= "check failed!";
121 ret
= fg_read_regs(p
, MAX17042_MODEL1
, r_data0
, ARRAY_SIZE(r_data0
));
125 ret
= fg_read_regs(p
, MAX17042_MODEL2
, r_data1
, ARRAY_SIZE(r_data1
));
129 ret
= fg_read_regs(p
, MAX17042_MODEL3
, r_data2
, ARRAY_SIZE(r_data2
));
133 for (i
= 0; i
< 16; i
++) {
134 if ((cell_character0
[i
] != r_data0
[i
])
135 || (cell_character1
[i
] != r_data1
[i
])
136 || (cell_character2
[i
] != r_data2
[i
]))
145 status_msg
= "lock failed!";
150 /* Lock model access */
151 pmic_reg_write(p
, MAX17042_MLOCKReg1
, MODEL_LOCK1
);
152 pmic_reg_write(p
, MAX17042_MLOCKReg2
, MODEL_LOCK2
);
154 /* Verify the model access is locked */
155 ret
= fg_read_regs(p
, MAX17042_MODEL1
, r_data0
, ARRAY_SIZE(r_data0
));
159 ret
= fg_read_regs(p
, MAX17042_MODEL2
, r_data1
, ARRAY_SIZE(r_data1
));
163 ret
= fg_read_regs(p
, MAX17042_MODEL3
, r_data2
, ARRAY_SIZE(r_data2
));
167 for (i
= 0; i
< ARRAY_SIZE(r_data0
); i
++) {
168 /* Check if model locked */
169 if (r_data0
[i
] || r_data1
[i
] || r_data2
[i
])
173 /* Write Custom Parameters */
174 fg_write_and_verify(p
, MAX17042_RCOMP0
, RCOMP0
);
175 fg_write_and_verify(p
, MAX17042_TEMPCO
, TempCo
);
177 /* Delay at least 350mS */
180 /* Initialization Complete */
181 pmic_reg_read(p
, MAX17042_STATUS
, &val
);
182 /* Write and Verify Status with POR bit Cleared */
183 fg_write_and_verify(p
, MAX17042_STATUS
, val
& ~MAX17042_POR
);
185 /* Delay at least 350 ms */
190 debug("%s: model init status: %s\n", p
->name
, status_msg
);
194 static int power_update_battery(struct pmic
*p
, struct pmic
*bat
)
196 struct power_battery
*pb
= bat
->pbat
;
201 puts("Can't find max17042 fuel gauge\n");
205 ret
|= pmic_reg_read(p
, MAX17042_VFSOC
, &val
);
206 pb
->bat
->state_of_chrg
= (val
>> 8);
208 pmic_reg_read(p
, MAX17042_VCELL
, &val
);
209 debug("vfsoc: 0x%x\n", val
);
210 pb
->bat
->voltage_uV
= ((val
& 0xFFUL
) >> 3) + ((val
& 0xFF00) >> 3);
211 pb
->bat
->voltage_uV
= (pb
->bat
->voltage_uV
* 625);
213 pmic_reg_read(p
, 0x05, &val
);
214 pb
->bat
->capacity
= val
>> 2;
219 static int power_check_battery(struct pmic
*p
, struct pmic
*bat
)
221 struct power_battery
*pb
= bat
->pbat
;
226 puts("Can't find max17042 fuel gauge\n");
230 ret
|= pmic_reg_read(p
, MAX17042_STATUS
, &val
);
231 debug("fg status: 0x%x\n", val
);
233 if (val
& MAX17042_POR
)
234 por_fuelgauge_init(p
);
236 ret
|= pmic_reg_read(p
, MAX17042_VERSION
, &val
);
237 pb
->bat
->version
= val
;
239 power_update_battery(p
, bat
);
240 debug("fg ver: 0x%x\n", pb
->bat
->version
);
241 printf("BAT: state_of_charge(SOC):%d%%\n",
242 pb
->bat
->state_of_chrg
);
244 printf(" voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
245 pb
->bat
->voltage_uV
/ 1000000,
246 pb
->bat
->voltage_uV
% 1000000,
249 if (pb
->bat
->voltage_uV
> 3850000)
250 pb
->bat
->state
= EXT_SOURCE
;
251 else if (pb
->bat
->voltage_uV
< 3600000 || pb
->bat
->state_of_chrg
< 5)
252 pb
->bat
->state
= CHARGE
;
254 pb
->bat
->state
= NORMAL
;
259 static struct power_fg power_fg_ops
= {
260 .fg_battery_check
= power_check_battery
,
261 .fg_battery_update
= power_update_battery
,
264 int power_fg_init(unsigned char bus
)
266 static const char name
[] = "MAX17042_FG";
267 struct pmic
*p
= pmic_alloc();
270 printf("%s: POWER allocation error!\n", __func__
);
274 debug("Board Fuel Gauge init\n");
277 p
->interface
= PMIC_I2C
;
278 p
->number_of_regs
= FG_NUM_OF_REGS
;
279 p
->hw
.i2c
.addr
= MAX17042_I2C_ADDR
;
280 p
->hw
.i2c
.tx_num
= 2;
281 p
->sensor_byte_order
= PMIC_SENSOR_BYTE_ORDER_BIG
;
284 p
->fg
= &power_fg_ops
;