Merge branch develop-3.10 into develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg_310 / usbdev_bc.c
index d08d894336c35988f2e9a2f064ffbf6532b38db8..0cad8b970d0146ff5a05cc051ea28e10436e5cc6 100755 (executable)
 
 #include "usbdev_rk.h"
 
-/****** GET and SET REGISTER FIELDS IN GRF UOC ******/
+char *bc_string[USB_BC_TYPE_MAX] = {"DISCONNECT",
+                                   "Stander Downstream Port",
+                                   "Dedicated Charging Port",
+                                   "Charging Downstream Port",
+                                   "UNKNOW"};
 
+/****** GET and SET REGISTER FIELDS IN GRF UOC ******/
 #define BC_GET(x) grf_uoc_get_field(&pBC_UOC_FIELDS[x])
-#define BC_SET(x,v) grf_uoc_set_field(&pBC_UOC_FIELDS[x], v)
+#define BC_SET(x, v) grf_uoc_set_field(&pBC_UOC_FIELDS[x], v)
+
+uoc_field_t *pBC_UOC_FIELDS;
+static void *pGRF_BASE;
+static struct mutex bc_mutex;
 
-uoc_field_t *pBC_UOC_FIELDS = NULL;
-static void *pGRF_BASE = NULL;
-int rk_usb_charger_status = USB_BC_TYPE_DISCNT;
+static enum bc_port_type usb_charger_status = USB_BC_TYPE_DISCNT;
 
 /****** GET REGISTER FIELD INFO FROM Device Tree ******/
 
-inline static void *get_grf_base(struct device_node *np)
+static inline void *get_grf_base(struct device_node *np)
 {
-    void *grf_base = of_iomap(of_get_parent(np), 0);
-    if(of_machine_is_compatible("rockchip,rk3188"))
-        return (grf_base - 0xac);
-    else if(of_machine_is_compatible("rockchip,rk3288"))
-        return (grf_base - 0x284);
-}
+       void *grf_base = of_iomap(of_get_parent(np), 0);
+
+       if (of_machine_is_compatible("rockchip,rk3188"))
+               grf_base -= 0xac;
+       else if (of_machine_is_compatible("rockchip,rk3288"))
+               grf_base -= 0x284;
 
+       return grf_base;
+}
 
 void grf_uoc_set_field(uoc_field_t *field, u32 value)
 {
-    if(!uoc_field_valid(field))
-        return ;
-    grf_uoc_set(pGRF_BASE, field->b.offset, field->b.bitmap, field->b.mask, value);
+       if (!uoc_field_valid(field))
+               return;
+       grf_uoc_set(pGRF_BASE, field->b.offset, field->b.bitmap, field->b.mask,
+                   value);
 }
 
 u32 grf_uoc_get_field(uoc_field_t *field)
 {
-    return grf_uoc_get(pGRF_BASE, field->b.offset, field->b.bitmap, field->b.mask);
+       return grf_uoc_get(pGRF_BASE, field->b.offset, field->b.bitmap,
+                          field->b.mask);
 }
 
-inline static int uoc_init_field(struct device_node *np, const char* name, uoc_field_t *f)
+static inline int uoc_init_field(struct device_node *np, const char *name,
+                                uoc_field_t *f)
 {
-    of_property_read_u32_array(np, name, f->array, 3);
-    //printk("usb battery charger detect: uoc_init_field: 0x%08x %d %d \n",f->b.offset,f->b.bitmap,f->b.mask);
-    return 0;
+       of_property_read_u32_array(np, name, f->array, 3);
+       /* printk("usb battery charger detect: uoc_init_field: 0x%08x %d %d \n",
+        *        f->b.offset,f->b.bitmap,f->b.mask);*/
+       return 0;
 }
-inline static void uoc_init_synop(struct device_node *np)
+
+static inline void uoc_init_synop(struct device_node *np)
 {
-    pBC_UOC_FIELDS = (uoc_field_t *)kzalloc(SYNOP_BC_MAX * sizeof(uoc_field_t), GFP_ATOMIC);
-
-    uoc_init_field(np, "rk_usb,bvalid", &pBC_UOC_FIELDS[SYNOP_BC_BVALID]);
-    uoc_init_field(np, "rk_usb,dcdenb", &pBC_UOC_FIELDS[SYNOP_BC_DCDENB]);
-    uoc_init_field(np, "rk_usb,vdatsrcenb", &pBC_UOC_FIELDS[SYNOP_BC_VDATSRCENB]);
-    uoc_init_field(np, "rk_usb,vdatdetenb", &pBC_UOC_FIELDS[SYNOP_BC_VDATDETENB]);
-    uoc_init_field(np, "rk_usb,chrgsel",  &pBC_UOC_FIELDS[SYNOP_BC_CHRGSEL]);
-    uoc_init_field(np, "rk_usb,chgdet",   &pBC_UOC_FIELDS[SYNOP_BC_CHGDET]);
+       pBC_UOC_FIELDS =
+           (uoc_field_t *) kzalloc(SYNOP_BC_MAX * sizeof(uoc_field_t),
+                                   GFP_ATOMIC);
+
+       uoc_init_field(np, "rk_usb,bvalid", &pBC_UOC_FIELDS[SYNOP_BC_BVALID]);
+       uoc_init_field(np, "rk_usb,iddig", &pBC_UOC_FIELDS[SYNOP_BC_IDDIG]);
+       uoc_init_field(np, "rk_usb,dcdenb", &pBC_UOC_FIELDS[SYNOP_BC_DCDENB]);
+       uoc_init_field(np, "rk_usb,vdatsrcenb",
+                      &pBC_UOC_FIELDS[SYNOP_BC_VDATSRCENB]);
+       uoc_init_field(np, "rk_usb,vdatdetenb",
+                      &pBC_UOC_FIELDS[SYNOP_BC_VDATDETENB]);
+       uoc_init_field(np, "rk_usb,chrgsel", &pBC_UOC_FIELDS[SYNOP_BC_CHRGSEL]);
+       uoc_init_field(np, "rk_usb,chgdet", &pBC_UOC_FIELDS[SYNOP_BC_CHGDET]);
+       uoc_init_field(np, "rk_usb,fsvplus", &pBC_UOC_FIELDS[SYNOP_BC_FSVPLUS]);
+       uoc_init_field(np, "rk_usb,fsvminus",
+                      &pBC_UOC_FIELDS[SYNOP_BC_FSVMINUS]);
 }
 
-inline static void uoc_init_rk(struct device_node *np)
+static inline void uoc_init_rk(struct device_node *np)
 {
-    pBC_UOC_FIELDS = (uoc_field_t *)kzalloc(RK_BC_MAX * sizeof(uoc_field_t), GFP_ATOMIC);
-
-    uoc_init_field(np, "rk_usb,bvalid",   &pBC_UOC_FIELDS[RK_BC_BVALID]);
-    uoc_init_field(np, "rk_usb,line",     &pBC_UOC_FIELDS[RK_BC_LINESTATE]);
-    uoc_init_field(np, "rk_usb,softctrl", &pBC_UOC_FIELDS[RK_BC_SOFTCTRL]);
-    uoc_init_field(np, "rk_usb,opmode",   &pBC_UOC_FIELDS[RK_BC_OPMODE]);
-    uoc_init_field(np, "rk_usb,xcvrsel",  &pBC_UOC_FIELDS[RK_BC_XCVRSELECT]);
-    uoc_init_field(np, "rk_usb,termsel",  &pBC_UOC_FIELDS[RK_BC_TERMSELECT]);
+       pBC_UOC_FIELDS =
+           (uoc_field_t *) kzalloc(RK_BC_MAX * sizeof(uoc_field_t),
+                                   GFP_ATOMIC);
+
+       uoc_init_field(np, "rk_usb,bvalid", &pBC_UOC_FIELDS[RK_BC_BVALID]);
+       uoc_init_field(np, "rk_usb,iddig", &pBC_UOC_FIELDS[RK_BC_IDDIG]);
+       uoc_init_field(np, "rk_usb,line", &pBC_UOC_FIELDS[RK_BC_LINESTATE]);
+       uoc_init_field(np, "rk_usb,softctrl", &pBC_UOC_FIELDS[RK_BC_SOFTCTRL]);
+       uoc_init_field(np, "rk_usb,opmode", &pBC_UOC_FIELDS[RK_BC_OPMODE]);
+       uoc_init_field(np, "rk_usb,xcvrsel", &pBC_UOC_FIELDS[RK_BC_XCVRSELECT]);
+       uoc_init_field(np, "rk_usb,termsel", &pBC_UOC_FIELDS[RK_BC_TERMSELECT]);
 }
 
-inline static void uoc_init_inno(struct device_node *np)
+static inline void uoc_init_inno(struct device_node *np)
 {
-    ;
+       pBC_UOC_FIELDS = (uoc_field_t *)
+                        kzalloc(INNO_BC_MAX * sizeof(uoc_field_t), GFP_ATOMIC);
+
+       uoc_init_field(np, "rk_usb,bvalid",
+                          &pBC_UOC_FIELDS[INNO_BC_BVALID]);
+       uoc_init_field(np, "rk_usb,iddig",
+                          &pBC_UOC_FIELDS[INNO_BC_IDDIG]);
+       uoc_init_field(np, "rk_usb,vdmsrcen",
+                          &pBC_UOC_FIELDS[INNO_BC_VDMSRCEN]);
+       uoc_init_field(np, "rk_usb,vdpsrcen",
+                          &pBC_UOC_FIELDS[INNO_BC_VDPSRCEN]);
+       uoc_init_field(np, "rk_usb,rdmpden",
+                          &pBC_UOC_FIELDS[INNO_BC_RDMPDEN]);
+       uoc_init_field(np, "rk_usb,idpsrcen",
+                          &pBC_UOC_FIELDS[INNO_BC_IDPSRCEN]);
+       uoc_init_field(np, "rk_usb,idmsinken",
+                          &pBC_UOC_FIELDS[INNO_BC_IDMSINKEN]);
+       uoc_init_field(np, "rk_usb,idpsinken",
+                          &pBC_UOC_FIELDS[INNO_BC_IDPSINKEN]);
+       uoc_init_field(np, "rk_usb,dpattach",
+                          &pBC_UOC_FIELDS[INNO_BC_DPATTACH]);
+       uoc_init_field(np, "rk_usb,cpdet",
+                          &pBC_UOC_FIELDS[INNO_BC_CPDET]);
+       uoc_init_field(np, "rk_usb,dcpattach",
+                          &pBC_UOC_FIELDS[INNO_BC_DCPATTACH]);
 }
 
 /****** BATTERY CHARGER DETECT FUNCTIONS ******/
+bool is_connected(void)
+{
+       if (!pGRF_BASE)
+               return false;
+       if (BC_GET(BC_BVALID) && BC_GET(BC_IDDIG))
+               return true;
+       return false;
+}
 
-int usb_battery_charger_detect_rk(bool wait)
+enum bc_port_type usb_battery_charger_detect_rk(bool wait)
 {
 
-    int port_type = USB_BC_TYPE_DISCNT;
-    
-    if(BC_GET(RK_BC_BVALID))
-    {   
-        mdelay(10);
-        BC_SET(RK_BC_SOFTCTRL, 1);
-        BC_SET(RK_BC_OPMODE, 0);
-        BC_SET(RK_BC_XCVRSELECT, 1);
-        BC_SET(RK_BC_TERMSELECT, 1);
-        
-        mdelay(1);
-        switch (BC_GET(RK_BC_LINESTATE))
-        {
-            case 1:
-                port_type = USB_BC_TYPE_SDP;
-                break;
-                
-            case 3:
-                port_type = USB_BC_TYPE_DCP;
-                break;
-                
-            default:
-                port_type = USB_BC_TYPE_SDP;
-                //printk("%s linestate = %d bad status\n", __func__, BC_GET(RK_BC_LINESTATE));
-        }
-        
-    }
-    BC_SET(RK_BC_SOFTCTRL, 0);    
-    
-    //printk("%s , battery_charger_detect %d\n", __func__, port_type);
-    return port_type;
+       enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
+
+       if (BC_GET(RK_BC_BVALID) &&
+           BC_GET(RK_BC_IDDIG)) {
+               mdelay(10);
+               BC_SET(RK_BC_SOFTCTRL, 1);
+               BC_SET(RK_BC_OPMODE, 0);
+               BC_SET(RK_BC_XCVRSELECT, 1);
+               BC_SET(RK_BC_TERMSELECT, 1);
+
+               mdelay(1);
+               switch (BC_GET(RK_BC_LINESTATE)) {
+               case 1:
+                       port_type = USB_BC_TYPE_SDP;
+                       break;
+
+               case 3:
+                       port_type = USB_BC_TYPE_DCP;
+                       break;
+
+               default:
+                       port_type = USB_BC_TYPE_SDP;
+                       /* printk("%s linestate = %d bad status\n",
+                        *        __func__, BC_GET(RK_BC_LINESTATE)); */
+               }
+
+       }
+       BC_SET(RK_BC_SOFTCTRL, 0);
+
+       /* printk("%s , battery_charger_detect %d\n",
+        *        __func__, port_type); */
+       return port_type;
 }
 
-int usb_battery_charger_detect_inno(bool wait)
+enum bc_port_type usb_battery_charger_detect_inno(bool wait)
 {
+       enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
+       int dcd_state = DCD_POSITIVE;
+       int timeout = 0, i = 0;
+
+       /* VBUS Valid detect */
+       if (BC_GET(INNO_BC_BVALID) &&
+               BC_GET(INNO_BC_IDDIG)) {
+               if (wait) {
+                       /* Do DCD */
+                       dcd_state = DCD_TIMEOUT;
+                       BC_SET(INNO_BC_RDMPDEN, 1);
+                       BC_SET(INNO_BC_IDPSRCEN, 1);
+                       timeout = T_DCD_TIMEOUT;
+                       while (timeout--) {
+                               if (BC_GET(INNO_BC_DPATTACH))
+                                       i++;
+                               if (i >= 3) {
+                                       /* It is a filter here to assure data
+                                        * lines contacted for at least 3ms */
+                                       dcd_state = DCD_POSITIVE;
+                                       break;
+                               }
+                               mdelay(1);
+                       }
+                       BC_SET(INNO_BC_RDMPDEN, 0);
+                       BC_SET(INNO_BC_IDPSRCEN, 0);
+               } else {
+                       dcd_state = DCD_PASSED;
+               }
+               if (dcd_state == DCD_TIMEOUT) {
+                       port_type = USB_BC_TYPE_UNKNOW;
+                       goto out;
+               }
+
+               /* Turn on VDPSRC */
+               /* Primary Detection */
+               BC_SET(INNO_BC_VDPSRCEN, 1);
+               BC_SET(INNO_BC_IDMSINKEN, 1);
+               udelay(T_BC_CHGDET_VALID);
+
+               /* SDP and CDP/DCP distinguish */
+               if (BC_GET(INNO_BC_CPDET)) {
+                       /* Turn off VDPSRC */
+                       BC_SET(INNO_BC_VDPSRCEN, 0);
+                       BC_SET(INNO_BC_IDMSINKEN, 0);
+
+                       udelay(T_BC_CHGDET_VALID);
+
+                       /* Turn on VDMSRC */
+                       BC_SET(INNO_BC_VDMSRCEN, 1);
+                       BC_SET(INNO_BC_IDPSINKEN, 1);
+                       udelay(T_BC_CHGDET_VALID);
+                       if (BC_GET(INNO_BC_DCPATTACH))
+                               port_type = USB_BC_TYPE_DCP;
+                       else
+                               port_type = USB_BC_TYPE_CDP;
+               } else {
+                       port_type = USB_BC_TYPE_SDP;
+               }
+
+               BC_SET(INNO_BC_VDPSRCEN, 0);
+               BC_SET(INNO_BC_IDMSINKEN, 0);
+               BC_SET(INNO_BC_VDMSRCEN, 0);
+               BC_SET(INNO_BC_IDPSINKEN, 0);
+
+       }
+out:
+       /*
+       printk("%s, Charger type %s, %s DCD, dcd_state = %d\n", __func__,
+              bc_string[port_type], wait ? "wait" : "pass", dcd_state);
+       */
+       return port_type;
 
-    return -1;
 }
 
 /* When do BC detect PCD pull-up register should be disabled  */
-//wait wait for dcd timeout 900ms
-int usb_battery_charger_detect_synop(bool wait)
+/* wait wait for dcd timeout 900ms */
+enum bc_port_type usb_battery_charger_detect_synop(bool wait)
 {
-    int port_type = USB_BC_TYPE_DISCNT;
-    int timeout;
-    //VBUS Valid detect
-
-    if(BC_GET(SYNOP_BC_BVALID)) {
-        //todo : add DCD !
-        mdelay(wait ? T_DCD_TIMEOUT : 1);
-
-        /* Turn on VDPSRC */
-        //Primary Detection
-        BC_SET(SYNOP_BC_VDATSRCENB, 1);
-        BC_SET(SYNOP_BC_VDATDETENB, 1);
-        BC_SET(SYNOP_BC_CHRGSEL, 0);
-
-        timeout = T_BC_WAIT_CHGDET;
-        while(timeout--) {
-            if(BC_GET(SYNOP_BC_CHGDET))
-                break;
-            mdelay(1);
-        }
-
-        /* SDP and CDP/DCP distinguish */
-        if(BC_GET(SYNOP_BC_CHGDET)) {
-            /* Turn off VDPSRC */
-            BC_SET(SYNOP_BC_VDATSRCENB, 0);
-            BC_SET(SYNOP_BC_VDATDETENB, 0);
-
-            timeout = T_BC_SRC_OFF;
-            while(timeout--) {
-                if(!BC_GET(SYNOP_BC_CHGDET))
-                    break;
-                mdelay(1);
-            };
-
-            /* Turn on VDMSRC */
-            BC_SET(SYNOP_BC_VDATSRCENB, 1);
-            BC_SET(SYNOP_BC_VDATDETENB, 1);
-            BC_SET(SYNOP_BC_CHRGSEL, 1);
-
-            if(BC_GET(SYNOP_BC_CHGDET))
-                port_type = USB_BC_TYPE_DCP;
-            else
-                port_type = USB_BC_TYPE_CDP;
-        } else {
-            port_type = USB_BC_TYPE_SDP;
-        }
-        BC_SET(SYNOP_BC_VDATSRCENB, 0);
-        BC_SET(SYNOP_BC_VDATDETENB, 0);
-        BC_SET(SYNOP_BC_CHRGSEL, 0);
-
-    }
-
-    //printk("%s , battery_charger_detect %d\n", __func__, port_type);
-    return port_type;
+       enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
+       int dcd_state = DCD_POSITIVE;
+       int timeout = 0, i = 0;
+
+       /* VBUS Valid detect */
+       if (BC_GET(SYNOP_BC_BVALID) &&
+           BC_GET(SYNOP_BC_IDDIG)) {
+               if (wait) {
+                       /* Do DCD */
+                       dcd_state = DCD_TIMEOUT;
+                       BC_SET(SYNOP_BC_DCDENB, 1);
+                       timeout = T_DCD_TIMEOUT;
+                       while (timeout--) {
+                               if (!BC_GET(SYNOP_BC_FSVPLUS))
+                                       i++;
+                               if (i >= 3) {
+                                       /* It is a filter here to assure data
+                                        * lines contacted for at least 3ms */
+                                       dcd_state = DCD_POSITIVE;
+                                       break;
+                               }
+
+                               mdelay(1);
+                       }
+                       BC_SET(SYNOP_BC_DCDENB, 0);
+               } else {
+                       dcd_state = DCD_PASSED;
+               }
+               if (dcd_state == DCD_TIMEOUT) {
+                       port_type = USB_BC_TYPE_UNKNOW;
+                       goto out;
+               }
+
+               /* Turn on VDPSRC */
+               /* Primary Detection */
+               BC_SET(SYNOP_BC_VDATSRCENB, 1);
+               BC_SET(SYNOP_BC_VDATDETENB, 1);
+               BC_SET(SYNOP_BC_CHRGSEL, 0);
+
+               udelay(T_BC_CHGDET_VALID);
+
+               /* SDP and CDP/DCP distinguish */
+               if (BC_GET(SYNOP_BC_CHGDET)) {
+                       /* Turn off VDPSRC */
+                       BC_SET(SYNOP_BC_VDATSRCENB, 0);
+                       BC_SET(SYNOP_BC_VDATDETENB, 0);
+
+                       udelay(T_BC_CHGDET_VALID);
+
+                       /* Turn on VDMSRC */
+                       BC_SET(SYNOP_BC_VDATSRCENB, 1);
+                       BC_SET(SYNOP_BC_VDATDETENB, 1);
+                       BC_SET(SYNOP_BC_CHRGSEL, 1);
+                       udelay(T_BC_CHGDET_VALID);
+                       if (BC_GET(SYNOP_BC_CHGDET))
+                               port_type = USB_BC_TYPE_DCP;
+                       else
+                               port_type = USB_BC_TYPE_CDP;
+               } else {
+                       port_type = USB_BC_TYPE_SDP;
+               }
+               BC_SET(SYNOP_BC_VDATSRCENB, 0);
+               BC_SET(SYNOP_BC_VDATDETENB, 0);
+               BC_SET(SYNOP_BC_CHRGSEL, 0);
+
+       }
+out:
+       /*
+       printk("%s, Charger type %s, %s DCD, dcd_state = %d\n", __func__,
+              bc_string[port_type], wait ? "wait" : "pass", dcd_state);
+       */
+       return port_type;
 }
 
-int usb_battery_charger_detect(bool wait)
+enum bc_port_type usb_battery_charger_detect(bool wait)
 {
-    static struct device_node *np = NULL;
-    if(!np)
-        np = of_find_node_by_name(NULL, "usb_bc");
-    if(!np)
-        goto fail;
-    if(!pGRF_BASE) {
-        pGRF_BASE = get_grf_base(np);
-    }
-
-    if(of_device_is_compatible(np,"rockchip,ctrl")) {
-        if(!pBC_UOC_FIELDS)
-            uoc_init_rk(np);
-        return usb_battery_charger_detect_rk(wait);
-    }
-
-    else if(of_device_is_compatible(np,"synopsys,phy")) {
-        if(!pBC_UOC_FIELDS)
-            uoc_init_synop(np);
-        return usb_battery_charger_detect_synop(wait);
-    }
-
-    else if(of_device_is_compatible(np,"inno,phy")) {
-        if(!pBC_UOC_FIELDS)
-            uoc_init_inno(np);
-        return usb_battery_charger_detect_inno(wait);
-    }
-fail:
-    return -1;
+       static struct device_node *np;
+       enum bc_port_type ret = USB_BC_TYPE_DISCNT;
+
+       might_sleep();
+
+       if (!np)
+               np = of_find_node_by_name(NULL, "usb_bc");
+       if (!np)
+               return -1;
+       if (!pGRF_BASE) {
+               pGRF_BASE = get_grf_base(np);
+               mutex_init(&bc_mutex);
+       }
+
+       mutex_lock(&bc_mutex);
+       if (of_device_is_compatible(np, "rockchip,ctrl")) {
+               if (!pBC_UOC_FIELDS)
+                       uoc_init_rk(np);
+               ret = usb_battery_charger_detect_rk(wait);
+       }
+
+       else if (of_device_is_compatible(np, "synopsys,phy")) {
+               if (!pBC_UOC_FIELDS)
+                       uoc_init_synop(np);
+               ret = usb_battery_charger_detect_synop(wait);
+       }
+
+       else if (of_device_is_compatible(np, "inno,phy")) {
+               if (!pBC_UOC_FIELDS)
+                       uoc_init_inno(np);
+               ret = usb_battery_charger_detect_inno(wait);
+       }
+       if (ret == USB_BC_TYPE_UNKNOW)
+               ret = USB_BC_TYPE_DCP;
+       mutex_unlock(&bc_mutex);
+       rk_battery_charger_detect_cb(ret);
+       return ret;
 }
-EXPORT_SYMBOL(usb_battery_charger_detect);
-
 
 int dwc_otg_check_dpdm(bool wait)
 {
-    static struct device_node *np = NULL;
-    if(!np)
-        np = of_find_node_by_name(NULL, "usb_bc");
-    if(!np)
-        return -1;
-    if(!pGRF_BASE) {
-        pGRF_BASE = get_grf_base(np);
-    }
-
-    if(of_device_is_compatible(np,"rockchip,ctrl")) {
-        if(!pBC_UOC_FIELDS)
-            uoc_init_rk(np);
-               if(!BC_GET(RK_BC_BVALID))
-                       rk_usb_charger_status = USB_BC_TYPE_DISCNT;
-
-    }else if(of_device_is_compatible(np,"synopsys,phy")) {
-        if(!pBC_UOC_FIELDS)
-            uoc_init_synop(np);
-               if(!BC_GET(SYNOP_BC_BVALID))
-                       rk_usb_charger_status = USB_BC_TYPE_DISCNT;
-
-    }else if(of_device_is_compatible(np,"inno,phy")) {
-        if(!pBC_UOC_FIELDS)
-            uoc_init_inno(np);
-    }
-
-    return rk_usb_charger_status;
+       return (is_connected() ? usb_charger_status : USB_BC_TYPE_DISCNT);
 }
 EXPORT_SYMBOL(dwc_otg_check_dpdm);
 
-/* CALL BACK FUNCTION for USB CHARGER TYPE CHANGED */
+/* Call back function for USB charger type changed */
+static ATOMIC_NOTIFIER_HEAD(rk_bc_notifier);
 
-void usb20otg_battery_charger_detect_cb(int charger_type_new)
+int rk_bc_detect_notifier_register(struct notifier_block *nb,
+                                          int *type)
 {
-    static int charger_type = USB_BC_TYPE_DISCNT;
-    if(charger_type != charger_type_new) {
-        switch(charger_type_new) {
-            case USB_BC_TYPE_DISCNT:
-                break;
-
-            case USB_BC_TYPE_SDP:
-                break;
-
-            case USB_BC_TYPE_DCP:
-                break;
-
-            case USB_BC_TYPE_CDP:
-                break;
-
-            case USB_BC_TYPE_UNKNOW:
-                break;
+       *type = (int)usb_battery_charger_detect(0);
+       return atomic_notifier_chain_register(&rk_bc_notifier, nb);
+}
+EXPORT_SYMBOL(rk_bc_detect_notifier_register);
 
-            default :
-                break;
-        }
+int rk_bc_detect_notifier_unregister(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&rk_bc_notifier, nb);
+}
+EXPORT_SYMBOL(rk_bc_detect_notifier_unregister);
 
-        //printk("%s , battery_charger_detect %d\n", __func__, charger_type_new);
-    }
-    charger_type = charger_type_new;
+void rk_bc_detect_notifier_callback(int bc_mode)
+{
+       atomic_notifier_call_chain(&rk_bc_notifier,bc_mode, NULL);
 }
 
+void rk_battery_charger_detect_cb(int new_type)
+{
+       might_sleep();
+
+       if (usb_charger_status != new_type) {
+               printk("%s , battery_charger_detect %d\n", __func__, new_type);
+               atomic_notifier_call_chain(&rk_bc_notifier, new_type, NULL);
+       }
+       mutex_lock(&bc_mutex);
+       usb_charger_status = new_type;
+       mutex_unlock(&bc_mutex);
+}