locks: add new fcntl cmd values for handling file private locks
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / drivers / battery / sm5703_fuelgauge.c
CommitLineData
3c2a0909
S
1/* drivers/battery/sm5703_fuelgauge.c
2 * SM5703 Voltage Tracking Fuelgauge Driver
3 *
4 * Copyright (C) 2013
5 * Author: Dongik Sin <dongik.sin@samsung.com>
6 * Modified by SW Jung
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 */
13#include <linux/battery/fuelgauge/sm5703_fuelgauge.h>
14#include <linux/battery/fuelgauge/sm5703_fuelgauge_impl.h>
15#if defined(CONFIG_STMP_SUPPORT_FG_ALERT)
16#include <linux/input/stmpe1801_key.h>
17#endif
18#include <linux/uaccess.h>
19#include <linux/of.h>
20#include <linux/of_gpio.h>
21#include <linux/fs.h>
22#include <linux/math64.h>
23#include <linux/compiler.h>
24
25#define FG_DET_BAT_PRESENT 1
26
27#define MINVAL(a, b) ((a <= b) ? a : b)
28
29static void sm5703_fuelgauge_fuelalert_init(struct sm5703_fuelgauge_data *fuelgauge,
30 int soc);
31
32static void fg_vbatocv_check(struct i2c_client *client);
33
34enum battery_table_type {
35 DISCHARGE_TABLE = 0,
36 CHARGE_TABLE,
37 Q_TABLE,
38 TABLE_MAX,
39};
40
41static enum power_supply_property sm5703_fuelgauge_props[] = {
42 POWER_SUPPLY_PROP_STATUS,
43 POWER_SUPPLY_PROP_VOLTAGE_NOW,
44 POWER_SUPPLY_PROP_VOLTAGE_AVG,
45 POWER_SUPPLY_PROP_CURRENT_NOW,
46 POWER_SUPPLY_PROP_CURRENT_AVG,
47 POWER_SUPPLY_PROP_CHARGE_FULL,
48 POWER_SUPPLY_PROP_ENERGY_NOW,
49 POWER_SUPPLY_PROP_CAPACITY,
50 POWER_SUPPLY_PROP_TEMP,
51 POWER_SUPPLY_PROP_TEMP_AMBIENT,
52};
53
54static bool sm5703_fg_reg_init(struct sm5703_fuelgauge_data *fuelgauge,
55 int manual_ocv_write);
56
57static inline int sm5703_fg_read_device(struct i2c_client *client,
58 int reg, int bytes, void *dest)
59{
60 int ret;
61
62 if (bytes > 1)
63 ret = i2c_smbus_read_i2c_block_data(client, reg, bytes, dest);
64 else {
65 ret = i2c_smbus_read_byte_data(client, reg);
66 if (ret < 0)
67 return ret;
68 *(unsigned char *)dest = (unsigned char)ret;
69 }
70 return ret;
71}
72
73static int32_t sm5703_fg_i2c_read_word(struct i2c_client *client,
74 uint8_t reg_addr)
75{
76 uint16_t data = 0;
77 int ret;
78 ret = sm5703_fg_read_device(client, reg_addr, 2, &data);
79 /* dev_dbg(&client->dev, "%s: ret = %d, addr = 0x%x, data = 0x%x\n",
80 __func__, ret, reg_addr, data); */
81
82 if (ret < 0)
83 return ret;
84 else
85 return data;
86
87 /* not use big endian */
88 /* return (int32_t)be16_to_cpu(data); */
89}
90
91static int32_t sm5703_fg_i2c_write_word(struct i2c_client *client,
92 uint8_t reg_addr,uint16_t data)
93{
94 int ret;
95
96 /* not use big endian */
97 /* data = cpu_to_be16(data); */
98 ret = i2c_smbus_write_i2c_block_data(client, reg_addr,
99 2, (uint8_t *)&data);
100
101 /* dev_dbg(&client->dev, "%s: ret = %d, addr = 0x%x, data = 0x%x\n",
102 __func__, ret, reg_addr, data);
103 */
104
105 return ret;
106}
107
108#if 0
109static void sm5703_pr_ver_info(struct i2c_client *client)
110{
111 dev_info(&client->dev, "SM5703 Fuel-Gauge Ver %s\n", FG_DRIVER_VER);
112}
113#endif
114
115static void sm5703_fg_test_read(struct i2c_client *client)
116{
117 int ret, ret1, ret2, ret3, ret4;
118
119 ret = sm5703_fg_i2c_read_word(client, 0x30);
120 dev_info(&client->dev, "%s: sm5703 FG 0x30 = 0x%x \n", __func__, ret);
121 ret = sm5703_fg_i2c_read_word(client, 0x31);
122 dev_info(&client->dev, "%s: sm5703 FG 0x31 = 0x%x \n", __func__, ret);
123 ret = sm5703_fg_i2c_read_word(client, 0x32);
124 dev_info(&client->dev, "%s: sm5703 FG 0x32 = 0x%x \n", __func__, ret);
125 ret = sm5703_fg_i2c_read_word(client, 0x33);
126 dev_info(&client->dev, "%s: sm5703 FG 0x33 = 0x%x \n", __func__, ret);
127 ret = sm5703_fg_i2c_read_word(client, 0x34);
128 dev_info(&client->dev, "%s: sm5703 FG 0x34 = 0x%x \n", __func__, ret);
129 ret = sm5703_fg_i2c_read_word(client, 0x35);
130 dev_info(&client->dev, "%s: sm5703 FG 0x35 = 0x%x \n", __func__, ret);
131 ret = sm5703_fg_i2c_read_word(client, 0x36);
132 dev_info(&client->dev, "%s: sm5703 FG 0x36 = 0x%x \n", __func__, ret);
133 ret = sm5703_fg_i2c_read_word(client, 0x37);
134 dev_info(&client->dev, "%s: sm5703 FG 0x37 = 0x%x \n", __func__, ret);
135
136 ret = sm5703_fg_i2c_read_word(client, 0x40);
137 dev_info(&client->dev, "%s: sm5703 FG 0x40 = 0x%x \n", __func__, ret);
138 ret = sm5703_fg_i2c_read_word(client, 0x41);
139 dev_info(&client->dev, "%s: sm5703 FG 0x41 = 0x%x \n", __func__, ret);
140 ret = sm5703_fg_i2c_read_word(client, 0x42);
141 dev_info(&client->dev, "%s: sm5703 FG 0x42 = 0x%x \n", __func__, ret);
142 ret = sm5703_fg_i2c_read_word(client, 0x43);
143 dev_info(&client->dev, "%s: sm5703 FG 0x43 = 0x%x \n", __func__, ret);
144
145 ret1 = sm5703_fg_i2c_read_word(client, 0xAC);
146 ret2 = sm5703_fg_i2c_read_word(client, 0xAD);
147 ret3 = sm5703_fg_i2c_read_word(client, 0xAE);
148 ret4 = sm5703_fg_i2c_read_word(client, 0xAF);
149 pr_info("0xAC=0x%04x, 0xAD=0x%04x, 0xAE=0x%04x, 0xAF=0x%04x \n", ret1, ret2, ret3, ret4);
150
151 ret1 = sm5703_fg_i2c_read_word(client, 0xBC);
152 ret2 = sm5703_fg_i2c_read_word(client, 0xBD);
153 ret3 = sm5703_fg_i2c_read_word(client, 0xBE);
154 ret4 = sm5703_fg_i2c_read_word(client, 0xBF);
155 pr_info("0xBC=0x%04x, 0xBD=0x%04x, 0xBE=0x%04x, 0xBF=0x%04x \n", ret1, ret2, ret3, ret4);
156
157 ret1 = sm5703_fg_i2c_read_word(client, 0xCC);
158 ret2 = sm5703_fg_i2c_read_word(client, 0xCD);
159 ret3 = sm5703_fg_i2c_read_word(client, 0xCE);
160 ret4 = sm5703_fg_i2c_read_word(client, 0xCF);
161 pr_info("0xCC=0x%04x, 0xCD=0x%04x, 0xCE=0x%04x, 0xCF=0x%04x \n", ret1, ret2, ret3, ret4);
162
163 ret1 = sm5703_fg_i2c_read_word(client, 0x85);
164 ret2 = sm5703_fg_i2c_read_word(client, 0x86);
165 ret3 = sm5703_fg_i2c_read_word(client, 0x87);
166 ret4 = sm5703_fg_i2c_read_word(client, 0x28);
167 pr_info("0x85=0x%04x, 0x86=0x%04x, 0x87=0x%04x, 0x28=0x%04x \n", ret1, ret2, ret3, ret4);
168}
169
170static int sm5703_get_temperature(struct sm5703_fuelgauge_data *fuelgauge)
171{
172 int ret;
173
174 int temp;/* = 250; 250 means 25.0oC*/
175 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_TEMPERATURE);
176 if (ret<0) {
177 pr_err("%s: read temp reg fail", __func__);
178 temp = 0;
179 } else {
180 /* integer bit */
181 temp = ((ret & 0x7F00) >> 8) * 10;
182 /* integer + fractional bit */
183 temp = temp + (((ret & 0x00ff) * 10) / 256);
184 if (ret & 0x8000) {
185 temp *= -1;
186 }
187 }
188 fuelgauge->info.temperature = temp;
189
190 dev_info(&fuelgauge->i2c->dev,
191 "%s: read = 0x%x, temperature = %d\n", __func__, ret, temp);
192
193 return temp;
194}
195
196static unsigned int sm5703_get_ocv(struct sm5703_fuelgauge_data *fuelgauge)
197{
198 int ret;
199 unsigned int ocv;/* = 3500; 3500 means 3500mV */
200 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_OCV);
201 if (ret<0) {
202 pr_err("%s: read ocv reg fail\n", __func__);
203 ocv = 4000;
204 } else {
205 /* integer bit */
206 ocv = ((ret&0x0700)>>8) * 1000;
207 /* integer + fractional bit */
208 ocv = ocv + (((ret&0x00ff)*1000)/256);
209 }
210
211 fuelgauge->info.batt_ocv = ocv;
212
213 dev_info(&fuelgauge->i2c->dev, "%s: read = 0x%x, ocv = %d\n", __func__, ret, ocv);
214
215 return ocv;
216}
217
218static u32 sm5703_get_soc(struct sm5703_fuelgauge_data *fuelgauge)
219{
220 int ret;
221 u32 soc;
222 int ta_exist;
223 int curr_cal;
224 int temp_cal_fact;
225 union power_supply_propval value;
226
227 fg_vbatocv_check(fuelgauge->i2c);
228
229 ta_exist = fuelgauge->is_charging && (fuelgauge->info.batt_current >= 0);
230
231 dev_dbg(&fuelgauge->i2c->dev, "%s: is_charging = %d, ta_exist = %d\n", __func__, fuelgauge->is_charging, ta_exist);
232
233 if(ta_exist)
234 curr_cal = fuelgauge->info.curr_cal + (fuelgauge->info.charge_offset_cal << 8);
235 else
236 curr_cal = fuelgauge->info.curr_cal;
237 dev_dbg(&fuelgauge->i2c->dev, "%s: curr_cal = 0x%x\n", __func__, curr_cal);
238
239 /* abnormal case.... SW reset */
240 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_FG_OP_STATUS);
241 if ((ret & 0x00FF) != DISABLE_RE_INIT) {
242 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_CNTL);
243 pr_info( "%s: SM5703 FG abnormal case!!!! SM5703_REG_CNTL : 0x%x\n", __func__, ret);
244 if (ret == 0x2008) {
245 pr_info( "%s: SM5703 FG abnormal case.... SW reset\n", __func__);
246 /* SW reset code */
247 sm5703_fg_i2c_write_word(fuelgauge->i2c, 0x90, 0x0008);
248 /* delay 200ms */
249 msleep(200);
250 /* init code */
251 sm5703_fg_reg_init(fuelgauge, 1);
252 }
253 }
254
255 sm5703_get_temperature(fuelgauge);
256 sm5703_get_ocv(fuelgauge);
257 temp_cal_fact = fuelgauge->info.temp_std - (fuelgauge->info.temperature / 10);
258 temp_cal_fact = temp_cal_fact / fuelgauge->info.temp_offset;
259 temp_cal_fact = temp_cal_fact * fuelgauge->info.temp_offset_cal;
260 curr_cal = curr_cal + (temp_cal_fact << 8);
261
262 /* compensate soc in case of low bat_temp */
263 psy_do_property("battery", get, POWER_SUPPLY_PROP_TEMP, value);
264 if ((value.intval / 10) < 25) {
265 curr_cal = curr_cal + ((((25 - (value.intval / 10)) / 6) * 3) << 8);
266 }
267
268 dev_info(&fuelgauge->i2c->dev, "%s: fg_get_soc : temp_std = %d, temperature = %d, temp_offset = %d, temp_offset_cal = 0x%x, curr_cal = 0x%x, bat_temp = %d\n",
269 __func__, fuelgauge->info.temp_std, fuelgauge->info.temperature, fuelgauge->info.temp_offset, fuelgauge->info.temp_offset_cal, curr_cal, value.intval);
270
271 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_CURR_CAL, curr_cal);
272
273 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_SOC);
274 if (ret < 0) {
275 pr_err("%s: read soc reg fail\n", __func__);
276 soc = 500;
277 } else {
278 /* integer bit */
279 soc = ((ret & 0xff00) >> 8) * 10;
280 /* integer + fractional bit */
281 soc = soc + (((ret & 0x00ff) * 10) / 256);
282 }
283
284 fuelgauge->info.batt_soc = soc;
285
286 dev_info(&fuelgauge->i2c->dev, "%s: read = 0x%x, soc = %d\n", __func__, ret, soc);
287
288 /* temp for SM5703 FG debug */
289 sm5703_fg_test_read(fuelgauge->i2c);
290
291 return soc;
292}
293
294static unsigned int sm5703_get_vbat(struct sm5703_fuelgauge_data *fuelgauge)
295{
296 int ret;
297
298 unsigned int vbat;/* = 3500; 3500 means 3500mV*/
299 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_VOLTAGE);
300 if (ret < 0) {
301 pr_err("%s: read vbat reg fail", __func__);
302 vbat = 4000;
303 } else {
304 /* integer bit */
305 vbat = ((ret & 0x0700) >> 8) * 1000;
306 /* integer + fractional bit */
307 vbat = vbat + (((ret&0x00ff) * 1000) / 256);
308 }
309
310 fuelgauge->info.batt_voltage = vbat;
311
312 if ((fuelgauge->force_dec_mode == SM5703_COLD_MODE) && vbat > 3400) {
313 fuelgauge->force_dec_mode = SM5703_RECOVERY_MODE;
314 wake_unlock(&fuelgauge->fuel_alert_wake_lock);
315 sm5703_fuelgauge_fuelalert_init(fuelgauge,
316 fuelgauge->pdata->fuel_alert_soc);
317 pr_info("%s : COLD MODE DISABLE\n", __func__);
318 }
319
320 dev_dbg(&fuelgauge->i2c->dev, "%s: read = 0x%x, vbat = %d\n", __func__, ret, vbat);
321
322 return vbat;
323}
324
325static unsigned int sm5703_get_avgvbat(struct sm5703_fuelgauge_data *fuelgauge)
326{
327 int ret, cnt;
328 u32 vbat; /* = 3500; 3500 means 3500mV*/
329 u32 old_vbat = 0;
330
331 for (cnt = 0; cnt < 5; cnt++) {
332 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_VOLTAGE);
333 if (ret < 0) {
334 pr_err("%s: read vbat reg fail", __func__);
335 vbat = 4000;
336 } else {
337 /* integer bit */
338 vbat = ((ret & 0x0700) >> 8) * 1000;
339 /* integer + fractional bit */
340 vbat = vbat + (((ret&0x00ff) * 1000) / 256);
341 }
342
343 if (cnt == 0)
344 old_vbat = vbat;
345 else
346 old_vbat = vbat / 2 + old_vbat / 2;
347 }
348
349 fuelgauge->info.batt_avgvoltage = old_vbat;
350 dev_dbg(&fuelgauge->i2c->dev, "%s: batt_avgvoltage = %d\n",
351 __func__, fuelgauge->info.batt_avgvoltage);
352
353 return old_vbat;
354}
355
356static int sm5703_get_curr(struct sm5703_fuelgauge_data *fuelgauge)
357{
358 int ret;
359 int curr;/* = 1000; 1000 means 1000mA*/
360
361 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_CURRENT);
362 if (ret<0) {
363 pr_err("%s: read curr reg fail", __func__);
364 curr = 0;
365 } else {
366 /* integer bit */
367 curr = ((ret&0x0700) >> 8) * 1000;
368 /* integer + fractional bit */
369 curr = curr + (((ret & 0x00ff) * 1000) / 256);
370 if(ret & 0x8000) {
371 curr *= -1;
372 }
373 }
374
375 fuelgauge->info.batt_current = curr;
376 dev_dbg(&fuelgauge->i2c->dev, "%s: read = 0x%x, curr = %d\n",
377 __func__, ret, curr);
378
379 return curr;
380}
381
382static int sm5703_get_avgcurr(struct sm5703_fuelgauge_data *fuelgauge)
383{
384 int ret, cnt;
385 int curr;/* = 1000; 1000 means 1000mA*/
386 int old_curr = 0;
387
388 for (cnt = 0; cnt < 5; cnt++) {
389 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_CURRENT);
390 if (ret < 0) {
391 pr_err("%s: read curr reg fail", __func__);
392 curr = 0;
393 } else {
394 /* integer bit */
395 curr = ((ret&0x0700) >> 8) * 1000;
396 /* integer + fractional bit */
397 curr = curr + (((ret & 0x00ff) * 1000) / 256);
398 if(ret & 0x8000) {
399 curr *= -1;
400 }
401 }
402
403 if (cnt == 0)
404 old_curr = curr;
405 else
406 old_curr = curr / 2 + old_curr / 2;
407 }
408
409 fuelgauge->info.batt_avgcurrent = old_curr;
410 dev_dbg(&fuelgauge->i2c->dev, "%s: batt_avgcurrent = %d\n",
411 __func__, fuelgauge->info.batt_avgcurrent);
412
413 return old_curr;
414}
415
416
417static unsigned int sm5703_get_device_id(struct i2c_client *client)
418{
419 int ret;
420 ret = sm5703_fg_i2c_read_word(client, SM5703_REG_DEVICE_ID);
421 /* ret &= 0x00ff; */
422
423 dev_info(&client->dev, "%s: device_id = 0x%x\n", __func__, ret);
424
425 return ret;
426}
427
428static bool sm5703_fg_check_reg_init_need(struct i2c_client *client)
429{
430 int ret;
431
432 ret = sm5703_fg_i2c_read_word(client, SM5703_REG_FG_OP_STATUS);
433
434 if((ret & 0x00FF) == DISABLE_RE_INIT) {
435 dev_dbg(&client->dev, "%s: return 0\n", __func__);
436 return 0;
437 } else {
438 dev_dbg(&client->dev, "%s: return 1\n", __func__);
439 return 1;
440 }
441}
442
443static int calculate_iocv(struct i2c_client *client)
444{
445 int i;
446 int max=0, min=0, sum=0, l_avg=0, s_avg=0, l_minmax_offset=0;
447 int ret=0;
448
449 for (i = SM5703_REG_IOCV_B_L_MIN; i <= SM5703_REG_IOCV_B_L_MAX; i++) {
450 ret = sm5703_fg_i2c_read_word(client, i);
451 if (i == SM5703_REG_IOCV_B_L_MIN) {
452 max = ret;
453 min = ret;
454 sum = ret;
455 } else {
456 if(ret > max)
457 max = ret;
458 else if(ret < min)
459 min = ret;
460 sum = sum + ret;
461 }
462 }
463 sum = sum - max - min;
464 l_minmax_offset = max - min;
465 l_avg = sum / (SM5703_REG_IOCV_B_L_MAX-SM5703_REG_IOCV_B_L_MIN-1);
466 dev_info(&client->dev,
467 "%s: iocv_l_max=0x%x, iocv_l_min=0x%x, iocv_l_sum=0x%x, iocv_l_avg=0x%x \n",
468 __func__, max, min, sum, l_avg);
469
470 ret = sm5703_fg_i2c_read_word(client, SM5703_REG_END_V_IDX);
471 pr_info("%s: iocv_status_read = addr : 0x%x , data : 0x%x\n",
472 __func__, SM5703_REG_END_V_IDX, ret);
473
474 if ((ret & 0x0030) == 0x0030) {
475 for (i = SM5703_REG_IOCV_B_S_MIN; i <= SM5703_REG_IOCV_B_S_MAX; i++) {
476 ret = sm5703_fg_i2c_read_word(client, i);
477 if (i == SM5703_REG_IOCV_B_S_MIN) {
478 max = ret;
479 min = ret;
480 sum = ret;
481 } else {
482 if(ret > max)
483 max = ret;
484 else if(ret < min)
485 min = ret;
486 sum = sum + ret;
487 }
488 }
489 sum = sum - max - min;
490 s_avg = sum / (SM5703_REG_IOCV_B_S_MAX-SM5703_REG_IOCV_B_S_MIN-1);
491 dev_info(&client->dev,
492 "%s: iocv_s_max=0x%x, iocv_s_min=0x%x, iocv_s_sum=0x%x, iocv_s_avg=0x%x \n",
493 __func__, max, min, sum, s_avg);
494 }
495
496 if (((abs(l_avg - s_avg) > 0x29) && (l_minmax_offset < 0xCC)) || (s_avg == 0)){
497 ret = l_avg;
498 } else {
499 ret = s_avg;
500 }
501
502 return ret;
503}
504
505static void fg_vbatocv_check(struct i2c_client *client)
506{
507 int ret;
508 int ta_exist;
509 union power_supply_propval value;
510 struct sm5703_fuelgauge_data *fuelgauge = i2c_get_clientdata(client);
511
512 ta_exist = fuelgauge->is_charging && (fuelgauge->info.batt_current >= 0);
513
514 /* iocv error case cover start */
515 if ((abs(fuelgauge->info.batt_current) < 40) ||
516 ((ta_exist) &&
517 (abs(fuelgauge->info.batt_current) < 100))) {
518 /* 30mV over */
519 if(abs(fuelgauge->info.batt_ocv-fuelgauge->info.batt_voltage) > 30) {
520 fuelgauge->info.iocv_error_count ++;
521 }
522 if(fuelgauge->info.iocv_error_count > 5) /* prevent to overflow */
523 fuelgauge->info.iocv_error_count = 6;
524 } else {
525 fuelgauge->info.iocv_error_count = 0;
526 }
527
528 dev_info(&client->dev, "%s: iocv_error_count (%d)\n",
529 __func__, fuelgauge->info.iocv_error_count);
530
531 if (fuelgauge->info.iocv_error_count > 5) {
532 dev_info(&client->dev,
533 "%s: p_v - v = (%d)\n", __func__,
534 fuelgauge->info.p_batt_voltage - fuelgauge->info.batt_voltage);
535
536 if (abs(fuelgauge->info.p_batt_voltage - fuelgauge->info.batt_voltage)>15) { /* 15mV over */
537 fuelgauge->info.iocv_error_count = 0;
538 } else {
539 /* mode change to mix RS manual mode */
540 dev_info(&client->dev, "%s: mode change to mix RS manual mode\n", __func__);
541 /* RS manual value write */
542 sm5703_fg_i2c_write_word(client, SM5703_REG_RS_MAN, fuelgauge->info.rs_value[0]);
543 /* run update */
544 sm5703_fg_i2c_write_word(client, SM5703_REG_PARAM_RUN_UPDATE, 0);
545 sm5703_fg_i2c_write_word(client, SM5703_REG_PARAM_RUN_UPDATE, 1);
546 /* mode change */
547 ret = sm5703_fg_i2c_read_word(client, SM5703_REG_CNTL);
548 ret = (ret | ENABLE_MIX_MODE) | ENABLE_RS_MAN_MODE; /* +RS_MAN_MODE */
549 sm5703_fg_i2c_write_word(client, SM5703_REG_CNTL, ret);
550 }
551 } else {
552 psy_do_property("battery", get, POWER_SUPPLY_PROP_TEMP, value);
553 if((value.intval / 10) > 15)
554 {
555 if((fuelgauge->info.p_batt_voltage < fuelgauge->info.n_tem_poff) &&
556 (fuelgauge->info.batt_voltage < fuelgauge->info.n_tem_poff) &&
557 (!ta_exist)) {
558 dev_info(&client->dev,
559 "%s: mode change to normal tem mix RS manual mode\n", __func__);
560 /* mode change to mix RS manual mode */
561 /* RS manual value write */
562 if((fuelgauge->info.p_batt_voltage < (fuelgauge->info.n_tem_poff - fuelgauge->info.n_tem_poff_offset)) &&
563 (fuelgauge->info.batt_voltage < (fuelgauge->info.n_tem_poff - fuelgauge->info.n_tem_poff_offset))) {
564 sm5703_fg_i2c_write_word(client, SM5703_REG_RS_MAN, fuelgauge->info.rs_value[0]>>1);
565 } else {
566 sm5703_fg_i2c_write_word(client, SM5703_REG_RS_MAN, fuelgauge->info.rs_value[0]);
567 }
568 /* run update*/
569 sm5703_fg_i2c_write_word(client, SM5703_REG_PARAM_RUN_UPDATE, 0);
570 sm5703_fg_i2c_write_word(client, SM5703_REG_PARAM_RUN_UPDATE, 1);
571
572 /* mode change */
573 ret = sm5703_fg_i2c_read_word(client, SM5703_REG_CNTL);
574 ret = (ret | ENABLE_MIX_MODE) | ENABLE_RS_MAN_MODE; // +RS_MAN_MODE
575 sm5703_fg_i2c_write_word(client, SM5703_REG_CNTL, ret);
576 } else {
577 dev_info(&client->dev, "%s: mode change to mix RS auto mode\n", __func__);
578
579 /* mode change to mix RS auto mode */
580 ret = sm5703_fg_i2c_read_word(client, SM5703_REG_CNTL);
581 ret = (ret | ENABLE_MIX_MODE) & ~ENABLE_RS_MAN_MODE; // -RS_MAN_MODE
582 sm5703_fg_i2c_write_word(client, SM5703_REG_CNTL, ret);
583 }
584 } else {
585 if((fuelgauge->info.p_batt_voltage < fuelgauge->info.l_tem_poff) &&
586 (fuelgauge->info.batt_voltage < fuelgauge->info.l_tem_poff) &&
587 (!ta_exist)) {
588 dev_info(&client->dev,
589 "%s: mode change to normal tem mix RS manual mode\n", __func__);
590 /* mode change to mix RS manual mode */
591 /* RS manual value write */
592 if((fuelgauge->info.p_batt_voltage < (fuelgauge->info.l_tem_poff - fuelgauge->info.l_tem_poff_offset)) &&
593 (fuelgauge->info.batt_voltage < (fuelgauge->info.l_tem_poff - fuelgauge->info.l_tem_poff_offset))) {
594 sm5703_fg_i2c_write_word(client, SM5703_REG_RS_MAN, fuelgauge->info.rs_value[0]>>1);
595 } else {
596 sm5703_fg_i2c_write_word(client, SM5703_REG_RS_MAN, fuelgauge->info.rs_value[0]);
597 }
598 /* run update */
599 sm5703_fg_i2c_write_word(client, SM5703_REG_PARAM_RUN_UPDATE, 0);
600 sm5703_fg_i2c_write_word(client, SM5703_REG_PARAM_RUN_UPDATE, 1);
601
602 /* mode change */
603 ret = sm5703_fg_i2c_read_word(client, SM5703_REG_CNTL);
604 ret = (ret | ENABLE_MIX_MODE) | ENABLE_RS_MAN_MODE; /* +RS_MAN_MODE */
605 sm5703_fg_i2c_write_word(client, SM5703_REG_CNTL, ret);
606 } else {
607 dev_info(&client->dev, "%s: mode change to mix RS auto mode\n", __func__);
608
609 /* mode change to mix RS auto mode */
610 ret = sm5703_fg_i2c_read_word(client, SM5703_REG_CNTL);
611 ret = (ret | ENABLE_MIX_MODE) & ~ENABLE_RS_MAN_MODE; /* -RS_MAN_MODE */
612 sm5703_fg_i2c_write_word(client, SM5703_REG_CNTL, ret);
613 }
614 }
615 }
616 fuelgauge->info.p_batt_voltage = fuelgauge->info.batt_voltage;
617 fuelgauge->info.p_batt_current = fuelgauge->info.batt_current;
618 /* iocv error case cover end */
619}
620
621/* capacity is 0.1% unit */
622static void sm5703_fg_get_scaled_capacity(
623 struct sm5703_fuelgauge_data *fuelgauge,
624 union power_supply_propval *val)
625{
626 val->intval = (val->intval < fuelgauge->pdata->capacity_min) ?
627 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 /
628 (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min));
629
630 dev_dbg(&fuelgauge->i2c->dev,
631 "%s: scaled capacity (%d.%d)\n",
632 __func__, val->intval/10, val->intval%10);
633}
634
635/* capacity is integer */
636static void sm5703_fg_get_atomic_capacity(
637 struct sm5703_fuelgauge_data *fuelgauge,
638 union power_supply_propval *val)
639{
640 if (fuelgauge->pdata->capacity_calculation_type &
641 SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC) {
642 if (fuelgauge->capacity_old < val->intval)
643 val->intval = fuelgauge->capacity_old + 1;
644 else if (fuelgauge->capacity_old > val->intval)
645 val->intval = fuelgauge->capacity_old - 1;
646 }
647
648 /* keep SOC stable in abnormal status */
649 if (fuelgauge->pdata->capacity_calculation_type &
650 SEC_FUELGAUGE_CAPACITY_TYPE_SKIP_ABNORMAL) {
651 if (!fuelgauge->is_charging &&
652 fuelgauge->capacity_old < val->intval) {
653 dev_err(&fuelgauge->i2c->dev,
654 "%s: capacity (old %d : new %d)\n",
655 __func__, fuelgauge->capacity_old, val->intval);
656 val->intval = fuelgauge->capacity_old;
657 }
658 }
659
660 /* updated old capacity */
661 fuelgauge->capacity_old = val->intval;
662}
663
664static int sm5703_fg_check_capacity_max(
665 struct sm5703_fuelgauge_data *fuelgauge, int capacity_max)
666{
667 int new_capacity_max = capacity_max;
668
669 if (new_capacity_max < (fuelgauge->pdata->capacity_max -
670 fuelgauge->pdata->capacity_max_margin - 10)) {
671 new_capacity_max =
672 (fuelgauge->pdata->capacity_max -
673 fuelgauge->pdata->capacity_max_margin);
674
675 dev_info(&fuelgauge->i2c->dev, "%s: set capacity max(%d --> %d)\n",
676 __func__, capacity_max, new_capacity_max);
677 } else if (new_capacity_max > (fuelgauge->pdata->capacity_max +
678 fuelgauge->pdata->capacity_max_margin)) {
679 new_capacity_max =
680 (fuelgauge->pdata->capacity_max +
681 fuelgauge->pdata->capacity_max_margin);
682
683 dev_info(&fuelgauge->i2c->dev, "%s: set capacity max(%d --> %d)\n",
684 __func__, capacity_max, new_capacity_max);
685 }
686
687 return new_capacity_max;
688}
689
690static int sm5703_fg_calculate_dynamic_scale(
691 struct sm5703_fuelgauge_data *fuelgauge, int capacity)
692{
693 union power_supply_propval raw_soc_val;
694 raw_soc_val.intval = sm5703_get_soc(fuelgauge);
695
696 if (raw_soc_val.intval <
697 fuelgauge->pdata->capacity_max -
698 fuelgauge->pdata->capacity_max_margin) {
699 fuelgauge->capacity_max =
700 fuelgauge->pdata->capacity_max -
701 fuelgauge->pdata->capacity_max_margin;
702 pr_info("%s: capacity_max (%d)", __func__,
703 fuelgauge->capacity_max);
704 } else {
705 fuelgauge->capacity_max =
706 (raw_soc_val.intval >
707 fuelgauge->pdata->capacity_max +
708 fuelgauge->pdata->capacity_max_margin) ?
709 (fuelgauge->pdata->capacity_max +
710 fuelgauge->pdata->capacity_max_margin) :
711 raw_soc_val.intval;
712 pr_info("%s: raw soc (%d)", __func__,
713 fuelgauge->capacity_max);
714 }
715
716 if (capacity != 100) {
717 fuelgauge->capacity_max = sm5703_fg_check_capacity_max(
718 fuelgauge, (fuelgauge->capacity_max * 100 / capacity));
719 fuelgauge->capacity_old = capacity;
720 } else {
721 fuelgauge->capacity_max =
722 (fuelgauge->capacity_max * 99 / 100);
723
724 sm5703_fg_get_scaled_capacity(fuelgauge, &raw_soc_val);
725 fuelgauge->capacity_old = min((raw_soc_val.intval / 10), 100);
726 }
727
728 pr_info("%s: %d is used for capacity_max, capacity(%d)\n",
729 __func__, fuelgauge->capacity_max, capacity);
730
731 return fuelgauge->capacity_max;
732}
733
734static void sm5703_fuelgauge_fuelalert_init(struct sm5703_fuelgauge_data *fuelgauge,
735 int soc)
736{
737 int ret;
738
739 dev_dbg(&fuelgauge->i2c->dev, "%s: sec_hal_fg_fuelalert_init\n", __func__);
740
741 /* remove interrupt */
742 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_INTFG);
743
744 /* check status ? need add action */
745 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_STATUS);
746
747 /* remove all mask */
748 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_INTFG_MASK, 0);
749
750 /* set volt and soc alert threshold */
751 ret = 0x0320; /* 3125mV */
752 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_V_ALARM, ret);
753
754 ret = soc << 8;
755 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_SOC_ALARM, ret);
756
757 /* update parameters */
758 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_PARAM_RUN_UPDATE, 0);
759 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_PARAM_RUN_UPDATE, 1);
760
761 /* enable low soc, low voltage alert */
762 fuelgauge->info.irq_ctrl = ENABLE_L_SOC_INT | ENABLE_L_VOL_INT;
763 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_CNTL);
764 ret = (ret & 0xFFF0) | fuelgauge->info.irq_ctrl;
765 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_CNTL, ret);
766
767 /* reset soc alert flag */
768 fuelgauge->info.soc_alert_flag = false;
769 fuelgauge->is_fuel_alerted = false;
770
771 return;
772}
773
774static bool sm5703_fg_reg_init(struct sm5703_fuelgauge_data *fuelgauge,
775 int manual_ocv_write)
776{
777 int i, j, value, ret;
778 uint8_t table_reg;
779
780 dev_info(&fuelgauge->i2c->dev, "%s: sm5703_fg_reg_init START!!\n", __func__);
781
782 /* start first param_ctrl unlock */
783 sm5703_fg_i2c_write_word(fuelgauge->i2c,
784 SM5703_REG_PARAM_CTRL, SM5703_FG_PARAM_UNLOCK_CODE);
785
786 /* RCE write */
787 for (i = 0; i < 3; i++) {
788 sm5703_fg_i2c_write_word(fuelgauge->i2c,
789 SM5703_REG_RCE0+i, fuelgauge->info.rce_value[i]);
790 dev_dbg(&fuelgauge->i2c->dev,
791 "%s: RCE write RCE%d = 0x%x : 0x%x\n",
792 __func__,
793 i, SM5703_REG_RCE0+i, fuelgauge->info.rce_value[i]);
794 }
795
796 /* DTCD write */
797 sm5703_fg_i2c_write_word(fuelgauge->i2c,
798 SM5703_REG_DTCD, fuelgauge->info.dtcd_value);
799 dev_dbg(&fuelgauge->i2c->dev,
800 "%s: DTCD write DTCD = 0x%x : 0x%x\n",
801 __func__,
802 SM5703_REG_DTCD, fuelgauge->info.dtcd_value);
803
804 /* RS write */
805 sm5703_fg_i2c_write_word(fuelgauge->i2c,
806 SM5703_REG_RS, fuelgauge->info.rs_value[0]);
807 dev_dbg(&fuelgauge->i2c->dev,
808 "%s: RS write RS = 0x%x : 0x%x\n",
809 __func__,
810 SM5703_REG_RS, fuelgauge->info.rs_value[0]);
811
812
813 /* VIT_PERIOD write */
814 sm5703_fg_i2c_write_word(fuelgauge->i2c,
815 SM5703_REG_VIT_PERIOD, fuelgauge->info.vit_period);
816 dev_dbg(&fuelgauge->i2c->dev,
817 "%s: VIT_PERIOD write VIT_PERIOD = 0x%x : 0x%x\n",
818 __func__,
819 SM5703_REG_VIT_PERIOD, fuelgauge->info.vit_period);
820
821 /* TABLE_LEN write & pram unlock */
822 sm5703_fg_i2c_write_word(fuelgauge->i2c,
823 SM5703_REG_PARAM_CTRL,
824 SM5703_FG_PARAM_UNLOCK_CODE | SM5703_FG_TABLE_LEN);
825
826 for (i=0; i < 3; i++) {
827 table_reg = SM5703_REG_TABLE_START + (i<<4);
828 for(j=0; j <= SM5703_FG_TABLE_LEN; j++) {
829 sm5703_fg_i2c_write_word(fuelgauge->i2c, (table_reg + j),
830 fuelgauge->info.battery_table[i][j]);
831 }
832 }
833
834 /* MIX_MODE write */
835 sm5703_fg_i2c_write_word(fuelgauge->i2c,
836 SM5703_REG_RS_MIX_FACTOR, fuelgauge->info.rs_value[1]);
837 sm5703_fg_i2c_write_word(fuelgauge->i2c,
838 SM5703_REG_RS_MAX, fuelgauge->info.rs_value[2]);
839 sm5703_fg_i2c_write_word(fuelgauge->i2c,
840 SM5703_REG_RS_MIN, fuelgauge->info.rs_value[3]);
841 sm5703_fg_i2c_write_word(fuelgauge->i2c,
842 SM5703_REG_MIX_RATE, fuelgauge->info.mix_value[0]);
843 sm5703_fg_i2c_write_word(fuelgauge->i2c,
844 SM5703_REG_MIX_INIT_BLANK, fuelgauge->info.mix_value[1]);
845
846 dev_dbg(&fuelgauge->i2c->dev,
847 "%s: RS_MIX_FACTOR = 0x%x, RS_MAX = 0x%x, RS_MIN = 0x%x,\
848 MIX_RATE = 0x%x, MIX_INIT_BLANK = 0x%x\n", \
849 __func__, fuelgauge->info.rs_value[1],
850 fuelgauge->info.rs_value[2],
851 fuelgauge->info.rs_value[3],
852 fuelgauge->info.mix_value[0],
853 fuelgauge->info.mix_value[1]);
854
855 /* CAL write */
856 sm5703_fg_i2c_write_word(fuelgauge->i2c,
857 SM5703_REG_VOLT_CAL, fuelgauge->info.volt_cal);
858 sm5703_fg_i2c_write_word(fuelgauge->i2c,
859 SM5703_REG_CURR_CAL, fuelgauge->info.curr_cal);
860
861 dev_dbg(&fuelgauge->i2c->dev, "%s: VOLT_CAL = 0x%x, CURR_CAL = 0x%x\n",
862 __func__, fuelgauge->info.volt_cal, fuelgauge->info.curr_cal);
863
864 /* top off soc set */
865 if(sm5703_get_device_id(fuelgauge->i2c) < 3) {
866 if(fuelgauge->info.topoff_soc >= 5)
867 fuelgauge->info.topoff_soc = 5; /* 93% */
868 else if(fuelgauge->info.topoff_soc >= 3)
869 fuelgauge->info.topoff_soc = fuelgauge->info.topoff_soc - 3;
870 else if(fuelgauge->info.topoff_soc >= 0)
871 fuelgauge->info.topoff_soc = fuelgauge->info.topoff_soc + 5;
872 }
873 sm5703_fg_i2c_write_word(fuelgauge->i2c,
874 SM5703_REG_TOPOFFSOC, fuelgauge->info.topoff_soc);
875
876 /* INIT_last - control register set */
877 value = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_CNTL);
878 value &= 0xDFFF;
879 value |= ENABLE_MIX_MODE | ENABLE_TEMP_MEASURE | (fuelgauge->info.enable_topoff_soc << 13);
880
881 /* surge reset defence */
882 if (manual_ocv_write) {
883 value = value | ENABLE_MANUAL_OCV;
884 }
885
886 pr_info("%s: SM5703_REG_CNTL reg : 0x%x\n", __func__, value);
887
888 ret = sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_CNTL, value);
889 if (ret < 0)
890 dev_dbg(&fuelgauge->i2c->dev,
891 "%s: fail control register set(%d)\n", __func__, ret);
892
893 /* Lock */
894 value = SM5703_FG_PARAM_LOCK_CODE | SM5703_FG_TABLE_LEN;
895 sm5703_fg_i2c_write_word(fuelgauge->i2c,
896 SM5703_REG_PARAM_CTRL, value);
897 dev_info(&fuelgauge->i2c->dev,
898 "%s: LAST PARAM CTRL VALUE = 0x%x : 0x%x\n",
899 __func__, SM5703_REG_PARAM_CTRL, value);
900
901 /* surge reset defence */
902 if (manual_ocv_write)
903 value = ((fuelgauge->info.batt_ocv << 8) / 125);
904 else
905 value = calculate_iocv(fuelgauge->i2c);
906
907 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_IOCV_MAN, value);
908 pr_info( "%s: IOCV_MAN_WRITE = %d : 0x%x\n",
909 __func__, fuelgauge->info.batt_ocv, value);
910
911 return 1;
912}
913
914static bool sm5703_fg_init(struct sm5703_fuelgauge_data *fuelgauge)
915{
916 int ret;
917 int ta_exist, reg_val;
918 union power_supply_propval value;
919
920 /* SM5703 i2c read check */
921 ret = sm5703_get_device_id(fuelgauge->i2c);
922 if (ret < 0) {
923 dev_dbg(&fuelgauge->i2c->dev,
924 "%s: fail to do i2c read(%d)\n", __func__, ret);
925
926 return false;
927 }
928
929 /* enable_topoff set */
930 reg_val = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_CNTL);
931 reg_val &= 0xDFFF;
932 reg_val |= (fuelgauge->info.enable_topoff_soc << 13);
933
934 pr_info("%s: SM5703_REG_CNTL reg : 0x%x\n", __func__, reg_val);
935
936 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_CNTL, reg_val);
937
938 value.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
939 psy_do_property("sm5703-charger", get,
940 POWER_SUPPLY_PROP_HEALTH, value);
941 dev_dbg(&fuelgauge->i2c->dev,
942 "%s: get POWER_SUPPLY_PROP_HEALTH = 0x%x\n",
943 __func__, value.intval);
944
945 ta_exist = fuelgauge->is_charging && (fuelgauge->info.batt_current >= 0);
946 dev_dbg(&fuelgauge->i2c->dev,
947 "%s: is_charging = %d, ta_exist = %d\n",
948 __func__, fuelgauge->is_charging, ta_exist);
949
950 /* get first voltage measure to avgvoltage */
951 fuelgauge->info.batt_avgvoltage = sm5703_get_avgvbat(fuelgauge);
952
953 /* get first temperature */
954 fuelgauge->info.temperature = sm5703_get_temperature(fuelgauge);
955
956 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x30);
957 pr_info("%s: sm5703 FG 0x30 = 0x%x \n", __func__, ret);
958 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x31);
959 pr_info("%s: sm5703 FG 0x31 = 0x%x \n", __func__, ret);
960 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x32);
961 pr_info("%s: sm5703 FG 0x32 = 0x%x \n", __func__, ret);
962 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x33);
963 pr_info("%s: sm5703 FG 0x33 = 0x%x \n", __func__, ret);
964 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x34);
965 pr_info("%s: sm5703 FG 0x34 = 0x%x \n", __func__, ret);
966 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x35);
967 pr_info("%s: sm5703 FG 0x35 = 0x%x \n", __func__, ret);
968 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x36);
969 pr_info("%s: sm5703 FG 0x36 = 0x%x \n", __func__, ret);
970 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x37);
971 pr_info("%s: sm5703 FG 0x37 = 0x%x \n", __func__, ret);
972
973 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x40);
974 pr_info("%s: sm5703 FG 0x40 = 0x%x \n", __func__, ret);
975 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x41);
976 pr_info("%s: sm5703 FG 0x41 = 0x%x \n", __func__, ret);
977 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x42);
978 pr_info("%s: sm5703 FG 0x42 = 0x%x \n", __func__, ret);
979 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, 0x43);
980 pr_info("%s: sm5703 FG 0x43 = 0x%x \n", __func__, ret);
981
982 return true;
983}
984
985static bool sm5703_fg_reset(struct sm5703_fuelgauge_data *fuelgauge)
986{
987 dev_info(&fuelgauge->i2c->dev, "%s: sec_hal_fg_reset\n", __func__);
988
989 /* SW reset code */
990 sm5703_fg_i2c_write_word(fuelgauge->i2c, 0x90, 0x0008);
991
992 /* delay 200ms */
993 msleep(200);
994
995 /* init code */
996 if(sm5703_fg_check_reg_init_need(fuelgauge->i2c))
997 sm5703_fg_reg_init(fuelgauge, 0);
998
999 return true;
1000}
1001
1002static void sm5703_fg_reset_capacity_by_jig_connection(struct sm5703_fuelgauge_data *fuelgauge)
1003{
1004 int ret;
1005
1006 if (fuelgauge->pdata->model_type == J2LTE) {
1007#ifdef USE_SUSPEND_LATE
1008 int retry = 0;
1009
1010 while(fuelgauge->is_sleep_state == true){
1011 pr_info("%s sleep_state retry=%d\n", __func__, retry);
1012 usleep_range(10 * 1000, 10 * 1000);
1013 if (++retry > 5)
1014 break;
1015 }
1016#endif
1017 }
1018
1019 ret = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_CNTL);
1020 ret &= 0xFFEF;
1021 sm5703_fg_i2c_write_word(fuelgauge->i2c, SM5703_REG_CNTL, ret);
1022}
1023
1024static int sm5703_fg_get_property(struct power_supply *psy,
1025 enum power_supply_property psp,
1026 union power_supply_propval *val)
1027{
1028 struct sm5703_fuelgauge_data *fuelgauge =
1029 container_of(psy, struct sm5703_fuelgauge_data, psy_fg);
1030
1031 switch (psp) {
1032 case POWER_SUPPLY_PROP_STATUS:
1033 case POWER_SUPPLY_PROP_CHARGE_FULL:
1034 case POWER_SUPPLY_PROP_ENERGY_NOW:
1035 return -ENODATA;
1036 /* Cell voltage (VCELL, mV) */
1037 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
1038 val->intval = sm5703_get_vbat(fuelgauge);
1039 break;
1040 /* Additional Voltage Information (mV) */
1041 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
1042 switch (val->intval) {
1043 case SEC_BATTERY_VOLTAGE_AVERAGE:
1044 val->intval = sm5703_get_avgvbat(fuelgauge);
1045 break;
1046 case SEC_BATTERY_VOLTAGE_OCV:
1047 val->intval = sm5703_get_ocv(fuelgauge);
1048 break;
1049 }
1050 break;
1051 /* Current (mA) */
1052 case POWER_SUPPLY_PROP_CURRENT_NOW:
1053 val->intval = sm5703_get_curr(fuelgauge);
1054 break;
1055 /* Average Current (mA) */
1056 case POWER_SUPPLY_PROP_CURRENT_AVG:
1057 val->intval = sm5703_get_avgcurr(fuelgauge);
1058 break;
1059 case POWER_SUPPLY_PROP_CAPACITY:
1060 if (val->intval == SEC_FUELGAUGE_CAPACITY_TYPE_RAW) {
1061 val->intval = sm5703_get_soc(fuelgauge) * 10;
1062 } else {
1063 val->intval = sm5703_get_soc(fuelgauge);
1064
1065 if (fuelgauge->pdata->capacity_calculation_type &
1066 (SEC_FUELGAUGE_CAPACITY_TYPE_SCALE |
1067 SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE))
1068 sm5703_fg_get_scaled_capacity(fuelgauge, val);
1069
1070 /* capacity should be between 0% and 100%
1071 * (0.1% degree)
1072 */
1073 if (val->intval > 1000)
1074 val->intval = 1000;
1075 if (val->intval < 0)
1076 val->intval = 0;
1077
1078 /* get only integer part */
1079 val->intval /= 10;
1080
1081 if (!fuelgauge->is_charging &&
1082 (fuelgauge->force_dec_mode == SM5703_COLD_MODE)) {
1083 pr_info("%s : SW V EMPTY. Decrease SOC\n", __func__);
1084 val->intval = 0;
1085 } else if ((fuelgauge->force_dec_mode == SM5703_RECOVERY_MODE) &&
1086 (val->intval == fuelgauge->capacity_old)) {
1087 fuelgauge->force_dec_mode = SM5703_NORMAL_MODE;
1088 }
1089
1090 /* check whether doing the wake_unlock */
1091 if ((val->intval > fuelgauge->pdata->fuel_alert_soc) &&
1092 fuelgauge->is_fuel_alerted) {
1093 wake_unlock(&fuelgauge->fuel_alert_wake_lock);
1094 sm5703_fuelgauge_fuelalert_init(fuelgauge,
1095 fuelgauge->pdata->fuel_alert_soc);
1096 }
1097
1098 /* (Only for atomic capacity)
1099 * In initial time, capacity_old is 0.
1100 * and in resume from sleep,
1101 * capacity_old is too different from actual soc.
1102 * should update capacity_old
1103 * by val->intval in booting or resume.
1104 */
1105 if (fuelgauge->initial_update_of_soc &&
1106 fuelgauge->force_dec_mode == SM5703_NORMAL_MODE) {
1107 /* updated old capacity */
1108 fuelgauge->capacity_old = val->intval;
1109 fuelgauge->initial_update_of_soc = false;
1110 break;
1111 }
1112
1113 if (fuelgauge->pdata->capacity_calculation_type &
1114 (SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC |
1115 SEC_FUELGAUGE_CAPACITY_TYPE_SKIP_ABNORMAL))
1116 sm5703_fg_get_atomic_capacity(fuelgauge, val);
1117 }
1118 break;
1119 /* Battery Temperature */
1120 case POWER_SUPPLY_PROP_TEMP:
1121 /* Target Temperature */
1122 case POWER_SUPPLY_PROP_TEMP_AMBIENT:
1123 val->intval = sm5703_get_temperature(fuelgauge);
1124 break;
1125 case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
1126 val->intval = fuelgauge->capacity_max;
1127 break;
1128 default:
1129 return -EINVAL;
1130 }
1131
1132 return 0;
1133}
1134
1135static int sm5703_fg_set_property(struct power_supply *psy,
1136 enum power_supply_property psp,
1137 const union power_supply_propval *val)
1138{
1139 struct sm5703_fuelgauge_data *fuelgauge =
1140 container_of(psy, struct sm5703_fuelgauge_data, psy_fg);
1141
1142 switch (psp) {
1143 case POWER_SUPPLY_PROP_STATUS:
1144 break;
1145 case POWER_SUPPLY_PROP_CHARGE_FULL:
1146 if (fuelgauge->pdata->capacity_calculation_type &
1147 SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE) {
1148#if defined(CONFIG_PREVENT_SOC_JUMP)
1149 sm5703_fg_calculate_dynamic_scale(fuelgauge, val->intval);
1150#else
1151 sm5703_fg_calculate_dynamic_scale(fuelgauge, 100);
1152#endif
1153 }
1154 break;
1155 case POWER_SUPPLY_PROP_ONLINE:
1156 fuelgauge->cable_type = val->intval;
1157 if (val->intval == POWER_SUPPLY_TYPE_BATTERY) {
1158 fuelgauge->is_charging = false;
1159 } else {
1160 fuelgauge->is_charging = true;
1161 if (fuelgauge->force_dec_mode != SM5703_NORMAL_MODE) {
1162 fuelgauge->force_dec_mode = SM5703_NORMAL_MODE;
1163 fuelgauge->initial_update_of_soc = true;
1164 sm5703_fuelgauge_fuelalert_init(fuelgauge,
1165 fuelgauge->pdata->fuel_alert_soc);
1166 }
1167
1168 if (fuelgauge->info.is_low_batt_alarm) {
1169 pr_info("%s: Reset low_batt_alarm\n",
1170 __func__);
1171 fuelgauge->info.is_low_batt_alarm = false;
1172 }
1173 }
1174 break;
1175 case POWER_SUPPLY_PROP_CAPACITY:
1176 if (val->intval == SEC_FUELGAUGE_CAPACITY_TYPE_RESET) {
1177 fuelgauge->initial_update_of_soc = true;
1178
1179 if (!sm5703_fg_reset(fuelgauge))
1180 return -EINVAL;
1181 else
1182 break;
1183
1184 }
1185 break;
1186 case POWER_SUPPLY_PROP_TEMP:
1187 break;
1188 case POWER_SUPPLY_PROP_TEMP_AMBIENT:
1189 break;
1190 case POWER_SUPPLY_PROP_ENERGY_NOW:
1191 sm5703_fg_reset_capacity_by_jig_connection(fuelgauge);
1192 break;
1193 case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
1194 dev_info(&fuelgauge->i2c->dev,
1195 "%s: capacity_max changed, %d -> %d\n",
1196 __func__, fuelgauge->capacity_max, val->intval);
1197 fuelgauge->capacity_max = sm5703_fg_check_capacity_max(fuelgauge, val->intval);
1198 fuelgauge->initial_update_of_soc = true;
1199 break;
1200 default:
1201 return -EINVAL;
1202 }
1203 return 0;
1204}
1205
1206static void sm5703_fg_isr_work(struct work_struct *work)
1207{
1208 struct sm5703_fuelgauge_data *fuelgauge =
1209 container_of(work, struct sm5703_fuelgauge_data, isr_work.work);
1210 int fg_alert_status;
1211
1212 fg_alert_status = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_STATUS);
1213 dev_info(&fuelgauge->i2c->dev, "%s: fg_alert_status(0x%x)\n",
1214 __func__, fg_alert_status);
1215
1216 fg_alert_status &= fuelgauge->info.irq_ctrl;
1217 if (!fg_alert_status) {
1218 wake_unlock(&fuelgauge->fuel_alert_wake_lock);
1219 }
1220
1221 if (fg_alert_status & ENABLE_L_VOL_INT) {
1222 pr_info("%s : Battery Voltage is Very Low!! SW V EMPTY ENABLE\n", __func__);
1223 fuelgauge->force_dec_mode = SM5703_COLD_MODE;
1224 }
1225}
1226
1227#if defined(CONFIG_STMP_SUPPORT_FG_ALERT)
1228static void sm5703_fg_isr(void *irq_data)
1229{
1230 struct sm5703_fuelgauge_data *fuelgauge = irq_data;
1231 int fg_irq;
1232
1233 /* clear interrupt */
1234 fg_irq = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_INTFG);
1235 dev_info(&fuelgauge->i2c->dev, "%s: fg_irq(0x%x)\n", __func__, fg_irq);
1236
1237 if (!fuelgauge->is_fuel_alerted) {
1238 wake_lock(&fuelgauge->fuel_alert_wake_lock);
1239 fuelgauge->is_fuel_alerted = true;
1240 schedule_delayed_work(&fuelgauge->isr_work, 0);
1241 }
1242}
1243#else
1244static irqreturn_t sm5703_fg_irq_thread(int irq, void *irq_data)
1245{
1246 struct sm5703_fuelgauge_data *fuelgauge = irq_data;
1247 int fg_irq;
1248
1249 /* clear interrupt */
1250 fg_irq = sm5703_fg_i2c_read_word(fuelgauge->i2c, SM5703_REG_INTFG);
1251 dev_info(&fuelgauge->i2c->dev, "%s: fg_irq(0x%x)\n",
1252 __func__, fg_irq);
1253
1254 if (!fuelgauge->is_fuel_alerted) {
1255 wake_lock(&fuelgauge->fuel_alert_wake_lock);
1256 fuelgauge->is_fuel_alerted = true;
1257 schedule_delayed_work(&fuelgauge->isr_work, 0);
1258 }
1259 return IRQ_HANDLED;
1260}
1261#endif
1262
1263#ifdef CONFIG_OF
1264#define PROPERTY_NAME_SIZE 128
1265
1266#define PINFO(format, args...) \
1267 printk(KERN_INFO "%s() line-%d: " format, \
1268 __func__, __LINE__, ## args)
1269
1270#define DECL_PARAM_PROP(_id, _name) {.id = _id, .name = _name,}
1271
1272static int get_battery_id(struct sm5703_fuelgauge_data *fuelgauge)
1273{
1274 /* sm5703fg does not support this function */
1275 return 0;
1276}
1277
1278static int sm5703_fg_parse_dt(struct sm5703_fuelgauge_data *fuelgauge)
1279{
1280 char prop_name[PROPERTY_NAME_SIZE];
1281 int battery_id = -1;
1282 int table[16];
1283 int rce_value[3];
1284 int rs_value[4];
1285 int mix_value[2];
1286 int topoff_soc[2];
1287 int set_temp_poff[4] = {3400,100,3300,80};
1288
1289 int ret;
1290 int i, j;
1291
1292 struct device_node *np = of_find_node_by_name(NULL, "sm5703-fuelgauge");
1293
1294 if (np == NULL) {
1295 pr_err("%s np NULL\n", __func__);
1296 } else {
1297 fuelgauge->pdata->fg_irq = of_get_named_gpio(np, "fuelgauge,fuel_int", 0);
1298 if (fuelgauge->pdata->fg_irq < 0)
1299 pr_err("%s error reading fg_irq = %d\n",
1300 __func__, fuelgauge->pdata->fg_irq);
1301
1302 ret = of_property_read_u32(np, "fuelgauge,capacity_max",
1303 &fuelgauge->pdata->capacity_max);
1304 if (ret < 0)
1305 pr_err("%s error reading capacity_max %d\n", __func__, ret);
1306
1307 ret = of_property_read_u32(np, "fuelgauge,capacity_max_margin",
1308 &fuelgauge->pdata->capacity_max_margin);
1309 if (ret < 0)
1310 pr_err("%s error reading capacity_max_margin %d\n", __func__, ret);
1311
1312 ret = of_property_read_u32(np, "fuelgauge,capacity_min",
1313 &fuelgauge->pdata->capacity_min);
1314 if (ret < 0)
1315 pr_err("%s error reading capacity_min %d\n", __func__, ret);
1316
1317 ret = of_property_read_u32(np, "fuelgauge,capacity_calculation_type",
1318 &fuelgauge->pdata->capacity_calculation_type);
1319 if (ret < 0)
1320 pr_err("%s error reading capacity_calculation_type %d\n",
1321 __func__, ret);
1322
1323 ret = of_property_read_u32(np, "fuelgauge,fuel_alert_soc",
1324 &fuelgauge->pdata->fuel_alert_soc);
1325 if (ret < 0)
1326 pr_err("%s error reading pdata->fuel_alert_soc %d\n",
1327 __func__, ret);
1328
1329 ret = of_property_read_u32(np, "fuelgauge,model_type",
1330 &fuelgauge->pdata->model_type);
1331 if (ret < 0)
1332 pr_err("%s error reading pdata->model_type %d\n",
1333 __func__, ret);
1334 }
1335
1336 pr_info("%s: fg_irq : %d, capacity_max : %d, capacity_max_margin : %d, capacity_min : %d\n",
1337 __func__, fuelgauge->pdata->fg_irq, fuelgauge->pdata->capacity_max,
1338 fuelgauge->pdata->capacity_max_margin, fuelgauge->pdata->capacity_min);
1339
1340 /* get battery_params node */
1341 np = of_find_node_by_name(of_node_get(np), "battery_params");
1342 if (np == NULL) {
1343 PINFO("Cannot find child node \"battery_params\"\n");
1344 return -EINVAL;
1345 }
1346
1347 /* get battery_id */
1348 if (of_property_read_u32(np, "battery,id", &battery_id) < 0)
1349 PINFO("not battery,id property\n");
1350 if (battery_id == -1)
1351 battery_id = get_battery_id(fuelgauge);
1352 PINFO("battery id = %d\n", battery_id);
1353
1354 /* get battery_table */
1355 for (i = DISCHARGE_TABLE; i < TABLE_MAX; i++) {
1356 snprintf(prop_name, PROPERTY_NAME_SIZE,
1357 "battery%d,%s%d", battery_id, "battery_table", i);
1358
1359 ret = of_property_read_u32_array(np, prop_name, table, 16);
1360 if (ret < 0) {
1361 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1362 }
1363 for (j = 0; j <= SM5703_FG_TABLE_LEN; j++) {
1364 fuelgauge->info.battery_table[i][j] = table[j];
1365 PINFO("%s = <table[%d][%d] 0x%x>\n", prop_name, i, j, table[j]);
1366 }
1367 }
1368
1369 /* get rce */
1370 for (i = 0; i < 3; i++) {
1371 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "rce_value");
1372 ret = of_property_read_u32_array(np, prop_name, rce_value, 3);
1373 if (ret < 0) {
1374 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1375 }
1376 fuelgauge->info.rce_value[i] = rce_value[i];
1377 }
1378 PINFO("%s = <0x%x 0x%x 0x%x>\n", prop_name, rce_value[0], rce_value[1], rce_value[2]);
1379
1380 /* get dtcd_value */
1381 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "dtcd_value");
1382 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.dtcd_value, 1);
1383 if (ret < 0)
1384 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1385 PINFO("%s = <0x%x>\n",prop_name, fuelgauge->info.dtcd_value);
1386
1387 /* get rs_value */
1388 for (i = 0; i < 4; i++) {
1389 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "rs_value");
1390 ret = of_property_read_u32_array(np, prop_name, rs_value, 4);
1391 if (ret < 0) {
1392 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1393 }
1394 fuelgauge->info.rs_value[i] = rs_value[i];
1395 }
1396 PINFO("%s = <0x%x 0x%x 0x%x 0x%x>\n", prop_name, rs_value[0], rs_value[1], rs_value[2], rs_value[3]);
1397
1398 /* get vit_period */
1399 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "vit_period");
1400 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.vit_period, 1);
1401 if (ret < 0)
1402 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1403 PINFO("%s = <0x%x>\n",prop_name, fuelgauge->info.vit_period);
1404
1405 /* get mix_value */
1406 for (i = 0; i < 2; i++) {
1407 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "mix_value");
1408 ret = of_property_read_u32_array(np, prop_name, mix_value, 2);
1409 if (ret < 0) {
1410 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1411 }
1412 fuelgauge->info.mix_value[i] = mix_value[i];
1413 }
1414 PINFO("%s = <0x%x 0x%x>\n", prop_name, mix_value[0], mix_value[1]);
1415
1416 /* battery_type */
1417 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "battery_type");
1418 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.battery_type, 1);
1419 if (ret < 0)
1420 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1421 PINFO("%s = <%d>\n", prop_name, fuelgauge->info.battery_type);
1422
1423 /* TOP OFF SOC */
1424 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "topoff_soc");
1425 ret = of_property_read_u32_array(np, prop_name, topoff_soc, 2);
1426 if (ret < 0)
1427 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1428 fuelgauge->info.enable_topoff_soc = topoff_soc[0];
1429 fuelgauge->info.topoff_soc = topoff_soc[1];
1430 PINFO("%s = <0x%x 0x%x>\n", prop_name, fuelgauge->info.enable_topoff_soc, fuelgauge->info.topoff_soc);
1431
1432 /* VOL & CURR CAL */
1433 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "volt_cal");
1434 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.volt_cal, 1);
1435 if (ret < 0)
1436 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1437 PINFO("%s = <0x%x>\n", prop_name, fuelgauge->info.volt_cal);
1438
1439 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "curr_cal");
1440 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.curr_cal, 1);
1441 if (ret < 0)
1442 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1443 PINFO("%s = <0x%x>\n", prop_name, fuelgauge->info.curr_cal);
1444
1445 /* temp_std */
1446 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "temp_std");
1447 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.temp_std, 1);
1448 if (ret < 0)
1449 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1450 PINFO("%s = <%d>\n", prop_name, fuelgauge->info.temp_std);
1451
1452 /* temp_offset */
1453 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "temp_offset");
1454 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.temp_offset, 1);
1455 if (ret < 0)
1456 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1457 PINFO("%s = <%d>\n", prop_name, fuelgauge->info.temp_offset);
1458
1459 /* temp_offset_cal */
1460 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "temp_offset_cal");
1461 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.temp_offset_cal, 1);
1462 if (ret < 0)
1463 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1464 PINFO("%s = <0x%x>\n", prop_name, fuelgauge->info.temp_offset_cal);
1465
1466 /* charge_offset_cal */
1467 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "charge_offset_cal");
1468 ret = of_property_read_u32_array(np, prop_name, &fuelgauge->info.charge_offset_cal, 1);
1469 if (ret < 0)
1470 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1471 PINFO("%s = <0x%x>\n", prop_name, fuelgauge->info.charge_offset_cal);
1472
1473 /* tem poff level */
1474 snprintf(prop_name, PROPERTY_NAME_SIZE, "battery%d,%s", battery_id, "tem_poff");
1475 ret = of_property_read_u32_array(np, prop_name, set_temp_poff, 4);
1476 if (ret < 0)
1477 PINFO("Can get prop %s (%d)\n", prop_name, ret);
1478 fuelgauge->info.n_tem_poff = set_temp_poff[0];
1479 fuelgauge->info.n_tem_poff_offset = set_temp_poff[1];
1480 fuelgauge->info.l_tem_poff = set_temp_poff[2];
1481 fuelgauge->info.l_tem_poff_offset = set_temp_poff[3];
1482
1483 PINFO("%s = <%d, %d, %d, %d>\n", prop_name,
1484 fuelgauge->info.n_tem_poff, fuelgauge->info.n_tem_poff_offset,
1485 fuelgauge->info.l_tem_poff, fuelgauge->info.l_tem_poff_offset);
1486
1487 np = of_find_node_by_name(NULL, "battery");
1488 if (!np) {
1489 pr_info("%s : np NULL\n", __func__);
1490 return -ENODATA;
1491 }
1492
1493 ret = of_property_read_string(np, "battery,fuelgauge_name",
1494 (char const **)&fuelgauge->pdata->fuelgauge_name);
1495 if (ret)
1496 pr_info("%s: fuelgauge name is Empty.\n", __func__);
1497
1498 return 0;
1499}
1500
1501static struct of_device_id sm5703_fuelgauge_match_table[] = {
1502 { .compatible = "samsung,sm5703-fuelgauge",},
1503 {},
1504};
1505#else
1506static int sm5703_fg_parse_dt(struct sm5703_fuelgauge_data *fuelgauge)
1507{
1508 return -ENOSYS;
1509}
1510
1511#define sm5703_fuelgauge_match_table NULL
1512#endif /* CONFIG_OF */
1513
1514static int sm5703_fuelgauge_probe(struct i2c_client *client,
1515 const struct i2c_device_id *id)
1516{
1517 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
1518 struct sm5703_fuelgauge_data *fuelgauge;
1519 union power_supply_propval raw_soc_val;
1520 int ret = 0;
1521
1522 pr_info("%s: SM5703 Fuelgauge Driver Loading\n", __func__);
1523
1524 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
1525 return -EIO;
1526
1527 fuelgauge = kzalloc(sizeof(*fuelgauge), GFP_KERNEL);
1528 if (!fuelgauge)
1529 return -ENOMEM;
1530
1531 mutex_init(&fuelgauge->fg_lock);
1532
1533 fuelgauge->i2c = client;
1534
1535 if (client->dev.of_node) {
1536 fuelgauge->pdata = devm_kzalloc(&client->dev, sizeof(*(fuelgauge->pdata)),
1537 GFP_KERNEL);
1538 if (!fuelgauge->pdata) {
1539 dev_err(&client->dev, "Failed to allocate memory\n");
1540 ret = -ENOMEM;
1541 goto err_parse_dt_nomem;
1542 }
1543 ret = sm5703_fg_parse_dt(fuelgauge);
1544 if (ret < 0)
1545 goto err_parse_dt;
1546 } else {
1547 fuelgauge->pdata = client->dev.platform_data;
1548 }
1549
1550 i2c_set_clientdata(client, fuelgauge);
1551
1552 if (fuelgauge->pdata->fuelgauge_name == NULL)
1553 fuelgauge->pdata->fuelgauge_name = "sm5703-fuelgauge";
1554
1555 fuelgauge->psy_fg.name = fuelgauge->pdata->fuelgauge_name;
1556 fuelgauge->psy_fg.type = POWER_SUPPLY_TYPE_UNKNOWN;
1557 fuelgauge->psy_fg.get_property = sm5703_fg_get_property;
1558 fuelgauge->psy_fg.set_property = sm5703_fg_set_property;
1559 fuelgauge->psy_fg.properties = sm5703_fuelgauge_props;
1560 fuelgauge->psy_fg.num_properties =
1561 ARRAY_SIZE(sm5703_fuelgauge_props);
1562
1563 fuelgauge->capacity_max = fuelgauge->pdata->capacity_max;
1564 raw_soc_val.intval = sm5703_get_soc(fuelgauge);
1565
1566 if (raw_soc_val.intval > fuelgauge->capacity_max)
1567 sm5703_fg_calculate_dynamic_scale(fuelgauge, 100);
1568
1569 ret = sm5703_fg_init(fuelgauge);
1570 if (ret < 0) {
1571 pr_err("%s: Failed to Initialize Fuelgauge\n", __func__);
1572 /* goto err_data_free; */
1573 }
1574
1575 ret = power_supply_register(&client->dev, &fuelgauge->psy_fg);
1576 if (ret) {
1577 pr_err("%s: Failed to Register psy_fg\n", __func__);
1578 goto err_data_free;
1579 }
1580
1581 if (fuelgauge->pdata->fuel_alert_soc >= 0) {
1582 sm5703_fuelgauge_fuelalert_init(fuelgauge,
1583 fuelgauge->pdata->fuel_alert_soc);
1584 wake_lock_init(&fuelgauge->fuel_alert_wake_lock,
1585 WAKE_LOCK_SUSPEND, "fuel_alerted");
1586
1587#if defined(CONFIG_STMP_SUPPORT_FG_ALERT)
1588 INIT_DELAYED_WORK(
1589 &fuelgauge->isr_work, sm5703_fg_isr_work);
1590 ret = stmpe_request_irq(6, sm5703_fg_isr,
1591 STMPE_TRIGGER_FALLING,
1592 "SM5703-Fuelgauge", fuelgauge);
1593 if(ret) {
1594 pr_err("%s: Failed register to STMPE (%d)\n", __func__, ret);
1595 goto err_supply_unreg;
1596 }
1597#else
1598 if (fuelgauge->pdata->fg_irq > 0) {
1599 INIT_DELAYED_WORK(
1600 &fuelgauge->isr_work, sm5703_fg_isr_work);
1601
1602 fuelgauge->fg_irq = gpio_to_irq(fuelgauge->pdata->fg_irq);
1603 dev_info(&client->dev,
1604 "%s: fg_irq = %d\n", __func__, fuelgauge->fg_irq);
1605 if (fuelgauge->fg_irq > 0) {
1606 ret = request_threaded_irq(fuelgauge->fg_irq,
1607 NULL, sm5703_fg_irq_thread,
1608 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING
1609 | IRQF_ONESHOT,
1610 "fuelgauge-irq", fuelgauge);
1611 if (ret) {
1612 dev_err(&client->dev,
1613 "%s: Failed to Reqeust IRQ\n", __func__);
1614 goto err_supply_unreg;
1615 }
1616
1617 ret = enable_irq_wake(fuelgauge->fg_irq);
1618 if (ret < 0)
1619 dev_err(&client->dev,
1620 "%s: Failed to Enable Wakeup Source(%d)\n",
1621 __func__, ret);
1622 } else {
1623 dev_err(&client->dev, "%s: Failed gpio_to_irq(%d)\n",
1624 __func__, fuelgauge->fg_irq);
1625 goto err_supply_unreg;
1626 }
1627 }
1628#endif
1629 }
1630
1631 fuelgauge->initial_update_of_soc = true;
1632 fuelgauge->force_dec_mode = SM5703_NORMAL_MODE;
1633
1634#ifdef USE_SUSPEND_LATE
1635 fuelgauge->is_sleep_state = false;
1636#endif
1637
1638 pr_info("%s: SM5703 Fuelgauge Driver Loaded\n", __func__);
1639 return 0;
1640
1641err_supply_unreg:
1642 power_supply_unregister(&fuelgauge->psy_fg);
1643err_data_free:
1644 if (client->dev.of_node)
1645 kfree(fuelgauge->pdata);
1646
1647err_parse_dt:
1648err_parse_dt_nomem:
1649 mutex_destroy(&fuelgauge->fg_lock);
1650 kfree(fuelgauge);
1651
1652 return ret;
1653}
1654
1655static const struct i2c_device_id sm5703_fuelgauge_id[] = {
1656 {"sm5703-fuelgauge", 0},
1657 {}
1658};
1659
1660static void sm5703_fuelgauge_shutdown(struct i2c_client *client)
1661{
1662}
1663
1664static int sm5703_fuelgauge_remove(struct i2c_client *client)
1665{
1666 struct sm5703_fuelgauge_data *fuelgauge = i2c_get_clientdata(client);
1667
1668 if (fuelgauge->pdata->fuel_alert_soc >= 0)
1669 wake_lock_destroy(&fuelgauge->fuel_alert_wake_lock);
1670
1671 return 0;
1672}
1673
1674#if defined CONFIG_PM
1675static int sm5703_fuelgauge_suspend(struct device *dev)
1676{
1677 return 0;
1678}
1679
1680static int sm5703_fuelgauge_resume(struct device *dev)
1681{
1682 return 0;
1683}
1684
1685#ifdef USE_SUSPEND_LATE
1686static int sm5703_suspend_late(struct device *dev)
1687{
1688 struct sm5703_fuelgauge_data *fuelgauge = dev_get_drvdata(dev);
1689
1690 fuelgauge->is_sleep_state = true;
1691
1692 return 0;
1693}
1694
1695static int sm5703_resume_noirq(struct device *dev)
1696{
1697 struct sm5703_fuelgauge_data *fuelgauge = dev_get_drvdata(dev);
1698
1699 fuelgauge->is_sleep_state = false;
1700
1701 return 0;
1702}
1703#endif
1704
1705#else
1706#define sm5703_fuelgauge_suspend NULL
1707#define sm5703_fuelgauge_resume NULL
1708#endif
1709
1710const struct dev_pm_ops sm5703_fuelgauge_pm_ops = {
1711 .suspend = sm5703_fuelgauge_suspend,
1712 .resume = sm5703_fuelgauge_resume,
1713#ifdef USE_SUSPEND_LATE
1714 .suspend_late = sm5703_suspend_late,
1715 .resume_noirq = sm5703_resume_noirq,
1716#endif
1717};
1718
1719static struct i2c_driver sm5703_fuelgauge_driver = {
1720 .driver = {
1721 .name = "sm5703-fuelgauge",
1722 .owner = THIS_MODULE,
1723 .pm = &sm5703_fuelgauge_pm_ops,
1724 .of_match_table = sm5703_fuelgauge_match_table,
1725 },
1726 .probe = sm5703_fuelgauge_probe,
1727 .remove = sm5703_fuelgauge_remove,
1728 .shutdown = sm5703_fuelgauge_shutdown,
1729 .id_table = sm5703_fuelgauge_id,
1730};
1731
1732static int __init sm5703_fuelgauge_init(void)
1733{
1734 pr_info("%s: SM5703 Fuelgauge Init\n", __func__);
1735 return i2c_add_driver(&sm5703_fuelgauge_driver);
1736}
1737
1738static void __exit sm5703_fuelgauge_exit(void)
1739{
1740 i2c_del_driver(&sm5703_fuelgauge_driver);
1741}
1742module_init(sm5703_fuelgauge_init);
1743module_exit(sm5703_fuelgauge_exit);
1744
1745MODULE_DESCRIPTION("Samsung SM5703 Fuel Gauge Driver");
1746MODULE_AUTHOR("Samsung Electronics");
1747MODULE_LICENSE("GPL");