power_supply: add cw2015 battery support
authorShunqing Chen <csq@rock-chips.com>
Fri, 26 May 2017 01:57:50 +0000 (09:57 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Fri, 16 Jun 2017 08:22:54 +0000 (16:22 +0800)
Change-Id: I36d65b9765a3303169f0ff60025d9ae722ceb1a9
Signed-off-by: Shunqing Chen <csq@rock-chips.com>
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/cw2015_battery.c [changed mode: 0755->0644]
include/linux/power/cw2015_battery.h

index e4b46fadd8fbce5f49d98c9e1cd86cf540fe8733..9427d28f2c8a3e2545bda183933df1eb5c8153df 100644 (file)
@@ -490,6 +490,13 @@ config BATTERY_EC
          If you say yes here you will get support for the battery of EC.
          This driver can give support for EC Battery Interface.
 
+config BATTERY_CW2015
+       bool "CW2015 Battery driver"
+       default n
+       help
+         If you say yes here you will get support for the battery of CW2015.
+         This driver can give support for CW2015 Battery Interface.
+
 config BATTERY_GOLDFISH
        tristate "Goldfish battery driver"
        depends on GOLDFISH || COMPILE_TEST
index b776caa73764eea2bb07463424e499132d739208..814abaf1617a0395229bb68affa5f48b066a09f6 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_TEST_POWER)      += test_power.o
 
 obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
 obj-$(CONFIG_BATTERY_EC)       += ec_battery.o
+obj-$(CONFIG_BATTERY_CW2015)   += cw2015_battery.o
 obj-$(CONFIG_BATTERY_DS2760)   += ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2780)   += ds2780_battery.o
 obj-$(CONFIG_BATTERY_DS2781)   += ds2781_battery.o
old mode 100755 (executable)
new mode 100644 (file)
index aaf01fc..2833679
  *
  */
 
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-#include <linux/workqueue.h>
-#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/rk_keys.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 
 #include <linux/power/cw2015_battery.h>
 
-static int i2c_master_reg8_send(const struct i2c_client *client, const char reg,
-                               const char *buf, int count, int scl_rate)
-{
-       int ret;
-       char *tx_buf;
-       struct i2c_msg msg;
-       struct i2c_adapter *adap = client->adapter;
+static int dbg_enable;
+module_param_named(dbg_level, dbg_enable, int, 0644);
 
-       tx_buf = kzalloc(count + 1, GFP_KERNEL);
-       if (!tx_buf)
-               return -ENOMEM;
-
-       tx_buf[0] = reg;
-       memcpy(tx_buf + 1, buf, count);
-
-       msg.addr = client->addr;
-       msg.flags = client->flags;
-       msg.len = count + 1;
-       msg.buf = (char *)tx_buf;
-       msg.scl_rate = scl_rate;
-
-       ret = i2c_transfer(adap, &msg, 1);
-       kfree(tx_buf);
-
-       return (ret == 1) ? count : ret;
-}
-
-static int i2c_master_reg8_recv(const struct i2c_client *client, const char reg,
-                               char *buf, int count, int scl_rate)
-{
-       struct i2c_adapter *adap = client->adapter;
-       struct i2c_msg msgs[2];
-       int ret;
-       char reg_buf = reg;
-
-       msgs[0].addr = client->addr;
-       msgs[0].flags = client->flags;
-       msgs[0].len = 1;
-       msgs[0].buf = &reg_buf;
-       msgs[0].scl_rate = scl_rate;
-
-       msgs[1].addr = client->addr;
-       msgs[1].flags = client->flags | I2C_M_RD;
-       msgs[1].len = count;
-       msgs[1].buf = (char *)buf;
-       msgs[1].scl_rate = scl_rate;
-
-       ret = i2c_transfer(adap, msgs, 2);
-
-       return (ret == 2) ? count : ret;
-}
+#define cw_printk(args...) \
+       do { \
+               if (dbg_enable) { \
+                       pr_info(args); \
+               } \
+       } while (0)
 
 static int cw_read(struct i2c_client *client, u8 reg, u8 buf[])
 {
-       int ret;
-
-       ret = i2c_master_reg8_recv(client, reg, buf, 1, CW_I2C_SPEED);
-
-       return ret;
+       return i2c_smbus_read_i2c_block_data(client, reg, 1, buf);
 }
 
 static int cw_write(struct i2c_client *client, u8 reg, u8 const buf[])
 {
-       int ret;
-
-       ret = i2c_master_reg8_send(client, reg, buf, 1, CW_I2C_SPEED);
-
-       return ret;
+       return i2c_smbus_write_i2c_block_data(client, reg, 1, &buf[0]);
 }
 
 static int cw_read_word(struct i2c_client *client, u8 reg, u8 buf[])
 {
-       int ret;
-
-       ret = i2c_master_reg8_recv(client, reg, buf, 2, CW_I2C_SPEED);
-
-       return ret;
+       return i2c_smbus_read_i2c_block_data(client, reg, 2, buf);
 }
 
-static int cw_update_config_info(struct cw_battery *cw_bat)
+int cw_update_config_info(struct cw_battery *cw_bat)
 {
        int ret;
        u8 reg_val;
        u8 i;
        u8 reset_val;
 
-       dev_info(&cw_bat->client->dev, "func: %s-------\n", __func__);
+       cw_printk("[FGADC] test config_info = 0x%x\n",
+                 cw_bat->plat_data.cw_bat_config_info[0]);
 
        /* make sure no in sleep mode */
        ret = cw_read(cw_bat->client, REG_MODE, &reg_val);
@@ -124,7 +66,7 @@ static int cw_update_config_info(struct cw_battery *cw_bat)
        reset_val = reg_val;
        if ((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) {
                dev_err(&cw_bat->client->dev,
-                       "Error, device in sleep mode, cannot update battery info\n");
+                       "device in sleep mode, cannot update battery info\n");
                return -1;
        }
 
@@ -138,18 +80,6 @@ static int cw_update_config_info(struct cw_battery *cw_bat)
                        return ret;
        }
 
-       /* readback & check */
-       for (i = 0; i < SIZE_BATINFO; i++) {
-               ret = cw_read(cw_bat->client, REG_BATINFO + i, &reg_val);
-               if (reg_val != cw_bat->plat_data.cw_bat_config_info[i])
-                       return -1;
-       }
-
-       /* set cw2015/cw2013 to use new battery info */
-       ret = cw_read(cw_bat->client, REG_CONFIG, &reg_val);
-       if (ret < 0)
-               return ret;
-
        reg_val |= CONFIG_UPDATE_FLG;   /* set UPDATE_FLAG */
        reg_val &= 0x07;        /* clear ATHD */
        reg_val |= ATHD;        /* set ATHD */
@@ -182,6 +112,8 @@ static int cw_update_config_info(struct cw_battery *cw_bat)
        if (ret < 0)
                return ret;
 
+       cw_printk("cw2015 update config success!\n");
+
        return 0;
 }
 
@@ -216,16 +148,17 @@ static int cw_init(struct cw_battery *cw_bat)
                return ret;
 
        if (!(reg_val & CONFIG_UPDATE_FLG)) {
-               dev_info(&cw_bat->client->dev,
-                        "update flag for new battery info have not set\n");
+               cw_printk("update config flg is true, need update config\n");
                ret = cw_update_config_info(cw_bat);
-               if (ret < 0)
+               if (ret < 0) {
+                       dev_info(&cw_bat->client->dev,
+                                "update flag for new battery info have not set\n");
                        return ret;
+               }
        } else {
                for (i = 0; i < SIZE_BATINFO; i++) {
-                       ret =
-                           cw_read(cw_bat->client, (REG_BATINFO + i),
-                                   &reg_val);
+                       ret = cw_read(cw_bat->client, (REG_BATINFO + i),
+                                     &reg_val);
                        if (ret < 0)
                                return ret;
 
@@ -248,11 +181,7 @@ static int cw_init(struct cw_battery *cw_bat)
                        return ret;
                else if (reg_val <= 0x64)
                        break;
-
-               msleep(100);
-               if (i > 25)
-                       dev_err(&cw_bat->client->dev,
-                               "cw2015/cw2013 input unvalid power error\n");
+               msleep(120);
        }
 
        if (i >= 30) {
@@ -261,272 +190,231 @@ static int cw_init(struct cw_battery *cw_bat)
                dev_info(&cw_bat->client->dev, "report battery capacity error");
                return -1;
        }
+
+       cw_printk("cw2015 init success!\n");
        return 0;
 }
 
-static void cw_update_time_member_charge_start(struct cw_battery *cw_bat)
+static int check_chrg_usb_psy(struct device *dev, void *data)
 {
-       struct timespec ts;
-       int new_run_time;
-       int new_sleep_time;
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct cw_battery *cw_bat = (struct cw_battery *)data;
 
-       ktime_get_ts(&ts);
-       new_run_time = ts.tv_sec;
+       if (psy->desc->type == POWER_SUPPLY_TYPE_USB) {
+               cw_bat->chrg_usb_psy = psy;
+               return 1;
+       }
+       return 0;
+}
 
-       get_monotonic_boottime(&ts);
-       new_sleep_time = ts.tv_sec - new_run_time;
+static int check_chrg_ac_psy(struct device *dev, void *data)
+{
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct cw_battery *cw_bat = (struct cw_battery *)data;
 
-       cw_bat->run_time_charge_start = new_run_time;
-       cw_bat->sleep_time_charge_start = new_sleep_time;
+       if (psy->desc->type == POWER_SUPPLY_TYPE_MAINS) {
+               cw_bat->chrg_ac_psy = psy;
+               return 1;
+       }
+       return 0;
 }
 
-static void cw_update_time_member_capacity_change(struct cw_battery *cw_bat)
+static void get_chrg_psy(struct cw_battery *cw_bat)
 {
-       struct timespec ts;
-       int new_run_time;
-       int new_sleep_time;
+       if (!cw_bat->chrg_usb_psy)
+               class_for_each_device(power_supply_class, NULL, cw_bat,
+                                     check_chrg_usb_psy);
+       if (!cw_bat->chrg_ac_psy)
+               class_for_each_device(power_supply_class, NULL, cw_bat,
+                                     check_chrg_ac_psy);
+}
 
-       ktime_get_ts(&ts);
-       new_run_time = ts.tv_sec;
+static int get_charge_state(struct cw_battery *cw_bat)
+{
+       union power_supply_propval val;
+       int ret = -ENODEV;
+       int usb_online = 0;
+       int ac_online = 0;
+       struct power_supply *chrg_usb_psy;
+       struct power_supply *chrg_ac_psy;
 
-       get_monotonic_boottime(&ts);
-       new_sleep_time = ts.tv_sec - new_run_time;
+       if (!cw_bat->chrg_usb_psy || !cw_bat->chrg_ac_psy)
+               get_chrg_psy(cw_bat);
 
-       cw_bat->run_time_capacity_change = new_run_time;
-       cw_bat->sleep_time_capacity_change = new_sleep_time;
+       chrg_usb_psy = cw_bat->chrg_usb_psy;
+       chrg_ac_psy = cw_bat->chrg_ac_psy;
+       if (chrg_usb_psy) {
+               ret = chrg_usb_psy->desc->get_property(chrg_usb_psy,
+                                                      POWER_SUPPLY_PROP_ONLINE,
+                                                      &val);
+               if (!ret)
+                       usb_online = val.intval;
+       }
+       if (chrg_ac_psy) {
+               ret = chrg_ac_psy->desc->get_property(chrg_ac_psy,
+                                                     POWER_SUPPLY_PROP_ONLINE,
+                                                     &val);
+               if (!ret)
+                       ac_online = val.intval;
+       }
+       if (!chrg_usb_psy)
+               cw_printk("Usb online didn't find\n");
+       if (!chrg_ac_psy)
+               cw_printk("Ac online didn't find\n");
+
+       cw_printk("ac_online = %d, usb_online = %d\n", ac_online, usb_online);
+       if (ac_online || usb_online)
+               return 1;
+
+       return 0;
 }
 
-#if (CW_QUICKSTART)
-static int cw_quickstart(struct cw_battery *cw_bat)
+static int cw_por(struct cw_battery *cw_bat)
 {
-       int ret = 0;
-       u8 reg_val = MODE_QUICK_START;
+       int ret;
+       unsigned char reset_val;
 
-       ret = cw_write(cw_bat->client, REG_MODE, &reg_val);
-       if (ret < 0) {
-               dev_err(&cw_bat->client->dev, "Error quick start1\n");
+       reset_val = MODE_SLEEP;
+       ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
+       if (ret < 0)
                return ret;
-       }
-
-       reg_val = MODE_NORMAL;
-       ret = cw_write(cw_bat->client, REG_MODE, &reg_val);
-       if (ret < 0) {
-               dev_err(&cw_bat->client->dev, "Error quick start2\n");
+       reset_val = MODE_NORMAL;
+       msleep(20);
+       ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
+       if (ret < 0)
                return ret;
-       }
-       return 1;
+       ret = cw_init(cw_bat);
+       if (ret)
+               return ret;
+       return 0;
 }
-#endif
+
 static int cw_get_capacity(struct cw_battery *cw_bat)
 {
-       u8 reg_val;
-       u8 reset_val;
-       int ret;
        int cw_capacity;
-       int charge_time;
-       int allow_change;
-       int allow_capacity;
-       long new_run_time;
-       long new_sleep_time;
-       long capacity_or_aconline_time;
-       static int if_quickstart;
-       static int jump_flag;
+       int ret;
+       unsigned char reg_val[2];
+
        static int reset_loop;
-       struct timespec ts;
+       static int charging_loop;
+       static int discharging_loop;
+       static int jump_flag;
+       static int charging_5_loop;
+       int sleep_cap;
 
-       ret = cw_read(cw_bat->client, REG_SOC, &reg_val);
+       ret = cw_read_word(cw_bat->client, REG_SOC, reg_val);
        if (ret < 0)
                return ret;
-       cw_capacity = reg_val;
 
-       if (cw_capacity < 0 || cw_capacity > 100) {
-               dev_err(&cw_bat->client->dev,
-                       "get cw_capacity error; cw_capacity = %d\n",
-                       cw_capacity);
-               reset_loop++;
+       cw_capacity = reg_val[0];
 
-               if (reset_loop > 5) {
-                       reset_val = MODE_SLEEP;
-                       ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
-                       if (ret < 0)
-                               return ret;
-                       reset_val = MODE_NORMAL;
-                       msleep(10);
-                       ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
-                       if (ret < 0)
-                               return ret;
-                       dev_info(&cw_bat->client->dev,
-                                "report battery capacity error");
-                       ret = cw_update_config_info(cw_bat);
-                       if (ret)
-                               return ret;
+       if ((cw_capacity < 0) || (cw_capacity > 100)) {
+               cw_printk("Error:  cw_capacity = %d\n", cw_capacity);
+               reset_loop++;
+               if (reset_loop >
+                   (BATTERY_CAPACITY_ERROR / cw_bat->monitor_sec)) {
+                       cw_por(cw_bat);
                        reset_loop = 0;
                }
-
-               return cw_capacity;
+               return cw_bat->capacity;
        } else {
                reset_loop = 0;
        }
 
-       ktime_get_ts(&ts);
-       new_run_time = ts.tv_sec;
-
-       get_monotonic_boottime(&ts);
-       new_sleep_time = ts.tv_sec - new_run_time;
-
-       /* modify battery level swing */
-       if ((cw_bat->charger_mode > 0 &&
-            cw_capacity <= (cw_bat->capacity - 1) &&
-            cw_capacity > (cw_bat->capacity - 9)) ||
-           (cw_bat->charger_mode == 0 &&
-            cw_capacity == (cw_bat->capacity + 1))) {
+       /* case 1 : aviod swing */
+       if (((cw_bat->charger_mode > 0) &&
+            (cw_capacity <= cw_bat->capacity - 1) &&
+            (cw_capacity > cw_bat->capacity - 9)) ||
+           ((cw_bat->charger_mode == 0) &&
+            (cw_capacity == (cw_bat->capacity + 1)))) {
                if (!(cw_capacity == 0 && cw_bat->capacity <= 2))
                        cw_capacity = cw_bat->capacity;
        }
 
-       /* avoid no charge full */
-       if (cw_bat->charger_mode > 0 &&
-           cw_capacity >= 95 &&
-           cw_capacity <= cw_bat->capacity) {
-               capacity_or_aconline_time =
-                   (cw_bat->sleep_time_capacity_change >
-                    cw_bat->sleep_time_charge_start) ? cw_bat->
-                   sleep_time_capacity_change : cw_bat->
-                   sleep_time_charge_start;
-               capacity_or_aconline_time +=
-                   (cw_bat->run_time_capacity_change >
-                    cw_bat->run_time_charge_start) ? cw_bat->
-                   run_time_capacity_change : cw_bat->run_time_charge_start;
-               allow_change =
-                   (new_sleep_time + new_run_time -
-                    capacity_or_aconline_time) / BATTERY_UP_MAX_CHANGE;
-               if (allow_change > 0) {
-                       allow_capacity = cw_bat->capacity + allow_change;
-                       cw_capacity =
-                           (allow_capacity <= 100) ? allow_capacity : 100;
+       /* case 2 : aviod no charge full */
+       if ((cw_bat->charger_mode > 0) &&
+           (cw_capacity >= 95) && (cw_capacity <= cw_bat->capacity)) {
+               cw_printk("Chaman join no charge full\n");
+               charging_loop++;
+               if (charging_loop >
+                   (BATTERY_UP_MAX_CHANGE / cw_bat->monitor_sec)) {
+                       cw_capacity = (cw_bat->capacity + 1) <= 100 ?
+                                     (cw_bat->capacity + 1) : 100;
+                       charging_loop = 0;
                        jump_flag = 1;
-               } else if (cw_capacity <= cw_bat->capacity) {
+               } else {
                        cw_capacity = cw_bat->capacity;
                }
        }
-       /* avoid battery level jump to CW_BAT */
-       else if (cw_bat->charger_mode == 0 &&
-                cw_capacity <= cw_bat->capacity &&
-                cw_capacity >= 90 && jump_flag == 1) {
-               capacity_or_aconline_time =
-                   (cw_bat->sleep_time_capacity_change >
-                    cw_bat->sleep_time_charge_start) ? cw_bat->
-                   sleep_time_capacity_change : cw_bat->
-                   sleep_time_charge_start;
-               capacity_or_aconline_time +=
-                   (cw_bat->run_time_capacity_change >
-                    cw_bat->run_time_charge_start) ? cw_bat->
-                   run_time_capacity_change : cw_bat->run_time_charge_start;
-               allow_change =
-                   (new_sleep_time + new_run_time -
-                    capacity_or_aconline_time) / BATTERY_DOWN_CHANGE;
-               if (allow_change > 0) {
-                       allow_capacity = cw_bat->capacity - allow_change;
-                       if (cw_capacity >= allow_capacity) {
-                               jump_flag = 0;
+
+       /* case 3 : avoid battery level jump to CW_BAT */
+       if ((cw_bat->charger_mode == 0) &&
+           (cw_capacity <= cw_bat->capacity) &&
+           (cw_capacity >= 90) && (jump_flag == 1)) {
+               cw_printk("Chaman join no charge full discharging\n");
+#ifdef CONFIG_PM
+               if (cw_bat->suspend_resume_mark == 1) {
+                       cw_bat->suspend_resume_mark = 0;
+                       sleep_cap = (cw_bat->after.tv_sec +
+                                    discharging_loop *
+                                    (cw_bat->monitor_sec / 1000)) /
+                                    (BATTERY_DOWN_MAX_CHANGE / 1000);
+                       cw_printk("sleep_cap = %d\n", sleep_cap);
+
+                       if (cw_capacity >= cw_bat->capacity - sleep_cap) {
+                               return cw_capacity;
                        } else {
-                               cw_capacity =
-                                   (allow_capacity <=
-                                    100) ? allow_capacity : 100;
+                               if (!sleep_cap)
+                                       discharging_loop = discharging_loop +
+                                               1 + cw_bat->after.tv_sec /
+                                               (cw_bat->monitor_sec / 1000);
+                               else
+                                       discharging_loop = 0;
+                               cw_printk("discharging_loop = %d\n",
+                                         discharging_loop);
+                               return cw_bat->capacity - sleep_cap;
                        }
-               } else if (cw_capacity <= cw_bat->capacity) {
-                       cw_capacity = cw_bat->capacity;
                }
-       }
+#endif
+               discharging_loop++;
+               if (discharging_loop >
+                   (BATTERY_DOWN_MAX_CHANGE / cw_bat->monitor_sec)) {
+                       if (cw_capacity >= cw_bat->capacity - 1)
+                               jump_flag = 0;
+                       else
+                               cw_capacity = cw_bat->capacity - 1;
 
-       /* avoid battery level jump to 0% at a moment from more than 2% */
-       if (cw_capacity == 0 && cw_bat->capacity > 1) {
-               allow_change =
-                   ((new_run_time -
-                     cw_bat->run_time_capacity_change) /
-                    BATTERY_DOWN_MIN_CHANGE_RUN);
-               allow_change +=
-                   ((new_sleep_time -
-                     cw_bat->sleep_time_capacity_change) /
-                    BATTERY_DOWN_MIN_CHANGE_SLEEP);
-
-               allow_capacity = cw_bat->capacity - allow_change;
-               cw_capacity =
-                   (allow_capacity >=
-                    cw_capacity) ? allow_capacity : cw_capacity;
-               dev_info(&cw_bat->client->dev, "report GGIC POR happened");
-               reset_val = MODE_SLEEP;
-               ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
-               if (ret < 0)
-                       return ret;
-               reset_val = MODE_NORMAL;
-               msleep(10);
-               ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
-               if (ret < 0)
-                       return ret;
-               dev_info(&cw_bat->client->dev, "report battery capacity error");
-               ret = cw_update_config_info(cw_bat);
-               if (ret)
-                       return ret;
-               dev_info(&cw_bat->client->dev,
-                        "report battery capacity jump 0 ");
-       }
-#if 1
-       if (cw_bat->charger_mode > 0 && cw_capacity == 0) {
-               charge_time =
-                   new_sleep_time + new_run_time -
-                   cw_bat->sleep_time_charge_start -
-                   cw_bat->run_time_charge_start;
-               if (charge_time > BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE &&
-                   if_quickstart == 0) {
-                       reset_val = MODE_SLEEP;
-                       ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
-                       if (ret < 0)
-                               return ret;
-                       reset_val = MODE_NORMAL;
-                       msleep(10);
-                       ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
-                       if (ret < 0)
-                               return ret;
-                       dev_info(&cw_bat->client->dev,
-                                "report battery capacity error");
-                       ret = cw_update_config_info(cw_bat);
-                       if (ret)
-                               return ret;
-                       dev_info(&cw_bat->client->dev,
-                                "report battery capacity still 0 if in changing");
-                       if_quickstart = 1;
+                       discharging_loop = 0;
+               } else {
+                       cw_capacity = cw_bat->capacity;
                }
-       } else if (if_quickstart == 1 && cw_bat->charger_mode == 0) {
-               if_quickstart = 0;
        }
-#endif
 
-#ifdef SYSTEM_SHUTDOWN_VOLTAGE
-       if (cw_bat->charger_mode == 0 && cw_capacity <= 10 &&
-           cw_bat->voltage <= SYSTEM_SHUTDOWN_VOLTAGE) {
-               if (if_quickstart == 10) {
-                       cw_quickstart(cw_bat);
-                       if_quickstart = 12;
-                       cw_capacity = 0;
-               } else if (if_quickstart <= 10) {
-                       if_quickstart = if_quickstart + 2;
+       /* case 4 : avoid battery level is 0% when long time charging */
+       if ((cw_bat->charger_mode > 0) && (cw_capacity == 0)) {
+               charging_5_loop++;
+               if (charging_5_loop >
+                   BATTERY_CHARGING_ZERO / cw_bat->monitor_sec) {
+                       cw_por(cw_bat);
+                       charging_5_loop = 0;
                }
-               dev_info(&cw_bat->client->dev,
-                        "voltage is less than shutdown voltage\n");
-       } else if ((cw_bat->charger_mode > 0) && (if_quickstart <= 12)) {
-               if_quickstart = 0;
+       } else if (charging_5_loop != 0) {
+               charging_5_loop = 0;
        }
+#ifdef CONFIG_PM
+       if (cw_bat->suspend_resume_mark == 1)
+               cw_bat->suspend_resume_mark = 0;
 #endif
        return cw_capacity;
 }
 
-static int cw_get_vol(struct cw_battery *cw_bat)
+static int cw_get_voltage(struct cw_battery *cw_bat)
 {
        int ret;
        u8 reg_val[2];
        u16 value16, value16_1, value16_2, value16_3;
        int voltage;
+       int res1, res2;
 
        ret = cw_read_word(cw_bat->client, REG_VCELL, reg_val);
        if (ret < 0)
@@ -561,39 +449,21 @@ static int cw_get_vol(struct cw_battery *cw_bat)
                value16_1 = value16_3;
        }
 
-       voltage = value16_1 * 305;
+       voltage = value16_1 * 312 / 1024;
+
+       if (cw_bat->plat_data.divider_res1 &&
+           cw_bat->plat_data.divider_res2) {
+               res1 = cw_bat->plat_data.divider_res1;
+               res2 = cw_bat->plat_data.divider_res2;
+               voltage = voltage * (res1 + res2) / res2;
+       }
 
        dev_dbg(&cw_bat->client->dev, "the cw201x voltage=%d,reg_val=%x %x\n",
                voltage, reg_val[0], reg_val[1]);
        return voltage;
 }
 
-#ifdef BAT_LOW_INTERRUPT
-static int cw_get_alt(struct cw_battery *cw_bat)
-{
-       int ret = 0;
-       u8 reg_val;
-       u8 value8 = 0;
-       int alrt;
-
-       ret = cw_read(cw_bat->client, REG_RRT_ALERT, &reg_val);
-       if (ret < 0)
-               return ret;
-       value8 = reg_val;
-       alrt = value8 >> 7;
-
-       value8 = value8 & 0x7f;
-       reg_val = value8;
-       ret = cw_write(cw_bat->client, REG_RRT_ALERT, &reg_val);
-       if (ret < 0) {
-               dev_err(&cw_bat->client->dev, "Error clear ALRT\n");
-               return ret;
-       }
-
-       return alrt;
-}
-#endif
-
+/*This function called when get RRT from cw2015*/
 static int cw_get_time_to_empty(struct cw_battery *cw_bat)
 {
        int ret;
@@ -614,7 +484,18 @@ static int cw_get_time_to_empty(struct cw_battery *cw_bat)
        return value16;
 }
 
-static void rk_bat_update_capacity(struct cw_battery *cw_bat)
+static void cw_update_charge_status(struct cw_battery *cw_bat)
+{
+       int cw_charger_mode;
+
+       cw_charger_mode = get_charge_state(cw_bat);
+       if (cw_bat->charger_mode != cw_charger_mode) {
+               cw_bat->charger_mode = cw_charger_mode;
+               cw_bat->bat_change = 1;
+       }
+}
+
+static void cw_update_capacity(struct cw_battery *cw_bat)
 {
        int cw_capacity;
 
@@ -623,24 +504,21 @@ static void rk_bat_update_capacity(struct cw_battery *cw_bat)
            (cw_bat->capacity != cw_capacity)) {
                cw_bat->capacity = cw_capacity;
                cw_bat->bat_change = 1;
-               cw_update_time_member_capacity_change(cw_bat);
-
-               if (cw_bat->capacity == 0)
-                       dev_info(&cw_bat->client->dev,
-                                "report battery capacity 0 and will shutdown if no changing");
        }
 }
 
-static void rk_bat_update_vol(struct cw_battery *cw_bat)
+static void cw_update_vol(struct cw_battery *cw_bat)
 {
        int ret;
 
-       ret = cw_get_vol(cw_bat);
-       if ((ret >= 0) && (cw_bat->voltage != ret))
+       ret = cw_get_voltage(cw_bat);
+       if ((ret >= 0) && (cw_bat->voltage != ret)) {
                cw_bat->voltage = ret;
+               cw_bat->bat_change = 1;
+       }
 }
 
-static void rk_bat_update_status(struct cw_battery *cw_bat)
+static void cw_update_status(struct cw_battery *cw_bat)
 {
        int status;
 
@@ -650,7 +528,7 @@ static void rk_bat_update_status(struct cw_battery *cw_bat)
                else
                        status = POWER_SUPPLY_STATUS_CHARGING;
        } else {
-               status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               status = POWER_SUPPLY_STATUS_DISCHARGING;
        }
 
        if (cw_bat->status != status) {
@@ -659,145 +537,15 @@ static void rk_bat_update_status(struct cw_battery *cw_bat)
        }
 }
 
-static void rk_bat_update_time_to_empty(struct cw_battery *cw_bat)
+static void cw_update_time_to_empty(struct cw_battery *cw_bat)
 {
        int ret;
 
        ret = cw_get_time_to_empty(cw_bat);
-       if ((ret >= 0) && (cw_bat->time_to_empty != ret))
+       if ((ret >= 0) && (cw_bat->time_to_empty != ret)) {
                cw_bat->time_to_empty = ret;
-}
-
-static int rk_ac_update_online(struct cw_battery *cw_bat)
-{
-       int ret = 0;
-
-       if (!gpio_is_valid(cw_bat->plat_data.dc_det_pin)) {
-               cw_bat->dc_online = 0;
-               pr_info("%s dc charger without dc_det_pin\n", __func__);
-               return 0;
-       }
-
-       if (gpio_get_value(cw_bat->plat_data.dc_det_pin) ==
-           cw_bat->plat_data.dc_det_level) {
-               if (cw_bat->dc_online != 1) {
-                       cw_update_time_member_charge_start(cw_bat);
-                       cw_bat->dc_online = 1;
-                       if (cw_bat->charger_mode != AC_CHARGER_MODE)
-                               cw_bat->charger_mode = AC_CHARGER_MODE;
-
-                       ret = 1;
-               }
-       } else {
-               if (cw_bat->dc_online != 0) {
-                       cw_update_time_member_charge_start(cw_bat);
-                       cw_bat->dc_online = 0;
-                       if (cw_bat->usb_online == 0)
-                               cw_bat->charger_mode = 0;
-                       ret = 1;
-               }
-       }
-       return ret;
-}
-
-static int get_usb_charge_state(struct cw_battery *cw_bat)
-{
-       int charge_time;
-       int time_from_boot;
-       struct timespec ts;
-
-       int gadget_status = get_gadget_connect_flag();
-       int usb_status = dwc_vbus_status();
-
-       get_monotonic_boottime(&ts);
-       time_from_boot = ts.tv_sec;
-
-       if (cw_bat->charger_init_mode) {
-               if (usb_status == 1 || usb_status == 2) {
-                       cw_bat->charger_init_mode = 0;
-               } else if (time_from_boot < 8) {
-                       usb_status = cw_bat->charger_init_mode;
-               } else if (strstr(saved_command_line, "charger")) {
-                       cw_bat->charger_init_mode = dwc_otg_check_dpdm();
-                       usb_status = cw_bat->charger_init_mode;
-               }
-       }
-#ifdef NO_STANDARD_AC_BIG_CHARGE_MODE
-       if (cw_bat->usb_online == 1) {
-               charge_time =
-                   time_from_boot - cw_bat->sleep_time_charge_start -
-                   cw_bat->run_time_charge_start;
-               if (charge_time > 3) {
-                       if (gadget_status == 0 && dwc_vbus_status() == 1)
-                               usb_status = 2;
-               }
-       }
-#endif
-
-       dev_dbg(&cw_bat->client->dev,
-               "%s usb_status=[%d],cw_bat->charger_mode=[%d],cw_bat->gadget_status=[%d], cw_bat->charger_init_mode = [%d]\n",
-               __func__, usb_status, cw_bat->charger_mode, gadget_status,
-               cw_bat->charger_init_mode);
-
-       return usb_status;
-}
-
-static int rk_usb_update_online(struct cw_battery *cw_bat)
-{
-       int gpio;
-       int value;
-       int ret = 0;
-       int usb_status = 0;
-
-       gpio = cw_bat->plat_data.chg_mode_sel_pin;
-       value = cw_bat->plat_data.chg_mode_sel_level;
-       usb_status = get_usb_charge_state(cw_bat);
-       if (usb_status == 2) {
-               if (cw_bat->charger_mode != AC_CHARGER_MODE) {
-                       cw_bat->charger_mode = AC_CHARGER_MODE;
-                       ret = 1;
-               }
-               if (gpio_is_valid(gpio)) {
-                       if (gpio_get_value(gpio) != value)
-                               gpio_direction_output(gpio, value);
-               }
-
-               if (cw_bat->usb_online != 1) {
-                       cw_bat->usb_online = 1;
-                       cw_update_time_member_charge_start(cw_bat);
-               }
-
-       } else if (usb_status == 1) {
-               if (cw_bat->charger_mode != USB_CHARGER_MODE &&
-                   cw_bat->dc_online == 0) {
-                       cw_bat->charger_mode = USB_CHARGER_MODE;
-                       ret = 1;
-               }
-
-               if (gpio_is_valid(gpio)) {
-                       if (gpio_get_value(gpio) == value)
-                               gpio_direction_output(gpio, !value);
-               }
-               if (cw_bat->usb_online != 1) {
-                       cw_bat->usb_online = 1;
-                       cw_update_time_member_charge_start(cw_bat);
-               }
-
-       } else if (usb_status == 0 && cw_bat->usb_online != 0) {
-               if (gpio_is_valid(gpio)) {
-                       if (gpio_get_value(gpio) == value)
-                               gpio_direction_output(gpio, !value);
-               }
-
-               if (cw_bat->dc_online == 0)
-                       cw_bat->charger_mode = 0;
-
-               cw_update_time_member_charge_start(cw_bat);
-               cw_bat->usb_online = 0;
-               ret = 1;
+               cw_bat->bat_change = 1;
        }
-
-       return ret;
 }
 
 static void cw_bat_work(struct work_struct *work)
@@ -805,105 +553,69 @@ static void cw_bat_work(struct work_struct *work)
        struct delayed_work *delay_work;
        struct cw_battery *cw_bat;
        int ret;
+       u8 reg_val;
+       int i = 0;
 
        delay_work = container_of(work, struct delayed_work, work);
        cw_bat =
-           container_of(delay_work, struct cw_battery, battery_delay_work);
-
-       if (cw_bat->plat_data.is_dc_charge == 1) {
-               ret = rk_ac_update_online(cw_bat);
-               if (ret == 1)
-                       power_supply_changed(&cw_bat->rk_ac);
-       }
+               container_of(delay_work, struct cw_battery, battery_delay_work);
 
-       if (cw_bat->plat_data.is_usb_charge == 1) {
-               ret = rk_usb_update_online(cw_bat);
-               if (ret == 1) {
-                       power_supply_changed(&cw_bat->rk_usb);
-                       power_supply_changed(&cw_bat->rk_ac);
+       /* Add for battery swap start */
+       ret = cw_read(cw_bat->client, REG_MODE, &reg_val);
+       if (ret < 0) {
+               cw_bat->bat_mode = MODE_VIRTUAL;
+               cw_bat->bat_change = 1;
+       } else {
+               if ((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) {
+                       for (i = 0; i < 5; i++) {
+                               if (cw_por(cw_bat) == 0)
+                                       break;
+                       }
                }
-       }
+               cw_update_capacity(cw_bat);
+               cw_update_vol(cw_bat);
+               cw_update_charge_status(cw_bat);
+               cw_update_status(cw_bat);
+               cw_update_time_to_empty(cw_bat);
+       }
+       /* Add for battery swap end */
+       cw_printk("charger_mod = %d\n", cw_bat->charger_mode);
+       cw_printk("status = %d\n", cw_bat->status);
+       cw_printk("capacity = %d\n", cw_bat->capacity);
+       cw_printk("voltage = %d\n", cw_bat->voltage);
 
-       rk_bat_update_status(cw_bat);
-       rk_bat_update_capacity(cw_bat);
-       rk_bat_update_vol(cw_bat);
-       rk_bat_update_time_to_empty(cw_bat);
+#ifdef CONFIG_PM
+       if (cw_bat->suspend_resume_mark == 1)
+               cw_bat->suspend_resume_mark = 0;
+#endif
 
-       if (cw_bat->bat_change) {
-               power_supply_changed(&cw_bat->rk_bat);
+       if (cw_bat->bat_change == 1) {
+               power_supply_changed(cw_bat->rk_bat);
                cw_bat->bat_change = 0;
        }
-
        queue_delayed_work(cw_bat->battery_workqueue,
-                          &cw_bat->battery_delay_work, msecs_to_jiffies(1000));
-
-       dev_dbg(&cw_bat->client->dev,
-               "cw_bat->bat_change = %d, cw_bat->time_to_empty = %d, cw_bat->capacity = %d\n",
-               cw_bat->bat_change, cw_bat->time_to_empty, cw_bat->capacity);
-
-       dev_dbg(&cw_bat->client->dev,
-               "cw_bat->voltage = %d, cw_bat->dc_online = %d, cw_bat->usb_online = %d\n",
-               cw_bat->voltage, cw_bat->dc_online, cw_bat->usb_online);
+                          &cw_bat->battery_delay_work,
+                          msecs_to_jiffies(cw_bat->monitor_sec));
 }
 
-static int rk_usb_get_property(struct power_supply *psy,
-                              enum power_supply_property psp,
-                              union power_supply_propval *val)
-{
-       int ret = 0;
-       struct cw_battery *cw_bat;
-
-       cw_bat = container_of(psy, struct cw_battery, rk_usb);
-       switch (psp) {
-       case POWER_SUPPLY_PROP_ONLINE:
-               val->intval = (cw_bat->charger_mode == USB_CHARGER_MODE);
-               break;
-       default:
-               break;
-       }
-       return ret;
-}
-
-static enum power_supply_property rk_usb_properties[] = {
-       POWER_SUPPLY_PROP_ONLINE,
-};
-
-static int rk_ac_get_property(struct power_supply *psy,
-                             enum power_supply_property psp,
-                             union power_supply_propval *val)
-{
-       int ret = 0;
-       struct cw_battery *cw_bat;
-
-       cw_bat = container_of(psy, struct cw_battery, rk_ac);
-       switch (psp) {
-       case POWER_SUPPLY_PROP_ONLINE:
-               val->intval = (cw_bat->charger_mode == AC_CHARGER_MODE);
-               break;
-       default:
-               break;
-       }
-       return ret;
-}
-
-static enum power_supply_property rk_ac_properties[] = {
-       POWER_SUPPLY_PROP_ONLINE,
-};
-
-static int rk_battery_get_property(struct power_supply *psy,
+static int cw_battery_get_property(struct power_supply *psy,
                                   enum power_supply_property psp,
                                   union power_supply_propval *val)
 {
        int ret = 0;
        struct cw_battery *cw_bat;
 
-       cw_bat = container_of(psy, struct cw_battery, rk_bat);
+       cw_bat = power_supply_get_drvdata(psy);
        switch (psp) {
        case POWER_SUPPLY_PROP_CAPACITY:
                val->intval = cw_bat->capacity;
+               if (cw_bat->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_SOC;
                break;
        case POWER_SUPPLY_PROP_STATUS:
                val->intval = cw_bat->status;
+               if (cw_bat->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_STATUS;
                break;
 
        case POWER_SUPPLY_PROP_HEALTH:
@@ -911,14 +623,20 @@ static int rk_battery_get_property(struct power_supply *psy,
                break;
        case POWER_SUPPLY_PROP_PRESENT:
                val->intval = cw_bat->voltage <= 0 ? 0 : 1;
+               if (cw_bat->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_PRESET;
                break;
 
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               val->intval = cw_bat->voltage;
+               val->intval = cw_bat->voltage * 1000;
+               if (cw_bat->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_VOLTAGE * 1000;
                break;
 
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
                val->intval = cw_bat->time_to_empty;
+               if (cw_bat->bat_mode == MODE_VIRTUAL)
+                       val->intval = VIRTUAL_TIME2EMPTY;
                break;
 
        case POWER_SUPPLY_PROP_TECHNOLOGY:
@@ -931,7 +649,7 @@ static int rk_battery_get_property(struct power_supply *psy,
        return ret;
 }
 
-static enum power_supply_property rk_battery_properties[] = {
+static enum power_supply_property cw_battery_properties[] = {
        POWER_SUPPLY_PROP_CAPACITY,
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_HEALTH,
@@ -941,166 +659,24 @@ static enum power_supply_property rk_battery_properties[] = {
        POWER_SUPPLY_PROP_TECHNOLOGY,
 };
 
-static int cw_bat_gpio_init(struct cw_battery *cw_bat)
-{
-       int ret;
-
-       if (gpio_is_valid(cw_bat->plat_data.dc_det_pin)) {
-               ret = gpio_request(cw_bat->plat_data.dc_det_pin, NULL);
-               if (ret) {
-                       dev_err(&cw_bat->client->dev,
-                               "failed to request dc_det_pin gpio\n");
-                       goto request_dc_det_pin_fail;
-               }
-               ret = gpio_direction_input(cw_bat->plat_data.dc_det_pin);
-               if (ret) {
-                       dev_err(&cw_bat->client->dev,
-                               "failed to set dc_det_pin input\n");
-                       goto request_bat_low_pin_fail;
-               }
-       }
-       if (gpio_is_valid(cw_bat->plat_data.bat_low_pin)) {
-               ret = gpio_request(cw_bat->plat_data.bat_low_pin, NULL);
-               if (ret) {
-                       dev_err(&cw_bat->client->dev,
-                               "failed to request bat_low_pin gpio\n");
-                       goto request_bat_low_pin_fail;
-               }
-
-               ret = gpio_direction_input(cw_bat->plat_data.bat_low_pin);
-               if (ret) {
-                       dev_err(&cw_bat->client->dev,
-                               "failed to set bat_low_pin input\n");
-                       goto request_bat_low_pin_fail;
-               }
-       }
-       if (gpio_is_valid(cw_bat->plat_data.chg_ok_pin)) {
-               ret = gpio_request(cw_bat->plat_data.chg_ok_pin, NULL);
-               if (ret) {
-                       dev_err(&cw_bat->client->dev,
-                               "failed to request chg_ok_pin gpio\n");
-                       goto request_chg_ok_pin_fail;
-               }
-
-               ret = gpio_direction_input(cw_bat->plat_data.chg_ok_pin);
-               if (ret) {
-                       dev_err(&cw_bat->client->dev,
-                               "failed to set chg_ok_pin input\n");
-                       gpio_free(cw_bat->plat_data.chg_ok_pin);
-                       goto request_chg_ok_pin_fail;
-               }
-       }
-
-       if ((gpio_is_valid(cw_bat->plat_data.chg_mode_sel_pin))) {
-               ret = gpio_request(cw_bat->plat_data.chg_mode_sel_pin, NULL);
-               if (ret) {
-                       dev_err(&cw_bat->client->dev,
-                               "failed to request chg_mode_sel_pin gpio\n");
-                       goto request_chg_mode_sel_pin_fail;
-               }
-               ret =
-                   gpio_direction_output(cw_bat->plat_data.chg_mode_sel_pin,
-                                         (cw_bat->plat_data.
-                                          chg_mode_sel_level ==
-                                          CW2015_GPIO_LOW) ? CW2015_GPIO_HIGH :
-                                         CW2015_GPIO_LOW);
-               if (ret) {
-                       dev_err(&cw_bat->client->dev,
-                               "failed to set chg_mode_sel_pin output\n");
-                       gpio_free(cw_bat->plat_data.chg_mode_sel_pin);
-                       goto request_chg_mode_sel_pin_fail;
-               }
-       }
-
-       return 0;
-
-request_chg_mode_sel_pin_fail:
-       gpio_free(cw_bat->plat_data.chg_mode_sel_pin);
-request_chg_ok_pin_fail:
-       if (gpio_is_valid(cw_bat->plat_data.bat_low_pin))
-               gpio_free(cw_bat->plat_data.bat_low_pin);
-request_bat_low_pin_fail:
-       if (gpio_is_valid(cw_bat->plat_data.dc_det_pin))
-               gpio_free(cw_bat->plat_data.dc_det_pin);
-request_dc_det_pin_fail:
-
-       return ret;
-}
-
-static void dc_detect_do_wakeup(struct work_struct *work)
-{
-       int ret;
-       int irq;
-       unsigned int type;
-
-       struct delayed_work *delay_work;
-       struct cw_battery *cw_bat;
-
-       delay_work = container_of(work, struct delayed_work, work);
-       cw_bat = container_of(delay_work, struct cw_battery, dc_wakeup_work);
-
-       rk_send_wakeup_key();
-
-       irq = gpio_to_irq(cw_bat->plat_data.dc_det_pin);
-       type =
-           gpio_get_value(cw_bat->plat_data.
-                          dc_det_pin) ? IRQ_TYPE_EDGE_FALLING :
-           IRQ_TYPE_EDGE_RISING;
-       ret = irq_set_irq_type(irq, type);
-       if (ret < 0) {
-               pr_err("%s: irq_set_irq_type(%d, %d) failed\n", __func__, irq,
-                      type);
-       }
-       enable_irq(irq);
-}
-
-static irqreturn_t dc_detect_irq_handler(int irq, void *dev_id)
-{
-       struct cw_battery *cw_bat = dev_id;
-
-       /* for irq debounce */
-       disable_irq_nosync(irq);
-       queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->dc_wakeup_work,
-                          msecs_to_jiffies(20));
-       return IRQ_HANDLED;
-}
-
-#ifdef BAT_LOW_INTERRUPT
-
-#define WAKE_LOCK_TIMEOUT       (10 * HZ)
-
-static void bat_low_detect_do_wakeup(struct work_struct *work)
-{
-       struct delayed_work *delay_work;
-       struct cw_battery *cw_bat;
-
-       delay_work = container_of(work, struct delayed_work, work);
-       cw_bat =
-           container_of(delay_work, struct cw_battery, bat_low_wakeup_work);
-       dev_info(&cw_bat->client->dev, "func: %s-------\n", __func__);
-       cw_get_alt(cw_bat);
-}
-
-static irqreturn_t bat_low_detect_irq_handler(int irq, void *dev_id)
-{
-       struct cw_battery *cw_bat = dev_id;
-
-       queue_delayed_work(cw_bat->battery_workqueue,
-                          &cw_bat->bat_low_wakeup_work, msecs_to_jiffies(20));
-       return IRQ_HANDLED;
-}
-#endif
+static const struct power_supply_desc cw2015_bat_desc = {
+       .name           = "rk-bat",
+       .type           = POWER_SUPPLY_TYPE_BATTERY,
+       .properties     = cw_battery_properties,
+       .num_properties = ARRAY_SIZE(cw_battery_properties),
+       .get_property   = cw_battery_get_property,
+};
 
 #ifdef CONFIG_OF
-static int cw2015_parse_dt(struct device *dev,
-                          struct cw_bat_platform_data *data)
+static int cw2015_parse_dt(struct cw_battery *cw_bat)
 {
+       struct device *dev = &cw_bat->client->dev;
        struct device_node *node = dev->of_node;
-       enum of_gpio_flags flags;
        struct property *prop;
        int length;
        u32 value;
        int ret;
+       struct cw_bat_platform_data *data = &cw_bat->plat_data;
 
        if (!node)
                return -ENODEV;
@@ -1128,69 +704,34 @@ static int cw2015_parse_dt(struct device *dev,
                        return ret;
        }
 
-       data->dc_det_pin = of_get_named_gpio_flags(node, "dc_det_gpio", 0,
-                                                  &flags);
-       if (data->dc_det_pin == -EPROBE_DEFER)
-               pr_info("%s  dc_det_gpio error\n", __func__);
-
-       if (gpio_is_valid(data->dc_det_pin))
-               data->dc_det_level =
-                   (flags & OF_GPIO_ACTIVE_LOW) ? CW2015_GPIO_LOW :
-                   CW2015_GPIO_HIGH;
-
-       data->bat_low_pin = of_get_named_gpio_flags(node, "bat_low_gpio", 0,
-                                                   &flags);
-       if (data->bat_low_pin == -EPROBE_DEFER)
-               pr_info("%s  bat_low_gpio error\n", __func__);
-
-       if (gpio_is_valid(data->bat_low_pin))
-               data->bat_low_level =
-                   (flags & OF_GPIO_ACTIVE_LOW) ? CW2015_GPIO_LOW :
-                   CW2015_GPIO_HIGH;
-
-       data->chg_ok_pin = of_get_named_gpio_flags(node, "chg_ok_gpio", 0,
-                                                  &flags);
-       if (data->chg_ok_pin == -EPROBE_DEFER)
-               pr_info("%s  chg_ok_gpio error\n", __func__);
-
-       if (gpio_is_valid(data->chg_ok_pin))
-               data->chg_ok_level =
-                   (flags & OF_GPIO_ACTIVE_LOW) ? CW2015_GPIO_LOW :
-                   CW2015_GPIO_HIGH;
-
-       data->chg_mode_sel_pin =
-           of_get_named_gpio_flags(node, "chg_mode_sel_gpio", 0, &flags);
-       if (data->chg_mode_sel_pin == -EPROBE_DEFER)
-               pr_info("%s  chg_mod_sel_gpio error\n", __func__);
-
-       if (gpio_is_valid(data->chg_mode_sel_pin))
-               data->chg_mode_sel_level =
-                   (flags & OF_GPIO_ACTIVE_LOW) ? CW2015_GPIO_LOW :
-                   CW2015_GPIO_HIGH;
-
-       ret = of_property_read_u32(node, "is_dc_charge", &value);
-       if (ret < 0) {
-               pr_info("%s:hardware unsupport dc charge\n", __func__);
+       cw_bat->bat_mode = MODE_BATTARY;
+       cw_bat->monitor_sec = DEFAULT_MONITOR_SEC * TIMER_MS_COUNTS;
+
+       ret = of_property_read_u32(node, "divider_res1", &value);
+       if (ret < 0)
                value = 0;
-       }
-       data->is_dc_charge = value;
+       data->divider_res1 = value;
 
-       ret = of_property_read_u32(node, "is_usb_charge", &value);
-       if (ret < 0) {
-               pr_info("%s:hardware unsupport usb charge\n", __func__);
+       ret = of_property_read_u32(node, "divider_res2", &value);
+       if (ret < 0)
                value = 0;
-       }
-       data->is_usb_charge = value;
+       data->divider_res2 = value;
+
+       ret = of_property_read_u32(node, "virtual_power", &value);
+       if (ret < 0)
+               value = 0;
+       cw_bat->bat_mode = value;
 
-       pr_info("cw201x:support %s %s charger\n",
-               data->is_dc_charge ? "DC" : "",
-               data->is_usb_charge ? "USB" : "");
+       ret = of_property_read_u32(node, "monitor_sec", &value);
+       if (ret < 0)
+               dev_err(dev, "monitor_sec missing!\n");
+       else
+               cw_bat->monitor_sec = value * TIMER_MS_COUNTS;
 
        return 0;
 }
 #else
-static int cw2015_parse_dt(struct device *dev,
-                          struct cw_bat_platform_data *data)
+static int cw2015_parse_dt(struct cw_battery *cw_bat)
 {
        return -ENODEV;
 }
@@ -1199,36 +740,33 @@ static int cw2015_parse_dt(struct device *dev,
 static int cw_bat_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       struct cw_battery *cw_bat;
-       struct cw_bat_platform_data *plat_data = client->dev.platform_data;
        int ret;
-       int irq;
-       int irq_flags;
-       int level = 0;
+       struct cw_battery *cw_bat;
+       struct power_supply_config psy_cfg = {0};
 
        cw_bat = devm_kzalloc(&client->dev, sizeof(*cw_bat), GFP_KERNEL);
        if (!cw_bat) {
-               dev_err(&cw_bat->client->dev,
+               dev_err(&client->dev,
                        "fail to allocate memory for cw2015\n");
                return -ENOMEM;
        }
+
        i2c_set_clientdata(client, cw_bat);
+       cw_bat->client = client;
 
-       if (!plat_data) {
-               ret = cw2015_parse_dt(&client->dev, &(cw_bat->plat_data));
-               if (ret < 0) {
-                       dev_err(&client->dev,
-                               "failed to find cw2015 platform data\n");
-                       goto pdate_fail;
-               }
+       ret = cw2015_parse_dt(cw_bat);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "failed to find cw2015 platform data\n");
+               return -1;
        }
 
-       cw_bat->client = client;
-       ret = cw_bat_gpio_init(cw_bat);
-       if (ret) {
-               dev_err(&cw_bat->client->dev, "cw_bat_gpio_init error\n");
-               return ret;
-       }
+       cw_bat->capacity = 1;
+       cw_bat->voltage = 0;
+       cw_bat->status = 0;
+       cw_bat->suspend_resume_mark = 0;
+       cw_bat->charger_mode = NO_CHARGING;
+       cw_bat->bat_change = 0;
 
        ret = cw_init(cw_bat);
        if (ret) {
@@ -1236,169 +774,79 @@ static int cw_bat_probe(struct i2c_client *client,
                return ret;
        }
 
-       cw_bat->rk_bat.name = "rk-bat";
-       cw_bat->rk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
-       cw_bat->rk_bat.properties = rk_battery_properties;
-       cw_bat->rk_bat.num_properties = ARRAY_SIZE(rk_battery_properties);
-       cw_bat->rk_bat.get_property = rk_battery_get_property;
-       ret = power_supply_register(&client->dev, &cw_bat->rk_bat);
-       if (ret < 0) {
-               dev_err(&cw_bat->client->dev,
-                       "power supply register rk_bat error\n");
-               goto rk_bat_register_fail;
-       }
+       psy_cfg.drv_data = cw_bat;
 
-       cw_bat->rk_ac.name = "rk-ac";
-       cw_bat->rk_ac.type = POWER_SUPPLY_TYPE_MAINS;
-       cw_bat->rk_ac.properties = rk_ac_properties;
-       cw_bat->rk_ac.num_properties = ARRAY_SIZE(rk_ac_properties);
-       cw_bat->rk_ac.get_property = rk_ac_get_property;
-       ret = power_supply_register(&client->dev, &cw_bat->rk_ac);
-       if (ret < 0) {
+       cw_bat->rk_bat = devm_power_supply_register(&client->dev,
+               &cw2015_bat_desc, &psy_cfg);
+       if (IS_ERR(cw_bat->rk_bat)) {
                dev_err(&cw_bat->client->dev,
-                       "power supply register rk_ac error\n");
-               goto rk_ac_register_fail;
-       }
-
-       if (cw_bat->plat_data.is_usb_charge == 1) {
-               cw_bat->rk_usb.name = "rk-usb";
-               cw_bat->rk_usb.type = POWER_SUPPLY_TYPE_USB;
-               cw_bat->rk_usb.properties = rk_usb_properties;
-               cw_bat->rk_usb.num_properties = ARRAY_SIZE(rk_usb_properties);
-               cw_bat->rk_usb.get_property = rk_usb_get_property;
-               ret = power_supply_register(&client->dev, &cw_bat->rk_usb);
-               if (ret < 0) {
-                       dev_err(&cw_bat->client->dev,
-                               "power supply register rk_usb error\n");
-                       goto rk_usb_register_fail;
-               }
-               cw_bat->charger_init_mode = dwc_otg_check_dpdm();
-               pr_info("%s cw2015 support charger by usb. usb_mode=%d\n",
-                       __func__, cw_bat->charger_init_mode);
+                       "power supply register rk_bat error\n");
+               return -1;
        }
 
-       cw_bat->dc_online = 0;
-       cw_bat->usb_online = 0;
-       cw_bat->charger_mode = 0;
-       cw_bat->capacity = 1;
-       cw_bat->voltage = 0;
-       cw_bat->status = 0;
-       cw_bat->time_to_empty = 0;
-       cw_bat->bat_change = 0;
-
-       cw_update_time_member_capacity_change(cw_bat);
-       cw_update_time_member_charge_start(cw_bat);
-
        cw_bat->battery_workqueue = create_singlethread_workqueue("rk_battery");
        INIT_DELAYED_WORK(&cw_bat->battery_delay_work, cw_bat_work);
-       INIT_DELAYED_WORK(&cw_bat->dc_wakeup_work, dc_detect_do_wakeup);
        queue_delayed_work(cw_bat->battery_workqueue,
                           &cw_bat->battery_delay_work, msecs_to_jiffies(10));
 
-       if (gpio_is_valid(cw_bat->plat_data.dc_det_pin)) {
-               irq = gpio_to_irq(cw_bat->plat_data.dc_det_pin);
-               level = gpio_get_value(cw_bat->plat_data.dc_det_pin);
-               if (level == cw_bat->plat_data.dc_det_level) {
-                       pr_info("%s booting up with dc plug\n", __func__);
-                       cw_bat->status = POWER_SUPPLY_STATUS_CHARGING;
-               }
-               irq_flags = level ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
-               ret =
-                   request_irq(irq, dc_detect_irq_handler, irq_flags,
-                               "dc_detect", cw_bat);
-               if (ret < 0)
-                       pr_err("%s: request_irq(%d) failed\n", __func__, irq);
-               enable_irq_wake(irq);
-       }
-
-       if (gpio_is_valid(cw_bat->plat_data.bat_low_pin)) {
-               INIT_DELAYED_WORK(&cw_bat->bat_low_wakeup_work,
-                                 bat_low_detect_do_wakeup);
-               level = gpio_get_value(cw_bat->plat_data.bat_low_pin);
-               if (level == cw_bat->plat_data.dc_det_level) {
-                       pr_info("%s booting up with lower power\n", __func__);
-                       cw_bat->capacity = 1;
-               }
-               irq = gpio_to_irq(cw_bat->plat_data.bat_low_pin);
-               ret =
-                   request_irq(irq, bat_low_detect_irq_handler,
-                               IRQF_TRIGGER_RISING, "bat_low_detect", cw_bat);
-               if (ret < 0)
-                       gpio_free(cw_bat->plat_data.bat_low_pin);
-
-               enable_irq_wake(irq);
-       }
-
        dev_info(&cw_bat->client->dev,
                 "cw2015/cw2013 driver v1.2 probe sucess\n");
        return 0;
-
-rk_usb_register_fail:
-       power_supply_unregister(&cw_bat->rk_usb);
-rk_ac_register_fail:
-       power_supply_unregister(&cw_bat->rk_ac);
-rk_bat_register_fail:
-       power_supply_unregister(&cw_bat->rk_bat);
-pdate_fail:
-       dev_info(&cw_bat->client->dev,
-                "cw2015/cw2013 driver v1.2 probe error!!!!\n");
-       return ret;
 }
 
-static int cw_bat_remove(struct i2c_client *client)
+#ifdef CONFIG_PM
+static int cw_bat_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct cw_battery *cw_bat = i2c_get_clientdata(client);
-
-       dev_dbg(&cw_bat->client->dev, "%s\n", __func__);
+       read_persistent_clock(&cw_bat->suspend_time_before);
        cancel_delayed_work(&cw_bat->battery_delay_work);
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int cw_bat_suspend(struct device *dev)
+static int cw_bat_resume(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct cw_battery *cw_bat = i2c_get_clientdata(client);
-
-       dev_dbg(&cw_bat->client->dev, "%s\n", __func__);
-       cancel_delayed_work(&cw_bat->battery_delay_work);
+       cw_bat->suspend_resume_mark = 1;
+       read_persistent_clock(&cw_bat->after);
+       cw_bat->after = timespec_sub(cw_bat->after,
+                                    cw_bat->suspend_time_before);
+       queue_delayed_work(cw_bat->battery_workqueue,
+                          &cw_bat->battery_delay_work, msecs_to_jiffies(2));
        return 0;
 }
 
-static int cw_bat_resume(struct device *dev)
+static const struct dev_pm_ops cw_bat_pm_ops = {
+       .suspend  = cw_bat_suspend,
+       .resume   = cw_bat_resume,
+};
+#endif
+
+static int cw_bat_remove(struct i2c_client *client)
 {
-       struct i2c_client *client = to_i2c_client(dev);
        struct cw_battery *cw_bat = i2c_get_clientdata(client);
 
        dev_dbg(&cw_bat->client->dev, "%s\n", __func__);
-       queue_delayed_work(cw_bat->battery_workqueue,
-                          &cw_bat->battery_delay_work, msecs_to_jiffies(100));
+       cancel_delayed_work(&cw_bat->battery_delay_work);
        return 0;
 }
 
-static const struct i2c_device_id cw_id[] = {
+static const struct i2c_device_id cw_bat_id_table[] = {
        {"cw201x", 0},
        {}
 };
-MODULE_DEVICE_TABLE(i2c, cw_id);
-
-static const struct dev_pm_ops cw_bat_pm_ops = {
-       .suspend = cw_bat_suspend,
-       .resume = cw_bat_resume,
-};
-#endif
 
 static struct i2c_driver cw_bat_driver = {
        .driver = {
-                  .name = "cw201x",
+               .name = "cw201x",
 #ifdef CONFIG_PM
-                  .pm = &cw_bat_pm_ops,
+               .pm = &cw_bat_pm_ops,
 #endif
-                  },
-
+       },
        .probe = cw_bat_probe,
        .remove = cw_bat_remove,
-       .id_table = cw_id,
+       .id_table = cw_bat_id_table,
 };
 
 static int __init cw_bat_init(void)
@@ -1411,7 +859,7 @@ static void __exit cw_bat_exit(void)
        i2c_del_driver(&cw_bat_driver);
 }
 
-fs_initcall(cw_bat_init);
+module_init(cw_bat_init);
 module_exit(cw_bat_exit);
 
 MODULE_AUTHOR("xhc<xhc@rock-chips.com>");
index 6f14aa71d00e44c564773fc449eaca282adb4bef..1e3703eff2f599eff9a22056a0dbf402eea2f8a7 100644 (file)
 #define CONFIG_UPDATE_FLG       (0x1<<1)
 #define ATHD                    (0x0<<3)
 
-#define CW_I2C_SPEED            100000
-#define BATTERY_UP_MAX_CHANGE   420
-#define BATTERY_DOWN_CHANGE   60
-#define BATTERY_DOWN_MIN_CHANGE_RUN 30
-#define BATTERY_DOWN_MIN_CHANGE_SLEEP 1800
+#define CW_I2C_SPEED                   100000
+#define BATTERY_UP_MAX_CHANGE          (420 * 1000)
+#define BATTERY_DOWN_MAX_CHANGE                (120 * 1000)
+#define BATTERY_DOWN_CHANGE            60
+#define BATTERY_DOWN_MIN_CHANGE_RUN    30
+#define BATTERY_DOWN_MIN_CHANGE_SLEEP  1800
+#define BATTERY_JUMP_TO_ZERO           (30 * 1000)
+#define BATTERY_CAPACITY_ERROR         (40 * 1000)
+#define BATTERY_CHARGING_ZERO          (1800 * 1000)
+
+#define DOUBLE_SERIES_BATTERY  0
+
+#define CHARGING_ON            1
+#define NO_CHARGING            0
 
 #define BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE 3600
 
 #define AC_CHARGER_MODE         2
 #define   CW_QUICKSTART         0
 
+#define TIMER_MS_COUNTS                        1000
+#define DEFAULT_MONITOR_SEC            8
+
+/* virtual params */
+#define VIRTUAL_CURRENT                        1000
+#define VIRTUAL_VOLTAGE                        3888
+#define VIRTUAL_SOC                    66
+#define VIRTUAL_PRESET                 1
+#define VIRTUAL_TEMPERATURE            188
+#define VIRTUAL_TIME2EMPTY             60
+#define VIRTUAL_STATUS                 POWER_SUPPLY_STATUS_CHARGING
+
+enum bat_mode {
+       MODE_BATTARY = 0,
+       MODE_VIRTUAL,
+};
+
 struct cw_bat_platform_data {
-       int is_dc_charge;
-       int dc_det_pin;
-       int dc_det_level;
-
-       int is_usb_charge;
-       int chg_mode_sel_pin;
-       int chg_mode_sel_level;
-
-       int bat_low_pin;
-       int bat_low_level;
-       int chg_ok_pin;
-       int chg_ok_level;
+       int divider_res1;
+       int divider_res2;
        u32 *cw_bat_config_info;
 };
 
@@ -74,52 +90,27 @@ struct cw_battery {
        struct i2c_client *client;
        struct workqueue_struct *battery_workqueue;
        struct delayed_work battery_delay_work;
-       struct delayed_work dc_wakeup_work;
-       struct delayed_work bat_low_wakeup_work;
        struct cw_bat_platform_data plat_data;
 
-       struct power_supply rk_bat;
-       struct power_supply rk_ac;
-       struct power_supply rk_usb;
-
-       long sleep_time_capacity_change;
-       long run_time_capacity_change;
+       struct power_supply *rk_bat;
 
-       long sleep_time_charge_start;
-       long run_time_charge_start;
+       struct power_supply *chrg_usb_psy;
+       struct power_supply *chrg_ac_psy;
 
-       int dc_online;
-       int usb_online;
+#ifdef CONFIG_PM
+       struct timespec suspend_time_before;
+       struct timespec after;
+       int suspend_resume_mark;
+#endif
        int charger_mode;
-       int charger_init_mode;
        int capacity;
        int voltage;
        int status;
        int time_to_empty;
        int alt;
-
+       u32 monitor_sec;
+       u32 bat_mode;
        int bat_change;
 };
 
-#if defined(CONFIG_ARCH_ROCKCHIP)
-int get_gadget_connect_flag(void);
-int dwc_otg_check_dpdm(void);
-int dwc_vbus_status(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 int dwc_vbus_status(void);
-{
-       return 0;
-}
-#endif
-
 #endif