power: rk81x-battery: update verison to 4.0.0
authorchenjh <chenjh@rock-chips.com>
Tue, 12 May 2015 09:22:33 +0000 (17:22 +0800)
committer许盛飞 <xsf@rock-chips.com>
Fri, 5 Jun 2015 10:18:58 +0000 (18:18 +0800)
this verison can support both ARM and SOFIA platform.

Signed-off-by: chenjh <chenjh@rock-chips.com>
Signed-off-by: 许盛飞 <xsf@rock-chips.com>
drivers/power/rk818_battery.c
drivers/power/rk818_battery.h [new file with mode: 0644]
include/linux/mfd/rk818.h
include/linux/power/rk818_battery.h [deleted file]

index c544efd7bda0b568c8a908a872785e2c9747c7e8..433077c370e4188420411ecb80a4363bbed794a2 100755 (executable)
@@ -1,11 +1,31 @@
 /*
- * rk818  battery driver
+ * rk818/rk819 battery driver
  *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- * */
-
+ *  Copyright (C) 2014 Rockchip Electronics Co., Ltd
+ *  Author: zhangqing <zhangqing@rock-chips.com>
+ *         chenjh    <chenjh@rock-chips.com>
+ *          Andy Yan  <andy.yan@rock-chips.com>
+ *
+ *  Copyright (C) 2008-2009 Texas Instruments, Inc.
+ *  Author: Texas Instruments, Inc.
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Author: Texas Instruments, Inc.
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: zhangqing <zhangqing@rock-chips.com>
+ * Copyright (C) 2014-2015 Intel Mobile Communications GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/param.h>
 #include <linux/jiffies.h>
@@ -20,7 +40,6 @@
 #include <linux/gpio.h>
 #include <linux/proc_fs.h>
 #include <linux/uaccess.h>
-#include <linux/power/rk818_battery.h>
 #include <linux/mfd/rk818.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/of_gpio.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
+#include <linux/usb/phy.h>
+#include <linux/fb.h>
+
+#if defined(CONFIG_X86_INTEL_SOFIA)
+#include <linux/usb/phy-intel.h>
+#endif
+#include "rk818_battery.h"
 
 /* if you  want to disable, don't set it as 0,
-                       just be: "static int dbg_enable;" is ok*/
+just be: "static int dbg_enable;" is ok*/
+
 static int dbg_enable;
 #define RK818_SYS_DBG 1
 
 module_param_named(dbg_level, dbg_enable, int, 0644);
+
 #define DBG(args...) \
        do { \
                if (dbg_enable) { \
@@ -43,32 +71,31 @@ module_param_named(dbg_level, dbg_enable, int, 0644);
                } \
        } while (0)
 
-
 #define DEFAULT_BAT_RES                        135
-#define DEFAULT_VLMT                   4200
-#define DEFAULT_ILMT                   2000
-#define DEFAULT_ICUR                   1600
-
-#define DEF_TEST_ILMT_MA               2000
-#define DEF_TEST_CURRENT_MA            1800
+#define DEFAULT_CHRG_VOL               4200
+#define DEFAULT_CHRG_CUR               1000
+#define DEFAULT_INPUT_CUR              1400
+#define DEFAULT_SLP_ENTER_CUR          600
+#define DEFAULT_SLP_EXIT_CUR           600
 
+#define DSOC_DISCHRG_EMU_CURR          1200
 #define DSOC_DISCHRG_FAST_DEC_SEC      120     /*seconds*/
-#define DSOC_DISCHRG_FAST_EER_RANGE    25
+#define DSOC_DISCHRG_FAST_EER_RANGE    10
 #define DSOC_CHRG_FAST_CALIB_CURR_MAX  400     /*mA*/
 #define DSOC_CHRG_FAST_INC_SEC         120     /*seconds*/
-#define DSOC_CHRG_FAST_EER_RANGE       15
+#define DSOC_CHRG_FAST_EER_RANGE       10
 #define DSOC_CHRG_EMU_CURR             1200
-#define DSOC_CHG_TERM_CURR             600
-#define DSOC_CHG_TERM_VOL              4100
-#define        CHG_FINISH_VOL                  4100
+#define DSOC_CHRG_TERM_CURR            600
+#define DSOC_CHRG_TERM_VOL             4100
+#define        CHRG_FINISH_VOL                 4100
 
 /*realtime RSOC calib param*/
-#define RSOC_DISCHG_ERR_LOWER  40
-#define RSOC_DISCHG_ERR_UPPER  50
+#define RSOC_DISCHRG_ERR_LOWER 40
+#define RSOC_DISCHRG_ERR_UPPER 50
 #define RSOC_ERR_CHCK_CNT      15
 #define RSOC_COMPS             20      /*compensation*/
 #define RSOC_CALIB_CURR_MAX    900     /*mA*/
-#define RSOC_CALIB_DISCHGR_TIME        3       /*min*/
+#define RSOC_CALIB_DISCHRGR_TIME       3       /*min*/
 
 #define RSOC_RESUME_ERR                10
 #define REBOOT_INTER_MIN       1
@@ -77,9 +104,9 @@ module_param_named(dbg_level, dbg_enable, int, 0644);
 #define MAX_INT                        0x7FFF
 #define TIME_10MIN_SEC         600
 
-#define CHG_VOL_SHIFT          4
-#define CHG_ILIM_SHIFT         0
-#define CHG_ICUR_SHIFT         0
+#define CHRG_VOL_SHIFT         4
+#define CHRG_ILIM_SHIFT                0
+#define CHRG_ICUR_SHIFT                0
 #define DEF_CHRG_VOL           CHRG_VOL4200
 #define DEF_CHRG_CURR_SEL      CHRG_CUR1400mA
 #define DEF_CHRG_CURR_LMT      ILIM_2000MA
@@ -93,69 +120,95 @@ module_param_named(dbg_level, dbg_enable, int, 0644);
 #define TEST_AC_ONLINE         1
 #define TEST_USB_ONLINE                0
 
+#define ZERO_ALGOR_THRESD      3800
+#define DISCHRG_ZERO_MODE      1
+#define DISCHRG_NORMAL_MODE    0
+#define DEF_LAST_ZERO_MODE_SOC -1
+
+#define        DISCHRG_MODE            0
+#define        CHRG_MODE               1
+
+#define        TREND_STAT_FLAT         0
+#define        TREND_STAT_DOWN         -1
+#define        TREND_STAT_UP           1
+#define        TREND_CAP_DIFF          5
+
+#define MINUTE                 60
+
+#define SLP_CURR_MAX           40
+#define SLP_CURR_MIN           6
+#define WAKEUP_SEC_THRESD      40
+#define CHRG_TIME_STEP         (60)
+#define DISCHRG_TIME_STEP_0    (30 * 60)
+#define DISCHRG_TIME_STEP_1    (60 * 60)
+
+#define DEF_PCB_OFFSET         42
+#define DEF_CAL_OFFSET         0x832
+#define DEF_PWRPATH_RES                50
+#define SEC_TO_EMPTY           300
+#define DSOC_CHRG_FINISH_CURR  1100
+#define SLP_CHRG_CURR          1000
+#define SLP_DSOC_VOL_THRESD    3600
+#define PWR_OFF_THRESD         3400
+#define MIN_ZERO_ACCURACY      10      /*0.01%*/
+
+#define MAX_FCC                        10000
+#define MIN_FCC                        500
 /*
  * the following table value depends on datasheet
  */
-int CHG_V_LMT[] = {4050, 4100, 4150, 4200, 4300, 4350};
+int CHRG_V_LMT[] = {4050, 4100, 4150, 4200, 4300, 4350};
 
-int CHG_I_CUR[] = {1000, 1200, 1400, 1600, 1800, 2000,
+int CHRG_I_CUR[] = {1000, 1200, 1400, 1600, 1800, 2000,
                   2250, 2400, 2600, 2800, 3000};
 
-int CHG_I_LMT[] = {450, 800, 850, 1000, 1250, 1500, 1750,
+int CHRG_I_LMT[] = {450, 800, 850, 1000, 1250, 1500, 1750,
                   2000, 2250, 2500, 2750, 3000};
 
-u8 CHG_CVCC_HOUR[] = {4, 5, 6, 8, 10, 12, 14, 16};
+u8 CHRG_CVCC_HOUR[] = {4, 5, 6, 8, 10, 12, 14, 16};
 
 #define RK818_DC_IN            0
 #define RK818_DC_OUT           1
-#define SEC_TO_MIN(x)          ((x)/60)
-#define BASE_TO_MIN(x)         ((get_seconds()-(x))/60)
-#define BASE_TO_SEC(x)         (get_seconds()-(x))
 
 #define        OCV_VALID_SHIFT         (0)
 #define        OCV_CALIB_SHIFT         (1)
 #define FIRST_PWRON_SHIFT      (2)
+#define LOADER_CHRG_SHIFT      (3)
 
+#define SEC_TO_MIN(x)          ((x) / 60)
 
-struct battery_info {
+struct rk81x_battery {
        struct device                   *dev;
        struct cell_state               cell;
        struct power_supply             bat;
        struct power_supply             ac;
        struct power_supply             usb;
        struct delayed_work             work;
-       /* struct i2c_client            *client; */
        struct rk818                    *rk818;
-       struct pinctrl                  *pinctrl;
-       struct pinctrl_state            *pins_default;
-
+       struct pinctrl                  *pinctrl;
+       struct pinctrl_state            *pins_default;
 
-       struct battery_platform_data    *platform_data;
+       struct battery_platform_data    *pdata;
 
        int                             dc_det_pin;
        int                             dc_det_level;
-       int                             dc_det_pullup_inside;
-       int                             work_on;
+       int                             dc_det_irq;
        int                             irq;
        int                             ac_online;
        int                             usb_online;
-       int                             dc_online;
-       int                             status;
+       int                             psy_status;
        int                             current_avg;
        int                             current_offset;
 
        uint16_t                        voltage;
        uint16_t                        voltage_ocv;
        uint16_t                        relax_voltage;
-       u8                              charge_status;
+       u8                              chrg_status;
+       u8                              slp_chrg_status;
+
        u8                              otg_status;
        int                             pcb_ioffset;
        bool                            pcb_ioffset_updated;
-       unsigned long                   queue_work_cnt;
-       u32                             term_chg_cnt;
-       u32                             emu_chg_cnt;
-
-       uint16_t                        warnning_voltage;
 
        int                             design_capacity;
        int                             fcc;
@@ -163,10 +216,10 @@ struct battery_info {
        int                             remain_capacity;
        int                             nac;
        int                             temp_nac;
-       int                             real_soc;
+       int                             dsoc;
        int                             display_soc;
-       int                             odd_capacity;
-       int                             temp_soc;
+       int                             rsoc;
+       int                             trend_start_cap;
 
        int                             est_ocv_vol;
        int                             est_ocv_soc;
@@ -196,86 +249,139 @@ struct battery_info {
 
        int                             voltage_k;/* VCALIB0 VCALIB1 */
        int                             voltage_b;
+       bool                            enter_finish;
+       int                             zero_timeout_cnt;
+       int                             zero_old_remain_cap;
 
-       int                             zero_updated;
-       int                             old_display_soc;
-       int                             zero_cycle;
-
-
-       int                             update_k;
        int                             line_k;
-       int                             voltage_old;
-
-       int                             q_dead;
-       int                             q_err;
-       int                             q_shtd;
-
        u8                              check_count;
-       /* u32                          status; */
-       struct timeval                  soc_timer;
-       struct timeval                  change_timer;
 
-       int                             vol_smooth_time;
        int                             charge_smooth_time;
        int                             sum_suspend_cap;
        int                             suspend_cap;
-       int                             resume_capacity;
-       struct timespec                 suspend_time;
-       struct timespec                 resume_time;
-       unsigned long                   suspend_time_start;
-       unsigned long                   count_sleep_time;
+
+       unsigned long                   suspend_time_sum;
 
        int                             suspend_rsoc;
-       int                             sleep_status;
+       int                             slp_psy_status;
        int                             suspend_charge_current;
        int                             resume_soc;
        int                             bat_res;
-       bool                            bat_res_updated;
        bool                            charge_smooth_status;
-       bool                            resume;
-       unsigned long                   last_plugin_time;
-       bool                            sys_wakeup;
+       bool                            discharge_smooth_status;
 
-       unsigned long                   charging_time;
-       unsigned long                   discharging_time;
-       unsigned long                   finish_time;
+       u32                             plug_in_min;
+       u32                             plug_out_min;
+       u32                             finish_sig_min;
 
-       u32                             charge_min;
-       u32                             discharge_min;
-       u32                             finish_min;
        struct notifier_block           battery_nb;
+       struct usb_phy                  *usb_phy;
+       struct notifier_block           usb_nb;
+       struct notifier_block           fb_nb;
+       int                             fb_blank;
+       int                             early_resume;
+       int                             s2r; /*suspend to resume*/
        struct workqueue_struct         *wq;
        struct delayed_work             battery_monitor_work;
        struct delayed_work             charge_check_work;
+       struct delayed_work             usb_phy_delay_work;
+       struct delayed_work             chrg_term_mode_switch_work;
        int                             charge_otg;
+       int                             ma;
 
        struct wake_lock                resume_wake_lock;
-       unsigned long                   sys_on_base;
-       unsigned long                   chrg_time_base;
-       int                             chrg_time2_full;
-       int                             chrg_cap2_full;
+       unsigned long                   plug_in_base;
+       unsigned long                   plug_out_base;
+       unsigned long                   finish_sig_base;
+       unsigned long                   power_on_base;
 
-       bool                            is_first_poweron;
-       int                             first_on_cap;
+       int                             chrg_time2full;
+       int                             chrg_cap2full;
 
+       bool                            is_first_poweron;
 
        int                             fg_drv_mode;
-       int                             test_chrg_current;
-       int                             test_chrg_ilmt;
        int                             debug_finish_real_soc;
        int                             debug_finish_temp_soc;
        int                             chrg_min[10];
-       int                             chg_v_lmt;
-       int                             chg_i_lmt;
-       int                             chg_i_cur;
-
+       int                             chrg_v_lmt;
+       int                             chrg_i_lmt;
+       int                             chrg_i_cur;
+       uint16_t                        pwroff_min;
+       unsigned long                   wakeup_sec;
+       u32                             delta_vol_smooth;
+       unsigned long                   dischrg_normal_base;
+       unsigned long                   dischrg_emu_base;
+       unsigned long                   chrg_normal_base;
+       unsigned long                   chrg_term_base;
+       unsigned long                   chrg_emu_base;
+       unsigned long                   chrg_finish_base;
+       unsigned long                   fcc_update_sec;
+       int                             loader_charged;
+       u8                              dischrg_algorithm_mode;
+       int                             last_zero_mode_dsoc;
+       u8                              current_mode;
+       unsigned long                   dischrg_save_sec;
+       unsigned long                   chrg_save_sec;
+       struct timeval                  suspend_rtc_base;
 };
 
-struct battery_info *g_battery;
-u32 support_uboot_chrg, support_usb_adp, support_dc_adp;
-static void rk81x_update_battery_info(struct battery_info *di);
+u32 support_usb_adp, support_dc_adp;
+
+#define to_device_info(x) container_of((x), \
+                               struct rk81x_battery, bat)
+
+#define to_ac_device_info(x) container_of((x), \
+                               struct rk81x_battery, ac)
+
+#define to_usb_device_info(x) container_of((x), \
+                               struct rk81x_battery, usb)
+
+static int loader_charged;
+
+static int __init rk81x_bat_loader_charged(char *__unused)
+{
+       loader_charged = 1;
+
+       pr_info("battery charged in loader\n");
+
+       return 0;
+}
+__setup("loader_charged", rk81x_bat_loader_charged);
+
+static u64 g_base_sec;
+static u64 get_runtime_sec(void)
+{
+       u64 ts_ns = local_clock();
+
+       do_div(ts_ns, 1000000000);
+
+       return ts_ns + g_base_sec;
+}
+
+static u64 is_local_clock_reset(void)
+{
+       u64 ts_ns = local_clock();
+
+       do_div(ts_ns, 1000000000);
+
+       return !ts_ns;
+}
+
+static inline unsigned long  BASE_TO_SEC(unsigned long x)
+{
+       if (x)
+               return get_runtime_sec() - x;
+       else
+               return 0;
+}
 
-static bool rk81x_support_adp_type(enum hw_support_adp_t type)
+static inline unsigned long BASE_TO_MIN(unsigned long x)
+{
+       return  BASE_TO_SEC(x) / 60;
+}
+
+static bool rk81x_bat_support_adp_type(enum hw_support_adp type)
 {
        bool bl = false;
 
@@ -299,6 +405,11 @@ static bool rk81x_support_adp_type(enum hw_support_adp_t type)
        return bl;
 }
 
+static bool rk81x_chrg_online(struct rk81x_battery *di)
+{
+       return di->usb_online || di->ac_online;
+}
+
 static u32 interpolate(int value, u32 *table, int size)
 {
        uint8_t i;
@@ -310,11 +421,11 @@ static u32 interpolate(int value, u32 *table, int size)
        }
 
        if ((i > 0) && (i < size)) {
-               d = (value - table[i-1]) * (INTERPOLATE_MAX/(size-1));
+               d = (value - table[i-1]) * (INTERPOLATE_MAX / (size - 1));
                d /= table[i] - table[i-1];
-               d = d + (i-1) * (INTERPOLATE_MAX/(size-1));
+               d = d + (i-1) * (INTERPOLATE_MAX / (size - 1));
        } else {
-               d = i * ((INTERPOLATE_MAX+size/2)/size);
+               d = i * ((INTERPOLATE_MAX + size / 2) / size);
        }
 
        if (d > 1000)
@@ -322,6 +433,7 @@ static u32 interpolate(int value, u32 *table, int size)
 
        return d;
 }
+
 /* Returns (a * b) / c */
 static int32_t ab_div_c(u32 a, u32 b, u32 c)
 {
@@ -335,7 +447,7 @@ static int32_t ab_div_c(u32 a, u32 b, u32 c)
                if (sign)
                        c = -c;
 
-               tmp = ((int32_t) a*b + (c>>1)) / c;
+               tmp = (a * b + (c >> 1)) / c;
 
                if (tmp < MAX_INT)
                        ans = tmp;
@@ -347,99 +459,160 @@ static int32_t ab_div_c(u32 a, u32 b, u32 c)
        return ans;
 }
 
-static  int32_t abs_int(int32_t x)
+static int div(int val)
 {
-       return (x > 0) ? x : -x;
+       return (val == 0) ? 1 : val;
 }
 
-static  int abs32_int(int x)
+static int rk81x_bat_read(struct rk81x_battery *di, u8 reg,
+                         u8 buf[], unsigned len)
 {
-       return (x > 0) ? x : -x;
-}
+       int ret = -1;
+       int i;
 
-static int div(int val)
-{
-       return (val == 0) ? 1 : val;
+       for (i = 0; ret < 0 && i < 3; i++) {
+               ret = rk818_i2c_read(di->rk818, reg, len, buf);
+               if (ret < 0)
+                       dev_err(di->dev, "read reg:0x%02x failed\n", reg);
+       }
+
+       return (ret < 0) ? ret : 0;
 }
 
-static int battery_read(struct rk818 *rk818, u8 reg,
-                       u8 buf[], unsigned len)
+static int rk81x_bat_write(struct rk81x_battery *di, u8 reg,
+                          u8 const buf[], unsigned len)
 {
-       int ret;
+       int ret = -1;
+       int i;
 
-       ret = rk818_i2c_read(rk818, reg, len, buf);
-       return ret;
+       for (i = 0; ret < 0 && i < 3; i++) {
+               ret = rk818_i2c_write(di->rk818, reg, (int)len, *buf);
+               if (ret < 0)
+                       dev_err(di->dev, "write reg:0x%02x failed\n", reg);
+       }
+
+       return (ret < 0) ? ret : 0;
 }
 
-static int battery_write(struct rk818 *rk818, u8 reg,
-                        u8 const buf[], unsigned len)
+static int rk81x_bat_set_bit(struct rk81x_battery *di, u8 reg, u8 shift)
 {
-       int ret;
+       int ret = -1;
+       int i;
+
+       for (i = 0; ret < 0 && i < 3; i++) {
+               ret = rk818_set_bits(di->rk818, reg, 1 << shift, 1 << shift);
+               if (ret < 0)
+                       dev_err(di->dev, "set reg:0x%02x failed\n", reg);
+       }
 
-       ret = rk818_i2c_write(rk818, reg, (int)len, *buf);
        return ret;
 }
 
-static void rk81x_set_bit(struct battery_info *di, u8 reg, u8 shift)
+static int rk81x_bat_clr_bit(struct rk81x_battery *di, u8 reg, u8 shift)
 {
-       rk818_set_bits(di->rk818, reg, 1 << shift, 1 << shift);
-}
+       int ret = -1;
+       int i;
 
-static void rk81x_clr_bit(struct battery_info *di, u8 reg, u8 shift)
-{
-       rk818_set_bits(di->rk818, reg, 1 << shift, 0 << shift);
+       for (i = 0; ret < 0 && i < 3; i++) {
+               ret = rk818_set_bits(di->rk818, reg, 1 << shift, 0 << shift);
+               if (ret < 0)
+                       dev_err(di->dev, "set reg:0x%02x failed\n", reg);
+       }
+
+       return ret;
 }
 
-static u8 rk81x_read_bit(struct battery_info *di, u8 reg, u8 shift)
+static u8 rk81x_bat_read_bit(struct rk81x_battery *di, u8 reg, u8 shift)
 {
        u8 buf;
        u8 val;
 
-       battery_read(di->rk818, reg, &buf, 1);
+       rk81x_bat_read(di, reg, &buf, 1);
        val = (buf & BIT(shift)) >> shift;
        return val;
 }
 
-static void dump_gauge_register(struct battery_info *di)
+static void rk81x_dbg_dmp_gauge_regs(struct rk81x_battery *di)
 {
        int i = 0;
-       char buf;
+       u8 buf;
 
        DBG("%s dump charger register start:\n", __func__);
-       for (i = 0xAC; i < 0xDF; i++) {
-               battery_read(di->rk818, i, &buf, 1);
-               DBG(" the register is  0x%02x, the value is 0x%02x\n", i, buf);
+       for (i = 0xAC; i < 0xEE; i++) {
+               rk81x_bat_read(di, i, &buf, 1);
+               DBG("0x%02x : 0x%02x\n", i, buf);
        }
        DBG("demp end!\n");
 }
 
-static void dump_charger_register(struct battery_info *di)
+static void rk81x_dbg_dmp_charger_regs(struct rk81x_battery *di)
 {
        int i = 0;
        char buf;
 
        DBG("%s dump the register start:\n", __func__);
        for (i = 0x99; i < 0xAB; i++) {
-               battery_read(di->rk818, i, &buf, 1);
+               rk81x_bat_read(di, i, &buf, 1);
                DBG(" the register is  0x%02x, the value is 0x%02x\n", i, buf);
        }
        DBG("demp end!\n");
 }
 
-#if RK818_SYS_DBG
+static void rk81x_bat_reset_zero_var(struct rk81x_battery *di)
+{
+       di->dischrg_algorithm_mode = DISCHRG_NORMAL_MODE;
+       di->last_zero_mode_dsoc = DEF_LAST_ZERO_MODE_SOC;
+}
+
+static void rk81x_bat_capacity_init_post(struct rk81x_battery *di)
+{
+       rk81x_bat_reset_zero_var(di);
+       di->trend_start_cap = di->remain_capacity;
+}
 
-static void  _capacity_init(struct battery_info *di, u32 capacity);
+static void rk81x_bat_capacity_init(struct rk81x_battery *di, u32 capacity)
+{
+       u8 buf;
+       u32 capacity_ma;
+       int delta_cap;
+
+       delta_cap = capacity - di->remain_capacity;
+       if (!delta_cap)
+               return;
+
+       di->adjust_cap += delta_cap;
+
+       capacity_ma = capacity * 2390;/* 2134;//36*14/900*4096/521*500; */
+       do {
+               buf = (capacity_ma >> 24) & 0xff;
+               rk81x_bat_write(di, GASCNT_CAL_REG3, &buf, 1);
+               buf = (capacity_ma >> 16) & 0xff;
+               rk81x_bat_write(di, GASCNT_CAL_REG2, &buf, 1);
+               buf = (capacity_ma >> 8) & 0xff;
+               rk81x_bat_write(di, GASCNT_CAL_REG1, &buf, 1);
+               buf = (capacity_ma & 0xff) | 0x01;
+               rk81x_bat_write(di, GASCNT_CAL_REG0, &buf, 1);
+               rk81x_bat_read(di, GASCNT_CAL_REG0, &buf, 1);
+
+       } while (buf == 0);
+
+       dev_info(di->dev, "update capacity :%d--remain_cap:%d\n",
+                capacity, di->remain_capacity);
+}
 
+#if RK818_SYS_DBG
 /*
- * interface for debug: do rsoc_first_poweron_init() without unloading battery
+ * interface for debug: do rk81x_bat_first_pwron() without unloading battery
  */
 static ssize_t bat_calib_read(struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
        int val;
 
-       val = rk81x_read_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
+       val = rk81x_bat_read_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
+
        return sprintf(buf, "%d\n", val);
 }
 
@@ -449,16 +622,17 @@ static ssize_t bat_calib_write(struct device *dev,
 {
        u8 val;
        int ret;
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
        ret = kstrtou8(buf, 0, &val);
        if (ret < 0)
                return ret;
 
        if (val)
-               rk81x_set_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
+               rk81x_bat_set_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
        else
-               rk81x_clr_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
+               rk81x_bat_clr_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
        return count;
 }
 
@@ -468,7 +642,8 @@ static ssize_t bat_calib_write(struct device *dev,
 static ssize_t bat_test_power_read(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
        return sprintf(buf, "%d\n", di->fg_drv_mode);
 }
@@ -479,7 +654,8 @@ static ssize_t bat_test_power_write(struct device *dev,
 {
        u8 val;
        int ret;
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
        ret = kstrtou8(buf, 0, &val);
        if (ret < 0)
@@ -493,22 +669,13 @@ static ssize_t bat_test_power_write(struct device *dev,
        return count;
 }
 
-
-static ssize_t bat_state_read(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct battery_info *di = g_battery;
-
-       return sprintf(buf, "dsoc = %d, rsoc = %d\n",
-                               di->real_soc, di->temp_soc);
-}
-
 static ssize_t bat_fcc_read(struct device *dev,
                            struct device_attribute *attr, char *buf)
 {
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
-       return sprintf(buf, "%d", di->fcc);
+       return sprintf(buf, "%d\n", di->fcc);
 }
 
 static ssize_t bat_fcc_write(struct device *dev,
@@ -517,7 +684,8 @@ static ssize_t bat_fcc_write(struct device *dev,
 {
        u16 val;
        int ret;
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
        ret = kstrtou16(buf, 0, &val);
        if (ret < 0)
@@ -528,316 +696,198 @@ static ssize_t bat_fcc_write(struct device *dev,
        return count;
 }
 
-
-static ssize_t bat_soc_read(struct device *dev,
-                           struct device_attribute *attr, char *buf)
+static ssize_t bat_dsoc_read(struct device *dev,
+                            struct device_attribute *attr, char *buf)
 {
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
-       return sprintf(buf, "%d", di->real_soc);
+       return sprintf(buf, "%d\n", di->dsoc);
 }
 
-static ssize_t bat_soc_write(struct device *dev,
-                            struct device_attribute *attr,
+static ssize_t bat_dsoc_write(struct device *dev,
+                             struct device_attribute *attr,
                             const char *buf, size_t count)
 {
        u8 val;
        int ret;
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
        ret = kstrtou8(buf, 0, &val);
        if (ret < 0)
                return ret;
 
-       di->real_soc = val;
+       di->dsoc = val;
 
        return count;
 }
-static ssize_t bat_temp_soc_read(struct device *dev,
-                                struct device_attribute *attr, char *buf)
+
+static ssize_t bat_rsoc_read(struct device *dev,
+                            struct device_attribute *attr, char *buf)
 {
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
-       return sprintf(buf, "%d", di->temp_soc);
+       return sprintf(buf, "%d\n", di->rsoc);
 }
 
-static ssize_t bat_temp_soc_write(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
+static ssize_t bat_rsoc_write(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
 {
        u8 val;
        int ret;
        u32 capacity;
-       struct battery_info *di = g_battery;
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
        ret = kstrtou8(buf, 0, &val);
        if (ret < 0)
                return ret;
 
-       capacity = di->fcc*val/100;
-       _capacity_init(di, capacity);
+       capacity = di->fcc * val / 100;
+       rk81x_bat_capacity_init(di, capacity);
+       rk81x_bat_capacity_init_post(di);
 
        return count;
 }
 
-static ssize_t bat_voltage_read(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct battery_info *di = g_battery;
-
-       return sprintf(buf, "%d", di->voltage);
-}
-
-static ssize_t bat_avr_current_read(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       struct battery_info *di = g_battery;
-
-       return sprintf(buf, "%d", di->current_avg);
-}
-
 static ssize_t bat_remain_cap_read(struct device *dev,
                                   struct device_attribute *attr,
                                   char *buf)
 {
-       struct battery_info *di = g_battery;
-
-       return sprintf(buf, "%d", di->remain_capacity);
-}
-
-/*
- * interface for debug: debug info switch
- */
-static ssize_t bat_debug_write(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
-{
-       u8 val;
-       int ret;
-
-       ret = kstrtou8(buf, 0, &val);
-       if (ret < 0)
-               return ret;
-
-       dbg_enable = val;
-
-       return count;
-}
-
-static ssize_t bat_regs_read(struct device *dev,
-                            struct device_attribute *attr, char *buf)
-{
-       u32 i;
-       u32 start_offset = 0x0;
-       u32 end_offset = 0xf2;
-       struct battery_info *di = g_battery;
-       u8 val;
-       char *str = buf;
-
-       str += sprintf(str, "start from add=0x%x, offset=0x%x\n",
-                      start_offset, end_offset);
+       struct power_supply *psy_bat = dev_get_drvdata(dev);
+       struct rk81x_battery *di = to_device_info(psy_bat);
 
-       for (i = start_offset; i <= end_offset; ) {
-               battery_read(di->rk818, i, &val, 1);
-               str += sprintf(str, "0x%x=0x%x", i, val);
-
-               if (i % 4 == 0) {
-                       str += sprintf(str, "\n");
-               } else {
-                       if (i != end_offset)
-                               str += sprintf(str, "   ");
-                       else
-                               str += sprintf(str, "\n");
-               }
-               i++;
-       }
-       return (str - buf);
+       return sprintf(buf, "%d\n", di->remain_capacity);
 }
 
-
 static struct device_attribute rk818_bat_attr[] = {
        __ATTR(fcc, 0664, bat_fcc_read, bat_fcc_write),
-       __ATTR(soc, 0664, bat_soc_read, bat_soc_write),
-       __ATTR(temp_soc, 0664, bat_temp_soc_read, bat_temp_soc_write),
-       __ATTR(voltage, 0664, bat_voltage_read, NULL),
-       __ATTR(avr_current, 0664, bat_avr_current_read, NULL),
+       __ATTR(dsoc, 0664, bat_dsoc_read, bat_dsoc_write),
+       __ATTR(rsoc, 0664, bat_rsoc_read, bat_rsoc_write),
        __ATTR(remain_capacity, 0664, bat_remain_cap_read, NULL),
-       __ATTR(debug, 0664, NULL, bat_debug_write),
-       __ATTR(regs, 0664, bat_regs_read, NULL),
-       __ATTR(state, 0664, bat_state_read, NULL),
        __ATTR(test_power, 0664, bat_test_power_read, bat_test_power_write),
        __ATTR(calib, 0664, bat_calib_read, bat_calib_write),
 };
-
 #endif
 
-static uint16_t get_relax_voltage(struct battery_info *di);
-
-static ssize_t show_state_attrs(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct battery_info *data = g_battery;
-
-       if (0 == get_relax_voltage(data)) {
-               return sprintf(buf,
-                       "voltage = %d, remain_capacity = %d, status = %d\n",
-                       data->voltage, data->remain_capacity,
-                       data->status);
-
-       } else
-               return sprintf(buf,
-                       "voltage = %d, remain_capacity = %d, status = %d\n",
-                       get_relax_voltage(data), data->remain_capacity,
-                       data->status);
-}
-
-static ssize_t restore_state_attrs(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       return size;
-}
-static struct device_attribute rkbatt_attrs[] = {
-       __ATTR(state, 0664, show_state_attrs, restore_state_attrs),
-};
-
-static int create_sysfs_interfaces(struct device *dev)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(rkbatt_attrs); i++) {
-               if (device_create_file(dev, rkbatt_attrs + i))
-                       goto error;
-       }
-
-       return 0;
-
-error:
-       for (; i >= 0; i--)
-               device_remove_file(dev, rkbatt_attrs + i);
-
-       dev_err(dev, "%s:Unable to create sysfs interface\n", __func__);
-       return -1;
-}
-
-static int  _gauge_enable(struct battery_info *di)
+static int rk81x_bat_gauge_enable(struct rk81x_battery *di)
 {
        int ret;
        u8 buf;
 
-
-       ret = battery_read(di->rk818, TS_CTRL_REG, &buf, 1);
+       ret = rk81x_bat_read(di, TS_CTRL_REG, &buf, 1);
        if (ret < 0) {
                dev_err(di->dev, "error reading TS_CTRL_REG");
                return ret;
        }
-       if (!(buf & GG_EN)) {
-               buf |= GG_EN;
-               ret = battery_write(di->rk818, TS_CTRL_REG, &buf, 1);/*enable*/
-               ret = battery_read(di->rk818, TS_CTRL_REG, &buf, 1);
-               return 0;
-       }
 
-       DBG("%s, %d\n", __func__, buf);
+       buf |= GG_EN;
+       rk81x_bat_write(di, TS_CTRL_REG, &buf, 1);
+
        return 0;
 }
 
-static void save_level(struct  battery_info *di, u8 save_soc)
+static void rk81x_bat_save_level(struct  rk81x_battery *di, u8 save_soc)
 {
-       u8 soc;
-
-       soc = save_soc;
-       battery_write(di->rk818, UPDAT_LEVE_REG, &soc, 1);
+       rk81x_bat_write(di, UPDAT_LEVE_REG, &save_soc, 1);
 }
-static u8 get_level(struct  battery_info *di)
+
+static u8 rk81x_bat_get_level(struct  rk81x_battery *di)
 {
        u8 soc;
 
-       battery_read(di->rk818, UPDAT_LEVE_REG, &soc, 1);
+       rk81x_bat_read(di, UPDAT_LEVE_REG, &soc, 1);
+
        return soc;
 }
 
-static int _get_vcalib0(struct battery_info *di)
+static int rk81x_bat_get_vcalib0(struct rk81x_battery *di)
 {
        int ret;
        int temp = 0;
        u8 buf;
 
-       ret = battery_read(di->rk818, VCALIB0_REGL, &buf, 1);
+       ret = rk81x_bat_read(di, VCALIB0_REGL, &buf, 1);
        temp = buf;
-       ret = battery_read(di->rk818, VCALIB0_REGH, &buf, 1);
-       temp |= buf<<8;
+       ret = rk81x_bat_read(di, VCALIB0_REGH, &buf, 1);
+       temp |= buf << 8;
 
        DBG("%s voltage0 offset vale is %d\n", __func__, temp);
        return temp;
 }
 
-static int _get_vcalib1(struct  battery_info *di)
+static int rk81x_bat_get_vcalib1(struct  rk81x_battery *di)
 {
        int ret;
        int temp = 0;
        u8 buf;
 
-       ret = battery_read(di->rk818, VCALIB1_REGL, &buf, 1);
+       ret = rk81x_bat_read(di, VCALIB1_REGL, &buf, 1);
        temp = buf;
-       ret = battery_read(di->rk818, VCALIB1_REGH, &buf, 1);
-       temp |= buf<<8;
+       ret = rk81x_bat_read(di, VCALIB1_REGH, &buf, 1);
+       temp |= buf << 8;
 
        DBG("%s voltage1 offset vale is %d\n", __func__, temp);
        return temp;
 }
 
-static int _get_ioffset(struct battery_info *di)
+static int rk81x_bat_get_ioffset(struct rk81x_battery *di)
 {
        int ret;
        int temp = 0;
        u8 buf;
 
-       ret = battery_read(di->rk818, IOFFSET_REGL, &buf, 1);
+       ret = rk81x_bat_read(di, IOFFSET_REGL, &buf, 1);
        temp = buf;
-       ret = battery_read(di->rk818, IOFFSET_REGH, &buf, 1);
-       temp |= buf<<8;
+       ret = rk81x_bat_read(di, IOFFSET_REGH, &buf, 1);
+       temp |= buf << 8;
 
        return temp;
 }
 
-static uint16_t  _get_cal_offset(struct battery_info *di)
+static uint16_t rk81x_bat_get_cal_offset(struct rk81x_battery *di)
 {
        int ret;
        uint16_t temp = 0;
        u8 buf;
 
-       ret = battery_read(di->rk818, CAL_OFFSET_REGL, &buf, 1);
+       ret = rk81x_bat_read(di, CAL_OFFSET_REGL, &buf, 1);
        temp = buf;
-       ret = battery_read(di->rk818, CAL_OFFSET_REGH, &buf, 1);
-       temp |= buf<<8;
+       ret = rk81x_bat_read(di, CAL_OFFSET_REGH, &buf, 1);
+       temp |= buf << 8;
 
        return temp;
 }
-static int _set_cal_offset(struct battery_info *di, u32 value)
+
+static int rk81x_bat_set_cal_offset(struct rk81x_battery *di, u32 value)
 {
        int ret;
        u8 buf;
 
-       buf = value&0xff;
-       ret = battery_write(di->rk818, CAL_OFFSET_REGL, &buf, 1);
-       buf = (value >> 8)&0xff;
-       ret = battery_write(di->rk818, CAL_OFFSET_REGH, &buf, 1);
+       buf = value & 0xff;
+       ret = rk81x_bat_write(di, CAL_OFFSET_REGL, &buf, 1);
+       buf = (value >> 8) & 0xff;
+       ret = rk81x_bat_write(di, CAL_OFFSET_REGH, &buf, 1);
 
        return 0;
 }
-static void _get_voltage_offset_value(struct battery_info *di)
+
+static void rk81x_bat_get_vol_offset(struct rk81x_battery *di)
 {
        int vcalib0, vcalib1;
 
-       vcalib0 = _get_vcalib0(di);
-       vcalib1 = _get_vcalib1(di);
+       vcalib0 = rk81x_bat_get_vcalib0(di);
+       vcalib1 = rk81x_bat_get_vcalib1(di);
 
-       di->voltage_k = (4200 - 3000)*1000/div((vcalib1 - vcalib0));
-       di->voltage_b = 4200 - (di->voltage_k*vcalib1)/1000;
+       di->voltage_k = (4200 - 3000) * 1000 / div((vcalib1 - vcalib0));
+       di->voltage_b = 4200 - (di->voltage_k * vcalib1) / 1000;
        DBG("voltage_k=%d(x1000),voltage_b=%d\n", di->voltage_k, di->voltage_b);
 }
-static uint16_t _get_OCV_voltage(struct battery_info *di)
+
+static uint16_t rk81x_bat_get_ocv_vol(struct rk81x_battery *di)
 {
        int ret;
        u8 buf;
@@ -847,10 +897,10 @@ static uint16_t _get_OCV_voltage(struct battery_info *di)
        int val[3];
 
        for (i = 0; i < 3; i++) {
-               ret = battery_read(di->rk818, BAT_OCV_REGL, &buf, 1);
+               ret = rk81x_bat_read(di, BAT_OCV_REGL, &buf, 1);
                val[i] = buf;
-               ret = battery_read(di->rk818, BAT_OCV_REGH, &buf, 1);
-               val[i] |= buf<<8;
+               ret = rk81x_bat_read(di, BAT_OCV_REGH, &buf, 1);
+               val[i] |= buf << 8;
 
                if (ret < 0) {
                        dev_err(di->dev, "error read BAT_OCV_REGH");
@@ -863,12 +913,12 @@ static uint16_t _get_OCV_voltage(struct battery_info *di)
        else
                temp = val[2];
 
-       voltage_now = di->voltage_k*temp/1000 + di->voltage_b;
+       voltage_now = di->voltage_k * temp / 1000 + di->voltage_b;
 
        return voltage_now;
 }
 
-static int _get_battery_voltage(struct battery_info *di)
+static int rk81x_bat_get_vol(struct rk81x_battery *di)
 {
        int ret;
        int voltage_now = 0;
@@ -878,10 +928,10 @@ static int _get_battery_voltage(struct battery_info *di)
        int i;
 
        for (i = 0; i < 3; i++) {
-               ret = battery_read(di->rk818, BAT_VOL_REGL, &buf, 1);
+               ret = rk81x_bat_read(di, BAT_VOL_REGL, &buf, 1);
                val[i] = buf;
-               ret = battery_read(di->rk818, BAT_VOL_REGH, &buf, 1);
-               val[i] |= buf<<8;
+               ret = rk81x_bat_read(di, BAT_VOL_REGH, &buf, 1);
+               val[i] |= buf << 8;
 
                if (ret < 0) {
                        dev_err(di->dev, "error read BAT_VOL_REGH");
@@ -894,259 +944,248 @@ static int _get_battery_voltage(struct battery_info *di)
        else
                temp = val[2];
 
-       voltage_now = di->voltage_k*temp/1000 + di->voltage_b;
+       voltage_now = di->voltage_k * temp / 1000 + di->voltage_b;
 
        return voltage_now;
 }
 
-/* OCV Lookup table
- * Open Circuit Voltage (OCV) correction routine. This function estimates SOC,
- * based on the voltage.
- */
-static int _voltage_to_capacity(struct battery_info *di, int voltage)
+static bool is_rk81x_bat_relax_mode(struct rk81x_battery *di)
 {
-       u32 *ocv_table;
-       int ocv_size;
-       u32 tmp;
-       int ocv_soc;
+       int ret;
+       u8 status;
 
-       ocv_table = di->platform_data->battery_ocv;
-       ocv_size = di->platform_data->ocv_size;
-       di->warnning_voltage = ocv_table[3];
-       tmp = interpolate(voltage, ocv_table, ocv_size);
-       ocv_soc = ab_div_c(tmp, MAX_PERCENTAGE, INTERPOLATE_MAX);
-       di->temp_nac = ab_div_c(tmp, di->fcc, INTERPOLATE_MAX);
+       ret = rk81x_bat_read(di, GGSTS, &status, 1);
 
-       return ocv_soc;
+       if ((!(status & RELAX_VOL1_UPD)) || (!(status & RELAX_VOL2_UPD)))
+               return false;
+       else
+               return true;
 }
 
-static uint16_t _get_relax_vol1(struct battery_info *di)
+static uint16_t rk81x_bat_get_relax_vol1(struct rk81x_battery *di)
 {
        int ret;
        u8 buf;
        uint16_t temp = 0, voltage_now;
 
-       ret = battery_read(di->rk818, RELAX_VOL1_REGL, &buf, 1);
+       ret = rk81x_bat_read(di, RELAX_VOL1_REGL, &buf, 1);
        temp = buf;
-       ret = battery_read(di->rk818, RELAX_VOL1_REGH, &buf, 1);
-       temp |= (buf<<8);
+       ret = rk81x_bat_read(di, RELAX_VOL1_REGH, &buf, 1);
+       temp |= (buf << 8);
 
-       voltage_now = di->voltage_k*temp/1000 + di->voltage_b;
+       voltage_now = di->voltage_k * temp / 1000 + di->voltage_b;
 
        return voltage_now;
 }
 
-static uint16_t _get_relax_vol2(struct battery_info *di)
+static uint16_t rk81x_bat_get_relax_vol2(struct rk81x_battery *di)
 {
        int ret;
-       uint16_t temp = 0, voltage_now;
        u8 buf;
+       uint16_t temp = 0, voltage_now;
 
-       ret = battery_read(di->rk818, RELAX_VOL2_REGL, &buf, 1);
+       ret = rk81x_bat_read(di, RELAX_VOL2_REGL, &buf, 1);
        temp = buf;
-       ret = battery_read(di->rk818, RELAX_VOL2_REGH, &buf, 1);
-       temp |= (buf<<8);
+       ret = rk81x_bat_read(di, RELAX_VOL2_REGH, &buf, 1);
+       temp |= (buf << 8);
 
-       voltage_now = di->voltage_k*temp/1000 + di->voltage_b;
+       voltage_now = di->voltage_k * temp / 1000 + di->voltage_b;
 
        return voltage_now;
 }
 
-static int  _get_raw_adc_current(struct battery_info *di)
+static uint16_t rk81x_bat_get_relax_vol(struct rk81x_battery *di)
+{
+       int ret;
+       u8 status;
+       uint16_t relax_vol1, relax_vol2;
+       u8 ggcon;
+
+       ret = rk81x_bat_read(di, GGSTS, &status, 1);
+       ret = rk81x_bat_read(di, GGCON, &ggcon, 1);
+
+       relax_vol1 = rk81x_bat_get_relax_vol1(di);
+       relax_vol2 = rk81x_bat_get_relax_vol2(di);
+       DBG("<%s>. GGSTS=0x%x, GGCON=0x%x, relax_vol1=%d, relax_vol2=%d\n",
+           __func__, status, ggcon, relax_vol1, relax_vol2);
+
+       if (is_rk81x_bat_relax_mode(di))
+               return relax_vol1 > relax_vol2 ? relax_vol1 : relax_vol2;
+       else
+               return 0;
+}
+
+/* OCV Lookup table
+ * Open Circuit Voltage (OCV) correction routine. This function estimates SOC,
+ * based on the voltage.
+ */
+static int rk81x_bat_vol_to_capacity(struct rk81x_battery *di, int voltage)
+{
+       u32 *ocv_table;
+       int ocv_size;
+       u32 tmp;
+       int ocv_soc;
+
+       ocv_table = di->pdata->battery_ocv;
+       ocv_size = di->pdata->ocv_size;
+       tmp = interpolate(voltage, ocv_table, ocv_size);
+       ocv_soc = ab_div_c(tmp, MAX_PERCENTAGE, INTERPOLATE_MAX);
+       di->temp_nac = ab_div_c(tmp, di->fcc, INTERPOLATE_MAX);
+
+       return ocv_soc;
+}
+
+static int rk81x_bat_get_raw_adc_current(struct rk81x_battery *di)
 {
        u8 buf;
        int ret;
-       int current_now;
+       int val;
 
-       ret = battery_read(di->rk818, BAT_CUR_AVG_REGL, &buf, 1);
+       ret = rk81x_bat_read(di, BAT_CUR_AVG_REGL, &buf, 1);
        if (ret < 0) {
                dev_err(di->dev, "error reading BAT_CUR_AVG_REGL");
                return ret;
        }
-       current_now = buf;
-       ret = battery_read(di->rk818, BAT_CUR_AVG_REGH, &buf, 1);
+       val = buf;
+       ret = rk81x_bat_read(di, BAT_CUR_AVG_REGH, &buf, 1);
        if (ret < 0) {
                dev_err(di->dev, "error reading BAT_CUR_AVG_REGH");
                return ret;
        }
-       current_now |= (buf<<8);
+       val |= (buf << 8);
 
        if (ret < 0) {
                dev_err(di->dev, "error reading BAT_CUR_AVG_REGH");
                return ret;
        }
 
-       return current_now;
+       if (val > 2047)
+               val -= 4096;
+
+       return val;
 }
 
-static void reset_zero_var(struct battery_info *di)
-{
-       di->update_k = 0;
-       di->q_err = 0;
-       di->voltage_old = 0;
-       di->display_soc = 0;
-}
-
-static void ioffset_sample_time(struct battery_info *di, int time)
+static void rk81x_bat_ioffset_sample_set(struct rk81x_battery *di, int time)
 {
        u8 ggcon;
 
-       battery_read(di->rk818, GGCON, &ggcon, 1);
+       rk81x_bat_read(di, GGCON, &ggcon, 1);
        ggcon &= ~(0x30); /*clear <5:4>*/
        ggcon |= time;
-       battery_write(di->rk818, GGCON, &ggcon, 1);
-}
-
-static void update_cal_offset(struct battery_info *di)
-{
-       int mod = di->queue_work_cnt % TIME_10MIN_SEC;
-       u8 pcb_offset;
-
-       battery_read(di->rk818, PCB_IOFFSET_REG, &pcb_offset, 1);
-       DBG("<%s>, queue_work_cnt = %lu, mod = %d\n",
-           __func__, di->queue_work_cnt, mod);
-       if ((!mod) && (di->pcb_ioffset_updated)) {
-               _set_cal_offset(di, _get_ioffset(di)+pcb_offset);
-               DBG("<%s>. 10min update cal_offset = %d",
-                   __func__, di->pcb_ioffset+_get_ioffset(di));
-       }
+       rk81x_bat_write(di, GGCON, &ggcon, 1);
 }
 
 /*
  * when charger finish signal comes, we need calibrate the current, make it
  * close to 0.
  */
-static void zero_current_calib(struct battery_info *di)
+static bool rk81x_bat_zero_current_calib(struct rk81x_battery *di)
 {
        int adc_value;
        uint16_t C0;
        uint16_t C1;
        int ioffset;
-       u8 pcb_offset;
+       u8 pcb_offset = 0;
        u8 retry = 0;
+       bool ret;
 
-       if ((di->charge_status == CHARGE_FINISH) &&
-           (abs32_int(di->current_avg) > 4)) {
+       if ((di->chrg_status == CHARGE_FINISH) &&
+           (BASE_TO_MIN(di->power_on_base) >= 3) &&
+           (abs(di->current_avg) > 4)) {
                for (retry = 0; retry < 5; retry++) {
-                       adc_value = _get_raw_adc_current(di);
-                       if (adc_value > 2047)
-                               adc_value -= 4096;
+                       adc_value = rk81x_bat_get_raw_adc_current(di);
+                       if (!rk81x_chrg_online(di) || abs(adc_value) > 30) {
+                               dev_dbg(di->dev, "charger plugout\n");
+                               ret = true;
+                               break;
+                       }
 
                        DBG("<%s>. adc_value = %d\n", __func__, adc_value);
-                       C0 = _get_cal_offset(di);
+                       C0 = rk81x_bat_get_cal_offset(di);
                        C1 = adc_value + C0;
                        DBG("<%s>. C0(cal_offset) = %d, C1 = %d\n",
                            __func__, C0, C1);
-                       _set_cal_offset(di, C1);
+                       rk81x_bat_set_cal_offset(di, C1);
                        DBG("<%s>. new cal_offset = %d\n",
-                           __func__, _get_cal_offset(di));
-                       msleep(2000);
-
-                       adc_value = _get_raw_adc_current(di);
+                           __func__, rk81x_bat_get_cal_offset(di));
+                       msleep(3000);
+                       adc_value = rk81x_bat_get_raw_adc_current(di);
                        DBG("<%s>. adc_value = %d\n", __func__, adc_value);
-                       if (adc_value < 4) {
-                               if (_get_cal_offset(di) < 0x7ff)
-                                       _set_cal_offset(di, di->current_offset+
-                                                       42);
-                               else {
-                                       ioffset = _get_ioffset(di);
+                       if (abs(adc_value) < 4) {
+                               if (rk81x_bat_get_cal_offset(di) < 0x7ff) {
+                                       ioffset = rk81x_bat_get_ioffset(di);
+                                       rk81x_bat_set_cal_offset(di,
+                                                                ioffset + 42);
+                               } else {
+                                       ioffset = rk81x_bat_get_ioffset(di);
                                        pcb_offset = C1 - ioffset;
                                        di->pcb_ioffset = pcb_offset;
                                        di->pcb_ioffset_updated  = true;
-                                       battery_write(di->rk818,
-                                                     PCB_IOFFSET_REG,
-                                                     &pcb_offset, 1);
+                                       rk81x_bat_write(di,
+                                                       PCB_IOFFSET_REG,
+                                                       &pcb_offset, 1);
                                }
                                DBG("<%s>. update the cal_offset, C1 = %d\n"
                                    "i_offset = %d, pcb_offset = %d\n",
                                        __func__, C1, ioffset, pcb_offset);
+                               ret = false;
                                break;
                        } else {
-                               di->pcb_ioffset_updated  = false;
+                               dev_warn(di->dev, "ioffset cal failed\n");
+                               rk81x_bat_set_cal_offset(di, C0);
                        }
+
+                       di->pcb_ioffset_updated  = false;
                }
        }
-}
-
-
-static bool  _is_relax_mode(struct battery_info *di)
-{
-       int ret;
-       u8 status;
-
-       ret = battery_read(di->rk818, GGSTS, &status, 1);
-
-       if ((!(status&RELAX_VOL1_UPD)) || (!(status&RELAX_VOL2_UPD)))
-               return false;
-       else
-               return true;
-}
-
-static uint16_t get_relax_voltage(struct battery_info *di)
-{
-       int ret;
-       u8 status;
-       uint16_t relax_vol1, relax_vol2;
-       u8 ggcon;
 
-       ret = battery_read(di->rk818, GGSTS, &status, 1);
-       ret = battery_read(di->rk818, GGCON, &ggcon, 1);
-
-       relax_vol1 = _get_relax_vol1(di);
-       relax_vol2 = _get_relax_vol2(di);
-       DBG("<%s>. GGSTS=0x%x, GGCON=0x%x, relax_vol1=%d, relax_vol2=%d\n",
-           __func__, status, ggcon, relax_vol1, relax_vol2);
-
-       if (_is_relax_mode(di))
-               return relax_vol1 > relax_vol2 ? relax_vol1 : relax_vol2;
-       else
-               return 0;
+       return ret;
 }
 
-static void  _set_relax_thres(struct battery_info *di)
+static void rk81x_bat_set_relax_thres(struct rk81x_battery *di)
 {
        u8 buf;
        int enter_thres, exit_thres;
        struct cell_state *cell = &di->cell;
 
-       enter_thres = (cell->config->ocv->sleep_enter_current)*1000/1506;
-       exit_thres = (cell->config->ocv->sleep_exit_current)*1000/1506;
+       enter_thres = (cell->config->ocv->sleep_enter_current) * 1000 / 1506;
+       exit_thres = (cell->config->ocv->sleep_exit_current) * 1000 / 1506;
        DBG("<%s>. sleep_enter_current = %d, sleep_exit_current = %d\n",
            __func__, cell->config->ocv->sleep_enter_current,
        cell->config->ocv->sleep_exit_current);
 
-       buf  = enter_thres&0xff;
-       battery_write(di->rk818, RELAX_ENTRY_THRES_REGL, &buf, 1);
-       buf = (enter_thres>>8)&0xff;
-       battery_write(di->rk818, RELAX_ENTRY_THRES_REGH, &buf, 1);
+       buf  = enter_thres & 0xff;
+       rk81x_bat_write(di, RELAX_ENTRY_THRES_REGL, &buf, 1);
+       buf = (enter_thres >> 8) & 0xff;
+       rk81x_bat_write(di, RELAX_ENTRY_THRES_REGH, &buf, 1);
 
-       buf  = exit_thres&0xff;
-       battery_write(di->rk818, RELAX_EXIT_THRES_REGL, &buf, 1);
-       buf = (exit_thres>>8)&0xff;
-       battery_write(di->rk818, RELAX_EXIT_THRES_REGH, &buf, 1);
+       buf  = exit_thres & 0xff;
+       rk81x_bat_write(di, RELAX_EXIT_THRES_REGL, &buf, 1);
+       buf = (exit_thres >> 8) & 0xff;
+       rk81x_bat_write(di, RELAX_EXIT_THRES_REGH, &buf, 1);
 
        /* set sample time */
-       battery_read(di->rk818, GGCON, &buf, 1);
-       buf &= ~(3<<2);/*8min*/
+       rk81x_bat_read(di, GGCON, &buf, 1);
+       buf &= ~(3 << 2);/*8min*/
        buf &= ~0x01; /* clear bat_res calc*/
-       battery_write(di->rk818, GGCON, &buf, 1);
+       rk81x_bat_write(di, GGCON, &buf, 1);
 }
 
-static void restart_relax(struct battery_info *di)
+static void rk81x_bat_restart_relax(struct rk81x_battery *di)
 {
-       u8 ggcon;/* chrg_ctrl_reg2;*/
+       u8 ggcon;
        u8 ggsts;
 
-       battery_read(di->rk818, GGCON, &ggcon, 1);
+       rk81x_bat_read(di, GGCON, &ggcon, 1);
        ggcon &= ~0x0c;
-       battery_write(di->rk818, GGCON, &ggcon, 1);
+       rk81x_bat_write(di, GGCON, &ggcon, 1);
 
-       battery_read(di->rk818, GGSTS, &ggsts, 1);
+       rk81x_bat_read(di, GGSTS, &ggsts, 1);
        ggsts &= ~0x0c;
-       battery_write(di->rk818, GGSTS, &ggsts, 1);
+       rk81x_bat_write(di, GGSTS, &ggsts, 1);
 }
 
-static int  _get_average_current(struct battery_info *di)
+static int rk81x_bat_get_avg_current(struct rk81x_battery *di)
 {
        u8  buf;
        int ret;
@@ -1156,14 +1195,14 @@ static int  _get_average_current(struct battery_info *di)
        int i;
 
        for (i = 0; i < 3; i++) {
-               ret = battery_read(di->rk818, BAT_CUR_AVG_REGL, &buf, 1);
+               ret = rk81x_bat_read(di, BAT_CUR_AVG_REGL, &buf, 1);
                if (ret < 0) {
                        dev_err(di->dev, "error read BAT_CUR_AVG_REGL");
                        return ret;
                }
                val[i] = buf;
 
-               ret = battery_read(di->rk818, BAT_CUR_AVG_REGH, &buf, 1);
+               ret = rk81x_bat_read(di, BAT_CUR_AVG_REGH, &buf, 1);
                if (ret < 0) {
                        dev_err(di->dev, "error read BAT_CUR_AVG_REGH");
                        return ret;
@@ -1179,47 +1218,99 @@ static int  _get_average_current(struct battery_info *di)
        if (current_now & 0x800)
                current_now -= 4096;
 
-       temp = current_now*1506/1000;/*1000*90/14/4096*500/521;*/
+       temp = current_now * 1506 / 1000;/*1000*90/14/4096*500/521;*/
 
        return temp;
 }
 
-static int is_rk81x_bat_exist(struct  battery_info *di)
+static void rk81x_bat_set_power_supply_state(struct rk81x_battery *di,
+                                            enum charger_type  charger_type)
+{
+       di->usb_online = OFFLINE;
+       di->ac_online = OFFLINE;
+
+       switch (charger_type) {
+       case NO_CHARGER:
+               di->psy_status = POWER_SUPPLY_STATUS_DISCHARGING;
+               break;
+       case USB_CHARGER:
+               di->usb_online = ONLINE;
+               di->psy_status = POWER_SUPPLY_STATUS_CHARGING;
+               break;
+       case DC_CHARGER:/*treat dc as ac*/
+       case AC_CHARGER:
+               di->ac_online = ONLINE;
+               di->psy_status = POWER_SUPPLY_STATUS_CHARGING;
+               break;
+       default:
+               di->psy_status = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+
+       if (di->wq)
+               queue_delayed_work(di->wq, &di->chrg_term_mode_switch_work,
+                                  msecs_to_jiffies(1000));
+}
+
+/* high load: current < 0 with charger in.
+ * System will not shutdown while dsoc=0% with charging state(ac_online),
+ * which will cause over discharge, so oppose status before report states.
+ */
+static void rk81x_bat_lowpwr_check(struct rk81x_battery *di)
+{
+       static u64 time;
+       int pwr_off_thresd = di->pdata->power_off_thresd - 50;
+
+       if (di->current_avg < 0 &&  di->voltage < pwr_off_thresd) {
+               if (!time)
+                       time = get_runtime_sec();
+
+               if (BASE_TO_SEC(time) > (MINUTE)) {
+                       rk81x_bat_set_power_supply_state(di, NO_CHARGER);
+                       dev_info(di->dev, "low power....\n");
+               }
+       } else {
+               time = 0;
+       }
+}
+
+static int is_rk81x_bat_exist(struct  rk81x_battery *di)
 {
        u8 buf;
 
-       battery_read(di->rk818, SUP_STS_REG, &buf, 1);
+       rk81x_bat_read(di, SUP_STS_REG, &buf, 1);
+
        return (buf & 0x80) ? 1 : 0;
 }
 
-static bool _is_first_poweron(struct  battery_info *di)
+static bool is_rk81x_bat_first_poweron(struct  rk81x_battery *di)
 {
        u8 buf;
        u8 temp;
 
-       battery_read(di->rk818, GGSTS, &buf, 1);
+       rk81x_bat_read(di, GGSTS, &buf, 1);
        DBG("%s GGSTS value is 0x%2x\n", __func__, buf);
        /*di->pwron_bat_con = buf;*/
        if (buf&BAT_CON) {
                buf &= ~(BAT_CON);
                do {
-                       battery_write(di->rk818, GGSTS, &buf, 1);
-                       battery_read(di->rk818, GGSTS, &temp, 1);
-               } while (temp&BAT_CON);
+                       rk81x_bat_write(di, GGSTS, &buf, 1);
+                       rk81x_bat_read(di, GGSTS, &temp, 1);
+               } while (temp & BAT_CON);
                return true;
        }
 
        return false;
 }
-static void flatzone_voltage_init(struct battery_info *di)
+
+static void rk81x_bat_flatzone_vol_init(struct rk81x_battery *di)
 {
        u32 *ocv_table;
        int ocv_size;
        int temp_table[21];
        int i, j;
 
-       ocv_table = di->platform_data->battery_ocv;
-       ocv_size = di->platform_data->ocv_size;
+       ocv_table = di->pdata->battery_ocv;
+       ocv_size = di->pdata->ocv_size;
 
        for (j = 0; j < 21; j++)
                temp_table[j] = 0;
@@ -1230,15 +1321,14 @@ static void flatzone_voltage_init(struct battery_info *di)
                        temp_table[j++] = i;
        }
 
-       temp_table[j] = temp_table[j-1]+1;
+       temp_table[j] = temp_table[j-1] + 1;
        i = temp_table[0];
        di->enter_flatzone = ocv_table[i];
        j = 0;
 
-
        for (i = 0; i < 20; i++) {
                if (temp_table[i] < temp_table[i+1])
-                       j = i+1;
+                       j = i + 1;
        }
 
        i = temp_table[j];
@@ -1248,26 +1338,25 @@ static void flatzone_voltage_init(struct battery_info *di)
            di->enter_flatzone, di->exit_flatzone);
 }
 
-static void power_on_save(struct   battery_info *di, int ocv_voltage)
+static void rk81x_bat_power_on_save(struct rk81x_battery *di, int ocv_voltage)
 {
        u8 ocv_valid, first_pwron;
-       u8 save_soc;
+       u8 soc_level;
        u8 ocv_soc;
 
        /*buf==1: OCV_VOL is valid*/
-       ocv_valid = rk81x_read_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
-       first_pwron = rk81x_read_bit(di, MISC_MARK_REG, FIRST_PWRON_SHIFT);
+       ocv_valid = rk81x_bat_read_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
+       first_pwron = rk81x_bat_read_bit(di, MISC_MARK_REG, FIRST_PWRON_SHIFT);
        DBG("readbit: ocv_valid=%d, first_pwron=%d\n", ocv_valid, first_pwron);
 
        if (first_pwron == 1 || ocv_valid == 1) {
                DBG("<%s> enter.\n", __func__);
-               ocv_soc = _voltage_to_capacity(di, ocv_voltage);
-               if (ocv_soc < 20) {
+               ocv_soc = rk81x_bat_vol_to_capacity(di, ocv_voltage);
+               if ((ocv_soc < 20) && (ocv_voltage > 2750)) {
                        di->dod0_voltage = ocv_voltage;
-                       di->dod0_capacity = di->nac;
-                       di->dod0_status = 1;
+                       di->dod0_capacity = di->temp_nac;
+                       di->adjust_cap = 0;
                        di->dod0 = ocv_soc;
-                       di->dod0_level = 80;
 
                        if (ocv_soc <= 0)
                                di->dod0_level = 100;
@@ -1275,22 +1364,35 @@ static void power_on_save(struct   battery_info *di, int ocv_voltage)
                                di->dod0_level = 95;
                        else if (ocv_soc < 10)
                                di->dod0_level = 90;
+                       else
+                               di->dod0_level = 80;
                        /* save_soc = di->dod0_level; */
-                       save_soc = get_level(di);
-                       if (save_soc <  di->dod0_level)
-                               save_soc = di->dod0_level;
-                       save_level(di, save_soc);
-                       DBG("<%s>: dod0_vol:%d, dod0_cap:%d, dod0:%d, level:%d",
-                           __func__, di->dod0_voltage, di->dod0_capacity,
-                           ocv_soc, save_soc);
+                       soc_level = rk81x_bat_get_level(di);
+                       if (soc_level >  di->dod0_level) {
+                               di->dod0_status = 0;
+                               soc_level -= 5;
+                               if (soc_level <= 80)
+                                       soc_level = 80;
+                               rk81x_bat_save_level(di, soc_level);
+                       } else {
+                               di->dod0_status = 1;
+                               /*time start*/
+                               di->fcc_update_sec = get_runtime_sec();
+                       }
+
+                       dev_info(di->dev, "dod0_vol:%d, dod0_cap:%d\n"
+                                "dod0:%d, soc_level:%d: dod0_status:%d\n"
+                                "dod0_level:%d",
+                                di->dod0_voltage, di->dod0_capacity,
+                                ocv_soc, soc_level, di->dod0_status,
+                                di->dod0_level);
                }
        }
 }
 
-
-static int _get_soc(struct   battery_info *di)
+static int rk81x_bat_get_rsoc(struct   rk81x_battery *di)
 {
-       return di->remain_capacity * 100 / div(di->fcc);
+       return (di->remain_capacity + di->fcc / 200) * 100 / div(di->fcc);
 }
 
 static enum power_supply_property rk_battery_props[] = {
@@ -1302,55 +1404,46 @@ static enum power_supply_property rk_battery_props[] = {
        POWER_SUPPLY_PROP_CAPACITY,
 };
 
-#define to_device_info(x) container_of((x), \
-                               struct battery_info, bat)
-
 static int rk81x_battery_get_property(struct power_supply *psy,
                                      enum power_supply_property psp,
                                      union power_supply_propval *val)
 {
-       struct battery_info *di = to_device_info(psy);
+       struct rk81x_battery *di = to_device_info(psy);
 
        switch (psp) {
        case POWER_SUPPLY_PROP_CURRENT_NOW:
-               val->intval = di->current_avg*1000;/*uA*/
+               val->intval = di->current_avg * 1000;/*uA*/
                if (di->fg_drv_mode == TEST_POWER_MODE)
-                       val->intval = TEST_CURRENT*1000;
+                       val->intval = TEST_CURRENT * 1000;
                break;
-
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               val->intval = di->voltage*1000;/*uV*/
+               val->intval = di->voltage * 1000;/*uV*/
                if (di->fg_drv_mode == TEST_POWER_MODE)
-                       val->intval = TEST_VOLTAGE*1000;
+                       val->intval = TEST_VOLTAGE * 1000;
 
                break;
-
        case POWER_SUPPLY_PROP_PRESENT:
                val->intval = is_rk81x_bat_exist(di);
                if (di->fg_drv_mode == TEST_POWER_MODE)
                        val->intval = TEST_PRESET;
 
                break;
-
        case POWER_SUPPLY_PROP_CAPACITY:
-               val->intval = di->real_soc;
+               val->intval = di->dsoc;
                if (di->fg_drv_mode == TEST_POWER_MODE)
                        val->intval = TEST_SOC;
 
                DBG("<%s>, report dsoc: %d\n", __func__, val->intval);
                break;
-
        case POWER_SUPPLY_PROP_HEALTH:
                val->intval = POWER_SUPPLY_HEALTH_GOOD;
                break;
-
        case POWER_SUPPLY_PROP_STATUS:
-               val->intval = di->status;
+               val->intval = di->psy_status;
                if (di->fg_drv_mode == TEST_POWER_MODE)
                        val->intval = TEST_STATUS;
 
                break;
-
        default:
                return -EINVAL;
        }
@@ -1358,33 +1451,30 @@ static int rk81x_battery_get_property(struct power_supply *psy,
        return 0;
 }
 
-
 static enum power_supply_property rk_battery_ac_props[] = {
        POWER_SUPPLY_PROP_ONLINE,
 };
+
 static enum power_supply_property rk_battery_usb_props[] = {
        POWER_SUPPLY_PROP_ONLINE,
 };
 
-
-#define to_ac_device_info(x) container_of((x), \
-                               struct battery_info, ac)
-
 static int rk81x_battery_ac_get_property(struct power_supply *psy,
                                         enum power_supply_property psp,
                                         union power_supply_propval *val)
 {
        int ret = 0;
-       struct battery_info *di = to_ac_device_info(psy);
+       struct rk81x_battery *di = to_ac_device_info(psy);
 
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
+               if (rk81x_chrg_online(di))
+                       rk81x_bat_lowpwr_check(di);
                val->intval = di->ac_online;    /*discharging*/
                if (di->fg_drv_mode == TEST_POWER_MODE)
                        val->intval = TEST_AC_ONLINE;
 
                break;
-
        default:
                ret = -EINVAL;
                break;
@@ -1392,28 +1482,21 @@ static int rk81x_battery_ac_get_property(struct power_supply *psy,
        return ret;
 }
 
-#define to_usb_device_info(x) container_of((x), \
-                               struct battery_info, usb)
-
 static int rk81x_battery_usb_get_property(struct power_supply *psy,
                                          enum power_supply_property psp,
                                          union power_supply_propval *val)
 {
        int ret = 0;
-       struct battery_info *di = to_usb_device_info(psy);
+       struct rk81x_battery *di = to_usb_device_info(psy);
 
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
-               if ((strstr(saved_command_line, "charger") == NULL) &&
-                   (di->real_soc == 0) && (di->work_on == 1))
-                       val->intval = 0;
-               else
-                       val->intval = di->usb_online;
-
+               if (rk81x_chrg_online(di))
+                       rk81x_bat_lowpwr_check(di);
+               val->intval = di->usb_online;
                if (di->fg_drv_mode == TEST_POWER_MODE)
                        val->intval = TEST_USB_ONLINE;
                break;
-
        default:
                ret = -EINVAL;
                break;
@@ -1422,9 +1505,10 @@ static int rk81x_battery_usb_get_property(struct power_supply *psy,
        return ret;
 }
 
-
-static void battery_power_supply_init(struct battery_info *di)
+static int rk81x_bat_power_supply_init(struct rk81x_battery *di)
 {
+       int ret;
+
        di->bat.name = "BATTERY";
        di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
        di->bat.properties = rk_battery_props;
@@ -1442,26 +1526,20 @@ static void battery_power_supply_init(struct battery_info *di)
        di->usb.properties = rk_battery_usb_props;
        di->usb.num_properties = ARRAY_SIZE(rk_battery_usb_props);
        di->usb.get_property = rk81x_battery_usb_get_property;
-}
-
-static int battery_power_supply_register(struct battery_info *di)
-{
-       int ret;
-       struct device *dev = di->dev;
 
-       ret = power_supply_register(dev, &di->bat);
+       ret = power_supply_register(di->dev, &di->bat);
        if (ret) {
-               dev_err(dev, "failed to register main battery\n");
+               dev_err(di->dev, "failed to register main battery\n");
                goto batt_failed;
        }
-       ret = power_supply_register(dev, &di->usb);
+       ret = power_supply_register(di->dev, &di->usb);
        if (ret) {
-               dev_err(dev, "failed to register usb power supply\n");
+               dev_err(di->dev, "failed to register usb power supply\n");
                goto usb_failed;
        }
-       ret = power_supply_register(dev, &di->ac);
+       ret = power_supply_register(di->dev, &di->ac);
        if (ret) {
-               dev_err(dev, "failed to register ac power supply\n");
+               dev_err(di->dev, "failed to register ac power supply\n");
                goto ac_failed;
        }
 
@@ -1477,37 +1555,11 @@ batt_failed:
        return ret;
 }
 
-static void  _capacity_init(struct battery_info *di, u32 capacity)
-{
-       u8 buf;
-       u32 capacity_ma;
-       int delta_cap;
-
-       delta_cap = capacity - di->remain_capacity;
-       di->adjust_cap += delta_cap;
-
-       reset_zero_var(di);
-
-       capacity_ma = capacity*2390;/* 2134;//36*14/900*4096/521*500; */
-       do {
-               buf = (capacity_ma>>24)&0xff;
-               battery_write(di->rk818, GASCNT_CAL_REG3, &buf, 1);
-               buf = (capacity_ma>>16)&0xff;
-               battery_write(di->rk818, GASCNT_CAL_REG2, &buf, 1);
-               buf = (capacity_ma>>8)&0xff;
-               battery_write(di->rk818, GASCNT_CAL_REG1, &buf, 1);
-               buf = (capacity_ma&0xff) | 0x01;
-               battery_write(di->rk818, GASCNT_CAL_REG0, &buf, 1);
-               battery_read(di->rk818, GASCNT_CAL_REG0, &buf, 1);
-
-       } while (buf == 0);
-}
-
-
-static void  _save_remain_capacity(struct battery_info *di, u32 capacity)
+static void rk81x_bat_save_remain_capacity(struct rk81x_battery *di,
+                                          int capacity)
 {
        u8 buf;
-       u32 capacity_ma;
+       static u32 capacity_ma;
 
        if (capacity >= di->qmax)
                capacity = di->qmax;
@@ -1515,19 +1567,22 @@ static void  _save_remain_capacity(struct battery_info *di, u32 capacity)
        if (capacity <= 0)
                capacity = 0;
 
+       if (capacity_ma == capacity)
+               return;
+
        capacity_ma = capacity;
 
-       buf = (capacity_ma>>24)&0xff;
-       battery_write(di->rk818, REMAIN_CAP_REG3, &buf, 1);
-       buf = (capacity_ma>>16)&0xff;
-       battery_write(di->rk818, REMAIN_CAP_REG2, &buf, 1);
-       buf = (capacity_ma>>8)&0xff;
-       battery_write(di->rk818, REMAIN_CAP_REG1, &buf, 1);
-       buf = (capacity_ma&0xff) | 0x01;
-       battery_write(di->rk818, REMAIN_CAP_REG0, &buf, 1);
+       buf = (capacity_ma >> 24) & 0xff;
+       rk81x_bat_write(di, REMAIN_CAP_REG3, &buf, 1);
+       buf = (capacity_ma >> 16) & 0xff;
+       rk81x_bat_write(di, REMAIN_CAP_REG2, &buf, 1);
+       buf = (capacity_ma >> 8) & 0xff;
+       rk81x_bat_write(di, REMAIN_CAP_REG1, &buf, 1);
+       buf = (capacity_ma & 0xff) | 0x01;
+       rk81x_bat_write(di, REMAIN_CAP_REG0, &buf, 1);
 }
 
-static int _get_remain_capacity(struct battery_info *di)
+static int rk81x_bat_get_remain_capacity(struct rk81x_battery *di)
 {
        int ret;
        u8 buf;
@@ -1536,13 +1591,13 @@ static int _get_remain_capacity(struct battery_info *di)
        int val[3];
 
        for (i = 0; i < 3; i++) {
-               ret = battery_read(di->rk818, REMAIN_CAP_REG3, &buf, 1);
+               ret = rk81x_bat_read(di, REMAIN_CAP_REG3, &buf, 1);
                val[i] = buf << 24;
-               ret = battery_read(di->rk818, REMAIN_CAP_REG2, &buf, 1);
+               ret = rk81x_bat_read(di, REMAIN_CAP_REG2, &buf, 1);
                val[i] |= buf << 16;
-               ret = battery_read(di->rk818, REMAIN_CAP_REG1, &buf, 1);
+               ret = rk81x_bat_read(di, REMAIN_CAP_REG1, &buf, 1);
                val[i] |= buf << 8;
-               ret = battery_read(di->rk818, REMAIN_CAP_REG0, &buf, 1);
+               ret = rk81x_bat_read(di, REMAIN_CAP_REG0, &buf, 1);
                val[i] |= buf;
        }
 
@@ -1554,49 +1609,53 @@ static int _get_remain_capacity(struct battery_info *di)
        return capacity;
 }
 
-
-static void  _save_FCC_capacity(struct battery_info *di, u32 capacity)
+static void rk81x_bat_save_fcc(struct rk81x_battery *di, u32 capacity)
 {
        u8 buf;
        u32 capacity_ma;
 
        capacity_ma = capacity;
-       buf = (capacity_ma>>24)&0xff;
-       battery_write(di->rk818, NEW_FCC_REG3, &buf, 1);
-       buf = (capacity_ma>>16)&0xff;
-       battery_write(di->rk818, NEW_FCC_REG2, &buf, 1);
-       buf = (capacity_ma>>8)&0xff;
-       battery_write(di->rk818, NEW_FCC_REG1, &buf, 1);
-       buf = (capacity_ma&0xff) | 0x01;
-       battery_write(di->rk818, NEW_FCC_REG0, &buf, 1);
+       buf = (capacity_ma >> 24) & 0xff;
+       rk81x_bat_write(di, NEW_FCC_REG3, &buf, 1);
+       buf = (capacity_ma >> 16) & 0xff;
+       rk81x_bat_write(di, NEW_FCC_REG2, &buf, 1);
+       buf = (capacity_ma >> 8) & 0xff;
+       rk81x_bat_write(di, NEW_FCC_REG1, &buf, 1);
+       buf = (capacity_ma & 0xff) | 0x01;
+       rk81x_bat_write(di, NEW_FCC_REG0, &buf, 1);
+
+       dev_info(di->dev, "update fcc : %d\n", capacity);
 }
 
-static int _get_FCC_capacity(struct battery_info *di)
+static int rk81x_bat_get_fcc(struct rk81x_battery *di)
 {
-       int ret;
-       int temp = 0;
        u8 buf;
        u32 capacity;
 
-       ret = battery_read(di->rk818, NEW_FCC_REG3, &buf, 1);
-       temp = buf << 24;
-       ret = battery_read(di->rk818, NEW_FCC_REG2, &buf, 1);
-       temp |= buf << 16;
-       ret = battery_read(di->rk818, NEW_FCC_REG1, &buf, 1);
-       temp |= buf << 8;
-       ret = battery_read(di->rk818, NEW_FCC_REG0, &buf, 1);
-       temp |= buf;
-
-       if (temp > 1)
-               capacity = temp-1;/* 4096*900/14/36*500/521 */
-       else
-               capacity = temp;
-       DBG("%s NEW_FCC_REG %d  capacity = %d\n", __func__, temp, capacity);
+       rk81x_bat_read(di, NEW_FCC_REG3, &buf, 1);
+       capacity = buf << 24;
+       rk81x_bat_read(di, NEW_FCC_REG2, &buf, 1);
+       capacity |= buf << 16;
+       rk81x_bat_read(di, NEW_FCC_REG1, &buf, 1);
+       capacity |= buf << 8;
+       rk81x_bat_read(di, NEW_FCC_REG0, &buf, 1);
+       capacity |= buf;
+
+       if (capacity < MIN_FCC) {
+               dev_warn(di->dev, "invalid fcc(0x%x), use design capacity",
+                        capacity);
+               capacity = di->design_capacity;
+               rk81x_bat_save_fcc(di, capacity);
+       } else if (capacity > di->qmax) {
+               dev_warn(di->dev, "invalid fcc(0x%x), use qmax", capacity);
+               capacity = di->qmax;
+               rk81x_bat_save_fcc(di, capacity);
+       }
 
        return capacity;
 }
 
-static int _get_realtime_capacity(struct battery_info *di)
+static int rk81x_bat_get_realtime_capacity(struct rk81x_battery *di)
 {
        int ret;
        int temp = 0;
@@ -1606,13 +1665,13 @@ static int _get_realtime_capacity(struct battery_info *di)
        int val[3];
 
        for (i = 0; i < 3; i++) {
-               ret = battery_read(di->rk818, GASCNT3, &buf, 1);
+               ret = rk81x_bat_read(di, GASCNT3, &buf, 1);
                val[i] = buf << 24;
-               ret = battery_read(di->rk818, GASCNT2, &buf, 1);
+               ret = rk81x_bat_read(di, GASCNT2, &buf, 1);
                val[i] |= buf << 16;
-               ret = battery_read(di->rk818, GASCNT1, &buf, 1);
+               ret = rk81x_bat_read(di, GASCNT1, &buf, 1);
                val[i] |= buf << 8;
-               ret = battery_read(di->rk818, GASCNT0, &buf, 1);
+               ret = rk81x_bat_read(di, GASCNT0, &buf, 1);
                val[i] |= buf;
        }
        if (val[0] == val[1])
@@ -1620,35 +1679,69 @@ static int _get_realtime_capacity(struct battery_info *di)
        else
                temp = val[2];
 
-       capacity = temp/2390;/* 4096*900/14/36*500/521; */
+       capacity = temp / 2390;/* 4096*900/14/36*500/521; */
 
        return capacity;
 }
 
-static int _copy_soc(struct  battery_info *di, u8 save_soc)
+static int rk81x_bat_save_dsoc(struct  rk81x_battery *di, u8 save_soc)
 {
-       u8 soc;
+       static u8 last_soc;
+
+       if (last_soc != save_soc) {
+               rk81x_bat_write(di, SOC_REG, &save_soc, 1);
+               last_soc = save_soc;
+       }
 
-       soc = save_soc;
-       battery_write(di->rk818, SOC_REG, &soc, 1);
        return 0;
 }
 
-static int copy_reboot_cnt(struct  battery_info *di, u8 save_cnt)
+static int rk81x_bat_save_reboot_cnt(struct  rk81x_battery *di, u8 save_cnt)
 {
        u8 cnt;
 
        cnt = save_cnt;
-       battery_write(di->rk818, REBOOT_CNT_REG, &cnt, 1);
+       rk81x_bat_write(di, REBOOT_CNT_REG, &cnt, 1);
        return 0;
 }
 
-static bool support_uboot_charge(void)
+static u8 rk81x_bat_support_loader_chrg(struct rk81x_battery *di)
+{
+       u8 ret;
+
+       ret = rk81x_bat_read_bit(di, MISC_MARK_REG, LOADER_CHRG_SHIFT);
+       rk81x_bat_clr_bit(di, MISC_MARK_REG, LOADER_CHRG_SHIFT);
+       return ret;
+}
+
+static void rk81x_bat_set_current(struct rk81x_battery *di, int charge_current)
 {
-       return support_uboot_chrg ? true : false;
+       u8 usb_ctrl_reg;
+
+       rk81x_bat_read(di, USB_CTRL_REG, &usb_ctrl_reg, 1);
+       usb_ctrl_reg &= (~0x0f);/* (VLIM_4400MV | ILIM_1200MA) |(0x01 << 7); */
+       usb_ctrl_reg |= (charge_current | CHRG_CT_EN);
+       rk81x_bat_write(di, USB_CTRL_REG, &usb_ctrl_reg, 1);
 }
 
+static void rk81x_bat_set_chrg_current(struct rk81x_battery *di,
+                                      enum charger_type charger_type)
+{
+       switch (charger_type) {
+       case NO_CHARGER:
+       case USB_CHARGER:
+               rk81x_bat_set_current(di, ILIM_450MA);
+               break;
+       case AC_CHARGER:
+       case DC_CHARGER:
+               rk81x_bat_set_current(di, di->chrg_i_lmt);
+               break;
+       default:
+               rk81x_bat_set_current(di, ILIM_450MA);
+       }
+}
 
+#if defined(CONFIG_ARCH_ROCKCHIP)
 /*
 * There are three ways to detect dc_adp:
 *      1. hardware only support dc_adp: by reg VB_MOD_REG of rk818,
@@ -1657,16 +1750,16 @@ static bool support_uboot_charge(void)
 *      3. support usb_adp and dc_adp: by VB_MOD_REG and usb interface.
 *         case that: gpio invalid or not define.
 */
-static enum charger_type_t rk81x_get_dc_state(struct battery_info *di)
+static enum charger_type rk81x_bat_get_dc_state(struct rk81x_battery *di)
 {
-       enum charger_type_t charger_type;
+       enum charger_type charger_type;
        u8 buf;
        int ret;
 
-       battery_read(di->rk818, VB_MOD_REG, &buf, 1);
+       rk81x_bat_read(di, VB_MOD_REG, &buf, 1);
 
        /*only HW_ADP_TYPE_DC: det by rk818 is easily and will be successful*/
-        if (!rk81x_support_adp_type(HW_ADP_TYPE_USB)) {
+        if (!rk81x_bat_support_adp_type(HW_ADP_TYPE_USB)) {
                if ((buf & PLUG_IN_STS) != 0)
                        charger_type = DC_CHARGER;
                else
@@ -1675,7 +1768,6 @@ static enum charger_type_t rk81x_get_dc_state(struct battery_info *di)
                return charger_type;
         }
 
-#if 1
        /*det by gpio level*/
        if (gpio_is_valid(di->dc_det_pin)) {
                ret = gpio_request(di->dc_det_pin, "rk818_dc_det");
@@ -1696,10 +1788,9 @@ static enum charger_type_t rk81x_get_dc_state(struct battery_info *di)
                DBG("**********rk818 dc_det_pin=%d\n", ret);
 
                return charger_type;
-       }
-#endif
+
        /*HW_ADP_TYPE_DUAL: det by rk818 and usb*/
-       else if (rk81x_support_adp_type(HW_ADP_TYPE_DUAL)) {
+       } else if (rk81x_bat_support_adp_type(HW_ADP_TYPE_DUAL)) {
                if ((buf & PLUG_IN_STS) != 0) {
                        charger_type = dwc_otg_check_dpdm();
                        if (charger_type == 0)
@@ -1712,9 +1803,9 @@ static enum charger_type_t rk81x_get_dc_state(struct battery_info *di)
        return charger_type;
 }
 
-static enum charger_type_t rk81x_get_usbac_state(struct battery_info *di)
+static enum charger_type rk81x_bat_get_usbac_state(struct rk81x_battery *di)
 {
-       enum charger_type_t charger_type;
+       enum charger_type charger_type;
        int usb_id, gadget_flag;
 
        usb_id = dwc_otg_check_dpdm();
@@ -1749,6 +1840,7 @@ static enum charger_type_t rk81x_get_usbac_state(struct battery_info *di)
                        }
                } else {
                        charger_type = USB_CHARGER;
+                       di->check_count = 0;
                }
        } else {
                di->check_count = 0;
@@ -1758,199 +1850,357 @@ static enum charger_type_t rk81x_get_usbac_state(struct battery_info *di)
 }
 
 /*
- * it is first time for battery to be weld, init by ocv table
+ * when support HW_ADP_TYPE_DUAL, and at the moment that usb_adp
+ * and dc_adp are plugined in together, the dc_apt has high priority.
+ * so we check dc_apt first and return rigth away if it's found.
  */
-static void rsoc_first_poweron_init(struct battery_info *di)
+static enum charger_type rk81x_bat_get_adp_type(struct rk81x_battery *di)
 {
-       _save_FCC_capacity(di, di->design_capacity);
-       di->fcc = _get_FCC_capacity(di);
+       u8 buf;
+       enum charger_type charger_type = NO_CHARGER;
 
-       di->temp_soc = _voltage_to_capacity(di, di->voltage_ocv);
-       di->real_soc = di->temp_soc;
-       di->nac      = di->temp_nac;
-       di->first_on_cap = di->nac;
+       /*check by ic hardware: this check make check work safer*/
+       rk81x_bat_read(di, VB_MOD_REG, &buf, 1);
+       if ((buf & PLUG_IN_STS) == 0)
+               return NO_CHARGER;
 
-       rk81x_set_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
-       rk81x_set_bit(di, MISC_MARK_REG, FIRST_PWRON_SHIFT);/*save*/
-       DBG("<%s>.this is first poweron: OCV-SOC:%d, OCV-CAP:%d, FCC:%d\n",
-           __func__, di->real_soc, di->nac, di->fcc);
-}
+       /*check DC first*/
+       if (rk81x_bat_support_adp_type(HW_ADP_TYPE_DC)) {
+               charger_type = rk81x_bat_get_dc_state(di);
+               if (charger_type == DC_CHARGER)
+                       return charger_type;
+       }
 
-/*
- * it is not first time for battery to be weld, init by last record info
- */
-static void rsoc_not_first_poweron_init(struct battery_info *di)
-{
-       u8 pwron_soc;
-       u8 init_soc;
-       u8 last_shtd_time;
-       u8 curr_shtd_time;
-       int remain_capacity;
-       int ocv_soc;
-       enum charger_type_t charger_type;
+       /*HW_ADP_TYPE_USB*/
+       charger_type = rk81x_bat_get_usbac_state(di);
 
-       rk81x_clr_bit(di, MISC_MARK_REG, FIRST_PWRON_SHIFT);
-       battery_read(di->rk818, SOC_REG, &pwron_soc, 1);
-       init_soc = pwron_soc;
-       DBG("<%s> Not first pwron, SOC_REG = %d\n", __func__, pwron_soc);
+       return charger_type;
+}
 
-       if (rk81x_support_adp_type(HW_ADP_TYPE_USB)) {
-               charger_type = rk81x_get_usbac_state(di);
-               if ((pwron_soc == 0) && (charger_type == USB_CHARGER)) {
-                       init_soc = 1;
-                       battery_write(di->rk818, SOC_REG, &init_soc, 1);
-               }
-       }
+static void rk81x_bat_status_check(struct rk81x_battery *di)
+{
+       static enum charger_type old_charger_type = DUAL_CHARGER;
+       enum charger_type  charger_type;
 
-       remain_capacity = _get_remain_capacity(di);
-       /* check if support uboot charge,
-        * if support, uboot charge driver should have done init work,
-        * so here we should skip init work
-        */
-       if (support_uboot_charge())
-               goto out;
+       charger_type = rk81x_bat_get_adp_type(di);
+       if (charger_type == old_charger_type)
+               return;
+       rk81x_bat_set_chrg_current(di, charger_type);
+       rk81x_bat_set_power_supply_state(di, charger_type);
+       old_charger_type = charger_type;
+}
+#endif
 
-       battery_read(di->rk818, NON_ACT_TIMER_CNT_REG,
-                    &curr_shtd_time, 1);
-       battery_read(di->rk818, NON_ACT_TIMER_CNT_REG_SAVE,
-                    &last_shtd_time, 1);
-       battery_write(di->rk818, NON_ACT_TIMER_CNT_REG_SAVE,
-                     &curr_shtd_time, 1);
-       DBG("<%s>, now_shtd_time = %d, last_shtd_time = %d, otg_status = %d\n",
-           __func__, curr_shtd_time, last_shtd_time, charger_type);
+#if defined(CONFIG_X86_INTEL_SOFIA)
+static int rk81x_get_chrg_type_by_usb_phy(struct rk81x_battery *di, int ma)
+{
+       enum charger_type charger_type;
 
-       ocv_soc = _voltage_to_capacity(di, di->voltage_ocv);
-       DBG("<%s>, Not first pwron, real_remain_cap = %d, ocv-remain_cp=%d\n",
-           __func__, remain_capacity, di->temp_nac);
+       if (ma > 500)
+               charger_type =  AC_CHARGER;
+       else if (ma >= 100)
+               charger_type = USB_CHARGER;
+       else
+               charger_type = NO_CHARGER;
 
-       /* if plugin, make sure current shtd_time diff from last_shtd_time.*/
-       if (last_shtd_time != curr_shtd_time) {
-               if (curr_shtd_time > 30) {
-                       rk81x_set_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
+       di->ma = ma;
 
-                       remain_capacity = di->temp_nac;
-                       di->first_on_cap = remain_capacity;
-                       DBG("<%s>pwroff > 30 minute, remain_cap = %d\n",
-                           __func__, remain_capacity);
+       dev_info(di->dev, "limit current:%d\n", ma);
 
-               } else if ((curr_shtd_time > 5) &&
-                               (abs32_int(ocv_soc - init_soc) >= 10)) {
-                       if (remain_capacity >= di->temp_nac*120/100)
-                               remain_capacity = di->temp_nac*110/100;
-                       else if (remain_capacity < di->temp_nac*8/10)
-                               remain_capacity = di->temp_nac*9/10;
-                       DBG("<%s> pwroff > 3 minute, remain_cap = %d\n",
-                           __func__, remain_capacity);
-               }
-       } else {
-               rk81x_clr_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
-       }
-out:
-       di->real_soc = init_soc;
-       di->nac = remain_capacity;
-       if (di->nac <= 0)
-               di->nac = 0;
-       DBG("<%s> init_soc = %d, init_capacity=%d\n",
-           __func__, di->real_soc, di->nac);
+       return charger_type;
 }
 
-static u8 get_sys_pwroff_min(struct battery_info *di)
+static void rk81x_battery_usb_notifier_delayed_work(struct work_struct *work)
 {
-       u8 curr_shtd_time, last_shtd_time;
+       struct rk81x_battery *di;
+       enum charger_type type;
 
-       battery_read(di->rk818, NON_ACT_TIMER_CNT_REG,
-                    &curr_shtd_time, 1);
-       battery_read(di->rk818, NON_ACT_TIMER_CNT_REG_SAVE,
-                    &last_shtd_time, 1);
+       di = container_of(work, struct rk81x_battery, usb_phy_delay_work.work);
+       type = rk81x_get_chrg_type_by_usb_phy(di, di->ma);
 
-       return (curr_shtd_time != last_shtd_time) ? curr_shtd_time : 0;
+       rk81x_bat_set_chrg_current(di, type);
+       power_supply_changed(&di->usb);
 }
 
-static int _rsoc_init(struct battery_info *di)
+static int rk81x_battery_usb_notifier(struct notifier_block *nb,
+                                     unsigned long event, void *data)
 {
-       u8 pwroff_min;
-       u8 calib_en;/*debug*/
+       struct rk81x_battery *di;
+       struct power_supply_cable_props *cable_props;
+       enum charger_type type;
 
-       di->voltage  = _get_battery_voltage(di);
-       di->voltage_ocv = _get_OCV_voltage(di);
-       pwroff_min = get_sys_pwroff_min(di);
+       di = container_of(nb, struct rk81x_battery, usb_nb);
 
-       DBG("OCV voltage=%d, voltage=%d, pwroff_min=%d\n",
-           di->voltage_ocv, di->voltage, pwroff_min);
+       if (!data)
+               return NOTIFY_BAD;
 
-       calib_en = rk81x_read_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
-       DBG("readbit: calib_en=%d\n", calib_en);
-       if (_is_first_poweron(di) ||
-           ((pwroff_min >= 30) && (calib_en == 1))) {
-               rsoc_first_poweron_init(di);
-               rk81x_clr_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
+       switch (event) {
+       case USB_EVENT_CHARGER:
+               cable_props = (struct power_supply_cable_props *)data;
+               type = rk81x_get_chrg_type_by_usb_phy(di, cable_props->ma);
+               rk81x_bat_set_power_supply_state(di, type);
+               queue_delayed_work(di->wq, &di->usb_phy_delay_work,
+                                  msecs_to_jiffies(50));
+               break;
 
-       } else {
-               rsoc_not_first_poweron_init(di);
+       default:
+               break;
        }
 
-       return 0;
+       return NOTIFY_OK;
 }
+#endif
 
-
-static u8 rk81x_get_charge_status(struct battery_info *di)
+static int rk81x_battery_fb_notifier(struct notifier_block *nb,
+                                    unsigned long event, void *data)
 {
-       u8 status;
-       u8 ret = 0;
+       struct rk81x_battery *di;
+       struct fb_event *evdata = data;
+       int blank;
 
-       battery_read(di->rk818, SUP_STS_REG, &status, 1);
-       status &= (0x70);
-       switch (status) {
-       case CHARGE_OFF:
-               ret = CHARGE_OFF;
-               DBG("  CHARGE-OFF ...\n");
-               break;
+       di = container_of(nb, struct rk81x_battery, fb_nb);
 
-       case DEAD_CHARGE:
-               ret = DEAD_CHARGE;
-               DBG("  DEAD CHARGE ...\n");
-               break;
+       if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
+               return 0;
 
-       case  TRICKLE_CHARGE:
-               ret = DEAD_CHARGE;
-               DBG("  TRICKLE CHARGE ...\n ");
-               break;
+       blank = *(int *)evdata->data;
 
-       case  CC_OR_CV:
-               ret = CC_OR_CV;
-               DBG("  CC or CV ...\n");
-               break;
+       if (di->fb_blank != blank)
+               di->fb_blank = blank;
+       else
+               return 0;
 
-       case  CHARGE_FINISH:
-               ret = CHARGE_FINISH;
-               DBG("  CHARGE FINISH ...\n");
-               break;
+       if (blank == FB_BLANK_UNBLANK)
+               di->early_resume = 1;
+
+       return 0;
+}
+
+static int rk81x_battery_register_fb_notify(struct rk81x_battery *di)
+{
+       memset(&di->fb_nb, 0, sizeof(di->fb_nb));
+       di->fb_nb.notifier_call = rk81x_battery_fb_notifier;
+
+       return fb_register_client(&di->fb_nb);
+}
+
+/*
+ * it is first time for battery to be weld, init by ocv table
+ */
+static void rk81x_bat_first_pwron(struct rk81x_battery *di)
+{
+       rk81x_bat_save_fcc(di, di->design_capacity);
+       di->fcc = rk81x_bat_get_fcc(di);
+
+       di->rsoc = rk81x_bat_vol_to_capacity(di, di->voltage_ocv);
+       di->dsoc = di->rsoc;
+       di->nac  = di->temp_nac;
+
+       rk81x_bat_set_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
+       rk81x_bat_set_bit(di, MISC_MARK_REG, FIRST_PWRON_SHIFT);/*save*/
+       DBG("<%s>.this is first poweron: OCV-SOC:%d, OCV-CAP:%d, FCC:%d\n",
+           __func__, di->dsoc, di->nac, di->fcc);
+}
+
+static int rk81x_bat_get_calib_vol(struct rk81x_battery *di)
+{
+       int calib_vol;
+       int init_cur, diff;
+       int est_vol;
+       int relax_vol = di->relax_voltage;
+       int ocv_vol = di->voltage_ocv;
+
+       init_cur = rk81x_bat_get_avg_current(di);
+       diff = (di->bat_res + di->pdata->chrg_diff_vol) * init_cur;
+       diff /= 1000;
+       est_vol = di->voltage - diff;
+
+       if (di->loader_charged) {
+               calib_vol = est_vol;
+               return calib_vol;
+       }
+
+       if (di->pwroff_min > 8) {
+               if (abs(relax_vol - ocv_vol) < 100) {
+                       calib_vol = ocv_vol;
+               } else {
+                       if (abs(relax_vol - est_vol) > abs(ocv_vol - est_vol))
+                               calib_vol = ocv_vol;
+                       else
+                               calib_vol = relax_vol;
+               }
+       } else if (di->pwroff_min > 2) {
+               calib_vol = ocv_vol;
+       } else {
+               calib_vol = -1;
+       }
+
+       dev_info(di->dev, "c=%d, v=%d, relax:%d, ocv:=%d, est=%d, calib=%d\n",
+                init_cur, di->voltage, relax_vol, ocv_vol, est_vol, calib_vol);
+
+       return calib_vol;
+}
+
+/*
+ * it is not first time for battery to be weld, init by last record info
+ */
+static void rk81x_bat_not_first_pwron(struct rk81x_battery *di)
+{
+       u8 pwron_soc;
+       u8 init_soc;
+       int remain_capacity;
+       int ocv_soc;
+       int calib_vol, calib_soc, calib_capacity;
+
+       rk81x_bat_clr_bit(di, MISC_MARK_REG, FIRST_PWRON_SHIFT);
+       rk81x_bat_read(di, SOC_REG, &pwron_soc, 1);
+       init_soc = pwron_soc;
+       remain_capacity = rk81x_bat_get_remain_capacity(di);
+
+       /* check if support uboot charge,
+        * if support, uboot charge driver should have done init work,
+        * so here we should skip init work
+        */
+       if (rk81x_bat_support_loader_chrg(di))
+               goto out;
+
+       calib_vol = rk81x_bat_get_calib_vol(di);
+       if (calib_vol > 0) {
+               calib_soc = rk81x_bat_vol_to_capacity(di, calib_vol);
+               calib_capacity = di->temp_nac;
+
+               if (abs(calib_soc - init_soc) >= 70 || di->loader_charged) {
+                       init_soc = calib_soc;
+                       remain_capacity = calib_capacity;
+               }
+               dev_info(di->dev, "calib_vol %d, init soc %d, remain_cap %d\n",
+                        calib_vol, init_soc, remain_capacity);
+       }
+
+       ocv_soc = rk81x_bat_vol_to_capacity(di, di->voltage_ocv);
+       DBG("<%s>, Not first pwron, real_remain_cap = %d, ocv-remain_cp=%d\n",
+           __func__, remain_capacity, di->temp_nac);
+
+       if (di->pwroff_min > 0) {
+               if (di->pwroff_min > 30) {
+                       rk81x_bat_set_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
+
+                       remain_capacity = di->temp_nac;
+                       DBG("<%s>pwroff > 30 minute, remain_cap = %d\n",
+                           __func__, remain_capacity);
+
+               } else if ((di->pwroff_min > 5) &&
+                               (abs(ocv_soc - init_soc) >= 10)) {
+                       if (remain_capacity >= di->temp_nac * 120/100)
+                               remain_capacity = di->temp_nac * 110/100;
+                       else if (remain_capacity < di->temp_nac * 8/10)
+                               remain_capacity = di->temp_nac * 9/10;
+                       DBG("<%s> pwroff > 5 minute, remain_cap = %d\n",
+                           __func__, remain_capacity);
+               }
+       } else {
+               rk81x_bat_clr_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
+       }
+out:
+       di->dsoc = init_soc;
+       di->nac = remain_capacity;
+       if (di->nac <= 0)
+               di->nac = 0;
+       DBG("<%s> init_soc = %d, init_capacity=%d\n",
+           __func__, di->dsoc, di->nac);
+}
+
+static u8 rk81x_bat_get_pwroff_min(struct rk81x_battery *di)
+{
+       u8 curr_pwroff_min, last_pwroff_min;
+
+       rk81x_bat_read(di, NON_ACT_TIMER_CNT_REG,
+                      &curr_pwroff_min, 1);
+       rk81x_bat_read(di, NON_ACT_TIMER_CNT_REG_SAVE,
+                      &last_pwroff_min, 1);
+
+       rk81x_bat_write(di, NON_ACT_TIMER_CNT_REG_SAVE,
+                       &curr_pwroff_min, 1);
+
+       return (curr_pwroff_min != last_pwroff_min) ? curr_pwroff_min : 0;
+}
+
+static int rk81x_bat_rsoc_init(struct rk81x_battery *di)
+{
+       u8 calib_en;/*debug*/
+
+       di->voltage  = rk81x_bat_get_vol(di);
+       di->voltage_ocv = rk81x_bat_get_ocv_vol(di);
+       di->pwroff_min = rk81x_bat_get_pwroff_min(di);
+       di->relax_voltage = rk81x_bat_get_relax_vol(di);
+       di->current_avg = rk81x_bat_get_avg_current(di);
+
+       dev_info(di->dev, "v=%d, ov=%d, rv=%d, c=%d, pwroff_min=%d\n",
+                di->voltage, di->voltage_ocv, di->relax_voltage,
+                di->current_avg, di->pwroff_min);
+
+       calib_en = rk81x_bat_read_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
+       DBG("readbit: calib_en=%d\n", calib_en);
+       if (is_rk81x_bat_first_poweron(di) ||
+           ((di->pwroff_min >= 30) && (calib_en == 1))) {
+               rk81x_bat_first_pwron(di);
+               rk81x_bat_clr_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
+
+       } else {
+               rk81x_bat_not_first_pwron(di);
+       }
+
+       return 0;
+}
+
+static u8 rk81x_bat_get_chrg_status(struct rk81x_battery *di)
+{
+       u8 status;
+       u8 ret = 0;
 
+       rk81x_bat_read(di, SUP_STS_REG, &status, 1);
+       status &= (0x70);
+       switch (status) {
+       case CHARGE_OFF:
+               ret = CHARGE_OFF;
+               DBG("  CHARGE-OFF ...\n");
+               break;
+       case DEAD_CHARGE:
+               ret = DEAD_CHARGE;
+               DBG("  DEAD CHARGE ...\n");
+               break;
+       case  TRICKLE_CHARGE:
+               ret = DEAD_CHARGE;
+               DBG("  TRICKLE CHARGE ...\n ");
+               break;
+       case  CC_OR_CV:
+               ret = CC_OR_CV;
+               DBG("  CC or CV ...\n");
+               break;
+       case  CHARGE_FINISH:
+               ret = CHARGE_FINISH;
+               DBG("  CHARGE FINISH ...\n");
+               break;
        case  USB_OVER_VOL:
                ret = USB_OVER_VOL;
                DBG("  USB OVER VOL ...\n");
                break;
-
        case  BAT_TMP_ERR:
                ret = BAT_TMP_ERR;
                DBG("  BAT TMP ERROR ...\n");
                break;
-
        case  TIMER_ERR:
                ret = TIMER_ERR;
                DBG("  TIMER ERROR ...\n");
                break;
-
        case  USB_EXIST:
                ret = USB_EXIST;
                DBG("  USB EXIST ...\n");
                break;
-
        case  USB_EFF:
                ret = USB_EFF;
                DBG("  USB EFF...\n");
                break;
-
        default:
                return -EINVAL;
        }
@@ -1958,108 +2208,114 @@ static u8 rk81x_get_charge_status(struct battery_info *di)
        return ret;
 }
 
-static void set_charge_current(struct battery_info *di, int charge_current)
-{
-       u8 usb_ctrl_reg;
-
-       battery_read(di->rk818, USB_CTRL_REG, &usb_ctrl_reg, 1);
-       usb_ctrl_reg &= (~0x0f);/* (VLIM_4400MV | ILIM_1200MA) |(0x01 << 7); */
-       usb_ctrl_reg |= (charge_current | CHRG_CT_EN);
-       battery_write(di->rk818, USB_CTRL_REG, &usb_ctrl_reg, 1);
-}
-
-static void rk81x_fg_match_param(struct battery_info *di, int chg_vol,
-                                int chg_ilim, int chg_cur)
+static void rk81x_bat_match_param(struct rk81x_battery *di, int chrg_vol,
+                                 int chrg_ilim, int chrg_cur)
 {
        int i;
 
-       di->chg_v_lmt = DEF_CHRG_VOL;
-       di->chg_i_lmt = DEF_CHRG_CURR_LMT;
-       di->chg_i_cur = DEF_CHRG_CURR_SEL;
+       di->chrg_v_lmt = DEF_CHRG_VOL;
+       di->chrg_i_lmt = DEF_CHRG_CURR_LMT;
+       di->chrg_i_cur = DEF_CHRG_CURR_SEL;
 
-       for (i = 0; i < ARRAY_SIZE(CHG_V_LMT); i++) {
-               if (chg_vol < CHG_V_LMT[i])
+       for (i = 0; i < ARRAY_SIZE(CHRG_V_LMT); i++) {
+               if (chrg_vol < CHRG_V_LMT[i])
                        break;
-               else
-                       di->chg_v_lmt = (i << CHG_VOL_SHIFT);
+
+               di->chrg_v_lmt = (i << CHRG_VOL_SHIFT);
        }
 
-       for (i = 0; i < ARRAY_SIZE(CHG_I_LMT); i++) {
-               if (chg_ilim < CHG_I_LMT[i])
+       for (i = 0; i < ARRAY_SIZE(CHRG_I_LMT); i++) {
+               if (chrg_ilim < CHRG_I_LMT[i])
                        break;
-               else
-                       di->chg_i_lmt = (i << CHG_ILIM_SHIFT);
+
+               di->chrg_i_lmt = (i << CHRG_ILIM_SHIFT);
        }
 
-       for (i = 0; i < ARRAY_SIZE(CHG_I_CUR); i++) {
-               if (chg_cur < CHG_I_CUR[i])
+       for (i = 0; i < ARRAY_SIZE(CHRG_I_CUR); i++) {
+               if (chrg_cur < CHRG_I_CUR[i])
                        break;
-               else
-                       di->chg_i_cur = (i << CHG_ICUR_SHIFT);
+
+               di->chrg_i_cur = (i << CHRG_ICUR_SHIFT);
        }
        DBG("<%s>. vol = 0x%x, i_lim = 0x%x, cur=0x%x\n",
-           __func__, di->chg_v_lmt, di->chg_i_lmt, di->chg_i_cur);
+           __func__, di->chrg_v_lmt, di->chrg_i_lmt, di->chrg_i_cur);
 }
 
-static u8 rk81x_chose_finish_ma(int fcc)
+static u8 rk81x_bat_select_finish_ma(int fcc)
 {
        u8 ma = FINISH_150MA;
 
-       if (fcc < 3000)
-               ma = FINISH_100MA;
-
-       else if (fcc >= 3000 && fcc <= 4000)
-               ma = FINISH_150MA;
+       if (fcc > 5000)
+               ma = FINISH_250MA;
 
-       else if (fcc > 4000 && fcc <= 5000)
+       else if (fcc >= 4000)
                ma = FINISH_200MA;
 
-       else/*fcc > 5000*/
-               ma = FINISH_250MA;
+       else if (fcc >= 3000)
+               ma = FINISH_150MA;
+
+       else
+               ma = FINISH_100MA;
 
        return ma;
 }
 
-static void rk81x_battery_charger_init(struct  battery_info *di)
+/*
+ * there is a timer inside rk81x to calc how long the battery is in charging
+ * state. rk81x will close PowerPath inside IC when timer reach, which will
+ * stop the charging work. we have to reset the corresponding bits to restart
+ * the timer to avoid that case.
+ */
+static void rk81x_bat_init_chrg_timer(struct rk81x_battery *di)
+{
+       u8 buf;
+
+       rk81x_bat_read(di, CHRG_CTRL_REG3, &buf, 1);
+       buf &= ~CHRG_TIMER_CCCV_EN;
+       rk81x_bat_write(di, CHRG_CTRL_REG3, &buf, 1);
+       udelay(40);
+       rk81x_bat_read(di, CHRG_CTRL_REG3, &buf, 1);
+       buf |= CHRG_TIMER_CCCV_EN;
+       rk81x_bat_write(di, CHRG_CTRL_REG3, &buf, 1);
+       dev_info(di->dev, "reset cccv charge timer\n");
+}
+
+static void rk81x_bat_charger_init(struct  rk81x_battery *di)
 {
        u8 chrg_ctrl_reg1, usb_ctrl_reg, chrg_ctrl_reg2, chrg_ctrl_reg3;
-       u8 sup_sts_reg, thremal_reg;
-       int chg_vol, chg_cur, chg_ilim;
+       u8 sup_sts_reg, thremal_reg, ggcon;
+       int chrg_vol, chrg_cur, chrg_ilim;
        u8 finish_ma;
 
-       chg_vol = di->rk818->battery_data->max_charger_voltagemV;
+       chrg_vol = di->pdata->max_charger_voltagemV;
+       chrg_cur = di->pdata->max_charger_currentmA;
+       chrg_ilim = di->pdata->max_charger_ilimitmA;
 
-       if (di->fg_drv_mode == TEST_POWER_MODE) {
-               chg_cur = di->test_chrg_current;
-               chg_ilim = di->test_chrg_ilmt;
-       } else {
-               chg_cur = di->rk818->battery_data->max_charger_currentmA;
-               chg_ilim = di->rk818->battery_data->max_charger_ilimitmA;
-       }
-
-       rk81x_fg_match_param(di, chg_vol, chg_ilim, chg_cur);
-       finish_ma = rk81x_chose_finish_ma(di->fcc);
+       rk81x_bat_match_param(di, chrg_vol, chrg_ilim, chrg_cur);
+       finish_ma = rk81x_bat_select_finish_ma(di->fcc);
 
-       battery_read(di->rk818, THERMAL_REG, &thremal_reg, 1);
-       battery_read(di->rk818, USB_CTRL_REG, &usb_ctrl_reg, 1);
-       battery_read(di->rk818, CHRG_CTRL_REG1, &chrg_ctrl_reg1, 1);
-       battery_read(di->rk818, CHRG_CTRL_REG2, &chrg_ctrl_reg2, 1);
-       battery_read(di->rk818, SUP_STS_REG, &sup_sts_reg, 1);
-       battery_read(di->rk818, CHRG_CTRL_REG3, &chrg_ctrl_reg3, 1);
+       rk81x_bat_init_chrg_timer(di);
 
+       rk81x_bat_read(di, THERMAL_REG, &thremal_reg, 1);
+       rk81x_bat_read(di, USB_CTRL_REG, &usb_ctrl_reg, 1);
+       rk81x_bat_read(di, CHRG_CTRL_REG1, &chrg_ctrl_reg1, 1);
+       rk81x_bat_read(di, CHRG_CTRL_REG2, &chrg_ctrl_reg2, 1);
+       rk81x_bat_read(di, SUP_STS_REG, &sup_sts_reg, 1);
+       rk81x_bat_read(di, CHRG_CTRL_REG3, &chrg_ctrl_reg3, 1);
+       rk81x_bat_read(di, GGCON, &ggcon, 1);
 
        usb_ctrl_reg &= (~0x0f);
 
-       if (rk81x_support_adp_type(HW_ADP_TYPE_USB))
+       if (rk81x_bat_support_adp_type(HW_ADP_TYPE_USB))
                usb_ctrl_reg |= (CHRG_CT_EN | ILIM_450MA);/*en temp feed back*/
        else
-               usb_ctrl_reg |= (CHRG_CT_EN | di->chg_i_lmt);
+               usb_ctrl_reg |= (CHRG_CT_EN | di->chrg_i_lmt);
 
-       thremal_reg &= (~0x0c);
-       thremal_reg |= TEMP_105C;/*temp feed back: 105c*/
+       if (di->fg_drv_mode == TEST_POWER_MODE)
+               usb_ctrl_reg |= (CHRG_CT_EN | di->chrg_i_lmt);
 
        chrg_ctrl_reg1 &= (0x00);
-       chrg_ctrl_reg1 |= (CHRG_EN) | (di->chg_v_lmt | di->chg_i_cur);
+       chrg_ctrl_reg1 |= (CHRG_EN) | (di->chrg_v_lmt | di->chrg_i_cur);
 
        chrg_ctrl_reg3 |= CHRG_TERM_DIG_SIGNAL;/* digital finish mode*/
        chrg_ctrl_reg2 &= ~(0xc7);
@@ -2070,85 +2326,80 @@ static void rk81x_battery_charger_init(struct  battery_info *di)
 
        thremal_reg &= (~0x0c);
        thremal_reg |= TEMP_105C;/*temp feed back: 105c*/
+       ggcon |= ADC_CURRENT_MODE;
 
-       battery_write(di->rk818, THERMAL_REG, &thremal_reg, 1);
-       battery_write(di->rk818, CHRG_CTRL_REG3, &chrg_ctrl_reg3, 1);
-       battery_write(di->rk818, USB_CTRL_REG, &usb_ctrl_reg, 1);
-       battery_write(di->rk818, CHRG_CTRL_REG1, &chrg_ctrl_reg1, 1);
-       battery_write(di->rk818, CHRG_CTRL_REG2, &chrg_ctrl_reg2, 1);
-       battery_write(di->rk818, SUP_STS_REG, &sup_sts_reg, 1);
+       rk81x_bat_write(di, THERMAL_REG, &thremal_reg, 1);
+       rk81x_bat_write(di, CHRG_CTRL_REG3, &chrg_ctrl_reg3, 1);
+       /*don't touch charge  setting when boot int loader charge mode*/
+       if (!di->loader_charged)
+               rk81x_bat_write(di, USB_CTRL_REG, &usb_ctrl_reg, 1);
+       rk81x_bat_write(di, CHRG_CTRL_REG1, &chrg_ctrl_reg1, 1);
+       rk81x_bat_write(di, CHRG_CTRL_REG2, &chrg_ctrl_reg2, 1);
+       rk81x_bat_write(di, SUP_STS_REG, &sup_sts_reg, 1);
+       rk81x_bat_write(di, GGCON, &ggcon, 1);
 }
 
-void charge_disable_open_otg(int value)
+void rk81x_charge_disable_open_otg(struct rk81x_battery *di)
 {
-       struct  battery_info *di = g_battery;
+       int value = di->charge_otg;
 
-       if (value == 1) {
+       if (value) {
                DBG("charge disable, enable OTG.\n");
                rk818_set_bits(di->rk818, CHRG_CTRL_REG1, 1 << 7, 0 << 7);
                rk818_set_bits(di->rk818, 0x23, 1 << 7, 1 << 7);
-       }
-       if (value == 0) {
+       } else {
                DBG("charge enable, disable OTG.\n");
                rk818_set_bits(di->rk818, 0x23, 1 << 7, 0 << 7);
                rk818_set_bits(di->rk818, CHRG_CTRL_REG1, 1 << 7, 1 << 7);
        }
 }
 
-static void rk81x_low_waring_init(struct battery_info *di)
-{
-       u8 vb_mon_reg;
-       u8 vb_mon_reg_init;
-
-       battery_read(di->rk818, VB_MOD_REG, &vb_mon_reg, 1);
-
-       /* 3.4v: interrupt*/
-       vb_mon_reg_init = (((vb_mon_reg | (1 << 4)) & (~0x07)) | 0x06);
-       battery_write(di->rk818, VB_MOD_REG, &vb_mon_reg_init, 1);
-}
-
-static void rk81x_fg_init(struct battery_info *di)
+static void rk81x_bat_fg_init(struct rk81x_battery *di)
 {
-       u8 adc_ctrl_val;
-       u8 buf = 0;
        u8 pcb_offset;
        int cal_offset;
+       u8 val;
 
-       adc_ctrl_val = 0x30;
-       battery_write(di->rk818, ADC_CTRL_REG, &adc_ctrl_val, 1);
+       val = 0x30;
+       rk81x_bat_write(di, ADC_CTRL_REG, &val, 1);
+       rk81x_bat_read(di, RK818_VB_MON_REG, &val, 1);
+       if (val & PLUG_IN_STS)
+               rk81x_bat_set_power_supply_state(di, USB_CHARGER);
 
-       _gauge_enable(di);
+       rk81x_bat_gauge_enable(di);
        /* get the volatege offset */
-       _get_voltage_offset_value(di);
-       rk81x_battery_charger_init(di);
-       _set_relax_thres(di);
+       rk81x_bat_get_vol_offset(di);
+       rk81x_bat_charger_init(di);
+       rk81x_bat_set_relax_thres(di);
 
        /* get the current offset , the value write to the CAL_OFFSET */
-       di->current_offset = _get_ioffset(di);
-       battery_read(di->rk818, PCB_IOFFSET_REG, &pcb_offset, 1);
-       DBG("<%s>. pcb_offset = 0x%x\n", __func__, pcb_offset);
-       DBG("<%s>. io_offset = 0x%x\n", __func__, di->current_offset);
-
-       _set_cal_offset(di, di->current_offset+pcb_offset);
-       cal_offset = _get_cal_offset(di);
-       if ((cal_offset < 0x7ff) || (pcb_offset == 0))
-               _set_cal_offset(di, di->current_offset+42);
+       di->current_offset = rk81x_bat_get_ioffset(di);
+       rk81x_bat_read(di, PCB_IOFFSET_REG, &pcb_offset, 1);
+       DBG("<%s>. pcb_offset = 0x%x, io_offset = 0x%x\n",
+           __func__, pcb_offset, di->current_offset);
+       if (!pcb_offset)
+               pcb_offset = DEF_PCB_OFFSET;
+       cal_offset = pcb_offset + di->current_offset;
+       if (cal_offset < 0x7ff || cal_offset > 0x8ff)
+               cal_offset = DEF_CAL_OFFSET;
+       rk81x_bat_set_cal_offset(di, cal_offset);
+       /* set sample time for cal_offset interval*/
+       rk81x_bat_ioffset_sample_set(di, SAMP_TIME_8MIN);
 
-       _rsoc_init(di);
-       _capacity_init(di, di->nac);
+       rk81x_bat_rsoc_init(di);
+       rk81x_bat_capacity_init(di, di->nac);
+       rk81x_bat_capacity_init_post(di);
 
-       di->remain_capacity = _get_realtime_capacity(di);
-       di->current_avg = _get_average_current(di);
+       di->remain_capacity = rk81x_bat_get_realtime_capacity(di);
+       di->current_avg = rk81x_bat_get_avg_current(di);
 
-       rk81x_low_waring_init(di);
-       restart_relax(di);
-       power_on_save(di, di->voltage_ocv);
-       battery_write(di->rk818, OCV_VOL_VALID_REG, &buf, 1);
+       rk81x_bat_restart_relax(di);
+       rk81x_bat_power_on_save(di, di->voltage_ocv);
+       val = 0;
+       rk81x_bat_write(di, OCV_VOL_VALID_REG, &val, 1);
 
-       /* set sample time for cal_offset interval*/
-       ioffset_sample_time(di, SAMP_TIME_8MIN);
-       dump_gauge_register(di);
-       dump_charger_register(di);
+       rk81x_dbg_dmp_gauge_regs(di);
+       rk81x_dbg_dmp_charger_regs(di);
 
        DBG("<%s> :\n"
            "nac = %d , remain_capacity = %d\n"
@@ -2158,196 +2409,116 @@ static void rk81x_fg_init(struct battery_info *di)
            __func__,
            di->nac, di->remain_capacity,
            di->voltage_ocv, di->voltage,
-           di->real_soc, di->fcc, di->current_avg,
+           di->dsoc, di->fcc, di->current_avg,
            cal_offset);
 }
-/*
- * this is a very important algorithm to avoid over discharge.
- */
-/* int R_soc, D_soc, r_soc, zq, k, Q_err, Q_ocv; */
-static void zero_get_soc(struct battery_info *di)
+
+static void rk81x_bat_zero_calc_linek(struct rk81x_battery *di)
 {
        int dead_voltage, ocv_voltage;
-       int temp_soc = -1, real_soc;
-       int currentold, currentnow, voltage;
-       int i;
-       int voltage_k;
-       int count_num = 0;
-       int q_ocv;
-       int ocv_soc;
+       int voltage, voltage_old, voltage_now;
+       int i, rsoc;
+       int q_ocv, q_dead;
+       int count_num, currentnow;
+       int ocv_soc, dead_soc;
+       int power_off_thresd = di->pdata->power_off_thresd;
 
-       DBG("\n\n+++++++zero mode++++++display soc+++++++++++\n");
        do {
-               currentold = _get_average_current(di);
-               _get_cal_offset(di);
-               _get_ioffset(di);
+               voltage_old = rk81x_bat_get_vol(di);
                msleep(100);
-               currentnow = _get_average_current(di);
+               voltage_now = rk81x_bat_get_vol(di);
                count_num++;
-       } while ((currentold == currentnow) && (count_num < 11));
+       } while ((voltage_old == voltage_now) && (count_num < 11));
+       DBG("<%s>. current calc count=%d\n", __func__, count_num);
 
-       voltage  = 0;
-       for (i = 0; i < 10 ; i++)
-               voltage += _get_battery_voltage(di);
+       voltage = 0;
+       for (i = 0; i < 10; i++) {
+               voltage += rk81x_bat_get_vol(di);
+               msleep(100);
+       }
        voltage /= 10;
 
-       if (di->voltage_old == 0)
-               di->voltage_old = voltage;
-       voltage_k = voltage;
-       voltage = (di->voltage_old*2 + 8*voltage)/10;
-       di->voltage_old = voltage;
-       currentnow = _get_average_current(di);
-
-       dead_voltage = 3400 + abs32_int(currentnow)*(di->bat_res+65)/1000;
-       /* 65 mo power-path mos */
-       ocv_voltage = voltage + abs32_int(currentnow)*di->bat_res/1000;
-       DBG("ZERO: dead_voltage(shtd) = %d, ocv_voltage(now) = %d\n",
+       currentnow = rk81x_bat_get_avg_current(di);
+
+       /* 50 mo power-path mos */
+       dead_voltage = power_off_thresd - currentnow *
+                               (di->bat_res + DEF_PWRPATH_RES) / 1000;
+
+       ocv_voltage = voltage - (currentnow * di->bat_res) / 1000;
+       DBG("ZERO0: dead_voltage(shtd) = %d, ocv_voltage(now) = %d\n",
            dead_voltage, ocv_voltage);
 
-       ocv_soc = _voltage_to_capacity(di, dead_voltage);
-       di->q_dead = di->temp_nac;
-       DBG("ZERO: dead_voltage_soc = %d, q_dead = %d\n",
-           ocv_soc, di->q_dead);
+       dead_soc = rk81x_bat_vol_to_capacity(di, dead_voltage);
+       q_dead = di->temp_nac;
+       DBG("ZERO0: dead_voltage_soc = %d, q_dead = %d\n",
+           dead_soc, q_dead);
 
-       ocv_soc = _voltage_to_capacity(di, ocv_voltage);
+       ocv_soc = rk81x_bat_vol_to_capacity(di, ocv_voltage);
        q_ocv = di->temp_nac;
-       DBG("ZERO: ocv_voltage_soc = %d, q_ocv = %d\n",
+       DBG("ZERO0: ocv_voltage_soc = %d, q_ocv = %d\n",
            ocv_soc, q_ocv);
 
-       /*[Q_err]: Qerr, [temp_nac]:check_voltage_nac*/
-       di->q_err = di->remain_capacity - q_ocv;
-       DBG("q_err=%d, [remain_capacity]%d - [q_ocv]%d",
-           di->q_err, di->remain_capacity, q_ocv);
-
-       if (di->display_soc == 0)
-               di->display_soc = di->real_soc*1000;
-       real_soc = di->display_soc;
-
-       DBG("remain_capacity = %d, q_dead = %d, q_err = %d\n",
-           di->remain_capacity, di->q_dead, di->q_err);
-       /*[temp_nac]:dead_voltage*/
-       if (q_ocv > di->q_dead) {
-               DBG("first: q_ocv > di->q_dead\n");
-
-               /*initical K0*/
-               if ((di->update_k == 0) || (di->zero_cycle >= 500)) {
-                       DBG("[K == 0]\n");
-                       di->zero_cycle = 0;
-                       di->update_k = 1;
-                       /* ZQ = Q_ded +  Qerr */
-                       /*[temp_nac]:dead_voltage*/
-                       di->q_shtd = di->q_dead + di->q_err;
-                       temp_soc = (di->remain_capacity - di->q_shtd)*
-                                       1000/div(di->fcc);
-                       if (temp_soc == 0)
-                               di->update_k = 0;
-                       else
-                               di->line_k = (real_soc + temp_soc/2)
-                                               /div(temp_soc);
-               /* recalc K0*/
-               } else if (di->zero_updated && di->update_k >= 10) {
-                       DBG("[K >= 10].\n");
-                       di->update_k = 1;
-                       _voltage_to_capacity(di, dead_voltage);
-                       di->q_dead = di->temp_nac;
-                       di->q_shtd = di->q_dead + di->q_err;
-                       temp_soc = ((di->remain_capacity - di->q_shtd)*
-                               1000 + di->fcc/2)/div(di->fcc); /* z1 */
-                       if (temp_soc == 0)
-                               di->update_k = 0;
-                       else
-                               di->line_k = (real_soc + temp_soc/2)
-                                               /div(temp_soc);
-
-                       DBG("[K >= 10]. new:line_k = %d\n", di->line_k);
-                       DBG("[K >= 10]. new:Y0(dis_soc)=%d\n", di->display_soc);
-                       DBG("[K >= 10]. new:X0(temp) = %d\n", temp_soc);
-
-               } else { /*update_k[1~9]*/
-                       DBG("[K1~9]\n");
-                       di->zero_cycle++;
-                       di->update_k++;
-                       DBG("[K1~9]. (old)Y0=%d, Y0=%d\n",
-                           di->old_display_soc, di->display_soc);
-                       if (di->update_k == 2)
-                               di->old_display_soc = di->display_soc;
-
-                       temp_soc = ((di->remain_capacity - di->q_shtd)*
-                               1000 + di->fcc/2)/div(di->fcc);
-                       real_soc = di->line_k*temp_soc;
-                       di->display_soc = real_soc;
-
-                       /* make sure display_soc change at least once*/
-                       if (di->display_soc >= di->old_display_soc)
-                               di->zero_updated = false;
-                       else
-                               di->zero_updated = true;
-
-                       DBG("[K1~9]. (temp_soc)X0 = %d\n", temp_soc);
-                       DBG("[K1~9]. line_k = %d\n", di->line_k);
-                       DBG("[K1~9]. (dis-soc)Y0=%d,real-soc=%d\n",
-                           di->display_soc, di->real_soc);
-
-                       if ((di->display_soc+500)/1000 < di->real_soc) {
-                               /*special for 0%*/
-                               if ((di->real_soc == 1) &&
-                                   (di->display_soc < 100))
-                                       di->real_soc--;
-                               else
-                                       di->real_soc--;
-                               /*di->odd_capacity = 0;*/
-                       }
-               }
+       rsoc = ocv_soc - dead_soc;
+       if ((di->dsoc == 1) && (rsoc > 0)) {/*discharge*/
+               di->line_k = 1000;
+       } else if (rsoc > 1) {
+               di->line_k = (di->display_soc + rsoc / 2) / div(rsoc);
        } else {
-               DBG("second: q_ocv < di->q_dead\n");
-               di->update_k++;
-
-               if (di->voltage < 3400) {
-                       DBG("second: voltage < 3400\n");
-                       di->real_soc--;
-               } else {
-                       if (di->update_k > 10) {
-                               di->update_k = 0;
-                               di->real_soc--;
-                               di->odd_capacity = 0;
-                       }
-               }
-       }
-
-       if (di->line_k <= 0) {
-               reset_zero_var(di);
-               DBG("ZERO: line_k <= 0, Update line_k!\n");
+               di->dsoc--;
+               di->display_soc = di->dsoc * 1000;
        }
 
-       DBG("ZERO: update_k=%d, odd_cap=%d\n", di->update_k, di->odd_capacity);
-       DBG("ZERO: q_ocv - q_dead=%d\n", (q_ocv-di->q_dead));
-       DBG("ZERO: remain_cap - q_shtd=%d\n",
-           (di->remain_capacity - di->q_shtd));
-       DBG("ZERO: (line_k)K0 = %d,(disp-soc)Y0 = %d, (temp_soc)X0 = %d\n",
-           di->line_k, di->display_soc, temp_soc);
-       DBG("ZERO: zero_cycle=%d,(old)Y0=%d, zero_updated=%d, update_k=%d\n",
-           di->zero_cycle, di->old_display_soc,
-           di->zero_updated, di->update_k);
+       di->zero_old_remain_cap = di->remain_capacity;
 
-       DBG("ZERO: remain_capacity=%d, q_shtd(nac)=%d, q_err(Q_rm-q_ocv)=%d\n",
-           di->remain_capacity, di->q_shtd, di->q_err);
-       DBG("ZERO: Warn_voltage=%d,temp_soc=%d,real_soc=%d\n\n",
-           di->warnning_voltage, _get_soc(di), di->real_soc);
+       DBG("ZERO-new: new-line_k=%d, dsoc=%d, X0soc=%d\n"
+           "ZERO-new: di->display_soc=%d, old_remain_cap=%d\n\n",
+           di->line_k, di->dsoc, rsoc,
+           di->display_soc, di->zero_old_remain_cap);
 }
 
+static void rk81x_bat_zero_algorithm(struct rk81x_battery *di)
+{
+       int delta_cap, delta_soc;
+       int tmp_dsoc;
+
+       di->zero_timeout_cnt++;
+       delta_cap = di->zero_old_remain_cap - di->remain_capacity;
+       delta_soc = di->line_k * (delta_cap * 100) / div(di->fcc);
+
+       DBG("ZERO1: line_k=%d, display_soc(Y0)=%d, dsoc=%d, rsoc=%d\n"
+           "ZERO1: delta_soc(X0)=%d, delta_cap=%d, old_remain_cap = %d\n"
+           "ZERO1: timeout_cnt=%d\n\n",
+           di->line_k, di->display_soc, di->dsoc, di->rsoc,
+           delta_soc, delta_cap, di->zero_old_remain_cap,
+           di->zero_timeout_cnt);
+
+       if ((abs(delta_soc) > MIN_ZERO_ACCURACY) ||
+           (di->zero_timeout_cnt > 500)) {
+               DBG("ZERO1:--------- enter calc -----------\n");
+               di->zero_timeout_cnt = 0;
+               di->display_soc -= delta_soc;
+               tmp_dsoc = (di->display_soc + 500) / 1000;
+               di->dsoc = tmp_dsoc;
+
+               DBG("ZERO1: display_soc(Y0)=%d, dsoc=%d, rsoc=%d, tmp_soc=%d",
+                   di->display_soc, di->dsoc, di->rsoc, tmp_dsoc);
 
-static int estimate_bat_ocv_vol(struct battery_info *di)
+               rk81x_bat_zero_calc_linek(di);
+       }
+}
+
+static int rk81x_bat_est_ocv_vol(struct rk81x_battery *di)
 {
        return (di->voltage -
                                (di->bat_res * di->current_avg) / 1000);
 }
 
-static int estimate_bat_ocv_soc(struct battery_info *di)
+static int rk81x_bat_est_ocv_soc(struct rk81x_battery *di)
 {
        int ocv_soc, ocv_voltage;
 
-       ocv_voltage = estimate_bat_ocv_vol(di);
-       ocv_soc = _voltage_to_capacity(di, ocv_voltage);
+       ocv_voltage = rk81x_bat_est_ocv_vol(di);
+       ocv_soc = rk81x_bat_vol_to_capacity(di, ocv_voltage);
 
        return ocv_soc;
 }
@@ -2356,39 +2527,39 @@ static int estimate_bat_ocv_soc(struct battery_info *di)
  * if there is a big offset between ocv_soc and rsoc,
  * we will decide whether we should reinit capacity or not
  */
-static void rsoc_dischrg_calib(struct battery_info *di)
+static void rk81x_bat_rsoc_dischrg_check(struct rk81x_battery *di)
 {
        int ocv_soc = di->est_ocv_soc;
        int ocv_volt = di->est_ocv_vol;
-       int temp_soc = _get_soc(di);
-       int max_volt = di->rk818->battery_data->max_charger_voltagemV;
+       int rsoc = rk81x_bat_get_rsoc(di);
+       int max_volt = di->pdata->max_charger_voltagemV;
 
        if (ocv_volt > max_volt)
                goto out;
 
-       if (di->discharge_min >= RSOC_CALIB_DISCHGR_TIME) {
-               if ((ocv_soc-temp_soc >= RSOC_DISCHG_ERR_LOWER) ||
-                   (di->temp_soc == 0) ||
-                   (temp_soc-ocv_soc >= RSOC_DISCHG_ERR_UPPER)) {
+       if (di->plug_out_min >= RSOC_CALIB_DISCHRGR_TIME) {
+               if ((ocv_soc-rsoc >= RSOC_DISCHRG_ERR_LOWER) ||
+                   (di->rsoc == 0) ||
+                   (rsoc-ocv_soc >= RSOC_DISCHRG_ERR_UPPER)) {
                        di->err_chck_cnt++;
                        di->err_soc_sum += ocv_soc;
                } else {
                        goto out;
                }
-               DBG("<%s>. rsoc err_chck_cnt = %d\n",
-                   __func__, di->err_chck_cnt);
-               DBG("<%s>. rsoc err_soc_sum = %d\n",
-                   __func__, di->err_soc_sum);
+               DBG("<%s>. rsoc err_chck_cnt = %d, err_soc_sum = %d\n",
+                   __func__, di->err_chck_cnt, di->err_soc_sum);
 
                if (di->err_chck_cnt >= RSOC_ERR_CHCK_CNT) {
                        ocv_soc = di->err_soc_sum / RSOC_ERR_CHCK_CNT;
-                       if (temp_soc-ocv_soc >= RSOC_DISCHG_ERR_UPPER)
+                       if (rsoc-ocv_soc >= RSOC_DISCHRG_ERR_UPPER)
                                ocv_soc += RSOC_COMPS;
 
                        di->temp_nac = ocv_soc * di->fcc / 100;
-                       _capacity_init(di, di->temp_nac);
-                       di->temp_soc = _get_soc(di);
-                       di->remain_capacity = _get_realtime_capacity(di);
+                       rk81x_bat_capacity_init(di, di->temp_nac);
+                       rk81x_bat_capacity_init_post(di);
+                       di->rsoc = rk81x_bat_get_rsoc(di);
+                       di->remain_capacity =
+                                       rk81x_bat_get_realtime_capacity(di);
                        di->err_soc_sum = 0;
                        di->err_chck_cnt = 0;
                        DBG("<%s>. update: rsoc = %d\n", __func__, ocv_soc);
@@ -2400,206 +2571,277 @@ out:
        }
 }
 
-static void rsoc_realtime_calib(struct battery_info *di)
+static void rk81x_bat_rsoc_check(struct rk81x_battery *di)
 {
-       u8 status = di->status;
+       u8 status = di->psy_status;
 
        if ((status == POWER_SUPPLY_STATUS_CHARGING) ||
            (status == POWER_SUPPLY_STATUS_FULL)) {
-               if ((di->current_avg < -10) &&
-                   (di->charge_status != CHARGE_FINISH))
-                       rsoc_dischrg_calib(di);
+               if ((di->current_avg < 0) &&
+                   (di->chrg_status != CHARGE_FINISH))
+                       rk81x_bat_rsoc_dischrg_check(di);
                /*
                else
                        rsoc_chrg_calib(di);
                */
 
        } else if (status == POWER_SUPPLY_STATUS_DISCHARGING) {
-               rsoc_dischrg_calib(di);
+               rk81x_bat_rsoc_dischrg_check(di);
+       }
+}
+
+static void rk81x_bat_emulator_dischrg(struct rk81x_battery *di)
+{
+       u32 temp, soc_time;
+       unsigned long sec_unit;
+
+       if (!di->dischrg_emu_base)
+               di->dischrg_emu_base = get_runtime_sec();
+
+       sec_unit = BASE_TO_SEC(di->dischrg_emu_base) + di->dischrg_save_sec;
+
+       temp = di->fcc * 3600 / 100;
+
+       if (abs(di->current_avg) < DSOC_DISCHRG_EMU_CURR)
+               soc_time = temp / div(abs(DSOC_DISCHRG_EMU_CURR));
+       else
+               soc_time = temp / div(abs(di->current_avg));
+
+       if  (sec_unit > soc_time) {
+               di->dsoc--;
+               di->dischrg_emu_base = get_runtime_sec();
+               di->dischrg_save_sec = 0;
        }
+
+       DBG("<%s> soc_time=%d, sec_unit=%lu\n",
+           __func__, soc_time, sec_unit);
 }
 
 /*
  * when there is a big offset between dsoc and rsoc, dsoc needs to
  * speed up to keep pace witch rsoc.
  */
-static bool do_ac_charger_emulator(struct battery_info *di)
+static void rk81x_bat_emulator_chrg(struct rk81x_battery *di)
 {
-       int delta_soc = di->temp_soc - di->real_soc;
-       u32 soc_time;
+       u32 soc_time, temp;
+       int plus_soc;
+       unsigned long chrg_emu_sec;
+
+       if (!di->chrg_emu_base)
+               di->chrg_emu_base = get_runtime_sec();
+
+       chrg_emu_sec = BASE_TO_SEC(di->chrg_emu_base) + di->chrg_save_sec;
+       temp = di->fcc * 3600 / 100;
 
-       if ((di->charge_status != CHARGE_FINISH) &&
-           (di->ac_online == ONLINE) &&
-           (delta_soc >= DSOC_CHRG_FAST_EER_RANGE)) {
+       if (di->ac_online) {
                if (di->current_avg < DSOC_CHRG_EMU_CURR)
-                       soc_time = di->fcc*3600/100/
-                                       (abs_int(DSOC_CHRG_EMU_CURR));
+                       soc_time = temp / abs(DSOC_CHRG_EMU_CURR);
                else
-                       soc_time = di->fcc*3600/100/
-                                       div(abs_int(di->current_avg));
-               di->emu_chg_cnt++;
-               if  (di->emu_chg_cnt > soc_time) {
-                       di->real_soc++;
-                       di->emu_chg_cnt = 0;
-               }
-               DBG("<%s>. soc_time=%d, emu_cnt=%d\n",
-                   __func__, soc_time, di->emu_chg_cnt);
+                       soc_time = temp / div(abs(di->current_avg));
+       } else {
+               soc_time = temp / 450;
+       }
 
-               return true;
+       plus_soc = chrg_emu_sec / soc_time;
+       if  (chrg_emu_sec > soc_time) {
+               di->dsoc += plus_soc;
+               di->chrg_emu_base = get_runtime_sec();
+               di->chrg_save_sec = 0;
        }
 
-       return false;
+       DBG("<%s>. soc_time=%d, chrg_emu_sec=%lu, plus_soc=%d\n",
+           __func__, soc_time, chrg_emu_sec, plus_soc);
 }
 
 /* check voltage and current when dsoc is close to full.
  * we will do a fake charge to adjust charing speed which
  * aims to make battery full charged and match finish signal.
  */
-static bool do_term_chrg_calib(struct battery_info *di)
+static void rk81x_bat_terminal_chrg(struct rk81x_battery *di)
 {
        u32 soc_time;
-       u32 *ocv_table = di->platform_data->battery_ocv;
+       int plus_soc;
+       unsigned long chrg_term_sec;
+
+       if (!di->chrg_term_base)
+               di->chrg_term_base = get_runtime_sec();
 
+       chrg_term_sec = BASE_TO_SEC(di->chrg_term_base) + di->chrg_save_sec;
        /*check current and voltage*/
-       if ((di->ac_online == ONLINE && di->real_soc >= 90) &&
-           ((di->current_avg > DSOC_CHG_TERM_CURR) ||
-            (di->voltage < ocv_table[18]+20))) {
-               soc_time = di->fcc*3600/100/(abs32_int(DSOC_CHG_TERM_CURR));
-               di->term_chg_cnt++;
-               if  (di->term_chg_cnt > soc_time) {
-                       di->real_soc++;
-                       di->term_chg_cnt = 0;
-               }
-               DBG("<%s>. soc_time=%d, term_cnt=%d\n",
-                   __func__, soc_time, di->term_chg_cnt);
 
-               return true;
-       }
+       soc_time = di->fcc * 3600 / 100 / (abs(DSOC_CHRG_TERM_CURR));
 
-       return false;
+       plus_soc = chrg_term_sec / soc_time;
+       if  (chrg_term_sec > soc_time) {
+               di->dsoc += plus_soc;
+               di->chrg_term_base = get_runtime_sec();
+               di->chrg_save_sec = 0;
+       }
+       DBG("<%s>. soc_time=%d, chrg_term_sec=%lu, plus_soc=%d\n",
+           __func__, soc_time, chrg_term_sec, plus_soc);
 }
 
-static void normal_discharge(struct battery_info *di)
+static void rk81x_bat_normal_dischrg(struct rk81x_battery *di)
 {
        int soc_time = 0;
        int now_current = di->current_avg;
-       int delta_soc = di->real_soc - di->temp_soc;
-
-       if (delta_soc > DSOC_DISCHRG_FAST_EER_RANGE) {
-               soc_time = DSOC_DISCHRG_FAST_DEC_SEC;
-               DBG("<%s>. dsoc decrease fast! delta_soc = %d\n",
-                   __func__, delta_soc);
-       } else {
-               soc_time = di->fcc*3600/100/div(abs_int(now_current));
-       }
-
-       if (di->temp_soc == di->real_soc) {
-               DBG("<%s>. temp_soc == real_soc\n", __func__);
-
-       } else if (di->temp_soc > di->real_soc) {
-               DBG("<%s>. temp_soc > real_soc\n", __func__);
-               di->vol_smooth_time++;
-               if (di->vol_smooth_time > soc_time*3/2) {
-                       di->real_soc--;
-                       di->vol_smooth_time = 0;
+       unsigned long dischrg_normal_sec;
+
+       if (!di->dischrg_normal_base)
+               di->dischrg_normal_base = get_runtime_sec();
+
+       dischrg_normal_sec = BASE_TO_SEC(di->dischrg_normal_base) +
+                                               di->dischrg_save_sec;
+
+       soc_time = di->fcc * 3600 / 100 / div(abs(now_current));
+       DBG("<%s>. rsoc=%d, dsoc=%d, dischrg_st=%d\n",
+           __func__, di->rsoc, di->dsoc, di->discharge_smooth_status);
+
+       if (di->rsoc == di->dsoc) {
+               DBG("<%s>. rsoc == dsoc\n", __func__);
+               di->dsoc = di->rsoc;
+               di->dischrg_normal_base = get_runtime_sec();
+               di->dischrg_save_sec = 0;
+               /*di->discharge_smooth_status = false;*/
+       } else if (di->rsoc > di->dsoc - 1) {
+               DBG("<%s>. rsoc > dsoc - 1\n", __func__);
+               if (dischrg_normal_sec > soc_time * 3 / 2) {
+                       di->dsoc--;
+                       di->dischrg_normal_base = get_runtime_sec();
+                       di->dischrg_save_sec = 0;
                }
-
-       } else {
-               DBG("<%s>. temp_soc < real_soc\n", __func__);
-               if (di->real_soc == (di->temp_soc + 1)) {
-                       di->change_timer = di->soc_timer;
-                       di->real_soc = di->temp_soc;
-               } else {
-                       di->vol_smooth_time++;
-                       if (di->vol_smooth_time > soc_time*3/4) {
-                               di->real_soc--;
-                               di->vol_smooth_time  = 0;
+               di->discharge_smooth_status = true;
+
+       } else if (di->rsoc < di->dsoc - 1) {
+               DBG("<%s>. rsoc < dsoc - 1\n", __func__);
+               if (dischrg_normal_sec > soc_time * 3 / 4) {
+                       di->dsoc--;
+                       di->dischrg_normal_base = get_runtime_sec();
+                       di->dischrg_save_sec = 0;
+               }
+               di->discharge_smooth_status = true;
+
+       } else if (di->rsoc == di->dsoc - 1) {
+               DBG("<%s>. rsoc == dsoc - 1\n", __func__);
+               if (di->discharge_smooth_status) {
+                       if (dischrg_normal_sec > soc_time * 3 / 4) {
+                               di->dsoc--;
+                               di->dischrg_normal_base = get_runtime_sec();
+                               di->dischrg_save_sec = 0;
+                               di->discharge_smooth_status = false;
                        }
+               } else {
+                       di->dsoc--;
+                       di->dischrg_normal_base = get_runtime_sec();
+                       di->dischrg_save_sec = 0;
+                       di->discharge_smooth_status = false;
                }
        }
-       reset_zero_var(di);
-       DBG("<%s>, temp_soc = %d, real_soc = %d\n",
-           __func__, di->temp_soc, di->real_soc);
-       DBG("<%s>, vol_smooth_time = %d, soc_time = %d\n",
-           __func__, di->vol_smooth_time, soc_time);
+
+       DBG("<%s>, rsoc = %d, dsoc = %d, discharge_smooth_status = %d\n"
+           "dischrg_normal_sec = %lu, soc_time = %d, delta_vol=%d\n",
+           __func__, di->rsoc, di->dsoc, di->discharge_smooth_status,
+           dischrg_normal_sec, soc_time, di->delta_vol_smooth);
 }
 
-static void rk81x_battery_discharge_smooth(struct battery_info *di)
+static void rk81x_bat_dischrg_smooth(struct rk81x_battery *di)
 {
-       int ocv_soc;
+       int delta_soc;
 
-       ocv_soc = _voltage_to_capacity(di, 3800);
-       di->temp_soc = _get_soc(di);
+       /* first resume from suspend: we don't run this,
+        * the sleep_dischrg will handle dsoc, and what
+        * ever this is fake wakeup or not, we should clean
+        * zero algorithm mode, or it will handle the dsoc.
+        */
+       if (di->s2r) {
+               rk81x_bat_reset_zero_var(di);
+               return;
+       }
 
-       DBG("<%s>. temp_soc = %d, real_soc = %d\n",
-           __func__, di->temp_soc, di->real_soc);
+       di->rsoc = rk81x_bat_get_rsoc(di);
 
-       if (di->voltage < 3800)
+       DBG("<%s>. rsoc = %d, dsoc = %d, dischrg_algorithm_mode=%d\n",
+           __func__, di->rsoc, di->dsoc, di->dischrg_algorithm_mode);
 
-               zero_get_soc(di);
-       else
-               normal_discharge(di);
-}
+       if (di->dischrg_algorithm_mode == DISCHRG_NORMAL_MODE) {
+               delta_soc = di->dsoc - di->rsoc;
 
-static int get_charging_time(struct battery_info *di)
-{
-       return (di->charging_time/60);
-}
+               if (delta_soc > DSOC_DISCHRG_FAST_EER_RANGE) {
+                       di->dischrg_normal_base = 0;
+                       rk81x_bat_emulator_dischrg(di);
+               } else {
+                       di->chrg_emu_base = 0;
+                       rk81x_bat_normal_dischrg(di);
+               }
 
-static int get_discharging_time(struct battery_info *di)
-{
-       return (di->discharging_time/60);
-}
+               if (di->voltage < ZERO_ALGOR_THRESD) {
+                       di->dischrg_normal_base = 0;
+                       di->chrg_emu_base = 0;
+                       di->dischrg_algorithm_mode = DISCHRG_ZERO_MODE;
+                       di->zero_timeout_cnt = 0;
+
+                       DBG("<%s>. dsoc=%d, last_zero_mode_dsoc=%d\n",
+                           __func__, di->dsoc, di->last_zero_mode_dsoc);
+                       if (di->dsoc != di->last_zero_mode_dsoc) {
+                               di->display_soc = di->dsoc * 1000;
+                               di->last_zero_mode_dsoc = di->dsoc;
+                               rk81x_bat_zero_calc_linek(di);
+                               DBG("<%s>. first calc, init linek\n", __func__);
+                       }
+               }
+       } else {
+               rk81x_bat_zero_algorithm(di);
 
-static int get_finish_time(struct battery_info *di)
-{
-       return (di->finish_time/60);
+               if (di->voltage > ZERO_ALGOR_THRESD + 50) {
+                       di->dischrg_algorithm_mode = DISCHRG_NORMAL_MODE;
+                       di->zero_timeout_cnt = 0;
+                       DBG("<%s>. exit zero_algorithm\n", __func__);
+               }
+       }
 }
 
-static void upd_time_table(struct battery_info *di);
-static void collect_debug_info(struct battery_info *di)
+static void rk81x_bat_dbg_time_table(struct rk81x_battery *di)
 {
-       if ((di->ac_online == ONLINE) || (di->usb_online == ONLINE)) {
-               di->charging_time++;
-               di->discharging_time = 0;
-       } else {
-               di->charging_time = 0;
-               if (di->voltage < 3800)
-                       di->discharging_time += 2;
-               else
-                       di->discharging_time++;
-       }
-       if (di->charge_status == CHARGE_FINISH)
-               di->finish_time++;
+       u8 i;
+       static int old_index;
+       static int old_min;
+       u32 time;
+       int mod = di->dsoc % 10;
+       int index = di->dsoc / 10;
+
+       if (rk81x_chrg_online(di))
+               time = di->plug_in_min;
        else
-               di->finish_time = 0;
+               time = di->plug_out_min;
 
-       di->charge_min = get_charging_time(di);
-       di->discharge_min = get_discharging_time(di);
-       di->finish_min = get_finish_time(di);
+       if ((mod == 0) && (index > 0) && (old_index != index)) {
+               di->chrg_min[index-1] = time - old_min;
+               old_min = time;
+               old_index = index;
+       }
 
-       upd_time_table(di);
+       for (i = 1; i < 11; i++)
+               DBG("Time[%d]=%d, ", (i * 10), di->chrg_min[i-1]);
+       DBG("\n");
 }
 
-static void dump_debug_info(struct battery_info *di)
+static void rk81x_bat_dbg_dmp_info(struct rk81x_battery *di)
 {
        u8 sup_tst_reg, ggcon_reg, ggsts_reg, vb_mod_reg;
        u8 usb_ctrl_reg, chrg_ctrl_reg1, thremal_reg;
        u8 chrg_ctrl_reg2, chrg_ctrl_reg3, rtc_val, misc_reg;
 
-       collect_debug_info(di);
-
-       battery_read(di->rk818, MISC_MARK_REG, &misc_reg, 1);
-       battery_read(di->rk818, GGCON, &ggcon_reg, 1);
-       battery_read(di->rk818, GGSTS, &ggsts_reg, 1);
-       battery_read(di->rk818, SUP_STS_REG, &sup_tst_reg, 1);
-       battery_read(di->rk818, VB_MOD_REG, &vb_mod_reg, 1);
-       battery_read(di->rk818, USB_CTRL_REG, &usb_ctrl_reg, 1);
-       battery_read(di->rk818, CHRG_CTRL_REG1, &chrg_ctrl_reg1, 1);
-       battery_read(di->rk818, CHRG_CTRL_REG2, &chrg_ctrl_reg2, 1);
-       battery_read(di->rk818, CHRG_CTRL_REG3, &chrg_ctrl_reg3, 1);
-       battery_read(di->rk818, 0x00, &rtc_val, 1);
-       battery_read(di->rk818, THERMAL_REG, &thremal_reg, 1);
+       rk81x_bat_read(di, MISC_MARK_REG, &misc_reg, 1);
+       rk81x_bat_read(di, GGCON, &ggcon_reg, 1);
+       rk81x_bat_read(di, GGSTS, &ggsts_reg, 1);
+       rk81x_bat_read(di, SUP_STS_REG, &sup_tst_reg, 1);
+       rk81x_bat_read(di, VB_MOD_REG, &vb_mod_reg, 1);
+       rk81x_bat_read(di, USB_CTRL_REG, &usb_ctrl_reg, 1);
+       rk81x_bat_read(di, CHRG_CTRL_REG1, &chrg_ctrl_reg1, 1);
+       rk81x_bat_read(di, CHRG_CTRL_REG2, &chrg_ctrl_reg2, 1);
+       rk81x_bat_read(di, CHRG_CTRL_REG3, &chrg_ctrl_reg3, 1);
+       rk81x_bat_read(di, 0x00, &rtc_val, 1);
+       rk81x_bat_read(di, THERMAL_REG, &thremal_reg, 1);
 
        DBG("\n------------- dump_debug_regs -----------------\n"
            "GGCON = 0x%2x, GGSTS = 0x%2x, RTC  = 0x%2x\n"
@@ -2614,495 +2856,548 @@ static void dump_debug_info(struct battery_info *di)
            chrg_ctrl_reg2, chrg_ctrl_reg3
           );
 
-       DBG(
-           "########################## [read] 3.0############################\n"
-           "--------------------------------------------------------------\n"
-           "realx-voltage = %d, voltage = %d, current-avg = %d\n"
+       DBG("#######################################################\n"
+           "voltage = %d, current-avg = %d\n"
            "fcc = %d, remain_capacity = %d, ocv_volt = %d\n"
            "check_ocv = %d, check_soc = %d, bat_res = %d\n"
-           "diplay_soc = %d, cpapacity_soc = %d, test_mode = %d\n"
+           "display_soc = %d, cpapacity_soc = %d\n"
            "AC-ONLINE = %d, USB-ONLINE = %d, charging_status = %d\n"
            "finish_real_soc = %d, finish_temp_soc = %d\n"
            "i_offset=0x%x, cal_offset=0x%x, adjust_cap=%d\n"
-           "chrg_time = %d, dischrg_time = %d, finish_time = %d\n",
-           get_relax_voltage(di),
+           "plug_in = %d, plug_out = %d, finish_sig = %d\n"
+           "sec: chrg=%lu, dischrg=%lu, term_chrg=%lu, emu_chrg=%lu\n"
+           "emu_dischrg = %lu, power_on_sec = %lu, g_base_sec=%lld\n"
+           "mode:%d, save_chrg_sec = %lu, save_dischrg_sec = %lu\n"
+           "#########################################################\n",
            di->voltage, di->current_avg,
-           di->fcc, di->remain_capacity, _get_OCV_voltage(di),
+           di->fcc, di->remain_capacity, di->voltage_ocv,
            di->est_ocv_vol, di->est_ocv_soc, di->bat_res,
-           di->real_soc, _get_soc(di), di->fg_drv_mode,
-           di->ac_online, di->usb_online, di->status,
+           di->dsoc, di->rsoc,
+           di->ac_online, di->usb_online, di->psy_status,
            di->debug_finish_real_soc, di->debug_finish_temp_soc,
-           _get_ioffset(di), _get_cal_offset(di), di->adjust_cap,
-           get_charging_time(di), get_discharging_time(di), get_finish_time(di)
+           rk81x_bat_get_ioffset(di), rk81x_bat_get_cal_offset(di),
+           di->adjust_cap, di->plug_in_min, di->plug_out_min,
+           di->finish_sig_min,
+           BASE_TO_SEC(di->chrg_normal_base),
+           BASE_TO_SEC(di->dischrg_normal_base),
+           BASE_TO_SEC(di->chrg_term_base),
+           BASE_TO_SEC(di->chrg_emu_base),
+           BASE_TO_SEC(di->dischrg_emu_base),
+           BASE_TO_SEC(di->power_on_base), g_base_sec,
+           di->current_mode, di->chrg_save_sec, di->dischrg_save_sec
           );
-       rk81x_get_charge_status(di);
-       DBG("###########################################################\n");
+       DBG();
 }
 
-static void update_fcc_capacity(struct battery_info *di)
+static void rk81x_bat_update_fcc(struct rk81x_battery *di)
 {
        int fcc0;
        int remain_cap;
+       int dod0_to_soc100_min;
+
+       remain_cap = di->remain_capacity - di->dod0_capacity - di->adjust_cap;
+       dod0_to_soc100_min = BASE_TO_MIN(di->fcc_update_sec);
 
-       remain_cap = di->remain_capacity + di->adjust_cap - di->first_on_cap;
-       DBG("%s: remain_cap:%d, ajust_cap:%d, first_on_cap=%d\n",
-           __func__, remain_cap, di->adjust_cap, di->first_on_cap);
+       DBG("%s: remain_cap:%d, ajust_cap:%d, dod0_status=%d\n"
+           "dod0_capacity:%d, dod0_to_soc100_min:%d\n",
+           __func__, remain_cap, di->adjust_cap, di->dod0_status,
+           di->dod0_capacity, dod0_to_soc100_min);
 
-       if ((di->charge_status == CHARGE_FINISH) && (di->dod0_status == 1)) {
+       if ((di->chrg_status == CHARGE_FINISH) && (di->dod0_status == 1) &&
+           (dod0_to_soc100_min < 1200)) {
                DBG("%s: dod0:%d, dod0_cap:%d, dod0_level:%d\n",
                    __func__, di->dod0, di->dod0_capacity, di->dod0_level);
 
-               if (get_level(di) >= di->dod0_level) {
-                       fcc0 = (remain_cap - di->dod0_capacity)*100
-                                       /(100-di->dod0);
-                       if (fcc0 > di->qmax)
-                               fcc0 = di->qmax;
-
-                       DBG("%s: fcc0:%d, fcc:%d\n", __func__, fcc0, di->fcc);
-                       if ((fcc0 < di->fcc) && (fcc0 > 1000)) {
-                               di->fcc = fcc0;
-                               _capacity_init(di, di->fcc);
-                               _save_FCC_capacity(di, di->fcc);
-                               DBG("%s: new fcc0:%d\n", __func__, di->fcc);
-                       }
+               fcc0 = remain_cap * 100 / div(100 - di->dod0);
+
+               dev_info(di->dev, "%s: fcc0:%d, fcc:%d\n",
+                        __func__, fcc0, di->fcc);
+
+               if ((fcc0 < di->qmax) && (fcc0 > 1000)) {
+                       di->dod0_status = 0;
+                       di->fcc = fcc0;
+                       rk81x_bat_capacity_init(di, di->fcc);
+                       rk81x_bat_capacity_init_post(di);
+                       rk81x_bat_save_fcc(di, di->fcc);
+                       rk81x_bat_save_level(di, di->dod0_level);
+                       DBG("%s: new fcc0:%d\n", __func__, di->fcc);
                }
+
                di->dod0_status = 0;
        }
 }
 
-static void debug_get_finish_soc(struct battery_info *di)
+static void rk81x_bat_dbg_get_finish_soc(struct rk81x_battery *di)
 {
-       if (di->charge_status == CHARGE_FINISH) {
-               di->debug_finish_real_soc = di->real_soc;
-               di->debug_finish_temp_soc = di->temp_soc;
+       if (di->chrg_status == CHARGE_FINISH) {
+               di->debug_finish_real_soc = di->dsoc;
+               di->debug_finish_temp_soc = di->rsoc;
        }
 }
 
-static void wait_charge_finish_signal(struct battery_info *di)
+static void rk81x_bat_wait_finish_sig(struct rk81x_battery *di)
 {
-       if ((di->charge_status == CHARGE_FINISH) &&
-           (di->voltage > CHG_FINISH_VOL))
-               update_fcc_capacity(di);/* save new fcc*/
+       int chrg_finish_vol = di->pdata->max_charger_voltagemV;
+       bool ret;
 
-       /* debug msg*/
-       debug_get_finish_soc(di);
+       if ((di->chrg_status == CHARGE_FINISH) &&
+           (di->voltage > chrg_finish_vol - 150) &&  di->enter_finish) {
+               rk81x_bat_update_fcc(di);/* save new fcc*/
+               ret = rk81x_bat_zero_current_calib(di);
+               if (ret)
+                       di->enter_finish = false;
+               /* debug msg*/
+               rk81x_bat_dbg_get_finish_soc(di);
+       }
 }
 
-static void charge_finish_routine(struct battery_info *di)
+static void rk81x_bat_finish_chrg(struct rk81x_battery *di)
 {
-       if ((di->charge_status == CHARGE_FINISH) &&
-           (di->voltage > CHG_FINISH_VOL)) {
-               _capacity_init(di, di->fcc);
-               zero_current_calib(di);
-
-               if (di->real_soc < 100) {
-                       DBG("<%s>,CHARGE_FINISH:real_soc<100,real_soc=%d\n",
-                           __func__, di->real_soc);
+       unsigned long sec_finish;
+       int soc_time, plus_soc;
+       int temp;
 
-                       if ((di->soc_counter < 80)) {
-                               di->soc_counter++;
-                       } else {
-                               di->soc_counter = 0;
-                               di->real_soc++;
-                       }
+       if (di->dsoc < 100) {
+               if (!di->chrg_finish_base)
+                       di->chrg_finish_base = get_runtime_sec();
+
+               sec_finish = BASE_TO_SEC(di->chrg_finish_base) +
+                                               di->chrg_save_sec;
+               temp = di->fcc * 3600 / 100;
+               if (di->ac_online)
+                       soc_time = temp / DSOC_CHRG_FINISH_CURR;
+               else if (di->usb_online)
+                       soc_time = temp / 450;
+
+               plus_soc = sec_finish / soc_time;
+               if (sec_finish > soc_time) {
+                       di->dsoc += plus_soc;
+                       di->chrg_finish_base = get_runtime_sec();
+                       di->chrg_save_sec = 0;
                }
+               DBG("<%s>,CHARGE_FINISH:dsoc<100,dsoc=%d\n"
+                   "soc_time=%d, sec_finish=%lu, plus_soc=%d\n",
+                   __func__, di->dsoc, soc_time, sec_finish, plus_soc);
        }
 }
 
-static void normal_charge(struct battery_info *di)
+static void rk81x_bat_normal_chrg(struct rk81x_battery *di)
 {
-       int now_current, soc_time;
+       int now_current;
+       u32 soc_time, unit_sec;
+       int plus_soc = 0;
+       unsigned long chrg_normal_sec;
 
-       now_current = _get_average_current(di);
-       soc_time = di->fcc*3600/100/div(abs_int(now_current));   /* 1%  time; */
-       di->temp_soc = _get_soc(di);
+       now_current = rk81x_bat_get_avg_current(di);
+       soc_time = di->fcc * 3600 / 100 / div(abs(now_current)); /*1% time*/
 
-       DBG("<%s>. temp_soc = %d, real_soc = %d\n",
-           __func__, di->temp_soc, di->real_soc);
+       if (!di->chrg_normal_base)
+               di->chrg_normal_base = get_runtime_sec();
 
-       if (di->real_soc == di->temp_soc) {
-               DBG("<%s>. temp_soc == real_soc\n", __func__);
-                   di->temp_soc = _get_soc(di);
-       }
-       if ((di->temp_soc != di->real_soc) && (now_current != 0)) {
-               if (di->temp_soc < di->real_soc + 1) {
-                       DBG("<%s>. temp_soc < real_soc\n", __func__);
-                       di->charge_smooth_time++;
-                       if  (di->charge_smooth_time > soc_time*3/2) {
-                               di->real_soc++;
-                               di->charge_smooth_time  = 0;
-                       }
-                       di->charge_smooth_status = true;
-               }
+       chrg_normal_sec = BASE_TO_SEC(di->chrg_normal_base) + di->chrg_save_sec;
+       di->rsoc = rk81x_bat_get_rsoc(di);
 
-               else if (di->temp_soc > di->real_soc + 1) {
-                       DBG("<%s>. temp_soc > real_soc\n", __func__);
-                       di->charge_smooth_time++;
-                       if  (di->charge_smooth_time > soc_time*3/4) {
-                               di->real_soc++;
-                               di->charge_smooth_time  = 0;
-                       }
-                       di->charge_smooth_status = true;
-
-               } else if (di->temp_soc == di->real_soc + 1) {
-                       DBG("<%s>. temp_soc == real_soc + 1\n", __func__);
-                       if (di->charge_smooth_status) {
-                               di->charge_smooth_time++;
-                               if (di->charge_smooth_time > soc_time*3/4) {
-                                       di->real_soc = di->temp_soc;
-                                       di->charge_smooth_time  = 0;
-                                       di->charge_smooth_status = false;
-                               }
+       DBG("<%s>. rsoc=%d, dsoc=%d, chrg_st=%d\n",
+           __func__, di->rsoc, di->dsoc, di->charge_smooth_status);
 
-                       } else {
-                               di->real_soc = di->temp_soc;
+       if (di->dsoc == di->rsoc) {
+               DBG("<%s>. rsoc == dsoc + 1\n", __func__);
+               di->rsoc = rk81x_bat_get_rsoc(di);
+               di->chrg_normal_base = get_runtime_sec();
+               di->chrg_save_sec = 0;
+               /*di->charge_smooth_status = false;*/
+       } else if (di->rsoc < di->dsoc + 1) {
+               DBG("<%s>. rsoc < dsoc + 1\n", __func__);
+               unit_sec = soc_time * 3 / 2;
+               plus_soc = chrg_normal_sec / unit_sec;
+               if  (chrg_normal_sec > unit_sec) {
+                       di->dsoc += plus_soc;
+                       di->chrg_normal_base = get_runtime_sec();
+                       di->chrg_save_sec = 0;
+               }
+               di->charge_smooth_status = true;
+       } else if (di->rsoc > di->dsoc + 1) {
+               DBG("<%s>. rsoc > dsoc + 1\n", __func__);
+               unit_sec = soc_time * 3 / 4;
+               plus_soc = chrg_normal_sec / unit_sec;
+               if  (chrg_normal_sec > unit_sec) {
+                       di->dsoc += plus_soc;
+                       di->chrg_normal_base = get_runtime_sec();
+                       di->chrg_save_sec = 0;
+               }
+               di->charge_smooth_status = true;
+       } else if (di->rsoc == di->dsoc + 1) {
+               DBG("<%s>. rsoc == dsoc + 1\n", __func__);
+               if (di->charge_smooth_status) {
+                       unit_sec = soc_time * 3 / 4;
+                       if (chrg_normal_sec > unit_sec) {
+                               di->dsoc = di->rsoc;
+                               di->chrg_normal_base = get_runtime_sec();
                                di->charge_smooth_status = false;
+                               di->chrg_save_sec = 0;
                        }
+               } else {
+                       di->dsoc = di->rsoc;
+                       di->chrg_normal_base = get_runtime_sec();
+                       di->charge_smooth_status = false;
+                       di->chrg_save_sec = 0;
                }
        }
 
-       DBG("<%s>, temp_soc = %d, real_soc = %d\n",
-           __func__, di->temp_soc, di->real_soc);
-       DBG("<%s>, vol_smooth_time = %d, soc_time = %d\n",
-           __func__, di->charge_smooth_time, soc_time);
+       DBG("<%s>, rsoc = %d, dsoc = %d, charge_smooth_status = %d\n"
+           "chrg_normal_sec = %lu, soc_time = %d, plus_soc=%d\n",
+           __func__, di->rsoc, di->dsoc, di->charge_smooth_status,
+           chrg_normal_sec, soc_time, plus_soc);
 }
 
-
-
-static void rk81x_battery_charge_smooth(struct battery_info *di)
+static void rk81x_bat_update_time(struct rk81x_battery *di)
 {
-       reset_zero_var(di);
-       /*calibrate: aim to match finish signal*/
-       if (do_term_chrg_calib(di))
-               return;
+       u64 runtime_sec;
 
-       /*calibrate: aim to calib error*/
-       di->term_chg_cnt = 0;
-       if (do_ac_charger_emulator(di))
-               return;
+       runtime_sec = get_runtime_sec();
 
-       normal_charge(di);
-}
-
-static void rk81x_battery_display_smooth(struct battery_info *di)
-{
-       int status;
-       u8  charge_status;
-
-       status = di->status;
-       charge_status = di->charge_status;
-       if ((status == POWER_SUPPLY_STATUS_CHARGING) ||
-           (status == POWER_SUPPLY_STATUS_FULL)) {
-               if ((di->current_avg < -10) &&
-                   (charge_status != CHARGE_FINISH))
-                       rk81x_battery_discharge_smooth(di);
-               else
-                       rk81x_battery_charge_smooth(di);
+       /*update by charger type*/
+       if (rk81x_chrg_online(di))
+               di->plug_out_base = runtime_sec;
+       else
+               di->plug_in_base = runtime_sec;
 
-       } else if (status == POWER_SUPPLY_STATUS_DISCHARGING) {
-               rk81x_battery_discharge_smooth(di);
-               if (di->real_soc == 1) {
-                       di->time2empty++;
-                       if (di->time2empty >= 300)
-                               di->real_soc = 0;
-               } else {
-                       di->time2empty = 0;
-               }
+       /*update by current*/
+       if (di->chrg_status != CHARGE_FINISH) {
+               di->finish_sig_base = runtime_sec;
+               di->chrg_finish_base = runtime_sec;
        }
-}
 
-/*
- * update rsoc by relax voltage
- */
-static void resume_relax_calib(struct battery_info *di)
-{
-       int relax_vol = di->relax_voltage;
-       int ocv_soc, capacity;
+       di->plug_in_min = BASE_TO_MIN(di->plug_in_base);
+       di->plug_out_min = BASE_TO_MIN(di->plug_out_base);
+       di->finish_sig_min = BASE_TO_MIN(di->finish_sig_base);
 
-       ocv_soc = _voltage_to_capacity(di, relax_vol);
-       capacity = (ocv_soc * di->fcc / 100);
-       _capacity_init(di, capacity);
-       di->remain_capacity = _get_realtime_capacity(di);
-       di->temp_soc = _get_soc(di);
-       DBG("%s, RSOC=%d, CAP=%d\n", __func__, ocv_soc, capacity);
+       rk81x_bat_dbg_time_table(di);
 }
 
-/* condition:
- * 1: must do it
- * 0: when neccessary
- */
-static void resume_vol_calib(struct battery_info *di, int condition)
+static int rk81x_bat_get_rsoc_trend(struct rk81x_battery *di)
 {
-       int ocv_vol = di->est_ocv_vol;
-       int ocv_soc = 0, capacity = 0;
+       int trend_start_cap = di->trend_start_cap;
+       int remain_cap = di->remain_capacity;
+       int diff_cap;
+       int state;
 
-       ocv_soc = _voltage_to_capacity(di, ocv_vol);
-       capacity = (ocv_soc * di->fcc / 100);
-       if (condition || (abs(ocv_soc-di->temp_soc) >= RSOC_RESUME_ERR)) {
-               _capacity_init(di, capacity);
-               di->remain_capacity = _get_realtime_capacity(di);
-               di->temp_soc = _get_soc(di);
-               DBG("<%s>, rsoc updated!\n", __func__);
+       DBG("<%s>. trend_start_cap = %d, diff_cap = %d\n",
+           __func__, trend_start_cap, diff_cap);
+       diff_cap = remain_cap - trend_start_cap;
+       if (abs(diff_cap) >= TREND_CAP_DIFF) {
+               di->trend_start_cap = di->remain_capacity;
+               state = (diff_cap > 0) ? TREND_STAT_UP : TREND_STAT_DOWN;
+               DBG("<%s>. new trend_start_cap=%d", __func__, trend_start_cap);
+       } else {
+               state = TREND_STAT_FLAT;
        }
-       DBG("<%s>, OCV_VOL=%d,OCV_SOC=%d, CAP=%d\n",
-           __func__, ocv_vol, ocv_soc, capacity);
+
+       if (di->s2r)
+               di->trend_start_cap = di->remain_capacity;
+
+       return state;
 }
 
-/*
- * when support HW_ADP_TYPE_DUAL, and at the moment that usb_adp
- * and dc_adp are plugined in together, the dc_apt has high priority.
- * so we check dc_apt first and return rigth away if it's found.
- */
-static enum charger_type_t rk81x_get_adp_type(struct battery_info *di)
+static void rk81x_bat_arbitrate_rsoc_trend(struct rk81x_battery *di)
 {
-       u8 buf;
-       enum charger_type_t charger_type = NO_CHARGER;
+       int state, soc_time;
+       static int trend_down_cnt, trend_up_cnt;
+       int trend_cnt_thresd;
+       int now_current = di->current_avg;
 
-       /*check by ic hardware: this check make check work safer*/
-       battery_read(di->rk818, VB_MOD_REG, &buf, 1);
-       if ((buf & PLUG_IN_STS) == 0)
-               return NO_CHARGER;
+       trend_cnt_thresd = di->fcc / 100 / TREND_CAP_DIFF;
+       state = rk81x_bat_get_rsoc_trend(di);
+       DBG("<%s>. TREND_STAT = %d, trend_down_cnt = %d\n",
+           __func__, state, trend_down_cnt);
+       if (di->chrg_status == CHARGE_FINISH)
+               return;
 
-       /*check DC first*/
-       if (rk81x_support_adp_type(HW_ADP_TYPE_DC)) {
-               charger_type = rk81x_get_dc_state(di);
-               if (charger_type == DC_CHARGER)
-                       return charger_type;
+       if (state == TREND_STAT_UP) {
+               rk81x_bat_reset_zero_var(di);
+               trend_down_cnt = 0;
+               trend_up_cnt++;
+               if (trend_up_cnt >= trend_cnt_thresd) {
+                       trend_up_cnt = 0;
+                       di->dischrg_save_sec = 0;
+               }
+       } else if (state == TREND_STAT_DOWN) {
+               trend_up_cnt = 0;
+               trend_down_cnt++;
+               if (trend_down_cnt >= trend_cnt_thresd) {
+                       trend_down_cnt = 0;
+                       di->chrg_save_sec = 0;
+               }
+       } else {/*state == TREND_STAT_FLAT*/
+               soc_time = di->fcc * 3600 / 100 / div(abs(now_current));
+               if ((di->chrg_save_sec + 20 > soc_time) &&
+                   (trend_up_cnt <= trend_cnt_thresd / 2) &&
+                   (now_current >= 0))
+                       di->chrg_save_sec = 0;
+
+               else if ((di->dischrg_save_sec + 20 > soc_time) &&
+                        (trend_down_cnt <= trend_cnt_thresd / 2) &&
+                        (now_current < 0))
+                       di->dischrg_save_sec = 0;
        }
 
-       /*HW_ADP_TYPE_USB*/
-       charger_type = rk81x_get_usbac_state(di);
-
-       return charger_type;
+       DBG("<%s>. state=%d, cnt_thresd=%d, soc_time=%d\n"
+           "up_cnt=%d, down_cnt=%d\n",
+           __func__, state, trend_cnt_thresd, soc_time,
+           trend_up_cnt, trend_down_cnt);
+}
+
+static void rk81x_bat_chrg_smooth(struct rk81x_battery *di)
+{
+       u32 *ocv_table = di->pdata->battery_ocv;
+       int delta_soc = di->rsoc - di->dsoc;
+       int chrg_finish_vol = di->pdata->max_charger_voltagemV;
+
+       if ((di->chrg_status == CHARGE_FINISH ||
+            di->slp_chrg_status == CHARGE_FINISH) &&
+            (di->voltage > chrg_finish_vol - 150)) {
+               /*clear sleep charge status*/
+               di->slp_chrg_status = rk81x_bat_get_chrg_status(di);
+               di->chrg_emu_base = 0;
+               di->chrg_normal_base = 0;
+               di->chrg_term_base = 0;
+               rk81x_bat_finish_chrg(di);
+               rk81x_bat_capacity_init(di, di->fcc);
+               rk81x_bat_capacity_init_post(di);
+       } else if ((di->ac_online == ONLINE && di->dsoc >= 90) &&
+           ((di->current_avg > DSOC_CHRG_TERM_CURR) ||
+            (di->voltage < ocv_table[18] + 20))) {
+               di->chrg_emu_base = 0;
+               di->chrg_normal_base = 0;
+               di->chrg_finish_base = 0;
+               rk81x_bat_terminal_chrg(di);
+       } else if (di->chrg_status != CHARGE_FINISH &&
+                  delta_soc >= DSOC_CHRG_FAST_EER_RANGE) {
+               di->chrg_term_base = 0;
+               di->chrg_normal_base = 0;
+               di->chrg_finish_base = 0;
+               rk81x_bat_emulator_chrg(di);
+       } else {
+               di->chrg_emu_base = 0;
+               di->chrg_term_base = 0;
+               di->chrg_finish_base = 0;
+               rk81x_bat_normal_chrg(di);
+       }
 }
 
-static void rk81x_sleep_discharge(struct battery_info *di)
+static unsigned long rk81x_bat_save_dischrg_sec(struct rk81x_battery *di)
 {
-       int delta_cap;
-       int delta_soc;
-       int sleep_min;
-       unsigned long sleep_sec;
-       int enter_rsoc;
-
-       enter_rsoc = di->real_soc;
-       sleep_sec = BASE_TO_SEC(di->suspend_time_start);
-       sleep_min = BASE_TO_MIN(di->suspend_time_start);
-       delta_cap = di->suspend_cap - di->remain_capacity;
-       delta_soc = di->suspend_rsoc - _get_soc(di);
-       di->sum_suspend_cap += delta_cap;
-
-       DBG("<%s>, slp_sec(s)=%lu, slp_min=%d\n"
-           "delta_cap(s)=%d, delta_soc=%d, sum_cap=%d\n"
-           "remain_cap=%d, rsoc=%d, dsoc=%d\n"
-           "relax_vol=%d, vol=%d, curr=%d\n",
-           __func__, sleep_sec, sleep_min,
-           delta_cap, delta_soc, di->sum_suspend_cap,
-           di->remain_capacity, _get_soc(di), di->real_soc,
-           di->relax_voltage, di->voltage, _get_average_current(di));
-
-       /*handle rsoc*/
-       if ((sleep_min >= 30) &&
-           (di->relax_voltage >= di->voltage)) {
-               resume_relax_calib(di);
-               restart_relax(di);
+       unsigned long dischrg_normal_sec = BASE_TO_SEC(di->dischrg_normal_base);
+       unsigned long dischrg_emu_sec = BASE_TO_SEC(di->dischrg_emu_base);
 
-       /* current_avg < 0: make sure the system is not
-        * wakeup by charger plugin.
-        */
+       DBG("dischrg_normal_sec=%lu, dischrg_emu_sec=%lu\n",
+           dischrg_normal_sec, dischrg_emu_sec);
 
-       /* even if relax voltage is not caught rightly, realtime voltage
-        * is quite close to relax voltage, we should not do nothing after
-        * sleep 30min
-        */
-       } else if ((sleep_min >= 30) && (di->current_avg < 0)) {
-               resume_vol_calib(di, 1);
-       } else if ((sleep_min >= 3) && (di->current_avg < 0)) {
-               resume_vol_calib(di, 0);
-       }
+       return (dischrg_normal_sec > dischrg_emu_sec) ?
+               dischrg_normal_sec : dischrg_emu_sec;
+}
 
-       /*handle dsoc*/
-       delta_soc = di->sum_suspend_cap/(di->fcc/100);
-
-       DBG("<%s>. sum_cap ==> delta_soc = %d\n", __func__, delta_soc);
-       if (delta_soc > 0) {
-               if (di->real_soc-(delta_soc*1/3) <= di->temp_soc)
-                       di->real_soc -= (delta_soc*1/3);
-               else if (di->real_soc-(delta_soc*1/2) < di->temp_soc)
-                       di->real_soc -= (delta_soc*1/2);
-               else
-                       di->real_soc -= delta_soc;
+static unsigned long rk81x_bat_save_chrg_sec(struct rk81x_battery *di)
+{
+       unsigned long sec1, sec2;
+       unsigned long chrg_normal_sec = BASE_TO_SEC(di->chrg_normal_base);
+       unsigned long chrg_term_sec = BASE_TO_SEC(di->chrg_term_base);
+       unsigned long chrg_emu_sec = BASE_TO_SEC(di->chrg_emu_base);
+       unsigned long chrg_finish_sec = BASE_TO_SEC(di->chrg_finish_base);
 
-               /*di->sum_suspend_cap %= (di->fcc/100);*/
-               if (di->real_soc != enter_rsoc)
-                       di->sum_suspend_cap = 0;
+       sec1 = (chrg_normal_sec > chrg_term_sec) ?
+               chrg_normal_sec : chrg_term_sec;
 
-       } else if (delta_soc < 0) {
-               di->real_soc--;
-       }
-       DBG("<%s>, out: dsoc=%d, rsoc=%d, sum_cap=%d\n",
-           __func__, di->real_soc, di->temp_soc, di->sum_suspend_cap);
+       sec2 = (chrg_emu_sec > chrg_finish_sec) ?
+               chrg_emu_sec : chrg_finish_sec;
+       DBG("chrg_normal_sec=%lu, chrg_term_sec=%lu\n"
+           "chrg_emu_sec=%lu, chrg_finish_sec=%lu\n",
+           chrg_normal_sec, chrg_term_sec,
+           chrg_emu_sec, chrg_finish_sec);
+
+       return (sec1 > sec2) ? sec1 : sec2;
 }
 
-static void rk81x_sleep_charge(struct battery_info *di)
+static void rk81x_bat_display_smooth(struct rk81x_battery *di)
 {
-       unsigned long sleep_soc;
-       unsigned long sleep_sec;
-       int delta_cap;
-       int delta_soc;
-       int sleep_min;
-       u8 charge_status = di->charge_status;
-
-       if ((di->suspend_charge_current >= 0) ||
-           (rk81x_get_charge_status(di) == CHARGE_FINISH)) {
-               sleep_sec = BASE_TO_SEC(di->suspend_time_start);
-               sleep_min = BASE_TO_MIN(di->suspend_time_start);
-               delta_cap = di->suspend_cap - di->remain_capacity;
-               delta_soc = di->suspend_rsoc - _get_soc(di);
-
-               DBG("<%s>, ac=%d, usb=%d, slp_curr=%d\n",
-                   __func__, di->ac_online, di->usb_online,
-                   di->suspend_charge_current);
-               if (((di->suspend_charge_current < 800) &&
-                    (di->ac_online == ONLINE)) ||
-                    (charge_status == CHARGE_FINISH)) {
-                       DBG("<%s>,sleep: ac online current < 800\n", __func__);
-                       if (sleep_sec > 0) {
-                               /*default charge current: 1000mA*/
-                               di->count_sleep_time += sleep_sec;
-                               sleep_soc = 1000*di->count_sleep_time*100
-                                                       /3600/div(di->fcc);
-                               DBG("<%s> sleep_soc=%lu, real_soc=%d\n",
-                                   __func__, sleep_soc, di->real_soc);
-                               if (sleep_soc > 0)
-                                       di->count_sleep_time = 0;
-                               di->real_soc += sleep_soc;
-                               if (di->real_soc > 100)
-                                       di->real_soc = 100;
-                       }
-               } else {
-                       DBG("<%s>, usb charge\n", __func__);
-                       if ((di->temp_soc - di->suspend_rsoc) > 0)
-                               di->real_soc +=
-                                       (di->temp_soc - di->suspend_rsoc);
+       if ((di->current_avg >= 0) || (di->chrg_status == CHARGE_FINISH)) {
+               if (di->current_mode == DISCHRG_MODE) {
+                       di->current_mode = CHRG_MODE;
+                       di->dischrg_save_sec += rk81x_bat_save_dischrg_sec(di);
+                       di->dischrg_normal_base = 0;
+                       di->dischrg_emu_base = 0;
+                       if (di->chrg_status == CHARGE_FINISH)
+                               di->dischrg_save_sec = 0;
+                       if ((di->chrg_status == CHARGE_FINISH) &&
+                           (di->dsoc >= 100))
+                               di->chrg_save_sec = 0;
+
+                       DBG("<%s>---dischrg_save_sec = %lu\n",
+                           __func__, di->dischrg_save_sec);
                }
 
-               DBG("<%s>, out: dsoc=%d, rsoc=%d\n",
-                   __func__, di->real_soc, di->temp_soc);
+               if (!rk81x_chrg_online(di)) {
+                       dev_err(di->dev, "discharge, current error:%d\n",
+                               di->current_avg);
+               } else {
+                       rk81x_bat_chrg_smooth(di);
+                       di->discharge_smooth_status = true;
+               }
+       } else {
+               if (di->current_mode == CHRG_MODE) {
+                       di->current_mode = DISCHRG_MODE;
+                       di->chrg_save_sec += rk81x_bat_save_chrg_sec(di);
+                       di->chrg_normal_base = 0;
+                       di->chrg_emu_base = 0;
+                       di->chrg_term_base = 0;
+                       di->chrg_finish_base = 0;
+                       DBG("<%s>---chrg_save_sec = %lu\n",
+                           __func__, di->chrg_save_sec);
+               }
+               rk81x_bat_dischrg_smooth(di);
+               di->charge_smooth_status = true;
        }
 }
 
 /*
- * we need flag "sys_wakeup" to make sure that the system is reall power up.
- * because there is fake system power up which causes suspend param be cleaned.
+ * update rsoc by relax voltage
  */
-static void update_resume_state(struct battery_info *di)
+static void rk81x_bat_relax_vol_calib(struct rk81x_battery *di)
 {
-       if (di->resume) {
-               di->resume = false;
-               di->sys_wakeup = true;
-               /*update the info first*/
-               rk81x_update_battery_info(di);
-               reset_zero_var(di);
-
-               if (di->sleep_status == POWER_SUPPLY_STATUS_DISCHARGING)
-                       rk81x_sleep_discharge(di);
+       int relax_vol = di->relax_voltage;
+       int ocv_soc, capacity;
 
-               else if (di->sleep_status == POWER_SUPPLY_STATUS_CHARGING)
-                       rk81x_sleep_charge(di);
-       }
+       ocv_soc = rk81x_bat_vol_to_capacity(di, relax_vol);
+       capacity = (ocv_soc * di->fcc / 100);
+       rk81x_bat_capacity_init(di, capacity);
+       di->remain_capacity = rk81x_bat_get_realtime_capacity(di);
+       di->rsoc = rk81x_bat_get_rsoc(di);
+       rk81x_bat_capacity_init_post(di);
+       DBG("%s, RSOC=%d, CAP=%d\n", __func__, ocv_soc, capacity);
 }
 
-static void rk81x_set_charger_current(struct battery_info *di,
-                                     enum charger_type_t charger_type)
+/* condition:
+ * 1: must do it, 0: when necessary
+ */
+static void rk81x_bat_vol_calib(struct rk81x_battery *di, int condition)
 {
-       switch (charger_type) {
-       case NO_CHARGER:
-       case USB_CHARGER:
-               set_charge_current(di, ILIM_450MA);
-               break;
+       int ocv_vol = di->est_ocv_vol;
+       int ocv_soc = 0, capacity = 0;
 
-       case AC_CHARGER:
-       case DC_CHARGER:
-               set_charge_current(di, di->chg_i_lmt);
-               break;
-       default:
-               set_charge_current(di, ILIM_450MA);
+       ocv_soc = rk81x_bat_vol_to_capacity(di, ocv_vol);
+       capacity = (ocv_soc * di->fcc / 100);
+       if (condition || (abs(ocv_soc-di->rsoc) >= RSOC_RESUME_ERR)) {
+               rk81x_bat_capacity_init(di, capacity);
+               di->remain_capacity = rk81x_bat_get_realtime_capacity(di);
+               di->rsoc = rk81x_bat_get_rsoc(di);
+               rk81x_bat_capacity_init_post(di);
+               DBG("<%s>, rsoc updated!\n", __func__);
        }
+       DBG("<%s>, OCV_VOL=%d,OCV_SOC=%d, CAP=%d\n",
+           __func__, ocv_vol, ocv_soc, capacity);
 }
 
-
-static void rk81x_set_power_supply_state(struct battery_info *di,
-                                        enum charger_type_t  charger_type)
+static int  rk81x_bat_sleep_dischrg(struct rk81x_battery *di)
 {
-       di->usb_online = OFFLINE;
-       di->ac_online = OFFLINE;
-       di->dc_online = OFFLINE;
+       int delta_soc, temp_dsoc;
+       unsigned long sleep_sec = di->suspend_time_sum;
+       int power_off_thresd = di->pdata->power_off_thresd;
 
-       switch (charger_type) {
-       case NO_CHARGER:
-               di->status = POWER_SUPPLY_STATUS_DISCHARGING;
-               break;
+       DBG("<%s>, enter: dsoc=%d, rsoc=%d\n"
+           "relax_vol=%d, vol=%d, sleep_min=%lu\n",
+           __func__, di->dsoc, di->rsoc,
+           di->relax_voltage, di->voltage, sleep_sec / 60);
 
-       case USB_CHARGER:
-               di->usb_online = ONLINE;
-               di->status = POWER_SUPPLY_STATUS_CHARGING;
-               break;
+       if (di->relax_voltage >= di->voltage) {
+               rk81x_bat_relax_vol_calib(di);
+               rk81x_bat_restart_relax(di);
 
-       case DC_CHARGER:/*treat dc as ac*/
-               di->dc_online = ONLINE;
-       case AC_CHARGER:
-               di->ac_online = ONLINE;
-               di->status = POWER_SUPPLY_STATUS_CHARGING;
-               break;
-       default:
-               di->status = POWER_SUPPLY_STATUS_DISCHARGING;
+       /* current_avg < 0: make sure the system is not
+        * wakeup by charger plugin.
+        */
+       /* even if relax voltage is not caught rightly, realtime voltage
+        * is quite close to relax voltage, we should not do nothing after
+        * sleep 30min
+        */
+       } else  {
+               rk81x_bat_vol_calib(di, 1);
        }
 
-       if (di->real_soc >= 100)
-               di->status = POWER_SUPPLY_STATUS_FULL;
-}
+       /*handle dsoc*/
+       if (di->dsoc <= di->rsoc) {
+               di->sum_suspend_cap = (SLP_CURR_MIN * sleep_sec / 3600);
+               delta_soc = di->sum_suspend_cap * 100 / di->fcc;
+               temp_dsoc = di->dsoc - delta_soc;
+
+               if (delta_soc > 0) {
+                       if ((temp_dsoc < di->dsoc) && (di->dsoc < 5))
+                               di->dsoc--;
+                       else if ((temp_dsoc < 5) && (di->dsoc >= 5))
+                               di->dsoc = 5;
+                       else if (temp_dsoc > 5)
+                               di->dsoc = temp_dsoc;
+               }
 
-static void rk81x_check_battery_status(struct battery_info *di)
-{
-       enum charger_type_t  charger_type;
+               DBG("%s: dsoc<=rsoc, sum_cap=%d==>delta_soc=%d,temp_dsoc=%d\n",
+                   __func__, di->sum_suspend_cap, delta_soc, temp_dsoc);
+       } else {
+               /*di->dsoc > di->rsoc*/
+               di->sum_suspend_cap = (SLP_CURR_MAX * sleep_sec / 3600);
+               delta_soc = di->sum_suspend_cap / (di->fcc / 100);
+               temp_dsoc = di->dsoc - di->rsoc;
+               if ((di->est_ocv_vol > SLP_DSOC_VOL_THRESD) &&
+                   (temp_dsoc > delta_soc))
+                       di->dsoc -= delta_soc;
+               else
+                       di->dsoc = di->rsoc;
 
-       charger_type = rk81x_get_adp_type(di);
-       rk81x_set_charger_current(di, charger_type);
-       rk81x_set_power_supply_state(di, charger_type);
-}
+               DBG("%s: dsoc > rsoc, sum_cap=%d==>delta_soc=%d,temp_dsoc=%d\n",
+                   __func__, di->sum_suspend_cap, delta_soc, temp_dsoc);
+       }
 
+       if (!di->relax_voltage && di->voltage <= power_off_thresd)
+               di->dsoc = 0;
 
-/* high load: current < 0 with charger in.
- * System will not shutdown while dsoc=0% with charging state(ac_online),
- * which will cause over discharge, so oppose status before report states.
- */
-static void last_check_report(struct battery_info *di)
-{
-       static u32 time;
+       if (di->dsoc <= 0)
+               di->dsoc = 0;
+
+       DBG("<%s>, out: dsoc=%d, rsoc=%d, sum_cap=%d\n",
+           __func__, di->dsoc, di->rsoc, di->sum_suspend_cap);
 
-       if ((di->real_soc == 0) &&
-           (di->status == POWER_SUPPLY_STATUS_CHARGING) &&
-          di->current_avg < 0) {
-               if (BASE_TO_SEC(time) > 60)
-                       rk81x_set_power_supply_state(di, NO_CHARGER);
+       return delta_soc;
+}
 
-               DBG("dsoc=0, time=%ld\n", get_seconds() - time);
-               DBG("status=%d, ac_online=%d, usb_online=%d\n",
-                   di->status, di->ac_online, di->usb_online);
+static int rk81x_bat_sleep_chrg(struct rk81x_battery *di)
+{
+       int sleep_soc;
+       unsigned long sleep_sec;
 
+       sleep_sec = di->suspend_time_sum;
+       if (((di->suspend_charge_current < 800) &&
+            (di->ac_online == ONLINE)) ||
+            (di->chrg_status == CHARGE_FINISH)) {
+               DBG("<%s>,sleep: ac online current < 800\n", __func__);
+               if (sleep_sec > 0) {
+                       /*default charge current: 1000mA*/
+                       sleep_soc = SLP_CHRG_CURR * sleep_sec * 100
+                                               / 3600 / div(di->fcc);
+               }
        } else {
-               time = get_seconds();
+               DBG("<%s>, usb charge\n", __func__);
        }
+
+       return sleep_soc;
 }
+
 /*
  * only do report when there is a change.
  *
- * if ((di->real_soc == 0) && (di->fg_drv_mode == FG_NORMAL_MODE)):
- * when real_soc == 0, we must do report. But it will generate too much android
+ * if ((di->dsoc == 0) && (di->fg_drv_mode == FG_NORMAL_MODE)):
+ * when dsoc == 0, we must do report. But it will generate too much android
  * info when we enter test_power mode without battery, so we add a fg_drv_mode
  * ajudgement.
  */
-static void report_power_supply_changed(struct battery_info *di)
+static void rk81x_bat_power_supply_changed(struct rk81x_battery *di)
 {
        static u32 old_soc;
        static u32 old_ac_status;
@@ -3111,110 +3406,75 @@ static void report_power_supply_changed(struct battery_info *di)
        bool state_changed;
 
        state_changed = false;
-       if ((di->real_soc == 0) && (di->fg_drv_mode == FG_NORMAL_MODE))
+       if ((di->dsoc == 0) && (di->fg_drv_mode == FG_NORMAL_MODE))
                state_changed = true;
-       else if (di->real_soc != old_soc)
+       else if (di->dsoc != old_soc)
                state_changed = true;
        else if (di->ac_online != old_ac_status)
                state_changed = true;
        else if (di->usb_online != old_usb_status)
                state_changed = true;
-       else if (old_charge_status != di->status)
+       else if (old_charge_status != di->psy_status)
                state_changed = true;
 
+       if (di->dsoc >= 100 && rk81x_chrg_online(di))
+               di->psy_status = POWER_SUPPLY_STATUS_FULL;
+
        if (state_changed) {
                power_supply_changed(&di->bat);
                power_supply_changed(&di->usb);
                power_supply_changed(&di->ac);
-               old_soc = di->real_soc;
+               old_soc = di->dsoc;
                old_ac_status = di->ac_online;
                old_usb_status = di->usb_online;
-               old_charge_status = di->status;
+               old_charge_status = di->psy_status;
                DBG("<%s>. report: dsoc=%d, rsoc=%d\n",
-                   __func__, di->real_soc, di->temp_soc);
-       }
-}
-
-static void upd_time_table(struct battery_info *di)
-{
-       u8 i;
-       static int old_index;
-       static int old_min;
-       u32 time;
-       int mod = di->real_soc % 10;
-       int index = di->real_soc / 10;
-
-       if (di->ac_online == ONLINE || di->usb_online == ONLINE)
-               time = di->charge_min;
-       else
-               time = di->discharge_min;
-
-       if ((mod == 0) && (index > 0) && (old_index != index)) {
-               di->chrg_min[index-1] = time - old_min;
-               old_min = time;
-               old_index = index;
+                   __func__, di->dsoc, di->rsoc);
        }
-
-       for (i = 1; i < 11; i++)
-               DBG("Time[%d]=%d, ", (i*10), di->chrg_min[i-1]);
-       DBG("\n");
-}
-
-/*
- * there is a timer inside rk81x to calc how long the battery is in charging
- * state. rk81x will close PowerPath inside IC when timer reach, which will
- * stop the charging work. we have to reset the corresponding bits to restart
- * the timer to avoid that case.
- */
-static void rk81x_init_chrg_timer(struct battery_info *di)
-{
-       u8 buf;
-
-       battery_read(di->rk818, CHRG_CTRL_REG3, &buf, 1);
-       buf &= ~(0x4);
-       battery_write(di->rk818, CHRG_CTRL_REG3, &buf, 1);
-       battery_read(di->rk818, CHRG_CTRL_REG3, &buf, 1);
-       DBG("%s: clr: CHRG_CTRL_REG3<2> = 0x%x", __func__, buf);
-       buf |= 0x04;
-       battery_write(di->rk818, CHRG_CTRL_REG3, &buf, 1);
 }
 
-static u8 get_cvcc_charge_hour(struct battery_info *di)
+static u8 rk81x_bat_get_cvcc_chrg_hour(struct rk81x_battery *di)
 {
        u8 hour, buf;
 
-       battery_read(di->rk818, CHRG_CTRL_REG2, &buf, 1);
+       rk81x_bat_read(di, CHRG_CTRL_REG2, &buf, 1);
        hour = buf & 0x07;
 
-       return CHG_CVCC_HOUR[hour];
+       return CHRG_CVCC_HOUR[hour];
 }
 
 /* we have to estimate the charging finish time from now, to decide
  * whether we should reset the timer or not.
  */
-static void rk81x_check_chrg_over_time(struct battery_info *di)
+static void rk81x_bat_chrg_over_time_check(struct rk81x_battery *di)
 {
        u8 cvcc_hour;
+       int remain_capacity;
+
+       cvcc_hour = rk81x_bat_get_cvcc_chrg_hour(di);
+       if (di->dsoc < di->rsoc)
+               remain_capacity = di->dsoc * di->fcc / 100;
+       else
+               remain_capacity = di->remain_capacity;
 
-       cvcc_hour = get_cvcc_charge_hour(di);
-       DBG("CHG_TIME(min): %ld, cvcc hour: %d",
-           BASE_TO_MIN(di->chrg_time_base), cvcc_hour);
+       DBG("CHRG_TIME(min): %ld, cvcc hour: %d",
+           BASE_TO_MIN(di->plug_in_base), cvcc_hour);
 
-       if (BASE_TO_MIN(di->chrg_time_base) >= (cvcc_hour-2)*60) {
-               di->chrg_cap2_full = di->fcc - di->remain_capacity;
+       if (BASE_TO_MIN(di->plug_in_base) >= (cvcc_hour - 2) * 60) {
+               di->chrg_cap2full = di->fcc - remain_capacity;
                if (di->current_avg <= 0)
                        di->current_avg = 1;
 
-               di->chrg_time2_full = di->chrg_cap2_full*3600/
-                                       div(abs_int(di->current_avg));
+               di->chrg_time2full = di->chrg_cap2full * 3600 /
+                                       div(abs(di->current_avg));
 
-               DBG("CHG_TIME2FULL(min):%d, chrg_cap2_full=%d, current=%d\n",
-                   SEC_TO_MIN(di->chrg_time2_full), di->chrg_cap2_full,
+               DBG("CHRG_TIME2FULL(min):%d, chrg_cap2full=%d, current=%d\n",
+                   SEC_TO_MIN(di->chrg_time2full), di->chrg_cap2full,
                    di->current_avg);
 
-               if (SEC_TO_MIN(di->chrg_time2_full) > 60) {
-                       rk81x_init_chrg_timer(di);
-                       di->chrg_time_base = get_seconds();
+               if (SEC_TO_MIN(di->chrg_time2full) > 60) {
+                       rk81x_bat_init_chrg_timer(di);
+                       di->plug_in_base = get_runtime_sec();
                        DBG("%s: reset charge timer\n", __func__);
                }
        }
@@ -3224,126 +3484,242 @@ static void rk81x_check_chrg_over_time(struct battery_info *di)
  * in case that we will do reboot stress test, we need a special way
  * to ajust the dsoc.
  */
-static void rk81x_check_reboot(struct battery_info *di)
+static void rk81x_bat_check_reboot(struct rk81x_battery *di)
 {
-       u8 rsoc = di->temp_soc;
-       u8 dsoc = di->real_soc;
-       u8 status = di->status;
+       u8 rsoc = di->rsoc;
+       u8 dsoc = di->dsoc;
+       u8 status = di->psy_status;
        u8 cnt;
        int unit_time;
        int smooth_time;
 
-       battery_read(di->rk818, REBOOT_CNT_REG, &cnt, 1);
+       rk81x_bat_read(di, REBOOT_CNT_REG, &cnt, 1);
        cnt++;
 
-       unit_time = di->fcc*3600/100/1200;/*1200mA default*/
-       smooth_time = cnt*BASE_TO_SEC(di->sys_on_base);
+       unit_time = di->fcc * 3600 / 100 / 1200;/*1200mA default*/
+       smooth_time = cnt * BASE_TO_SEC(di->power_on_base);
 
        DBG("%s: cnt:%d, unit:%d, sm:%d, sec:%lu, dsoc:%d, rsoc:%d\n",
            __func__, cnt, unit_time, smooth_time,
-           BASE_TO_SEC(di->sys_on_base), dsoc, rsoc);
+           BASE_TO_SEC(di->power_on_base), dsoc, rsoc);
 
        if (((status == POWER_SUPPLY_STATUS_CHARGING) ||
-            (status == POWER_SUPPLY_STATUS_FULL)) && (di->current_avg > 0)) {
-               DBG("chrg, sm:%d, aim:%d\n", smooth_time, unit_time*3/5);
-               if ((dsoc < rsoc-1) && (smooth_time > unit_time*3/5)) {
+            (status == POWER_SUPPLY_STATUS_FULL)) &&
+            (abs(di->current_avg) < 5)) {
+               DBG("chrg, sm:%d, aim:%d\n", smooth_time, unit_time * 3 / 5);
+               if ((dsoc < rsoc - 1) && (smooth_time > unit_time * 3 / 5)) {
                        cnt = 0;
                        dsoc++;
                        if (dsoc >= 100)
                                dsoc = 100;
-                       _copy_soc(di, dsoc);
+                       rk81x_bat_save_dsoc(di, dsoc);
                }
        } else {/*status == POWER_SUPPLY_STATUS_DISCHARGING*/
 
-               DBG("dischrg, sm:%d, aim:%d\n", smooth_time, unit_time*3/5);
-               if ((dsoc > rsoc) && (smooth_time > unit_time*3/5)) {
+               DBG("dischrg, sm:%d, aim:%d\n", smooth_time, unit_time * 3/5);
+               if ((dsoc > rsoc) && (smooth_time > unit_time * 3/5)) {
                        cnt = 0;
                        dsoc--;
                        if (dsoc <= 0)
                                dsoc = 0;
-                       _copy_soc(di, dsoc);
+                       rk81x_bat_save_dsoc(di, dsoc);
                }
        }
 
-       copy_reboot_cnt(di, cnt);
+       rk81x_bat_save_reboot_cnt(di, cnt);
+}
+
+static void rk81x_bat_update_calib_param(struct rk81x_battery *di)
+{
+       static u32 old_min;
+       u32 min;
+       int current_offset;
+       uint16_t cal_offset;
+       u8 pcb_offset = DEF_PCB_OFFSET;
+
+       min = BASE_TO_MIN(di->power_on_base);
+       if ((min % 8) && (old_min != min)) {
+               old_min = min;
+               rk81x_bat_get_vol_offset(di);
+               if (di->pcb_ioffset_updated)
+                       rk81x_bat_read(di, PCB_IOFFSET_REG, &pcb_offset, 1);
+
+               current_offset = rk81x_bat_get_ioffset(di);
+               rk81x_bat_set_cal_offset(di, current_offset + pcb_offset);
+               cal_offset = rk81x_bat_get_cal_offset(di);
+               if (cal_offset < 0x7ff)
+                       rk81x_bat_set_cal_offset(di, di->current_offset +
+                                                DEF_PCB_OFFSET);
+               DBG("<%s>. k=%d, b=%d, cal_offset=%d, i_offset=%d\n",
+                   __func__, di->voltage_k, di->voltage_b, cal_offset,
+                   rk81x_bat_get_ioffset(di));
+       }
 }
 
-
-static void rk81x_update_battery_info(struct battery_info *di)
+static void rk81x_bat_update_info(struct rk81x_battery *di)
 {
-       int round_off_dsoc;
+       if (di->dsoc > 100)
+               di->dsoc = 100;
+       else if (di->dsoc < 0)
+               di->dsoc = 0;
+
+       /*
+        * we need update fcc in continuous charging state, if discharge state
+        * keep at least 2 hour, we decide not to update fcc, so clear the
+        * fcc update flag: dod0_status.
+        */
+       if (BASE_TO_MIN(di->plug_out_base) > 120)
+               di->dod0_status = 0;
+
+       di->voltage  = rk81x_bat_get_vol(di);
+       di->current_avg = rk81x_bat_get_avg_current(di);
+       di->chrg_status = rk81x_bat_get_chrg_status(di);
+       di->relax_voltage = rk81x_bat_get_relax_vol(di);
+       di->est_ocv_vol = rk81x_bat_est_ocv_vol(di);
+       di->est_ocv_soc = rk81x_bat_est_ocv_soc(di);
+       rk81x_bat_chrg_over_time_check(di);
+       rk81x_bat_update_calib_param(di);
+       if (di->chrg_status == CC_OR_CV)
+               di->enter_finish = true;
+#if defined(CONFIG_ARCH_ROCKCHIP)
+       rk81x_bat_status_check(di);/* ac_online, usb_online, status*/
+#endif
+
+       if (!rk81x_chrg_online(di) && di->s2r)
+               return;
 
-       di->remain_capacity = _get_realtime_capacity(di);
-       if (di->remain_capacity > di->fcc)
-               _capacity_init(di, di->fcc);
+       di->remain_capacity = rk81x_bat_get_realtime_capacity(di);
+       if (di->remain_capacity > di->fcc) {
+               rk81x_bat_capacity_init(di, di->fcc);
+               rk81x_bat_capacity_init_post(di);
+               di->remain_capacity = di->fcc;
+       }
+
+       di->rsoc = rk81x_bat_get_rsoc(di);
+}
+
+static int rk81x_bat_update_resume_state(struct rk81x_battery *di)
+{
+       if (di->slp_psy_status)
+               return rk81x_bat_sleep_chrg(di);
+       else
+               return rk81x_bat_sleep_dischrg(di);
+}
 
-       if (di->real_soc > 100)
-               di->real_soc = 100;
-       else if (di->real_soc < 0)
-               di->real_soc = 0;
+static void rk81x_bat_fcc_flag_check(struct rk81x_battery *di)
+{
+       u8 ocv_soc, soc_level;
+       int relax_vol = di->relax_voltage;
 
-       if (di->chrg_time_base == 0)
-               di->chrg_time_base = get_seconds();
+       if (relax_vol <= 0)
+               return;
 
-       if (di->sys_on_base == 0)
-               di->sys_on_base = get_seconds();
+       ocv_soc = rk81x_bat_vol_to_capacity(di, relax_vol);
+       DBG("<%s>. ocv_soc=%d, min=%lu, vol=%d\n", __func__,
+           ocv_soc, SEC_TO_MIN(di->suspend_time_sum), relax_vol);
+
+       if ((SEC_TO_MIN(di->suspend_time_sum) > 30) &&
+           (di->dod0_status == 0) &&
+           (ocv_soc <= 10)) {
+               di->dod0_voltage = relax_vol;
+               di->dod0_capacity = di->temp_nac;
+               di->adjust_cap = 0;
+               di->dod0 = ocv_soc;
+
+               if (ocv_soc <= 1)
+                       di->dod0_level = 100;
+               else if (ocv_soc < 5)
+                       di->dod0_level = 90;
+               else
+                       di->dod0_level = 80;
 
-       if (di->status == POWER_SUPPLY_STATUS_DISCHARGING) {
-               di->chrg_time_base = get_seconds();
+               /* save_soc = di->dod0_level; */
+               soc_level = rk81x_bat_get_level(di);
+               if (soc_level >  di->dod0_level) {
+                       di->dod0_status = 0;
+               } else {
+                       di->dod0_status = 1;
+                       /*time start*/
+                       di->fcc_update_sec = get_runtime_sec();
+               }
 
-               /*round off dsoc = 100*/
-               round_off_dsoc = (di->remain_capacity+di->fcc/100/2)*
-                                       100/div(di->fcc);
-               if (round_off_dsoc >= 100 && di->real_soc >= 99)
-                       di->real_soc = 100;
-               DBG("<%s>. round_off_dsoc = %d", __func__, round_off_dsoc);
+               dev_info(di->dev, "resume: relax_vol:%d, dod0_cap:%d\n"
+                        "dod0:%d, soc_level:%d: dod0_status:%d\n"
+                        "dod0_level:%d",
+                        di->dod0_voltage, di->dod0_capacity,
+                        ocv_soc, soc_level, di->dod0_status,
+                        di->dod0_level);
        }
+}
 
-       di->work_on = 1;
-       di->voltage  = _get_battery_voltage(di);
-       di->current_avg = _get_average_current(di);
-       di->remain_capacity = _get_realtime_capacity(di);
-       di->voltage_ocv = _get_OCV_voltage(di);
-       di->charge_status = rk81x_get_charge_status(di);
-       di->relax_voltage = get_relax_voltage(di);
-       di->temp_soc = _get_soc(di);
-       di->est_ocv_vol = estimate_bat_ocv_vol(di);
-       di->est_ocv_soc = estimate_bat_ocv_soc(di);
-       rk81x_check_battery_status(di);/* ac_online, usb_online, status*/
-       rk81x_check_chrg_over_time(di);
-       update_cal_offset(di);
+static void rk81x_chrg_term_mode_set(struct rk81x_battery *di, int mode)
+{
+       u8 buf;
+       u8 mask = 0x20;
+
+       rk81x_bat_read(di, CHRG_CTRL_REG3, &buf, 1);
+       buf &= ~mask;
+       buf |= mode;
+       rk81x_bat_write(di, CHRG_CTRL_REG3, &buf, 1);
+
+       dev_info(di->dev, "set charge to %s termination mode\n",
+                mode ? "digital" : "analog");
+}
+
+static void rk81x_chrg_term_mode_switch_work(struct work_struct *work)
+{
+       struct rk81x_battery *di;
+
+       di = container_of(work, struct rk81x_battery,
+                         chrg_term_mode_switch_work.work);
+
+       if (rk81x_chrg_online(di))
+               rk81x_chrg_term_mode_set(di, CHRG_TERM_DIG_SIGNAL);
+       else
+               rk81x_chrg_term_mode_set(di, CHRG_TERM_ANA_SIGNAL);
 }
 
 static void rk81x_battery_work(struct work_struct *work)
 {
-       struct battery_info *di = container_of(work,
-                       struct battery_info, battery_monitor_work.work);
+       struct rk81x_battery *di;
+       int ms = TIMER_MS_COUNTS;
 
-       update_resume_state(di);
-       wait_charge_finish_signal(di);
-       charge_finish_routine(di);
+       di = container_of(work, struct rk81x_battery,
+                         battery_monitor_work.work);
+       if (rk81x_chrg_online(di)) {
+               rk81x_bat_wait_finish_sig(di);
+               /*rk81x_bat_chrg_finish_routine(di);*/
+       }
+       rk81x_bat_fcc_flag_check(di);
+       rk81x_bat_arbitrate_rsoc_trend(di);
+       rk81x_bat_display_smooth(di);
+       rk81x_bat_update_time(di);
+       rk81x_bat_update_info(di);
+       rk81x_bat_rsoc_check(di);
+       rk81x_bat_power_supply_changed(di);
+       rk81x_bat_save_dsoc(di, di->dsoc);
+       rk81x_bat_save_remain_capacity(di, di->remain_capacity);
+
+       rk81x_bat_dbg_dmp_info(di);
+
+       if (!di->early_resume && di->s2r && !di->slp_psy_status)
+               ms = 30 * TIMER_MS_COUNTS;
+       else
+               di->early_resume = 0;
 
-       rk81x_battery_display_smooth(di);
-       rk81x_update_battery_info(di);
-       rsoc_realtime_calib(di);
-       last_check_report(di);
-       report_power_supply_changed(di);
-       _copy_soc(di, di->real_soc);
-       _save_remain_capacity(di, di->remain_capacity);
+       di->s2r = 0;
 
-       dump_debug_info(di);
-       di->queue_work_cnt++;
        queue_delayed_work(di->wq, &di->battery_monitor_work,
-                          msecs_to_jiffies(TIMER_MS_COUNTS));
+                          msecs_to_jiffies(ms));
 }
 
 static void rk81x_battery_charge_check_work(struct work_struct *work)
 {
-       struct battery_info *di = container_of(work,
-                       struct battery_info, charge_check_work.work);
+       struct rk81x_battery *di = container_of(work,
+                       struct rk81x_battery, charge_check_work.work);
 
        DBG("rk81x_battery_charge_check_work\n");
-       charge_disable_open_otg(di->charge_otg);
+       rk81x_charge_disable_open_otg(di);
 }
 
 static BLOCKING_NOTIFIER_HEAD(battery_chain_head);
@@ -3367,294 +3743,230 @@ int battery_notifier_call_chain(unsigned long val)
 }
 EXPORT_SYMBOL_GPL(battery_notifier_call_chain);
 
-static void poweron_lowerpoer_handle(struct battery_info *di)
+static void poweron_lowerpoer_handle(struct rk81x_battery *di)
 {
 #ifdef CONFIG_LOGO_LOWERPOWER_WARNING
-       if ((di->real_soc <= 2) &&
-           (di->status == POWER_SUPPLY_STATUS_DISCHARGING)) {
+       if ((di->dsoc <= 2) &&
+           (di->psy_status == POWER_SUPPLY_STATUS_DISCHARGING)) {
                mdelay(1500);
                /* kernel_power_off(); */
        }
 #endif
 }
 
-static int battery_notifier_call(struct notifier_block *nb,
-                                unsigned long event, void *data)
+static int rk81x_bat_notifier_call(struct notifier_block *nb,
+                                  unsigned long event, void *data)
 {
-       struct battery_info *di =
-           container_of(nb, struct battery_info, battery_nb);
+       struct rk81x_battery *di =
+           container_of(nb, struct rk81x_battery, battery_nb);
 
        switch (event) {
        case 0:
                DBG(" CHARGE enable\n");
                di->charge_otg = 0;
+               rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, PLUG_IN_INT);
+               rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, PLUG_OUT_INT);
                queue_delayed_work(di->wq, &di->charge_check_work,
                                   msecs_to_jiffies(50));
                break;
-
        case 1:
                di->charge_otg  = 1;
+               rk81x_bat_set_bit(di, NT_STS_MSK_REG2, PLUG_IN_INT);
+               rk81x_bat_set_bit(di, NT_STS_MSK_REG2, PLUG_OUT_INT);
                queue_delayed_work(di->wq, &di->charge_check_work,
                                   msecs_to_jiffies(50));
                DBG("charge disable OTG enable\n");
                break;
-
        case 2:
                poweron_lowerpoer_handle(di);
                break;
-
        default:
                return NOTIFY_OK;
        }
        return NOTIFY_OK;
 }
 
-static irqreturn_t rk818_vbat_lo_irq(int irq, void *di)
+static irqreturn_t rk81x_vbat_lo_irq(int irq, void *bat)
 {
-       pr_info("<%s>lower power warning!\n", __func__);
+       pr_info("\n------- %s:lower power warning!\n", __func__);
 
        rk_send_wakeup_key();
        kernel_power_off();
        return IRQ_HANDLED;
 }
 
-static void disable_vbat_low_irq(struct battery_info *di)
-{
-       /* mask vbat low */
-       rk818_set_bits(di->rk818, 0x4d, (0x1 << 1), (0x1 << 1));
-       /*clr vbat low interrupt */
-       /* rk818_set_bits(di->rk818, 0x4c, (0x1 << 1), (0x1 << 1));*/
-}
-static void enable_vbat_low_irq(struct battery_info *di)
+static irqreturn_t rk81x_vbat_plug_in(int irq, void *bat)
 {
-       /* clr vbat low interrupt */
-       rk818_set_bits(di->rk818, 0x4c, (0x1 << 1), (0x1 << 1));
-       /* mask vbat low */
-       rk818_set_bits(di->rk818, 0x4d, (0x1 << 1), (0x0 << 1));
+       pr_info("\n------- %s:irq = %d\n", __func__, irq);
+       rk_send_wakeup_key();
+       return IRQ_HANDLED;
 }
 
-static irqreturn_t rk818_vbat_plug_in(int irq, void *di)
+static irqreturn_t rk81x_vbat_plug_out(int irq, void  *bat)
 {
-       pr_info("\n------- %s:irq = %d\n", __func__, irq);
-       g_battery->chrg_time_base = get_seconds();
+       pr_info("\n-------- %s:irq = %d\n", __func__, irq);
        rk_send_wakeup_key();
        return IRQ_HANDLED;
 }
-static irqreturn_t rk818_vbat_plug_out(int irq, void  *di)
+
+static irqreturn_t rk81x_vbat_charge_ok(int irq, void  *bat)
 {
-       pr_info("\n-------- %s:irq = %d\n", __func__, irq);
-       charge_disable_open_otg(0);
+       struct rk81x_battery *di = (struct rk81x_battery *)bat;
+
+       pr_info("\n---------- %s:irq = %d\n", __func__, irq);
+       di->finish_sig_base = get_runtime_sec();
        rk_send_wakeup_key();
        return IRQ_HANDLED;
 }
 
-static irqreturn_t rk818_vbat_charge_ok(int irq, void  *di)
+static irqreturn_t rk81x_vbat_dc_det(int irq, void *bat)
 {
-       pr_info("---------- %s:irq = %d\n", __func__, irq);
        rk_send_wakeup_key();
+
        return IRQ_HANDLED;
 }
 
-static int rk81x_battery_sysfs_init(struct battery_info *di, struct device *dev)
+static int rk81x_bat_sysfs_init(struct rk81x_battery *di)
 {
        int ret;
        int i;
-       struct kobject *rk818_fg_kobj;
-
-       ret = create_sysfs_interfaces(dev);
-       if (ret < 0) {
-               ret = -EINVAL;
-               dev_err(dev, "device RK818 battery sysfs register failed\n");
-               goto err_sysfs;
-       }
 
-       rk818_fg_kobj = kobject_create_and_add("rk818_battery", NULL);
-       if (!rk818_fg_kobj)
-               return -ENOMEM;
        for (i = 0; i < ARRAY_SIZE(rk818_bat_attr); i++) {
-               ret = sysfs_create_file(rk818_fg_kobj, &rk818_bat_attr[i].attr);
-               if (ret != 0) {
-                       dev_err(dev, "create rk818_battery node error\n");
-                       goto err_sysfs;
-               }
+               ret = sysfs_create_file(&di->bat.dev->kobj,
+                                       &rk818_bat_attr[i].attr);
+               if (ret != 0)
+                       dev_err(di->dev, "create battery node(%s) error\n",
+                               rk818_bat_attr[i].attr.name);
        }
 
-       return ret;
-
-err_sysfs:
-       power_supply_unregister(&di->ac);
-       power_supply_unregister(&di->usb);
-       power_supply_unregister(&di->bat);
-
        return ret;
 }
 
-static void rk81x_battery_irq_init(struct battery_info *di)
+static void rk81x_bat_irq_init(struct rk81x_battery *di)
 {
-       int plug_in_irq, plug_out_irq, chg_ok_irq, vb_lo_irq;
+       int plug_in_irq, plug_out_irq, chrg_ok_irq, vb_lo_irq;
        int ret;
        struct rk818 *chip = di->rk818;
 
+#if defined(CONFIG_X86_INTEL_SOFIA)
+       vb_lo_irq = chip->irq_base + RK818_IRQ_VB_LO;
+       chrg_ok_irq = chip->irq_base + RK818_IRQ_CHG_OK;
+       plug_in_irq = chip->irq_base + RK818_IRQ_PLUG_IN;
+       plug_out_irq = chip->irq_base + RK818_IRQ_PLUG_OUT;
+#else
        vb_lo_irq = irq_create_mapping(chip->irq_domain, RK818_IRQ_VB_LO);
        plug_in_irq = irq_create_mapping(chip->irq_domain, RK818_IRQ_PLUG_IN);
        plug_out_irq = irq_create_mapping(chip->irq_domain, RK818_IRQ_PLUG_OUT);
-       chg_ok_irq = irq_create_mapping(chip->irq_domain, RK818_IRQ_CHG_OK);
+       chrg_ok_irq = irq_create_mapping(chip->irq_domain, RK818_IRQ_CHG_OK);
+#endif
 
-       ret = request_threaded_irq(vb_lo_irq, NULL, rk818_vbat_lo_irq,
-                                  IRQF_TRIGGER_HIGH, "rk818_vbatlow", chip);
+       ret = request_threaded_irq(vb_lo_irq, NULL, rk81x_vbat_lo_irq,
+                                  IRQF_TRIGGER_HIGH, "rk818_vbatlow", di);
        if (ret != 0)
                dev_err(chip->dev, "vb_lo_irq request failed!\n");
 
        di->irq = vb_lo_irq;
        enable_irq_wake(di->irq);
-       disable_vbat_low_irq(di);
 
-       ret = request_threaded_irq(plug_in_irq, NULL, rk818_vbat_plug_in,
-                                  IRQF_TRIGGER_RISING, "rk818_vbat_plug_in",
-                                  chip);
+       ret = request_threaded_irq(plug_in_irq, NULL, rk81x_vbat_plug_in,
+                                  IRQF_TRIGGER_RISING, "rk81x_vbat_plug_in",
+                                  di);
        if (ret != 0)
                dev_err(chip->dev, "plug_in_irq request failed!\n");
 
-
-       ret = request_threaded_irq(plug_out_irq, NULL, rk818_vbat_plug_out,
-                                  IRQF_TRIGGER_FALLING, "rk818_vbat_plug_out",
-                                  chip);
+       ret = request_threaded_irq(plug_out_irq, NULL, rk81x_vbat_plug_out,
+                                  IRQF_TRIGGER_FALLING, "rk81x_vbat_plug_out",
+                                  di);
        if (ret != 0)
                dev_err(chip->dev, "plug_out_irq request failed!\n");
 
-
-       ret = request_threaded_irq(chg_ok_irq, NULL, rk818_vbat_charge_ok,
-                                  IRQF_TRIGGER_RISING, "rk818_vbat_charge_ok",
-                                  chip);
+       ret = request_threaded_irq(chrg_ok_irq, NULL, rk81x_vbat_charge_ok,
+                                  IRQF_TRIGGER_RISING, "rk81x_vbat_charge_ok",
+                                  di);
        if (ret != 0)
-               dev_err(chip->dev, "chg_ok_irq request failed!\n");
+               dev_err(chip->dev, "chrg_ok_irq request failed!\n");
 }
 
-
-static void rk81x_battery_info_init(struct battery_info *di, struct rk818 *chip)
+static void rk81x_bat_info_init(struct rk81x_battery *di,
+                               struct rk818 *chip)
 {
-       int fcc_capacity;
-       u8 i;
+       unsigned long time_base = get_runtime_sec();
 
-       g_battery = di;
-       di->platform_data = chip->battery_data;
-       di->cell.config = di->platform_data->cell_cfg;
-       di->design_capacity = di->platform_data->cell_cfg->design_capacity;
-       di->qmax = di->platform_data->cell_cfg->design_qmax;
-       di->fcc = di->design_capacity;
-       di->vol_smooth_time = 0;
-       di->charge_smooth_time = 0;
-       di->charge_smooth_status = false;
-       di->sleep_status = 0;
-       di->work_on = 0;
-       di->sys_wakeup = true;
-       di->pcb_ioffset = 0;
-       di->pcb_ioffset_updated = false;
-       di->queue_work_cnt = 0;
-       di->update_k = 0;
-       di->voltage_old = 0;
-       di->display_soc = 0;
-       di->bat_res = 0;
-       di->resume = false;
-       di->sys_wakeup = true;
-       di->status = POWER_SUPPLY_STATUS_DISCHARGING;
-       di->finish_min = 0;
-       di->charge_min = 0;
-       di->discharge_min = 0;
-       di->charging_time = 0;
-       di->discharging_time = 0;
-       di->finish_time = 0;
-       di->q_dead = 0;
-       di->q_err = 0;
-       di->q_shtd = 0;
-       di->odd_capacity = 0;
-       di->bat_res = di->rk818->battery_data->sense_resistor_mohm;
-       di->term_chg_cnt = 0;
-       di->emu_chg_cnt = 0;
-       di->zero_cycle = 0;
-       di->chrg_time_base = 0;
-       di->sys_on_base = 0;
-       di->sum_suspend_cap = 0;
-       di->adjust_cap = 0;
-       di->first_on_cap = 0;
+       di->cell.config = di->pdata->cell_cfg;
+       di->design_capacity = di->pdata->cell_cfg->design_capacity;
+       di->qmax = di->pdata->cell_cfg->design_qmax;
+       di->early_resume = 1;
+       di->psy_status = POWER_SUPPLY_STATUS_DISCHARGING;
+       di->bat_res = di->pdata->sense_resistor_mohm;
        di->fg_drv_mode = FG_NORMAL_MODE;
-
-       for (i = 0; i < 10; i++)
-               di->chrg_min[i] = 0;
-
-       di->debug_finish_real_soc = 0;
-       di->debug_finish_temp_soc = 0;
-
-       fcc_capacity = _get_FCC_capacity(di);
-       if (fcc_capacity > 1000)
-               di->fcc = fcc_capacity;
-       else
-               di->fcc = di->design_capacity;
+       di->dischrg_algorithm_mode = DISCHRG_NORMAL_MODE;
+       di->last_zero_mode_dsoc = DEF_LAST_ZERO_MODE_SOC;
+       di->slp_chrg_status = rk81x_bat_get_chrg_status(di);
+       di->loader_charged = loader_charged;
+       di->chrg_finish_base = time_base;
+       di->power_on_base = time_base;
+       di->plug_in_base = time_base;
+       di->plug_out_base = time_base;
+       di->finish_sig_base = time_base;
+       di->fcc = rk81x_bat_get_fcc(di);
 }
-/*
-static struct of_device_id rk818_battery_of_match[] = {
-{ .compatible = "rk818_battery" },
-{ }
-};
-
-MODULE_DEVICE_TABLE(of, rk818_battery_of_match);
-*/
 
-
-/*
- * dc_det_pullup_inside:
- *
- *  0:  thers is resistance in the pcb to pull the pin up;
- *  1:  there is no resistance in the pcb to pull the pin up.
- *     we have to use inside pullup resistance function,
- *      so we have to define pinctrl info in DTS and analyze it
- */
-static void rk81x_dc_det_init(struct battery_info *di,
-                             struct device_node *np)
+static void rk81x_bat_dc_det_init(struct rk81x_battery *di,
+                                 struct device_node *np)
 {
        struct device *dev = di->dev;
-       struct rk818 *rk818 = di->rk818;
        enum of_gpio_flags flags;
        int ret;
 
-       /*thers is resistance in the pcb to pull the pin up*/
-       if (!di->dc_det_pullup_inside)
-               goto out;
+       di->dc_det_pin = of_get_named_gpio_flags(np, "dc_det_gpio", 0, &flags);
+       if (di->dc_det_pin == -EPROBE_DEFER)
+               dev_err(dev, "dc_det_gpio error\n");
+       if (gpio_is_valid(di->dc_det_pin))
+               di->dc_det_level = (flags & OF_GPIO_ACTIVE_LOW) ?
+                                       RK818_DC_IN : RK818_DC_OUT;
 
-       /*there is no resistance in the pcb to pull the pin up.*/
-       di->pinctrl = devm_pinctrl_get(rk818->dev);
-       if (IS_ERR(di->pinctrl)) {
-               dev_err(dev, "No pinctrl used!\n");
-               return;
-       }
+       di->dc_det_irq = gpio_to_irq(di->dc_det_pin);
+       ret = request_irq(di->dc_det_irq, rk81x_vbat_dc_det,
+                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                         "rk81x_dc_det", NULL);
 
-       /* lookup default state */
-       di->pins_default = pinctrl_lookup_state(di->pinctrl, "default");
-       if (IS_ERR(di->pins_default)) {
-               dev_err(dev, "No default pinctrl found!\n");
-       } else {
-               ret = pinctrl_select_state(di->pinctrl, di->pins_default);
-               if (ret < 0) {
-                       dev_err(dev, "Default pinctrl setting failed!\n");
-               } else {
-out:
-                       di->dc_det_pin = of_get_named_gpio_flags(np,
-                                               "dc_det_gpio", 0, &flags);
-                       if (di->dc_det_pin == -EPROBE_DEFER)
-                               dev_err(dev, "dc_det_gpio error\n");
-                       if (gpio_is_valid(di->dc_det_pin))
-                               di->dc_det_level =
-                                       (flags & OF_GPIO_ACTIVE_LOW) ?
-                                               RK818_DC_IN : RK818_DC_OUT;
-               }
+       if (ret != 0)
+               dev_err(di->dev, "rk818_dc_det_irq request failed!\n");
+       enable_irq_wake(di->dc_det_irq);
+}
+
+static int rk81x_bat_get_suspend_sec(struct rk81x_battery *di)
+{
+       int err;
+       int delta_sec;
+       struct rtc_time tm;
+       struct timespec tv = {
+               .tv_nsec = NSEC_PER_SEC >> 1,
+       };
+       struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+       err = rtc_read_time(rtc, &tm);
+       if (err) {
+               dev_err(rtc->dev.parent,
+                       "hctosys: unable to read the hardware clock\n");
        }
+       err = rtc_valid_tm(&tm);
+       if (err) {
+               dev_err(rtc->dev.parent,
+                       "hctosys: invalid date/time\n");
+       }
+
+       rtc_tm_to_time(&tm, &tv.tv_sec);
+       delta_sec = tv.tv_sec - di->suspend_rtc_base.tv_sec;
+
+       return delta_sec;
 }
 
 #ifdef CONFIG_OF
-static int rk81x_battery_parse_dt(struct battery_info *di)
+static int rk81x_bat_parse_dt(struct rk81x_battery *di)
 {
-       struct device_node *regs, *rk818_pmic_np, *test_np;
-       struct battery_platform_data *data;
+       struct device_node *np;
+       struct battery_platform_data *pdata;
        struct cell_config *cell_cfg;
        struct ocv_config *ocv_cfg;
        struct property *prop;
@@ -3662,147 +3974,117 @@ static int rk81x_battery_parse_dt(struct battery_info *di)
        struct device *dev = di->dev;
        u32 out_value;
        int length, ret;
+       size_t size;
 
-       rk818_pmic_np = of_node_get(rk818->dev->of_node);
-       if (!rk818_pmic_np) {
-               dev_err(dev, "could not find pmic sub-node\n");
-               return -EINVAL;
-       }
-
-       regs = of_find_node_by_name(rk818_pmic_np, "battery");
-       if (!regs) {
+       np = of_find_node_by_name(rk818->dev->of_node, "battery");
+       if (!np) {
                dev_err(dev, "battery node not found!\n");
                return -EINVAL;
        }
 
-       data = devm_kzalloc(rk818->dev, sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(dev, "kzalloc for battery_platform_data failed!\n");
+       pdata = devm_kzalloc(rk818->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
                return -ENOMEM;
-       }
 
        cell_cfg = devm_kzalloc(rk818->dev, sizeof(*cell_cfg), GFP_KERNEL);
-       if (!cell_cfg) {
-               dev_err(dev, "kzalloc for cell_config failed!\n");
+       if (!cell_cfg)
                return -ENOMEM;
-       }
+
        ocv_cfg = devm_kzalloc(rk818->dev, sizeof(*ocv_cfg), GFP_KERNEL);
-       if (!ocv_cfg) {
-               dev_err(dev, "kzalloc for ocv_config failed!\n");
+       if (!ocv_cfg)
                return -ENOMEM;
-       }
 
-       prop = of_find_property(regs, "ocv_table", &length);
+       prop = of_find_property(np, "ocv_table", &length);
        if (!prop) {
                dev_err(dev, "ocv_table not found!\n");
                return -EINVAL;
        }
-       data->ocv_size = length / sizeof(u32);
+       pdata->ocv_size = length / sizeof(u32);
+       if (pdata->ocv_size <= 0) {
+               dev_err(dev, "invalid ocv table\n");
+               return -EINVAL;
+       }
 
-       if (data->ocv_size > 0) {
-               size_t size = sizeof(*data->battery_ocv) * data->ocv_size;
+       size = sizeof(*pdata->battery_ocv) * pdata->ocv_size;
 
-               data->battery_ocv = devm_kzalloc(rk818->dev, size, GFP_KERNEL);
-               if (!data->battery_ocv) {
-                       dev_err(dev, "kzalloc for ocv_table failed!\n");
-                       return -ENOMEM;
-               }
-               ret = of_property_read_u32_array(regs, "ocv_table",
-                                                data->battery_ocv,
-                                                data->ocv_size);
-               if (ret < 0)
-                       return ret;
-       }
+       pdata->battery_ocv = devm_kzalloc(rk818->dev, size, GFP_KERNEL);
+       if (!pdata->battery_ocv)
+               return -ENOMEM;
+
+       ret = of_property_read_u32_array(np, "ocv_table", pdata->battery_ocv,
+                                        pdata->ocv_size);
+       if (ret < 0)
+               return ret;
 
        /******************** charger param  ****************************/
-       ret = of_property_read_u32(regs, "max_charge_currentmA", &out_value);
+       ret = of_property_read_u32(np, "max_chrg_currentmA", &out_value);
        if (ret < 0) {
-               dev_err(dev, "max_charge_currentmA not found!\n");
-               out_value = DEFAULT_ICUR;
+               dev_err(dev, "max_chrg_currentmA not found!\n");
+               out_value = DEFAULT_CHRG_CUR;
        }
-       data->max_charger_currentmA = out_value;
+       pdata->max_charger_currentmA = out_value;
 
-       ret = of_property_read_u32(regs, "max_charge_ilimitmA", &out_value);
+       ret = of_property_read_u32(np, "max_input_currentmA", &out_value);
        if (ret < 0) {
                dev_err(dev, "max_charger_ilimitmA not found!\n");
-               out_value = DEFAULT_ILMT;
+               out_value = DEFAULT_INPUT_CUR;
        }
-       data->max_charger_ilimitmA = out_value;
+       pdata->max_charger_ilimitmA = out_value;
 
-       ret = of_property_read_u32(regs, "bat_res", &out_value);
+       ret = of_property_read_u32(np, "bat_res", &out_value);
        if (ret < 0) {
                dev_err(dev, "bat_res not found!\n");
                out_value = DEFAULT_BAT_RES;
        }
-       data->sense_resistor_mohm = out_value;
+       pdata->sense_resistor_mohm = out_value;
 
-       ret = of_property_read_u32(regs, "max_charge_voltagemV", &out_value);
+       ret = of_property_read_u32(np, "max_charge_voltagemV", &out_value);
        if (ret < 0) {
                dev_err(dev, "max_charge_voltagemV not found!\n");
-               out_value = DEFAULT_VLMT;
+               out_value = DEFAULT_CHRG_VOL;
        }
-       data->max_charger_voltagemV = out_value;
+       pdata->max_charger_voltagemV = out_value;
 
-       ret = of_property_read_u32(regs, "design_capacity", &out_value);
+       ret = of_property_read_u32(np, "design_capacity", &out_value);
        if (ret < 0) {
                dev_err(dev, "design_capacity not found!\n");
                return ret;
        }
        cell_cfg->design_capacity  = out_value;
 
-       ret = of_property_read_u32(regs, "design_qmax", &out_value);
+       ret = of_property_read_u32(np, "design_qmax", &out_value);
        if (ret < 0) {
                dev_err(dev, "design_qmax not found!\n");
                return ret;
        }
        cell_cfg->design_qmax = out_value;
 
-       ret = of_property_read_u32(regs, "sleep_enter_current", &out_value);
+       ret = of_property_read_u32(np, "sleep_enter_current", &out_value);
        if (ret < 0) {
                dev_err(dev, "sleep_enter_current not found!\n");
-               return ret;
+               out_value = DEFAULT_SLP_ENTER_CUR;
        }
        ocv_cfg->sleep_enter_current = out_value;
 
-       ret = of_property_read_u32(regs, "sleep_exit_current", &out_value);
+       ret = of_property_read_u32(np, "sleep_exit_current", &out_value);
        if (ret < 0) {
                dev_err(dev, "sleep_exit_current not found!\n");
-               return ret;
+               out_value = DEFAULT_SLP_EXIT_CUR;
        }
        ocv_cfg->sleep_exit_current = out_value;
 
-       /********************  test power param ****************************/
-       test_np = of_find_node_by_name(regs, "test_power");
-       if (!regs) {
-               dev_err(dev, "test-power node not found!\n");
-               di->test_chrg_current = DEF_TEST_CURRENT_MA;
-               di->test_chrg_ilmt = DEF_TEST_ILMT_MA;
-       } else {
-               ret = of_property_read_u32(test_np, "test_charge_currentmA",
-                                          &out_value);
-               if (ret < 0) {
-                       dev_err(dev, "test_charge_currentmA not found!\n");
-                       out_value = DEF_TEST_CURRENT_MA;
-               }
-               di->test_chrg_current = out_value;
-
-               ret = of_property_read_u32(test_np, "test_charge_ilimitmA",
-                                          &out_value);
-               if (ret < 0) {
-                       dev_err(dev, "test_charge_ilimitmA not found!\n");
-                       out_value = DEF_TEST_ILMT_MA;
-               }
-               di->test_chrg_ilmt = out_value;
+       ret = of_property_read_u32(np, "power_off_thresd", &out_value);
+       if (ret < 0) {
+               dev_warn(dev, "power_off_thresd not found!\n");
+               out_value = PWR_OFF_THRESD;
        }
+       pdata->power_off_thresd = out_value;
+
+       of_property_read_u32(np, "chrg_diff_voltagemV", &pdata->chrg_diff_vol);
 
        /*************  charger support adp types **********************/
-       ret = of_property_read_u32(regs, "support_uboot_chrg", &support_uboot_chrg);
-       ret = of_property_read_u32(regs, "support_usb_adp", &support_usb_adp);
-       ret = of_property_read_u32(regs, "support_dc_adp", &support_dc_adp);
-       ret = of_property_read_u32(regs, "dc_det_pullup_inside", &out_value);
-       if (ret < 0)
-               out_value = 0;
-       di->dc_det_pullup_inside = out_value;
+       ret = of_property_read_u32(np, "support_usb_adp", &support_usb_adp);
+       ret = of_property_read_u32(np, "support_dc_adp", &support_dc_adp);
 
        if (!support_usb_adp && !support_dc_adp) {
                dev_err(dev, "miss both: usb_adp and dc_adp,default:usb_adp!\n");
@@ -3810,163 +4092,220 @@ static int rk81x_battery_parse_dt(struct battery_info *di)
        }
 
        if (support_dc_adp)
-               rk81x_dc_det_init(di, regs);
+               rk81x_bat_dc_det_init(di, np);
 
        cell_cfg->ocv = ocv_cfg;
-       data->cell_cfg = cell_cfg;
-       rk818->battery_data = data;
-
-       DBG("\n--------- the battery OCV TABLE dump:\n");
-       DBG("bat_res :%d\n", data->sense_resistor_mohm);
-       DBG("max_charge_ilimitmA :%d\n", data->max_charger_ilimitmA);
-       DBG("max_charge_currentmA :%d\n", data->max_charger_currentmA);
-       DBG("max_charge_voltagemV :%d\n", data->max_charger_voltagemV);
-       DBG("design_capacity :%d\n", cell_cfg->design_capacity);
-       DBG("design_qmax :%d\n", cell_cfg->design_qmax);
-       DBG("sleep_enter_current :%d\n", cell_cfg->ocv->sleep_enter_current);
-       DBG("sleep_exit_current :%d\n", cell_cfg->ocv->sleep_exit_current);
-       DBG("support_uboot_chrg = %d\n", support_uboot_chrg);
-       DBG("support_usb_adp = %d\n", support_usb_adp);
-       DBG("support_dc_adp= %d\n", support_dc_adp);
-       DBG("test_charge_currentmA = %d\n", di->test_chrg_current);
-       DBG("test_charge_ilimitmA = %d\n", di->test_chrg_ilmt);
-       DBG("dc_det_pullup_inside = %d\n", di->dc_det_pullup_inside);
-       DBG("--------- rk818_battery dt_parse ok.\n");
+       pdata->cell_cfg = cell_cfg;
+       di->pdata = pdata;
+
+       DBG("\nthe battery dts info dump:\n"
+           "bat_res:%d\n"
+           "max_input_currentmA:%d\n"
+           "max_chrg_currentmA:%d\n"
+           "max_charge_voltagemV:%d\n"
+           "design_capacity:%d\n"
+           "design_qmax :%d\n"
+           "sleep_enter_current:%d\n"
+           "sleep_exit_current:%d\n"
+           "support_usb_adp:%d\n"
+           "support_dc_adp:%d\n"
+           "power_off_thresd:%d\n",
+           pdata->sense_resistor_mohm, pdata->max_charger_ilimitmA,
+           pdata->max_charger_currentmA, pdata->max_charger_voltagemV,
+           cell_cfg->design_capacity, cell_cfg->design_qmax,
+           cell_cfg->ocv->sleep_enter_current,
+           cell_cfg->ocv->sleep_exit_current,
+           support_usb_adp, support_dc_adp, pdata->power_off_thresd);
+
        return 0;
 }
 
 #else
-static int rk81x_battery_parse_dt(struct battery_info *di)
+static int rk81x_bat_parse_dt(struct rk81x_battery *di)
 {
        return -ENODEV;
 }
 #endif
 
-
 static int rk81x_battery_probe(struct platform_device *pdev)
 {
        struct rk818 *chip = dev_get_drvdata(pdev->dev.parent);
-       struct battery_info *di;
+       struct rk81x_battery *di;
        int ret;
 
-       DBG("battery driver version %s\n", DRIVER_VERSION);
        di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
-       if (!di) {
-               dev_err(&pdev->dev, "kzalloc di failed!\n");
+       if (!di)
                return -ENOMEM;
-       }
        di->rk818 = chip;
        di->dev = &pdev->dev;
        platform_set_drvdata(pdev, di);
 
-       ret = rk81x_battery_parse_dt(di);
+       ret = rk81x_bat_parse_dt(di);
        if (ret < 0) {
                dev_err(&pdev->dev, "rk81x battery parse dt failed!\n");
                return ret;
        }
-       rk81x_battery_info_init(di, chip);
+
+       rk81x_bat_info_init(di, chip);
        if (!is_rk81x_bat_exist(di)) {
-               pr_info("not find Li-ion battery, test power mode\n");
-               rk81x_battery_charger_init(di);
+               dev_info(di->dev, "not battery, enter test power mode\n");
                di->fg_drv_mode = TEST_POWER_MODE;
        }
 
-       battery_power_supply_init(di);
-       ret = battery_power_supply_register(di);
+       ret = rk81x_bat_power_supply_init(di);
        if (ret) {
                dev_err(&pdev->dev, "rk81x power supply register failed!\n");
                return ret;
        }
 
-       rk81x_battery_irq_init(di);
-       rk81x_battery_sysfs_init(di, &pdev->dev);
+       rk81x_bat_irq_init(di);
+       rk81x_bat_sysfs_init(di);
 
-       rk81x_fg_init(di);
+       rk81x_bat_fg_init(di);
        wake_lock_init(&di->resume_wake_lock, WAKE_LOCK_SUSPEND,
                       "resume_charging");
-       flatzone_voltage_init(di);
-       rk81x_check_battery_status(di);
+       rk81x_bat_flatzone_vol_init(di);
+
+#if defined(CONFIG_X86_INTEL_SOFIA)
+       di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
+       if (IS_ERR_OR_NULL(di->usb_phy)) {
+               dev_err(di->dev, "get usb phy failed\n");
+               return PTR_ERR(di->usb_phy);
+       }
+       di->usb_nb.notifier_call = rk81x_battery_usb_notifier;
+       ret = usb_register_notifier(di->usb_phy, &di->usb_nb);
+       if (ret)
+               dev_err(di->dev, "registr usb phy notification failed\n");
+       INIT_DELAYED_WORK(&di->usb_phy_delay_work,
+                         rk81x_battery_usb_notifier_delayed_work);
+#endif
 
-       di->wq = create_singlethread_workqueue("rk81x-battery-work");
+       rk81x_battery_register_fb_notify(di);
+       di->wq = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM | WQ_FREEZABLE,
+                                        "rk81x-battery-work");
        INIT_DELAYED_WORK(&di->battery_monitor_work, rk81x_battery_work);
+       INIT_DELAYED_WORK(&di->chrg_term_mode_switch_work,
+                         rk81x_chrg_term_mode_switch_work);
+
        queue_delayed_work(di->wq, &di->battery_monitor_work,
-                          msecs_to_jiffies(TIMER_MS_COUNTS*5));
+                          msecs_to_jiffies(TIMER_MS_COUNTS * 5));
+
        INIT_DELAYED_WORK(&di->charge_check_work,
                          rk81x_battery_charge_check_work);
-       di->battery_nb.notifier_call = battery_notifier_call;
+       di->battery_nb.notifier_call = rk81x_bat_notifier_call;
        register_battery_notifier(&di->battery_nb);
 
-       DBG("rk81x battery probe ok!\n");
+       dev_info(di->dev, "battery driver version %s\n", DRIVER_VERSION);
 
        return ret;
 }
 
-
-#ifdef CONFIG_PM
-
 static int rk81x_battery_suspend(struct platform_device *dev,
                                 pm_message_t state)
 {
-       struct battery_info *di = platform_get_drvdata(dev);
+       struct rk81x_battery *di = platform_get_drvdata(dev);
 
-       enable_vbat_low_irq(di);
-       di->sleep_status = di->status;
+       di->slp_psy_status = rk81x_chrg_online(di);
 
-       /* avoid abrupt wakeup which will clean the variable*/
-       if (di->sys_wakeup) {
-               di->suspend_cap = di->remain_capacity;
-               di->suspend_rsoc = _get_soc(di);
-               di->suspend_time_start = get_seconds();
-               di->sys_wakeup = false;
+       di->chrg_status = rk81x_bat_get_chrg_status(di);
+       di->slp_chrg_status = rk81x_bat_get_chrg_status(di);
+       di->suspend_charge_current = rk81x_bat_get_avg_current(di);
+       di->dischrg_save_sec += rk81x_bat_save_dischrg_sec(di);
+       di->dischrg_normal_base = 0;
+       di->dischrg_emu_base = 0;
+       do_gettimeofday(&di->suspend_rtc_base);
+       /*
+        * do not modify the g_base_sec
+        */
+       g_base_sec = BASE_TO_SEC(di->power_on_base)+di->power_on_base;
+
+       if (!rk81x_chrg_online(di)) {
+               di->chrg_save_sec += rk81x_bat_save_chrg_sec(di);
+               di->chrg_normal_base = 0;
+               di->chrg_emu_base = 0;
+               di->chrg_term_base = 0;
+               di->chrg_finish_base = 0;
        }
 
-       pr_info("rk81x-battery suspend: v=%d ld=%d lr=%d c=%d chg=%d\n",
-               _get_battery_voltage(di), di->real_soc, _get_soc(di),
-               _get_average_current(di), di->status);
-
-       cancel_delayed_work(&di->battery_monitor_work);
+       di->s2r = 0;
 
        return 0;
 }
 
 static int rk81x_battery_resume(struct platform_device *dev)
 {
-       struct battery_info *di = platform_get_drvdata(dev);
+       struct rk81x_battery *di = platform_get_drvdata(dev);
+       int pwroff_thresd = di->pdata->power_off_thresd;
+       int delta_time;
+       int time_step;
+       int delta_soc;
 
-       di->resume = true;
-       disable_vbat_low_irq(di);
-       queue_delayed_work(di->wq, &di->battery_monitor_work,
-                          msecs_to_jiffies(TIMER_MS_COUNTS/2));
+       di->discharge_smooth_status = true;
+       di->charge_smooth_status = true;
+       di->s2r = 1;
+       di->voltage  = rk81x_bat_get_vol(di);
+       di->current_avg = rk81x_bat_get_avg_current(di);
+       di->relax_voltage = rk81x_bat_get_relax_vol(di);
+       di->est_ocv_vol = rk81x_bat_est_ocv_vol(di);
+       di->est_ocv_soc = rk81x_bat_est_ocv_soc(di);
+       delta_time = rk81x_bat_get_suspend_sec(di);
+       di->suspend_time_sum += delta_time;
+
+       /*
+        * do not modify the g_base_sec
+        */
+       if (is_local_clock_reset())
+               g_base_sec += delta_time;
+       else
+               g_base_sec = 0;
+
+       if (di->slp_psy_status) {
+               time_step = CHRG_TIME_STEP;
+       } else {
+               if (di->voltage <= pwroff_thresd + 50)
+                       time_step = DISCHRG_TIME_STEP_0;
+               else
+                       time_step = DISCHRG_TIME_STEP_1;
+       }
+
+       if (di->suspend_time_sum > time_step) {
+               delta_soc = rk81x_bat_update_resume_state(di);
+               if (delta_soc)
+                       di->suspend_time_sum = 0;
+       }
 
-       if (di->sleep_status == POWER_SUPPLY_STATUS_CHARGING ||
-           di->real_soc <= 5)
-               wake_lock_timeout(&di->resume_wake_lock, 5*HZ);
+       if ((!rk81x_chrg_online(di) && di->voltage <= pwroff_thresd) ||
+           rk81x_chrg_online(di))
+               wake_lock_timeout(&di->resume_wake_lock, 5 * HZ);
+
+       DBG("<%s>. current:%d, est_ocv_vol:%d, delta_time:%d, vol:%d\n"
+           "relax-vol:%d, suspend_time:%ld, online:%d, resume_sec:%lld\n",
+           __func__, di->current_avg, di->est_ocv_vol, delta_time,
+           di->voltage, di->relax_voltage, di->suspend_time_sum,
+           di->slp_psy_status, get_runtime_sec());
 
-       pr_info("rk81x-battery resume: v=%d  rv=%d ld=%d lr=%d c=%d chg=%d\n",
-               _get_battery_voltage(di), get_relax_voltage(di),
-               di->real_soc, _get_soc(di), _get_average_current(di),
-               di->status);
        return 0;
 }
+
 static int rk81x_battery_remove(struct platform_device *dev)
 {
-       struct battery_info *di = platform_get_drvdata(dev);
+       struct rk81x_battery *di = platform_get_drvdata(dev);
 
        cancel_delayed_work_sync(&di->battery_monitor_work);
        return 0;
 }
+
 static void rk81x_battery_shutdown(struct platform_device *dev)
 {
-       struct battery_info *di = platform_get_drvdata(dev);
+       struct rk81x_battery *di = platform_get_drvdata(dev);
 
        cancel_delayed_work_sync(&di->battery_monitor_work);
-       if (BASE_TO_MIN(di->sys_on_base) <= REBOOT_INTER_MIN)
-               rk81x_check_reboot(di);
+       if (BASE_TO_MIN(di->power_on_base) <= REBOOT_INTER_MIN)
+               rk81x_bat_check_reboot(di);
        else
-               copy_reboot_cnt(di, 0);
-       DBG("rk818 shutdown!");
+               rk81x_bat_save_reboot_cnt(di, 0);
+       rk81x_chrg_term_mode_set(di, CHRG_TERM_ANA_SIGNAL);
 }
-#endif
 
 static struct platform_driver rk81x_battery_driver = {
        .driver     = {
diff --git a/drivers/power/rk818_battery.h b/drivers/power/rk818_battery.h
new file mode 100644 (file)
index 0000000..7e358d6
--- /dev/null
@@ -0,0 +1,682 @@
+/*
+*rk818-battery.h - Battery fuel gauge driver structures
+ *
+ */
+#ifndef RK818_BATTERY
+#define  RK818_BATTERY
+
+#define VB_MOD_REG                                     0x21
+#define THERMAL_REG                                    0x22
+#define NT_STS_MSK_REG2                                0x4f
+#define DCDC_ILMAX_REG                         0x90
+#define CHRG_COMP_REG1                         0x99
+#define CHRG_COMP_REG2                         0x9A
+#define SUP_STS_REG                                    0xA0
+#define USB_CTRL_REG                           0xA1
+#define CHRG_CTRL_REG1                         0xA3
+#define CHRG_CTRL_REG2                         0xA4
+#define CHRG_CTRL_REG3                         0xA5
+#define BAT_CTRL_REG                           0xA6
+#define BAT_HTS_TS1_REG                        0xA8
+#define BAT_LTS_TS1_REG                        0xA9
+#define BAT_HTS_TS2_REG                        0xAA
+#define BAT_LTS_TS2_REG                        0xAB
+
+
+#define TS_CTRL_REG                                    0xAC
+#define ADC_CTRL_REG                           0xAD
+
+#define ON_SOURCE                                      0xAE
+#define OFF_SOURCE                                     0xAF
+
+#define GGCON                                          0xB0
+#define GGSTS                                          0xB1
+#define FRAME_SMP_INTERV_REG           0xB2
+#define AUTO_SLP_CUR_THR_REG           0xB3
+
+#define GASCNT_CAL_REG3                        0xB4
+#define GASCNT_CAL_REG2                        0xB5
+#define GASCNT_CAL_REG1                        0xB6
+#define GASCNT_CAL_REG0                        0xB7
+#define GASCNT3                                                0xB8
+#define GASCNT2                                                0xB9
+#define GASCNT1                                                0xBA
+#define GASCNT0                                                0xBB
+
+#define BAT_CUR_AVG_REGH                       0xBC
+#define BAT_CUR_AVG_REGL                       0xBD
+
+#define TS1_ADC_REGH                           0xBE
+#define TS1_ADC_REGL                           0xBF
+#define TS2_ADC_REGH                           0xC0
+#define TS2_ADC_REGL                           0xC1
+
+#define BAT_OCV_REGH                           0xC2
+#define BAT_OCV_REGL                           0xC3
+#define BAT_VOL_REGH                           0xC4
+#define BAT_VOL_REGL                           0xC5
+
+#define RELAX_ENTRY_THRES_REGH 0xC6
+#define RELAX_ENTRY_THRES_REGL 0xC7
+#define RELAX_EXIT_THRES_REGH          0xC8
+#define RELAX_EXIT_THRES_REGL          0xC9
+
+#define RELAX_VOL1_REGH                        0xCA
+#define RELAX_VOL1_REGL                        0xCB
+#define RELAX_VOL2_REGH                        0xCC
+#define RELAX_VOL2_REGL                        0xCD
+
+#define BAT_CUR_R_CALC_REGH            0xCE
+#define BAT_CUR_R_CALC_REGL            0xCF
+#define BAT_VOL_R_CALC_REGH            0xD0
+#define BAT_VOL_R_CALC_REGL            0xD1
+
+#define CAL_OFFSET_REGH                        0xD2
+#define CAL_OFFSET_REGL                        0xD3
+
+#define NON_ACT_TIMER_CNT_REG  0xD4
+
+#define VCALIB0_REGH                           0xD5
+#define VCALIB0_REGL                           0xD6
+#define VCALIB1_REGH                           0xD7
+#define VCALIB1_REGL                           0xD8
+
+#define IOFFSET_REGH                           0xDD
+#define IOFFSET_REGL                           0xDE
+
+
+/*0xE0 ~0xF2  data register,*/
+#define  SOC_REG                                               0xE0
+
+#define  REMAIN_CAP_REG3                       0xE1
+#define  REMAIN_CAP_REG2                       0xE2
+#define  REMAIN_CAP_REG1                       0xE3
+#define  REMAIN_CAP_REG0                       0xE4
+
+#define UPDAT_LEVE_REG                         0xE5
+
+#define  NEW_FCC_REG3                          0xE6
+#define  NEW_FCC_REG2                          0xE7
+#define  NEW_FCC_REG1                          0xE8
+#define  NEW_FCC_REG0                          0xE9
+
+#define NON_ACT_TIMER_CNT_REG_SAVE             0xEA
+#define OCV_VOL_VALID_REG                      0xEB
+#define REBOOT_CNT_REG                         0xEC
+#define PCB_IOFFSET_REG                                0xED
+#define MISC_MARK_REG                          0xEE
+
+#define PLUG_IN_INT                            (0)
+#define PLUG_OUT_INT                           (1)
+
+/* gasgauge module enable bit 0: disable  1:enabsle
+TS_CTRL_REG  0xAC*/
+#define GG_EN                                          (1<<7)
+
+/*ADC_CTRL_REG*/
+/*
+if GG_EN = 0 , then the ADC of BAT voltage controlled by the
+bit 0:diabsle 1:enable
+*/
+#define ADC_VOL_EN                                     (1<<7)
+/*
+if GG_EN = 0, then the ADC of BAT current controlled by the
+bit  0: disable 1: enable
+*/
+#define ADC_CUR_EN                                     (1<<6)
+/*the ADC of TS1 controlled by the bit 0:disabsle 1:enable */
+#define ADC_TS1_EN                                     (1<<5)
+/*the ADC of TS2 controlled by the bit 0:disabsle 1:enable */
+#define ADC_TS2_EN                                     (1<<4)
+/*ADC colock phase  0:normal 1:inverted*/
+#define ADC_PHASE                                      (1<<3)
+#define ADC_CLK_SEL                                    7
+/*****************************************************
+#define ADC_CLK_SEL_2M                         0x000
+#define ADC_CLK_SEL_1M                         0x001
+#define ADC_CLK_SEL_500K                       0x002
+#define ADC_CLK_SEL_250K                       0x003
+#define ADC_CLK_SEL_125K                       0x004
+******************************************************/
+/*GGCON*/
+/* ADC bat current continue sample times  00:8  01:16 10:32 11:64*/
+#define CUR_SAMPL_CON_TIMES            (3<<6)
+/*ADC offset calibreation interval time 00:8min 01:16min 10:32min 11:48min*/
+#define ADC_OFF_CAL_INTERV                     (3<<4)
+/*OCV sampling interval time 00:8min 01:16min 10:32min :11:48min*/
+#define OCV_SAMPL_INTERV                       (3<<2)
+
+/*ADC working in current voltage collection mode*/
+#define ADC_CUR_VOL_MODE                       (1<<1)
+/*ADC working in resistor calculation mode 0:disable 1:enable*/
+#define ADC_RES_MODE                           1
+
+/*GGSTS*/
+/*average current filter times 00:1/2  01:1/4 10:1/8 11:1/16*/
+#define RES_CUR_AVG_SEL                                (3<<5)
+/*battery first connection,edge trigger 0:NOT  1:YES*/
+#define BAT_CON                                                (1<<4)
+/*battery voltage1 update in relax status 0: NOT 1:YE*/
+#define RELAX_VOL1_UPD                         (1<<3)
+/*battery voltage2 update in relax status 0: NOT 1:YE*/
+#define RELAX_VOL2_UPD                         (1<<2)
+/*battery coming into relax status  0: NOT 1:YE*/
+#define RELAX_STS                                      (1<<1)
+/*battery average voltage and current updated status 0: NOT 1:YES*/
+#define IV_AVG_UPD_STS                         (1<<0)
+
+/*FRAME_SMP_INTERV_REG*/
+#define AUTO_SLP_EN                                    (1<<5)
+/* auto sleep mode 0:disable 1:enable*/
+#define FRAME_SMP_INTERV_TIME          0x1F
+
+/*VB_MOD_REG*/
+#define PLUG_IN_STS                                    (1<<6)
+
+/*SUP_STS_REG*/
+#define BAT_EXS                                                (1<<7)
+#define CHARGE_OFF                                     (0x00<<4)
+#define DEAD_CHARGE                                    (0x01<<4)
+#define TRICKLE_CHARGE                         (0x02<<4)
+#define CC_OR_CV                                               (0x03<<4)
+#define CHARGE_FINISH                          (0x04<<4)
+#define USB_OVER_VOL                           (0x05<<4)
+#define BAT_TMP_ERR                                    (0x06<<4)
+#define TIMER_ERR                                      (0x07<<4)
+/* usb is exists*/
+#define USB_EXIST                                      (1<<1)
+/* usb is effective*/
+#define USB_EFF                                                (1<<0)
+
+/*USB_CTRL_REG*/
+#define CHRG_CT_EN                                     (1<<7)
+/* USB_VLIM_SEL*/
+/*
+#define VLIM_4000MV                                    (0x00<<4)
+#define VLIM_4100MV                                    (0x01<<4)
+#define VLIM_4200MV                                    (0x02<<4)
+#define VLIM_4300MV                                    (0x03<<4)
+#define VLIM_4400MV                                    (0x04<<4)
+#define VLIM_4500MV                                    (0x05<<4)
+#define VLIM_4600MV                                    (0x06<<4)
+#define VLIM_4700MV                                    (0x07<<4)
+*/
+
+/*USB_ILIM_SEL*/
+#define ILIM_450MA                                     (0x00)
+#define ILIM_800MA                                     (0x01)
+#define ILIM_850MA                                     (0x02)
+#define ILIM_1000MA                                    (0x03)
+#define ILIM_1250MA                                    (0x04)
+#define ILIM_1500MA                                    (0x05)
+#define ILIM_1750MA                                    (0x06)
+#define ILIM_2000MA                                    (0x07)
+#define ILIM_2250MA                                    (0x08)
+#define ILIM_2500MA                                    (0x09)
+#define ILIM_2750MA                                    (0x0A)
+#define ILIM_3000MA                                    (0x0B)
+
+
+/*CHRG_CTRL_REG*/
+#define CHRG_EN                                                (0x01<<7)
+
+/*CHRG_VOL_SEL*/
+#define CHRG_VOL4050                           (0x00<<4)
+#define CHRG_VOL4100                           (0x01<<4)
+#define CHRG_VOL4150                           (0x02<<4)
+#define CHRG_VOL4200                           (0x03<<4)
+#define CHRG_VOL4300                           (0x04<<4)
+#define CHRG_VOL4350                           (0x05<<4)
+
+/*CHRG_CUR_SEL*/
+#define CHRG_CUR1000mA                 (0x00)
+#define CHRG_CUR1200mA                 (0x01)
+#define CHRG_CUR1400mA                 (0x02)
+#define CHRG_CUR1600mA                 (0x03)
+#define CHRG_CUR1800mA                 (0x04)
+#define CHRG_CUR2000mA                 (0x05)
+#define CHRG_CUR2200mA                 (0x06)
+#define CHRG_CUR2400mA                 (0x07)
+#define CHRG_CUR2600mA                 (0x08)
+#define CHRG_CUR2800mA                 (0x09)
+#define CHRG_CUR3000mA                 (0x0A)
+
+/*CHRG_CTRL_REG2*/
+#define FINISH_100MA                           (0x00<<6)
+#define FINISH_150MA                           (0x01<<6)
+#define FINISH_200MA                           (0x02<<6)
+#define FINISH_250MA                           (0x03<<6)
+
+/*temp feed back degree*/
+#define TEMP_85C                       (0x00 << 2)
+#define TEMP_95C                       (0x01 << 2)
+#define TEMP_105C                      (0x02 << 2)
+#define TEMP_115C                      (0x03 << 2)
+
+
+/* CHRG_CTRL_REG3*/
+#define CHRG_TERM_ANA_SIGNAL           (0 << 5)
+#define CHRG_TERM_DIG_SIGNAL           (1 << 5)
+#define CHRG_TIMER_CCCV_EN             (1 << 2)
+
+/*CHRG_CTRL_REG2*/
+#define CHG_CCCV_4HOUR                 (0x00)
+#define CHG_CCCV_5HOUR                 (0x01)
+#define CHG_CCCV_6HOUR                 (0x02)
+#define CHG_CCCV_8HOUR                 (0x03)
+#define CHG_CCCV_10HOUR                        (0x04)
+#define CHG_CCCV_12HOUR                        (0x05)
+#define CHG_CCCV_14HOUR                        (0x06)
+#define CHG_CCCV_16HOUR                        (0x07)
+
+/*GGCON*/
+#define SAMP_TIME_8MIN                         (0X00<<4)
+#define SAMP_TIME_16MIN                                (0X01<<4)
+#define SAMP_TIME_32MIN                                (0X02<<4)
+#define SAMP_TIME_48MIN                                (0X03<<4)
+
+#define ADC_CURRENT_MODE                       (1 << 1)
+#define ADC_VOLTAGE_MODE                       (0 << 1)
+
+#define DRIVER_VERSION                         "4.0.0"
+#define ROLEX_SPEED                                    (100 * 1000)
+
+#define CHARGING                                       0x01
+#define DISCHARGING                                    0x00
+
+#define TIMER_MS_COUNTS                        1000
+#define MAX_CHAR                                       0x7F
+#define MAX_UNSIGNED_CHAR                      0xFF
+#define MAX_INT                                                0x7FFF
+#define MAX_UNSIGNED_INT                       0xFFFF
+#define MAX_INT8                                       0x7F
+#define MAX_UINT8                                      0xFF
+
+/* Gas Gauge Constatnts */
+#define TEMP_0C                        2732
+#define MAX_CAPACITY           0x7fff
+#define MAX_SOC                        100
+#define MAX_PERCENTAGE         100
+
+/* Num, cycles with no Learning, after this many cycles, the gauge
+   start adjusting FCC, based on Estimated Cell Degradation */
+#define NO_LEARNING_CYCLES     25
+/* Size of the OCV Lookup table */
+#define OCV_TABLE_SIZE         21
+/*
+ * OCV Config
+ */
+struct ocv_config {
+       /*voltage_diff, current_diff: Maximal allowed deviation
+       of the voltage and the current from one reading to the
+       next that allows the fuel gauge to apply an OCV correction.
+       The main purpose of these thresholds is to filter current
+       and voltage spikes. Recommended value: these value are
+       highly depend on the load nature. if the load creates a lot
+       of current spikes .the value may need to be increase*/
+       uint8_t voltage_diff;
+       uint8_t current_diff;
+       /* sleep_enter_current: if the current remains under
+       this threshold for [sleep_enter_samples]
+       consecutive samples. the gauge enters the SLEEP MODE*/
+       uint16_t sleep_enter_current;
+       /*sleep_enter_samples: the number of samples that
+       satis fy asleep enter or exit condition in order
+       to actually enter of exit SLEEP mode*/
+       uint8_t sleep_enter_samples;
+       /*sleep_exit_samples: to exit SLEEP mode , average
+       current should pass this threshold first. then
+       current should remain above this threshold for
+       [sleep_exit_samples] consecutive samples*/
+       uint16_t sleep_exit_current;
+       /*sleep_exit_samples: to exit SLEEP mode, average
+       current should pass this threshold first, then current
+       should remain above this threshold for [sleep_exit_samples]
+       consecutive samples.*/
+       uint8_t sleep_exit_samples;
+       /*relax_period: defines the number of seconds the
+       fuel gauge should spend in the SLEEP mode
+       before entering the OCV mode, this setting makes
+       the gauge wait for a cell voltage recovery after
+       a charge or discharge operation*/
+       uint16_t relax_period;
+       /* flat_zone_low : flat_zone_high :if soc falls into
+       the flat zone low% - flat zone high %.the fuel gauge
+       wait for a cell voltage recovery after a charge or
+       discharge operation.*/
+       uint8_t flat_zone_low;
+       uint8_t flat_zone_high;
+       /*FCC leaning is disqualified if the discharge capacity
+       in the OCV mode is greater than this threshold*/
+       uint16_t max_ocv_discharge;
+       /*the 21-point OCV table*/
+       uint16_t table[OCV_TABLE_SIZE];
+       /*uint16_t *table;*/
+};
+
+/* EDV Point */
+struct edv_point {
+       int16_t voltage;
+       uint8_t percent;
+};
+
+/* EDV Point tracking data */
+struct edv_state {
+       int16_t voltage;
+       uint8_t percent;
+       int16_t min_capacity;
+       uint8_t edv_cmp;
+};
+
+/* EDV Configuration */
+struct edv_config {
+       /*avieraging: True = evokes averaging on voltage
+       reading to detect an EDV condition.
+       False = no averaging of voltage readings to detect an
+       EDV conditation.*/
+       bool averaging;
+       /*sequential_edv: the sequential_edv setting defines
+       how many times in a row the battery should
+       pass the EDV threshold to detect an EDV condition.
+       this setting is intended to fiter short voltage spikes
+       cause by current spikes*/
+       uint8_t sequential_edv;
+       /*filter_light: difine the calculated EDV voltage
+       recovery IIR filter strength
+       light-lsetting : for light load (below Qmax/5)
+       heavy setting : for ligh load (above Qmax/5)
+       the filter is applied only if the load is greater than
+       Qmax/3. if average = True. then the Qmax/5 threshold
+       is compared to averge current.otherwise it is compared
+       to current.
+       Recommended value: 15-255. 255---disabsle the filter
+       */
+       uint8_t filter_light;
+       uint8_t filter_heavy;
+       /*overload_current: the current level above which an
+       EDV condition will not be detected and
+       capacity not reconciled*/
+       int16_t overload_current;
+
+       struct edv_point edv[3];
+       /*edv: the end-of-discharge voltage-to-capactiy
+       correlation points.*/
+       /*struct edv_point *edv;*/
+};
+
+/* General Battery Cell Gauging Configuration */
+struct cell_config {
+       bool cc_polarity;  /*To Be Determined*/
+       bool cc_out;
+       /*ocv_below_edv1: if set (True), OCV correction allowed
+       bellow EDV1 point*/
+       bool ocv_below_edv1;
+       /*cc_voltage: the charge complete voltage threshold(e.g. 4.2v)
+       of the battery. charge cannot be considered complete if the
+       battery voltage is below this threshold*/
+       int16_t cc_voltage;
+       /*cc_current:the charge complete current threshold(e.g. c/20).
+       charge cannot  be considered complete when charge
+       current and average current are greater than this threshold*/
+       int16_t cc_current;
+       /*design_capacity: design capacity of the battery.
+       the battery datasheet should provide this value*/
+       uint16_t design_capacity;
+       /*design_qmax: the calculated discharge capacity of
+       the OCV discharge curve*/
+       int16_t design_qmax;
+       /*r_sense: the resistance of the current sence element.
+       the sense resistor needs to be slelected to
+       ensure accurate current measuremen and integration
+       at currents >OFF consumption*/
+       uint8_t r_sense;
+       /*qmax_adjust: the value decremented from QMAX
+       every cycle for aging compensation.*/
+       uint8_t qmax_adjust;
+       /*fcc_adjust: the value decremented from the FCC
+       when no learning happen for 25 cycles in a row*/
+       uint8_t fcc_adjust;
+       /*max_overcharge: the fuel gauge tracks the capacity
+       that goes into the battery after a termination
+       condition is detected. this improve gauging accuracy
+       if the charger's charge termination condition does't
+       match to the fuel gauge charge termination condition.*/
+       uint16_t max_overcharge;
+       /*electronics_load: the current that the system consumes
+       int the OFF mode(MPU low power, screen  OFF)*/
+       uint16_t electronics_load;
+       /*max_increment: the maximum increment of FCC if the
+       learned capacity is much greater than the exiting
+       FCC. recommentded value 150mAh*/
+       int16_t max_increment;
+       /*max_decrement: the maximum increment of FCC if the
+       learned capacity is much lower than the exiting FCC*/
+       int16_t max_decrement;
+       /*low_temp: the correlation between voltage and remaining
+       capacity is considered inaccurate below this temperature.
+       any leaning will be disqualified, if the battery temperature
+       is below this threshold
+       */
+       uint8_t low_temp;
+       /*deep_dsg_voltage:in order to qualify capacity learning on
+       the discharge, the battery voltage should
+       be within EDV-deep-dsg_voltage and EDV.*/
+       uint16_t deep_dsg_voltage;
+       /*
+       max_dsg_voltage:limits the amount of the estimated
+       discharge when learning is in progress. if the amount of
+       the capacity estimation get greater than this threshold,
+       the learning gets disqualified
+       */
+       uint16_t max_dsg_estimate;
+       /*
+       light_load: FCC learning on discharge disqualifies if
+       the load is below this threshold when the
+       when EDV2 is reached.
+       */
+       uint8_t light_load;
+       /*
+       near_full: this defines a capacity zone from FCC
+       to FCC - near_full. A discharge cycles start
+       from this capacity zone qualifies for FCC larning.
+       */
+       uint16_t near_full;
+       /*
+       cycle_threshold: the amount of capacity that should
+       be dicharged from the battery to increment the cycle
+       count by 1.cycle counting happens on the discharge only.
+       */
+       uint16_t cycle_threshold;
+       /*recharge: the voltage of recharge.*/
+       uint16_t recharge;
+       /*
+       mode_swtich_capacity: this defines how much capacity
+       should pass through the coulomb counter to cause a cycle
+       count start condition (either charge or discharge). the gauge
+       support 2 cycle typeds.charge and discharge. a cycle starts
+       when mode_switch_capacity passes through the coulomb counter
+       the cycle get canceled and switches to the opposite direciton
+       if mode_switch_capacity passes though
+       the coulomb counter in oppositer direciton.
+       */
+       uint8_t mode_switch_capacity;
+       /*call_period: approximate time between fuel gauge calls.*/
+       uint8_t call_period;
+
+       struct ocv_config *ocv;
+       struct edv_config *edv;
+};
+
+/* Cell State */
+/*
+light-load: ( < C/40)
+
+*/
+struct cell_state {
+       /*
+       SOC : state-of-charge of the battery in %,it represents
+       the % full of the battery from the system empty voltage.
+       SOC = NAC/FCC,  SOC = 1 -DOD
+       */
+       int16_t soc;
+       /*
+       nac :nominal avaiable charge of the battery in mAh.
+       it represents the present remain capacity of the battery
+       to the system empty voltage under nominal conditions
+       */
+       int16_t nac;
+       /*
+       fcc: full battery capacity .this represents the discharge capacity
+       of the battery from the defined full condition to the system empty
+       voltage(EDV0) under nominal conditions.the value is learned by
+       the algorithm on qualified charge and discharge cycleds
+       */
+       int16_t fcc;
+       /* qmax: the battery capacity(mAh) at the OCV curve discharge rate*/
+       int16_t qmax;
+
+       int16_t voltage;
+       int16_t av_voltage;
+       int16_t cur;
+       int16_t av_current;
+
+       int16_t temperature;
+       /*
+       cycle_count: it represents how many charge or discharge
+       cycles a battery has experience. this is used to estimate the
+       change of impedance of the battery due to "aging"
+       */
+       int16_t cycle_count;
+       /*
+       sleep : in this mode ,the battery fuel gauge is counting
+       discharge with the coulomb counter and checking for the
+       battery relaxed condition, if a relaxed battery is destected
+       the fuel gauge enters OCV mode
+       */
+       bool sleep;
+       bool relax;
+
+       bool chg;
+       bool dsg;
+
+       bool edv0;
+       bool edv1;
+       bool edv2;
+       bool ocv;
+       bool cc;
+       bool full;
+
+       bool eocl;
+       bool vcq;
+       bool vdq;
+       bool init;
+
+       struct timeval sleep_timer;
+       struct timeval el_sleep_timer;
+       uint16_t cumulative_sleep;
+
+       int16_t prev_soc;
+       int16_t learn_q;
+       uint16_t dod_eoc;
+       int16_t learn_offset;
+       uint16_t learned_cycle;
+       int16_t new_fcc;
+       int16_t ocv_total_q;
+       int16_t ocv_enter_q;
+       int16_t negative_q;
+       int16_t overcharge_q;
+       int16_t charge_cycle_q;
+       int16_t discharge_cycle_q;
+       int16_t cycle_q;
+       uint8_t sequential_cc;
+       uint8_t sleep_samples;
+       uint8_t sequential_edvs;
+
+       uint16_t electronics_load;
+       uint16_t cycle_dsg_estimate;
+
+       struct edv_state edv;
+
+       bool updated;
+       bool calibrate;
+
+       struct cell_config *config;
+};
+
+struct battery_platform_data {
+       int *battery_tmp_tbl;
+       unsigned int tblsize;
+       u32 *battery_ocv;
+       unsigned int  ocv_size;
+
+       unsigned int monitoring_interval;
+       unsigned int max_charger_ilimitmA;
+       unsigned int max_charger_currentmA;
+       unsigned int max_charger_voltagemV;
+       unsigned int termination_currentmA;
+
+       unsigned int max_bat_voltagemV;
+       unsigned int low_bat_voltagemV;
+       unsigned int chrg_diff_vol;
+       unsigned int power_off_thresd;
+       unsigned int sense_resistor_mohm;
+
+       /* twl6032 */
+       unsigned long features;
+       unsigned long errata;
+
+       struct cell_config *cell_cfg;
+};
+
+enum fg_mode {
+       FG_NORMAL_MODE = 0,/*work normally*/
+       TEST_POWER_MODE,   /*work without battery*/
+};
+
+enum hw_support_adp {
+       HW_ADP_TYPE_USB = 0,/*'HW' means:hardware*/
+       HW_ADP_TYPE_DC,
+       HW_ADP_TYPE_DUAL
+};
+
+
+/* don't change the following ID, they depend on usb check
+ * interface: dwc_otg_check_dpdm()
+ */
+enum charger_type {
+       NO_CHARGER = 0,
+       USB_CHARGER,
+       AC_CHARGER,
+       DC_CHARGER,
+       DUAL_CHARGER
+};
+
+enum charger_state {
+       OFFLINE = 0,
+       ONLINE
+};
+
+void kernel_power_off(void);
+#if defined(CONFIG_ARCH_ROCKCHIP)
+int dwc_vbus_status(void);
+int get_gadget_connect_flag(void);
+int dwc_otg_check_dpdm(void);
+void rk_send_wakeup_key(void);
+#else
+
+static inline int get_gadget_connect_flag(void)
+{
+       return 0;
+}
+
+static inline int dwc_otg_check_dpdm(void)
+{
+       return 0;
+}
+
+static inline void rk_send_wakeup_key(void)
+{
+}
+#endif
+
+#endif
index 02aedd151d08006cccb28b62a75c33106c237289..bdcc3c6d32e44c724ec3fc36ca776d89993c43b8 100755 (executable)
@@ -16,7 +16,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/wakelock.h>
 #include <linux/power_supply.h>
-#include <linux/power/rk818_battery.h>
+//#include <linux/power/rk818_battery.h>
 
 //#define RK818_START 30
 
diff --git a/include/linux/power/rk818_battery.h b/include/linux/power/rk818_battery.h
deleted file mode 100644 (file)
index f9bcc72..0000000
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
-*rk818-battery.h - Battery fuel gauge driver structures
- *
- */
-#ifndef RK818_BATTERY
-#define  RK818_BATTERY
-#include <linux/time.h>
-
-#define VB_MOD_REG                                     0x21
-#define THERMAL_REG                                    0x22
-#define DCDC_ILMAX_REG                         0x90
-#define CHRG_COMP_REG1                         0x99
-#define CHRG_COMP_REG2                         0x9A
-#define SUP_STS_REG                                    0xA0
-#define USB_CTRL_REG                           0xA1
-#define CHRG_CTRL_REG1                         0xA3
-#define CHRG_CTRL_REG2                         0xA4
-#define CHRG_CTRL_REG3                         0xA5
-#define BAT_CTRL_REG                           0xA6
-#define BAT_HTS_TS1_REG                        0xA8
-#define BAT_LTS_TS1_REG                        0xA9
-#define BAT_HTS_TS2_REG                        0xAA
-#define BAT_LTS_TS2_REG                        0xAB
-
-
-#define TS_CTRL_REG                                    0xAC
-#define ADC_CTRL_REG                           0xAD
-
-#define ON_SOURCE                                      0xAE
-#define OFF_SOURCE                                     0xAF
-
-#define GGCON                                          0xB0
-#define GGSTS                                          0xB1
-#define FRAME_SMP_INTERV_REG           0xB2
-#define AUTO_SLP_CUR_THR_REG           0xB3
-
-#define GASCNT_CAL_REG3                        0xB4
-#define GASCNT_CAL_REG2                        0xB5
-#define GASCNT_CAL_REG1                        0xB6
-#define GASCNT_CAL_REG0                        0xB7
-#define GASCNT3                                                0xB8
-#define GASCNT2                                                0xB9
-#define GASCNT1                                                0xBA
-#define GASCNT0                                                0xBB
-
-#define BAT_CUR_AVG_REGH                       0xBC
-#define BAT_CUR_AVG_REGL                       0xBD
-
-#define TS1_ADC_REGH                           0xBE
-#define TS1_ADC_REGL                           0xBF
-#define TS2_ADC_REGH                           0xC0
-#define TS2_ADC_REGL                           0xC1
-
-#define BAT_OCV_REGH                           0xC2
-#define BAT_OCV_REGL                           0xC3
-#define BAT_VOL_REGH                           0xC4
-#define BAT_VOL_REGL                           0xC5
-
-#define RELAX_ENTRY_THRES_REGH 0xC6
-#define RELAX_ENTRY_THRES_REGL 0xC7
-#define RELAX_EXIT_THRES_REGH          0xC8
-#define RELAX_EXIT_THRES_REGL          0xC9
-
-#define RELAX_VOL1_REGH                        0xCA
-#define RELAX_VOL1_REGL                        0xCB
-#define RELAX_VOL2_REGH                        0xCC
-#define RELAX_VOL2_REGL                        0xCD
-
-#define BAT_CUR_R_CALC_REGH            0xCE
-#define BAT_CUR_R_CALC_REGL            0xCF
-#define BAT_VOL_R_CALC_REGH            0xD0
-#define BAT_VOL_R_CALC_REGL            0xD1
-
-#define CAL_OFFSET_REGH                        0xD2
-#define CAL_OFFSET_REGL                        0xD3
-
-#define NON_ACT_TIMER_CNT_REG  0xD4
-
-#define VCALIB0_REGH                           0xD5
-#define VCALIB0_REGL                           0xD6
-#define VCALIB1_REGH                           0xD7
-#define VCALIB1_REGL                           0xD8
-
-#define IOFFSET_REGH                           0xDD
-#define IOFFSET_REGL                           0xDE
-
-
-/*0xE0 ~0xF2  data register,*/
-#define  SOC_REG                                               0xE0
-
-#define  REMAIN_CAP_REG3                       0xE1
-#define  REMAIN_CAP_REG2                       0xE2
-#define  REMAIN_CAP_REG1                       0xE3
-#define  REMAIN_CAP_REG0                       0xE4
-
-#define UPDAT_LEVE_REG                         0xE5
-
-#define  NEW_FCC_REG3                          0xE6
-#define  NEW_FCC_REG2                          0xE7
-#define  NEW_FCC_REG1                          0xE8
-#define  NEW_FCC_REG0                          0xE9
-
-#define NON_ACT_TIMER_CNT_REG_SAVE             0xEA
-#define OCV_VOL_VALID_REG                      0xEB
-#define REBOOT_CNT_REG                         0xEC
-#define PCB_IOFFSET_REG                                0xED
-#define MISC_MARK_REG                          0xEE
-
-
-/* gasgauge module enable bit 0: disable  1:enabsle
-TS_CTRL_REG  0xAC*/
-#define GG_EN                                          (1<<7)
-
-/*ADC_CTRL_REG*/
-/*
-if GG_EN = 0 , then the ADC of BAT voltage controlled by the
-bit 0:diabsle 1:enable
-*/
-#define ADC_VOL_EN                                     (1<<7)
-/*
-if GG_EN = 0, then the ADC of BAT current controlled by the
-bit  0: disable 1: enable
-*/
-#define ADC_CUR_EN                                     (1<<6)
-/*the ADC of TS1 controlled by the bit 0:disabsle 1:enable */
-#define ADC_TS1_EN                                     (1<<5)
-/*the ADC of TS2 controlled by the bit 0:disabsle 1:enable */
-#define ADC_TS2_EN                                     (1<<4)
-/*ADC colock phase  0:normal 1:inverted*/
-#define ADC_PHASE                                      (1<<3)
-#define ADC_CLK_SEL                                    7
-/*****************************************************
-#define ADC_CLK_SEL_2M                         0x000
-#define ADC_CLK_SEL_1M                         0x001
-#define ADC_CLK_SEL_500K                       0x002
-#define ADC_CLK_SEL_250K                       0x003
-#define ADC_CLK_SEL_125K                       0x004
-******************************************************/
-/*GGCON*/
-/* ADC bat current continue sample times  00:8  01:16 10:32 11:64*/
-#define CUR_SAMPL_CON_TIMES            (3<<6)
-/*ADC offset calibreation interval time 00:8min 01:16min 10:32min 11:48min*/
-#define ADC_OFF_CAL_INTERV                     (3<<4)
-/*OCV sampling interval time 00:8min 01:16min 10:32min :11:48min*/
-#define OCV_SAMPL_INTERV                       (3<<2)
-
-/*ADC working in current voltage collection mode*/
-#define ADC_CUR_VOL_MODE                       (1<<1)
-/*ADC working in resistor calculation mode 0:disable 1:enable*/
-#define ADC_RES_MODE                           1
-
-/*GGSTS*/
-/*average current filter times 00:1/2  01:1/4 10:1/8 11:1/16*/
-#define RES_CUR_AVG_SEL                                (3<<5)
-/*battery first connection,edge trigger 0:NOT  1:YES*/
-#define BAT_CON                                                (1<<4)
-/*battery voltage1 update in relax status 0: NOT 1:YE*/
-#define RELAX_VOL1_UPD                         (1<<3)
-/*battery voltage2 update in relax status 0: NOT 1:YE*/
-#define RELAX_VOL2_UPD                         (1<<2)
-/*battery coming into relax status  0: NOT 1:YE*/
-#define RELAX_STS                                      (1<<1)
-/*battery average voltage and current updated status 0: NOT 1:YES*/
-#define IV_AVG_UPD_STS                         (1<<0)
-
-/*FRAME_SMP_INTERV_REG*/
-#define AUTO_SLP_EN                                    (1<<5)
-/* auto sleep mode 0:disable 1:enable*/
-#define FRAME_SMP_INTERV_TIME          0x1F
-
-/*VB_MOD_REG*/
-#define PLUG_IN_STS                                    (1<<6)
-
-/*SUP_STS_REG*/
-#define BAT_EXS                                                (1<<7)
-#define CHARGE_OFF                                     (0x00<<4)
-#define DEAD_CHARGE                                    (0x01<<4)
-#define TRICKLE_CHARGE                         (0x02<<4)
-#define CC_OR_CV                                               (0x03<<4)
-#define CHARGE_FINISH                          (0x04<<4)
-#define USB_OVER_VOL                           (0x05<<4)
-#define BAT_TMP_ERR                                    (0x06<<4)
-#define TIMER_ERR                                      (0x07<<4)
-/* usb is exists*/
-#define USB_EXIST                                      (1<<1)
-/* usb is effective*/
-#define USB_EFF                                                (1<<0)
-
-/*USB_CTRL_REG*/
-#define CHRG_CT_EN                                     (1<<7)
-/* USB_VLIM_SEL*/
-/*
-#define VLIM_4000MV                                    (0x00<<4)
-#define VLIM_4100MV                                    (0x01<<4)
-#define VLIM_4200MV                                    (0x02<<4)
-#define VLIM_4300MV                                    (0x03<<4)
-#define VLIM_4400MV                                    (0x04<<4)
-#define VLIM_4500MV                                    (0x05<<4)
-#define VLIM_4600MV                                    (0x06<<4)
-#define VLIM_4700MV                                    (0x07<<4)
-*/
-
-/*USB_ILIM_SEL*/
-#define ILIM_450MA                                     (0x00)
-#define ILIM_800MA                                     (0x01)
-#define ILIM_850MA                                     (0x02)
-#define ILIM_1000MA                                    (0x03)
-#define ILIM_1250MA                                    (0x04)
-#define ILIM_1500MA                                    (0x05)
-#define ILIM_1750MA                                    (0x06)
-#define ILIM_2000MA                                    (0x07)
-#define ILIM_2250MA                                    (0x08)
-#define ILIM_2500MA                                    (0x09)
-#define ILIM_2750MA                                    (0x0A)
-#define ILIM_3000MA                                    (0x0B)
-
-
-/*CHRG_CTRL_REG*/
-#define CHRG_EN                                                (0x01<<7)
-
-/*CHRG_VOL_SEL*/
-#define CHRG_VOL4050                           (0x00<<4)
-#define CHRG_VOL4100                           (0x01<<4)
-#define CHRG_VOL4150                           (0x02<<4)
-#define CHRG_VOL4200                           (0x03<<4)
-#define CHRG_VOL4300                           (0x04<<4)
-#define CHRG_VOL4350                           (0x05<<4)
-
-/*CHRG_CUR_SEL*/
-#define CHRG_CUR1000mA                 (0x00)
-#define CHRG_CUR1200mA                 (0x01)
-#define CHRG_CUR1400mA                 (0x02)
-#define CHRG_CUR1600mA                 (0x03)
-#define CHRG_CUR1800mA                 (0x04)
-#define CHRG_CUR2000mA                 (0x05)
-#define CHRG_CUR2200mA                 (0x06)
-#define CHRG_CUR2400mA                 (0x07)
-#define CHRG_CUR2600mA                 (0x08)
-#define CHRG_CUR2800mA                 (0x09)
-#define CHRG_CUR3000mA                 (0x0A)
-
-/*CHRG_CTRL_REG2*/
-#define FINISH_100MA                           (0x00<<6)
-#define FINISH_150MA                           (0x01<<6)
-#define FINISH_200MA                           (0x02<<6)
-#define FINISH_250MA                           (0x03<<6)
-
-/*temp feed back degree*/
-#define TEMP_85C                       (0x00 << 2)
-#define TEMP_95C                       (0x01 << 2)
-#define TEMP_105C                      (0x02 << 2)
-#define TEMP_115C                      (0x03 << 2)
-
-
-/* CHRG_CTRL_REG3*/
-#define CHRG_TERM_ANA_SIGNAL (0 << 5)
-#define CHRG_TERM_DIG_SIGNAL (1 << 5)
-
-/*CHRG_CTRL_REG2*/
-#define CHG_CCCV_4HOUR                 (0x00)
-#define CHG_CCCV_5HOUR                 (0x01)
-#define CHG_CCCV_6HOUR                 (0x02)
-#define CHG_CCCV_8HOUR                 (0x03)
-#define CHG_CCCV_10HOUR                        (0x04)
-#define CHG_CCCV_12HOUR                        (0x05)
-#define CHG_CCCV_14HOUR                        (0x06)
-#define CHG_CCCV_16HOUR                        (0x07)
-
-/*GGCON*/
-#define SAMP_TIME_8MIN                         (0X00<<4)
-#define SAMP_TIME_16MIN                                (0X01<<4)
-#define SAMP_TIME_32MIN                                (0X02<<4)
-#define SAMP_TIME_48MIN                                (0X03<<4)
-
-#define DRIVER_VERSION                         "3.0.0"
-#define ROLEX_SPEED                                    (100 * 1000)
-
-#define CHARGING                                       0x01
-#define DISCHARGING                                    0x00
-
-#define TIMER_MS_COUNTS                        1000
-#define MAX_CHAR                                       0x7F
-#define MAX_UNSIGNED_CHAR                      0xFF
-#define MAX_INT                                                0x7FFF
-#define MAX_UNSIGNED_INT                       0xFFFF
-#define MAX_INT8                                       0x7F
-#define MAX_UINT8                                      0xFF
-
-/* Gas Gauge Constatnts */
-#define TEMP_0C                        2732
-#define MAX_CAPACITY           0x7fff
-#define MAX_SOC                        100
-#define MAX_PERCENTAGE         100
-
-/* Num, cycles with no Learning, after this many cycles, the gauge
-   start adjusting FCC, based on Estimated Cell Degradation */
-#define NO_LEARNING_CYCLES     25
-/* Size of the OCV Lookup table */
-#define OCV_TABLE_SIZE         21
-/*
- * OCV Config
- */
-struct ocv_config {
-       /*voltage_diff, current_diff: Maximal allowed deviation
-       of the voltage and the current from one reading to the
-       next that allows the fuel gauge to apply an OCV correction.
-       The main purpose of these thresholds is to filter current
-       and voltage spikes. Recommended value: these value are
-       highly depend on the load nature. if the load creates a lot
-       of current spikes .the value may need to be increase*/
-       uint8_t voltage_diff;
-       uint8_t current_diff;
-       /* sleep_enter_current: if the current remains under
-       this threshold for [sleep_enter_samples]
-       consecutive samples. the gauge enters the SLEEP MODE*/
-       uint16_t sleep_enter_current;
-       /*sleep_enter_samples: the number of samples that
-       satis fy asleep enter or exit condition in order
-       to actually enter of exit SLEEP mode*/
-       uint8_t sleep_enter_samples;
-       /*sleep_exit_samples: to exit SLEEP mode , average
-       current should pass this threshold first. then
-       current should remain above this threshold for
-       [sleep_exit_samples] consecutive samples*/
-       uint16_t sleep_exit_current;
-       /*sleep_exit_samples: to exit SLEEP mode, average
-       current should pass this threshold first, then current
-       should remain above this threshold for [sleep_exit_samples]
-       consecutive samples.*/
-       uint8_t sleep_exit_samples;
-       /*relax_period: defines the number of seconds the
-       fuel gauge should spend in the SLEEP mode
-       before entering the OCV mode, this setting makes
-       the gauge wait for a cell voltage recovery after
-       a charge or discharge operation*/
-       uint16_t relax_period;
-       /* flat_zone_low : flat_zone_high :if soc falls into
-       the flat zone low% - flat zone high %.the fuel gauge
-       wait for a cell voltage recovery after a charge or
-       discharge operation.*/
-       uint8_t flat_zone_low;
-       uint8_t flat_zone_high;
-       /*FCC leaning is disqualified if the discharge capacity
-       in the OCV mode is greater than this threshold*/
-       uint16_t max_ocv_discharge;
-       /*the 21-point OCV table*/
-       uint16_t table[OCV_TABLE_SIZE];
-       /*uint16_t *table;*/
-};
-
-/* EDV Point */
-struct edv_point {
-       int16_t voltage;
-       uint8_t percent;
-};
-
-/* EDV Point tracking data */
-struct edv_state {
-       int16_t voltage;
-       uint8_t percent;
-       int16_t min_capacity;
-       uint8_t edv_cmp;
-};
-
-/* EDV Configuration */
-struct edv_config {
-       /*avieraging: True = evokes averaging on voltage
-       reading to detect an EDV condition.
-       False = no averaging of voltage readings to detect an
-       EDV conditation.*/
-       bool averaging;
-       /*sequential_edv: the sequential_edv setting defines
-       how many times in a row the battery should
-       pass the EDV threshold to detect an EDV condition.
-       this setting is intended to fiter short voltage spikes
-       cause by current spikes*/
-       uint8_t sequential_edv;
-       /*filter_light: difine the calculated EDV voltage
-       recovery IIR filter strength
-       light-lsetting : for light load (below Qmax/5)
-       heavy setting : for ligh load (above Qmax/5)
-       the filter is applied only if the load is greater than
-       Qmax/3. if average = True. then the Qmax/5 threshold
-       is compared to averge current.otherwise it is compared
-       to current.
-       Recommended value: 15-255. 255---disabsle the filter
-       */
-       uint8_t filter_light;
-       uint8_t filter_heavy;
-       /*overload_current: the current level above which an
-       EDV condition will not be detected and
-       capacity not reconciled*/
-       int16_t overload_current;
-
-       struct edv_point edv[3];
-       /*edv: the end-of-discharge voltage-to-capactiy
-       correlation points.*/
-       /*struct edv_point *edv;*/
-};
-
-/* General Battery Cell Gauging Configuration */
-struct cell_config {
-       bool cc_polarity;  /*To Be Determined*/
-       bool cc_out;
-       /*ocv_below_edv1: if set (True), OCV correction allowed
-       bellow EDV1 point*/
-       bool ocv_below_edv1;
-       /*cc_voltage: the charge complete voltage threshold(e.g. 4.2v)
-       of the battery. charge cannot be considered complete if the
-       battery voltage is below this threshold*/
-       int16_t cc_voltage;
-       /*cc_current:the charge complete current threshold(e.g. c/20).
-       charge cannot  be considered complete when charge
-       current and average current are greater than this threshold*/
-       int16_t cc_current;
-       /*design_capacity: design capacity of the battery.
-       the battery datasheet should provide this value*/
-       uint16_t design_capacity;
-       /*design_qmax: the calculated discharge capacity of
-       the OCV discharge curve*/
-       int16_t design_qmax;
-       /*r_sense: the resistance of the current sence element.
-       the sense resistor needs to be slelected to
-       ensure accurate current measuremen and integration
-       at currents >OFF consumption*/
-       uint8_t r_sense;
-       /*qmax_adjust: the value decremented from QMAX
-       every cycle for aging compensation.*/
-       uint8_t qmax_adjust;
-       /*fcc_adjust: the value decremented from the FCC
-       when no learning happen for 25 cycles in a row*/
-       uint8_t fcc_adjust;
-       /*max_overcharge: the fuel gauge tracks the capacity
-       that goes into the battery after a termination
-       condition is detected. this improve gauging accuracy
-       if the charger's charge termination condition does't
-       match to the fuel gauge charge termination condition.*/
-       uint16_t max_overcharge;
-       /*electronics_load: the current that the system consumes
-       int the OFF mode(MPU low power, screen  OFF)*/
-       uint16_t electronics_load;
-       /*max_increment: the maximum increment of FCC if the
-       learned capacity is much greater than the exiting
-       FCC. recommentded value 150mAh*/
-       int16_t max_increment;
-       /*max_decrement: the maximum increment of FCC if the
-       learned capacity is much lower than the exiting FCC*/
-       int16_t max_decrement;
-       /*low_temp: the correlation between voltage and remaining
-       capacity is considered inaccurate below this temperature.
-       any leaning will be disqualified, if the battery temperature
-       is below this threshold
-       */
-       uint8_t low_temp;
-       /*deep_dsg_voltage:in order to qualify capacity learning on
-       the discharge, the battery voltage should
-       be within EDV-deep-dsg_voltage and EDV.*/
-       uint16_t deep_dsg_voltage;
-       /*
-       max_dsg_voltage:limits the amount of the estimated
-       discharge when learning is in progress. if the amount of
-       the capacity estimation get greater than this threshold,
-       the learning gets disqualified
-       */
-       uint16_t max_dsg_estimate;
-       /*
-       light_load: FCC learning on discharge disqualifies if
-       the load is below this threshold when the
-       when EDV2 is reached.
-       */
-       uint8_t light_load;
-       /*
-       near_full: this defines a capacity zone from FCC
-       to FCC - near_full. A discharge cycles start
-       from this capacity zone qualifies for FCC larning.
-       */
-       uint16_t near_full;
-       /*
-       cycle_threshold: the amount of capacity that should
-       be dicharged from the battery to increment the cycle
-       count by 1.cycle counting happens on the discharge only.
-       */
-       uint16_t cycle_threshold;
-       /*recharge: the voltage of recharge.*/
-       uint16_t recharge;
-       /*
-       mode_swtich_capacity: this defines how much capacity
-       should pass through the coulomb counter to cause a cycle
-       count start condition (either charge or discharge). the gauge
-       support 2 cycle typeds.charge and discharge. a cycle starts
-       when mode_switch_capacity passes through the coulomb counter
-       the cycle get canceled and switches to the opposite direciton
-       if mode_switch_capacity passes though
-       the coulomb counter in oppositer direciton.
-       */
-       uint8_t mode_switch_capacity;
-       /*call_period: approximate time between fuel gauge calls.*/
-       uint8_t call_period;
-
-       struct ocv_config *ocv;
-       struct edv_config *edv;
-};
-
-/* Cell State */
-/*
-light-load: ( < C/40)
-
-*/
-struct cell_state {
-       /*
-       SOC : state-of-charge of the battery in %,it represents
-       the % full of the battery from the system empty voltage.
-       SOC = NAC/FCC,  SOC = 1 -DOD
-       */
-       int16_t soc;
-       /*
-       nac :nominal avaiable charge of the battery in mAh.
-       it represents the present remain capacity of the battery
-       to the system empty voltage under nominal conditions
-       */
-       int16_t nac;
-       /*
-       fcc: full battery capacity .this represents the discharge capacity
-       of the battery from the defined full condition to the system empty
-       voltage(EDV0) under nominal conditions.the value is learned by
-       the algorithm on qualified charge and discharge cycleds
-       */
-       int16_t fcc;
-       /* qmax: the battery capacity(mAh) at the OCV curve discharge rate*/
-       int16_t qmax;
-
-       int16_t voltage;
-       int16_t av_voltage;
-       int16_t cur;
-       int16_t av_current;
-
-       int16_t temperature;
-       /*
-       cycle_count: it represents how many charge or discharge
-       cycles a battery has experience. this is used to estimate the
-       change of impedance of the battery due to "aging"
-       */
-       int16_t cycle_count;
-       /*
-       sleep : in this mode ,the battery fuel gauge is counting
-       discharge with the coulomb counter and checking for the
-       battery relaxed condition, if a relaxed battery is destected
-       the fuel gauge enters OCV mode
-       */
-       bool sleep;
-       bool relax;
-
-       bool chg;
-       bool dsg;
-
-       bool edv0;
-       bool edv1;
-       bool edv2;
-       bool ocv;
-       bool cc;
-       bool full;
-
-       bool eocl;
-       bool vcq;
-       bool vdq;
-       bool init;
-
-       struct timeval sleep_timer;
-       struct timeval el_sleep_timer;
-       uint16_t cumulative_sleep;
-
-       int16_t prev_soc;
-       int16_t learn_q;
-       uint16_t dod_eoc;
-       int16_t learn_offset;
-       uint16_t learned_cycle;
-       int16_t new_fcc;
-       int16_t ocv_total_q;
-       int16_t ocv_enter_q;
-       int16_t negative_q;
-       int16_t overcharge_q;
-       int16_t charge_cycle_q;
-       int16_t discharge_cycle_q;
-       int16_t cycle_q;
-       uint8_t sequential_cc;
-       uint8_t sleep_samples;
-       uint8_t sequential_edvs;
-
-       uint16_t electronics_load;
-       uint16_t cycle_dsg_estimate;
-
-       struct edv_state edv;
-
-       bool updated;
-       bool calibrate;
-
-       struct cell_config *config;
-};
-
-struct battery_platform_data {
-       int *battery_tmp_tbl;
-       unsigned int tblsize;
-       u32 *battery_ocv;
-       unsigned int  ocv_size;
-
-       unsigned int monitoring_interval;
-       unsigned int max_charger_ilimitmA;
-       unsigned int max_charger_currentmA;
-       unsigned int max_charger_voltagemV;
-       unsigned int termination_currentmA;
-
-       unsigned int max_bat_voltagemV;
-       unsigned int low_bat_voltagemV;
-
-       unsigned int sense_resistor_mohm;
-
-       /* twl6032 */
-       unsigned long features;
-       unsigned long errata;
-
-       struct cell_config *cell_cfg;
-};
-
-enum fg_mode_t {
-       FG_NORMAL_MODE = 0,/*work normally*/
-       TEST_POWER_MODE,   /*work without battery*/
-};
-
-enum hw_support_adp_t {
-       HW_ADP_TYPE_USB = 0,/*'HW' means:hardware*/
-       HW_ADP_TYPE_DC,
-       HW_ADP_TYPE_DUAL
-};
-
-
-/* don't change the following ID, they depend on usb check
- * interface: dwc_otg_check_dpdm()
- */
-enum charger_type_t {
-       NO_CHARGER = 0,
-       USB_CHARGER,
-       AC_CHARGER,
-       DC_CHARGER,
-       DUAL_CHARGER
-};
-
-enum charger_state_t {
-       OFFLINE = 0,
-       ONLINE
-};
-
-int dwc_vbus_status(void);
-int get_gadget_connect_flag(void);
-int dwc_otg_check_dpdm(void);
-void kernel_power_off(void);
-void rk_send_wakeup_key(void);
-
-#endif