power: rk818: support rk818 battery driver
authorJianhong Chen <chenjh@rock-chips.com>
Fri, 17 Jun 2016 07:35:47 +0000 (15:35 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 27 Jul 2016 08:44:12 +0000 (16:44 +0800)
Update version to v7.0, main features:
    1. new algorithm which is independent of time calculation in almost case,
    2. remove charger detect to driver: rk818-charger.c;
    3. save algorithm calculation rest value for next system power on calculation;
    4. recognize system halt and reset dsoc as rsoc;
    5. support hardware sample resistor selected as 10mR or 20mR;
    6. optimize zero algorithm to make discharge figure more smooth;
    7. fix some logic bugs.

Change-Id: I789d070693ac16102ecbe813d878a2a3c256c030
Signed-off-by: Jianhong Chen <chenjh@rock-chips.com>
drivers/mfd/rk808.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/rk818_battery.c
drivers/power/rk818_battery.h
include/linux/mfd/rk808.h

index 2220855cc1fe0b0b8a0b1f71f3a70f7f07e0792f..86dd427b0fe358e66df0b4783ae3b609cbb5f808 100644 (file)
@@ -89,6 +89,38 @@ static int rk818_shutdown(struct regmap *regmap)
        return ret;
 }
 
        return ret;
 }
 
+static bool rk818_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       /*
+        * Notes:
+        * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
+        *   we don't use that feature.  It's better to cache.
+        * - It's unlikely we care that RK808_DEVCTRL_REG is volatile since
+        *   bits are cleared in case when we shutoff anyway, but better safe.
+        */
+
+       switch (reg) {
+       case RK808_SECONDS_REG ... RK808_WEEKS_REG:
+       case RK808_RTC_STATUS_REG:
+       case RK808_VB_MON_REG:
+       case RK808_THERMAL_REG:
+       case RK808_DCDC_EN_REG:
+       case RK808_DCDC_UV_STS_REG:
+       case RK808_LDO_UV_STS_REG:
+       case RK808_DCDC_PG_REG:
+       case RK808_LDO_PG_REG:
+       case RK808_DEVCTRL_REG:
+       case RK808_INT_STS_REG1:
+       case RK808_INT_STS_REG2:
+       case RK808_INT_STS_MSK_REG1:
+       case RK808_INT_STS_MSK_REG2:
+       case RK818_SUP_STS_REG ... RK818_SAVE_DATA19:
+               return true;
+       }
+
+       return false;
+}
+
 static const struct regmap_config rk808_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 static const struct regmap_config rk808_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
@@ -185,12 +217,13 @@ static const struct regmap_config rk818_regmap_config = {
        .val_bits = 8,
        .max_register = RK818_SAVE_DATA19,
        .cache_type = REGCACHE_RBTREE,
        .val_bits = 8,
        .max_register = RK818_SAVE_DATA19,
        .cache_type = REGCACHE_RBTREE,
-       .volatile_reg = rk808_is_volatile_reg,
+       .volatile_reg = rk818_is_volatile_reg,
 };
 
 static const struct mfd_cell rk818s[] = {
        { .name = "rk808-clkout", },
        { .name = "rk818-regulator", },
 };
 
 static const struct mfd_cell rk818s[] = {
        { .name = "rk808-clkout", },
        { .name = "rk818-regulator", },
+       { .name = "rk818-battery", .of_compatible = "rk818-battery", },
        {
                .name = "rk808-rtc",
                .num_resources = ARRAY_SIZE(rtc_resources),
        {
                .name = "rk808-rtc",
                .num_resources = ARRAY_SIZE(rtc_resources),
index 237d7aa73e8c8e15d74560c97560fb0ebdfcfead..1f6ec03cd378e723bb08a4a7e2a30fd09ab9bc99 100644 (file)
@@ -493,6 +493,14 @@ config BATTERY_RT5033
          The fuelgauge calculates and determines the battery state of charge
          according to battery open circuit voltage.
 
          The fuelgauge calculates and determines the battery state of charge
          according to battery open circuit voltage.
 
+config BATTERY_RK818
+       bool "RK818 Battery driver"
+       depends on MFD_RK808
+       default n
+       help
+         If you say yes here you will get support for the battery of RK818 PMIC.
+         This driver can give support for Rk818 Battery Charge Interface.
+
 config CHARGER_RT9455
        tristate "Richtek RT9455 battery charger driver"
        depends on I2C
 config CHARGER_RT9455
        tristate "Richtek RT9455 battery charger driver"
        depends on I2C
index b656638f8b3984ed41be4cb7bd26a57fb05d028c..b038e25333300408c7234f0016a07f3f128fdd1f 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_BATTERY_DA9150)  += da9150-fg.o
 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
 obj-$(CONFIG_BATTERY_Z2)       += z2_battery.o
 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
 obj-$(CONFIG_BATTERY_Z2)       += z2_battery.o
+obj-$(CONFIG_BATTERY_RK818)    += rk818_battery.o
 obj-$(CONFIG_BATTERY_RT5033)   += rt5033_battery.o
 obj-$(CONFIG_CHARGER_RT9455)   += rt9455_charger.o
 obj-$(CONFIG_BATTERY_S3C_ADC)  += s3c_adc_battery.o
 obj-$(CONFIG_BATTERY_RT5033)   += rt5033_battery.o
 obj-$(CONFIG_CHARGER_RT9455)   += rt9455_charger.o
 obj-$(CONFIG_BATTERY_S3C_ADC)  += s3c_adc_battery.o
index c2381e79a1d4b911f88b3c857175950d04ee1c81..6e824836b761c64783ae43d6edba8e2d64403215 100644 (file)
@@ -1,19 +1,8 @@
 /*
 /*
- * rk818/rk819 battery driver
+ * rk818 battery driver
  *
  *
- *  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
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd
+ * chenjh <chenjh@rock-chips.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * more details.
  *
  */
  * more details.
  *
  */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/param.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
+
 #include <linux/delay.h>
 #include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-#include <linux/idr.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/fb.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
-#include <linux/proc_fs.h>
-#include <linux/uaccess.h>
-#include <linux/mfd/rk818.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/rtc.h>
-#include <linux/wakelock.h>
-#include <linux/of_gpio.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.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>
-#else
+#include <linux/jiffies.h>
+#include <linux/mfd/rk808.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
 #include <linux/power/rk_usbbc.h>
 #include <linux/power/rk_usbbc.h>
-#endif
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/timer.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
 #include "rk818_battery.h"
 
 #include "rk818_battery.h"
 
-/* if you  want to disable, don't set it as 0,
-just be: "static int dbg_enable;" is ok*/
-
-static int dbg_enable;
-#define RK818_SYS_DBG 1
-
+static int dbg_enable = 0;
 module_param_named(dbg_level, dbg_enable, int, 0644);
 
 #define DBG(args...) \
 module_param_named(dbg_level, dbg_enable, int, 0644);
 
 #define DBG(args...) \
@@ -73,347 +47,198 @@ module_param_named(dbg_level, dbg_enable, int, 0644);
                } \
        } while (0)
 
                } \
        } while (0)
 
-#define DEFAULT_BAT_RES                        135
-#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    10
-#define DSOC_CHRG_FAST_CALIB_CURR_MAX  400     /*mA*/
-#define DSOC_CHRG_FAST_INC_SEC         120     /*seconds*/
-#define DSOC_CHRG_FAST_EER_RANGE       10
-#define DSOC_CHRG_EMU_CURR             1200
-#define DSOC_CHRG_TERM_CURR            600
-#define DSOC_CHRG_TERM_VOL             4100
-#define        CHRG_FINISH_VOL                 4100
-
-/*realtime RSOC calib param*/
-#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_DISCHRGR_TIME       3       /*min*/
-
-#define RSOC_RESUME_ERR                10
-#define REBOOT_INTER_MIN       1
-
-#define INTERPOLATE_MAX                1000
-#define MAX_INT                        0x7FFF
-#define TIME_10MIN_SEC         600
-
-#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
-
-/*TEST_POWER_MODE params*/
-#define TEST_CURRENT           1000
-#define TEST_VOLTAGE           3800
-#define TEST_SOC               66
-#define TEST_STATUS            POWER_SUPPLY_STATUS_CHARGING
-#define TEST_PRESET            1
-#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        POWER_ON_SEC_BASE       1
-#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
-/*if voltage is lower than this thresd,
-   we consider it as invalid
- */
-#define INVALID_VOL_THRESD     2500
-#define PWR_OFF_THRESD         3400
-#define MIN_ZERO_ACCURACY      5       /*0.01%*/
-#define MIN_ROUND_ACCURACY     1
-
-#define MAX_FCC                        10000
-#define MIN_FCC                        500
-/*
- * the following table value depends on datasheet
- */
-int CHRG_V_LMT[] = {4050, 4100, 4150, 4200, 4250, 4300, 4350};
-
-int CHRG_I_CUR[] = {1000, 1200, 1400, 1600, 1800, 2000,
-                  2250, 2400, 2600, 2800, 3000};
+#define BAT_INFO(fmt, args...) pr_info("rk818-bat: "fmt, ##args)
 
 
-int CHRG_I_LMT[] = {450, 800, 850, 1000, 1250, 1500, 1750,
-                  2000, 2250, 2500, 2750, 3000};
-
-u8 CHRG_CVCC_HOUR[] = {4, 5, 6, 8, 10, 12, 14, 16};
-
-#define RK818_DC_IN            0
-#define RK818_DC_OUT           1
-
-#define        OCV_VALID_SHIFT         (0)
-#define        OCV_CALIB_SHIFT         (1)
-#define FIRST_PWRON_SHIFT      (2)
-
-#define SEC_TO_MIN(x)          ((x) / 60)
-
-struct rk81x_battery {
+/* default param */
+#define DEFAULT_BAT_RES                        135
+#define DEFAULT_SLP_ENTER_CUR          300
+#define DEFAULT_SLP_EXIT_CUR           300
+#define DEFAULT_SLP_FILTER_CUR         100
+#define DEFAULT_PWROFF_VOL_THRESD      3400
+#define DEFAULT_MONITOR_SEC            5
+#define DEFAULT_ALGR_VOL_THRESD1       3850
+#define DEFAULT_ALGR_VOL_THRESD2       3950
+#define DEFAULT_MAX_SOC_OFFSET         60
+#define DEFAULT_FB_TEMP                        TEMP_105C
+#define DEFAULT_POFFSET                        42
+#define DEFAULT_COFFSET                        0x832
+#define DEFAULT_SAMPLE_RES             20
+#define DEFAULT_ENERGY_MODE            0
+#define INVALID_COFFSET_MIN            0x780
+#define INVALID_COFFSET_MAX            0x980
+#define INVALID_VOL_THRESD             2500
+
+/* sample resistor and division */
+#define SAMPLE_RES_10MR                        10
+#define SAMPLE_RES_20MR                        20
+#define SAMPLE_RES_DIV1                        1
+#define SAMPLE_RES_DIV2                        2
+
+/* virtual params */
+#define VIRTUAL_CURRENT                        1000
+#define VIRTUAL_VOLTAGE                        3888
+#define VIRTUAL_SOC                    66
+#define VIRTUAL_PRESET                 1
+#define VIRTUAL_TEMPERATURE            188
+
+/* charge */
+#define FINISH_CHRG_CUR                        1000
+#define TERM_CHRG_DSOC                 88
+#define TERM_CHRG_CURR                 600
+#define TERM_CHRG_K                    650
+#define SIMULATE_CHRG_INTV             8
+#define SIMULATE_CHRG_CURR             400
+#define SIMULATE_CHRG_K                        1500
+#define FULL_CHRG_K                    400
+
+/* zero algorithm */
+#define PWROFF_THRESD                  3400
+#define MIN_ZERO_DSOC_ACCURACY         10      /*0.01%*/
+#define MIN_ZERO_OVERCNT               100
+#define MIN_ACCURACY                   1
+#define DEF_PWRPATH_RES                        50
+#define        WAIT_DSOC_DROP_SEC              15
+#define        WAIT_SHTD_DROP_SEC              30
+#define ZERO_GAP_XSOC1                 10
+#define ZERO_GAP_XSOC2                 5
+#define ZERO_GAP_XSOC3                 3
+#define ZERO_LOAD_LVL1                 1400
+#define ZERO_LOAD_LVL2                 600
+
+#define ADC_CALIB_THRESHOLD            4
+#define ADC_CALIB_LMT_MIN              3
+#define NTC_CALC_FACTOR                        7
+
+/* time */
+#define        POWER_ON_SEC_BASE               1
+#define MINUTE(x)                      ((x) * 60)
+
+/* sleep */
+#define SLP_CURR_MAX                   40
+#define SLP_CURR_MIN                   6
+#define DISCHRG_TIME_STEP1             MINUTE(10)
+#define DISCHRG_TIME_STEP2             MINUTE(60)
+#define SLP_DSOC_VOL_THRESD            3600
+#define REBOOT_PERIOD_SEC              180
+#define REBOOT_MAX_CNT                 80
+
+/* fcc */
+#define MIN_FCC                                500
+
+struct rk818_battery {
+       struct platform_device          *pdev;
+       struct rk808                    *rk818;
+       struct regmap                   *regmap;
        struct device                   *dev;
        struct device                   *dev;
-       struct cell_state               cell;
-       struct power_supply             bat;
-       struct power_supply             ac;
-       struct power_supply             usb;
-       struct delayed_work             work;
-       struct rk818                    *rk818;
-       struct pinctrl                  *pinctrl;
-       struct pinctrl_state            *pins_default;
-
+       struct power_supply             *bat;
        struct battery_platform_data    *pdata;
        struct battery_platform_data    *pdata;
-
-       int                             dc_det_pin;
-       int                             dc_det_level;
-       int                             dc_det_irq;
-       int                             irq;
-       int                             ac_online;
-       int                             usb_online;
-       int                             otg_online;
-       int                             dc_online;
-       int                             psy_status;
+       struct workqueue_struct         *bat_monitor_wq;
+       struct delayed_work             bat_delay_work;
+       struct delayed_work             calib_delay_work;
+       struct wake_lock                wake_lock;
+       struct notifier_block           fb_nb;
+       struct timer_list               caltimer;
+       struct timeval                  rtc_base;
+       int                             bat_res;
+       int                             chrg_status;
+       bool                            is_initialized;
+       bool                            is_first_power_on;
+       u8                              res_div;
        int                             current_avg;
        int                             current_avg;
-       int                             current_offset;
-
-       uint16_t                        voltage;
-       uint16_t                        voltage_ocv;
-       uint16_t                        relax_voltage;
-       u8                              chrg_status;
-       u8                              slp_chrg_status;
-
-       u8                              otg_status;
-       int                             pcb_ioffset;
-       bool                            pcb_ioffset_updated;
-
-       int                             design_capacity;
+       int                             voltage_avg;
+       int                             voltage_ocv;
+       int                             voltage_relax;
+       int                             voltage_k;
+       int                             voltage_b;
+       int                             remain_cap;
+       int                             design_cap;
+       int                             nac;
        int                             fcc;
        int                             qmax;
        int                             fcc;
        int                             qmax;
-       int                             remain_capacity;
-       int                             nac;
-       int                             temp_nac;
        int                             dsoc;
        int                             dsoc;
-       int                             display_soc;
        int                             rsoc;
        int                             rsoc;
-       int                             trend_start_cap;
-
-       int                             est_ocv_vol;
-       int                             est_ocv_soc;
-       u8                              err_chck_cnt;
-       int                             err_soc_sum;
-       int                             bat_res_update_cnt;
-       int                             soc_counter;
-       int                             dod0;
-       int                             dod0_status;
-       int                             dod0_voltage;
-       int                             dod0_capacity;
-       unsigned long                   dod0_time;
-       u8                              dod0_level;
-       int                             adjust_cap;
-
-       int                             enter_flatzone;
-       int                             exit_flatzone;
-
-       int                             time2empty;
-       int                             time2full;
-
-       int                             *ocv_table;
-       int                             *res_table;
-
-       int                             current_k;/* (ICALIB0, ICALIB1) */
-       int                             current_b;
-
-       int                             voltage_k;/* VCALIB0 VCALIB1 */
-       int                             voltage_b;
-       bool                            enter_finish;
+       int                             poffset;
+       int                             age_ocv_soc;
+       bool                            age_allow_update;
+       int                             age_level;
+       int                             age_ocv_cap;
+       int                             age_voltage;
+       int                             age_adjust_cap;
+       unsigned long                   age_keep_sec;
        int                             zero_timeout_cnt;
        int                             zero_timeout_cnt;
-       int                             zero_old_remain_cap;
-
-       int                             line_k;
-       u8                              check_count;
-
-       int                             charge_smooth_time;
-       int                             sum_suspend_cap;
-       int                             suspend_cap;
-
-       unsigned long                   suspend_time_sum;
-
-       int                             suspend_rsoc;
-       int                             slp_psy_status;
-       int                             suspend_charge_current;
-       int                             resume_soc;
-       int                             bat_res;
-       bool                            charge_smooth_status;
-       bool                            discharge_smooth_status;
-
-       u32                             plug_in_min;
-       u32                             plug_out_min;
-       u32                             finish_sig_min;
-
-       struct notifier_block           battery_nb;
-       struct usb_phy                  *usb_phy;
-       struct notifier_block           usb_nb;
-       struct notifier_block           fb_nb;
+       int                             zero_remain_cap;
+       int                             zero_dsoc;
+       int                             zero_linek;
+       u64                             zero_drop_sec;
+       u64                             shtd_drop_sec;
+       int                             sm_remain_cap;
+       int                             sm_linek;
+       int                             sm_chrg_dsoc;
+       int                             sm_dischrg_dsoc;
+       int                             algo_rest_val;
+       int                             algo_rest_mode;
+       int                             sleep_sum_cap;
+       int                             sleep_remain_cap;
+       unsigned long                   sleep_dischrg_sec;
+       unsigned long                   sleep_sum_sec;
+       bool                            sleep_chrg_online;
+       u8                              sleep_chrg_status;
+       bool                            adc_allow_update;
        int                             fb_blank;
        int                             fb_blank;
-       int                             early_resume;
-       int                             s2r; /*suspend to resume*/
-       struct workqueue_struct         *wq;
-       struct delayed_work             battery_monitor_work;
-       struct delayed_work             otg_check_work;
-       struct delayed_work             usb_phy_delay_work;
-       struct delayed_work             chrg_term_mode_switch_work;
-       struct delayed_work             ac_usb_check_work;
-       struct delayed_work             dc_det_check_work;
-       enum bc_port_type               charge_otg;
-       int                             ma;
-
-       struct wake_lock                resume_wake_lock;
+       bool                            s2r; /*suspend to resume*/
+       u32                             work_mode;
+       int                             temperature;
+       u32                             monitor_ms;
+       u32                             pwroff_min;
+       unsigned long                   finish_base;
+       unsigned long                   boot_base;
+       unsigned long                   flat_match_sec;
        unsigned long                   plug_in_base;
        unsigned long                   plug_out_base;
        unsigned long                   plug_in_base;
        unsigned long                   plug_out_base;
-       unsigned long                   finish_sig_base;
-       unsigned long                   power_on_base;
-
-       int                             chrg_time2full;
-       int                             chrg_cap2full;
-
-       bool                            is_first_poweron;
-
-       int                             fg_drv_mode;
-       int                             debug_finish_real_soc;
-       int                             debug_finish_temp_soc;
-       int                             chrg_min[10];
-       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;
+       u8                              halt_cnt;
+       bool                            is_halt;
+       bool                            is_max_soc_offset;
+       bool                            is_sw_reset;
+       bool                            is_ocv_calib;
+       int                             last_dsoc;
+       int                             dbg_cap_low0;
+       int                             dbg_pwr_dsoc;
+       int                             dbg_pwr_rsoc;
+       int                             dbg_pwr_vol;
+       int                             dbg_chrg_min[10];
+       int                             dbg_meet_soc;
+       int                             dbg_calc_dsoc;
+       int                             dbg_calc_rsoc;
 };
 
 };
 
-u32 support_usb_adp, support_dc_adp, power_dc2otg;
-
-#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");
+#define DIV(x) ((x) ? (x) : 1)
 
 
-       return 0;
-}
-__setup("loader_charged", rk81x_bat_loader_charged);
-
-static u64 get_runtime_sec(void)
+static u64 get_boot_sec(void)
 {
        struct timespec ts;
 
        get_monotonic_boottime(&ts);
 {
        struct timespec ts;
 
        get_monotonic_boottime(&ts);
+
        return ts.tv_sec;
 }
 
        return ts.tv_sec;
 }
 
-static inline unsigned long  BASE_TO_SEC(unsigned long x)
+static unsigned long base2sec(unsigned long x)
 {
        if (x)
 {
        if (x)
-               return (get_runtime_sec() > x) ? (get_runtime_sec() - x) : 0;
+               return (get_boot_sec() > x) ? (get_boot_sec() - x) : 0;
        else
                return 0;
 }
 
        else
                return 0;
 }
 
-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;
-
-       switch (type) {
-       case HW_ADP_TYPE_USB:
-               if (support_usb_adp)
-                       bl = true;
-               break;
-       case HW_ADP_TYPE_DC:
-               if (support_dc_adp)
-                       bl = true;
-               break;
-       case HW_ADP_TYPE_DUAL:
-               if (support_usb_adp && support_dc_adp)
-                       bl = true;
-               break;
-       default:
-                       break;
-       }
-
-       return bl;
-}
-
-static bool rk81x_chrg_online(struct rk81x_battery *di)
+static unsigned long base2min(unsigned long x)
 {
 {
-       return di->usb_online || di->ac_online;
+       return base2sec(x) / 60;
 }
 
 static u32 interpolate(int value, u32 *table, int size)
 {
 }
 
 static u32 interpolate(int value, u32 *table, int size)
 {
-       uint8_t i;
-       uint16_t d;
+       u8 i;
+       u16 d;
 
        for (i = 0; i < size; i++) {
                if (value < table[i])
 
        for (i = 0; i < size; i++) {
                if (value < table[i])
@@ -421,11 +246,11 @@ static u32 interpolate(int value, u32 *table, int size)
        }
 
        if ((i > 0) && (i < size)) {
        }
 
        if ((i > 0) && (i < size)) {
-               d = (value - table[i-1]) * (INTERPOLATE_MAX / (size - 1));
-               d /= table[i] - table[i-1];
-               d = d + (i-1) * (INTERPOLATE_MAX / (size - 1));
+               d = (value - table[i - 1]) * (MAX_INTERPOLATE / (size - 1));
+               d /= table[i] - table[i - 1];
+               d = d + (i - 1) * (MAX_INTERPOLATE / (size - 1));
        } else {
        } else {
-               d = i * ((INTERPOLATE_MAX + size / 2) / size);
+               d = i * ((MAX_INTERPOLATE + size / 2) / size);
        }
 
        if (d > 1000)
        }
 
        if (d > 1000)
@@ -434,21 +259,18 @@ static u32 interpolate(int value, u32 *table, int size)
        return d;
 }
 
        return d;
 }
 
-/* Returns (a * b) / c */
+/* (a*b)/c */
 static int32_t ab_div_c(u32 a, u32 b, u32 c)
 {
        bool sign;
        u32 ans = MAX_INT;
 static int32_t ab_div_c(u32 a, u32 b, u32 c)
 {
        bool sign;
        u32 ans = MAX_INT;
-       int32_t tmp;
-
-       sign = ((((a^b)^c) & 0x80000000) != 0);
+       int tmp;
 
 
+       sign = ((((a ^ b) ^ c) & 0x80000000) != 0);
        if (c != 0) {
                if (sign)
                        c = -c;
        if (c != 0) {
                if (sign)
                        c = -c;
-
                tmp = (a * b + (c >> 1)) / c;
                tmp = (a * b + (c >> 1)) / c;
-
                if (tmp < MAX_INT)
                        ans = tmp;
        }
                if (tmp < MAX_INT)
                        ans = tmp;
        }
@@ -459,998 +281,592 @@ static int32_t ab_div_c(u32 a, u32 b, u32 c)
        return ans;
 }
 
        return ans;
 }
 
-static int div(int val)
+static int rk818_bat_read(struct rk818_battery *di, u8 reg)
 {
 {
-       return (val == 0) ? 1 : val;
+       int ret, val;
+
+       ret = regmap_read(di->regmap, reg, &val);
+       if (ret)
+               dev_err(di->dev, "read reg:0x%x failed\n", reg);
+
+       return val;
 }
 
 }
 
-static int rk81x_bat_read(struct rk81x_battery *di, u8 reg,
-                         u8 buf[], unsigned len)
+static int rk818_bat_write(struct rk818_battery *di, u8 reg, u8 buf)
 {
 {
-       int ret = -1;
-       int i;
+       int ret;
 
 
-       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);
-       }
+       ret = regmap_write(di->regmap, reg, buf);
+       if (ret)
+               dev_err(di->dev, "i2c write reg: 0x%2x error\n", reg);
 
 
-       return (ret < 0) ? ret : 0;
+       return ret;
 }
 
 }
 
-static int rk81x_bat_write(struct rk81x_battery *di, u8 reg,
-                          u8 const buf[], unsigned len)
+static int rk818_bat_set_bits(struct rk818_battery *di, u8 reg, u8 mask, u8 buf)
 {
 {
-       int ret = -1;
-       int i;
+       int 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);
-       }
+       ret = regmap_update_bits(di->regmap, reg, mask, buf);
+       if (ret)
+               dev_err(di->dev, "write reg:0x%x failed\n", reg);
 
 
-       return (ret < 0) ? ret : 0;
+       return ret;
 }
 
 }
 
-static int rk81x_bat_set_bit(struct rk81x_battery *di, u8 reg, u8 shift)
+static int rk818_bat_clear_bits(struct rk818_battery *di, u8 reg, u8 mask)
 {
 {
-       int ret = -1;
-       int i;
+       int ret;
 
 
-       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 = regmap_update_bits(di->regmap, reg, mask, 0);
+       if (ret)
+               dev_err(di->dev, "clr reg:0x%02x failed\n", reg);
 
        return ret;
 }
 
 
        return ret;
 }
 
-static int rk81x_bat_clr_bit(struct rk81x_battery *di, u8 reg, u8 shift)
+static void rk818_bat_dump_regs(struct rk818_battery *di, u8 start, u8 end)
 {
 {
-       int ret = -1;
        int i;
 
        int i;
 
-       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);
-       }
+       if (!dbg_enable)
+               return;
 
 
-       return ret;
+       DBG("dump regs from: 0x%x-->0x%x\n", start, end);
+       for (i = start; i < end; i++)
+               DBG("0x%x: 0x%0x\n", i, rk818_bat_read(di, i));
 }
 
 }
 
-static u8 rk81x_bat_read_bit(struct rk81x_battery *di, u8 reg, u8 shift)
+static bool rk818_bat_chrg_online(struct rk818_battery *di)
 {
        u8 buf;
 {
        u8 buf;
-       u8 val;
 
 
-       rk81x_bat_read(di, reg, &buf, 1);
-       val = (buf & BIT(shift)) >> shift;
-       return val;
+       buf = rk818_bat_read(di, RK818_VB_MON_REG);
+
+       return (buf & PLUG_IN_STS) ? true : false;
 }
 
 }
 
-static void rk81x_dbg_dmp_gauge_regs(struct rk81x_battery *di)
+static int rk818_bat_get_coulomb_cap(struct rk818_battery *di)
 {
 {
-       int i = 0;
-       u8 buf;
+       int val = 0;
 
 
-       DBG("%s dump charger register start:\n", __func__);
-       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");
+       val |= rk818_bat_read(di, RK818_GASCNT3_REG) << 24;
+       val |= rk818_bat_read(di, RK818_GASCNT2_REG) << 16;
+       val |= rk818_bat_read(di, RK818_GASCNT1_REG) << 8;
+       val |= rk818_bat_read(di, RK818_GASCNT0_REG) << 0;
+
+       return (val / 2390) * di->res_div;
 }
 
 }
 
-static void rk81x_dbg_dmp_charger_regs(struct rk81x_battery *di)
+static int rk818_bat_get_rsoc(struct rk818_battery *di)
 {
 {
-       int i = 0;
-       char buf;
+       int remain_cap;
 
 
-       DBG("%s dump the register start:\n", __func__);
-       for (i = 0x99; i < 0xAB; i++) {
-               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");
+       remain_cap = rk818_bat_get_coulomb_cap(di);
+       return (remain_cap + di->fcc / 200) * 100 / DIV(di->fcc);
 }
 
 }
 
-static void rk81x_bat_reset_zero_var(struct rk81x_battery *di)
+static ssize_t bat_info_store(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
 {
 {
-       di->dischrg_algorithm_mode = DISCHRG_NORMAL_MODE;
-       di->last_zero_mode_dsoc = DEF_LAST_ZERO_MODE_SOC;
-}
+       char cmd;
+       struct rk818_battery *di = dev_get_drvdata(dev);
+
+       sscanf(buf, "%c", &cmd);
+
+       if (cmd == 'n')
+               rk818_bat_set_bits(di, RK818_MISC_MARK_REG,
+                                  FG_RESET_NOW, FG_RESET_NOW);
+       else if (cmd == 'm')
+               rk818_bat_set_bits(di, RK818_MISC_MARK_REG,
+                                  FG_RESET_LATE, FG_RESET_LATE);
+       else if (cmd == 'c')
+               rk818_bat_clear_bits(di, RK818_MISC_MARK_REG,
+                                    FG_RESET_LATE | FG_RESET_NOW);
+       else if (cmd == 'r')
+               BAT_INFO("0x%2x\n", rk818_bat_read(di, RK818_MISC_MARK_REG));
+       else
+               BAT_INFO("command error\n");
 
 
-static void rk81x_bat_capacity_init_post(struct rk81x_battery *di)
-{
-       rk81x_bat_reset_zero_var(di);
-       di->trend_start_cap = di->remain_capacity;
+       return count;
 }
 
 }
 
-static void rk81x_bat_capacity_init(struct rk81x_battery *di, u32 capacity)
+static struct device_attribute rk818_bat_attr[] = {
+       __ATTR(bat, 0664, NULL, bat_info_store),
+};
+
+static void rk818_bat_enable_gauge(struct rk818_battery *di)
 {
        u8 buf;
 {
        u8 buf;
-       u32 capacity_ma;
-       int delta_cap;
 
 
-       delta_cap = capacity - di->remain_capacity;
-       if (!delta_cap)
-               return;
+       buf = rk818_bat_read(di, RK818_TS_CTRL_REG);
+       buf |= GG_EN;
+       rk818_bat_write(di, RK818_TS_CTRL_REG, buf);
+}
 
 
-       di->adjust_cap += delta_cap;
+static void rk818_bat_save_age_level(struct rk818_battery *di, u8 level)
+{
+       rk818_bat_write(di, RK818_UPDAT_LEVE_REG, level);
+}
 
 
-       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);
-
-       if (di->chrg_status != CHARGE_FINISH || di->dod0_status == 1)
-               dev_dbg(di->dev, "update capacity :%d--remain_cap:%d\n",
-                       capacity, di->remain_capacity);
+static u8 rk818_bat_get_age_level(struct  rk818_battery *di)
+{
+       return rk818_bat_read(di, RK818_UPDAT_LEVE_REG);
 }
 
 }
 
-#if RK818_SYS_DBG
-/*
- * 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)
+static int rk818_bat_get_vcalib0(struct rk818_battery *di)
 {
 {
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
-       int val;
+       int val = 0;
 
 
-       val = rk81x_bat_read_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
+       val |= rk818_bat_read(di, RK818_VCALIB0_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_VCALIB0_REGH) << 8;
 
 
-       return sprintf(buf, "%d\n", val);
+       DBG("<%s>. voffset0: 0x%x\n", __func__, val);
+       return val;
 }
 
 }
 
-static ssize_t bat_calib_write(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
+static int rk818_bat_get_vcalib1(struct rk818_battery *di)
 {
 {
-       u8 val;
-       int ret;
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
+       int val = 0;
 
 
-       ret = kstrtou8(buf, 0, &val);
-       if (ret < 0)
-               return ret;
+       val |= rk818_bat_read(di, RK818_VCALIB1_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_VCALIB1_REGH) << 8;
 
 
-       if (val)
-               rk81x_bat_set_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
-       else
-               rk81x_bat_clr_bit(di, MISC_MARK_REG, OCV_CALIB_SHIFT);
-       return count;
+       DBG("<%s>. voffset1: 0x%x\n", __func__, val);
+       return val;
 }
 
 }
 
-/*
- * interface for debug: force battery to over discharge
- */
-static ssize_t bat_test_power_read(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static int rk818_bat_get_ioffset(struct rk818_battery *di)
 {
 {
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
+       int val = 0;
 
 
-       return sprintf(buf, "%d\n", di->fg_drv_mode);
+       val |= rk818_bat_read(di, RK818_IOFFSET_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_IOFFSET_REGH) << 8;
+
+       DBG("<%s>. ioffset: 0x%x\n", __func__, val);
+       return val;
 }
 
 }
 
-static ssize_t bat_test_power_write(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
+static int rk818_bat_get_coffset(struct rk818_battery *di)
 {
 {
-       u8 val;
-       int ret;
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
+       int val = 0;
 
 
-       ret = kstrtou8(buf, 0, &val);
-       if (ret < 0)
-               return ret;
-
-       if (val == 1)
-               di->fg_drv_mode = TEST_POWER_MODE;
-       else
-               di->fg_drv_mode = FG_NORMAL_MODE;
+       val |= rk818_bat_read(di, RK818_CAL_OFFSET_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_CAL_OFFSET_REGH) << 8;
 
 
-       return count;
+       DBG("<%s>. coffset: 0x%x\n", __func__, val);
+       return val;
 }
 
 }
 
-static ssize_t bat_fcc_read(struct device *dev,
-                           struct device_attribute *attr, char *buf)
+static void rk818_bat_set_coffset(struct rk818_battery *di, int val)
 {
 {
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
+       u8 buf;
+
+       if ((val < INVALID_COFFSET_MIN) || (val > INVALID_COFFSET_MAX)) {
+               BAT_INFO("set invalid coffset=0x%x\n", val);
+               return;
+       }
 
 
-       return sprintf(buf, "%d\n", di->fcc);
+       buf = (val >> 8) & 0xff;
+       rk818_bat_write(di, RK818_CAL_OFFSET_REGH, buf);
+       buf = (val >> 0) & 0xff;
+       rk818_bat_write(di, RK818_CAL_OFFSET_REGL, buf);
+       DBG("<%s>. coffset: 0x%x\n", __func__, val);
 }
 
 }
 
-static ssize_t bat_fcc_write(struct device *dev,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
+static void rk818_bat_init_voltage_kb(struct rk818_battery *di)
 {
 {
-       u16 val;
-       int ret;
-       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)
-               return ret;
+       int vcalib0, vcalib1;
 
 
-       di->fcc = val;
+       vcalib0 = rk818_bat_get_vcalib0(di);
+       vcalib1 = rk818_bat_get_vcalib1(di);
+       di->voltage_k = (4200 - 3000) * 1000 / DIV(vcalib1 - vcalib0);
+       di->voltage_b = 4200 - (di->voltage_k * vcalib1) / 1000;
 
 
-       return count;
+       DBG("voltage_k=%d(*1000),voltage_b=%d\n", di->voltage_k, di->voltage_b);
 }
 
 }
 
-static ssize_t bat_dsoc_read(struct device *dev,
-                            struct device_attribute *attr, char *buf)
+static int rk818_bat_get_ocv_voltage(struct rk818_battery *di)
 {
 {
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
+       int vol, val = 0;
+
+       val |= rk818_bat_read(di, RK818_BAT_OCV_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_BAT_OCV_REGH) << 8;
 
 
-       return sprintf(buf, "%d\n", di->dsoc);
+       vol = di->voltage_k * val / 1000 + di->voltage_b;
+
+       return vol;
 }
 
 }
 
-static ssize_t bat_dsoc_write(struct device *dev,
-                             struct device_attribute *attr,
-                            const char *buf, size_t count)
+static int rk818_bat_get_avg_voltage(struct rk818_battery *di)
 {
 {
-       u8 val;
-       int ret;
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
+       int vol, val = 0;
 
 
-       ret = kstrtou8(buf, 0, &val);
-       if (ret < 0)
-               return ret;
+       val |= rk818_bat_read(di, RK818_BAT_VOL_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_BAT_VOL_REGH) << 8;
 
 
-       di->dsoc = val;
+       vol = di->voltage_k * val / 1000 + di->voltage_b;
 
 
-       return count;
+       return vol;
 }
 
 }
 
-static ssize_t bat_rsoc_read(struct device *dev,
-                            struct device_attribute *attr, char *buf)
+static bool is_rk818_bat_relax_mode(struct rk818_battery *di)
 {
 {
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
+       u8 status;
 
 
-       return sprintf(buf, "%d\n", di->rsoc);
+       status = rk818_bat_read(di, RK818_GGSTS_REG);
+       if (!(status & RELAX_VOL1_UPD) || !(status & RELAX_VOL2_UPD))
+               return false;
+       else
+               return true;
 }
 
 }
 
-static ssize_t bat_rsoc_write(struct device *dev,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
+static u16 rk818_bat_get_relax_vol1(struct rk818_battery *di)
 {
 {
-       u8 val;
-       int ret;
-       u32 capacity;
-       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;
+       u16 vol, val = 0;
 
 
-       capacity = di->fcc * val / 100;
-       rk81x_bat_capacity_init(di, capacity);
-       rk81x_bat_capacity_init_post(di);
+       val |= rk818_bat_read(di, RK818_RELAX_VOL1_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_RELAX_VOL1_REGH) << 8;
+       vol = di->voltage_k * val / 1000 + di->voltage_b;
 
 
-       return count;
+       return vol;
 }
 
 }
 
-static ssize_t bat_remain_cap_read(struct device *dev,
-                                  struct device_attribute *attr,
-                                  char *buf)
+static u16 rk818_bat_get_relax_vol2(struct rk818_battery *di)
 {
 {
-       struct power_supply *psy_bat = dev_get_drvdata(dev);
-       struct rk81x_battery *di = to_device_info(psy_bat);
+       u16 vol, val = 0;
 
 
-       return sprintf(buf, "%d\n", di->remain_capacity);
-}
+       val |= rk818_bat_read(di, RK818_RELAX_VOL2_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_RELAX_VOL2_REGH) << 8;
+       vol = di->voltage_k * val / 1000 + di->voltage_b;
 
 
-static struct device_attribute rk818_bat_attr[] = {
-       __ATTR(fcc, 0664, bat_fcc_read, bat_fcc_write),
-       __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(test_power, 0664, bat_test_power_read, bat_test_power_write),
-       __ATTR(calib, 0664, bat_calib_read, bat_calib_write),
-};
-#endif
+       return vol;
+}
 
 
-static int rk81x_bat_gauge_enable(struct rk81x_battery *di)
+static u16 rk818_bat_get_relax_voltage(struct rk818_battery *di)
 {
 {
-       int ret;
-       u8 buf;
+       u16 relax_vol1, relax_vol2;
 
 
-       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 (!is_rk818_bat_relax_mode(di))
+               return 0;
 
 
-       buf |= GG_EN;
-       rk81x_bat_write(di, TS_CTRL_REG, &buf, 1);
+       relax_vol1 = rk818_bat_get_relax_vol1(di);
+       relax_vol2 = rk818_bat_get_relax_vol2(di);
 
 
-       return 0;
+       return relax_vol1 > relax_vol2 ? relax_vol1 : relax_vol2;
 }
 
 }
 
-static void rk81x_bat_save_level(struct  rk81x_battery *di, u8 save_soc)
+static int rk818_bat_get_avg_current(struct rk818_battery *di)
 {
 {
-       rk81x_bat_write(di, UPDAT_LEVE_REG, &save_soc, 1);
-}
+       int cur, val = 0;
 
 
-static u8 rk81x_bat_get_level(struct  rk81x_battery *di)
-{
-       u8 soc;
+       val |= rk818_bat_read(di, RK818_BAT_CUR_AVG_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_BAT_CUR_AVG_REGH) << 8;
 
 
-       rk81x_bat_read(di, UPDAT_LEVE_REG, &soc, 1);
+       if (val & 0x800)
+               val -= 4096;
+       cur = val * di->res_div * 1506 / 1000;
 
 
-       return soc;
+       return cur;
 }
 
 }
 
-static int rk81x_bat_get_vcalib0(struct rk81x_battery *di)
+static int rk818_bat_vol_to_ocvsoc(struct rk818_battery *di, int voltage)
 {
 {
-       int ret;
-       int temp = 0;
-       u8 buf;
+       u32 *ocv_table, temp;
+       int ocv_size, ocv_soc;
 
 
-       ret = rk81x_bat_read(di, VCALIB0_REGL, &buf, 1);
-       temp = buf;
-       ret = rk81x_bat_read(di, VCALIB0_REGH, &buf, 1);
-       temp |= buf << 8;
+       ocv_table = di->pdata->ocv_table;
+       ocv_size = di->pdata->ocv_size;
+       temp = interpolate(voltage, ocv_table, ocv_size);
+       ocv_soc = ab_div_c(temp, MAX_PERCENTAGE, MAX_INTERPOLATE);
 
 
-       DBG("%s voltage0 offset vale is %d\n", __func__, temp);
-       return temp;
+       return ocv_soc;
 }
 
 }
 
-static int rk81x_bat_get_vcalib1(struct  rk81x_battery *di)
+static int rk818_bat_vol_to_ocvcap(struct rk818_battery *di, int voltage)
 {
 {
-       int ret;
-       int temp = 0;
-       u8 buf;
+       u32 *ocv_table, temp;
+       int ocv_size, cap;
 
 
-       ret = rk81x_bat_read(di, VCALIB1_REGL, &buf, 1);
-       temp = buf;
-       ret = rk81x_bat_read(di, VCALIB1_REGH, &buf, 1);
-       temp |= buf << 8;
+       ocv_table = di->pdata->ocv_table;
+       ocv_size = di->pdata->ocv_size;
+       temp = interpolate(voltage, ocv_table, ocv_size);
+       cap = ab_div_c(temp, di->fcc, MAX_INTERPOLATE);
 
 
-       DBG("%s voltage1 offset vale is %d\n", __func__, temp);
-       return temp;
+       return cap;
 }
 
 }
 
-static int rk81x_bat_get_ioffset(struct rk81x_battery *di)
+static int rk818_bat_vol_to_zerosoc(struct rk818_battery *di, int voltage)
 {
 {
-       int ret;
-       int temp = 0;
-       u8 buf;
+       u32 *ocv_table, temp;
+       int ocv_size, ocv_soc;
 
 
-       ret = rk81x_bat_read(di, IOFFSET_REGL, &buf, 1);
-       temp = buf;
-       ret = rk81x_bat_read(di, IOFFSET_REGH, &buf, 1);
-       temp |= buf << 8;
+       ocv_table = di->pdata->zero_table;
+       ocv_size = di->pdata->ocv_size;
+       temp = interpolate(voltage, ocv_table, ocv_size);
+       ocv_soc = ab_div_c(temp, MAX_PERCENTAGE, MAX_INTERPOLATE);
 
 
-       return temp;
+       return ocv_soc;
 }
 
 }
 
-static uint16_t rk81x_bat_get_cal_offset(struct rk81x_battery *di)
+static int rk818_bat_vol_to_zerocap(struct rk818_battery *di, int voltage)
 {
 {
-       int ret;
-       uint16_t temp = 0;
-       u8 buf;
+       u32 *ocv_table, temp;
+       int ocv_size, cap;
 
 
-       ret = rk81x_bat_read(di, CAL_OFFSET_REGL, &buf, 1);
-       temp = buf;
-       ret = rk81x_bat_read(di, CAL_OFFSET_REGH, &buf, 1);
-       temp |= buf << 8;
+       ocv_table = di->pdata->zero_table;
+       ocv_size = di->pdata->ocv_size;
+       temp = interpolate(voltage, ocv_table, ocv_size);
+       cap = ab_div_c(temp, di->fcc, MAX_INTERPOLATE);
 
 
-       return temp;
+       return cap;
 }
 
 }
 
-static int rk81x_bat_set_cal_offset(struct rk81x_battery *di, u32 value)
+static int rk818_bat_get_iadc(struct rk818_battery *di)
 {
 {
-       int ret;
-       u8 buf;
+       int val = 0;
 
 
-       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);
+       val |= rk818_bat_read(di, RK818_BAT_CUR_AVG_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_BAT_CUR_AVG_REGH) << 8;
+       if (val > 2047)
+               val -= 4096;
 
 
-       return 0;
+       return val;
 }
 
 }
 
-static void rk81x_bat_get_vol_offset(struct rk81x_battery *di)
+static bool rk818_bat_adc_calib(struct rk818_battery *di)
 {
 {
-       int vcalib0, vcalib1;
+       int i, ioffset, coffset, adc, save_coffset;
 
 
-       vcalib0 = rk81x_bat_get_vcalib0(di);
-       vcalib1 = rk81x_bat_get_vcalib1(di);
+       if ((di->chrg_status != CHARGE_FINISH) ||
+           (base2min(di->boot_base) < ADC_CALIB_LMT_MIN) ||
+           (abs(di->current_avg) < ADC_CALIB_THRESHOLD))
+               return false;
 
 
-       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);
+       save_coffset = rk818_bat_get_coffset(di);
+       for (i = 0; i < 5; i++) {
+               adc = rk818_bat_get_iadc(di);
+               if (!rk818_bat_chrg_online(di)) {
+                       rk818_bat_set_coffset(di, save_coffset);
+                       BAT_INFO("quit, charger plugout when calib adc\n");
+                       return false;
+               }
+               coffset = rk818_bat_get_coffset(di);
+               rk818_bat_set_coffset(di, coffset + adc);
+               msleep(2000);
+               adc = rk818_bat_get_iadc(di);
+               if (abs(adc) < ADC_CALIB_THRESHOLD) {
+                       coffset = rk818_bat_get_coffset(di);
+                       ioffset = rk818_bat_get_ioffset(di);
+                       di->poffset = coffset - ioffset;
+                       rk818_bat_write(di, RK818_POFFSET_REG, di->poffset);
+                       BAT_INFO("new offset:c=0x%x, i=0x%x, p=0x%x\n",
+                                coffset, ioffset, di->poffset);
+                       return true;
+               } else {
+                       BAT_INFO("coffset calib again %d..\n", i);
+                       rk818_bat_set_coffset(di, coffset);
+                       msleep(2000);
+               }
+       }
+
+       return false;
 }
 
 }
 
-static uint16_t rk81x_bat_get_ocv_vol(struct rk81x_battery *di)
+static void rk818_bat_set_ioffset_sample(struct rk818_battery *di)
 {
 {
-       int ret;
-       u8 buf;
-       uint16_t temp;
-       uint16_t voltage_now = 0;
-       int i;
-       int val[3];
+       u8 ggcon;
 
 
-       for (i = 0; i < 3; i++) {
-               ret = rk81x_bat_read(di, BAT_OCV_REGL, &buf, 1);
-               val[i] = buf;
-               ret = rk81x_bat_read(di, BAT_OCV_REGH, &buf, 1);
-               val[i] |= buf << 8;
+       ggcon = rk818_bat_read(di, RK818_GGCON_REG);
+       ggcon &= ~ADC_CAL_MIN_MSK;
+       ggcon |= ADC_CAL_8MIN;
+       rk818_bat_write(di, RK818_GGCON_REG, ggcon);
+}
 
 
-               if (ret < 0) {
-                       dev_err(di->dev, "error read BAT_OCV_REGH");
-                       return ret;
-               }
-       }
+static void rk818_bat_set_ocv_sample(struct rk818_battery *di)
+{
+       u8 ggcon;
 
 
-       if (val[0] == val[1])
-               temp = val[0];
-       else
-               temp = val[2];
+       ggcon = rk818_bat_read(di, RK818_GGCON_REG);
+       ggcon &= ~OCV_SAMP_MIN_MSK;
+       ggcon |= OCV_SAMP_8MIN;
+       rk818_bat_write(di, RK818_GGCON_REG, ggcon);
+}
 
 
-       voltage_now = di->voltage_k * temp / 1000 + di->voltage_b;
+static void rk818_bat_restart_relax(struct rk818_battery *di)
+{
+       u8 ggsts;
 
 
-       return voltage_now;
+       ggsts = rk818_bat_read(di, RK818_GGSTS_REG);
+       ggsts &= ~RELAX_VOL12_UPD_MSK;
+       rk818_bat_write(di, RK818_GGSTS_REG, ggsts);
 }
 
 }
 
-static int rk81x_bat_get_vol(struct rk81x_battery *di)
+static void rk818_bat_set_relax_sample(struct rk818_battery *di)
 {
 {
-       int ret;
-       int vol;
        u8 buf;
        u8 buf;
-       int temp;
-       int val[3];
-       int i;
+       int enter_thres, exit_thres;
+       struct battery_platform_data *pdata = di->pdata;
 
 
-       for (i = 0; i < 3; i++) {
-               ret = rk81x_bat_read(di, BAT_VOL_REGL, &buf, 1);
-               val[i] = buf;
-               ret = rk81x_bat_read(di, BAT_VOL_REGH, &buf, 1);
-               val[i] |= buf << 8;
+       enter_thres = pdata->sleep_enter_current * 1000 / 1506 / di->res_div;
+       exit_thres = pdata->sleep_exit_current * 1000 / 1506 / di->res_div;
 
 
-               if (ret < 0) {
-                       dev_err(di->dev, "error read BAT_VOL_REGH");
-                       return ret;
-               }
-       }
-       /*check value*/
-       if (val[0] == val[1])
-               temp = val[0];
-       else
-               temp = val[2];
-
-       vol = di->voltage_k * temp / 1000 + di->voltage_b;
-
-       return vol;
-}
-
-static bool is_rk81x_bat_relax_mode(struct rk81x_battery *di)
-{
-       int ret;
-       u8 status;
-
-       ret = rk81x_bat_read(di, GGSTS, &status, 1);
-
-       if ((!(status & RELAX_VOL1_UPD)) || (!(status & RELAX_VOL2_UPD)))
-               return false;
-       else
-               return true;
-}
-
-static uint16_t rk81x_bat_get_relax_vol1(struct rk81x_battery *di)
-{
-       int ret;
-       u8 buf;
-       uint16_t temp = 0, voltage_now;
-
-       ret = rk81x_bat_read(di, RELAX_VOL1_REGL, &buf, 1);
-       temp = buf;
-       ret = rk81x_bat_read(di, RELAX_VOL1_REGH, &buf, 1);
-       temp |= (buf << 8);
-
-       voltage_now = di->voltage_k * temp / 1000 + di->voltage_b;
-
-       return voltage_now;
-}
-
-static uint16_t rk81x_bat_get_relax_vol2(struct rk81x_battery *di)
-{
-       int ret;
-       u8 buf;
-       uint16_t temp = 0, voltage_now;
-
-       ret = rk81x_bat_read(di, RELAX_VOL2_REGL, &buf, 1);
-       temp = buf;
-       ret = rk81x_bat_read(di, RELAX_VOL2_REGH, &buf, 1);
-       temp |= (buf << 8);
-
-       voltage_now = di->voltage_k * temp / 1000 + di->voltage_b;
-
-       return voltage_now;
-}
-
-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 val;
-
-       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;
-       }
-       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;
-       }
-       val |= (buf << 8);
-
-       if (ret < 0) {
-               dev_err(di->dev, "error reading BAT_CUR_AVG_REGH");
-               return ret;
-       }
-
-       if (val > 2047)
-               val -= 4096;
-
-       return val;
-}
-
-static void rk81x_bat_ioffset_sample_set(struct rk81x_battery *di, int time)
-{
-       u8 ggcon;
-
-       rk81x_bat_read(di, GGCON, &ggcon, 1);
-       ggcon &= ~(0x30); /*clear <5:4>*/
-       ggcon |= time;
-       rk81x_bat_write(di, GGCON, &ggcon, 1);
-}
-
-/*
- * when charger finish signal comes, we need calibrate the current, make it
- * close to 0.
- */
-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 = 0;
-       u8 retry = 0;
-       bool ret = true;
-
-       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 = rk81x_bat_get_raw_adc_current(di);
-                       if (!rk81x_chrg_online(di) || abs(adc_value) > 30) {
-                               dev_warn(di->dev, "charger plugout\n");
-                               ret = true;
-                               break;
-                       }
-
-                       DBG("<%s>. adc_value = %d\n", __func__, adc_value);
-                       C0 = rk81x_bat_get_cal_offset(di);
-                       C1 = adc_value + C0;
-                       DBG("<%s>. C0(cal_offset) = %d, C1 = %d\n",
-                           __func__, C0, C1);
-                       rk81x_bat_set_cal_offset(di, C1);
-                       DBG("<%s>. new cal_offset = %d\n",
-                           __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 (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;
-                                       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 {
-                               dev_dbg(di->dev, "ioffset cal failed\n");
-                               rk81x_bat_set_cal_offset(di, C0);
-                       }
-
-                       di->pcb_ioffset_updated  = false;
-               }
-       }
-
-       return ret;
-}
-
-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;
-       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;
-       rk81x_bat_write(di, RELAX_ENTRY_THRES_REGL, &buf, 1);
+       /* set relax enter and exit threshold */
+       buf = enter_thres & 0xff;
+       rk818_bat_write(di, RK818_RELAX_ENTRY_THRES_REGL, buf);
        buf = (enter_thres >> 8) & 0xff;
        buf = (enter_thres >> 8) & 0xff;
-       rk81x_bat_write(di, RELAX_ENTRY_THRES_REGH, &buf, 1);
+       rk818_bat_write(di, RK818_RELAX_ENTRY_THRES_REGH, buf);
 
 
-       buf  = exit_thres & 0xff;
-       rk81x_bat_write(di, RELAX_EXIT_THRES_REGL, &buf, 1);
+       buf = exit_thres & 0xff;
+       rk818_bat_write(di, RK818_RELAX_EXIT_THRES_REGL, buf);
        buf = (exit_thres >> 8) & 0xff;
        buf = (exit_thres >> 8) & 0xff;
-       rk81x_bat_write(di, RELAX_EXIT_THRES_REGH, &buf, 1);
-
-       /* set sample time */
-       rk81x_bat_read(di, GGCON, &buf, 1);
-       buf &= ~(3 << 2);/*8min*/
-       buf &= ~0x01; /* clear bat_res calc*/
-       rk81x_bat_write(di, GGCON, &buf, 1);
-}
+       rk818_bat_write(di, RK818_RELAX_EXIT_THRES_REGH, buf);
 
 
-static void rk81x_bat_restart_relax(struct rk81x_battery *di)
-{
-       u8 ggcon;
-       u8 ggsts;
-
-       rk81x_bat_read(di, GGCON, &ggcon, 1);
-       ggcon &= ~0x0c;
-       rk81x_bat_write(di, GGCON, &ggcon, 1);
-
-       rk81x_bat_read(di, GGSTS, &ggsts, 1);
-       ggsts &= ~0x0c;
-       rk81x_bat_write(di, GGSTS, &ggsts, 1);
+       /* reset relax update state */
+       rk818_bat_restart_relax(di);
+       DBG("<%s>. sleep_enter_current = %d, sleep_exit_current = %d\n",
+           __func__, pdata->sleep_enter_current, pdata->sleep_exit_current);
 }
 
 }
 
-static int rk81x_bat_get_avg_current(struct rk81x_battery *di)
+static bool is_rk818_bat_exist(struct rk818_battery *di)
 {
 {
-       u8  buf;
-       int ret;
-       int current_now;
-       int temp;
-       int val[3];
-       int i;
-
-       for (i = 0; i < 3; i++) {
-               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 = 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;
-               }
-               val[i] |= (buf<<8);
-       }
-       /*check value*/
-       if (val[0] == val[1])
-               current_now = val[0];
-       else
-               current_now = val[2];
-
-       if (current_now & 0x800)
-               current_now -= 4096;
-
-       temp = current_now * 1506 / 1000;/*1000*90/14/4096*500/521;*/
-
-       return temp;
+       return (rk818_bat_read(di, RK818_SUP_STS_REG) & BAT_EXS) ? true : false;
 }
 
 }
 
-static void rk81x_bat_set_power_supply_state(struct rk81x_battery *di,
-                                            enum charger_type  charger_type)
+static bool is_rk818_bat_first_pwron(struct rk818_battery *di)
 {
 {
-       di->usb_online = OFFLINE;
-       di->ac_online = OFFLINE;
-       di->dc_online = OFFLINE;
+       u8 buf;
 
 
-       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*/
-               di->dc_online = ONLINE;
-       case AC_CHARGER:
-               di->ac_online = ONLINE;
-               di->psy_status = POWER_SUPPLY_STATUS_CHARGING;
-               break;
-       default:
-               di->psy_status = POWER_SUPPLY_STATUS_DISCHARGING;
+       buf = rk818_bat_read(di, RK818_GGSTS_REG);
+       if (buf & BAT_CON) {
+               buf &= ~BAT_CON;
+               rk818_bat_write(di, RK818_GGSTS_REG, buf);
+               return true;
        }
 
        }
 
-       if (di->wq)
-               queue_delayed_work(di->wq, &di->chrg_term_mode_switch_work,
-                                  msecs_to_jiffies(1000));
+       return false;
 }
 
 }
 
-/* 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 u8 rk818_bat_get_pwroff_min(struct rk818_battery *di)
 {
 {
-       static u64 time;
-       int pwr_off_thresd = di->pdata->power_off_thresd;
-
-       if (di->current_avg < 0 &&  di->voltage < pwr_off_thresd) {
-               if (!time)
-                       time = get_runtime_sec();
+       u8 cur, last;
 
 
-               if (BASE_TO_SEC(time) > (MINUTE)) {
-                       rk81x_bat_set_power_supply_state(di, NO_CHARGER);
-                       dev_info(di->dev, "low power....\n");
-               }
+       cur = rk818_bat_read(di, RK818_NON_ACT_TIMER_CNT_REG);
+       last = rk818_bat_read(di, RK818_NON_ACT_TIMER_CNT_SAVE_REG);
+       rk818_bat_write(di, RK818_NON_ACT_TIMER_CNT_SAVE_REG, cur);
 
 
-               if (di->voltage <= pwr_off_thresd - 50) {
-                       di->dsoc--;
-                       rk81x_bat_set_power_supply_state(di, NO_CHARGER);
-               }
-       } else {
-               time = 0;
-       }
+       return (cur != last) ? cur : 0;
 }
 
 }
 
-static int is_rk81x_bat_exist(struct  rk81x_battery *di)
+static u8 is_rk818_bat_initialized(struct rk818_battery *di)
 {
 {
-       u8 buf;
-
-       rk81x_bat_read(di, SUP_STS_REG, &buf, 1);
+       u8 val = rk818_bat_read(di, RK818_MISC_MARK_REG);
 
 
-       return (buf & 0x80) ? 1 : 0;
-}
-
-static bool is_rk81x_bat_first_poweron(struct  rk81x_battery *di)
-{
-       u8 buf;
-       u8 temp;
-
-       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 {
-                       rk81x_bat_write(di, GGSTS, &buf, 1);
-                       rk81x_bat_read(di, GGSTS, &temp, 1);
-               } while (temp & BAT_CON);
+       if (val & FG_INIT) {
+               val &= ~FG_INIT;
+               rk818_bat_write(di, RK818_MISC_MARK_REG, val);
                return true;
                return true;
+       } else {
+               return false;
        }
        }
-
-       return false;
 }
 
 }
 
-static void rk81x_bat_flatzone_vol_init(struct rk81x_battery *di)
+static bool is_rk818_bat_ocv_valid(struct rk818_battery *di)
 {
 {
-       u32 *ocv_table;
-       int ocv_size;
-       int temp_table[21];
-       int i, j;
-
-       ocv_table = di->pdata->battery_ocv;
-       ocv_size = di->pdata->ocv_size;
-
-       for (j = 0; j < 21; j++)
-               temp_table[j] = 0;
-
-       j = 0;
-       for (i = 1; i < ocv_size-1; i++) {
-               if (ocv_table[i+1] < ocv_table[i] + 20)
-                       temp_table[j++] = i;
-       }
-
-       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;
-       }
-
-       i = temp_table[j];
-       di->exit_flatzone = ocv_table[i];
-
-       DBG("enter_flatzone = %d exit_flatzone = %d\n",
-           di->enter_flatzone, di->exit_flatzone);
+       return (!di->is_initialized && di->pwroff_min >= 30) ? true : false;
 }
 
 }
 
-static void rk81x_bat_power_on_save(struct rk81x_battery *di, int ocv_voltage)
+static void rk818_bat_init_age_algorithm(struct rk818_battery *di)
 {
 {
-       u8 ocv_valid, first_pwron;
-       u8 soc_level;
-       u8 ocv_soc;
-
-       /*buf==1: OCV_VOL is valid*/
-       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);
+       int age_level, ocv_soc, ocv_cap, ocv_vol;
 
 
-       if (first_pwron == 1 || ocv_valid == 1) {
+       if (di->is_first_power_on || is_rk818_bat_ocv_valid(di)) {
                DBG("<%s> enter.\n", __func__);
                DBG("<%s> enter.\n", __func__);
-               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->temp_nac;
-                       di->adjust_cap = 0;
-                       di->dod0 = ocv_soc;
+               ocv_vol = rk818_bat_get_ocv_voltage(di);
+               ocv_soc = rk818_bat_vol_to_ocvsoc(di, ocv_vol);
+               ocv_cap = rk818_bat_vol_to_ocvcap(di, ocv_vol);
+               if (ocv_soc < 20) {
+                       di->age_voltage = ocv_vol;
+                       di->age_ocv_cap = ocv_cap;
+                       di->age_ocv_soc = ocv_soc;
+                       di->age_adjust_cap = 0;
 
                        if (ocv_soc <= 0)
 
                        if (ocv_soc <= 0)
-                               di->dod0_level = 100;
+                               di->age_level = 100;
                        else if (ocv_soc < 5)
                        else if (ocv_soc < 5)
-                               di->dod0_level = 95;
+                               di->age_level = 95;
                        else if (ocv_soc < 10)
                        else if (ocv_soc < 10)
-                               di->dod0_level = 90;
+                               di->age_level = 90;
                        else
                        else
-                               di->dod0_level = 80;
-                       /* save_soc = di->dod0_level; */
-                       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);
+                               di->age_level = 80;
+
+                       age_level = rk818_bat_get_age_level(di);
+                       if (age_level > di->age_level) {
+                               di->age_allow_update = false;
+                               age_level -= 5;
+                               if (age_level <= 80)
+                                       age_level = 80;
+                               rk818_bat_save_age_level(di, age_level);
                        } else {
                        } else {
-                               di->dod0_status = 1;
-                               /*time start*/
-                               di->fcc_update_sec = get_runtime_sec();
+                               di->age_allow_update = true;
+                               di->age_keep_sec = get_boot_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);
+                       BAT_INFO("init_age_algorithm: "
+                                "age_vol:%d, age_ocv_cap:%d, "
+                                "age_ocv_soc:%d, old_age_level:%d, "
+                                "age_allow_update:%d, new_age_level:%d\n",
+                                di->age_voltage, di->age_ocv_cap,
+                                ocv_soc, age_level, di->age_allow_update,
+                                di->age_level);
                }
        }
 }
 
                }
        }
 }
 
-static int rk81x_bat_get_rsoc(struct   rk81x_battery *di)
-{
-       return (di->remain_capacity + di->fcc / 200) * 100 / div(di->fcc);
-}
-
-static enum power_supply_property rk_battery_props[] = {
-       POWER_SUPPLY_PROP_STATUS,
+static enum power_supply_property rk818_bat_props[] = {
        POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_HEALTH,
        POWER_SUPPLY_PROP_CAPACITY,
        POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_HEALTH,
        POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
 };
 
 };
 
-static int rk81x_battery_get_property(struct power_supply *psy,
+static int rk818_battery_get_property(struct power_supply *psy,
                                      enum power_supply_property psp,
                                      union power_supply_propval *val)
 {
                                      enum power_supply_property psp,
                                      union power_supply_propval *val)
 {
-       struct rk81x_battery *di = to_device_info(psy);
+       struct rk818_battery *di = power_supply_get_drvdata(psy);
 
        switch (psp) {
        case POWER_SUPPLY_PROP_CURRENT_NOW:
                val->intval = di->current_avg * 1000;/*uA*/
 
        switch (psp) {
        case POWER_SUPPLY_PROP_CURRENT_NOW:
                val->intval = di->current_avg * 1000;/*uA*/
-               if (di->fg_drv_mode == TEST_POWER_MODE)
-                       val->intval = TEST_CURRENT * 1000;
+               if (di->pdata->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_CURRENT * 1000;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               val->intval = di->voltage * 1000;/*uV*/
-               if (di->fg_drv_mode == TEST_POWER_MODE)
-                       val->intval = TEST_VOLTAGE * 1000;
-
+               val->intval = di->voltage_avg * 1000;/*uV*/
+               if (di->pdata->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_VOLTAGE * 1000;
                break;
        case POWER_SUPPLY_PROP_PRESENT:
                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;
-
+               val->intval = is_rk818_bat_exist(di);
+               if (di->pdata->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_PRESET;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
                val->intval = di->dsoc;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
                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);
+               if (di->pdata->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_SOC;
+               DBG("<%s>. report dsoc: %d\n", __func__, val->intval);
                break;
        case POWER_SUPPLY_PROP_HEALTH:
                val->intval = POWER_SUPPLY_HEALTH_GOOD;
                break;
                break;
        case POWER_SUPPLY_PROP_HEALTH:
                val->intval = POWER_SUPPLY_HEALTH_GOOD;
                break;
-       case POWER_SUPPLY_PROP_STATUS:
-               val->intval = di->psy_status;
-               if (di->fg_drv_mode == TEST_POWER_MODE)
-                       val->intval = TEST_STATUS;
-
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = di->temperature;
+               if (di->pdata->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_TEMPERATURE;
                break;
        default:
                return -EINVAL;
                break;
        default:
                return -EINVAL;
@@ -1459,2960 +875,2334 @@ static int rk81x_battery_get_property(struct power_supply *psy,
        return 0;
 }
 
        return 0;
 }
 
-static enum power_supply_property rk_battery_ac_props[] = {
-       POWER_SUPPLY_PROP_ONLINE,
+static const struct power_supply_desc rk818_bat_desc = {
+       .name           = "battery",
+       .type           = POWER_SUPPLY_TYPE_BATTERY,
+       .properties     = rk818_bat_props,
+       .num_properties = ARRAY_SIZE(rk818_bat_props),
+       .get_property   = rk818_battery_get_property,
 };
 
 };
 
-static enum power_supply_property rk_battery_usb_props[] = {
-       POWER_SUPPLY_PROP_ONLINE,
-};
-
-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 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;
-       }
-       return ret;
-}
-
-static int rk81x_battery_usb_get_property(struct power_supply *psy,
-                                         enum power_supply_property psp,
-                                         union power_supply_propval *val)
+static int rk818_bat_init_power_supply(struct rk818_battery *di)
 {
 {
-       int ret = 0;
-       struct rk81x_battery *di = to_usb_device_info(psy);
+       struct power_supply_config psy_cfg = { .drv_data = di, };
 
 
-       switch (psp) {
-       case POWER_SUPPLY_PROP_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;
-       }
-
-       return ret;
-}
-
-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;
-       di->bat.num_properties = ARRAY_SIZE(rk_battery_props);
-       di->bat.get_property = rk81x_battery_get_property;
-
-       di->ac.name = "AC";
-       di->ac.type = POWER_SUPPLY_TYPE_MAINS;
-       di->ac.properties = rk_battery_ac_props;
-       di->ac.num_properties = ARRAY_SIZE(rk_battery_ac_props);
-       di->ac.get_property = rk81x_battery_ac_get_property;
-
-       di->usb.name = "USB";
-       di->usb.type = POWER_SUPPLY_TYPE_USB;
-       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;
-
-       ret = power_supply_register(di->dev, &di->bat);
-       if (ret) {
-               dev_err(di->dev, "failed to register main battery\n");
-               goto batt_failed;
-       }
-       ret = power_supply_register(di->dev, &di->usb);
-       if (ret) {
-               dev_err(di->dev, "failed to register usb power supply\n");
-               goto usb_failed;
-       }
-       ret = power_supply_register(di->dev, &di->ac);
-       if (ret) {
-               dev_err(di->dev, "failed to register ac power supply\n");
-               goto ac_failed;
+       di->bat = devm_power_supply_register(di->dev, &rk818_bat_desc, &psy_cfg);
+       if (IS_ERR(di->bat)) {
+               dev_err(di->dev, "register bat power supply fail\n");
+               return PTR_ERR(di->bat);
        }
 
        return 0;
        }
 
        return 0;
-
-ac_failed:
-       power_supply_unregister(&di->ac);
-usb_failed:
-       power_supply_unregister(&di->usb);
-batt_failed:
-       power_supply_unregister(&di->bat);
-
-       return ret;
 }
 
 }
 
-static void rk81x_bat_save_remain_capacity(struct rk81x_battery *di,
-                                          int capacity)
+static void rk818_bat_save_cap(struct rk818_battery *di, int cap)
 {
        u8 buf;
 {
        u8 buf;
-       static u32 capacity_ma;
+       static u32 old_cap;
 
 
-       if (capacity >= di->qmax)
-               capacity = di->qmax;
-
-       if (capacity <= 0)
-               capacity = 0;
-
-       if (capacity_ma == capacity)
+       if (cap >= di->qmax)
+               cap = di->qmax;
+       if (cap <= 0)
+               cap = 0;
+       if (old_cap == cap)
                return;
 
                return;
 
-       capacity_ma = capacity;
-
-       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);
+       old_cap = cap;
+       buf = (cap >> 24) & 0xff;
+       rk818_bat_write(di, RK818_REMAIN_CAP_REG3, buf);
+       buf = (cap >> 16) & 0xff;
+       rk818_bat_write(di, RK818_REMAIN_CAP_REG2, buf);
+       buf = (cap >> 8) & 0xff;
+       rk818_bat_write(di, RK818_REMAIN_CAP_REG1, buf);
+       buf = (cap >> 0) & 0xff;
+       rk818_bat_write(di, RK818_REMAIN_CAP_REG0, buf);
 }
 
 }
 
-static int rk81x_bat_get_remain_capacity(struct rk81x_battery *di)
+static int rk818_bat_get_prev_cap(struct rk818_battery *di)
 {
 {
-       int ret;
-       u8 buf;
-       u32 capacity;
-       int i;
-       int val[3];
-
-       for (i = 0; i < 3; i++) {
-               ret = rk81x_bat_read(di, REMAIN_CAP_REG3, &buf, 1);
-               val[i] = buf << 24;
-               ret = rk81x_bat_read(di, REMAIN_CAP_REG2, &buf, 1);
-               val[i] |= buf << 16;
-               ret = rk81x_bat_read(di, REMAIN_CAP_REG1, &buf, 1);
-               val[i] |= buf << 8;
-               ret = rk81x_bat_read(di, REMAIN_CAP_REG0, &buf, 1);
-               val[i] |= buf;
-       }
+       int val = 0;
 
 
-       if (val[0] == val[1])
-               capacity = val[0];
-       else
-               capacity = val[2];
+       val |= rk818_bat_read(di, RK818_REMAIN_CAP_REG3) << 24;
+       val |= rk818_bat_read(di, RK818_REMAIN_CAP_REG2) << 16;
+       val |= rk818_bat_read(di, RK818_REMAIN_CAP_REG1) << 8;
+       val |= rk818_bat_read(di, RK818_REMAIN_CAP_REG0) << 0;
 
 
-       return capacity;
+       return val;
 }
 
 }
 
-static void rk81x_bat_save_fcc(struct rk81x_battery *di, u32 capacity)
+static void rk818_bat_save_fcc(struct rk818_battery *di, u32 fcc)
 {
        u8 buf;
 {
        u8 buf;
-       u32 capacity_ma;
-
-       capacity_ma = capacity;
-       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 rk81x_bat_get_fcc(struct rk81x_battery *di)
-{
-       u8 buf;
-       u32 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);
-       }
+       buf = (fcc >> 24) & 0xff;
+       rk818_bat_write(di, RK818_NEW_FCC_REG3, buf);
+       buf = (fcc >> 16) & 0xff;
+       rk818_bat_write(di, RK818_NEW_FCC_REG2, buf);
+       buf = (fcc >> 8) & 0xff;
+       rk818_bat_write(di, RK818_NEW_FCC_REG1, buf);
+       buf = (fcc >> 0) & 0xff;
+       rk818_bat_write(di, RK818_NEW_FCC_REG0, buf);
 
 
-       return capacity;
+       BAT_INFO("save fcc: %d\n", fcc);
 }
 
 }
 
-static int rk81x_bat_get_realtime_capacity(struct rk81x_battery *di)
+static int rk818_bat_get_fcc(struct rk818_battery *di)
 {
 {
-       int ret;
-       int temp = 0;
-       u8 buf;
-       u32 capacity;
-       int i;
-       int val[3];
-
-       for (i = 0; i < 3; i++) {
-               ret = rk81x_bat_read(di, GASCNT3, &buf, 1);
-               val[i] = buf << 24;
-               ret = rk81x_bat_read(di, GASCNT2, &buf, 1);
-               val[i] |= buf << 16;
-               ret = rk81x_bat_read(di, GASCNT1, &buf, 1);
-               val[i] |= buf << 8;
-               ret = rk81x_bat_read(di, GASCNT0, &buf, 1);
-               val[i] |= buf;
-       }
-       if (val[0] == val[1])
-               temp = val[0];
-       else
-               temp = val[2];
+       u32 fcc = 0;
 
 
-       capacity = temp / 2390;/* 4096*900/14/36*500/521; */
+       fcc |= rk818_bat_read(di, RK818_NEW_FCC_REG3) << 24;
+       fcc |= rk818_bat_read(di, RK818_NEW_FCC_REG2) << 16;
+       fcc |= rk818_bat_read(di, RK818_NEW_FCC_REG1) << 8;
+       fcc |= rk818_bat_read(di, RK818_NEW_FCC_REG0) << 0;
 
 
-       return capacity;
-}
-
-static int rk81x_bat_save_dsoc(struct  rk81x_battery *di, u8 save_soc)
-{
-       static u8 last_soc;
-
-       if (last_soc != save_soc) {
-               rk81x_bat_write(di, SOC_REG, &save_soc, 1);
-               last_soc = save_soc;
+       if (fcc < MIN_FCC) {
+               BAT_INFO("invalid fcc(%d), use design cap", fcc);
+               fcc = di->pdata->design_capacity;
+               rk818_bat_save_fcc(di, fcc);
+       } else if (fcc > di->pdata->design_qmax) {
+               BAT_INFO("invalid fcc(%d), use qmax", fcc);
+               fcc = di->pdata->design_qmax;
+               rk818_bat_save_fcc(di, fcc);
        }
 
        }
 
-       return 0;
-}
-
-static int rk81x_bat_save_reboot_cnt(struct  rk81x_battery *di, u8 save_cnt)
-{
-       u8 cnt;
-
-       cnt = save_cnt;
-       rk81x_bat_write(di, REBOOT_CNT_REG, &cnt, 1);
-       return 0;
+       return fcc;
 }
 
 }
 
-static void rk81x_bat_set_current(struct rk81x_battery *di, int charge_current)
+static void rk818_bat_init_coulomb_cap(struct rk818_battery *di, u32 capacity)
 {
 {
-       u8 usb_ctrl_reg;
+       u8 buf;
+       u32 cap;
 
 
-       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);
-}
+       cap = capacity * 2390 / di->res_div;
+       buf = (cap >> 24) & 0xff;
+       rk818_bat_write(di, RK818_GASCNT_CAL_REG3, buf);
+       buf = (cap >> 16) & 0xff;
+       rk818_bat_write(di, RK818_GASCNT_CAL_REG2, buf);
+       buf = (cap >> 8) & 0xff;
+       rk818_bat_write(di, RK818_GASCNT_CAL_REG1, buf);
+       buf = ((cap >> 0) & 0xff);
+       rk818_bat_write(di, RK818_GASCNT_CAL_REG0, buf);
 
 
-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);
-       }
+       DBG("<%s>. new coulomb cap = %d\n", __func__, capacity);
+       di->remain_cap = capacity;
+       di->rsoc = rk818_bat_get_rsoc(di);
 }
 
 }
 
-#if defined(CONFIG_ARCH_ROCKCHIP)
-
-static void rk81x_bat_set_charger_param(struct rk81x_battery *di,
-                                       enum charger_type charger_type)
+static void rk818_bat_save_dsoc(struct rk818_battery *di, u8 save_soc)
 {
 {
-       rk81x_bat_set_chrg_current(di, charger_type);
-       rk81x_bat_set_power_supply_state(di, charger_type);
+       static int last_soc = -1;
 
 
-       switch (charger_type) {
-       case NO_CHARGER:
-               power_supply_changed(&di->bat);
-               break;
-       case USB_CHARGER:
-       case AC_CHARGER:
-               power_supply_changed(&di->usb);
-               break;
-       case DC_CHARGER:
-               power_supply_changed(&di->ac);
-               break;
-       default:
-               break;
+       if (last_soc != save_soc) {
+               rk818_bat_write(di, RK818_SOC_REG, save_soc);
+               last_soc = save_soc;
        }
 }
 
        }
 }
 
-static void rk81x_bat_set_otg_state(struct rk81x_battery *di, int state)
+static int rk818_bat_get_prev_dsoc(struct rk818_battery *di)
 {
 {
-       switch (state) {
-       case USB_OTG_POWER_ON:
-               rk81x_bat_set_bit(di, NT_STS_MSK_REG2, PLUG_IN_INT);
-               rk81x_bat_set_bit(di, NT_STS_MSK_REG2, PLUG_OUT_INT);
-               rk818_set_bits(di->rk818, DCDC_EN_REG, OTG_EN_MASK, OTG_EN);
-               break;
-       case USB_OTG_POWER_OFF:
-               rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, PLUG_IN_INT);
-               rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, PLUG_OUT_INT);
-               rk818_set_bits(di->rk818, DCDC_EN_REG, OTG_EN_MASK, OTG_DIS);
-               break;
-       default:
-               break;
-       }
+       return rk818_bat_read(di, RK818_SOC_REG);
 }
 
 }
 
-static enum charger_type rk81x_bat_get_dc_state(struct rk81x_battery *di)
+static void rk818_bat_save_reboot_cnt(struct rk818_battery *di, u8 save_cnt)
 {
 {
-       int ret;
-       enum charger_type charger_type = NO_CHARGER;
-
-       if (di->fg_drv_mode == TEST_POWER_MODE) {
-               charger_type = DC_CHARGER;
-               goto out;
-       }
-       /*
-       if (di->otg_online)
-               goto out;
-       */
-       if (!gpio_is_valid(di->dc_det_pin))
-               goto out;
-
-       ret = gpio_request(di->dc_det_pin, "rk818_dc_det");
-       if (ret < 0) {
-               pr_err("Failed to request gpio %d with ret:""%d\n",
-                      di->dc_det_pin, ret);
-               goto out;
-       }
-
-       gpio_direction_input(di->dc_det_pin);
-       ret = gpio_get_value(di->dc_det_pin);
-       if (ret == di->dc_det_level)
-               charger_type = DC_CHARGER;
-       else
-               charger_type = NO_CHARGER;
-       gpio_free(di->dc_det_pin);
-out:
-       return charger_type;
+       rk818_bat_write(di, RK818_REBOOT_CNT_REG, save_cnt);
 }
 
 }
 
-static void rk81x_battery_dc_delay_work(struct work_struct *work)
+static int rk818_bat_fb_notifier(struct notifier_block *nb,
+                                unsigned long event, void *data)
 {
 {
-       enum charger_type charger_type;
-       struct rk81x_battery *di = container_of(work,
-                               struct rk81x_battery, dc_det_check_work.work);
+       struct rk818_battery *di;
+       struct fb_event *evdata = data;
 
 
-       charger_type = rk81x_bat_get_dc_state(di);
+       di = container_of(nb, struct rk818_battery, fb_nb);
+       di->fb_blank = *(int *)evdata->data;
 
 
-       if (charger_type == DC_CHARGER) {
-               rk81x_bat_set_charger_param(di, DC_CHARGER);
-               if (power_dc2otg && di->otg_online)
-                       rk81x_bat_set_otg_state(di, USB_OTG_POWER_OFF);
-       } else {
-               if (di->otg_online) {
-                       rk81x_bat_set_otg_state(di, USB_OTG_POWER_ON);
-                       rk81x_bat_set_charger_param(di, NO_CHARGER);
-               } else {
-                       queue_delayed_work(di->wq,
-                                          &di->ac_usb_check_work,
-                                          msecs_to_jiffies(10));
-               }
-       }
-}
-
-static void rk81x_battery_acusb_delay_work(struct work_struct *work)
-{
-       u8 buf;
-       int gadget_flag, usb_id;
-       struct rk81x_battery *di = container_of(work,
-                       struct rk81x_battery, ac_usb_check_work.work);
-
-       rk81x_bat_read(di, VB_MOD_REG, &buf, 1);
-       usb_id = dwc_otg_check_dpdm(0);
-       switch (usb_id) {
-       case 0:
-               if ((buf & PLUG_IN_STS) != 0)
-                       rk81x_bat_set_charger_param(di, DC_CHARGER);
-               else
-                       rk81x_bat_set_charger_param(di, NO_CHARGER);
-               break;
-       case 1:
-       case 3:
-               rk81x_bat_set_charger_param(di, USB_CHARGER);
-               break;
-       case 2:
-               rk81x_bat_set_charger_param(di, AC_CHARGER);
-               break;
-       default:
-               break;
-       }
-       /*check unstanderd charger*/
-       if (usb_id == 1 || usb_id == 3) {
-               gadget_flag = get_gadget_connect_flag();
-               if (0 == gadget_flag) {
-                       di->check_count++;
-                       if (di->check_count >= 5) {
-                               di->check_count = 0;
-                               rk81x_bat_set_charger_param(di, AC_CHARGER);
-                       } else {
-                               queue_delayed_work(di->wq,
-                                                  &di->ac_usb_check_work,
-                                                  msecs_to_jiffies(1000));
-                       }
-               } else {/*confirm: USB_CHARGER*/
-                       di->check_count = 0;
-               }
-       }
+       return 0;
 }
 }
-#endif
 
 
-#if defined(CONFIG_X86_INTEL_SOFIA)
-static int rk81x_get_chrg_type_by_usb_phy(struct rk81x_battery *di, int ma)
+static int rk818_bat_register_fb_notify(struct rk818_battery *di)
 {
 {
-       enum charger_type charger_type;
-
-       if (ma > 500)
-               charger_type =  AC_CHARGER;
-       else if (ma >= 100)
-               charger_type = USB_CHARGER;
-       else
-               charger_type = NO_CHARGER;
-
-       di->ma = ma;
-
-       dev_info(di->dev, "limit current:%d\n", ma);
+       memset(&di->fb_nb, 0, sizeof(di->fb_nb));
+       di->fb_nb.notifier_call = rk818_bat_fb_notifier;
 
 
-       return charger_type;
+       return fb_register_client(&di->fb_nb);
 }
 
 }
 
-static void rk81x_battery_usb_notifier_delayed_work(struct work_struct *work)
+static int rk818_bat_unregister_fb_notify(struct rk818_battery *di)
 {
 {
-       struct rk81x_battery *di;
-       enum charger_type type;
-
-       di = container_of(work, struct rk81x_battery, usb_phy_delay_work.work);
-       type = rk81x_get_chrg_type_by_usb_phy(di, di->ma);
-
-       rk81x_bat_set_chrg_current(di, type);
-       power_supply_changed(&di->usb);
+       return fb_unregister_client(&di->fb_nb);
 }
 
 }
 
-static int rk81x_battery_usb_notifier(struct notifier_block *nb,
-                                     unsigned long event, void *data)
+static u8 rk818_bat_get_halt_cnt(struct rk818_battery *di)
 {
 {
-       struct rk81x_battery *di;
-       struct power_supply_cable_props *cable_props;
-       enum charger_type type;
-
-       di = container_of(nb, struct rk81x_battery, usb_nb);
-
-       if (!data)
-               return NOTIFY_BAD;
-
-       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;
-
-       default:
-               break;
-       }
-
-       return NOTIFY_OK;
+       return rk818_bat_read(di, RK818_HALT_CNT_REG);
 }
 }
-#endif
 
 
-static int rk81x_battery_fb_notifier(struct notifier_block *nb,
-                                    unsigned long event, void *data)
+static void rk818_bat_inc_halt_cnt(struct rk818_battery *di)
 {
 {
-       struct rk81x_battery *di;
-       struct fb_event *evdata = data;
-       int blank;
-
-       di = container_of(nb, struct rk81x_battery, fb_nb);
-
-       if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
-               return 0;
-
-       blank = *(int *)evdata->data;
-
-       if (di->fb_blank != blank)
-               di->fb_blank = blank;
-       else
-               return 0;
-
-       if (blank == FB_BLANK_UNBLANK)
-               di->early_resume = 1;
+       u8 cnt;
 
 
-       return 0;
+       cnt = rk818_bat_read(di, RK818_HALT_CNT_REG);
+       rk818_bat_write(di, RK818_HALT_CNT_REG, ++cnt);
 }
 
 }
 
-static int rk81x_battery_register_fb_notify(struct rk81x_battery *di)
+static bool is_rk818_bat_last_halt(struct rk818_battery *di)
 {
 {
-       memset(&di->fb_nb, 0, sizeof(di->fb_nb));
-       di->fb_nb.notifier_call = rk81x_battery_fb_notifier;
+       int pre_cap = rk818_bat_get_prev_cap(di);
+       int now_cap = rk818_bat_get_coulomb_cap(di);
 
 
-       return fb_register_client(&di->fb_nb);
+       /* over 10%: system halt last time */
+       if (abs(now_cap - pre_cap) > (di->fcc / 10)) {
+               rk818_bat_inc_halt_cnt(di);
+               return true;
+       } else {
+               return false;
+       }
 }
 
 }
 
-/*
- * it is first time for battery to be weld, init by ocv table
- */
-static void rk81x_bat_first_pwron(struct rk81x_battery *di)
+static void rk818_bat_first_pwron(struct rk818_battery *di)
 {
 {
-       rk81x_bat_save_fcc(di, di->design_capacity);
-       di->fcc = rk81x_bat_get_fcc(di);
+       int ocv_vol;
 
 
-       di->rsoc = rk81x_bat_vol_to_capacity(di, di->voltage_ocv);
+       rk818_bat_save_fcc(di, di->design_cap);
+       ocv_vol = rk818_bat_get_ocv_voltage(di);
+       di->fcc = rk818_bat_get_fcc(di);
+       di->nac = rk818_bat_vol_to_ocvcap(di, ocv_vol);
+       di->rsoc = rk818_bat_vol_to_ocvsoc(di, ocv_vol);
        di->dsoc = di->rsoc;
        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;
+       BAT_INFO("first on: dsoc=%d, rsoc=%d cap=%d, fcc=%d, ov=%d\n",
+                di->dsoc, di->rsoc, di->nac, di->fcc, ocv_vol);
+}
+
+static void rk818_bat_not_first_pwron(struct rk818_battery *di)
+{
+       int now_cap, pre_soc, pre_cap, ocv_cap, ocv_soc, ocv_vol;
+
+       di->fcc = rk818_bat_get_fcc(di);
+       pre_soc = rk818_bat_get_prev_dsoc(di);
+       pre_cap = rk818_bat_get_prev_cap(di);
+       now_cap = rk818_bat_get_coulomb_cap(di);
+       di->is_halt = is_rk818_bat_last_halt(di);
+       di->halt_cnt = rk818_bat_get_halt_cnt(di);
+       di->is_initialized = is_rk818_bat_initialized(di);
+       di->is_ocv_calib = is_rk818_bat_ocv_valid(di);
+
+       if (di->is_halt) {
+               BAT_INFO("system halt last time... cap: pre=%d, now=%d\n",
+                        pre_cap, now_cap);
+               if (now_cap < 0)
+                       now_cap = 0;
+               rk818_bat_init_coulomb_cap(di, now_cap);
+               pre_cap = now_cap;
+               pre_soc = di->rsoc;
+               goto finish;
+       } else if (di->is_initialized) {
+               BAT_INFO("initialized yet..\n");
+               goto finish;
+       } else if (di->is_ocv_calib) {
+               ocv_vol = rk818_bat_get_ocv_voltage(di);
+               ocv_soc = rk818_bat_vol_to_ocvsoc(di, ocv_vol);
+               ocv_cap = rk818_bat_vol_to_ocvcap(di, ocv_vol);
+               pre_cap = ocv_cap;
+               if (abs(ocv_soc - pre_soc) >= di->pdata->max_soc_offset) {
+                       BAT_INFO("trigger max soc offset, dsoc: %d -> %d\n",
+                                pre_soc, ocv_soc);
+                       pre_soc = ocv_soc;
+                       di->is_max_soc_offset = true;
                }
                }
-       } else if (di->pwroff_min > 2) {
-               calib_vol = ocv_vol;
-       } else {
-               calib_vol = -1;
+               BAT_INFO("OCV calib: cap=%d, rsoc=%d\n", ocv_cap, ocv_soc);
        }
 
        }
 
-       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);
+finish:
+       di->dsoc = pre_soc;
+       di->nac = pre_cap;
+       if (di->nac < 0)
+               di->nac = 0;
 
 
-       return calib_vol;
+       BAT_INFO("dsoc=%d cap=%d v=%d ov=%d rv=%d min=%d psoc=%d pcap=%d\n",
+                di->dsoc, di->nac, rk818_bat_get_avg_voltage(di),
+                rk818_bat_get_ocv_voltage(di), rk818_bat_get_relax_voltage(di),
+                di->pwroff_min, rk818_bat_get_prev_dsoc(di),
+                rk818_bat_get_prev_cap(di));
 }
 
 }
 
-/*
- * 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)
+static bool rk818_bat_ocv_sw_reset(struct rk818_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 defined(CONFIG_ARCH_ROCKCHIP)
-       if (di->loader_charged) {
-               dev_info(di->dev, "loader charged\n");
-               goto out;
-       }
-#endif
-       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);
-       }
+       u8 buf;
 
 
-       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);
-               }
+       buf = rk818_bat_read(di, RK818_MISC_MARK_REG);
+       if (((buf & FG_RESET_LATE) && di->pwroff_min >= 30) ||
+           (buf & FG_RESET_NOW)) {
+               buf &= ~FG_RESET_LATE;
+               buf &= ~FG_RESET_NOW;
+               rk818_bat_write(di, RK818_MISC_MARK_REG, buf);
+               BAT_INFO("manual reset fuel gauge\n");
+               return true;
        } else {
        } else {
-               rk81x_bat_clr_bit(di, MISC_MARK_REG, OCV_VALID_SHIFT);
+               return false;
        }
        }
-out:
-       di->dsoc = init_soc;
-       di->nac = remain_capacity;
-       if (di->nac <= 0)
-               di->nac = 0;
-       dev_info(di->dev, "reg soc=%d, init soc = %d, init cap=%d\n",
-                pwron_soc, di->dsoc, di->nac);
 }
 
 }
 
-static u8 rk81x_bat_get_pwroff_min(struct rk81x_battery *di)
+static void rk818_bat_init_rsoc(struct rk818_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);
+       di->is_first_power_on = is_rk818_bat_first_pwron(di);
+       di->is_sw_reset = rk818_bat_ocv_sw_reset(di);
+       di->pwroff_min = rk818_bat_get_pwroff_min(di);
 
 
-       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;
+       if (di->is_first_power_on || di->is_sw_reset)
+               rk818_bat_first_pwron(di);
+       else
+               rk818_bat_not_first_pwron(di);
 }
 
 }
 
-static u8 rk81x_bat_get_chrg_status(struct rk81x_battery *di)
+static u8 rk818_bat_get_chrg_status(struct rk818_battery *di)
 {
        u8 status;
 {
        u8 status;
-       u8 ret = 0;
 
 
-       rk81x_bat_read(di, SUP_STS_REG, &status, 1);
-       status &= (0x70);
+       status = rk818_bat_read(di, RK818_SUP_STS_REG) & CHRG_STATUS_MSK;
        switch (status) {
        case CHARGE_OFF:
        switch (status) {
        case CHARGE_OFF:
-               ret = CHARGE_OFF;
-               DBG("  CHARGE-OFF ...\n");
+               DBG("CHARGE-OFF ...\n");
                break;
        case DEAD_CHARGE:
                break;
        case DEAD_CHARGE:
-               ret = DEAD_CHARGE;
-               DBG("  DEAD CHARGE ...\n");
+               BAT_INFO("DEAD CHARGE...\n");
                break;
                break;
-       case  TRICKLE_CHARGE:
-               ret = DEAD_CHARGE;
-               DBG("  TRICKLE CHARGE ...\n ");
+       case TRICKLE_CHARGE:
+               BAT_INFO("TRICKLE CHARGE...\n ");
                break;
                break;
-       case  CC_OR_CV:
-               ret = CC_OR_CV;
-               DBG("  CC or CV ...\n");
+       case CC_OR_CV:
+               DBG("CC or CV...\n");
                break;
                break;
-       case  CHARGE_FINISH:
-               ret = CHARGE_FINISH;
-               DBG("  CHARGE FINISH ...\n");
+       case CHARGE_FINISH:
+               DBG("CHARGE FINISH...\n");
                break;
                break;
-       case  USB_OVER_VOL:
-               ret = USB_OVER_VOL;
-               DBG("  USB OVER VOL ...\n");
+       case USB_OVER_VOL:
+               BAT_INFO("USB OVER VOL...\n");
                break;
                break;
-       case  BAT_TMP_ERR:
-               ret = BAT_TMP_ERR;
-               DBG("  BAT TMP ERROR ...\n");
+       case BAT_TMP_ERR:
+               BAT_INFO("BAT TMP ERROR...\n");
                break;
                break;
-       case  TIMER_ERR:
-               ret = TIMER_ERR;
-               DBG("  TIMER ERROR ...\n");
+       case TIMER_ERR:
+               BAT_INFO("TIMER ERROR...\n");
                break;
                break;
-       case  USB_EXIST:
-               ret = USB_EXIST;
-               DBG("  USB EXIST ...\n");
+       case USB_EXIST:
+               BAT_INFO("USB EXIST...\n");
                break;
                break;
-       case  USB_EFF:
-               ret = USB_EFF;
-               DBG("  USB EFF...\n");
+       case USB_EFF:
+               BAT_INFO("USB EFF...\n");
                break;
        default:
                return -EINVAL;
        }
 
                break;
        default:
                return -EINVAL;
        }
 
-       return ret;
+       return status;
 }
 
 }
 
-static void rk81x_bat_match_param(struct rk81x_battery *di, int chrg_vol,
-                                 int chrg_ilim, int chrg_cur)
+static u8 rk818_bat_parse_fb_temperature(struct rk818_battery *di)
 {
 {
-       int i;
-
-       di->chrg_v_lmt = DEF_CHRG_VOL;
-       di->chrg_i_lmt = DEF_CHRG_CURR_LMT;
-       di->chrg_i_cur = DEF_CHRG_CURR_SEL;
+       u8 reg;
+       int index, fb_temp;
 
 
-       for (i = 0; i < ARRAY_SIZE(CHRG_V_LMT); i++) {
-               if (chrg_vol < CHRG_V_LMT[i])
+       reg = DEFAULT_FB_TEMP;
+       fb_temp = di->pdata->fb_temp;
+       for (index = 0; index < ARRAY_SIZE(feedback_temp_array); index++) {
+               if (fb_temp < feedback_temp_array[index])
                        break;
                        break;
-
-               di->chrg_v_lmt = (i << CHRG_VOL_SHIFT);
+               reg = (index << FB_TEMP_SHIFT);
        }
 
        }
 
-       for (i = 0; i < ARRAY_SIZE(CHRG_I_LMT); i++) {
-               if (chrg_ilim < CHRG_I_LMT[i])
-                       break;
-
-               di->chrg_i_lmt = (i << CHRG_ILIM_SHIFT);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(CHRG_I_CUR); i++) {
-               if (chrg_cur < CHRG_I_CUR[i])
-                       break;
-
-               di->chrg_i_cur = (i << CHRG_ICUR_SHIFT);
-       }
-       DBG("<%s>. vol = 0x%x, i_lim = 0x%x, cur=0x%x\n",
-           __func__, di->chrg_v_lmt, di->chrg_i_lmt, di->chrg_i_cur);
+       return reg;
 }
 
 }
 
-static u8 rk81x_bat_select_finish_ma(int fcc)
+static u8 rk818_bat_parse_finish_ma(struct rk818_battery *di, int fcc)
 {
 {
-       u8 ma = FINISH_150MA;
+       u8 ma;
 
 
-       if (fcc > 5000)
+       if (di->pdata->sample_res == SAMPLE_RES_10MR)
+               ma = FINISH_100MA;
+       else if (fcc > 5000)
                ma = FINISH_250MA;
                ma = FINISH_250MA;
-
        else if (fcc >= 4000)
                ma = FINISH_200MA;
        else if (fcc >= 4000)
                ma = FINISH_200MA;
-
        else if (fcc >= 3000)
                ma = FINISH_150MA;
        else if (fcc >= 3000)
                ma = FINISH_150MA;
-
        else
                ma = FINISH_100MA;
 
        return ma;
 }
        else
                ma = FINISH_100MA;
 
        return ma;
 }
-#if 0
-/*
- * 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");
-}
-#endif
 
 
-static void rk81x_bat_charger_init(struct  rk81x_battery *di)
+static void rk818_bat_init_chrg_config(struct rk818_battery *di)
 {
 {
-       u8 chrg_ctrl_reg1, usb_ctrl_reg, chrg_ctrl_reg2, chrg_ctrl_reg3;
-       u8 sup_sts_reg, thremal_reg, ggcon;
-       int chrg_vol, chrg_cur, chrg_ilim;
-       u8 finish_ma;
+       u8 usb_ctrl, chrg_ctrl2, chrg_ctrl3;
+       u8 thermal, ggcon, finish_ma, fb_temp;
 
 
-       chrg_vol = di->pdata->max_charger_voltagemV;
-       chrg_cur = di->pdata->max_charger_currentmA;
-       chrg_ilim = di->pdata->max_charger_ilimitmA;
+       finish_ma = rk818_bat_parse_finish_ma(di, di->fcc);
+       fb_temp = rk818_bat_parse_fb_temperature(di);
 
 
-       rk81x_bat_match_param(di, chrg_vol, chrg_ilim, chrg_cur);
-       finish_ma = rk81x_bat_select_finish_ma(di->fcc);
+       ggcon = rk818_bat_read(di, RK818_GGCON_REG);
+       thermal = rk818_bat_read(di, RK818_THERMAL_REG);
+       usb_ctrl = rk818_bat_read(di, RK818_USB_CTRL_REG);
+       chrg_ctrl2 = rk818_bat_read(di, RK818_CHRG_CTRL_REG2);
+       chrg_ctrl3 = rk818_bat_read(di, RK818_CHRG_CTRL_REG3);
 
 
-       /*rk81x_bat_init_chrg_timer(di);*/
+       /* set charge finish current */
+       chrg_ctrl3 |= CHRG_TERM_DIG_SIGNAL;
+       chrg_ctrl2 &= ~FINISH_CUR_MSK;
+       chrg_ctrl2 |= finish_ma;
 
 
-       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);
+       /* disable cccv mode */
+       chrg_ctrl3 &= ~CHRG_TIMER_CCCV_EN;
 
 
-       usb_ctrl_reg &= (~0x0f);
-
-       if (rk81x_bat_support_adp_type(HW_ADP_TYPE_USB))
-               usb_ctrl_reg |= (CHRG_CT_EN | ILIM_450MA);/*en temp feed back*/
+       /* set feed back temperature */
+       if (di->pdata->fb_temp)
+               usb_ctrl |= CHRG_CT_EN;
        else
        else
-               usb_ctrl_reg |= (CHRG_CT_EN | di->chrg_i_lmt);
-
-       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->chrg_v_lmt | di->chrg_i_cur);
-
-       chrg_ctrl_reg3 |= CHRG_TERM_DIG_SIGNAL;/* digital finish mode*/
-       chrg_ctrl_reg3 &= ~CHRG_TIMER_CCCV_EN;/*disable*/
-
-       chrg_ctrl_reg2 &= ~(0xc7);
-       chrg_ctrl_reg2 |= finish_ma | CHG_CCCV_6HOUR;
+               usb_ctrl &= ~CHRG_CT_EN;
+       thermal &= ~FB_TEMP_MSK;
+       thermal |= fb_temp;
 
 
-       sup_sts_reg &= ~(0x01 << 3);
-       sup_sts_reg |= (0x01 << 2);
+       /* adc current mode */
+       ggcon |= ADC_CUR_MODE;
 
 
-       thremal_reg &= (~0x0c);
-       thremal_reg |= TEMP_105C;/*temp feed back: 105c*/
-       ggcon |= ADC_CURRENT_MODE;
-
-       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);
+       rk818_bat_write(di, RK818_GGCON_REG, ggcon);
+       rk818_bat_write(di, RK818_THERMAL_REG, thermal);
+       rk818_bat_write(di, RK818_USB_CTRL_REG, usb_ctrl);
+       rk818_bat_write(di, RK818_CHRG_CTRL_REG2, chrg_ctrl2);
+       rk818_bat_write(di, RK818_CHRG_CTRL_REG3, chrg_ctrl3);
 }
 
 }
 
-static void rk81x_bat_fg_init(struct rk81x_battery *di)
+static void rk818_bat_init_coffset(struct rk818_battery *di)
 {
 {
-       u8 pcb_offset;
-       int cal_offset;
-       u8 val;
+       int coffset, ioffset;
 
 
-       val = 0x30;
-       rk81x_bat_write(di, ADC_CTRL_REG, &val, 1);
-
-       rk81x_bat_gauge_enable(di);
-       /* get the volatege offset */
-       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 = 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);
-
-       rk81x_bat_rsoc_init(di);
-       rk81x_bat_capacity_init(di, di->nac);
-       rk81x_bat_capacity_init_post(di);
-
-       di->remain_capacity = rk81x_bat_get_realtime_capacity(di);
-       di->current_avg = rk81x_bat_get_avg_current(di);
-
-       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);
-
-       rk81x_dbg_dmp_gauge_regs(di);
-       rk81x_dbg_dmp_charger_regs(di);
-
-       DBG("<%s> :\n"
-           "nac = %d , remain_capacity = %d\n"
-           "OCV_voltage = %d, voltage = %d\n"
-           "SOC = %d, fcc = %d\n, current=%d\n"
-           "cal_offset = 0x%x\n",
-           __func__,
-           di->nac, di->remain_capacity,
-           di->voltage_ocv, di->voltage,
-           di->dsoc, di->fcc, di->current_avg,
-           cal_offset);
-}
+       ioffset = rk818_bat_get_ioffset(di);
+       di->poffset = rk818_bat_read(di, RK818_POFFSET_REG);
+       if (!di->poffset)
+               di->poffset = DEFAULT_POFFSET;
 
 
-static void rk81x_bat_zero_calc_linek(struct rk81x_battery *di)
-{
-       int dead_voltage, ocv_voltage;
-       int voltage, voltage_old, voltage_now;
-       int i, rsoc;
-       int q_ocv, q_dead;
-       int count_num = 0;
-       int currentnow;
-       int ocv_soc, dead_soc;
-       int power_off_thresd = di->pdata->power_off_thresd;
+       coffset = di->poffset + ioffset;
+       if (coffset < INVALID_COFFSET_MIN || coffset > INVALID_COFFSET_MAX)
+               coffset = DEFAULT_COFFSET;
 
 
-       do {
-               voltage_old = rk81x_bat_get_vol(di);
-               msleep(100);
-               voltage_now = rk81x_bat_get_vol(di);
-               count_num++;
-       } 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 += rk81x_bat_get_vol(di);
-               msleep(100);
-       }
-       voltage /= 10;
-
-       currentnow = rk81x_bat_get_avg_current(di);
+       rk818_bat_set_coffset(di, coffset);
 
 
-       /* 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);
-
-       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 = rk81x_bat_vol_to_capacity(di, ocv_voltage);
-       q_ocv = di->temp_nac;
-       DBG("ZERO0: ocv_voltage_soc = %d, q_ocv = %d\n",
-           ocv_soc, q_ocv);
-
-       rsoc = ocv_soc - dead_soc;
-       if ((di->dsoc == 1) && (rsoc > 0)) {/*discharge*/
-               di->line_k = 1000;
-       } else if (rsoc > 0) {
-               di->line_k = (di->display_soc + rsoc / 2) / div(rsoc);
-       } else {
-               di->dsoc--;
-               di->display_soc = di->dsoc * 1000;
-       }
-
-       di->zero_old_remain_cap = di->remain_capacity;
-
-       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);
+       DBG("<%s>. offset: p=0x%x, i=0x%x, c=0x%x\n",
+           __func__, di->poffset, ioffset, rk818_bat_get_coffset(di));
 }
 
 }
 
-static void rk81x_bat_zero_algorithm(struct rk81x_battery *di)
+static void rk818_bat_caltimer_isr(unsigned long data)
 {
 {
-       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 ((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 + MIN_ROUND_ACCURACY) / 1000;
-               di->dsoc = tmp_dsoc;
-               /* need to be init, otherwise when switch between discharge and
-                * charge display_soc will be init as: dsoc * 1000
-                */
-               di->last_zero_mode_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);
+       struct rk818_battery *di = (struct rk818_battery *)data;
 
 
-               rk81x_bat_zero_calc_linek(di);
-       }
+       mod_timer(&di->caltimer, jiffies + MINUTE(8) * HZ);
+       queue_delayed_work(di->bat_monitor_wq, &di->calib_delay_work,
+                          msecs_to_jiffies(10));
 }
 
 }
 
-static int rk81x_bat_est_ocv_vol(struct rk81x_battery *di)
+static void rk818_bat_internal_calib(struct work_struct *work)
 {
 {
-       return (di->voltage -
-                               (di->bat_res * di->current_avg) / 1000);
-}
+       int ioffset, poffset;
+       struct rk818_battery *di = container_of(work,
+                       struct rk818_battery, calib_delay_work.work);
 
 
-static int rk81x_bat_est_ocv_soc(struct rk81x_battery *di)
-{
-       int ocv_soc, ocv_voltage;
+       /* calib coffset */
+       poffset = rk818_bat_read(di, RK818_POFFSET_REG);
+       if (poffset)
+               di->poffset = poffset;
+       else
+               di->poffset = DEFAULT_POFFSET;
 
 
-       ocv_voltage = rk81x_bat_est_ocv_vol(di);
-       ocv_soc = rk81x_bat_vol_to_capacity(di, ocv_voltage);
+       ioffset = rk818_bat_get_ioffset(di);
+       rk818_bat_set_coffset(di, ioffset + di->poffset);
 
 
-       return ocv_soc;
+       /* calib voltage kb */
+       rk818_bat_init_voltage_kb(di);
+       BAT_INFO("caltimer: ioffset=0x%x, coffset=0x%x, poffset=%d\n",
+                ioffset, rk818_bat_get_coffset(di), di->poffset);
 }
 
 }
 
-/* we will estimate a ocv voltage to get a ocv soc.
- * if there is a big offset between ocv_soc and rsoc,
- * we will decide whether we should reinit capacity or not
- */
-static void rk81x_bat_rsoc_dischrg_check(struct rk81x_battery *di)
+static void rk818_bat_init_caltimer(struct rk818_battery *di)
 {
 {
-       int ocv_soc = di->est_ocv_soc;
-       int ocv_volt = di->est_ocv_vol;
-       int rsoc = rk81x_bat_get_rsoc(di);
-       int max_volt = di->pdata->max_charger_voltagemV;
+       setup_timer(&di->caltimer, rk818_bat_caltimer_isr, (unsigned long)di);
+       di->caltimer.expires = jiffies + MINUTE(8) * HZ;
+       add_timer(&di->caltimer);
+       INIT_DELAYED_WORK(&di->calib_delay_work, rk818_bat_internal_calib);
+}
 
 
-       if (ocv_volt > max_volt)
-               goto out;
+static void rk818_bat_init_zero_table(struct rk818_battery *di)
+{
+       int i, diff, min, max;
+       size_t ocv_size, length;
 
 
-       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, 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 (rsoc-ocv_soc >= RSOC_DISCHRG_ERR_UPPER)
-                               ocv_soc += RSOC_COMPS;
-
-                       di->temp_nac = ocv_soc * di->fcc / 100;
-                       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);
-               }
-        } else {
-out:
-               di->err_chck_cnt = 0;
-               di->err_soc_sum = 0;
+       ocv_size = di->pdata->ocv_size;
+       length = sizeof(di->pdata->zero_table) * ocv_size;
+       di->pdata->zero_table =
+                       devm_kzalloc(di->dev, length, GFP_KERNEL);
+       if (!di->pdata->zero_table) {
+               di->pdata->zero_table = di->pdata->ocv_table;
+               dev_err(di->dev, "malloc zero table fail\n");
+               return;
        }
        }
-}
 
 
-static void rk81x_bat_rsoc_check(struct rk81x_battery *di)
-{
-       u8 status = di->psy_status;
+       min = di->pdata->pwroff_vol,
+       max = di->pdata->ocv_table[ocv_size - 4];
+       diff = (max - min) / (ocv_size - 1);
+       for (i = 0; i < ocv_size; i++)
+               di->pdata->zero_table[i] = min + (i * diff);
 
 
-       if ((status == POWER_SUPPLY_STATUS_CHARGING) ||
-           (status == POWER_SUPPLY_STATUS_FULL)) {
-               if ((di->current_avg < 0) &&
-                   (di->chrg_status != CHARGE_FINISH))
-                       rk81x_bat_rsoc_dischrg_check(di);
-               /*
-               else
-                       rsoc_chrg_calib(di);
-               */
+       for (i = 0; i < ocv_size; i++)
+               DBG("zero[%d] = %d\n", i, di->pdata->zero_table[i]);
 
 
-       } else if (status == POWER_SUPPLY_STATUS_DISCHARGING) {
-               rk81x_bat_rsoc_dischrg_check(di);
-       }
+       for (i = 0; i < ocv_size; i++)
+               DBG("ocv[%d] = %d\n", i, di->pdata->ocv_table[i]);
 }
 
 }
 
-static void rk81x_bat_emulator_dischrg(struct rk81x_battery *di)
+static void rk818_bat_calc_sm_linek(struct rk818_battery *di)
 {
 {
-       u32 temp, soc_time = 0;
-       unsigned long sec_unit;
+       int linek, current_avg;
+       u8 diff, delta;
+
+       delta = abs(di->dsoc - di->rsoc);
+       diff = delta * 3;/* speed:3/4 */
+       current_avg = rk818_bat_get_avg_current(di);
+       if (current_avg >= 0) {
+               if (di->dsoc < di->rsoc)
+                       linek = 1000 * (delta + diff) / diff;
+               else if (di->dsoc > di->rsoc)
+                       linek = 1000 * diff / (delta + diff);
+               else
+                       linek = 1000;
+               di->dbg_meet_soc = (di->dsoc >= di->rsoc) ?
+                                  (di->dsoc + diff) : (di->rsoc + diff);
+       } else {
+               if (di->dsoc < di->rsoc)
+                       linek = -1000 * diff / (delta + diff);
+               else if (di->dsoc > di->rsoc)
+                       linek = -1000 * (delta + diff) / diff;
+               else
+                       linek = -1000;
+               di->dbg_meet_soc = (di->dsoc >= di->rsoc) ?
+                                  (di->dsoc - diff) : (di->rsoc - diff);
+       }
 
 
-       if (!di->dischrg_emu_base)
-               di->dischrg_emu_base = get_runtime_sec();
+       di->sm_linek = linek;
+       di->sm_remain_cap = di->remain_cap;
+       di->dbg_calc_dsoc = di->dsoc;
+       di->dbg_calc_rsoc = di->rsoc;
 
 
-       sec_unit = BASE_TO_SEC(di->dischrg_emu_base) + di->dischrg_save_sec;
+       DBG("<%s>.diff=%d, k=%d, cur=%d\n", __func__, diff, linek, current_avg);
+}
 
 
-       temp = di->fcc * 3600 / 100;
+static void rk818_bat_calc_zero_linek(struct rk818_battery *di)
+{
+       int dead_voltage, ocv_voltage;
+       int voltage_avg, current_avg, vsys;
+       int ocv_cap, dead_cap, xsoc;
+       int ocv_soc, dead_soc;
+       int pwroff_vol;
+       int i, cnt, vol_old, vol_now;
+       int org_linek = 0, min_gap_xsoc;
 
 
-       if (abs(di->current_avg) < DSOC_DISCHRG_EMU_CURR)
-               soc_time = temp / div(abs(DSOC_DISCHRG_EMU_CURR));
+       if ((abs(di->current_avg) < 500) && (di->dsoc > 10))
+               pwroff_vol = di->pdata->pwroff_vol + 50;
        else
        else
-               soc_time = temp / div(abs(di->current_avg));
+               pwroff_vol = di->pdata->pwroff_vol;
 
 
-       if  (sec_unit > soc_time) {
-               di->dsoc--;
-               di->dischrg_emu_base = get_runtime_sec();
-               di->dischrg_save_sec = 0;
-       }
+       do {
+               vol_old = rk818_bat_get_avg_voltage(di);
+               msleep(100);
+               vol_now = rk818_bat_get_avg_voltage(di);
+               cnt++;
+       } while ((vol_old == vol_now) && (cnt < 11));
 
 
-       DBG("<%s> soc_time=%d, sec_unit=%lu\n",
-           __func__, soc_time, sec_unit);
-}
+       voltage_avg = 0;
+       for (i = 0; i < 10; i++) {
+               voltage_avg += rk818_bat_get_avg_voltage(di);
+               msleep(100);
+       }
 
 
-/*
- * when there is a big offset between dsoc and rsoc, dsoc needs to
- * speed up to keep pace witch rsoc.
- */
-static void rk81x_bat_emulator_chrg(struct rk81x_battery *di)
-{
-       u32 soc_time = 0, temp;
-       int plus_soc;
-       unsigned long chrg_emu_sec;
+       /* calc estimate ocv voltage */
+       voltage_avg /= 10;
+       current_avg = rk818_bat_get_avg_current(di);
+       vsys = voltage_avg + (current_avg * DEF_PWRPATH_RES) / 1000;
 
 
-       if (!di->chrg_emu_base)
-               di->chrg_emu_base = get_runtime_sec();
+       DBG("ZERO0: shtd_vol: org = %d, now = %d\n",
+           di->pdata->pwroff_vol, pwroff_vol);
 
 
-       chrg_emu_sec = BASE_TO_SEC(di->chrg_emu_base) + di->chrg_save_sec;
-       temp = di->fcc * 3600 / 100;
+       dead_voltage = pwroff_vol - current_avg *
+                               (di->bat_res + DEF_PWRPATH_RES) / 1000;
+       ocv_voltage = voltage_avg - (current_avg * di->bat_res) / 1000;
+       DBG("ZERO0: dead_voltage(shtd) = %d, ocv_voltage(now) = %d\n",
+           dead_voltage, ocv_voltage);
 
 
-       if (di->ac_online) {
-               if (di->current_avg < DSOC_CHRG_EMU_CURR)
-                       soc_time = temp / abs(DSOC_CHRG_EMU_CURR);
-               else
-                       soc_time = temp / div(abs(di->current_avg));
+       /* calc estimate soc and cap */
+       dead_soc = rk818_bat_vol_to_zerosoc(di, dead_voltage);
+       dead_cap = rk818_bat_vol_to_zerocap(di, dead_voltage);
+       DBG("ZERO0: dead_soc = %d, dead_cap = %d\n",
+           dead_soc, dead_cap);
+
+       ocv_soc = rk818_bat_vol_to_zerosoc(di, ocv_voltage);
+       ocv_cap = rk818_bat_vol_to_zerocap(di, ocv_voltage);
+       DBG("ZERO0: ocv_soc = %d, ocv_cap = %d\n",
+           ocv_soc, ocv_cap);
+
+       if (abs(current_avg) > ZERO_LOAD_LVL1)
+               min_gap_xsoc = ZERO_GAP_XSOC3;
+       else if (abs(current_avg) > ZERO_LOAD_LVL2)
+               min_gap_xsoc = ZERO_GAP_XSOC2;
+       else
+               min_gap_xsoc = ZERO_GAP_XSOC1;
+
+       /* xsoc: available rsoc */
+       xsoc = ocv_soc - dead_soc;
+       di->zero_remain_cap = di->remain_cap;
+       di->zero_timeout_cnt = 0;
+       if ((di->dsoc <= 1) && (xsoc > 0)) {
+               di->zero_linek = 400;
+               di->zero_drop_sec = 0;
+       } else if (xsoc >= 0) {
+               di->zero_drop_sec = 0;
+               di->zero_linek = (di->zero_dsoc + xsoc / 2) / DIV(xsoc);
+               org_linek = di->zero_linek;
+               /* battery energy mode to use up voltage */
+               if ((di->pdata->energy_mode) &&
+                   (xsoc - di->dsoc >= ZERO_GAP_XSOC3) &&
+                   (di->dsoc <= 10) && (di->zero_linek < 600)) {
+                       di->zero_linek = 500;
+                       DBG("ZERO-new: zero_linek adjust step0...\n");
+               /* reserve enough power yet, slow down any way */
+               } else if ((xsoc - di->dsoc >= min_gap_xsoc) ||
+                          ((xsoc - di->dsoc >= ZERO_GAP_XSOC2) &&
+                           (di->dsoc <= 10))) {
+                       if (xsoc - di->dsoc >= 2 * min_gap_xsoc)
+                               di->zero_linek = 400;
+                       else if (xsoc - di->dsoc >= 2 + min_gap_xsoc)
+                               di->zero_linek = 600;
+                       else
+                               di->zero_linek = 800;
+                       DBG("ZERO-new: zero_linek adjust step1...\n");
+               /* control zero mode beginning enter */
+               } else if ((di->zero_linek > 1800) && (di->dsoc > 70)) {
+                       di->zero_linek = 1800;
+                       DBG("ZERO-new: zero_linek adjust step2...\n");
+               /* dsoc close to xsoc: it must reserve power */
+               } else if ((di->zero_linek > 1000) && (di->zero_linek < 1300)) {
+                       di->zero_linek = 1300;
+                       DBG("ZERO-new: zero_linek adjust step3...\n");
+               /* dsoc[5~15], dsoc < xsoc */
+               } else if ((di->dsoc <= 15 && di->dsoc > 5) &&
+                          (di->zero_linek <= 1300)) {
+                       /* slow down */
+                       if (xsoc - di->dsoc >= min_gap_xsoc)
+                               di->zero_linek = 800;
+                       /* reserve power */
+                       else
+                               di->zero_linek = 1300;
+                       DBG("ZERO-new: zero_linek adjust step4...\n");
+               /* dsoc[5, 100], dsoc < xsoc */
+               } else if ((di->zero_linek < 1000) && (di->dsoc >= 5)) {
+                       if ((xsoc - di->dsoc) < min_gap_xsoc) {
+                               /* reserve power */
+                               di->zero_linek = 1300;
+                       } else {
+                               if (abs(di->current_avg) > 500)/* heavy */
+                                       di->zero_linek = 900;
+                               else
+                                       di->zero_linek = 1000;
+                       }
+                       DBG("ZERO-new: zero_linek adjust step5...\n");
+               /* dsoc[0~5], dsoc < xsoc */
+               } else if ((di->zero_linek < 1000) && (di->dsoc <= 5)) {
+                       if ((xsoc - di->dsoc) <= 3)
+                               di->zero_linek = 1300;
+                       else
+                               di->zero_linek = 800;
+                               DBG("ZERO-new: zero_linek adjust step6...\n");
+               }
        } else {
        } else {
-               soc_time = temp / 450;
+               /* xsoc < 0 */
+               di->zero_linek = 1000;
+               if (!di->zero_drop_sec)
+                       di->zero_drop_sec = get_boot_sec();
+               if (base2sec(di->zero_drop_sec) >= WAIT_DSOC_DROP_SEC) {
+                       DBG("ZERO0: t=%lu\n", base2sec(di->zero_drop_sec));
+                       di->zero_drop_sec = 0;
+                       di->dsoc--;
+                       di->zero_dsoc = (di->dsoc + 1) * 1000 -
+                                               MIN_ACCURACY;
+               }
        }
 
        }
 
-       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;
+       if (voltage_avg < pwroff_vol - 70) {
+               if (!di->shtd_drop_sec)
+                       di->shtd_drop_sec = get_boot_sec();
+               if (base2sec(di->shtd_drop_sec) > WAIT_SHTD_DROP_SEC) {
+                       BAT_INFO("voltage extreme low...soc:%d->0\n", di->dsoc);
+                       di->shtd_drop_sec = 0;
+                       di->dsoc = 0;
+               }
+       } else {
+               di->shtd_drop_sec = 0;
        }
 
        }
 
-       DBG("<%s>. soc_time=%d, chrg_emu_sec=%lu, plus_soc=%d\n",
-           __func__, soc_time, chrg_emu_sec, plus_soc);
+       DBG("ZERO-new: org_linek=%d, zero_linek=%d, dsoc=%d, Xsoc=%d, "
+           "rsoc=%d, gap=%d, v=%d, vsys=%d\n"
+           "ZERO-new: di->zero_dsoc=%d, zero_remain_cap=%d, zero_drop=%ld, "
+           "sht_drop=%ld\n\n",
+           org_linek, di->zero_linek, di->dsoc, xsoc, di->rsoc,
+           min_gap_xsoc, voltage_avg, vsys, di->zero_dsoc, di->zero_remain_cap,
+           base2sec(di->zero_drop_sec), base2sec(di->shtd_drop_sec));
 }
 
 }
 
-/* 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 void rk81x_bat_terminal_chrg(struct rk81x_battery *di)
+static void rk818_bat_finish_algo_prepare(struct rk818_battery *di)
+{
+       di->finish_base = get_boot_sec();
+       if (!di->finish_base)
+               di->finish_base = 1;
+}
+
+static void rk818_bat_smooth_algo_prepare(struct rk818_battery *di)
 {
 {
-       u32 soc_time;
-       int plus_soc;
-       unsigned long chrg_term_sec;
+       int tmp_soc;
 
 
-       if (!di->chrg_term_base)
-               di->chrg_term_base = get_runtime_sec();
+       tmp_soc = di->sm_chrg_dsoc / 1000;
+       if (tmp_soc != di->dsoc)
+               di->sm_chrg_dsoc = di->dsoc * 1000;
 
 
-       chrg_term_sec = BASE_TO_SEC(di->chrg_term_base) + di->chrg_save_sec;
-       /*check current and voltage*/
+       tmp_soc = di->sm_dischrg_dsoc / 1000;
+       if (tmp_soc != di->dsoc)
+               di->sm_dischrg_dsoc =
+               (di->dsoc + 1) * 1000 - MIN_ACCURACY;
 
 
-       soc_time = di->fcc * 3600 / 100 / (abs(DSOC_CHRG_TERM_CURR));
+       DBG("<%s>. tmp_soc=%d, dsoc=%d, dsoc:sm_dischrg=%d, sm_chrg=%d\n",
+           __func__, tmp_soc, di->dsoc, di->sm_dischrg_dsoc, di->sm_chrg_dsoc);
 
 
-       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);
+       rk818_bat_calc_sm_linek(di);
 }
 
 }
 
-static void rk81x_bat_normal_dischrg(struct rk81x_battery *di)
+static void rk818_bat_zero_algo_prepare(struct rk818_battery *di)
 {
 {
-       int soc_time = 0;
-       int now_current = di->current_avg;
-       unsigned long dischrg_normal_sec;
+       int tmp_dsoc;
 
 
-       if (!di->dischrg_normal_base)
-               di->dischrg_normal_base = get_runtime_sec();
+       tmp_dsoc = di->zero_dsoc / 1000;
+       if (tmp_dsoc != di->dsoc)
+               di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY;
 
 
-       dischrg_normal_sec = BASE_TO_SEC(di->dischrg_normal_base) +
-                                               di->dischrg_save_sec;
+       DBG("<%s>. first calc, reinit linek\n", __func__);
 
 
-       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);
+       rk818_bat_calc_zero_linek(di);
+}
 
 
-       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;
-               }
-               di->discharge_smooth_status = true;
+static void rk818_bat_calc_zero_algorithm(struct rk818_battery *di)
+{
+       int tmp_soc = 0, sm_delta_dsoc = 0;
 
 
-       } 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;
+       tmp_soc = di->zero_dsoc / 1000;
+       if (tmp_soc == di->dsoc)
+               goto out;
 
 
-       } 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;
+       DBG("<%s>. enter: dsoc=%d, rsoc=%d\n", __func__, di->dsoc, di->rsoc);
+       /* when discharge slow down, take sm chrg into calc */
+       if (di->dsoc < di->rsoc) {
+               /* take sm charge rest into calc */
+               tmp_soc = di->sm_chrg_dsoc / 1000;
+               if (tmp_soc == di->dsoc) {
+                       sm_delta_dsoc = di->sm_chrg_dsoc - di->dsoc * 1000;
+                       di->sm_chrg_dsoc = di->dsoc * 1000;
+                       di->zero_dsoc += sm_delta_dsoc;
+                       DBG("ZERO1: take sm chrg,delta=%d\n", sm_delta_dsoc);
                }
        }
 
                }
        }
 
-       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_bat_dischrg_smooth(struct rk81x_battery *di)
-{
-       int delta_soc;
-       int tmp_dsoc;
-
-       /* 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;
+       /* when discharge speed up, take sm dischrg into calc */
+       if (di->dsoc > di->rsoc) {
+               /* take sm discharge rest into calc */
+               tmp_soc = di->sm_dischrg_dsoc / 1000;
+               if (tmp_soc == di->dsoc) {
+                       sm_delta_dsoc = di->sm_dischrg_dsoc -
+                               ((di->dsoc + 1) * 1000 - MIN_ACCURACY);
+                       di->sm_dischrg_dsoc = (di->dsoc + 1) * 1000 -
+                                                               MIN_ACCURACY;
+                       di->zero_dsoc += sm_delta_dsoc;
+                       DBG("ZERO1: take sm dischrg,delta=%d\n", sm_delta_dsoc);
+               }
        }
 
        }
 
-       di->rsoc = rk81x_bat_get_rsoc(di);
-
-       DBG("<%s>. rsoc = %d, dsoc = %d, dischrg_algorithm_mode=%d\n",
-           __func__, di->rsoc, di->dsoc, di->dischrg_algorithm_mode);
-
-       if (di->dischrg_algorithm_mode == DISCHRG_NORMAL_MODE) {
-               delta_soc = di->dsoc - di->rsoc;
+       /* check overflow */
+       if (di->zero_dsoc > (di->dsoc + 1) * 1000 - MIN_ACCURACY) {
+               DBG("ZERO1: zero dsoc overflow: %d\n", di->zero_dsoc);
+               di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY;
+       }
 
 
-               if (delta_soc > DSOC_DISCHRG_FAST_EER_RANGE) {
-                       di->dischrg_normal_base = 0;
-                       rk81x_bat_emulator_dischrg(di);
+       /* check new dsoc */
+       tmp_soc = di->zero_dsoc / 1000;
+       if (tmp_soc != di->dsoc) {
+               /* avoid dsoc jump when heavy load */
+               if ((di->dsoc - tmp_soc) > 1) {
+                       di->dsoc--;
+                       di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY;
+                       DBG("ZERO1: heavy load...\n");
                } else {
                } else {
-                       di->chrg_emu_base = 0;
-                       rk81x_bat_normal_dischrg(di);
+                       di->dsoc = tmp_soc;
                }
                }
+               di->zero_drop_sec = 0;
+       }
 
 
-               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) {
-                               tmp_dsoc = (di->display_soc +
-                                               MIN_ROUND_ACCURACY) / 1000;
-                               /* if last display_soc invalid, recalc.
-                                * otherwise keep this value(in case: plugin and
-                                * plugout quickly or wakeup from deep sleep,
-                                * we need't init display_soc)
-                                */
-                               if (tmp_dsoc != di->dsoc)
-                                       /* first init value should round up,
-                                        * other wise dsoc will quickly turn to
-                                        * dsoc-- if MIN_ROUND_ACCURACY value is
-                                        * small,eg:1.(in case: power on system)
-                                        */
-                                       di->display_soc = (di->dsoc + 1) *
-                                               1000 - MIN_ROUND_ACCURACY;
-                               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);
+out:
+       DBG("ZERO1: zero_dsoc(Y0)=%d, dsoc=%d, rsoc=%d, tmp_soc=%d\n",
+           di->zero_dsoc, di->dsoc, di->rsoc, tmp_soc);
+       DBG("ZERO1: sm_dischrg_dsoc=%d, sm_chrg_dsoc=%d\n",
+           di->sm_dischrg_dsoc, di->sm_chrg_dsoc);
+}
 
 
-               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 rk818_bat_zero_algorithm(struct rk818_battery *di)
+{
+       int delta_cap = 0, delta_soc = 0;
+
+       di->zero_timeout_cnt++;
+       delta_cap = di->zero_remain_cap - di->remain_cap;
+       delta_soc = di->zero_linek * (delta_cap * 100) / DIV(di->fcc);
+
+       DBG("ZERO1: zero_linek=%d, zero_dsoc(Y0)=%d, dsoc=%d, rsoc=%d\n"
+           "ZERO1: delta_soc(X0)=%d, delta_cap=%d, zero_remain_cap = %d\n"
+           "ZERO1: timeout_cnt=%d, sm_dischrg=%d, sm_chrg=%d\n\n",
+           di->zero_linek, di->zero_dsoc, di->dsoc, di->rsoc,
+           delta_soc, delta_cap, di->zero_remain_cap,
+           di->zero_timeout_cnt, di->sm_dischrg_dsoc, di->sm_chrg_dsoc);
+
+       if ((delta_soc >= MIN_ZERO_DSOC_ACCURACY) ||
+           (di->zero_timeout_cnt > MIN_ZERO_OVERCNT) ||
+           (di->zero_linek == 0)) {
+               DBG("ZERO1:--------- enter calc -----------\n");
+               di->zero_timeout_cnt = 0;
+               di->zero_dsoc -= delta_soc;
+               rk818_bat_calc_zero_algorithm(di);
+               rk818_bat_calc_zero_linek(di);
        }
 }
 
        }
 }
 
-static void rk81x_bat_dbg_time_table(struct rk81x_battery *di)
+static void rk818_bat_dump_time_table(struct rk818_battery *di)
 {
        u8 i;
        static int old_index;
        static int old_min;
 {
        u8 i;
        static int old_index;
        static int old_min;
-       u32 time;
        int mod = di->dsoc % 10;
        int index = di->dsoc / 10;
        int mod = di->dsoc % 10;
        int index = di->dsoc / 10;
+       u32 time;
 
 
-       if (rk81x_chrg_online(di))
-               time = di->plug_in_min;
+       if (rk818_bat_chrg_online(di))
+               time = base2min(di->plug_in_base);
        else
        else
-               time = di->plug_out_min;
+               time = base2min(di->plug_out_base);
 
        if ((mod == 0) && (index > 0) && (old_index != index)) {
 
        if ((mod == 0) && (index > 0) && (old_index != index)) {
-               di->chrg_min[index-1] = time - old_min;
+               di->dbg_chrg_min[index - 1] = time - old_min;
                old_min = time;
                old_index = index;
        }
 
        for (i = 1; i < 11; i++)
                old_min = time;
                old_index = index;
        }
 
        for (i = 1; i < 11; i++)
-               DBG("Time[%d]=%d, ", (i * 10), di->chrg_min[i-1]);
+               DBG("Time[%d]=%d, ", (i * 10), di->dbg_chrg_min[i - 1]);
        DBG("\n");
 }
 
        DBG("\n");
 }
 
-static void rk81x_bat_dbg_dmp_info(struct rk81x_battery *di)
+static void rk818_bat_debug_info(struct rk818_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;
-
-       if (dbg_enable) {
-               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);
-       }
+       u8 sup_tst, ggcon, ggsts, vb_mod, ts_ctrl, reboot_cnt;
+       u8 usb_ctrl, chrg_ctrl1, thermal;
+       u8 int_sts1, int_sts2;
+       u8 int_msk1, int_msk2;
+       u8 chrg_ctrl2, chrg_ctrl3, rtc, misc, dcdc_en;
+       char *work_mode[] = {"ZERO", "FINISH", "UN", "UN", "SMOOTH"};
+       char *bat_mode[] = {"BAT", "VIRTUAL"};
+
+       if (rk818_bat_chrg_online(di))
+               di->plug_out_base = get_boot_sec();
+       else
+               di->plug_in_base = get_boot_sec();
+
+       rk818_bat_dump_time_table(di);
+
+       if (!dbg_enable)
+               return;
 
 
-       DBG("\n------------- dump_debug_regs -----------------\n"
-           "GGCON = 0x%2x, GGSTS = 0x%2x, RTC  = 0x%2x\n"
-           "SUP_STS_REG  = 0x%2x, VB_MOD_REG   = 0x%2x\n"
-           "USB_CTRL_REG  = 0x%2x, CHRG_CTRL_REG1 = 0x%2x\n"
-           "THERMAL_REG = 0x%2x, MISC_MARK_REG = 0x%x\n"
-           "CHRG_CTRL_REG2 = 0x%2x, CHRG_CTRL_REG3 = 0x%2x\n\n",
-           ggcon_reg, ggsts_reg, rtc_val,
-           sup_tst_reg, vb_mod_reg,
-           usb_ctrl_reg, chrg_ctrl_reg1,
-           thremal_reg, misc_reg,
-           chrg_ctrl_reg2, chrg_ctrl_reg3
+       ts_ctrl = rk818_bat_read(di, RK818_TS_CTRL_REG);
+       misc = rk818_bat_read(di, RK818_MISC_MARK_REG);
+       ggcon = rk818_bat_read(di, RK818_GGCON_REG);
+       ggsts = rk818_bat_read(di, RK818_GGSTS_REG);
+       sup_tst = rk818_bat_read(di, RK818_SUP_STS_REG);
+       vb_mod = rk818_bat_read(di, RK818_VB_MON_REG);
+       usb_ctrl = rk818_bat_read(di, RK818_USB_CTRL_REG);
+       chrg_ctrl1 = rk818_bat_read(di, RK818_CHRG_CTRL_REG1);
+       chrg_ctrl2 = rk818_bat_read(di, RK818_CHRG_CTRL_REG2);
+       chrg_ctrl3 = rk818_bat_read(di, RK818_CHRG_CTRL_REG3);
+       rtc = rk818_bat_read(di, 0);
+       thermal = rk818_bat_read(di, RK818_THERMAL_REG);
+       int_sts1 = rk818_bat_read(di, RK818_INT_STS_REG1);
+       int_sts2 = rk818_bat_read(di, RK818_INT_STS_REG2);
+       int_msk1 = rk818_bat_read(di, RK818_INT_STS_MSK_REG1);
+       int_msk2 = rk818_bat_read(di, RK818_INT_STS_MSK_REG2);
+       dcdc_en = rk818_bat_read(di, RK818_DCDC_EN_REG);
+       reboot_cnt = rk818_bat_read(di, RK818_REBOOT_CNT_REG);
+
+       DBG("\n------- DEBUG REGS, [Ver: %s] -------------------\n"
+           "GGCON=0x%2x, GGSTS=0x%2x, RTC=0x%2x, DCDC_EN2=0x%2x\n"
+           "SUP_STS= 0x%2x, VB_MOD=0x%2x, USB_CTRL=0x%2x\n"
+           "THERMAL=0x%2x, MISC_MARK=0x%2x, TS_CTRL=0x%2x\n"
+           "CHRG_CTRL:REG1=0x%2x, REG2=0x%2x, REG3=0x%2x\n"
+           "INT_STS:  REG1=0x%2x, REG2=0x%2x\n"
+           "INT_MSK:  REG1=0x%2x, REG2=0x%2x\n",
+           DRIVER_VERSION, ggcon, ggsts, rtc, dcdc_en,
+           sup_tst, vb_mod, usb_ctrl,
+           thermal, misc, ts_ctrl,
+           chrg_ctrl1, chrg_ctrl2, chrg_ctrl3,
+           int_sts1, int_sts2, int_msk1, int_msk2
           );
 
           );
 
-       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"
-           "display_soc = %d, cpapacity_soc = %d\n"
-           "AC-ONLINE = %d, USB-ONLINE = %d, charging_status = %d\n"
-           "i_offset=0x%x, cal_offset=0x%x, adjust_cap=%d\n"
-           "plug_in = %d, plug_out = %d, finish_sig = %d, finish_chrg=%lu\n"
-           "sec: chrg=%lu, dischrg=%lu, term_chrg=%lu, emu_chrg=%lu\n"
-           "emu_dischrg = %lu, power_on_sec = %lu\n"
-           "mode:%d, save_chrg_sec = %lu, save_dischrg_sec = %lu\n"
-           "#########################################################\n",
-           di->voltage, di->current_avg,
-           di->fcc, di->remain_capacity, di->voltage_ocv,
-           di->est_ocv_vol, di->est_ocv_soc, di->bat_res,
-           di->dsoc, di->rsoc,
-           di->ac_online, di->usb_online, di->psy_status,
-           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_finish_base),
-           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),
-           di->current_mode, di->chrg_save_sec, di->dischrg_save_sec
+       DBG("###############################################################\n"
+           "Dsoc=%d, Rsoc=%d, Vavg=%d, Iavg=%d, Cap=%d, Fcc=%d, d=%d\n"
+           "K=%d, Mode=%s, Oldcap=%d, Is=%d, Ip=%d, Vs=%d\n"
+           "shtd_min=%d, fb_temp=%d, bat_temp=%d, sample_res=%d\n"
+           "off:i=0x%x, c=0x%x, p=%d, Rbat=%d, age_ocv_cap=%d, fb=%d\n"
+           "adp:finish=%lu, boot_min=%lu, sleep_min=%lu, adc=%d, Vsys=%d\n"
+           "bat:%s, meet: soc=%d, calc: dsoc=%d, rsoc=%d, Vocv=%d\n"
+           "pwr: dsoc=%d, rsoc=%d, vol=%d, halt: st=%d, cnt=%d, reboot=%d\n"
+           "max=%d, init=%d, sw=%d, ocv_c=%d, below0=%d, changed=%d\n"
+           "###############################################################\n",
+           di->dsoc, di->rsoc, di->voltage_avg, di->current_avg,
+           di->remain_cap, di->fcc, di->rsoc - di->dsoc,
+           di->sm_linek, work_mode[di->work_mode], di->sm_remain_cap,
+           di->res_div * chrg_cur_sel_array[chrg_ctrl1 & 0x0f],
+           chrg_cur_input_array[usb_ctrl & 0x0f],
+           chrg_vol_sel_array[(chrg_ctrl1 & 0x70) >> 4],
+           di->pwroff_min,
+           feedback_temp_array[(thermal & 0x0c) >> 2], di->temperature,
+           di->pdata->sample_res, rk818_bat_get_ioffset(di),
+           rk818_bat_get_coffset(di), di->poffset, di->bat_res,
+           di->age_adjust_cap, di->fb_blank, base2min(di->finish_base),
+           base2min(di->boot_base), di->sleep_sum_sec / 60,
+           di->adc_allow_update,
+           di->voltage_avg + di->current_avg * DEF_PWRPATH_RES / 1000,
+           bat_mode[di->pdata->bat_mode], di->dbg_meet_soc, di->dbg_calc_dsoc,
+           di->dbg_calc_rsoc, di->voltage_ocv, di->dbg_pwr_dsoc,
+           di->dbg_pwr_rsoc, di->dbg_pwr_vol, di->is_halt, di->halt_cnt,
+           reboot_cnt, di->is_max_soc_offset, di->is_initialized,
+           di->is_sw_reset, di->is_ocv_calib, di->dbg_cap_low0, di->last_dsoc
           );
 }
 
           );
 }
 
-static void rk81x_bat_update_fcc(struct rk81x_battery *di)
+static void rk818_bat_init_capacity(struct rk818_battery *di, u32 cap)
 {
 {
-       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);
-
-       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->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);
-
-               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);
-               }
+       int delta_cap;
 
 
-               di->dod0_status = 0;
-       }
-}
+       delta_cap = cap - di->remain_cap;
+       if (!delta_cap)
+               return;
 
 
-static void rk81x_bat_dbg_get_finish_soc(struct rk81x_battery *di)
-{
-       if (di->chrg_status == CHARGE_FINISH) {
-               di->debug_finish_real_soc = di->dsoc;
-               di->debug_finish_temp_soc = di->rsoc;
-       }
+       di->age_adjust_cap += delta_cap;
+       rk818_bat_init_coulomb_cap(di, cap);
+       rk818_bat_smooth_algo_prepare(di);
+       rk818_bat_zero_algo_prepare(di);
 }
 
 }
 
-static void rk81x_bat_wait_finish_sig(struct rk81x_battery *di)
+static void rk818_bat_update_age_fcc(struct rk818_battery *di)
 {
 {
-       int chrg_finish_vol = di->pdata->max_charger_voltagemV;
-       bool ret;
+       int fcc, remain_cap, age_keep_min, lock_fcc;
 
 
-       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);
-       }
-}
+       lock_fcc = rk818_bat_get_coulomb_cap(di);
+       remain_cap = lock_fcc - di->age_ocv_cap - di->age_adjust_cap;
+       age_keep_min = base2min(di->age_keep_sec);
 
 
-static void rk81x_bat_finish_chrg(struct rk81x_battery *di)
-{
-       unsigned long sec_finish;
-       int soc_time = 0, plus_soc;
-       int temp;
+       DBG("<%s>. lock_fcc=%d, age:ocv_cap=%d, adjust_cap=%d, remain_cap=%d, "
+           "allow_update=%d, keep_min:%d\n",
+           __func__, lock_fcc, di->age_ocv_cap, di->age_adjust_cap, remain_cap,
+           di->age_allow_update, age_keep_min);
 
 
-       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
-                       soc_time = temp / 450;
+       if ((di->chrg_status == CHARGE_FINISH) && (di->age_allow_update) &&
+           (age_keep_min < 1200)) {
+               di->age_allow_update = false;
+               fcc = remain_cap * 100 / DIV(100 - di->age_ocv_soc);
+               BAT_INFO("lock_fcc=%d, calc_cap=%d, age: soc=%d, cap=%d, "
+                        "level=%d, fcc:%d->%d?\n",
+                        lock_fcc, remain_cap, di->age_ocv_soc,
+                        di->age_ocv_cap, di->age_level, di->fcc, fcc);
 
 
-               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;
+               if ((fcc < di->qmax) && (fcc > MIN_FCC)) {
+                       BAT_INFO("fcc:%d->%d!\n", di->fcc, fcc);
+                       di->fcc = fcc;
+                       rk818_bat_init_capacity(di, di->fcc);
+                       rk818_bat_save_fcc(di, di->fcc);
+                       rk818_bat_save_age_level(di, di->age_level);
                }
                }
-               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 u8 rk81x_bat_get_valid_soc(unsigned long soc)
+static void rk818_bat_wait_finish_sig(struct rk818_battery *di)
 {
 {
-       return (soc <= 100) ? soc : 0;
-}
+       int chrg_finish_vol = di->pdata->max_chrg_voltage;
 
 
-static void rk81x_bat_normal_chrg(struct rk81x_battery *di)
-{
-       int now_current;
-       u32 soc_time, unit_sec;
-       int plus_soc = 0;
-       unsigned long chrg_normal_sec;
-
-       now_current = rk81x_bat_get_avg_current(di);
-       soc_time = di->fcc * 3600 / 100 / div(abs(now_current)); /*1% time*/
-
-       if (!di->chrg_normal_base)
-               di->chrg_normal_base = get_runtime_sec();
-
-       chrg_normal_sec = BASE_TO_SEC(di->chrg_normal_base) + di->chrg_save_sec;
-       di->rsoc = rk81x_bat_get_rsoc(di);
-
-       DBG("<%s>. rsoc=%d, dsoc=%d, chrg_st=%d\n",
-           __func__, di->rsoc, di->dsoc, di->charge_smooth_status);
-
-       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 = rk81x_bat_get_valid_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 = rk81x_bat_get_valid_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;
-               }
-       }
+       if (!rk818_bat_chrg_online(di))
+               return;
 
 
-       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);
+       if ((di->chrg_status == CHARGE_FINISH) && (di->adc_allow_update) &&
+           (di->voltage_avg > chrg_finish_vol - 150)) {
+               rk818_bat_update_age_fcc(di);
+               if (rk818_bat_adc_calib(di))
+                       di->adc_allow_update = false;
+       }
 }
 
 }
 
-static void rk81x_bat_update_time(struct rk81x_battery *di)
+static void rk818_bat_finish_algorithm(struct rk818_battery *di)
 {
 {
-       u64 runtime_sec;
-
-       runtime_sec = get_runtime_sec();
-
-       /*update by charger type*/
-       if (rk81x_chrg_online(di))
-               di->plug_out_base = runtime_sec;
-       else
-               di->plug_in_base = runtime_sec;
+       unsigned long finish_sec, soc_sec;
+       int plus_soc, rest = 0;
 
 
-       /*update by current*/
-       if (di->chrg_status != CHARGE_FINISH) {
-               di->finish_sig_base = runtime_sec;
-               di->chrg_finish_base = runtime_sec;
+       /* rsoc */
+       if ((di->remain_cap != di->fcc) &&
+           (rk818_bat_get_chrg_status(di) == CHARGE_FINISH)) {
+               di->age_adjust_cap += (di->fcc - di->remain_cap);
+               rk818_bat_init_coulomb_cap(di, di->fcc);
        }
 
        }
 
-       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);
-
-       rk81x_bat_dbg_time_table(di);
-}
-
-static int rk81x_bat_get_rsoc_trend(struct rk81x_battery *di, int *trend_mult)
-{
-       int trend_start_cap = di->trend_start_cap;
-       int remain_cap = di->remain_capacity;
-       int diff_cap;
-       int state;
-
-       if (di->s2r && !di->slp_psy_status)
-               di->trend_start_cap = di->remain_capacity;
-
-       diff_cap = remain_cap - trend_start_cap;
-       DBG("<%s>. trend_start_cap = %d, diff_cap = %d\n",
-           __func__, trend_start_cap, diff_cap);
-       *trend_mult = abs(diff_cap) / TREND_CAP_DIFF;
-
-       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;
+       /* dsoc */
+       if (di->dsoc < 100) {
+               if (!di->finish_base)
+                       di->finish_base = get_boot_sec();
+               finish_sec = base2sec(di->finish_base);
+               soc_sec = di->fcc * 3600 / 100 / FINISH_CHRG_CUR;
+               plus_soc = finish_sec / soc_sec;
+               if (finish_sec > soc_sec) {
+                       rest = finish_sec % soc_sec;
+                       di->dsoc += plus_soc;
+                       di->finish_base = get_boot_sec();
+                       if (di->finish_base > rest)
+                               di->finish_base = get_boot_sec() - rest;
+               }
+               DBG("<%s>.CHARGE_FINISH:dsoc<100,dsoc=%d\n"
+                   "soc_time=%lu, sec_finish=%lu, plus_soc=%d, rest=%d\n",
+                   __func__, di->dsoc, soc_sec, finish_sec, plus_soc, rest);
        }
        }
-
-       return state;
 }
 
 }
 
-static void rk81x_bat_arbitrate_rsoc_trend(struct rk81x_battery *di)
+static void rk818_bat_calc_smooth_dischrg(struct rk818_battery *di)
 {
 {
-       int state, soc_time;
-       static int trend_down_cnt, trend_up_cnt;
-       int trend_cnt_thresd;
-       int now_current = di->current_avg;
-       int trend_mult = 0;
-
-       trend_cnt_thresd = di->fcc / 100 / TREND_CAP_DIFF;
-       state = rk81x_bat_get_rsoc_trend(di, &trend_mult);
-       DBG("<%s>. TREND_STAT = %d, trend_mult = %d\n",
-           __func__, state, trend_mult);
-       if (di->chrg_status == CHARGE_FINISH)
-               return;
+       int tmp_soc = 0, sm_delta_dsoc = 0, zero_delta_dsoc = 0;
 
 
-       if (state == TREND_STAT_UP) {
-               rk81x_bat_reset_zero_var(di);
-               trend_down_cnt = 0;
-               trend_up_cnt += trend_mult;
-               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 += trend_mult;
-               if (trend_down_cnt >= trend_cnt_thresd) {
-                       trend_down_cnt = 0;
-                       di->chrg_save_sec = 0;
+       tmp_soc = di->sm_dischrg_dsoc / 1000;
+       if (tmp_soc == di->dsoc)
+               goto out;
+
+       DBG("<%s>. enter: dsoc=%d, rsoc=%d\n", __func__, di->dsoc, di->rsoc);
+       /* when dischrge slow down, take sm charge rest into calc */
+       if (di->dsoc < di->rsoc) {
+               tmp_soc = di->sm_chrg_dsoc / 1000;
+               if (tmp_soc == di->dsoc) {
+                       sm_delta_dsoc = di->sm_chrg_dsoc - di->dsoc * 1000;
+                       di->sm_chrg_dsoc = di->dsoc * 1000;
+                       di->sm_dischrg_dsoc += sm_delta_dsoc;
+                       DBG("<%s>. take sm dischrg, delta=%d\n",
+                           __func__, sm_delta_dsoc);
                }
        }
 
                }
        }
 
-       soc_time = di->fcc * 3600 / 100 / div(abs(now_current));
-       if ((di->chrg_save_sec * 3 / 4 > soc_time) &&
-           (trend_up_cnt <= trend_cnt_thresd / 2) &&
-           (now_current >= 0))
-               di->chrg_save_sec = 0;
-
-       else if ((di->dischrg_save_sec * 3 / 4 > soc_time) &&
-                (trend_down_cnt <= trend_cnt_thresd / 2) &&
-                (now_current < 0))
-               di->dischrg_save_sec = 0;
-
-       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;
-
-       if (di->chrg_status == CHARGE_FINISH ||
-           di->slp_chrg_status == CHARGE_FINISH) {
-               /*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);
+       /* when discharge speed up, take zero discharge rest into calc */
+       if (di->dsoc > di->rsoc) {
+               tmp_soc = di->zero_dsoc / 1000;
+               if (tmp_soc == di->dsoc) {
+                       zero_delta_dsoc = di->zero_dsoc - ((di->dsoc + 1) *
+                                               1000 - MIN_ACCURACY);
+                       di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY;
+                       di->sm_dischrg_dsoc += zero_delta_dsoc;
+                       DBG("<%s>. take zero schrg, delta=%d\n",
+                           __func__, zero_delta_dsoc);
+               }
        }
        }
-}
 
 
-static unsigned long rk81x_bat_save_dischrg_sec(struct rk81x_battery *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);
+       /* check up overflow */
+       if ((di->sm_dischrg_dsoc) > ((di->dsoc + 1) * 1000 - MIN_ACCURACY)) {
+               DBG("<%s>. dischrg_dsoc up overflow\n", __func__);
+               di->sm_dischrg_dsoc = (di->dsoc + 1) *
+                                       1000 - MIN_ACCURACY;
+       }
 
 
-       DBG("dischrg_normal_sec=%lu, dischrg_emu_sec=%lu\n",
-           dischrg_normal_sec, dischrg_emu_sec);
+       /* check new dsoc */
+       tmp_soc = di->sm_dischrg_dsoc / 1000;
+       if (tmp_soc != di->dsoc) {
+               di->dsoc = tmp_soc;
+               di->sm_chrg_dsoc = di->dsoc * 1000;
+       }
+out:
+       DBG("<%s>. dsoc=%d, rsoc=%d, dsoc:sm_dischrg=%d, sm_chrg=%d, zero=%d\n",
+           __func__, di->dsoc, di->rsoc, di->sm_dischrg_dsoc, di->sm_chrg_dsoc,
+           di->zero_dsoc);
 
 
-       return (dischrg_normal_sec > dischrg_emu_sec) ?
-               dischrg_normal_sec : dischrg_emu_sec;
 }
 
 }
 
-static unsigned long rk81x_bat_save_chrg_sec(struct rk81x_battery *di)
+static void rk818_bat_calc_smooth_chrg(struct rk818_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);
-
-       sec1 = (chrg_normal_sec > chrg_term_sec) ?
-               chrg_normal_sec : chrg_term_sec;
-
-       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;
-}
+       int tmp_soc = 0, sm_delta_dsoc = 0, zero_delta_dsoc = 0;
 
 
-static void rk81x_bat_display_smooth(struct rk81x_battery *di)
-{
-       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);
-               }
+       tmp_soc = di->sm_chrg_dsoc / 1000;
+       if (tmp_soc == di->dsoc)
+               goto out;
 
 
-               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;
+       DBG("<%s>. enter: dsoc=%d, rsoc=%d\n", __func__, di->dsoc, di->rsoc);
+       /* when charge slow down, take zero & sm dischrg into calc */
+       if (di->dsoc > di->rsoc) {
+               /* take sm discharge rest into calc */
+               tmp_soc = di->sm_dischrg_dsoc / 1000;
+               if (tmp_soc == di->dsoc) {
+                       sm_delta_dsoc = di->sm_dischrg_dsoc -
+                                       ((di->dsoc + 1) * 1000 - MIN_ACCURACY);
+                       di->sm_dischrg_dsoc = (di->dsoc + 1) * 1000 -
+                                                       MIN_ACCURACY;
+                       di->sm_chrg_dsoc += sm_delta_dsoc;
+                       DBG("<%s>. take sm dischrg, delta=%d\n",
+                          __func__, sm_delta_dsoc);
                }
                }
-       } 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);
+
+               /* take zero discharge rest into calc */
+               tmp_soc = di->zero_dsoc / 1000;
+               if (tmp_soc == di->dsoc) {
+                       zero_delta_dsoc = di->zero_dsoc -
+                       ((di->dsoc + 1) * 1000 - MIN_ACCURACY);
+                       di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY;
+                       di->sm_chrg_dsoc += zero_delta_dsoc;
+                       DBG("<%s>. take zero dischrg, delta=%d\n",
+                           __func__, zero_delta_dsoc);
                }
                }
-               rk81x_bat_dischrg_smooth(di);
-               di->charge_smooth_status = true;
        }
        }
-}
-
-/*
- * update rsoc by relax voltage
- */
-static void rk81x_bat_relax_vol_calib(struct rk81x_battery *di)
-{
-       int relax_vol = di->relax_voltage;
-       int ocv_soc, capacity;
-
-       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);
-}
 
 
-/* condition:
- * 1: must do it, 0: when necessary
- */
-static void rk81x_bat_vol_calib(struct rk81x_battery *di, int condition)
-{
-       int ocv_vol = di->est_ocv_vol;
-       int ocv_soc = 0, capacity = 0;
-
-       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__);
+       /* check down overflow */
+       if (di->sm_chrg_dsoc < di->dsoc * 1000) {
+               DBG("<%s>. chrg_dsoc down overflow\n", __func__);
+               di->sm_chrg_dsoc = di->dsoc * 1000;
        }
        }
-       DBG("<%s>, OCV_VOL=%d,OCV_SOC=%d, CAP=%d\n",
-           __func__, ocv_vol, ocv_soc, capacity);
-}
 
 
-static int  rk81x_bat_sleep_dischrg(struct rk81x_battery *di)
-{
-       int delta_soc = 0;
-       int temp_dsoc;
-       unsigned long sleep_sec = di->suspend_time_sum;
-       int power_off_thresd = di->pdata->power_off_thresd;
-
-       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);
-
-       if (di->relax_voltage >= di->voltage) {
-               rk81x_bat_relax_vol_calib(di);
-               rk81x_bat_restart_relax(di);
-
-       /* 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);
+       /* check new dsoc */
+       tmp_soc = di->sm_chrg_dsoc / 1000;
+       if (tmp_soc != di->dsoc) {
+               di->dsoc = tmp_soc;
+               di->sm_dischrg_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY;
        }
        }
-
-       /*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;
-
-               pr_info("battery calib0: rl=%d, dl=%d, intl=%d\n",
-                       di->rsoc, 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;
+out:
+       DBG("<%s>.dsoc=%d, rsoc=%d, dsoc: sm_dischrg=%d, sm_chrg=%d, zero=%d\n",
+           __func__, di->dsoc, di->rsoc, di->sm_dischrg_dsoc, di->sm_chrg_dsoc,
+           di->zero_dsoc);
+}
+
+static void rk818_bat_smooth_algorithm(struct rk818_battery *di)
+{
+       int ydsoc = 0, delta_cap = 0, old_cap = 0;
+       unsigned long tgt_sec = 0;
+
+       di->remain_cap = rk818_bat_get_coulomb_cap(di);
+
+       /* full charge: slow down */
+       if ((di->dsoc == 99) && (di->chrg_status == CC_OR_CV)) {
+               di->sm_linek = FULL_CHRG_K;
+       /* terminal charge, slow down */
+       } else if ((di->current_avg >= TERM_CHRG_CURR) &&
+           (di->chrg_status == CC_OR_CV) && (di->dsoc >= TERM_CHRG_DSOC)) {
+               di->sm_linek = TERM_CHRG_K;
+               DBG("<%s>. terminal mode..\n", __func__);
+       /* simulate charge, speed up */
+       } else if ((di->current_avg <= SIMULATE_CHRG_CURR) &&
+                  (di->current_avg > 0) && (di->chrg_status == CC_OR_CV) &&
+                  (di->dsoc < TERM_CHRG_DSOC) &&
+                  ((di->rsoc - di->dsoc) >= SIMULATE_CHRG_INTV)) {
+               di->sm_linek = SIMULATE_CHRG_K;
+               DBG("<%s>. simulate mode..\n", __func__);
+       } else {
+               /* charge and discharge switch */
+               if ((di->sm_linek * di->current_avg <= 0) ||
+                   (di->sm_linek == TERM_CHRG_K) ||
+                   (di->sm_linek == FULL_CHRG_K) ||
+                   (di->sm_linek == SIMULATE_CHRG_K)) {
+                       DBG("<%s>. linek mode, retinit sm linek..\n", __func__);
+                       rk818_bat_calc_sm_linek(di);
                }
                }
+       }
 
 
-               DBG("%s: dsoc<=rsoc, sum_cap=%d==>delta_soc=%d,temp_dsoc=%d\n",
-                   __func__, di->sum_suspend_cap, delta_soc, temp_dsoc);
+       old_cap = di->sm_remain_cap;
+       /*
+        * when dsoc equal rsoc(not include full, term, simulate case),
+        * sm_linek should change to -1000/1000 smoothly to avoid dsoc+1/-1
+        * right away, so change it after flat seconds
+        */
+       if ((di->dsoc == di->rsoc) && (abs(di->sm_linek) != 1000) &&
+           (di->sm_linek != FULL_CHRG_K && di->sm_linek != TERM_CHRG_K &&
+            di->sm_linek != SIMULATE_CHRG_K)) {
+               if (!di->flat_match_sec)
+                       di->flat_match_sec = get_boot_sec();
+               tgt_sec = di->fcc * 3600 / 100 / abs(di->current_avg) / 3;
+               if (base2sec(di->flat_match_sec) >= tgt_sec) {
+                       di->flat_match_sec = 0;
+                       di->sm_linek = (di->current_avg >= 0) ? 1000 : -1000;
+               }
+               DBG("<%s>. flat_sec=%ld, tgt_sec=%ld, sm_k=%d\n", __func__,
+                   base2sec(di->flat_match_sec), tgt_sec, di->sm_linek);
        } else {
        } 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;
-
-               pr_info("battery calib1: rsoc=%d, dsoc=%d, intsoc=%d\n",
-                       di->rsoc, di->dsoc, delta_soc);
-
-               if ((di->est_ocv_vol > SLP_DSOC_VOL_THRESD) &&
-                   (temp_dsoc > delta_soc))
-                       di->dsoc -= delta_soc;
-               else
-                       di->dsoc = di->rsoc;
-
-               DBG("%s: dsoc > rsoc, sum_cap=%d==>delta_soc=%d,temp_dsoc=%d\n",
-                   __func__, di->sum_suspend_cap, delta_soc, temp_dsoc);
+               di->flat_match_sec = 0;
        }
 
        }
 
-       if (!di->relax_voltage && di->voltage <= power_off_thresd)
-               di->dsoc = 0;
-
-       if (di->dsoc <= 0)
-               di->dsoc = 0;
+       /* abs(k)=1000 or dsoc=100, stop calc */
+       if ((abs(di->sm_linek) == 1000) || (di->current_avg >= 0 &&
+            di->chrg_status == CC_OR_CV && di->dsoc >= 100)) {
+               DBG("<%s>. sm_linek=%d\n", __func__, di->sm_linek);
+               if (abs(di->sm_linek) == 1000) {
+                       di->dsoc = di->rsoc;
+                       di->sm_linek = (di->sm_linek > 0) ? 1000 : -1000;
+                       DBG("<%s>. dsoc == rsoc, sm_linek=%d\n",
+                           __func__, di->sm_linek);
+               }
+               di->sm_remain_cap = di->remain_cap;
+               di->sm_chrg_dsoc = di->dsoc * 1000;
+               di->sm_dischrg_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY;
+               DBG("<%s>. sm_dischrg_dsoc=%d, sm_chrg_dsoc=%d\n",
+                   __func__, di->sm_dischrg_dsoc, di->sm_chrg_dsoc);
+       } else {
+               delta_cap = di->remain_cap - di->sm_remain_cap;
+               if (delta_cap == 0) {
+                       DBG("<%s>. delta_cap = 0\n", __func__);
+                       return;
+               }
+               ydsoc = di->sm_linek * abs(delta_cap) * 100 / DIV(di->fcc);
+               if (ydsoc == 0) {
+                       DBG("<%s>. ydsoc = 0\n", __func__);
+                       return;
+               }
+               di->sm_remain_cap = di->remain_cap;
 
 
-       DBG("<%s>, out: dsoc=%d, rsoc=%d, sum_cap=%d\n",
-           __func__, di->dsoc, di->rsoc, di->sum_suspend_cap);
+               DBG("<%s>. k=%d, ydsoc=%d; cap:old=%d, new:%d; delta_cap=%d\n",
+                   __func__, di->sm_linek, ydsoc, old_cap,
+                   di->sm_remain_cap, delta_cap);
 
 
-       return delta_soc;
-}
+               /* discharge mode */
+               if (ydsoc < 0) {
+                       di->sm_dischrg_dsoc += ydsoc;
+                       rk818_bat_calc_smooth_dischrg(di);
+               /* charge mode */
+               } else {
+                       di->sm_chrg_dsoc += ydsoc;
+                       rk818_bat_calc_smooth_chrg(di);
+               }
 
 
-static int rk81x_bat_sleep_chrg(struct rk81x_battery *di)
-{
-       int sleep_soc = 0;
-       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);
+               if (di->s2r) {
+                       di->s2r = false;
+                       rk818_bat_calc_sm_linek(di);
                }
                }
-       } else {
-               DBG("<%s>, usb charge\n", __func__);
        }
        }
-
-       return sleep_soc;
 }
 
 /*
 }
 
 /*
- * only do report when there is a change.
- *
- * 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.
+ * cccv and finish switch all the time will cause dsoc freeze,
+ * if so, do finish chrg, 100ma is less than min finish_ma.
  */
  */
-static void rk81x_bat_power_supply_changed(struct rk81x_battery *di)
+static bool rk818_bat_fake_finish_mode(struct rk818_battery *di)
 {
 {
-       static u32 old_soc;
-       static u32 old_ac_status;
-       static u32 old_usb_status;
-       static u32 old_charge_status;
-       bool state_changed;
-
-       state_changed = false;
-       if ((di->dsoc == 0) && (di->fg_drv_mode == FG_NORMAL_MODE))
-               state_changed = true;
-       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->psy_status)
-               state_changed = true;
-
-       if (rk81x_chrg_online(di)) {
-               if (di->dsoc == 100)
-                       di->psy_status = POWER_SUPPLY_STATUS_FULL;
-               else
-                       di->psy_status = POWER_SUPPLY_STATUS_CHARGING;
+       if ((di->rsoc == 100) && (rk818_bat_get_chrg_status(di) == CC_OR_CV) &&
+           (abs(di->current_avg) <= 100))
+               return true;
+       else
+               return false;
+}
+
+static void rk818_bat_display_smooth(struct rk818_battery *di)
+{
+       /* discharge: reinit "zero & smooth" algorithm to avoid handling dsoc */
+       if (di->s2r && !di->sleep_chrg_online) {
+               DBG("s2r: discharge, reset algorithm...\n");
+               di->s2r = false;
+               rk818_bat_zero_algo_prepare(di);
+               rk818_bat_smooth_algo_prepare(di);
+               return;
        }
 
        }
 
-       if (state_changed) {
-               power_supply_changed(&di->bat);
-               power_supply_changed(&di->usb);
-               power_supply_changed(&di->ac);
-               old_soc = di->dsoc;
-               old_ac_status = di->ac_online;
-               old_usb_status = di->usb_online;
-               old_charge_status = di->psy_status;
-               dev_info(di->dev, "changed: dsoc=%d, rsoc=%d\n",
-                        di->dsoc, di->rsoc);
+       if (di->work_mode == MODE_FINISH) {
+               DBG("step1: charge finish...\n");
+               rk818_bat_finish_algorithm(di);
+               if ((rk818_bat_get_chrg_status(di) != CHARGE_FINISH) &&
+                   !rk818_bat_fake_finish_mode(di)) {
+                       if ((di->current_avg < 0) &&
+                           (di->voltage_avg < di->pdata->zero_algorithm_vol)) {
+                               DBG("step1: change to zero mode...\n");
+                               rk818_bat_zero_algo_prepare(di);
+                               di->work_mode = MODE_ZERO;
+                       } else {
+                               DBG("step1: change to smooth mode...\n");
+                               rk818_bat_smooth_algo_prepare(di);
+                               di->work_mode = MODE_SMOOTH;
+                       }
+               }
+       } else if (di->work_mode == MODE_ZERO) {
+               DBG("step2: zero algorithm...\n");
+               rk818_bat_zero_algorithm(di);
+               if ((di->voltage_avg >= di->pdata->zero_algorithm_vol + 50) ||
+                   (di->current_avg >= 0)) {
+                       DBG("step2: change to smooth mode...\n");
+                       rk818_bat_smooth_algo_prepare(di);
+                       di->work_mode = MODE_SMOOTH;
+               } else if ((rk818_bat_get_chrg_status(di) == CHARGE_FINISH) ||
+                          rk818_bat_fake_finish_mode(di)) {
+                       DBG("step2: change to finish mode...\n");
+                       rk818_bat_finish_algo_prepare(di);
+                       di->work_mode = MODE_FINISH;
+               }
+       } else {
+               DBG("step3: smooth algorithm...\n");
+               rk818_bat_smooth_algorithm(di);
+               if ((di->current_avg < 0) &&
+                   (di->voltage_avg < di->pdata->zero_algorithm_vol)) {
+                       DBG("step3: change to zero mode...\n");
+                       rk818_bat_zero_algo_prepare(di);
+                       di->work_mode = MODE_ZERO;
+               } else if ((rk818_bat_get_chrg_status(di) == CHARGE_FINISH) ||
+                          rk818_bat_fake_finish_mode(di)) {
+                       DBG("step3: change to finish mode...\n");
+                       rk818_bat_finish_algo_prepare(di);
+                       di->work_mode = MODE_FINISH;
+               }
        }
 }
 
        }
 }
 
-#if 0
-static u8 rk81x_bat_get_cvcc_chrg_hour(struct rk81x_battery *di)
+static void rk818_bat_relax_vol_calib(struct rk818_battery *di)
 {
 {
-       u8 hour, buf;
-
-       rk81x_bat_read(di, CHRG_CTRL_REG2, &buf, 1);
-       hour = buf & 0x07;
+       int soc, cap, vol;
 
 
-       return CHRG_CVCC_HOUR[hour];
+       vol = di->voltage_relax;
+       soc = rk818_bat_vol_to_ocvsoc(di, vol);
+       cap = rk818_bat_vol_to_ocvcap(di, vol);
+       rk818_bat_init_capacity(di, cap);
+       BAT_INFO("sleep ocv calib: rsoc=%d, cap=%d\n", soc, cap);
 }
 
 }
 
-/* we have to estimate the charging finish time from now, to decide
- * whether we should reset the timer or not.
- */
-static void rk81x_bat_chrg_over_time_check(struct rk81x_battery *di)
+static void rk818_bat_relife_age_flag(struct rk818_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;
+       u8 ocv_soc, ocv_cap, soc_level;
 
 
-       DBG("CHRG_TIME(min): %ld, cvcc hour: %d",
-           BASE_TO_MIN(di->plug_in_base), cvcc_hour);
+       if (di->voltage_relax <= 0)
+               return;
 
 
-       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;
+       ocv_soc = rk818_bat_vol_to_ocvsoc(di, di->voltage_relax);
+       ocv_cap = rk818_bat_vol_to_ocvcap(di, di->voltage_relax);
+       DBG("<%s>. ocv_soc=%d, min=%lu, vol=%d\n", __func__,
+           ocv_soc, di->sleep_dischrg_sec / 60, di->voltage_relax);
 
 
-               di->chrg_time2full = di->chrg_cap2full * 3600 /
-                                       div(abs(di->current_avg));
+       /* sleep enough time and ocv_soc enough low */
+       if (!di->age_allow_update && ocv_soc <= 10) {
+               di->age_voltage = di->voltage_relax;
+               di->age_ocv_cap = ocv_cap;
+               di->age_ocv_soc = ocv_soc;
+               di->age_adjust_cap = 0;
 
 
-               DBG("CHRG_TIME2FULL(min):%d, chrg_cap2full=%d, current=%d\n",
-                   SEC_TO_MIN(di->chrg_time2full), di->chrg_cap2full,
-                   di->current_avg);
+               if (ocv_soc <= 1)
+                       di->age_level = 100;
+               else if (ocv_soc < 5)
+                       di->age_level = 90;
+               else
+                       di->age_level = 80;
 
 
-               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__);
+               soc_level = rk818_bat_get_age_level(di);
+               if (soc_level > di->age_level) {
+                       di->age_allow_update = false;
+               } else {
+                       di->age_allow_update = true;
+                       di->age_keep_sec = get_boot_sec();
                }
                }
+
+               BAT_INFO("resume: age_vol:%d, age_ocv_cap:%d, age_ocv_soc:%d, "
+                        "soc_level:%d, age_allow_update:%d, "
+                        "age_level:%d\n",
+                        di->age_voltage, di->age_ocv_cap, ocv_soc, soc_level,
+                        di->age_allow_update, di->age_level);
        }
 }
        }
 }
-#endif
 
 
-/*
- * in case that we will do reboot stress test, we need a special way
- * to ajust the dsoc.
- */
-static void rk81x_bat_check_reboot(struct rk81x_battery *di)
+static int rk818_bat_sleep_dischrg(struct rk818_battery *di)
 {
 {
-       u8 rsoc = di->rsoc;
-       u8 dsoc = di->dsoc;
-       u8 cnt;
-       int unit_time;
-       int smooth_time;
+       bool ocv_soc_updated = false;
+       int tgt_dsoc, gap_soc, sleep_soc = 0;
+       int pwroff_vol = di->pdata->pwroff_vol;
+       unsigned long sleep_sec = di->sleep_dischrg_sec;
 
 
-       rk81x_bat_read(di, REBOOT_CNT_REG, &cnt, 1);
-       cnt++;
+       DBG("<%s>. enter: dsoc=%d, rsoc=%d, rv=%d, v=%d, sleep_min=%lu\n",
+           __func__, di->dsoc, di->rsoc, di->voltage_relax,
+           di->voltage_avg, sleep_sec / 60);
+
+       if (di->voltage_relax >= di->voltage_avg) {
+               rk818_bat_relax_vol_calib(di);
+               rk818_bat_restart_relax(di);
+               rk818_bat_relife_age_flag(di);
+               ocv_soc_updated = true;
+       }
 
 
-       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->power_on_base), dsoc, rsoc);
-
-       if (di->current_avg >= 0 || di->chrg_status == CHARGE_FINISH) {
-               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;
-                       rk81x_bat_save_dsoc(di, dsoc);
+       /* handle dsoc */
+       if (di->dsoc <= di->rsoc) {
+               di->sleep_sum_cap = (SLP_CURR_MIN * sleep_sec / 3600);
+               sleep_soc = di->sleep_sum_cap * 100 / di->fcc;
+               tgt_dsoc = di->dsoc - sleep_soc;
+               if (sleep_soc > 0) {
+                       BAT_INFO("calib0: rl=%d, dl=%d, intval=%d\n",
+                                di->rsoc, di->dsoc, sleep_soc);
+                       if (di->dsoc < 5) {
+                               di->dsoc--;
+                       } else if ((tgt_dsoc < 5) && (di->dsoc >= 5)) {
+                               if (di->dsoc == 5)
+                                       di->dsoc--;
+                               else
+                                       di->dsoc = 5;
+                       } else if (tgt_dsoc > 5) {
+                               di->dsoc = tgt_dsoc;
+                       }
                }
                }
+
+               DBG("%s: dsoc<=rsoc, sum_cap=%d==>sleep_soc=%d, tgt_dsoc=%d\n",
+                   __func__, di->sleep_sum_cap, sleep_soc, tgt_dsoc);
        } else {
        } else {
-               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;
-                       rk81x_bat_save_dsoc(di, dsoc);
+               /* di->dsoc > di->rsoc */
+               di->sleep_sum_cap = (SLP_CURR_MAX * sleep_sec / 3600);
+               sleep_soc = di->sleep_sum_cap / (di->fcc / 100);
+               gap_soc = di->dsoc - di->rsoc;
+
+               BAT_INFO("calib1: rsoc=%d, dsoc=%d, intval=%d\n",
+                        di->rsoc, di->dsoc, sleep_soc);
+               if (gap_soc > sleep_soc) {
+                       if ((gap_soc - 5) > (sleep_soc * 2))
+                               di->dsoc -= (sleep_soc * 2);
+                       else
+                               di->dsoc -= sleep_soc;
+               } else {
+                       di->dsoc = di->rsoc;
                }
                }
+
+               DBG("%s: dsoc>rsoc, sum_cap=%d=>sleep_soc=%d, gap_soc=%d\n",
+                   __func__, di->sleep_sum_cap, sleep_soc, gap_soc);
+       }
+
+       if (di->voltage_avg <= pwroff_vol - 70) {
+               di->dsoc = 0;
+               BAT_INFO("low power sleeping, shutdown... %d\n", di->dsoc);
        }
 
        }
 
-       rk81x_bat_save_reboot_cnt(di, cnt);
-}
+       if (ocv_soc_updated && sleep_soc && (di->rsoc - di->dsoc) < 5 &&
+           di->dsoc < 40) {
+               di->dsoc--;
+               BAT_INFO("low power sleeping, reserved... %d\n", di->dsoc);
+       }
 
 
-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));
+       if (di->dsoc <= 0) {
+               di->dsoc = 0;
+               BAT_INFO("sleep dsoc is %d...\n", di->dsoc);
        }
        }
+
+       DBG("<%s>. out: dsoc=%d, rsoc=%d, sum_cap=%d\n",
+           __func__, di->dsoc, di->rsoc, di->sleep_sum_cap);
+
+       return sleep_soc;
 }
 
 }
 
-static void rk81x_bat_update_info(struct rk81x_battery *di)
+static void rk818_bat_power_supply_changed(struct rk818_battery *di)
 {
 {
+       static int old_soc = -1;
+
        if (di->dsoc > 100)
                di->dsoc = 100;
        else if (di->dsoc < 0)
                di->dsoc = 0;
 
        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 (!rk81x_chrg_online(di) && di->s2r)
+       if (di->dsoc == old_soc)
                return;
 
                return;
 
-       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);
+       old_soc = di->dsoc;
+       di->last_dsoc = di->dsoc;
+       power_supply_changed(di->bat);
+       BAT_INFO("changed: dsoc=%d, rsoc=%d, v=%d, c=%d, cap=%d\n",
+                di->dsoc, di->rsoc, di->voltage_avg, di->current_avg,
+                di->remain_cap);
 }
 
 }
 
-static void rk81x_bat_fcc_flag_check(struct rk81x_battery *di)
+static u8 rk818_bat_check_reboot(struct rk818_battery *di)
 {
 {
-       u8 ocv_soc, soc_level;
-       int relax_vol = di->relax_voltage;
+       u8 cnt;
 
 
-       if (relax_vol <= 0)
-               return;
+       cnt = rk818_bat_read(di, RK818_REBOOT_CNT_REG);
+       cnt++;
 
 
-       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 (cnt >= REBOOT_MAX_CNT) {
+               BAT_INFO("reboot: %d --> %d\n", di->dsoc, di->rsoc);
+               di->dsoc = di->rsoc;
+               if (di->dsoc > 100)
+                       di->dsoc = 100;
+               else if (di->dsoc < 0)
+                       di->dsoc = 0;
+               rk818_bat_save_dsoc(di, di->dsoc);
+               cnt = REBOOT_MAX_CNT;
+       }
 
 
-       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;
+       rk818_bat_save_reboot_cnt(di, cnt);
+       DBG("reboot cnt: %d\n", cnt);
 
 
-               if (ocv_soc <= 1)
-                       di->dod0_level = 100;
-               else if (ocv_soc < 5)
-                       di->dod0_level = 90;
-               else
-                       di->dod0_level = 80;
+       return cnt;
+}
 
 
-               /* 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();
+static void rk818_bat_rsoc_daemon(struct rk818_battery *di)
+{
+       int est_vol;
+       static unsigned long sec;
+
+       if ((di->remain_cap < 0) && (di->fb_blank != 0)) {
+               sec = get_boot_sec();
+               wake_lock_timeout(&di->wake_lock,
+                                 (di->pdata->monitor_sec + 1) * HZ);
+               if (base2sec(sec) >= 60) {
+                       sec = 0;
+                       di->dbg_cap_low0++;
+                       est_vol = di->voltage_avg -
+                                       (di->bat_res * di->current_avg) / 1000;
+                       di->remain_cap = rk818_bat_vol_to_ocvcap(di, est_vol);
+                       di->rsoc = rk818_bat_vol_to_ocvsoc(di, est_vol);
+                       rk818_bat_init_capacity(di, di->remain_cap);
+                       BAT_INFO("adjust cap below 0 --> %d, rsoc=%d\n",
+                                di->remain_cap, di->rsoc);
+                       wake_unlock(&di->wake_lock);
                }
                }
-
-               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);
+       } else {
+               sec = 0;
        }
 }
 
        }
 }
 
-static void rk81x_chrg_term_mode_set(struct rk81x_battery *di, int mode)
+static void rk818_bat_update_info(struct rk818_battery *di)
 {
 {
-       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);
+       di->voltage_avg = rk818_bat_get_avg_voltage(di);
+       di->current_avg = rk818_bat_get_avg_current(di);
+       di->voltage_relax = rk818_bat_get_relax_voltage(di);
+       di->rsoc = rk818_bat_get_rsoc(di);
+       di->remain_cap = rk818_bat_get_coulomb_cap(di);
+       di->chrg_status = rk818_bat_get_chrg_status(di);
 
 
-       dev_info(di->dev, "set charge to %s termination mode\n",
-                mode ? "digital" : "analog");
-}
+       /* smooth charge */
+       if (di->remain_cap > di->fcc) {
+               di->sm_remain_cap -= (di->remain_cap - di->fcc);
+               DBG("<%s>. cap: remain=%d, sm_remain=%d\n",
+                   __func__, di->remain_cap, di->sm_remain_cap);
+               rk818_bat_init_coulomb_cap(di, di->fcc);
+       }
 
 
-static void rk81x_chrg_term_mode_switch_work(struct work_struct *work)
-{
-       struct rk81x_battery *di;
+       if (di->chrg_status != CHARGE_FINISH)
+               di->finish_base = get_boot_sec();
 
 
-       di = container_of(work, struct rk81x_battery,
-                         chrg_term_mode_switch_work.work);
+       /*
+        * 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: age_allow_update.
+        */
+       if (base2min(di->plug_out_base) > 120)
+               di->age_allow_update = false;
 
 
-       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);
+       /* do adc calib: status must from cccv mode to finish mode */
+       if (di->chrg_status == CC_OR_CV)
+               di->adc_allow_update = true;
 }
 
 }
 
-static void rk81x_battery_work(struct work_struct *work)
+/* get ntc resistance */
+static int rk818_bat_get_ntc_res(struct rk818_battery *di)
 {
 {
-       struct rk81x_battery *di;
-       int ms = TIMER_MS_COUNTS;
-
-       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;
+       int val = 0;
+
+       val |= rk818_bat_read(di, RK818_TS1_ADC_REGL) << 0;
+       val |= rk818_bat_read(di, RK818_TS1_ADC_REGH) << 8;
 
 
-       di->s2r = 0;
+       val = val * NTC_CALC_FACTOR; /*reference voltage 2.2V,current 80ua*/
+       DBG("<%s>. ntc_res=%d\n", __func__, val);
 
 
-       queue_delayed_work(di->wq, &di->battery_monitor_work,
-                          msecs_to_jiffies(ms));
+       return val;
 }
 
 }
 
-#if defined(CONFIG_ARCH_ROCKCHIP)
-static void rk81x_battery_otg_delay_work(struct work_struct *work)
+static void rk818_bat_update_temperature(struct rk818_battery *di)
 {
 {
-       struct rk81x_battery *di = container_of(work,
-                       struct rk81x_battery, otg_check_work.work);
+       u32 ntc_size, *ntc_table;
+       int i, res;
 
 
-       enum bc_port_type event = di->charge_otg;
+       ntc_table = di->pdata->ntc_table;
+       ntc_size = di->pdata->ntc_size;
+       di->temperature = VIRTUAL_TEMPERATURE;
 
 
-       /* do not touch CHRG_CTRL_REG1[7]: CHRG_EN, hardware can
-        * recognize otg plugin and will auto ajust this bit
-        */
-       switch (event) {
-       case USB_OTG_POWER_ON:
-               di->otg_online = ONLINE;
-               if (power_dc2otg && di->dc_online) {
-                       dev_info(di->dev, "otg power from dc adapter\n");
-                       return;
+       if (ntc_size) {
+               res = rk818_bat_get_ntc_res(di);
+               if (res < ntc_table[ntc_size - 1]) {
+                       BAT_INFO("bat ntc upper max degree: R=%d\n", res);
+               } else if (res > ntc_table[0]) {
+                       BAT_INFO("bat ntc lower min degree: R=%d\n", res);
+               } else {
+                       for (i = 0; i < ntc_size; i++) {
+                               if (res >= ntc_table[i])
+                                       break;
+                       }
+                       di->temperature = (i + di->pdata->ntc_degree_from) * 10;
                }
                }
-               dev_info(di->dev, "charge disable, otg enable\n");
-               rk81x_bat_set_otg_state(di, USB_OTG_POWER_ON);
-               break;
-
-       case USB_OTG_POWER_OFF:
-               dev_info(di->dev, "charge enable, otg disable\n");
-               di->otg_online = OFFLINE;
-               rk81x_bat_set_otg_state(di, USB_OTG_POWER_OFF);
-               /*maybe dc still plugin*/
-               queue_delayed_work(di->wq, &di->dc_det_check_work,
-                                  msecs_to_jiffies(10));
-               break;
-
-       default:
-               break;
        }
 }
 
        }
 }
 
-static BLOCKING_NOTIFIER_HEAD(battery_chain_head);
-
-int register_battery_notifier(struct notifier_block *nb)
+static void rk818_bat_init_dsoc_algorithm(struct rk818_battery *di)
 {
 {
-       return blocking_notifier_chain_register(&battery_chain_head, nb);
-}
-EXPORT_SYMBOL_GPL(register_battery_notifier);
+       u8 buf;
+       int16_t rest = 0;
+       unsigned long soc_sec;
+       const char *mode_name[] = { "MODE_ZERO", "MODE_FINISH",
+               "MODE_SMOOTH_CHRG", "MODE_SMOOTH_DISCHRG", "MODE_SMOOTH", };
+
+       /* get rest */
+       rest |= rk818_bat_read(di, RK818_CALC_REST_REGH) << 8;
+       rest |= rk818_bat_read(di, RK818_CALC_REST_REGL) << 0;
+
+       /* get mode */
+       buf = rk818_bat_read(di, RK818_MISC_MARK_REG);
+       di->algo_rest_mode = (buf & ALGO_REST_MODE_MSK) >> ALGO_REST_MODE_SHIFT;
+
+       if (rk818_bat_get_chrg_status(di) == CHARGE_FINISH) {
+               if (di->algo_rest_mode == MODE_FINISH) {
+                       soc_sec = di->fcc * 3600 / 100 / FINISH_CHRG_CUR;
+                       if ((rest / soc_sec) > 0) {
+                               if (di->dsoc < 100) {
+                                       di->dsoc++;
+                                       di->algo_rest_val = rest % soc_sec;
+                                       BAT_INFO("algorithm rest(%d) dsoc "
+                                                "inc: %d\n",
+                                                rest, di->dsoc);
+                               } else {
+                                       di->algo_rest_val = 0;
+                               }
+                       } else {
+                               di->algo_rest_val = rest;
+                       }
+               } else {
+                       di->algo_rest_val = rest;
+               }
+       } else {
+               /* charge speed up */
+               if ((rest / 1000) > 0 && rk818_bat_chrg_online(di)) {
+                       if (di->dsoc < di->rsoc) {
+                               di->dsoc++;
+                               di->algo_rest_val = rest % 1000;
+                               BAT_INFO("algorithm rest(%d) dsoc inc: %d\n",
+                                        rest, di->dsoc);
+                       } else {
+                               di->algo_rest_val = 0;
+                       }
+               /* discharge speed up */
+               } else if (((rest / 1000) < 0) && !rk818_bat_chrg_online(di)) {
+                       if (di->dsoc > di->rsoc) {
+                               di->dsoc--;
+                               di->algo_rest_val = rest % 1000;
+                               BAT_INFO("algorithm rest(%d) dsoc sub: %d\n",
+                                        rest, di->dsoc);
+                       } else {
+                               di->algo_rest_val = 0;
+                       }
+               } else {
+                       di->algo_rest_val = rest;
+               }
+       }
 
 
-int unregister_battery_notifier(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_unregister(&battery_chain_head, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_battery_notifier);
+       if (di->dsoc >= 100)
+               di->dsoc = 100;
+       else if (di->dsoc <= 0)
+               di->dsoc = 0;
 
 
-int battery_notifier_call_chain(unsigned long val)
-{
-       return (blocking_notifier_call_chain(&battery_chain_head, val, NULL)
-               == NOTIFY_BAD) ? -EINVAL : 0;
-}
-EXPORT_SYMBOL_GPL(battery_notifier_call_chain);
+       /* init current mode */
+       di->voltage_avg = rk818_bat_get_avg_voltage(di);
+       di->current_avg = rk818_bat_get_avg_current(di);
+       if (rk818_bat_get_chrg_status(di) == CHARGE_FINISH) {
+               rk818_bat_finish_algo_prepare(di);
+               di->work_mode = MODE_FINISH;
+       } else if ((di->current_avg < 0) &&
+                  (di->voltage_avg < di->pdata->zero_algorithm_vol)) {
+               rk818_bat_zero_algo_prepare(di);
+               di->work_mode = MODE_ZERO;
+       } else {
+               rk818_bat_smooth_algo_prepare(di);
+               di->work_mode = MODE_SMOOTH;
+       }
+
+       DBG("<%s>. init: org_rest=%d, rest=%d, mode=%s; "
+           "doc(x1000): zero=%d, chrg=%d, dischrg=%d, finish=%lu\n",
+           __func__, rest, di->algo_rest_val, mode_name[di->algo_rest_mode],
+           di->zero_dsoc, di->sm_chrg_dsoc, di->sm_dischrg_dsoc,
+           di->finish_base);
+}
+
+static void rk818_bat_save_algo_rest(struct rk818_battery *di)
+{
+       u8 buf, mode;
+       int16_t algo_rest = 0;
+       int tmp_soc;
+       int zero_rest = 0, sm_chrg_rest = 0;
+       int sm_dischrg_rest = 0, finish_rest = 0;
+       const char *mode_name[] = { "MODE_ZERO", "MODE_FINISH",
+               "MODE_SMOOTH_CHRG", "MODE_SMOOTH_DISCHRG", "MODE_SMOOTH", };
+
+       /* zero dischrg */
+       tmp_soc = (di->zero_dsoc) / 1000;
+       if (tmp_soc == di->dsoc)
+               zero_rest = di->zero_dsoc - ((di->dsoc + 1) * 1000 -
+                               MIN_ACCURACY);
+
+       /* sm chrg */
+       tmp_soc = di->sm_chrg_dsoc / 1000;
+       if (tmp_soc == di->dsoc)
+               sm_chrg_rest = di->sm_chrg_dsoc - di->dsoc * 1000;
+
+       /* sm dischrg */
+       tmp_soc = (di->sm_dischrg_dsoc) / 1000;
+       if (tmp_soc == di->dsoc)
+               sm_dischrg_rest = di->sm_dischrg_dsoc - ((di->dsoc + 1) * 1000 -
+                               MIN_ACCURACY);
+
+       /* last time is also finish chrg, then add last rest */
+       if (di->algo_rest_mode == MODE_FINISH && di->algo_rest_val)
+               finish_rest = base2sec(di->finish_base) + di->algo_rest_val;
+       else
+               finish_rest = base2sec(di->finish_base);
+
+       /* total calc */
+       if ((rk818_bat_chrg_online(di) && (di->dsoc > di->rsoc)) ||
+           (!rk818_bat_chrg_online(di) && (di->dsoc < di->rsoc)) ||
+           (di->dsoc == di->rsoc)) {
+               di->algo_rest_val = 0;
+               algo_rest = 0;
+               DBG("<%s>. step1..\n", __func__);
+       } else if (di->work_mode == MODE_FINISH) {
+               algo_rest = finish_rest;
+               DBG("<%s>. step2..\n", __func__);
+       } else if (di->algo_rest_mode == MODE_FINISH) {
+               algo_rest = zero_rest + sm_dischrg_rest + sm_chrg_rest;
+               DBG("<%s>. step3..\n", __func__);
+       } else {
+               if (rk818_bat_chrg_online(di) && (di->dsoc < di->rsoc))
+                       algo_rest = sm_chrg_rest + di->algo_rest_val;
+               else if (!rk818_bat_chrg_online(di) && (di->dsoc > di->rsoc))
+                       algo_rest = zero_rest + sm_dischrg_rest +
+                                   di->algo_rest_val;
+               else
+                       algo_rest = zero_rest + sm_dischrg_rest + sm_chrg_rest +
+                                   di->algo_rest_val;
+               DBG("<%s>. step4..\n", __func__);
+       }
 
 
-static int rk81x_bat_usb_notifier_call(struct notifier_block *nb,
-                                      unsigned long event, void *data)
-{
-       enum charger_type charger_type;
-       struct rk81x_battery *di =
-           container_of(nb, struct rk81x_battery, battery_nb);
-
-       if (di->fg_drv_mode == TEST_POWER_MODE)
-               return NOTIFY_OK;
-
-       /*if dc is pluging, ignore usb*/
-       charger_type = rk81x_bat_get_dc_state(di);
-       if ((charger_type == DC_CHARGER) &&
-           (event != USB_OTG_POWER_OFF) &&
-           (event != USB_OTG_POWER_ON))
-               return NOTIFY_OK;
-
-       switch (event) {
-       case USB_BC_TYPE_DISCNT:/*maybe dc still plugin*/
-               queue_delayed_work(di->wq, &di->dc_det_check_work,
-                                  msecs_to_jiffies(10));
-               break;
-       case USB_BC_TYPE_SDP:
-       case USB_BC_TYPE_CDP:/*nonstandard charger*/
-       case USB_BC_TYPE_DCP:/*standard charger*/
-               queue_delayed_work(di->wq, &di->ac_usb_check_work,
-                                  msecs_to_jiffies(10));
-               break;
-       case USB_OTG_POWER_ON:/*otg on*/
-               di->charge_otg  = USB_OTG_POWER_ON;
-               queue_delayed_work(di->wq, &di->otg_check_work,
-                                  msecs_to_jiffies(10));
-               break;
-       case USB_OTG_POWER_OFF:/*otg off*/
-               di->charge_otg = USB_OTG_POWER_OFF;
-               queue_delayed_work(di->wq, &di->otg_check_work,
-                                  msecs_to_jiffies(10));
-               break;
-       default:
-               return NOTIFY_OK;
+       /* check mode */
+       if ((di->work_mode == MODE_FINISH) || (di->work_mode == MODE_ZERO)) {
+               mode = di->work_mode;
+       } else {/* MODE_SMOOTH */
+               if (di->sm_linek > 0)
+                       mode = MODE_SMOOTH_CHRG;
+               else
+                       mode = MODE_SMOOTH_DISCHRG;
        }
        }
-       return NOTIFY_OK;
-}
-#endif
-static irqreturn_t rk81x_vbat_lo_irq(int irq, void *bat)
-{
-       pr_info("\n------- %s:lower power warning!\n", __func__);
 
 
-       rk_send_wakeup_key();
-       kernel_power_off();
-       return IRQ_HANDLED;
-}
+       /* save mode */
+       buf = rk818_bat_read(di, RK818_MISC_MARK_REG);
+       buf &= ~ALGO_REST_MODE_MSK;
+       buf |= (mode << ALGO_REST_MODE_SHIFT);
+       rk818_bat_write(di, RK818_MISC_MARK_REG, buf);
 
 
-static irqreturn_t rk81x_vbat_plug_in(int irq, void *bat)
-{
-       pr_info("\n------- %s:irq = %d\n", __func__, irq);
-       rk_send_wakeup_key();
-       return IRQ_HANDLED;
+       /* save rest */
+       buf = (algo_rest >> 8) & 0xff;
+       rk818_bat_write(di, RK818_CALC_REST_REGH, buf);
+       buf = (algo_rest >> 0) & 0xff;
+       rk818_bat_write(di, RK818_CALC_REST_REGL, buf);
+
+       DBG("<%s>. rest: algo=%d, mode=%s, last_rest=%d; zero=%d, "
+           "chrg=%d, dischrg=%d, finish=%lu\n",
+           __func__, algo_rest, mode_name[mode], di->algo_rest_val, zero_rest,
+           sm_chrg_rest, sm_dischrg_rest, base2sec(di->finish_base));
 }
 
 }
 
-static irqreturn_t rk81x_vbat_plug_out(int irq, void  *bat)
+static void rk818_bat_save_data(struct rk818_battery *di)
 {
 {
-       pr_info("\n-------- %s:irq = %d\n", __func__, irq);
-       rk_send_wakeup_key();
-       return IRQ_HANDLED;
+       rk818_bat_save_dsoc(di, di->dsoc);
+       rk818_bat_save_cap(di, di->remain_cap);
+       rk818_bat_save_algo_rest(di);
 }
 
 }
 
-static irqreturn_t rk81x_vbat_charge_ok(int irq, void  *bat)
+static void rk818_battery_work(struct work_struct *work)
 {
 {
-       struct rk81x_battery *di = (struct rk81x_battery *)bat;
+       struct rk818_battery *di =
+               container_of(work, struct rk818_battery, bat_delay_work.work);
 
 
-       pr_info("\n---------- %s:irq = %d\n", __func__, irq);
-       di->finish_sig_base = get_runtime_sec();
-       rk_send_wakeup_key();
-       return IRQ_HANDLED;
+       rk818_bat_update_info(di);
+       rk818_bat_wait_finish_sig(di);
+       rk818_bat_rsoc_daemon(di);
+       rk818_bat_update_temperature(di);
+       rk818_bat_display_smooth(di);
+       rk818_bat_power_supply_changed(di);
+       rk818_bat_save_data(di);
+       rk818_bat_debug_info(di);
+
+       queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work,
+                          msecs_to_jiffies(di->monitor_ms));
 }
 
 }
 
-static irqreturn_t rk81x_vbat_dc_det(int irq, void *bat)
+static irqreturn_t rk818_vb_low_irq(int irq, void *bat)
 {
 {
-       struct rk81x_battery *di = (struct rk81x_battery *)bat;
+       struct rk818_battery *di = (struct rk818_battery *)bat;
 
 
-       queue_delayed_work(di->wq,
-                          &di->dc_det_check_work,
-                          msecs_to_jiffies(10));
+       di->dsoc = 0;
        rk_send_wakeup_key();
        rk_send_wakeup_key();
+       BAT_INFO("lower power yet, power off system! v=%d, c=%d, dsoc=%d\n",
+                di->voltage_avg, di->current_avg, di->dsoc);
 
        return IRQ_HANDLED;
 }
 
 
        return IRQ_HANDLED;
 }
 
-static int rk81x_bat_sysfs_init(struct rk81x_battery *di)
+static void rk818_bat_init_sysfs(struct rk818_battery *di)
 {
 {
-       int ret;
-       int i;
+       int i, ret;
 
        for (i = 0; i < ARRAY_SIZE(rk818_bat_attr); i++) {
 
        for (i = 0; i < ARRAY_SIZE(rk818_bat_attr); i++) {
-               ret = sysfs_create_file(&di->bat.dev->kobj,
+               ret = sysfs_create_file(&di->dev->kobj,
                                        &rk818_bat_attr[i].attr);
                                        &rk818_bat_attr[i].attr);
-               if (ret != 0)
-                       dev_err(di->dev, "create battery node(%s) error\n",
+               if (ret)
+                       dev_err(di->dev, "create bat node(%s) error\n",
                                rk818_bat_attr[i].attr.name);
        }
                                rk818_bat_attr[i].attr.name);
        }
-
-       return ret;
 }
 
 }
 
-static void rk81x_bat_irq_init(struct rk81x_battery *di)
+static int rk818_bat_init_irqs(struct rk818_battery *di)
 {
 {
-       int plug_in_irq, plug_out_irq, chrg_ok_irq, vb_lo_irq;
-       int ret;
-       struct rk818 *chip = di->rk818;
+       struct rk808 *rk818 = di->rk818;
+       struct platform_device *pdev = di->pdev;
+       int ret, vb_lo_irq;
 
 
-#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);
-       chrg_ok_irq = irq_create_mapping(chip->irq_domain, RK818_IRQ_CHG_OK);
-#endif
+       vb_lo_irq = regmap_irq_get_virq(rk818->irq_data, RK818_IRQ_VB_LO);
+       if (vb_lo_irq < 0) {
+               dev_err(di->dev, "vb_lo_irq request failed!\n");
+               return vb_lo_irq;
+       }
 
 
-       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);
-
-       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, 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(chrg_ok_irq, NULL, rk81x_vbat_charge_ok,
-                                  IRQF_TRIGGER_RISING, "rk81x_vbat_charge_ok",
-                                  di);
-       if (ret != 0)
-               dev_err(chip->dev, "chrg_ok_irq request failed!\n");
-}
+       ret = devm_request_threaded_irq(di->dev, vb_lo_irq, NULL,
+                                       rk818_vb_low_irq, IRQF_TRIGGER_HIGH,
+                                       "rk818_vb_low", di);
+       if (ret) {
+               dev_err(&pdev->dev, "vb_lo_irq request failed!\n");
+               return ret;
+       }
+       enable_irq_wake(vb_lo_irq);
 
 
-static void rk81x_bat_info_init(struct rk81x_battery *di,
-                               struct rk818 *chip)
-{
-       u8 val;
-       unsigned long time_base = POWER_ON_SEC_BASE;
-
-       rk81x_bat_read(di, RK818_VB_MON_REG, &val, 1);
-       if (val & PLUG_IN_STS)
-               rk81x_bat_set_power_supply_state(di, USB_CHARGER);
-
-       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->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);
+       return 0;
 }
 
 }
 
-static void rk81x_bat_dc_det_init(struct rk81x_battery *di,
-                                 struct device_node *np)
+static void rk818_bat_init_info(struct rk818_battery *di)
 {
 {
-       struct device *dev = di->dev;
-       enum of_gpio_flags flags;
-       int ret;
-
-       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");
-               return;
-       }
-
-       if (gpio_is_valid(di->dc_det_pin)) {
-               di->dc_det_level = (flags & OF_GPIO_ACTIVE_LOW) ?
-                                               RK818_DC_IN : RK818_DC_OUT;
-               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", di);
-               if (ret != 0) {
-                       dev_err(di->dev, "rk818_dc_det_irq request failed!\n");
-                       goto err;
-               }
-               enable_irq_wake(di->dc_det_irq);
-       }
-
-       return;
-err:
-       gpio_free(di->dc_det_pin);
+       di->design_cap = di->pdata->design_capacity;
+       di->qmax = di->pdata->design_qmax;
+       di->bat_res = di->pdata->bat_res;
+       di->monitor_ms = di->pdata->monitor_sec * TIMER_MS_COUNTS;
+       di->boot_base = POWER_ON_SEC_BASE;
+       di->res_div = (di->pdata->sample_res == SAMPLE_RES_20MR) ?
+                      SAMPLE_RES_DIV1 : SAMPLE_RES_DIV2;
 }
 
 }
 
-static int rk81x_bat_get_suspend_sec(struct rk81x_battery *di)
+static int rk818_bat_rtc_sleep_sec(struct rk818_battery *di)
 {
        int err;
 {
        int err;
-       int delta_sec = 0;
+       int interval_sec = 0;
        struct rtc_time tm;
        struct rtc_time tm;
-       struct timespec tv = {
-               .tv_nsec = NSEC_PER_SEC >> 1,
-       };
+       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) {
        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");
-               goto out;
+               dev_err(rtc->dev.parent, "hctosys: read hardware clk failed\n");
+               return 0;
        }
        }
+
        err = rtc_valid_tm(&tm);
        if (err) {
        err = rtc_valid_tm(&tm);
        if (err) {
-               dev_err(rtc->dev.parent,
-                       "hctosys: invalid date/time\n");
-               goto out;
+               dev_err(rtc->dev.parent, "hctosys: invalid date time\n");
+               return 0;
        }
 
        rtc_tm_to_time(&tm, &tv.tv_sec);
        }
 
        rtc_tm_to_time(&tm, &tv.tv_sec);
-       delta_sec = tv.tv_sec - di->suspend_rtc_base.tv_sec;
-out:
-       return (delta_sec > 0) ? delta_sec : 0;
+       interval_sec = tv.tv_sec - di->rtc_base.tv_sec;
+
+       return (interval_sec > 0) ? interval_sec : 0;
+}
+
+static void rk818_bat_init_ts1_detect(struct rk818_battery *di)
+{
+       u8 buf;
+
+       if (!di->pdata->ntc_size)
+               return;
+
+       /* ADC_TS1_EN */
+       buf = rk818_bat_read(di, RK818_ADC_CTRL_REG);
+       buf |= ADC_TS1_EN;
+       rk818_bat_write(di, RK818_ADC_CTRL_REG, buf);
+}
+
+static void rk818_bat_set_shtd_vol(struct rk818_battery *di)
+{
+       u8 val;
+
+       /* set vbat lowest 3.0v shutdown */
+       val = rk818_bat_read(di, RK818_VB_MON_REG);
+       val &= ~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK);
+       val |= (RK818_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN);
+       rk818_bat_write(di, RK818_VB_MON_REG, val);
+
+       /* disable low irq */
+       rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1,
+                          VB_LOW_INT_EN, VB_LOW_INT_EN);
+}
+
+static void rk818_bat_init_fg(struct rk818_battery *di)
+{
+       rk818_bat_enable_gauge(di);
+       rk818_bat_init_voltage_kb(di);
+       rk818_bat_init_coffset(di);
+       rk818_bat_set_relax_sample(di);
+       rk818_bat_set_ioffset_sample(di);
+       rk818_bat_set_ocv_sample(di);
+       rk818_bat_init_ts1_detect(di);
+       rk818_bat_init_rsoc(di);
+       rk818_bat_init_coulomb_cap(di, di->nac);
+       rk818_bat_init_age_algorithm(di);
+       rk818_bat_init_chrg_config(di);
+       rk818_bat_set_shtd_vol(di);
+       rk818_bat_init_zero_table(di);
+       rk818_bat_init_caltimer(di);
+       rk818_bat_init_dsoc_algorithm(di);
+
+       di->voltage_avg = rk818_bat_get_avg_voltage(di);
+       di->voltage_ocv = rk818_bat_get_ocv_voltage(di);
+       di->voltage_relax = rk818_bat_get_relax_voltage(di);
+       di->current_avg = rk818_bat_get_avg_current(di);
+       di->remain_cap = rk818_bat_get_coulomb_cap(di);
+       di->dbg_pwr_dsoc = di->dsoc;
+       di->dbg_pwr_rsoc = di->rsoc;
+       di->dbg_pwr_vol = di->voltage_avg;
+
+       rk818_bat_dump_regs(di, 0x99, 0xee);
+       DBG("nac=%d cap=%d ov=%d v=%d rv=%d dl=%d rl=%d c=%d\n",
+           di->nac, di->remain_cap, di->voltage_ocv, di->voltage_avg,
+           di->voltage_relax, di->dsoc, di->rsoc, di->current_avg);
 }
 
 #ifdef CONFIG_OF
 }
 
 #ifdef CONFIG_OF
-static int rk81x_bat_parse_dt(struct rk81x_battery *di)
+static int rk818_bat_parse_dt(struct rk818_battery *di)
 {
 {
-       struct device_node *np;
-       struct battery_platform_data *pdata;
-       struct cell_config *cell_cfg;
-       struct ocv_config *ocv_cfg;
-       struct property *prop;
-       struct rk818 *rk818 = di->rk818;
-       struct device *dev = di->dev;
        u32 out_value;
        int length, ret;
        size_t size;
        u32 out_value;
        int length, ret;
        size_t size;
+       struct device_node *np = di->dev->of_node;
+       struct battery_platform_data *pdata;
+       struct device *dev = di->dev;
 
 
-       np = of_find_node_by_name(rk818->dev->of_node, "battery");
-       if (!np) {
-               dev_err(dev, "battery node not found!\n");
-               return -EINVAL;
-       }
-
-       pdata = devm_kzalloc(rk818->dev, sizeof(*pdata), GFP_KERNEL);
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
 
        if (!pdata)
                return -ENOMEM;
 
-       cell_cfg = devm_kzalloc(rk818->dev, sizeof(*cell_cfg), GFP_KERNEL);
-       if (!cell_cfg)
-               return -ENOMEM;
-
-       ocv_cfg = devm_kzalloc(rk818->dev, sizeof(*ocv_cfg), GFP_KERNEL);
-       if (!ocv_cfg)
-               return -ENOMEM;
-
-       prop = of_find_property(np, "ocv_table", &length);
-       if (!prop) {
+       di->pdata = pdata;
+       /* init default param */
+       pdata->bat_res = DEFAULT_BAT_RES;
+       pdata->monitor_sec = DEFAULT_MONITOR_SEC;
+       pdata->pwroff_vol = DEFAULT_PWROFF_VOL_THRESD;
+       pdata->sleep_exit_current = DEFAULT_SLP_EXIT_CUR;
+       pdata->sleep_enter_current = DEFAULT_SLP_ENTER_CUR;
+       pdata->bat_mode = MODE_BATTARY;
+       pdata->max_soc_offset = DEFAULT_MAX_SOC_OFFSET;
+       pdata->sample_res = DEFAULT_SAMPLE_RES;
+       pdata->energy_mode = DEFAULT_ENERGY_MODE;
+       pdata->fb_temp = DEFAULT_FB_TEMP;
+
+       /* parse necessary param */
+       if (!of_find_property(np, "ocv_table", &length)) {
                dev_err(dev, "ocv_table not found!\n");
                return -EINVAL;
        }
                dev_err(dev, "ocv_table not found!\n");
                return -EINVAL;
        }
+
        pdata->ocv_size = length / sizeof(u32);
        if (pdata->ocv_size <= 0) {
                dev_err(dev, "invalid ocv table\n");
                return -EINVAL;
        }
 
        pdata->ocv_size = length / sizeof(u32);
        if (pdata->ocv_size <= 0) {
                dev_err(dev, "invalid ocv table\n");
                return -EINVAL;
        }
 
-       size = sizeof(*pdata->battery_ocv) * pdata->ocv_size;
-
-       pdata->battery_ocv = devm_kzalloc(rk818->dev, size, GFP_KERNEL);
-       if (!pdata->battery_ocv)
+       size = sizeof(*pdata->ocv_table) * pdata->ocv_size;
+       pdata->ocv_table = devm_kzalloc(di->dev, size, GFP_KERNEL);
+       if (!pdata->ocv_table)
                return -ENOMEM;
 
                return -ENOMEM;
 
-       ret = of_property_read_u32_array(np, "ocv_table", pdata->battery_ocv,
+       ret = of_property_read_u32_array(np, "ocv_table",
+                                        pdata->ocv_table,
                                         pdata->ocv_size);
        if (ret < 0)
                return ret;
 
                                         pdata->ocv_size);
        if (ret < 0)
                return ret;
 
-       /******************** charger param  ****************************/
-       ret = of_property_read_u32(np, "max_chrg_currentmA", &out_value);
-       if (ret < 0) {
-               dev_err(dev, "max_chrg_currentmA not found!\n");
-               out_value = DEFAULT_CHRG_CUR;
-       }
-       pdata->max_charger_currentmA = 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_INPUT_CUR;
-       }
-       pdata->max_charger_ilimitmA = 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;
-       }
-       pdata->sense_resistor_mohm = 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_CHRG_VOL;
-       }
-       pdata->max_charger_voltagemV = 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;
        }
        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;
+       pdata->design_capacity = 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;
        }
 
        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(np, "sleep_enter_current", &out_value);
+       pdata->design_qmax = out_value;
+       ret = of_property_read_u32(np, "max_chrg_voltage", &out_value);
        if (ret < 0) {
        if (ret < 0) {
-               dev_err(dev, "sleep_enter_current not found!\n");
-               out_value = DEFAULT_SLP_ENTER_CUR;
+               dev_err(dev, "max_chrg_voltage missing!\n");
+               return ret;
        }
        }
-       ocv_cfg->sleep_enter_current = out_value;
+       pdata->max_chrg_voltage = out_value;
+       if (out_value >= 4300)
+               pdata->zero_algorithm_vol = DEFAULT_ALGR_VOL_THRESD2;
+       else
+               pdata->zero_algorithm_vol = DEFAULT_ALGR_VOL_THRESD1;
 
 
-       ret = of_property_read_u32(np, "sleep_exit_current", &out_value);
-       if (ret < 0) {
-               dev_err(dev, "sleep_exit_current not found!\n");
-               out_value = DEFAULT_SLP_EXIT_CUR;
-       }
-       ocv_cfg->sleep_exit_current = out_value;
+       ret = of_property_read_u32(np, "fb_temperature", &pdata->fb_temp);
+       if (ret < 0)
+               dev_err(dev, "fb_temperature missing!\n");
 
 
-       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;
+       ret = of_property_read_u32(np, "sample_res", &pdata->sample_res);
+       if (ret < 0)
+               dev_err(dev, "sample_res missing!\n");
 
 
-       of_property_read_u32(np, "chrg_diff_voltagemV", &pdata->chrg_diff_vol);
-       of_property_read_u32(np, "virtual_power", &di->fg_drv_mode);
-       di->fg_drv_mode = di->fg_drv_mode ? TEST_POWER_MODE : FG_NORMAL_MODE;
+       ret = of_property_read_u32(np, "energy_mode", &pdata->energy_mode);
+       if (ret < 0)
+               dev_err(dev, "energy_mode missing!\n");
+
+       ret = of_property_read_u32(np, "max_soc_offset",
+                                  &pdata->max_soc_offset);
+       if (ret < 0)
+               dev_err(dev, "max_soc_offset missing!\n");
+
+       ret = of_property_read_u32(np, "monitor_sec", &pdata->monitor_sec);
+       if (ret < 0)
+               dev_err(dev, "monitor_sec missing!\n");
+
+       ret = of_property_read_u32(np, "zero_algorithm_vol",
+                                  &pdata->zero_algorithm_vol);
+       if (ret < 0)
+               dev_err(dev, "zero_algorithm_vol missing!\n");
+
+       ret = of_property_read_u32(np, "virtual_power", &pdata->bat_mode);
+       if (ret < 0)
+               dev_err(dev, "virtual_power missing!\n");
+
+       ret = of_property_read_u32(np, "bat_res", &pdata->bat_res);
+       if (ret < 0)
+               dev_err(dev, "bat_res missing!\n");
+
+       ret = of_property_read_u32(np, "sleep_enter_current",
+                                  &pdata->sleep_enter_current);
+       if (ret < 0)
+               dev_err(dev, "sleep_enter_current missing!\n");
+
+       ret = of_property_read_u32(np, "sleep_exit_current",
+                                  &pdata->sleep_exit_current);
+       if (ret < 0)
+               dev_err(dev, "sleep_exit_current missing!\n");
+
+       ret = of_property_read_u32(np, "power_off_thresd", &pdata->pwroff_vol);
+       if (ret < 0)
+               dev_err(dev, "power_off_thresd missing!\n");
+
+       if (!of_find_property(np, "ntc_table", &length)) {
+               pdata->ntc_size = 0;
+       } else {
+               /* get ntc degree base value */
+               ret = of_property_read_u32_index(np, "ntc_degree_from", 1,
+                                                &pdata->ntc_degree_from);
+               if (ret) {
+                       dev_err(dev, "invalid ntc_degree_from\n");
+                       return -EINVAL;
+               }
 
 
-       /*************  charger support adp types **********************/
-       ret = of_property_read_u32(np, "support_usb_adp", &support_usb_adp);
-       ret = of_property_read_u32(np, "support_dc_adp", &support_dc_adp);
-       ret = of_property_read_u32(np, "power_dc2otg", &power_dc2otg);
+               of_property_read_u32_index(np, "ntc_degree_from", 0,
+                                          &out_value);
+               if (out_value)
+                       pdata->ntc_degree_from = -pdata->ntc_degree_from;
 
 
-       if (!support_usb_adp && !support_dc_adp) {
-               dev_err(dev, "miss both: usb_adp and dc_adp,default:usb_adp!\n");
-               support_usb_adp = 1;
+               pdata->ntc_size = length / sizeof(u32);
        }
 
        }
 
-       /*if (support_dc_adp)*/
-       rk81x_bat_dc_det_init(di, np);
+       if (pdata->ntc_size) {
+               size = sizeof(*pdata->ntc_table) * pdata->ntc_size;
+               pdata->ntc_table = devm_kzalloc(di->dev, size, GFP_KERNEL);
+               if (!pdata->ntc_table)
+                       return -ENOMEM;
 
 
-       cell_cfg->ocv = ocv_cfg;
-       pdata->cell_cfg = cell_cfg;
-       di->pdata = pdata;
+               ret = of_property_read_u32_array(np, "ntc_table",
+                                                pdata->ntc_table,
+                                                pdata->ntc_size);
+               if (ret < 0)
+                       return ret;
+       }
 
 
-       DBG("\nthe battery dts info dump:\n"
+       DBG("the battery dts info dump:\n"
            "bat_res:%d\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"
            "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);
+           "zero_algorithm_vol:%d\n"
+           "monitor_sec:%d\n"
+           "max_soc_offset:%d\n"
+           "virtual_power:%d\n"
+           "pwroff_vol:%d\n"
+           "sample_res:%d\n"
+           "ntc_size=%d\n"
+           "ntc_degree_from:%d\n"
+           "ntc_degree_to:%d\n",
+           pdata->bat_res, pdata->design_capacity, pdata->design_qmax,
+           pdata->sleep_enter_current, pdata->sleep_exit_current,
+           pdata->zero_algorithm_vol, pdata->monitor_sec,
+           pdata->max_soc_offset, pdata->bat_mode, pdata->pwroff_vol,
+           pdata->sample_res, pdata->ntc_size, pdata->ntc_degree_from,
+           pdata->ntc_degree_from + pdata->ntc_size - 1
+           );
 
        return 0;
 }
 
        return 0;
 }
-
 #else
 #else
-static int rk81x_bat_parse_dt(struct rk81x_battery *di)
+static int rk818_bat_parse_dt(struct rk818_battery *di)
 {
        return -ENODEV;
 }
 #endif
 
 {
        return -ENODEV;
 }
 #endif
 
-static int rk81x_battery_probe(struct platform_device *pdev)
+static const struct of_device_id rk818_battery_of_match[] = {
+       {.compatible = "rk818-battery",},
+       { },
+};
+
+static int rk818_battery_probe(struct platform_device *pdev)
 {
 {
-       struct rk818 *chip = dev_get_drvdata(pdev->dev.parent);
-       struct rk81x_battery *di;
+       const struct of_device_id *of_id =
+                       of_match_device(rk818_battery_of_match, &pdev->dev);
+       struct rk818_battery *di;
+       struct rk808 *rk818 = dev_get_drvdata(pdev->dev.parent);
        int ret;
 
        int ret;
 
+       if (!of_id) {
+               dev_err(&pdev->dev, "Failed to find matching dt id\n");
+               return -ENODEV;
+       }
+
        di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
        if (!di)
                return -ENOMEM;
        di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
        if (!di)
                return -ENOMEM;
-       di->rk818 = chip;
+
+       di->rk818 = rk818;
+       di->pdev = pdev;
        di->dev = &pdev->dev;
        di->dev = &pdev->dev;
+       di->regmap = rk818->regmap;
        platform_set_drvdata(pdev, di);
 
        platform_set_drvdata(pdev, di);
 
-       ret = rk81x_bat_parse_dt(di);
+       ret = rk818_bat_parse_dt(di);
        if (ret < 0) {
        if (ret < 0) {
-               dev_err(&pdev->dev, "rk81x battery parse dt failed!\n");
+               dev_err(di->dev, "rk818 battery parse dt failed!\n");
                return ret;
        }
 
                return ret;
        }
 
-       rk81x_bat_info_init(di, chip);
-       if (!is_rk81x_bat_exist(di)) {
-               dev_info(di->dev, "not battery, enter test power mode\n");
-               di->fg_drv_mode = TEST_POWER_MODE;
+       if (!is_rk818_bat_exist(di)) {
+               di->pdata->bat_mode = MODE_VIRTUAL;
+               dev_err(di->dev, "no battery, virtual power mode\n");
        }
 
        }
 
-       ret = rk81x_bat_power_supply_init(di);
-       if (ret) {
-               dev_err(&pdev->dev, "rk81x power supply register failed!\n");
+       ret = rk818_bat_init_irqs(di);
+       if (ret != 0) {
+               dev_err(di->dev, "rk818 bat init irqs failed!\n");
                return ret;
        }
 
                return ret;
        }
 
-       rk81x_bat_irq_init(di);
-       rk81x_bat_sysfs_init(di);
-
-       rk81x_bat_fg_init(di);
-       wake_lock_init(&di->resume_wake_lock, WAKE_LOCK_SUSPEND,
-                      "resume_charging");
-       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);
+       ret = rk818_bat_init_power_supply(di);
+       if (ret) {
+               dev_err(di->dev, "rk818 power supply register failed!\n");
+               return ret;
        }
        }
-       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
-
-       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));
 
 
-#if defined(CONFIG_ARCH_ROCKCHIP)
-       INIT_DELAYED_WORK(&di->otg_check_work,
-                         rk81x_battery_otg_delay_work);
-       INIT_DELAYED_WORK(&di->ac_usb_check_work,
-                         rk81x_battery_acusb_delay_work);
-       INIT_DELAYED_WORK(&di->dc_det_check_work,
-                         rk81x_battery_dc_delay_work);
-       /*power on check*/
-       queue_delayed_work(di->wq, &di->dc_det_check_work,
+       rk818_bat_init_info(di);
+       rk818_bat_init_fg(di);
+       rk818_bat_init_sysfs(di);
+       rk818_bat_register_fb_notify(di);
+       wake_lock_init(&di->wake_lock, WAKE_LOCK_SUSPEND, "rk818_bat_lock");
+       di->bat_monitor_wq = alloc_ordered_workqueue("%s",
+                       WQ_MEM_RECLAIM | WQ_FREEZABLE, "rk818-bat-monitor-wq");
+       INIT_DELAYED_WORK(&di->bat_delay_work, rk818_battery_work);
+       queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work,
                           msecs_to_jiffies(TIMER_MS_COUNTS * 5));
 
                           msecs_to_jiffies(TIMER_MS_COUNTS * 5));
 
-       di->battery_nb.notifier_call = rk81x_bat_usb_notifier_call;
-       rk_bc_detect_notifier_register(&di->battery_nb, &di->charge_otg);
-#endif
-       dev_info(di->dev, "battery driver version %s\n", DRIVER_VERSION);
+       BAT_INFO("driver version %s\n", DRIVER_VERSION);
 
        return ret;
 }
 
 
        return ret;
 }
 
-static int rk81x_battery_suspend(struct platform_device *dev,
+static int rk818_battery_suspend(struct platform_device *dev,
                                 pm_message_t state)
 {
                                 pm_message_t state)
 {
-       struct rk81x_battery *di = platform_get_drvdata(dev);
-
-       /*while otg and dc both plugin*/
-       rk81x_bat_set_bit(di, NT_STS_MSK_REG2, CHRG_CVTLMT_INT);
-
-       di->slp_psy_status = rk81x_chrg_online(di);
-       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);
-
-       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;
+       struct rk818_battery *di = platform_get_drvdata(dev);
+       u8 val;
+
+       cancel_delayed_work_sync(&di->bat_delay_work);
+
+       di->s2r = false;
+       di->sleep_chrg_online = rk818_bat_chrg_online(di);
+       di->sleep_chrg_status = rk818_bat_get_chrg_status(di);
+       di->current_avg = rk818_bat_get_avg_current(di);
+       di->remain_cap = rk818_bat_get_coulomb_cap(di);
+       di->rsoc = rk818_bat_get_rsoc(di);
+       do_gettimeofday(&di->rtc_base);
+       rk818_bat_save_data(di);
+
+       /* if not CHARGE_FINISH, reinit finish_base.
+        * avoid sleep loop between suspend and resume
+        */
+       if (di->sleep_chrg_status != CHARGE_FINISH)
+               di->finish_base = get_boot_sec();
+
+       /* avoid: enter suspend from MODE_ZERO: load from heavy to light */
+       if ((di->work_mode == MODE_ZERO) &&
+           (di->sleep_chrg_online) && (di->current_avg >= 0)) {
+               DBG("suspend: MODE_ZERO exit...\n");
+               /* it need't do prepare for mode finish and smooth, it will
+                * be done in display_smooth
+                */
+               if (di->sleep_chrg_status == CHARGE_FINISH) {
+                       di->work_mode = MODE_FINISH;
+                       di->finish_base = get_boot_sec();
+               } else {
+                       di->work_mode = MODE_SMOOTH;
+                       rk818_bat_smooth_algo_prepare(di);
+               }
        }
 
        }
 
-       di->s2r = 0;
+       /* set vbat low than 3.4v to generate a wakeup irq */
+       val = rk818_bat_read(di, RK818_VB_MON_REG);
+       val &= (~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK));
+       val |= (RK818_VBAT_LOW_3V4 | EN_VBAT_LOW_IRQ);
+       rk818_bat_write(di, RK818_VB_MON_REG, val);
+       rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1, VB_LOW_INT_EN, 0);
 
 
-       pr_info("battery suspend dl=%d rl=%d c=%d v=%d at=%ld st=0x%x chg=%d\n",
-               di->dsoc, di->rsoc, di->suspend_charge_current, di->voltage,
-               di->suspend_time_sum, di->chrg_status, di->slp_psy_status);
+       BAT_INFO("suspend: dl=%d rl=%d c=%d v=%d cap=%d at=%ld st=0x%x ch=%d\n",
+                di->dsoc, di->rsoc, di->current_avg,
+                rk818_bat_get_avg_voltage(di), rk818_bat_get_coulomb_cap(di),
+                di->sleep_dischrg_sec, di->sleep_chrg_status,
+                di->sleep_chrg_online);
 
        return 0;
 }
 
 
        return 0;
 }
 
-static int rk81x_battery_resume(struct platform_device *dev)
+static int rk818_battery_resume(struct platform_device *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;
-       int vol;
-
-       /*while otg and dc both plugin*/
-       rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, CHRG_CVTLMT_INT);
-
-       di->discharge_smooth_status = true;
-       di->charge_smooth_status = true;
-       di->s2r = 1;
-       vol  = rk81x_bat_get_vol(di);
-       if (vol < INVALID_VOL_THRESD) {
-               dev_err(di->dev, "invalid voltage :%d", vol);
-               vol = di->voltage;
-               dbg_enable = 1;
-       }
-       di->voltage = vol;
-       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;
-#if defined(CONFIG_ARCH_ROCKCHIP)
-       di->remain_capacity = rk81x_bat_get_realtime_capacity(di);
-#endif
+       struct rk818_battery *di = platform_get_drvdata(dev);
+       int interval_sec, time_step, pwroff_vol;
+       u8 val;
 
 
-       if (di->slp_psy_status) {
-               time_step = CHRG_TIME_STEP;
-       } else {
-               if (di->voltage <= pwroff_thresd + 50)
-                       time_step = DISCHRG_TIME_STEP_0;
+       di->s2r = true;
+       di->current_avg = rk818_bat_get_avg_current(di);
+       di->voltage_relax = rk818_bat_get_relax_voltage(di);
+       di->voltage_avg = rk818_bat_get_avg_voltage(di);
+       di->remain_cap = rk818_bat_get_coulomb_cap(di);
+       di->rsoc = rk818_bat_get_rsoc(di);
+       interval_sec = rk818_bat_rtc_sleep_sec(di);
+       di->sleep_sum_sec += interval_sec;
+       pwroff_vol = di->pdata->pwroff_vol;
+
+       if (!di->sleep_chrg_online) {
+               /* only add up discharge sleep seconds */
+               di->sleep_dischrg_sec += interval_sec;
+               if (di->voltage_avg <= pwroff_vol + 50)
+                       time_step = DISCHRG_TIME_STEP1;
                else
                else
-                       time_step = DISCHRG_TIME_STEP_1;
+                       time_step = DISCHRG_TIME_STEP2;
        }
 
        }
 
-       pr_info("battery resume c=%d v=%d ev=%d rv=%d dt=%d at=%ld chg=%d\n",
-               di->current_avg, di->voltage, di->est_ocv_vol,
-               di->relax_voltage, delta_time, di->suspend_time_sum,
-               di->slp_psy_status);
+       BAT_INFO("resume: dl=%d rl=%d c=%d v=%d rv=%d "
+                "cap=%d dt=%d at=%ld ch=%d\n",
+                di->dsoc, di->rsoc, di->current_avg, di->voltage_avg,
+                di->voltage_relax, rk818_bat_get_coulomb_cap(di), interval_sec,
+                di->sleep_dischrg_sec, di->sleep_chrg_online);
 
 
-       if (di->suspend_time_sum > time_step) {
-               delta_soc = rk81x_bat_update_resume_state(di);
-               if (delta_soc)
-                       di->suspend_time_sum = 0;
+       /* sleep: enough time and discharge */
+       if ((di->sleep_dischrg_sec > time_step) && (!di->sleep_chrg_online)) {
+               if (rk818_bat_sleep_dischrg(di))
+                       di->sleep_dischrg_sec = 0;
        }
 
        }
 
-       if ((!rk81x_chrg_online(di) && di->voltage <= pwroff_thresd) ||
-           rk81x_chrg_online(di))
-               wake_lock_timeout(&di->resume_wake_lock, 5 * HZ);
-       return 0;
-}
+       rk818_bat_save_data(di);
 
 
-static int rk81x_battery_remove(struct platform_device *dev)
-{
-       struct rk81x_battery *di = platform_get_drvdata(dev);
+       /* set vbat lowest 3.0v shutdown */
+       val = rk818_bat_read(di, RK818_VB_MON_REG);
+       val &= ~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK);
+       val |= (RK818_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN);
+       rk818_bat_write(di, RK818_VB_MON_REG, val);
+       rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1,
+                          VB_LOW_INT_EN, VB_LOW_INT_EN);
+
+       /* charge/lowpower lock: for battery work to update dsoc and rsoc */
+       if ((di->sleep_chrg_online) ||
+           (!di->sleep_chrg_online && di->voltage_avg < di->pdata->pwroff_vol))
+               wake_lock_timeout(&di->wake_lock, msecs_to_jiffies(2000));
+
+       queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work,
+                          msecs_to_jiffies(1000));
 
 
-       cancel_delayed_work_sync(&di->battery_monitor_work);
        return 0;
 }
 
        return 0;
 }
 
-static void rk81x_battery_shutdown(struct platform_device *dev)
+static void rk818_battery_shutdown(struct platform_device *dev)
 {
 {
-       struct rk81x_battery *di = platform_get_drvdata(dev);
+       u8 cnt = 0;
+       struct rk818_battery *di = platform_get_drvdata(dev);
 
 
-       cancel_delayed_work_sync(&di->battery_monitor_work);
-       rk_bc_detect_notifier_unregister(&di->battery_nb);
-
-       if (BASE_TO_MIN(di->power_on_base) <= REBOOT_INTER_MIN)
-               rk81x_bat_check_reboot(di);
+       cancel_delayed_work_sync(&di->bat_delay_work);
+       cancel_delayed_work_sync(&di->calib_delay_work);
+       rk818_bat_unregister_fb_notify(di);
+       del_timer(&di->caltimer);
+       if (base2sec(di->boot_base) < REBOOT_PERIOD_SEC)
+               cnt = rk818_bat_check_reboot(di);
        else
        else
-               rk81x_bat_save_reboot_cnt(di, 0);
-       rk81x_chrg_term_mode_set(di, CHRG_TERM_ANA_SIGNAL);
-}
-
-static struct platform_driver rk81x_battery_driver = {
-       .driver     = {
-               .name   = "rk818-battery",
-               .owner  = THIS_MODULE,
+               rk818_bat_save_reboot_cnt(di, 0);
+
+       BAT_INFO("shutdown: dl=%d rl=%d c=%d v=%d cap=%d f=%d ch=%d n=%d "
+                "mode=%d rest=%d\n",
+                di->dsoc, di->rsoc, di->current_avg, di->voltage_avg,
+                di->remain_cap, di->fcc, rk818_bat_chrg_online(di), cnt,
+                di->algo_rest_mode, di->algo_rest_val);
+}
+
+static struct platform_driver rk818_battery_driver = {
+       .probe = rk818_battery_probe,
+       .suspend = rk818_battery_suspend,
+       .resume = rk818_battery_resume,
+       .shutdown = rk818_battery_shutdown,
+       .driver = {
+               .name = "rk818-battery",
+               .of_match_table = rk818_battery_of_match,
        },
        },
-
-       .probe      = rk81x_battery_probe,
-       .remove     = rk81x_battery_remove,
-       .suspend    = rk81x_battery_suspend,
-       .resume     = rk81x_battery_resume,
-       .shutdown   = rk81x_battery_shutdown,
 };
 
 static int __init battery_init(void)
 {
 };
 
 static int __init battery_init(void)
 {
-       return platform_driver_register(&rk81x_battery_driver);
+       return platform_driver_register(&rk818_battery_driver);
 }
 }
-
 fs_initcall_sync(battery_init);
 fs_initcall_sync(battery_init);
+
 static void __exit battery_exit(void)
 {
 static void __exit battery_exit(void)
 {
-       platform_driver_unregister(&rk81x_battery_driver);
+       platform_driver_unregister(&rk818_battery_driver);
 }
 module_exit(battery_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:rk818-battery");
 }
 module_exit(battery_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:rk818-battery");
-MODULE_AUTHOR("ROCKCHIP");
+MODULE_AUTHOR("chenjh<chenjh@rock-chips.com>");
index 2c8e648edafa4f715a18af053917a58536809ed6..76a4d65b682376334d58de5c0c443db743edcc89 100644 (file)
 /*
 /*
-*rk818-battery.h - Battery fuel gauge driver structures
+ * rk818_battery.h: fuel gauge driver structures
  *
  *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd
+ * Author: chenjh <chenjh@rock-chips.com>
+ *
+ * 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.
  */
  */
-#ifndef RK818_BATTERY
-#define  RK818_BATTERY
-
-#define VB_MOD_REG                                     0x21
-#define THERMAL_REG                                    0x22
-#define DCDC_EN_REG                                    0x23
-#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)
-#define CHRG_CVTLMT_INT                                (6)
-
-#define CHRG_EN_MASK                           (1 << 7)
-#define CHRG_EN                                        (1 << 7)
-#define CHRG_DIS                               (0 << 7)
-
-#define OTG_EN_MASK                            (1 << 7)
-#define OTG_EN                                 (1 << 7)
-#define OTG_DIS                                        (0 << 7)
-
-/* 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_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
+#ifndef RK818_BATTERY
+#define RK818_BATTERY
+
+/* RK818_INT_STS_MSK_REG2 */
+#define PLUG_IN_MSK            BIT(0)
+#define PLUG_OUT_MSK           BIT(1)
+#define CHRG_CVTLMT_INT_MSK    BIT(6)
+
+/* RK818_TS_CTRL_REG */
+#define GG_EN                  BIT(7)
+#define ADC_CUR_EN             BIT(6)
+#define ADC_TS1_EN             BIT(5)
+#define ADC_TS2_EN             BIT(4)
+
+/* RK818_GGCON */
+#define OCV_SAMP_MIN_MSK       0x0c
+#define OCV_SAMP_8MIN          (0x00 << 2)
+
+#define ADC_CAL_MIN_MSK                0x30
+#define ADC_CAL_8MIN           (0x00 << 4)
+#define ADC_CUR_MODE           BIT(1)
+
+/* RK818_GGSTS */
+#define BAT_CON                        BIT(4)
+#define RELAX_VOL1_UPD         BIT(3)
+#define RELAX_VOL2_UPD         BIT(2)
+#define RELAX_VOL12_UPD_MSK    (RELAX_VOL1_UPD | RELAX_VOL2_UPD)
+
+/* RK818_SUP_STS_REG */
+#define CHRG_STATUS_MSK                0x70
+#define BAT_EXS                        BIT(7)
+#define CHARGE_OFF             (0x0 << 4)
+#define DEAD_CHARGE            (0x1 << 4)
+#define TRICKLE_CHARGE         (0x2 << 4)
+#define CC_OR_CV               (0x3 << 4)
+#define CHARGE_FINISH          (0x4 << 4)
+#define USB_OVER_VOL           (0x5 << 4)
+#define BAT_TMP_ERR            (0x6 << 4)
+#define TIMER_ERR              (0x7 << 4)
+#define USB_VLIMIT_EN          BIT(3)
+#define USB_CLIMIT_EN          BIT(2)
+#define USB_EXIST              BIT(1)
+#define USB_EFF                        BIT(0)
+
+/* RK818_USB_CTRL_REG */
+#define CHRG_CT_EN             BIT(7)
+#define FINISH_CUR_MSK         0xc0
+#define TEMP_105C              (0x02 << 2)
+#define FINISH_100MA           (0x00 << 6)
+#define FINISH_150MA           (0x01 << 6)
+#define FINISH_200MA           (0x02 << 6)
+#define FINISH_250MA           (0x03 << 6)
+
+/* RK818_CHRG_CTRL_REG3 */
+#define CHRG_TERM_MODE_MSK     BIT(5)
+#define CHRG_TERM_ANA_SIGNAL   (0 << 5)
+#define CHRG_TERM_DIG_SIGNAL   BIT(5)
+#define CHRG_TIMER_CCCV_EN     BIT(2)
+#define CHRG_EN                        BIT(7)
+
+/* RK818_VB_MON_REG */
+#define        RK818_VBAT_LOW_3V0      0x02
+#define        RK818_VBAT_LOW_3V4      0x06
+#define PLUG_IN_STS            BIT(6)
+
+/* RK818_THERMAL_REG */
+#define FB_TEMP_MSK            0x0c
+
+/* RK818_INT_STS_MSK_REG1 */
+#define VB_LOW_INT_EN          BIT(1)
+
+/* RK818_MISC_MARK_REG */
+#define FG_INIT                        BIT(5)
+#define FG_RESET_LATE          BIT(4)
+#define FG_RESET_NOW           BIT(3)
+#define ALGO_REST_MODE_MSK     (0xc0)
+#define ALGO_REST_MODE_SHIFT   6
+
+/* bit shift */
+#define FB_TEMP_SHIFT          2
+
+/* parse ocv table param */
+#define TIMER_MS_COUNTS                1000
 #define MAX_PERCENTAGE         100
 #define MAX_PERCENTAGE         100
+#define MAX_INTERPOLATE                1000
+#define MAX_INT                        0x7FFF
 
 
-/* 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;
+#define DRIVER_VERSION         "7.0"
 
 
-       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;
+struct battery_platform_data {
+       u32 *ocv_table;
+       u32 *zero_table;
+       u32 *ntc_table;
+       u32 ocv_size;
+       u32 max_chrg_voltage;
+       u32 ntc_size;
+       int ntc_degree_from;
+       u32 pwroff_vol;
+       u32 monitor_sec;
+       u32 zero_algorithm_vol;
+       u32 bat_res;
+       u32 design_capacity;
+       u32 design_qmax;
+       u32 sleep_enter_current;
+       u32 sleep_exit_current;
+       u32 max_soc_offset;
+       u32 sample_res;
+       u32 bat_mode;
+       u32 fb_temp;
+       u32 energy_mode;
+       u32 cccv_hour;
 };
 
 };
 
-/* 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;
+enum work_mode {
+       MODE_ZERO = 0,
+       MODE_FINISH,
+       MODE_SMOOTH_CHRG,
+       MODE_SMOOTH_DISCHRG,
+       MODE_SMOOTH,
 };
 
 };
 
-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 bat_mode {
+       MODE_BATTARY = 0,
+       MODE_VIRTUAL,
 };
 
 };
 
-enum fg_mode {
-       FG_NORMAL_MODE = 0,/*work normally*/
-       TEST_POWER_MODE,   /*work without battery*/
+static const u16 feedback_temp_array[] = {
+       85, 95, 105, 115
 };
 
 };
 
-enum hw_support_adp {
-       HW_ADP_TYPE_USB = 0,/*'HW' means:hardware*/
-       HW_ADP_TYPE_DC,
-       HW_ADP_TYPE_DUAL
+static const u16 chrg_vol_sel_array[] = {
+       4050, 4100, 4150, 4200, 4250, 4300, 4350
 };
 
 };
 
-
-/* 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
+static const u16 chrg_cur_sel_array[] = {
+       1000, 1200, 1400, 1600, 1800, 2000, 2250, 2400, 2600, 2800, 3000
 };
 
 };
 
-enum charger_state {
-       OFFLINE = 0,
-       ONLINE
+static const u16 chrg_cur_input_array[] = {
+       450, 800, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000
 };
 
 void kernel_power_off(void);
 };
 
 void kernel_power_off(void);
-#if defined(CONFIG_ARCH_ROCKCHIP)
-int dwc_vbus_status(void);
-int get_gadget_connect_flag(void);
 void rk_send_wakeup_key(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(bool wait)
-{
-       return 0;
-}
-
-static inline void rk_send_wakeup_key(void)
-{
-}
-#endif
 
 #endif
 
 #endif
index 15c6e62c2fb67de2846313e2a238addf8cde7be2..d1ee93ef6823e3d0ddd53e3c78be085902e8942a 100644 (file)
@@ -188,8 +188,80 @@ enum rk818_reg {
 #define RK818_CHRG_COMP_REG            0x9a
 #define RK818_SUP_STS_REG              0xa0
 #define RK818_USB_CTRL_REG             0xa1
 #define RK818_CHRG_COMP_REG            0x9a
 #define RK818_SUP_STS_REG              0xa0
 #define RK818_USB_CTRL_REG             0xa1
-
-#define RK818_SAVE_DATA19              0xF2
+#define RK818_CHRG_CTRL_REG1           0xa3
+#define RK818_CHRG_CTRL_REG2           0xa4
+#define RK818_CHRG_CTRL_REG3           0xa5
+#define RK818_BAT_CTRL_REG             0xa6
+#define RK818_BAT_HTS_TS1_REG          0xa8
+#define RK818_BAT_LTS_TS1_REG          0xa9
+#define RK818_BAT_HTS_TS2_REG          0xaa
+#define RK818_BAT_LTS_TS2_REG          0xab
+#define RK818_TS_CTRL_REG              0xac
+#define RK818_ADC_CTRL_REG             0xad
+#define RK818_ON_SOURCE_REG            0xae
+#define RK818_OFF_SOURCE_REG           0xaf
+#define RK818_GGCON_REG                        0xb0
+#define RK818_GGSTS_REG                        0xb1
+#define RK818_FRAME_SMP_INTERV_REG     0xb2
+#define RK818_AUTO_SLP_CUR_THR_REG     0xb3
+#define RK818_GASCNT_CAL_REG3          0xb4
+#define RK818_GASCNT_CAL_REG2          0xb5
+#define RK818_GASCNT_CAL_REG1          0xb6
+#define RK818_GASCNT_CAL_REG0          0xb7
+#define RK818_GASCNT3_REG              0xb8
+#define RK818_GASCNT2_REG              0xb9
+#define RK818_GASCNT1_REG              0xba
+#define RK818_GASCNT0_REG              0xbb
+#define RK818_BAT_CUR_AVG_REGH         0xbc
+#define RK818_BAT_CUR_AVG_REGL         0xbd
+#define RK818_TS1_ADC_REGH             0xbe
+#define RK818_TS1_ADC_REGL             0xbf
+#define RK818_TS2_ADC_REGH             0xc0
+#define RK818_TS2_ADC_REGL             0xc1
+#define RK818_BAT_OCV_REGH             0xc2
+#define RK818_BAT_OCV_REGL             0xc3
+#define RK818_BAT_VOL_REGH             0xc4
+#define RK818_BAT_VOL_REGL             0xc5
+#define RK818_RELAX_ENTRY_THRES_REGH   0xc6
+#define RK818_RELAX_ENTRY_THRES_REGL   0xc7
+#define RK818_RELAX_EXIT_THRES_REGH    0xc8
+#define RK818_RELAX_EXIT_THRES_REGL    0xc9
+#define RK818_RELAX_VOL1_REGH          0xca
+#define RK818_RELAX_VOL1_REGL          0xcb
+#define RK818_RELAX_VOL2_REGH          0xcc
+#define RK818_RELAX_VOL2_REGL          0xcd
+#define RK818_BAT_CUR_R_CALC_REGH      0xce
+#define RK818_BAT_CUR_R_CALC_REGL      0xcf
+#define RK818_BAT_VOL_R_CALC_REGH      0xd0
+#define RK818_BAT_VOL_R_CALC_REGL      0xd1
+#define RK818_CAL_OFFSET_REGH          0xd2
+#define RK818_CAL_OFFSET_REGL          0xd3
+#define RK818_NON_ACT_TIMER_CNT_REG    0xd4
+#define RK818_VCALIB0_REGH             0xd5
+#define RK818_VCALIB0_REGL             0xd6
+#define RK818_VCALIB1_REGH             0xd7
+#define RK818_VCALIB1_REGL             0xd8
+#define RK818_IOFFSET_REGH             0xdd
+#define RK818_IOFFSET_REGL             0xde
+#define RK818_SOC_REG                  0xe0
+#define RK818_REMAIN_CAP_REG3          0xe1
+#define RK818_REMAIN_CAP_REG2          0xe2
+#define RK818_REMAIN_CAP_REG1          0xe3
+#define RK818_REMAIN_CAP_REG0          0xe4
+#define RK818_UPDAT_LEVE_REG           0xe5
+#define RK818_NEW_FCC_REG3             0xe6
+#define RK818_NEW_FCC_REG2             0xe7
+#define RK818_NEW_FCC_REG1             0xe8
+#define RK818_NEW_FCC_REG0             0xe9
+#define RK818_NON_ACT_TIMER_CNT_SAVE_REG 0xea
+#define RK818_OCV_VOL_VALID_REG                0xeb
+#define RK818_REBOOT_CNT_REG           0xec
+#define RK818_POFFSET_REG              0xed
+#define RK818_MISC_MARK_REG            0xee
+#define RK818_HALT_CNT_REG             0xef
+#define RK818_CALC_REST_REGH           0xf0
+#define RK818_CALC_REST_REGL           0xf1
+#define RK818_SAVE_DATA19              0xf2
 #define RK818_NUM_REGULATORS           14
 
 /* IRQ Definitions */
 #define RK818_NUM_REGULATORS           14
 
 /* IRQ Definitions */