Tizen 2.0 Release
[platform/kernel/u-boot.git] / drivers / misc / max77693_fg.c
1 /*
2  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
3  * Sanghee Kim <sh0130.kim@samsung.com>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <command.h>
26 #include <asm/arch/power.h>
27 #include <i2c.h>
28 #include <max77693.h>
29 #include "fuelgauge_battery_data.h"
30
31 #ifdef DEBUG_FG
32 #define DEBUG(fmt,args...) printk(fmt, ##args)
33 #else
34 #define DEBUG(fmt,args...) do {} while(0)
35 #endif
36
37 #define msleep(a)       udelay(a * 1000)
38
39 /* Register address */
40 #define MAX77693_REG_STATUS             0x00
41 #define MAX77693_REG_CAPREP             0x05
42 #define MAX77693_REG_SOCREP             0x06
43 #define MAX77693_REG_VCELL              0x09
44 #define MAX77693_REG_CURRENT            0x0A
45 #define MAX77693_REG_AVG_CURRENT        0x0B
46 #define MAX77693_REG_CONFIG             0x1D
47 #define MAX77693_REG_VERSION            0x21
48 #define MAX77693_REG_OCV_RO             0xEE
49 #define MAX77693_REG_OCV_WR             0xFB
50 #define MAX77693_REG_VFSOC              0xFF
51
52 static int fg_bus = -1;
53 static int rst_status;
54 static int charger_status;
55 static int por;
56 static u32 vfocv_table;
57 static const char pszfg[] = "max77693-fg:";
58
59 /* parameter for SDI 1750mA 2012.02.17 */
60 /* Address 0x80h */
61 static u16 sdi_1750_cell_character0[16] = {
62         0xACB0, 0xB630, 0xB950, 0xBA20, 0xBBB0, 0xBBE0, 0xBC30, 0xBD00,
63         0xBD60, 0xBDC0, 0xBF30, 0xC0A0, 0xC480, 0xC890, 0xCC40, 0xD010
64 };
65
66 /* Address 0x90h */
67 static u16 sdi_1750_cell_character1[16] = {
68         0x0180, 0x0F10, 0x0060, 0x0E40, 0x3DC0, 0x4E10, 0x2D50, 0x3680,
69         0x3680, 0x0D50, 0x0D60, 0x0D80, 0x0C80, 0x0860, 0x0800, 0x0800
70 };
71
72 /* Address 0xA0h */
73 static u16 sdi_1750_cell_character2[16] = {
74         0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080,
75         0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080
76 };
77
78 /* parameter for SDI 2100mA 2012.01.25 */
79 /* Address 0x80h */
80 static u16 sdi_2100_cell_character0[16] = {
81         0xA890, 0xB780, 0xB9A0, 0xBBF0, 0xBC30, 0xBC80, 0xBCF0, 0xBD50,
82         0xBE60, 0xBFB0, 0xC1B0, 0xC4B0, 0xC560, 0xCCE0, 0xD170, 0xD7A0
83 };
84
85 /* Address 0x90h */
86 static u16 sdi_2100_cell_character1[16] = {
87         0x0150, 0x1000, 0x0C10, 0x3850, 0x2E50, 0x32F0, 0x3040, 0x12F0,
88         0x0FE0, 0x1090, 0x09E0, 0x0BD0, 0x0820, 0x0720, 0x0700, 0x0700
89 };
90
91 /* Address 0xA0h */
92 static u16 sdi_2100_cell_character2[16] = {
93         0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
94         0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100
95 };
96
97 /* parameter for SDI 2100mA 2012.10.11 */
98 /* Address 0x80h */
99 static u16 sdi_3000_cell_character0[16] = {
100         0xAF70, 0xB570, 0xB7A0, 0xB900, 0xBA70, 0xBBF0, 0xBC40, 0xBC90,
101         0xBE20, 0xBF80, 0xC340, 0xC600, 0xCA90, 0xCD90, 0xD3B0, 0xD7C0
102 };
103
104 /* Address 0x90h */
105 static u16 sdi_3000_cell_character1[16] = {
106         0x0170, 0x0D20, 0x0BA0, 0x0BF0, 0x0DF0, 0x3F40, 0x3F00, 0x1A00,
107         0x18E0, 0x09F0, 0x0970, 0x0920, 0x0860, 0x0680, 0x0600, 0x0600
108 };
109
110 /* Address 0xA0h */
111 static u16 sdi_3000_cell_character2[16] = {
112         0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
113         0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100
114 };
115
116 /* table_soc = (new_vcell - new_v0)*new_slope/100000 (unit : 0.01% ) */
117 static struct fuelgauge_dsg_data_table {
118         u32 table_vcell;
119         u32 table_v0;
120         u32 table_slope;
121 } max77693_fg_dsg_soc_table[19] = {
122         { 410100, 280167, 7638 },
123         { 400000, 329011, 12264 },
124         { 380000, 337808, 14022 },
125         { 377600, 346818, 17883 },
126         { 376100, 353171, 22312 },
127         { 375600, 296446, 6367 },
128         { 375000, 360396, 32929 },
129         { 373000, 358802, 29874 },
130         { 371900, 360851, 34015 },
131         { 370900, 362898, 42288 },
132         { 370000, 363902, 47744 },
133         { 369000, 365484, 64460 },
134         { 368300, 364487, 53280 },
135         { 366800, 360937, 25881 },
136         { 364500, 356525, 14484 },
137         { 361000, 353762, 10324 },
138         { 359400, 357230, 20593 },
139         { 355700, 352425, 6500 },
140         { 311600, 311349, 477 }
141 };
142
143 static struct fuelgauge_chg_data_table {
144         u32 table_vcell;
145         u32 table_v0;
146         u32 table_slope;
147 } max77693_fg_chg_soc_table[13] = {
148         { 348100, 326900, 634 },
149         { 365300, 331362, 798 },
150         { 368200, 351400, 1939 },
151         { 372200, 366842, 23987 },
152         { 378900, 361312, 11738 },
153         { 381900, 375992, 73529 },
154         { 382400, 374780, 61013 },
155         { 386300, 361965, 22635 },
156         { 388500, 339987, 11946 },
157         { 391200, 361291, 21538 },
158         { 399200, 350354, 15312 },
159         { 418700, 338278, 12277 },
160         { 419700, 365571, 18646 }
161 };
162
163 /* ocv table for finding vfocv */
164 static struct fuelgauge_ocv_data_table {
165         u32 table_soc;
166         u32 table_v0;
167         u32 table_slope;
168 } max77693_fg_ocv_table[17] = {
169         { 10000, -1421176, 543 },
170         { 9983, 325581, 10936 },
171         { 8370, 351593, 16565 },
172         { 6735, 331923, 11164 },
173         { 5939, 364431, 28706 },
174         { 4541, 371623, 52640 },
175         { 3883, 366294, 30560 },
176         { 3501, 371615, 57067 },
177         { 3073, 371628, 57200 },
178         { 2644, 370772, 48267 },
179         { 2282, 371529, 57460 },
180         { 1920, 370165, 40806 },
181         { 1667, 370099, 40159 },
182         { 1414, 335196, 3680 },
183         { 1230, 364884, 32927 },
184         { 285, 325250, 704 },
185         { 0, 0, 0 }
186 };
187
188 static struct table_soc_data sdi_2100_table_soc_data[] = {
189         {       3000, 0, 0, 0                   },
190         {       3306, 1289, 105100, 3170600     },
191         {       3597, 4059, 4100, 3580300       },
192         {       3622, 10148, 8500, 3535900      },
193         {       3672, 16039, 2200, 3637100      },
194         {       3714, 35344, 4100, 3569600      },
195         {       3782, 51984, 7000, 3420600      },
196         {       3902, 69246, 11400, 3112200     },
197         {       4225, 97566, 0, 100000000       },
198 };
199
200 static struct table_soc_data sdi_3000_table_soc_data[] = {
201         { 3301, 1148, 0, 0 },
202         { 3609, 4230, 0, 0 },
203         { 3640, 11828, 0, 0 },
204         { 3657, 13469, 0, 0 },
205         { 3707, 21840, 0, 0 },
206         { 3733, 34992, 0, 0 },
207         { 3758, 43629, 0, 0 },
208         { 3806, 53027, 0, 0 },
209         { 3900, 65387, 0, 0 },
210         { 4265, 100492, 0, 0 },
211 };
212
213 static inline void mdelay(int msec)
214 {
215         udelay(msec * 1000);
216 }
217
218 static inline u16 fuelgauge_reg_read(int reg)
219 {
220         u16 data;
221
222         i2c_read(MAX77693_FG_ADDR, reg, 1, (uchar *)&data, 2);
223
224         return data;
225 }
226
227 static inline void fuelgauge_reg_write(int reg, u16 data)
228 {
229         i2c_write(MAX77693_FG_ADDR, reg, 1, (uchar *)&data, 2);
230 }
231
232 static inline void fuelgauge_reg_read_16n(int reg, u16 *data)
233 {
234         int i;
235
236         for (i = 0; i < 16; i++)
237                 i2c_read(MAX77693_FG_ADDR, reg + i, 1, (uchar *)(data + i), 2);
238 }
239
240 static inline void fuelgauge_reg_write_16n(int reg, u16 *data)
241 {
242         int i;
243
244         for (i = 0; i < 16; i++)
245                 i2c_write(MAX77693_FG_ADDR, reg + i, 1, (uchar *)(data + i), 2);
246 }
247
248 static void fuelgauge_reg_write_and_verify(int reg, u16 data)
249 {
250         fuelgauge_reg_write(reg, data);
251         fuelgauge_reg_read(reg);
252 }
253
254 void max77693_fg_bus_init(int bus_num)
255 {
256         fg_bus = bus_num;
257 }
258
259 int max77693_fg_probe(void)
260 {
261         unsigned char addr = MAX77693_FG_ADDR;
262
263         i2c_set_bus_num(fg_bus);
264
265         if (i2c_probe(addr)) {
266                 puts("Can't found max77693 fuel gauge\n");
267                 return 1;
268         }
269
270         return 0;
271 }
272
273 u32 max77693_fg_get_cap(void)
274 {
275         u16 value;
276
277         value = fuelgauge_reg_read(MAX77693_REG_CAPREP);
278
279         DEBUG("%s\tcaprep = 0x%x\n", pszfg, value);
280
281         return (u32)value;
282 }
283
284 u32 max77693_fg_get_vcell(void)
285 {
286         u16 value;
287         u32 vcell;
288
289         value = fuelgauge_reg_read(MAX77693_REG_VCELL);
290
291         vcell = (u32)(value >> 3);
292
293         DEBUG("%s\tvcell = 0x%x (0x%x)\n", pszfg, vcell, value);
294
295         /* uV */
296         return vcell * 625;
297 }
298
299 static u32 max77693_fg_get_ocv(void)
300 {
301         u16 value;
302         u32 ocv;
303
304         value = fuelgauge_reg_read(MAX77693_REG_OCV_RO);
305         ocv = (u32)(value >> 3);
306
307         DEBUG("%s\tocv = 0x%x (0x%x)\n", pszfg, vcell, value);
308
309         return ocv * 625 / 1000;
310 }
311
312 u32 max77693_fg_get_soc(void)
313 {
314         u16 value;
315         u32 soc;
316
317         value = fuelgauge_reg_read(MAX77693_REG_VFSOC);
318         soc = (u32)(value >> 8);
319
320         DEBUG("%s\tsoc = 0x%x (0x%x)\n", pszfg, soc, value);
321
322         return soc;
323 }
324
325 static u32 max77693_fg_get_vfocv(void)
326 {
327         u16 value;
328         u32 vfocv;
329
330         value = fuelgauge_reg_read(MAX77693_REG_OCV_WR);
331         vfocv = (u32)(value >> 3);
332
333         DEBUG("%s\tvfocv = 0x%x (0x%x)\n", pszfg, vcell, value);
334
335         return vfocv * 625 / 1000;
336 }
337
338 static u32 max77693_fg_get_average_vcell(void)
339 {
340         int i;
341         u32 vcell_data;
342         u32 vcell_max = 0;
343         u32 vcell_min = 0;
344         u32 vcell_total = 0;
345
346         for (i = 0; i < AVER_SAMPLE_CNT; i++) {
347                 vcell_data = max77693_fg_get_vcell() / 1000;
348
349                 if (i != 0) {
350                         if (vcell_data > vcell_max)
351                                 vcell_max = vcell_data;
352                         else if (vcell_data < vcell_min)
353                                 vcell_min = vcell_data;
354                 } else {
355                         vcell_max = vcell_data;
356                         vcell_min = vcell_data;
357                 }
358                 vcell_total += vcell_data;
359         }
360
361         return (vcell_total - vcell_max - vcell_min) / (AVER_SAMPLE_CNT - 2);
362 }
363
364 static u32 max77693_fg_get_vfocv_table(u32 raw_soc)
365 {
366         int i, idx, idx_end;
367         u32 vfocv;
368
369         /* find range */
370         idx_end = (int)ARRAY_SIZE(max77693_fg_ocv_table) - 1;
371         for (i = 0, idx = 0; i < idx_end; i++) {
372                 if (raw_soc == 0 || raw_soc >= 10000) {
373                         break;
374                 } else if (raw_soc <= max77693_fg_ocv_table[i].table_soc &&
375                            raw_soc > max77693_fg_ocv_table[i + 1].table_soc) {
376                         idx = i;
377                         break;
378                 }
379         }
380
381         if (raw_soc == 0) {
382                 vfocv = 325000;
383         } else if (raw_soc >= 10000) {
384                 vfocv = 417000;
385         } else {
386                 vfocv = ((raw_soc * 100000) /
387                                 max77693_fg_ocv_table[idx].table_slope) +
388                                 max77693_fg_ocv_table[idx].table_v0;
389
390                 DEBUG("[%d] %d = (%d * 100000) / %d + %d\n",
391                        idx, vfocv, raw_soc,
392                        max77693_fg_ocv_table[idx].table_slope,
393                        max77693_fg_ocv_table[idx].table_v0);
394         }
395
396         vfocv /= 100;
397
398         return vfocv;
399 }
400
401 static u16 max77693_fg_check_version(void)
402 {
403         u16 version = fuelgauge_reg_read(MAX77693_REG_VERSION);
404
405         DEBUG("%s\tversion: 0x%x\n", pszfg, version);
406
407         return version;
408 }
409
410 static void max77693_fg_load_init_config(enum battery_type batt_type)
411 {
412         u16 data0[16], data1[16], data2[16];
413         u16 status;
414         u16 rcomp0, tempco;
415         u16 *cell_character0, *cell_character1, *cell_character2;
416         u32 vcell, soc, vfocv;
417         u32 i;
418         u32 rewrite_count = 5;
419
420         vcell = max77693_fg_get_average_vcell();
421         soc = max77693_fg_get_soc();
422         vfocv = max77693_fg_get_ocv();
423
424         printf("%s\tPOR start: vcell(%d), vfocv(%d), soc(%d)\n", pszfg, vcell, vfocv, soc);
425
426         /* update battery parameter */
427         switch (batt_type) {
428         case BATTERY_SDI_1750:
429                 printf("%s\tupdate SDI 1750 parameter\n", pszfg);
430                 rcomp0 = SDI_1750_RCOMP0;
431                 tempco = SDI_1750_TEMPCO;
432                 cell_character0 = sdi_1750_cell_character0;
433                 cell_character1 = sdi_1750_cell_character1;
434                 cell_character2 = sdi_1750_cell_character2;
435                 break;
436         case BATTERY_SDI_2100:
437                 printf("%s\tupdate SDI 2100 parameter\n", pszfg);
438                 rcomp0 = SDI_2100_RCOMP0;
439                 tempco = SDI_2100_TEMPCO;
440                 cell_character0 = sdi_2100_cell_character0;
441                 cell_character1 = sdi_2100_cell_character1;
442                 cell_character2 = sdi_2100_cell_character2;
443                 break;
444         case BATTERY_SDI_3000:
445                 printf("%s\tupdate SDI 3000 parameter\n", pszfg);
446                 rcomp0 = SDI_3000_RCOMP0;
447                 tempco = SDI_3000_TEMPCO;
448                 cell_character0 = sdi_3000_cell_character0;
449                 cell_character1 = sdi_3000_cell_character1;
450                 cell_character2 = sdi_3000_cell_character2;
451                 break;
452
453         default:
454                 printf("%s\tunknown battery type, keep parameter\n", pszfg);
455                 break;
456         }
457
458         /* 1. Delay 500mS */
459         /* delay(500); */
460
461         /* 2. Initilize Configuration */
462         fuelgauge_reg_write(MAX77693_REG_CONFIG, 0x2210);
463
464 rewrite_model:
465         /* 4. Unlock Model Access */
466         fuelgauge_reg_write(0x62, 0x0059);
467         fuelgauge_reg_write(0x63, 0x00C4);
468
469         /* 5. Write/Read/Verify the Custom Model */
470         fuelgauge_reg_write_16n(0x80, cell_character0);
471         fuelgauge_reg_write_16n(0x90, cell_character1);
472         fuelgauge_reg_write_16n(0xA0, cell_character2);
473
474         fuelgauge_reg_read_16n(0x80, data0);
475         fuelgauge_reg_read_16n(0x90, data1);
476         fuelgauge_reg_read_16n(0xA0, data2);
477
478         for (i = 0; i < 16; i++) {
479                 if (cell_character0[i] != data0[i])
480                         goto rewrite_model;
481                 if (cell_character1[i] != data1[i])
482                         goto rewrite_model;
483                 if (cell_character2[i] != data2[i])
484                         goto rewrite_model;
485         }
486 relock_model:
487         /* 8. Lock model access */
488         fuelgauge_reg_write(0x62, 0x0000);
489         fuelgauge_reg_write(0x63, 0x0000);
490
491         /* 9. Verify the model access is locked */
492         fuelgauge_reg_read_16n(0x80, data0);
493         fuelgauge_reg_read_16n(0x90, data1);
494         fuelgauge_reg_read_16n(0xA0, data2);
495
496         for (i = 0; i < 16; i++) {
497                 /* if any model data is non-zero, it's not locked. */
498                 if (data0[i] || data1[i] || data2[i]) {
499                         if (rewrite_count--) {
500                                 printf("%s\tLock model access failed, rewrite it\n", pszfg);
501                                 goto rewrite_model;
502                         } else {
503                                 printf("%s\tLock model access failed, but ignore it\n", pszfg);
504                         }
505                 }
506         }
507
508         /* 10. Write Custom Parameters */
509         fuelgauge_reg_write_and_verify(0x38, rcomp0);
510         fuelgauge_reg_write_and_verify(0x39, tempco);
511
512         /* 11. Delay at least 350mS */
513         mdelay(350);
514
515         /* 12. Initialization Complete */
516         status = fuelgauge_reg_read(MAX77693_REG_STATUS);
517         /* Write and Verify Status with POR bit Cleared */
518         fuelgauge_reg_write_and_verify(MAX77693_REG_STATUS, (status & 0xFFFD));
519
520         /* 13. Idendify Battery */
521
522         /* 14. Check for Fuelgauge Reset */
523
524         /* 16. Save Learned Parameters */
525
526         /* 17. Restore Learned Parameters */
527
528         /* 18. Delay at least 350mS */
529
530         vcell = max77693_fg_get_average_vcell();
531         soc = max77693_fg_get_soc();
532         vfocv = max77693_fg_get_ocv();
533
534         printf("%s\tPOR finish: vcell(%d), vfocv(%d), soc(%d)\n", pszfg, vcell, vfocv, soc);
535 }
536
537 static int get_table_soc(u32 vcell, enum battery_type batt_type)
538 {
539         s32 raw_table_soc = 0;
540         u32 table_soc;
541         u32 idx_start, idx_end, idx;
542         struct table_soc_data *table_soc_data;
543
544         idx_start = 0;
545         idx_end = 0;
546
547         switch (batt_type) {
548         case BATTERY_SDI_2100:
549                 table_soc_data = sdi_2100_table_soc_data;
550                 idx_end = (int)ARRAY_SIZE(sdi_2100_table_soc_data) - 1;
551                 break;
552         case BATTERY_SDI_3000:
553                 table_soc_data = sdi_3000_table_soc_data;
554                 idx_end = (int)ARRAY_SIZE(sdi_3000_table_soc_data) - 1;
555                 break;
556         default:
557                 printf("%s\tunknown battery type. uses 2100mAh data default.\n", pszfg);
558                 table_soc_data = sdi_2100_table_soc_data;
559                 idx_end = (int)ARRAY_SIZE(sdi_2100_table_soc_data) - 1;
560                 break;
561         }
562
563         if (vcell < table_soc_data[idx_start].table_vcell) {
564                 printf("%s: vcell(%d) out of range, set table soc as 0\n", __func__, vcell);
565                 table_soc = 0;
566                 goto calculate_finish;
567         } else if (vcell > table_soc_data[idx_end].table_vcell) {
568                 printf("%s: vcell(%d) out of range, set table soc as 100\n", __func__, vcell);
569                 table_soc = 100;
570                 goto calculate_finish;
571         }
572
573         while (idx_start <= idx_end) {
574                 idx = (idx_start + idx_end) / 2;
575                 if (table_soc_data[idx].table_vcell > vcell) {
576                         idx_end = idx - 1;
577                 } else if (table_soc_data[idx].table_vcell < vcell) {
578                         idx_start = idx + 1;
579                 } else
580                         break;
581         }
582         table_soc = table_soc_data[idx].table_soc;
583
584         /* high resolution */
585         if (vcell < table_soc_data[idx].table_vcell)
586                 table_soc = table_soc_data[idx].table_soc -
587                         ((table_soc_data[idx].table_soc - table_soc_data[idx-1].table_soc) *
588                         (table_soc_data[idx].table_vcell - vcell) /
589                         (table_soc_data[idx].table_vcell - table_soc_data[idx-1].table_vcell));
590         else
591                 table_soc = table_soc_data[idx].table_soc +
592                         ((table_soc_data[idx+1].table_soc - table_soc_data[idx].table_soc) *
593                         (vcell - table_soc_data[idx].table_vcell) /
594                         (table_soc_data[idx+1].table_vcell - table_soc_data[idx].table_vcell));
595
596         printf("%s: vcell(%d) is caculated to t-soc(%d.%d)\n", __func__, vcell, table_soc / 1000, table_soc % 1000);
597         table_soc /= 1000;
598
599 calculate_finish:
600         return table_soc;
601 }
602
603 static int check_fuelgauge_powered(void)
604 {
605         int pwr_chk = 0;
606
607         pwr_chk = fuelgauge_reg_read(MAX77693_REG_OCV_RO);
608
609         if (pwr_chk < 0)
610                 return 0;
611         else
612                 return 1;
613 }
614
615 void max77693_fg_init(enum battery_type batt_type, int charger_type)
616 {
617         u32 soc, vcell, vfocv, power_check, table_soc, soc_diff, soc_chk_cnt, check_cnt;
618         u32 raw_data, t_raw_data;
619         u16 status, reg_data;
620         u8 recalculation_type = 0, soc_valid = 0;
621         u8 raw_vcell[2], t_raw_vcell[2] = {0 , 0};
622
623         if (max77693_fg_probe()) {
624                 printf("%s\tinitialize failed\n", pszfg);
625                 return;
626         }
627
628         power_check = check_fuelgauge_powered();
629         while (power_check == 0) {
630                 msleep(500);
631                 power_check = check_fuelgauge_powered();
632
633                 check_cnt++;
634                 printf("%s\t:fuelgauge is not powered(%d).\n", pszfg, check_cnt);
635
636                 if (check_cnt >= FUELGAUGE_POWER_CHECK_COUNT) {
637                         printf("%s\t:fuelgauge power failed.\n", pszfg);
638                         return;
639                 }
640         }
641
642         charger_status = charger_type;
643
644         rst_status = get_reset_status();
645
646         status = fuelgauge_reg_read(MAX77693_REG_STATUS);
647         if (status & 0x02) {
648                 max77693_fg_load_init_config(batt_type);
649                 por = 1;
650         } else {
651                 por = 0;
652         }
653
654         printf("%s\tpor = 0x%04x\n", pszfg, status);
655
656         vcell = max77693_fg_get_average_vcell();
657         raw_data = (vcell * 1000) / 625;
658         raw_data <<= 3;
659         raw_vcell[1] = (raw_data & 0xff00) >> 8;
660         raw_vcell[0] = raw_data & 0xff;
661
662         /* NOTICE : use soc after initializing, soc can be changed */
663         soc = max77693_fg_get_soc();
664         vfocv = max77693_fg_get_vfocv();
665         max77693_fg_check_version();
666
667         printf("%s\tvcell = %d mV, soc = %d, vfocv = %d mV\n",
668                 pszfg, vcell, soc, vfocv);
669
670         if ((batt_type == BATTERY_SDI_2100) || (batt_type == BATTERY_SDI_3000)) {
671                 table_soc = get_table_soc(vcell, batt_type);
672
673                 if (por == 0)
674                         goto init_finish;
675
676 check_soc_validation:
677                 /* check validation */
678                 if (soc > table_soc)
679                         soc_diff = soc - table_soc;
680                 else
681                         soc_diff = table_soc - soc;
682
683                 if (soc_diff > SOC_DIFF_TH) {
684                         printf("%s: [#%d] diff(%d), soc(%d) and table soc(%d)\n", __func__,
685                                 ++soc_chk_cnt, soc_diff, soc, table_soc);
686
687                         raw_data = (vcell * 1000) / 625;
688                         raw_data <<= 3;
689                         raw_vcell[1] = (raw_data & 0xff00) >> 8;
690                         raw_vcell[0] = raw_data & 0xff;
691                         fuelgauge_reg_write(MAX77693_REG_OCV_WR, (raw_vcell[1] << 8) | raw_vcell[0]);
692
693                         mdelay(300);
694
695                         soc = max77693_fg_get_soc();
696                         vfocv = max77693_fg_get_vfocv();
697                         vcell = max77693_fg_get_average_vcell();
698                         table_soc = get_table_soc(vcell, batt_type);
699
700                         if (soc_chk_cnt < SOC_DIFF_CHECK_COUNT)
701                                 goto check_soc_validation;
702                 }
703                 goto init_finish;
704         }
705
706         vfocv_table = 0;
707         recalculation_type = 0;
708
709         if (rst_status != SWRESET) {
710                 if (charger_status) {
711                         if (((vcell - CHG_DV) > (vfocv + T_DV)) ||      /* h/w POR and cable booting case */
712                             (vfocv > vcell))                            /* h/w POR with cable present case */
713                                 recalculation_type = 1;
714                 } else {
715                         if (((vcell + DSG_DV) > (vfocv + T_DV)) ||      /* fast batt exchange (low -> high) */
716                             (vfocv > ((vcell + DSG_DV) + T_DV)))        /* fast batt exchange (high -> low) */
717                                 recalculation_type = 2;
718                 }
719         }
720
721         if (vfocv_table != 0) {
722                 t_raw_data = (vfocv_table * 1000) / 625;
723                 t_raw_data <<= 3;
724                 t_raw_vcell[1] = (t_raw_data & 0xff00) >> 8;
725                 t_raw_vcell[0] = t_raw_data & 0xff;
726         }
727
728         switch (recalculation_type) {
729         case 1:
730         case 3:
731                 /* 0x200 means 40mV */
732                 if (vfocv_table != 0)
733                         fuelgauge_reg_write(MAX77693_REG_OCV_WR,
734                                         (t_raw_vcell[1] << 8) | t_raw_vcell[0]);
735                 else
736                         fuelgauge_reg_write(MAX77693_REG_OCV_WR,
737                                         ((raw_vcell[1] -
738                                           0x2) << 8) | (raw_vcell[0] - 0x00));
739                 mdelay(500);
740                 break;
741         case 2:
742         case 4:
743                 /* 0x2C0 means 55mV */
744                 /* 0x340 means 65mV */
745                 if (vfocv_table != 0)
746                         fuelgauge_reg_write(MAX77693_REG_OCV_WR,
747                                         (t_raw_vcell[1] << 8) | t_raw_vcell[0]);
748                 else
749                         fuelgauge_reg_write(MAX77693_REG_OCV_WR,
750                                         ((raw_vcell[1] +
751                                           0x3) << 8) | (raw_vcell[0] + 0x40));
752                 mdelay(500);
753                 break;
754         default:
755                 break;
756         }
757
758 init_finish:
759         /* NOTICE : use soc after initializing, soc can be changed */
760         soc = max77693_fg_get_soc();
761         vfocv = max77693_fg_get_vfocv();
762         max77693_fg_check_version();
763
764         printf("%s\tvcell = %d mV, soc = %d, vfocv = %d mV\n",
765                 pszfg, vcell, soc, vfocv);
766
767 }
768
769 static int max77693_fg_reg_dump(void)
770 {
771         int i;
772
773         printf("   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F");
774         for (i = 0; i < 0x100; i++) {
775                 if ((i % 0x10) == 0)
776                         printf("\n%02X ", i);
777
778                 printf("%04x ", fuelgauge_reg_read(i));
779         }
780         printf("\n");
781
782         return 0;
783 }
784
785 void max77693_fg_show_battery(void)
786 {
787         unsigned int soc = max77693_fg_get_soc();
788         unsigned int uV = max77693_fg_get_vcell();
789
790         if (max77693_fg_probe())
791                 return;
792
793         printf("battery:\t%d%%\n", soc);
794         printf("voltage:\t%d.%6.6d V\n", uV / 1000000, uV % 1000000);
795 }
796
797 static int do_max77693_fg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
798 {
799         switch (argc) {
800         case 2:
801                 if (!strncmp(argv[1], "dump", 4)) {
802                         max77693_fg_probe();
803                         max77693_fg_reg_dump();
804                         return 0;
805                 } else {
806                         cmd_usage(cmdtp);
807                         return 1;
808                 }
809                 break;
810         default:
811                 cmd_usage(cmdtp);
812                 return 1;
813         }
814 }
815
816 U_BOOT_CMD(
817         fg, 4, 1, do_max77693_fg,
818         "Fuel gauge utility for MAX77693-FG",
819         "dump - dump the register\n"
820 );