battery: cw2015: add wakeup system when capacity is 0 and Resolve some bug
authorxuhuicong <xhc@rock-chips.com>
Sat, 22 Jun 2013 05:55:54 +0000 (13:55 +0800)
committerxuhuicong <xhc@rock-chips.com>
Sat, 22 Jun 2013 05:55:54 +0000 (13:55 +0800)
drivers/power/cw2015_battery.c

index 869dff3356c4b681ecae7fbc7991ccfd0919627f..69f3b6a4380f81a090ddd79a8cdcc4970dfbb976 100755 (executable)
@@ -10,6 +10,8 @@
  *
  */
 
+// #define DEBUG    1
+
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/workqueue.h>
 #define MODE_RESTART            (0xf<<0)
 
 #define CONFIG_UPDATE_FLG       (0x1<<1)
-#define ATHD                    (0x0<<3)        //ATHD =10%
+#define ATHD                    (0x0<<3)        //ATHD = 0%
 
 #define CW_I2C_SPEED            100000          // default i2c speed set 100khz
-
 #define BATTERY_UP_MAX_CHANGE   420             // the max time allow battery change quantity
 #define BATTERY_DOWN_CHANGE   60                // the max time allow battery change quantity
 #define BATTERY_DOWN_MIN_CHANGE_RUN 30          // the min time allow battery change quantity when run
 
 #define BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE 3600
 
-#define Enable_BATDRV_LOG       0
+#define NO_STANDARD_AC_BIG_CHARGE_MODE 1
+// #define SYSTEM_SHUTDOWN_VOLTAGE  3400000        //set system shutdown voltage related in battery info.
+#define BAT_LOW_INTERRUPT    1
 
 #define USB_CHARGER_MODE        1
 #define AC_CHARGER_MODE         2
 
-
-#if Enable_BATDRV_LOG
-#define xprintk(format, arg...)  printk("func: %s\n" format,  __FUNCTION__, ##arg)
-#else
-#define xprintk(format, ...)
-#endif
-
 extern int dwc_otg_check_dpdm(void);
 extern int get_gadget_connect_flag(void);
 extern int dwc_vbus_status( void );
@@ -70,17 +66,18 @@ struct cw_battery {
         struct workqueue_struct *battery_workqueue;
         struct delayed_work battery_delay_work;
         struct delayed_work dc_wakeup_work;
+        struct delayed_work bat_low_wakeup_work;
         const 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;      // the sleep time from capacity change to present, it will set 0 when capacity change 
-        long run_time_capacity;
+        long sleep_time_capacity_change;      // the sleep time from capacity change to present, it will set 0 when capacity change 
+        long run_time_capacity_change;
 
-        long sleep_time_ac_online;      // the sleep time from insert ac to present, it will set 0 when insert ac
-        long run_time_ac_online;
+        long sleep_time_charge_start;      // the sleep time from insert ac to present, it will set 0 when insert ac
+        long run_time_charge_start;
 
         int dc_online;
         int usb_online;
@@ -108,6 +105,7 @@ static int cw_write(struct i2c_client *client, u8 reg, u8 const buf[])
         ret = i2c_master_reg8_send(client, reg, buf, 1, CW_I2C_SPEED);
         return ret;
 }
+
 static int cw_read_word(struct i2c_client *client, u8 reg, u8 buf[])
 {
         int ret;
@@ -133,7 +131,8 @@ static int cw_update_config_info(struct cw_battery *cw_bat)
         int i;
         u8 reset_val;
 
-        printk("func: %s-------\n", __func__);
+        dev_info(&cw_bat->client->dev, "func: %s-------\n", __func__);
+        
         /* make sure no in sleep mode */
         ret = cw_read(cw_bat->client, REG_MODE, &reg_val);
         if (ret < 0)
@@ -141,14 +140,13 @@ static int cw_update_config_info(struct cw_battery *cw_bat)
 
         reset_val = reg_val;
         if((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) {
-                printk("Error, device in sleep mode, cannot update battery info\n");
+                dev_err(&cw_bat->client->dev, "Error, device in sleep mode, cannot update battery info\n");
                 return -1;
         }
 
         /* update new battery info */
-
         for (i = 0; i < SIZE_BATINFO; i++) {
-                printk("cw_bat->plat_data->cw_bat_config_info[%d] = 0x%x\n", i, \
+                dev_info(&cw_bat->client->dev, "cw_bat->plat_data->cw_bat_config_info[%d] = 0x%x\n", i, \
                                 cw_bat->plat_data->cw_bat_config_info[i]);
                 ret = cw_write(cw_bat->client, REG_BATINFO + i, &cw_bat->plat_data->cw_bat_config_info[i]);
 
@@ -162,31 +160,30 @@ static int cw_update_config_info(struct cw_battery *cw_bat)
                 if (reg_val != cw_bat->plat_data->cw_bat_config_info[i])
                         return -1;
         }
-
         
-        /* set cw2015 to use new battery info */
+        /* 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
+        reg_val |= CONFIG_UPDATE_FLG;   /* set UPDATE_FLAG */
+        reg_val &= 0x07;                /* clear ATHD */
+        reg_val |= ATHD;                /* set ATHD */
         ret = cw_write(cw_bat->client, REG_CONFIG, &reg_val);
         if (ret < 0)
                 return ret;
 
-        /* check 2015 for ATHD & update_flag */ 
+        /* check 2015/cw2013 for ATHD & update_flag */ 
         ret = cw_read(cw_bat->client, REG_CONFIG, &reg_val);
         if (ret < 0)
                 return ret;
         
         if (!(reg_val & CONFIG_UPDATE_FLG)) {
-                printk("update flag for new battery info have not set..\n");
+                dev_info(&cw_bat->client->dev, "update flag for new battery info have not set..\n");
         }
 
         if ((reg_val & 0xf8) != ATHD) {
-                printk("the new ATHD have not set..\n");
+                dev_info(&cw_bat->client->dev, "the new ATHD have not set..\n");
         }
 
         /* reset */
@@ -226,9 +223,9 @@ static int cw_init(struct cw_battery *cw_bat)
                 return ret;
 
         if ((reg_val & 0xf8) != ATHD) {
-                printk("the new ATHD have not set\n");
-                reg_val &= 0x07;    // clear ATHD
-                reg_val |= ATHD;    // set ATHD
+                dev_info(&cw_bat->client->dev, "the new ATHD have not set\n");
+                reg_val &= 0x07;    /* clear ATHD */
+                reg_val |= ATHD;    /* set ATHD */
                 ret = cw_write(cw_bat->client, REG_CONFIG, &reg_val);
                 if (ret < 0)
                         return ret;
@@ -239,7 +236,7 @@ static int cw_init(struct cw_battery *cw_bat)
                 return ret;
 
         if (!(reg_val & CONFIG_UPDATE_FLG)) {
-                printk("update flag for new battery info have not set\n");
+                dev_info(&cw_bat->client->dev, "update flag for new battery info have not set\n");
                 ret = cw_update_config_info(cw_bat);
                 if (ret < 0)
                         return ret;
@@ -254,7 +251,7 @@ static int cw_init(struct cw_battery *cw_bat)
                 }
 
                 if (i != SIZE_BATINFO) {
-                        printk("update flag for new battery info have not set\n"); 
+                        dev_info(&cw_bat->client->dev, "update flag for new battery info have not set\n"); 
                         ret = cw_update_config_info(cw_bat);
                         if (ret < 0)
                                 return ret;
@@ -270,14 +267,14 @@ static int cw_init(struct cw_battery *cw_bat)
                 
                 msleep(100);
                 if (i > 25)
-                        printk("cw2015 input unvalid power error\n");
+                        dev_err(&cw_bat->client->dev, "cw2015/cw2013 input unvalid power error\n");
 
         }
         
         return 0;
 }
 
-static void cw_update_time_member_ac_online(struct cw_battery *cw_bat)
+static void cw_update_time_member_charge_start(struct cw_battery *cw_bat)
 {
         struct timespec ts;
         int new_run_time;
@@ -289,11 +286,11 @@ static void cw_update_time_member_ac_online(struct cw_battery *cw_bat)
         get_monotonic_boottime(&ts);
         new_sleep_time = ts.tv_sec - new_run_time;
 
-        cw_bat->run_time_ac_online = new_run_time;
-        cw_bat->sleep_time_ac_online = new_sleep_time; 
+        cw_bat->run_time_charge_start = new_run_time;
+        cw_bat->sleep_time_charge_start = new_sleep_time; 
 }
 
-static void cw_update_time_member_capacity(struct cw_battery *cw_bat)
+static void cw_update_time_member_capacity_change(struct cw_battery *cw_bat)
 {
         struct timespec ts;
         int new_run_time;
@@ -305,8 +302,8 @@ static void cw_update_time_member_capacity(struct cw_battery *cw_bat)
         get_monotonic_boottime(&ts);
         new_sleep_time = ts.tv_sec - new_run_time;
 
-        cw_bat->run_time_capacity = new_run_time;
-        cw_bat->sleep_time_capacity = new_sleep_time; 
+        cw_bat->run_time_capacity_change = new_run_time;
+        cw_bat->sleep_time_capacity_change = new_sleep_time; 
 }
 
 static int cw_quickstart(struct cw_battery *cw_bat)
@@ -316,14 +313,14 @@ static int cw_quickstart(struct cw_battery *cw_bat)
 
         ret = cw_write(cw_bat->client, REG_MODE, &reg_val);     //(MODE_QUICK_START | MODE_NORMAL));  // 0x30
         if(ret < 0) {
-                printk("Error quick start1\n");
+                dev_err(&cw_bat->client->dev, "Error quick start1\n");
                 return ret;
         }
         
         reg_val = MODE_NORMAL;
         ret = cw_write(cw_bat->client, REG_MODE, &reg_val);
         if(ret < 0) {
-                printk("Error quick start2\n");
+                dev_err(&cw_bat->client->dev, "Error quick start2\n");
                 return ret;
         }
         return 1;
@@ -343,6 +340,7 @@ static int cw_get_capacity(struct cw_battery *cw_bat)
         int allow_capacity;
         static int if_quickstart = 0;
         static int jump_flag =0;
+        int charge_time;
 
 
         // ret = cw_read(cw_bat->client, REG_SOC, &reg_val);
@@ -352,14 +350,14 @@ static int cw_get_capacity(struct cw_battery *cw_bat)
 
         cw_capacity = reg_val[0];
         if ((cw_capacity < 0) || (cw_capacity > 100)) {
-                printk("get cw_capacity error; cw_capacity = %d\n", cw_capacity);
+                dev_err(&cw_bat->client->dev, "get cw_capacity error; cw_capacity = %d\n", cw_capacity);
                 return cw_capacity;
         } 
 
         if (cw_capacity == 0) 
-                xprintk("the cw201x capacity is 0 !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__);
+                dev_dbg(&cw_bat->client->dev, "the cw201x capacity is 0 !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__);
         else 
-                xprintk("the cw201x capacity is %d, funciton: %s\n", cw_capacity, __func__);
+                dev_dbg(&cw_bat->client->dev, "the cw201x capacity is %d, funciton: %s\n", cw_capacity, __func__);
 
         // ret = cw_read(cw_bat->client, REG_SOC + 1, &reg_val);
 
@@ -371,13 +369,15 @@ static int cw_get_capacity(struct cw_battery *cw_bat)
 
         if ((cw_bat->charger_mode > 0) && (cw_capacity >= 95) && (cw_capacity <= cw_bat->capacity)) {     // avoid no charge full
 
-                capacity_or_aconline_time = (cw_bat->sleep_time_capacity > cw_bat->sleep_time_ac_online) ? cw_bat->sleep_time_capacity : cw_bat->sleep_time_ac_online;
-                capacity_or_aconline_time += (cw_bat->run_time_capacity > cw_bat->run_time_ac_online) ? cw_bat->run_time_capacity : cw_bat->run_time_ac_online;
+                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;
                         jump_flag =1;
+                } else if (cw_capacity <= cw_bat->capacity) {
+                        cw_capacity = cw_bat->capacity; 
                 }
 
         } else if (((cw_bat->charger_mode > 0) && (cw_capacity == (cw_bat->capacity - 1)))
@@ -389,8 +389,8 @@ static int cw_get_capacity(struct cw_battery *cw_bat)
                                
 
         } else if ((cw_capacity == 0) && (cw_bat->capacity > 1)) {              // avoid battery level jump to 0% at a moment from more than 2%
-                allow_change = ((new_run_time - cw_bat->run_time_capacity) / BATTERY_DOWN_MIN_CHANGE_RUN);
-                allow_change += ((new_sleep_time - cw_bat->sleep_time_capacity) / BATTERY_DOWN_MIN_CHANGE_SLEEP);
+                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;
@@ -400,8 +400,8 @@ static int cw_get_capacity(struct cw_battery *cw_bat)
                         return ret;
 
         } else if ((cw_bat->charger_mode == 0) && (cw_capacity <= cw_bat->capacity ) && (cw_capacity >= 90) && (jump_flag == 1)) {     // avoid battery level jump to CW_BAT
-                capacity_or_aconline_time = (cw_bat->sleep_time_capacity > cw_bat->sleep_time_ac_online) ? cw_bat->sleep_time_capacity : cw_bat->sleep_time_ac_online;
-                capacity_or_aconline_time += (cw_bat->run_time_capacity > cw_bat->run_time_ac_online) ? cw_bat->run_time_capacity : cw_bat->run_time_ac_online;
+                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; 
@@ -409,15 +409,18 @@ static int cw_get_capacity(struct cw_battery *cw_bat)
                                jump_flag =0;
                         }
                         else{
-                        cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100;
+                                cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100;
                         }
+                } else if (cw_capacity <= cw_bat->capacity) {
+                        cw_capacity = cw_bat->capacity;
                 }
         }
  
 #if 1  
        if((cw_bat->charger_mode > 0) &&(cw_capacity == 0))
        {                 
-                if (((new_sleep_time + new_run_time - cw_bat->sleep_time_ac_online - cw_bat->run_time_ac_online) > BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE) && (if_quickstart == 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)) {
                        cw_quickstart(cw_bat);      // if the cw_capacity = 0 the cw2015 will qstrt
                         if_quickstart = 1;
                 }
@@ -427,11 +430,33 @@ static int cw_get_capacity(struct cw_battery *cw_bat)
 
 #endif
 
+#if 0
         if (cw_bat->plat_data->chg_ok_pin != INVALID_GPIO) {
-                if((cw_capacity == 100) && (gpio_get_value(cw_bat->plat_data->chg_ok_pin) != cw_bat->plat_data->chg_ok_level))
-                        cw_capacity = 99;
+                if(gpio_get_value(cw_bat->plat_data->chg_ok_pin) != cw_bat->plat_data->chg_ok_level) {
+                        if (cw_capacity == 100) {
+                                cw_capacity = 99;
+                        }
+                } else {
+                        if (cw_bat->charger_mode > 0) {
+                                cw_capacity = 100;
+                        }
+                }
         }
+#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;
+                dev_info(&cw_bat->client->dev, "the cw201x voltage is less than SYSTEM_SHUTDOWN_VOLTAGE !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__);
+        } else if ((cw_bat->charger_mode > 0)&& (if_quickstart <= 12)) {
+                if_quickstart = 0;
+        }
+#endif
         return cw_capacity;
 }
 
@@ -480,34 +505,35 @@ static int cw_get_vol(struct cw_battery *cw_bat)
         }                      
 
         voltage = value16_1 * 312 / 1024;
+        voltage = voltage * 1000;
 
         return voltage;
 }
 
-#if 0
+#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;
-
-       //dev_info(&client->dev, "read RRT %d%%. value16 0x%x\n", alrt, value16);
-             value8 = value8&0x7f;
-             reg_val = value8;
-             ret = cw_write(cw_bat->client, REG_RRT_ALERT, &reg_val);
+        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;
+        
+        //dev_info(&cw_bat->client->dev, "read RRT %d%%. value16 0x%x\n", alrt, value16);
+        value8 = value8&0x7f;
+        reg_val = value8;
+        ret = cw_write(cw_bat->client, REG_RRT_ALERT, &reg_val);
         if(ret < 0) {
-                printk("Error clear ALRT\n");
+                dev_err(&cw_bat->client->dev, "Error clear ALRT\n");
                 return ret;
         }
-               
-             return alrt;
+        
+        return alrt;
 }
 #endif
 
@@ -540,10 +566,10 @@ static void rk_bat_update_capacity(struct cw_battery *cw_bat)
         if ((cw_capacity >= 0) && (cw_capacity <= 100) && (cw_bat->capacity != cw_capacity)) {
                 cw_bat->capacity = cw_capacity;
                 cw_bat->bat_change = 1;
-                cw_update_time_member_capacity(cw_bat);
+                cw_update_time_member_capacity_change(cw_bat);
 
                 if (cw_bat->capacity == 0)
-                        printk("report battery capacity 0 and will shutdown if no changing");
+                        dev_info(&cw_bat->client->dev, "report battery capacity 0 and will shutdown if no changing");
 
         }
 }
@@ -565,7 +591,7 @@ static void rk_bat_update_status(struct cw_battery *cw_bat)
         int status;
 
 
-        if ((cw_bat->dc_online == 1) || (cw_bat->usb_online == 1)) {
+        if (cw_bat->charger_mode > 0) {
                 if (cw_bat->capacity >= 100) 
                         status=POWER_SUPPLY_STATUS_FULL;
                 else
@@ -594,95 +620,140 @@ static void rk_bat_update_time_to_empty(struct cw_battery *cw_bat)
 
 static int rk_ac_update_online(struct cw_battery *cw_bat)
 {
-        if(cw_bat->plat_data->dc_det_pin == INVALID_GPIO)
+        int ret = 0;
+
+        if(cw_bat->plat_data->dc_det_pin == INVALID_GPIO) {
+                cw_bat->dc_online = 0;
+                return 0;
+        }
+#if 0
+        if (cw_bat->plat_data->is_dc_charge == 0) {
+                cw_bat->dc_online = 0;
                 return 0;
+        }
+#endif
+
         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_ac_online(cw_bat);
+                        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;
  
-                        return 1;
+                        ret = 1;
                 }
         } else {
                 if (cw_bat->dc_online != 0) {
-                        cw_update_time_member_ac_online(cw_bat);
+                        cw_update_time_member_charge_start(cw_bat);
                         cw_bat->dc_online = 0;
-                if ((cw_bat->usb_online == 0)&&(cw_bat->charger_mode != 0))
-                                cw_bat->charger_mode = 0;
-
-                        return 1;
+                        if (cw_bat->usb_online == 0)
+                                cw_bat->charger_mode = 0;
+                        ret = 1;
                 }
         }
-
-        return 0;
+        return ret;
 }
 
-static int rk_usb_update_online(struct cw_battery *cw_bat)
+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();
-        int gadget_status =get_gadget_connect_flag();
 
-        xprintk("%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);
+        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
+        return usb_status;
+        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);
+
 
 
+}
+
+static int rk_usb_update_online(struct cw_battery *cw_bat)
+{
+        int ret = 0;
+        int usb_status = 0;
+      
         if (cw_bat->plat_data->is_usb_charge == 0) {
                 cw_bat->usb_online = 0;
                 return 0;
 
         }
+        
+        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 (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO) {
+                        if (gpio_get_value (cw_bat->plat_data->chg_mode_sel_pin) != cw_bat->plat_data->chg_mode_sel_level)
+                                gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_HIGH : GPIO_LOW);
+                }
+                
+                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 (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO) {
+                        if (gpio_get_value (cw_bat->plat_data->chg_mode_sel_pin) == cw_bat->plat_data->chg_mode_sel_level)
+                                gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
+                }
+                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 (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO) {
+                        if (gpio_get_value (cw_bat->plat_data->chg_mode_sel_pin == cw_bat->plat_data->chg_mode_sel_level))
+                                gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
+                }
+
+                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;
+        }
 
-        if (((usb_status == 2) || (cw_bat->charger_init_mode==2)) && (cw_bat->charger_mode != AC_CHARGER_MODE)){
-
-                        if (cw_bat->charger_mode != AC_CHARGER_MODE)
-                            cw_bat->charger_mode = AC_CHARGER_MODE;
-                        if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO)
-                       gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_HIGH : GPIO_LOW);
-                   if (cw_bat->usb_online != 1){
-                              cw_bat->usb_online = 1;
-                            cw_update_time_member_ac_online(cw_bat);
-                            return 1;
-                        }
-        } else if ((usb_status == 1) || ((cw_bat->charger_init_mode==1))) {
-#if 1
-             if (0 == gadget_status){
-                   if (cw_bat->charger_mode != AC_CHARGER_MODE)
-                         cw_bat->charger_mode = AC_CHARGER_MODE;
-                   if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO)
-                         gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_HIGH : GPIO_LOW);
-                   if (cw_bat->usb_online != 1){
-                                   cw_bat->usb_online = 1;
-                        cw_update_time_member_ac_online(cw_bat);
-                        return 1; 
-                   } 
-             }
-             else{
-#endif
-                    if (cw_bat->charger_mode != USB_CHARGER_MODE)
-                         cw_bat->charger_mode = USB_CHARGER_MODE;
-                   if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO)
-                         gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
-                   if (cw_bat->usb_online != 1){
-                       cw_bat->usb_online = 1;
-                        cw_update_time_member_ac_online(cw_bat);
-                        return 1; 
-                   } 
-             }                             
-        } else {//if (usb_status == 0){
-                   if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO)
-                         gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
-                   if ((cw_bat->dc_online == 0)&&(cw_bat->charger_mode != 0))
-                         cw_bat->charger_mode = 0;
-                   if (cw_bat->usb_online != 0) {
-                       cw_update_time_member_ac_online(cw_bat);
-                       cw_bat->usb_online = 0;
-                       return 1;
-                   }
-        }     
-
-              
-        return 0;
+        return ret;
 }
 
 static void cw_bat_work(struct work_struct *work)
@@ -691,17 +762,9 @@ static void cw_bat_work(struct work_struct *work)
         struct cw_battery *cw_bat;
         int ret;
 
-        struct timespec ts;
-        int time_from_boot;
-
         delay_work = container_of(work, struct delayed_work, work);
         cw_bat = container_of(delay_work, struct cw_battery, battery_delay_work);
 
-        get_monotonic_boottime(&ts);
-        time_from_boot = ts.tv_sec;
-        if ((time_from_boot > 30) && cw_bat->charger_init_mode) {
-                cw_bat->charger_init_mode = 0;
-        }
 
         ret = rk_ac_update_online(cw_bat);
         if (ret == 1) {
@@ -712,7 +775,7 @@ static void cw_bat_work(struct work_struct *work)
                 ret = rk_usb_update_online(cw_bat);
                 if (ret == 1) {
                         power_supply_changed(&cw_bat->rk_usb);     
-                        power_supply_changed(&cw_bat->rk_ac);          /////////////////////////////////////////////////////
+                        power_supply_changed(&cw_bat->rk_ac);
                 }
         }
 
@@ -729,7 +792,7 @@ static void cw_bat_work(struct work_struct *work)
 
         queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->battery_delay_work, msecs_to_jiffies(1000));
 
-        xprintk("cw_bat->bat_change = %d, cw_bat->time_to_empty = %d, cw_bat->capacity = %d, cw_bat->voltage = %d, cw_bat->dc_online = %d, cw_bat->usb_online = %d\n",\
+        dev_dbg(&cw_bat->client->dev, "cw_bat->bat_change = %d, cw_bat->time_to_empty = %d, cw_bat->capacity = %d, cw_bat->voltage = %d, cw_bat->dc_online = %d, cw_bat->usb_online = %d\n",\
                         cw_bat->bat_change, cw_bat->time_to_empty, cw_bat->capacity, cw_bat->voltage, cw_bat->dc_online, cw_bat->usb_online);
 }
 
@@ -839,42 +902,42 @@ static int cw_bat_gpio_init(struct cw_battery *cw_bat)
         if (cw_bat->plat_data->dc_det_pin != INVALID_GPIO) {
                 ret = gpio_request(cw_bat->plat_data->dc_det_pin, NULL);
                 if (ret) {
-                        printk("failed to request dc_det_pin gpio\n");
+                        dev_err(&cw_bat->client->dev, "failed to request dc_det_pin gpio\n");
                         goto request_dc_det_pin_fail;
                 }
 
                 gpio_pull_updown(cw_bat->plat_data->dc_det_pin, GPIOPullUp);
                 ret = gpio_direction_input(cw_bat->plat_data->dc_det_pin);
                 if (ret) {
-                        printk("failed to set dc_det_pin input\n");
+                        dev_err(&cw_bat->client->dev, "failed to set dc_det_pin input\n");
                         goto request_bat_low_pin_fail;
                 }
         }
         if (cw_bat->plat_data->bat_low_pin != INVALID_GPIO) {
                 ret = gpio_request(cw_bat->plat_data->bat_low_pin, NULL);
                 if (ret) {
-                        printk("failed to request bat_low_pin gpio\n");
+                        dev_err(&cw_bat->client->dev, "failed to request bat_low_pin gpio\n");
                         goto request_bat_low_pin_fail;
                 }
 
                 gpio_pull_updown(cw_bat->plat_data->bat_low_pin, GPIOPullUp);
                 ret = gpio_direction_input(cw_bat->plat_data->bat_low_pin);
                 if (ret) {
-                        printk("failed to set bat_low_pin input\n");
+                        dev_err(&cw_bat->client->dev, "failed to set bat_low_pin input\n");
                         goto request_chg_ok_pin_fail;
                 }
         }
         if (cw_bat->plat_data->chg_ok_pin != INVALID_GPIO) {
                 ret = gpio_request(cw_bat->plat_data->chg_ok_pin, NULL);
                 if (ret) {
-                        printk("failed to request chg_ok_pin gpio\n");
+                        dev_err(&cw_bat->client->dev, "failed to request chg_ok_pin gpio\n");
                         goto request_chg_ok_pin_fail;
                 }
 
                 gpio_pull_updown(cw_bat->plat_data->chg_ok_pin, GPIOPullUp);
                 ret = gpio_direction_input(cw_bat->plat_data->chg_ok_pin);
                 if (ret) {
-                        printk("failed to set chg_ok_pin input\n");
+                        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;
                 }
@@ -883,12 +946,12 @@ static int cw_bat_gpio_init(struct cw_battery *cw_bat)
         if ((cw_bat->plat_data->is_usb_charge == 1) && (cw_bat->plat_data->chg_mode_sel_pin!= INVALID_GPIO)) {
                 ret = gpio_request(cw_bat->plat_data->chg_mode_sel_pin, NULL);
                 if (ret) {
-                        printk("failed to request chg_mode_sel_pin gpio\n");
+                        dev_err(&cw_bat->client->dev, "failed to request chg_mode_sel_pin gpio\n");
                         goto request_chg_ok_pin_fail;
                 }
                 ret = gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
                 if (ret) {
-                        printk("failed to set chg_mode_sel_pin input\n");
+                        dev_err(&cw_bat->client->dev, "failed to set chg_mode_sel_pin input\n");
                         gpio_free(cw_bat->plat_data->chg_mode_sel_pin); 
                         goto request_chg_ok_pin_fail;
                 }
@@ -926,8 +989,10 @@ static void dc_detect_do_wakeup(struct work_struct *work)
         rk28_send_wakeup_key();
 
         /* this assume if usb insert or extract dc_det pin is change */
+#if 0
         if(cw_bat->charger_init_mode)
                 cw_bat->charger_init_mode=0;
+#endif
 
         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;
@@ -942,12 +1007,36 @@ static irqreturn_t dc_detect_irq_handler(int irq, void *dev_id)
 {
         struct cw_battery *cw_bat = dev_id;
         disable_irq_nosync(irq); // for irq debounce
-        //wake_lock_timeout(&usb_wakelock, WAKE_LOCK_TIMEOUT);
-        //schedule_delayed_work(&wakeup_work, HZ / 10);
         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 struct wake_lock bat_low_wakelock;
+
+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);
+        //enable_irq(irq);
+}
+
+static irqreturn_t bat_low_detect_irq_handler(int irq, void *dev_id)
+{
+        struct cw_battery *cw_bat = dev_id;
+        // disable_irq_nosync(irq); // for irq debounce
+        wake_lock_timeout(&bat_low_wakelock, WAKE_LOCK_TIMEOUT);
+        queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->bat_low_wakeup_work, msecs_to_jiffies(20));
+        return IRQ_HANDLED;
+}
+#endif
 
 static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
@@ -959,7 +1048,7 @@ static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *i
 
         cw_bat = devm_kzalloc(&client->dev, sizeof(*cw_bat), GFP_KERNEL);
         if (!cw_bat) {
-                printk("fail to allocate memory\n");
+                dev_err(&cw_bat->client->dev, "fail to allocate memory\n");
                 return -ENOMEM;
         }
 
@@ -967,7 +1056,7 @@ static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *i
         cw_bat->plat_data = client->dev.platform_data;
         ret = cw_bat_gpio_init(cw_bat);
         if (ret) {
-                printk("cw_bat_gpio_init error\n");
+                dev_err(&cw_bat->client->dev, "cw_bat_gpio_init error\n");
                 return ret;
         }
         
@@ -988,7 +1077,7 @@ static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *i
         cw_bat->rk_bat.get_property = rk_battery_get_property;
         ret = power_supply_register(&client->dev, &cw_bat->rk_bat);
         if(ret < 0) {
-                printk("power supply register rk_bat error\n");
+                dev_err(&cw_bat->client->dev, "power supply register rk_bat error\n");
                 goto rk_bat_register_fail;
         }
 
@@ -999,7 +1088,7 @@ static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *i
         cw_bat->rk_ac.get_property = rk_ac_get_property;
         ret = power_supply_register(&client->dev, &cw_bat->rk_ac);
         if(ret < 0) {
-                printk("power supply register rk_ac error\n");
+                dev_err(&cw_bat->client->dev, "power supply register rk_ac error\n");
                 goto rk_ac_register_fail;
         }
 
@@ -1010,7 +1099,7 @@ static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *i
         cw_bat->rk_usb.get_property = rk_usb_get_property;
         ret = power_supply_register(&client->dev, &cw_bat->rk_usb);
         if(ret < 0) {
-                printk("power supply register rk_ac error\n");
+                dev_err(&cw_bat->client->dev, "power supply register rk_ac error\n");
                 goto rk_usb_register_fail;
         }
 
@@ -1025,23 +1114,38 @@ static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *i
         cw_bat->time_to_empty = 0;
         cw_bat->bat_change = 0;
 
-        cw_update_time_member_capacity(cw_bat);
-        cw_update_time_member_ac_online(cw_bat);
+        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));
         
-        irq = gpio_to_irq(cw_bat->plat_data->dc_det_pin);
-        irq_flags = gpio_get_value(cw_bat->plat_data->dc_det_pin) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
-        ret = request_irq(irq, dc_detect_irq_handler, irq_flags, "usb_detect", cw_bat);
-        if (ret < 0) {
-                pr_err("%s: request_irq(%d) failed\n", __func__, irq);
+        if (cw_bat->plat_data->dc_det_pin != INVALID_GPIO) {
+                irq = gpio_to_irq(cw_bat->plat_data->dc_det_pin);
+                irq_flags = gpio_get_value(cw_bat->plat_data->dc_det_pin) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
+                ret = request_irq(irq, dc_detect_irq_handler, irq_flags, "usb_detect", cw_bat);
+                if (ret < 0) {
+                        pr_err("%s: request_irq(%d) failed\n", __func__, irq);
+                }
+                enable_irq_wake(irq);
         }
-        enable_irq_wake(irq);
 
-        printk("cw2015 driver v1.0 probe sucess\n");
+#ifdef BAT_LOW_INTERRUPT
+        INIT_DELAYED_WORK(&cw_bat->bat_low_wakeup_work, bat_low_detect_do_wakeup);
+        wake_lock_init(&bat_low_wakelock, WAKE_LOCK_SUSPEND, "bat_low_detect");
+        if (cw_bat->plat_data->bat_low_pin != INVALID_GPIO) {
+                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);
+        }
+#endif
+
+        dev_info(&cw_bat->client->dev, "cw2015/cw2013 driver v1.2 probe sucess\n");
         return 0;
 
 rk_usb_register_fail:
@@ -1049,14 +1153,14 @@ rk_usb_register_fail:
 rk_ac_register_fail:
         power_supply_unregister(&cw_bat->rk_ac);
 rk_bat_register_fail:
-        printk("cw2015 driver v1.0 probe error!!!!\n");
+        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)
 {
         struct cw_battery *cw_bat = i2c_get_clientdata(client);
-        xprintk();
+        dev_dbg(&cw_bat->client->dev, "%s\n", __func__);
         cancel_delayed_work(&cw_bat->battery_delay_work);
         return 0;
 }
@@ -1066,7 +1170,7 @@ 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);
-        xprintk();
+        dev_dbg(&cw_bat->client->dev, "%s\n", __func__);
         cancel_delayed_work(&cw_bat->battery_delay_work);
         return 0;
 }
@@ -1075,7 +1179,7 @@ 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);
-        xprintk();
+        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));
         return 0;
 }
@@ -1106,13 +1210,11 @@ static struct i2c_driver cw_bat_driver = {
 
 static int __init cw_bat_init(void)
 {
-        xprintk();
         return i2c_add_driver(&cw_bat_driver);
 }
 
 static void __exit cw_bat_exit(void)
 {
-        xprintk();
         i2c_del_driver(&cw_bat_driver);
 }
 
@@ -1120,6 +1222,6 @@ fs_initcall(cw_bat_init);
 module_exit(cw_bat_exit);
 
 MODULE_AUTHOR("xhc<xhc@rock-chips.com>");
-MODULE_DESCRIPTION("cw2015 battery driver");
+MODULE_DESCRIPTION("cw2015/cw2013 battery driver");
 MODULE_LICENSE("GPL");