power: rk81x-battery: get charger type by usb notifier instead of polling
[firefly-linux-kernel-4.4.55.git] / drivers / power / rk818_battery.c
index ceb28ec4e9b77c51ef2e4b7dedf01007d76ef5dc..52c623710a1164cd241bcacd1dd861cf63e7953e 100644 (file)
@@ -53,6 +53,8 @@
 
 #if defined(CONFIG_X86_INTEL_SOFIA)
 #include <linux/usb/phy-intel.h>
+#else
+#include <linux/power/rk_usbbc.h>
 #endif
 #include "rk818_battery.h"
 
@@ -149,6 +151,10 @@ module_param_named(dbg_level, dbg_enable, int, 0644);
 #define DSOC_CHRG_FINISH_CURR  1100
 #define SLP_CHRG_CURR          1000
 #define SLP_DSOC_VOL_THRESD    3600
+/*if voltage is lower than this thresd,
+   we consider it as invalid
+ */
+#define INVALID_VOL_THRESD     2500
 #define PWR_OFF_THRESD         3400
 #define MIN_ZERO_ACCURACY      10      /*0.01%*/
 
@@ -195,6 +201,7 @@ struct rk81x_battery {
        int                             irq;
        int                             ac_online;
        int                             usb_online;
+       int                             otg_online;
        int                             psy_status;
        int                             current_avg;
        int                             current_offset;
@@ -282,10 +289,12 @@ struct rk81x_battery {
        int                             s2r; /*suspend to resume*/
        struct workqueue_struct         *wq;
        struct delayed_work             battery_monitor_work;
-       struct delayed_work             charge_check_work;
+       struct delayed_work             otg_check_work;
        struct delayed_work             usb_phy_delay_work;
        struct delayed_work             chrg_term_mode_switch_work;
-       int                             charge_otg;
+       struct delayed_work             ac_usb_check_work;
+       struct delayed_work             dc_det_check_work;
+       enum bc_port_type               charge_otg;
        int                             ma;
 
        struct wake_lock                resume_wake_lock;
@@ -595,7 +604,7 @@ static void rk81x_bat_capacity_init(struct rk81x_battery *di, u32 capacity)
 
        } while (buf == 0);
 
-       dev_info(di->dev, "update capacity :%d--remain_cap:%d\n",
+       dev_dbg(di->dev, "update capacity :%d--remain_cap:%d\n",
                 capacity, di->remain_capacity);
 }
 
@@ -920,7 +929,7 @@ static uint16_t rk81x_bat_get_ocv_vol(struct rk81x_battery *di)
 static int rk81x_bat_get_vol(struct rk81x_battery *di)
 {
        int ret;
-       int voltage_now = 0;
+       int vol;
        u8 buf;
        int temp;
        int val[3];
@@ -943,9 +952,9 @@ static int rk81x_bat_get_vol(struct rk81x_battery *di)
        else
                temp = val[2];
 
-       voltage_now = di->voltage_k * temp / 1000 + di->voltage_b;
+       vol = di->voltage_k * temp / 1000 + di->voltage_b;
 
-       return voltage_now;
+       return vol;
 }
 
 static bool is_rk81x_bat_relax_mode(struct rk81x_battery *di)
@@ -1094,7 +1103,7 @@ static bool rk81x_bat_zero_current_calib(struct rk81x_battery *di)
                for (retry = 0; retry < 5; retry++) {
                        adc_value = rk81x_bat_get_raw_adc_current(di);
                        if (!rk81x_chrg_online(di) || abs(adc_value) > 30) {
-                               dev_dbg(di->dev, "charger plugout\n");
+                               dev_warn(di->dev, "charger plugout\n");
                                ret = true;
                                break;
                        }
@@ -1130,7 +1139,7 @@ static bool rk81x_bat_zero_current_calib(struct rk81x_battery *di)
                                ret = false;
                                break;
                        } else {
-                               dev_warn(di->dev, "ioffset cal failed\n");
+                               dev_dbg(di->dev, "ioffset cal failed\n");
                                rk81x_bat_set_cal_offset(di, C0);
                        }
 
@@ -1732,152 +1741,122 @@ static void rk81x_bat_set_chrg_current(struct rk81x_battery *di,
 }
 
 #if defined(CONFIG_ARCH_ROCKCHIP)
-/*
-* There are three ways to detect dc_adp:
-*      1. hardware only support dc_adp: by reg VB_MOD_REG of rk818,
-*         do not care about whether define dc_det_pin or not;
-*      2. define de_det_pin: check gpio level;
-*      3. support usb_adp and dc_adp: by VB_MOD_REG and usb interface.
-*         case that: gpio invalid or not define.
-*/
-static enum charger_type rk81x_bat_get_dc_state(struct rk81x_battery *di)
-{
-       enum charger_type charger_type;
-       u8 buf;
-       int ret;
 
-       rk81x_bat_read(di, VB_MOD_REG, &buf, 1);
-
-       /*only HW_ADP_TYPE_DC: det by rk818 is easily and will be successful*/
-        if (!rk81x_bat_support_adp_type(HW_ADP_TYPE_USB)) {
-               if ((buf & PLUG_IN_STS) != 0)
-                       charger_type = DC_CHARGER;
-               else
-                       charger_type = NO_CHARGER;
-
-               return charger_type;
-        }
-
-       /*det by gpio level*/
-       if (gpio_is_valid(di->dc_det_pin)) {
-               ret = gpio_request(di->dc_det_pin, "rk818_dc_det");
-               if (ret < 0) {
-                       pr_err("Failed to request gpio %d with ret:""%d\n",
-                              di->dc_det_pin, ret);
-                       return NO_CHARGER;
-               }
+static void rk81x_bat_set_charger_param(struct rk81x_battery *di,
+                                       enum charger_type charger_type)
+{
+       rk81x_bat_set_chrg_current(di, charger_type);
+       rk81x_bat_set_power_supply_state(di, charger_type);
 
-               gpio_direction_input(di->dc_det_pin);
-               ret = gpio_get_value(di->dc_det_pin);
-               if (ret == di->dc_det_level)
-                       charger_type = DC_CHARGER;
-               else
-                       charger_type = NO_CHARGER;
+       switch (charger_type) {
+       case NO_CHARGER:
+               power_supply_changed(&di->bat);
+               break;
+       case USB_CHARGER:
+       case AC_CHARGER:
+               power_supply_changed(&di->usb);
+               break;
+       case DC_CHARGER:
+               power_supply_changed(&di->ac);
+               break;
+       default:
+               break;
+       }
+}
 
-               gpio_free(di->dc_det_pin);
-               DBG("**********rk818 dc_det_pin=%d\n", ret);
+static enum charger_type rk81x_bat_get_dc_state(struct rk81x_battery *di)
+{
+       int ret;
+       enum charger_type charger_type = NO_CHARGER;
 
-               return charger_type;
+       if (di->fg_drv_mode == TEST_POWER_MODE) {
+               charger_type = DC_CHARGER;
+               goto out;
+       }
+       /*
+       if (di->otg_online)
+               goto out;
+       */
+       if (!gpio_is_valid(di->dc_det_pin))
+               goto out;
 
-       /*HW_ADP_TYPE_DUAL: det by rk818 and usb*/
-       } else if (rk81x_bat_support_adp_type(HW_ADP_TYPE_DUAL)) {
-               if ((buf & PLUG_IN_STS) != 0) {
-                       charger_type = dwc_otg_check_dpdm();
-                       if (charger_type == 0)
-                               charger_type = DC_CHARGER;
-                       else
-                               charger_type = NO_CHARGER;
-               }
+       ret = gpio_request(di->dc_det_pin, "rk818_dc_det");
+       if (ret < 0) {
+               pr_err("Failed to request gpio %d with ret:""%d\n",
+                      di->dc_det_pin, ret);
+               goto out;
        }
 
+       gpio_direction_input(di->dc_det_pin);
+       ret = gpio_get_value(di->dc_det_pin);
+       if (ret == di->dc_det_level)
+               charger_type = DC_CHARGER;
+       else
+               charger_type = NO_CHARGER;
+       gpio_free(di->dc_det_pin);
+out:
        return charger_type;
 }
 
-static enum charger_type rk81x_bat_get_usbac_state(struct rk81x_battery *di)
+static void rk81x_battery_dc_delay_work(struct work_struct *work)
 {
        enum charger_type charger_type;
-       int usb_id, gadget_flag;
+       struct rk81x_battery *di = container_of(work,
+                               struct rk81x_battery, dc_det_check_work.work);
+
+       charger_type = rk81x_bat_get_dc_state(di);
+
+       if (charger_type == DC_CHARGER)
+               rk81x_bat_set_charger_param(di, DC_CHARGER);
+       else/*NO_CHARGER: maybe usb charger still plugin*/
+               queue_delayed_work(di->wq,
+                                  &di->ac_usb_check_work,
+                                  msecs_to_jiffies(10));
+}
 
-       usb_id = dwc_otg_check_dpdm();
+static void rk81x_battery_acusb_delay_work(struct work_struct *work)
+{
+       u8 buf;
+       int gadget_flag, usb_id;
+       struct rk81x_battery *di = container_of(work,
+                       struct rk81x_battery, ac_usb_check_work.work);
+
+       rk81x_bat_read(di, VB_MOD_REG, &buf, 1);
+       usb_id = dwc_otg_check_dpdm(0);
        switch (usb_id) {
        case 0:
-               charger_type = NO_CHARGER;
+               if ((buf & PLUG_IN_STS) != 0)
+                       rk81x_bat_set_charger_param(di, DC_CHARGER);
+               else
+                       rk81x_bat_set_charger_param(di, NO_CHARGER);
                break;
        case 1:
        case 3:
-               charger_type = USB_CHARGER;
+               rk81x_bat_set_charger_param(di, USB_CHARGER);
                break;
        case 2:
-               charger_type = AC_CHARGER;
+               rk81x_bat_set_charger_param(di, AC_CHARGER);
                break;
        default:
-               charger_type = NO_CHARGER;
+               break;
        }
-
-       DBG("<%s>. DWC_OTG = %d\n", __func__, usb_id);
-       if (charger_type == USB_CHARGER) {
+       /*check unstanderd charger*/
+       if (usb_id == 1 || usb_id == 3) {
                gadget_flag = get_gadget_connect_flag();
-               DBG("<%s>. gadget_flag=%d, check_cnt=%d\n",
-                   __func__, gadget_flag, di->check_count);
-
                if (0 == gadget_flag) {
-                       if (++di->check_count >= 5) {
-                               charger_type = AC_CHARGER;
-                               DBG("<%s>. turn to AC_CHARGER, check_cnt=%d\n",
-                                   __func__, di->check_count);
+                       di->check_count++;
+                       if (di->check_count >= 5) {
+                               di->check_count = 0;
+                               rk81x_bat_set_charger_param(di, AC_CHARGER);
                        } else {
-                               charger_type = USB_CHARGER;
+                               queue_delayed_work(di->wq,
+                                                  &di->ac_usb_check_work,
+                                                  msecs_to_jiffies(1000));
                        }
-               } else {
-                       charger_type = USB_CHARGER;
+               } else {/*confirm: USB_CHARGER*/
                        di->check_count = 0;
                }
-       } else {
-               di->check_count = 0;
        }
-
-       return charger_type;
-}
-
-/*
- * when support HW_ADP_TYPE_DUAL, and at the moment that usb_adp
- * and dc_adp are plugined in together, the dc_apt has high priority.
- * so we check dc_apt first and return rigth away if it's found.
- */
-static enum charger_type rk81x_bat_get_adp_type(struct rk81x_battery *di)
-{
-       u8 buf;
-       enum charger_type charger_type = NO_CHARGER;
-
-       /*check by ic hardware: this check make check work safer*/
-       rk81x_bat_read(di, VB_MOD_REG, &buf, 1);
-       if ((buf & PLUG_IN_STS) == 0)
-               return NO_CHARGER;
-
-       /*check DC first*/
-       if (rk81x_bat_support_adp_type(HW_ADP_TYPE_DC)) {
-               charger_type = rk81x_bat_get_dc_state(di);
-               if (charger_type == DC_CHARGER)
-                       return charger_type;
-       }
-
-       /*HW_ADP_TYPE_USB*/
-       charger_type = rk81x_bat_get_usbac_state(di);
-
-       return charger_type;
-}
-
-static void rk81x_bat_status_check(struct rk81x_battery *di)
-{
-       static enum charger_type old_charger_type = DUAL_CHARGER;
-       enum charger_type  charger_type;
-
-       charger_type = rk81x_bat_get_adp_type(di);
-       if (charger_type == old_charger_type)
-               return;
-       rk81x_bat_set_chrg_current(di, charger_type);
-       rk81x_bat_set_power_supply_state(di, charger_type);
-       old_charger_type = charger_type;
 }
 #endif
 
@@ -2333,21 +2312,6 @@ static void rk81x_bat_charger_init(struct  rk81x_battery *di)
        rk81x_bat_write(di, GGCON, &ggcon, 1);
 }
 
-void rk81x_charge_disable_open_otg(struct rk81x_battery *di)
-{
-       int value = di->charge_otg;
-
-       if (value) {
-               DBG("charge disable, enable OTG.\n");
-               rk818_set_bits(di->rk818, CHRG_CTRL_REG1, 1 << 7, 0 << 7);
-               rk818_set_bits(di->rk818, 0x23, 1 << 7, 1 << 7);
-       } else {
-               DBG("charge enable, disable OTG.\n");
-               rk818_set_bits(di->rk818, 0x23, 1 << 7, 0 << 7);
-               rk818_set_bits(di->rk818, CHRG_CTRL_REG1, 1 << 7, 1 << 7);
-       }
-}
-
 static void rk81x_bat_fg_init(struct rk81x_battery *di)
 {
        u8 pcb_offset;
@@ -2958,7 +2922,7 @@ static void rk81x_bat_finish_chrg(struct rk81x_battery *di)
                temp = di->fcc * 3600 / 100;
                if (di->ac_online)
                        soc_time = temp / DSOC_CHRG_FINISH_CURR;
-               else if (di->usb_online)
+               else
                        soc_time = temp / 450;
 
                plus_soc = sec_finish / soc_time;
@@ -3370,7 +3334,7 @@ static int  rk81x_bat_sleep_dischrg(struct rk81x_battery *di)
 
 static int rk81x_bat_sleep_chrg(struct rk81x_battery *di)
 {
-       int sleep_soc;
+       int sleep_soc = 0;
        unsigned long sleep_sec;
 
        sleep_sec = di->suspend_time_sum;
@@ -3495,7 +3459,6 @@ static void rk81x_bat_check_reboot(struct rk81x_battery *di)
 {
        u8 rsoc = di->rsoc;
        u8 dsoc = di->dsoc;
-       u8 status = di->psy_status;
        u8 cnt;
        int unit_time;
        int smooth_time;
@@ -3510,8 +3473,7 @@ static void rk81x_bat_check_reboot(struct rk81x_battery *di)
            __func__, cnt, unit_time, smooth_time,
            BASE_TO_SEC(di->power_on_base), dsoc, rsoc);
 
-       if ((status == POWER_SUPPLY_STATUS_CHARGING) ||
-           (status == POWER_SUPPLY_STATUS_FULL && abs(di->current_avg) < 5)) {
+       if (di->current_avg >= 0 || di->chrg_status == CHARGE_FINISH) {
                DBG("chrg, sm:%d, aim:%d\n", smooth_time, unit_time * 3 / 5);
                if ((dsoc < rsoc - 1) && (smooth_time > unit_time * 3 / 5)) {
                        cnt = 0;
@@ -3520,10 +3482,9 @@ static void rk81x_bat_check_reboot(struct rk81x_battery *di)
                                dsoc = 100;
                        rk81x_bat_save_dsoc(di, dsoc);
                }
-       } else {/*status == POWER_SUPPLY_STATUS_DISCHARGING*/
-
-               DBG("dischrg, sm:%d, aim:%d\n", smooth_time, unit_time * 3/5);
-               if ((dsoc > rsoc) && (smooth_time > unit_time * 3/5)) {
+       } else {
+               DBG("dischrg, sm:%d, aim:%d\n", smooth_time, unit_time * 3 / 5);
+               if ((dsoc > rsoc) && (smooth_time > unit_time * 3 / 5)) {
                        cnt = 0;
                        dsoc--;
                        if (dsoc <= 0)
@@ -3587,9 +3548,6 @@ static void rk81x_bat_update_info(struct rk81x_battery *di)
        rk81x_bat_update_calib_param(di);
        if (di->chrg_status == CC_OR_CV)
                di->enter_finish = true;
-#if defined(CONFIG_ARCH_ROCKCHIP)
-       rk81x_bat_status_check(di);/* ac_online, usb_online, status*/
-#endif
 
        if (!rk81x_chrg_online(di) && di->s2r)
                return;
@@ -3719,13 +3677,41 @@ static void rk81x_battery_work(struct work_struct *work)
                           msecs_to_jiffies(ms));
 }
 
-static void rk81x_battery_charge_check_work(struct work_struct *work)
+#if defined(CONFIG_ARCH_ROCKCHIP)
+static void rk81x_battery_otg_delay_work(struct work_struct *work)
 {
        struct rk81x_battery *di = container_of(work,
-                       struct rk81x_battery, charge_check_work.work);
+                       struct rk81x_battery, otg_check_work.work);
+
+       enum bc_port_type event = di->charge_otg;
+
+       /* do not touch CHRG_CTRL_REG1[7]: CHRG_EN, hardware can
+        * recognize otg plugin and will auto ajust this bit
+        */
+       switch (event) {
+       case USB_OTG_POWER_ON:
+               dev_info(di->dev, "charge disable, otg enable\n");
+               di->otg_online = ONLINE;
+               /*rk81x_bat_set_charger_param(di, NO_CHARGER);*/
+               rk81x_bat_set_bit(di, NT_STS_MSK_REG2, PLUG_IN_INT);
+               rk81x_bat_set_bit(di, NT_STS_MSK_REG2, PLUG_OUT_INT);
+               rk818_set_bits(di->rk818, DCDC_EN_REG, OTG_EN_MASK, OTG_EN);
+               break;
 
-       DBG("rk81x_battery_charge_check_work\n");
-       rk81x_charge_disable_open_otg(di);
+       case USB_OTG_POWER_OFF:
+               dev_info(di->dev, "charge enable, otg disable\n");
+               di->otg_online = OFFLINE;
+               rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, PLUG_IN_INT);
+               rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, PLUG_OUT_INT);
+               rk818_set_bits(di->rk818, DCDC_EN_REG, OTG_EN_MASK, OTG_DIS);
+               /*maybe dc still plugin*/
+               queue_delayed_work(di->wq, &di->dc_det_check_work,
+                                  msecs_to_jiffies(10));
+               break;
+
+       default:
+               break;
+       }
 }
 
 static BLOCKING_NOTIFIER_HEAD(battery_chain_head);
@@ -3749,49 +3735,50 @@ int battery_notifier_call_chain(unsigned long val)
 }
 EXPORT_SYMBOL_GPL(battery_notifier_call_chain);
 
-static void poweron_lowerpoer_handle(struct rk81x_battery *di)
-{
-#ifdef CONFIG_LOGO_LOWERPOWER_WARNING
-       if ((di->dsoc <= 2) &&
-           (di->psy_status == POWER_SUPPLY_STATUS_DISCHARGING)) {
-               mdelay(1500);
-               /* kernel_power_off(); */
-       }
-#endif
-}
-
-static int rk81x_bat_notifier_call(struct notifier_block *nb,
-                                  unsigned long event, void *data)
+static int rk81x_bat_usb_notifier_call(struct notifier_block *nb,
+                                      unsigned long event, void *data)
 {
+       enum charger_type charger_type;
        struct rk81x_battery *di =
            container_of(nb, struct rk81x_battery, battery_nb);
 
+       if (di->fg_drv_mode == TEST_POWER_MODE)
+               return NOTIFY_OK;
+
+       /*if dc is pluging, ignore usb*/
+       charger_type = rk81x_bat_get_dc_state(di);
+       if ((charger_type == DC_CHARGER) &&
+           (event != USB_OTG_POWER_OFF) &&
+           (event != USB_OTG_POWER_ON))
+               return NOTIFY_OK;
+
        switch (event) {
-       case 0:
-               DBG(" CHARGE enable\n");
-               di->charge_otg = 0;
-               rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, PLUG_IN_INT);
-               rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, PLUG_OUT_INT);
-               queue_delayed_work(di->wq, &di->charge_check_work,
-                                  msecs_to_jiffies(50));
+       case USB_BC_TYPE_DISCNT:/*maybe dc still plugin*/
+               queue_delayed_work(di->wq, &di->dc_det_check_work,
+                                  msecs_to_jiffies(10));
                break;
-       case 1:
-               di->charge_otg  = 1;
-               rk81x_bat_set_bit(di, NT_STS_MSK_REG2, PLUG_IN_INT);
-               rk81x_bat_set_bit(di, NT_STS_MSK_REG2, PLUG_OUT_INT);
-               queue_delayed_work(di->wq, &di->charge_check_work,
-                                  msecs_to_jiffies(50));
-               DBG("charge disable OTG enable\n");
+       case USB_BC_TYPE_SDP:
+       case USB_BC_TYPE_CDP:/*nonstandard charger*/
+       case USB_BC_TYPE_DCP:/*standard charger*/
+               queue_delayed_work(di->wq, &di->ac_usb_check_work,
+                                  msecs_to_jiffies(10));
                break;
-       case 2:
-               poweron_lowerpoer_handle(di);
+       case USB_OTG_POWER_ON:/*otg on*/
+               di->charge_otg  = USB_OTG_POWER_ON;
+               queue_delayed_work(di->wq, &di->otg_check_work,
+                                  msecs_to_jiffies(10));
+               break;
+       case USB_OTG_POWER_OFF:/*otg off*/
+               di->charge_otg = USB_OTG_POWER_OFF;
+               queue_delayed_work(di->wq, &di->otg_check_work,
+                                  msecs_to_jiffies(10));
                break;
        default:
                return NOTIFY_OK;
        }
        return NOTIFY_OK;
 }
-
+#endif
 static irqreturn_t rk81x_vbat_lo_irq(int irq, void *bat)
 {
        pr_info("\n------- %s:lower power warning!\n", __func__);
@@ -3827,6 +3814,11 @@ static irqreturn_t rk81x_vbat_charge_ok(int irq, void  *bat)
 
 static irqreturn_t rk81x_vbat_dc_det(int irq, void *bat)
 {
+       struct rk81x_battery *di = (struct rk81x_battery *)bat;
+
+       queue_delayed_work(di->wq,
+                          &di->dc_det_check_work,
+                          msecs_to_jiffies(10));
        rk_send_wakeup_key();
 
        return IRQ_HANDLED;
@@ -3896,8 +3888,13 @@ static void rk81x_bat_irq_init(struct rk81x_battery *di)
 static void rk81x_bat_info_init(struct rk81x_battery *di,
                                struct rk818 *chip)
 {
+       u8 val;
        unsigned long time_base = get_runtime_sec();
 
+       rk81x_bat_read(di, RK818_VB_MON_REG, &val, 1);
+       if (val & PLUG_IN_STS)
+               rk81x_bat_set_power_supply_state(di, USB_CHARGER);
+
        di->cell.config = di->pdata->cell_cfg;
        di->design_capacity = di->pdata->cell_cfg->design_capacity;
        di->qmax = di->pdata->cell_cfg->design_qmax;
@@ -3924,19 +3921,29 @@ static void rk81x_bat_dc_det_init(struct rk81x_battery *di,
        int ret;
 
        di->dc_det_pin = of_get_named_gpio_flags(np, "dc_det_gpio", 0, &flags);
-       if (di->dc_det_pin == -EPROBE_DEFER)
+       if (di->dc_det_pin == -EPROBE_DEFER) {
                dev_err(dev, "dc_det_gpio error\n");
-       if (gpio_is_valid(di->dc_det_pin))
+               return;
+       }
+
+       if (gpio_is_valid(di->dc_det_pin)) {
                di->dc_det_level = (flags & OF_GPIO_ACTIVE_LOW) ?
-                                       RK818_DC_IN : RK818_DC_OUT;
-       di->dc_det_irq = gpio_to_irq(di->dc_det_pin);
-       ret = request_irq(di->dc_det_irq, rk81x_vbat_dc_det,
-                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                         "rk81x_dc_det", NULL);
+                                               RK818_DC_IN : RK818_DC_OUT;
+               di->dc_det_irq = gpio_to_irq(di->dc_det_pin);
+
+               ret = request_irq(di->dc_det_irq, rk81x_vbat_dc_det,
+                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                 "rk81x_dc_det", di);
+               if (ret != 0) {
+                       dev_err(di->dev, "rk818_dc_det_irq request failed!\n");
+                       goto err;
+               }
+               enable_irq_wake(di->dc_det_irq);
+       }
 
-       if (ret != 0)
-               dev_err(di->dev, "rk818_dc_det_irq request failed!\n");
-       enable_irq_wake(di->dc_det_irq);
+       return;
+err:
+       gpio_free(di->dc_det_pin);
 }
 
 static int rk81x_bat_get_suspend_sec(struct rk81x_battery *di)
@@ -4097,8 +4104,8 @@ static int rk81x_bat_parse_dt(struct rk81x_battery *di)
                support_usb_adp = 1;
        }
 
-       if (support_dc_adp)
-               rk81x_bat_dc_det_init(di, np);
+       /*if (support_dc_adp)*/
+       rk81x_bat_dc_det_init(di, np);
 
        cell_cfg->ocv = ocv_cfg;
        pdata->cell_cfg = cell_cfg;
@@ -4196,11 +4203,20 @@ static int rk81x_battery_probe(struct platform_device *pdev)
        queue_delayed_work(di->wq, &di->battery_monitor_work,
                           msecs_to_jiffies(TIMER_MS_COUNTS * 5));
 
-       INIT_DELAYED_WORK(&di->charge_check_work,
-                         rk81x_battery_charge_check_work);
-       di->battery_nb.notifier_call = rk81x_bat_notifier_call;
-       register_battery_notifier(&di->battery_nb);
+#if defined(CONFIG_ARCH_ROCKCHIP)
+       INIT_DELAYED_WORK(&di->otg_check_work,
+                         rk81x_battery_otg_delay_work);
+       INIT_DELAYED_WORK(&di->ac_usb_check_work,
+                         rk81x_battery_acusb_delay_work);
+       INIT_DELAYED_WORK(&di->dc_det_check_work,
+                         rk81x_battery_dc_delay_work);
+       /*power on check*/
+       queue_delayed_work(di->wq, &di->dc_det_check_work,
+                          msecs_to_jiffies(TIMER_MS_COUNTS * 5));
 
+       di->battery_nb.notifier_call = rk81x_bat_usb_notifier_call;
+       rk_bc_detect_notifier_register(&di->battery_nb, &di->charge_otg);
+#endif
        dev_info(di->dev, "battery driver version %s\n", DRIVER_VERSION);
 
        return ret;
@@ -4211,8 +4227,10 @@ static int rk81x_battery_suspend(struct platform_device *dev,
 {
        struct rk81x_battery *di = platform_get_drvdata(dev);
 
-       di->slp_psy_status = rk81x_chrg_online(di);
+       /*while otg and dc both plugin*/
+       rk81x_bat_set_bit(di, NT_STS_MSK_REG2, CHRG_CVTLMT_INT);
 
+       di->slp_psy_status = rk81x_chrg_online(di);
        di->chrg_status = rk81x_bat_get_chrg_status(di);
        di->slp_chrg_status = rk81x_bat_get_chrg_status(di);
        di->suspend_charge_current = rk81x_bat_get_avg_current(di);
@@ -4249,11 +4267,21 @@ static int rk81x_battery_resume(struct platform_device *dev)
        int delta_time;
        int time_step;
        int delta_soc;
+       int vol;
+
+       /*while otg and dc both plugin*/
+       rk81x_bat_clr_bit(di, NT_STS_MSK_REG2, CHRG_CVTLMT_INT);
 
        di->discharge_smooth_status = true;
        di->charge_smooth_status = true;
        di->s2r = 1;
-       di->voltage  = rk81x_bat_get_vol(di);
+       vol  = rk81x_bat_get_vol(di);
+       if (vol < INVALID_VOL_THRESD) {
+               dev_err(di->dev, "invalid voltage :%d", vol);
+               vol = di->voltage;
+               dbg_enable = 1;
+       }
+       di->voltage = vol;
        di->current_avg = rk81x_bat_get_avg_current(di);
        di->relax_voltage = rk81x_bat_get_relax_vol(di);
        di->est_ocv_vol = rk81x_bat_est_ocv_vol(di);
@@ -4287,6 +4315,7 @@ static int rk81x_battery_resume(struct platform_device *dev)
        if ((!rk81x_chrg_online(di) && di->voltage <= pwroff_thresd) ||
            rk81x_chrg_online(di))
                wake_lock_timeout(&di->resume_wake_lock, 5 * HZ);
+
        /*
         * do not modify the g_base_sec
         */
@@ -4311,6 +4340,8 @@ static void rk81x_battery_shutdown(struct platform_device *dev)
        struct rk81x_battery *di = platform_get_drvdata(dev);
 
        cancel_delayed_work_sync(&di->battery_monitor_work);
+       rk_bc_detect_notifier_unregister(&di->battery_nb);
+
        if (BASE_TO_MIN(di->power_on_base) <= REBOOT_INTER_MIN)
                rk81x_bat_check_reboot(di);
        else