[COMMON] usb: notify: add related USB notify driver
authorKisang Lee <kisang80.lee@samsung.com>
Thu, 17 May 2018 11:52:26 +0000 (20:52 +0900)
committerKisang Lee <kisang80.lee@samsung.com>
Thu, 17 May 2018 12:22:41 +0000 (21:22 +0900)
Change-Id: I0aee0a5f9e2c300a1cb788a6b7fe5be6c01ccad9
Signed-off-by: Kisang Lee <kisang80.lee@samsung.com>
25 files changed:
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/manager/Kconfig [new file with mode: 0644]
drivers/usb/manager/Makefile [new file with mode: 0644]
drivers/usb/manager/usb_typec_manager_notifier.c [new file with mode: 0644]
drivers/usb/notify/Kconfig [new file with mode: 0644]
drivers/usb/notify/Makefile [new file with mode: 0644]
drivers/usb/notify/dock_notify.c [new file with mode: 0644]
drivers/usb/notify/dock_notify.h [new file with mode: 0644]
drivers/usb/notify/external_notify.c [new file with mode: 0644]
drivers/usb/notify/host_notify_class.c [new file with mode: 0644]
drivers/usb/notify/usb_notifier.c [new file with mode: 0644]
drivers/usb/notify/usb_notifier.h [new file with mode: 0644]
drivers/usb/notify/usb_notify.c [new file with mode: 0644]
drivers/usb/notify/usb_notify_sysfs.c [new file with mode: 0644]
drivers/usb/notify/usb_notify_sysfs.h [new file with mode: 0644]
drivers/usb/notify/usblog_proc_notify.c [new file with mode: 0644]
include/linux/battery/sec_charging_common.h [new file with mode: 0644]
include/linux/external_notify.h [new file with mode: 0644]
include/linux/host_notify.h [new file with mode: 0644]
include/linux/mfd/samsung/s2mps18-private.h [new file with mode: 0644]
include/linux/usb/manager/usb_typec_manager_notifier.h [new file with mode: 0644]
include/linux/usb_hw_param.h [new file with mode: 0644]
include/linux/usb_notify.h [new file with mode: 0644]
include/linux/usblog_proc_notify.h [new file with mode: 0644]

index 72eb3e41e3b65d66b26972f3579fa29c7cdd48a4..cc20214e6b93075f955a4ae4af43d5a392e7a442 100644 (file)
@@ -117,6 +117,10 @@ source "drivers/usb/mtu3/Kconfig"
 
 source "drivers/usb/musb/Kconfig"
 
+source "drivers/usb/notify/Kconfig"
+
+source "drivers/usb/manager/Kconfig"
+
 source "drivers/usb/dwc3/Kconfig"
 
 source "drivers/usb/dwc2/Kconfig"
index 060643a1b5c8aa4f446973bc1ca8b7bfadfcb54b..dad5bd3effc9405ed924bb2cca493d44914ba774 100644 (file)
@@ -65,3 +65,5 @@ obj-$(CONFIG_USB_COMMON)      += common/
 obj-$(CONFIG_USBIP_CORE)       += usbip/
 
 obj-$(CONFIG_TYPEC)            += typec/
+obj-$(CONFIG_USB_NOTIFY_LAYER) += notify/
+obj-$(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)       += manager/
diff --git a/drivers/usb/manager/Kconfig b/drivers/usb/manager/Kconfig
new file mode 100644 (file)
index 0000000..7bdcfa3
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# USB TypeC Manager driver
+#
+
+comment "USB TypeC Manager configs"
+
+config USB_TYPEC_MANAGER_NOTIFIER
+    bool "USB TypeC Manager driver"
+    help
+    If you say yes here you will get support for
+      USB TypeC Manager function
diff --git a/drivers/usb/manager/Makefile b/drivers/usb/manager/Makefile
new file mode 100644 (file)
index 0000000..fcc6409
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for usb typec manager drivers
+#
+
+obj-$(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)     += usb_typec_manager_notifier.o
+#obj-$(CONFIG_USB_TYPEC_MANAGER)     += usb_typec_manager.o
diff --git a/drivers/usb/manager/usb_typec_manager_notifier.c b/drivers/usb/manager/usb_typec_manager_notifier.c
new file mode 100644 (file)
index 0000000..9e84f97
--- /dev/null
@@ -0,0 +1,1114 @@
+#include <linux/device.h>
+#include <linux/module.h>
+
+#include <linux/notifier.h>
+#include <linux/usb/manager/usb_typec_manager_notifier.h>
+
+#include <linux/ccic/ccic_core.h>
+#include <linux/ccic/ccic_notifier.h>
+
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/sec_sysfs.h>
+
+#if defined(CONFIG_VBUS_NOTIFIER)
+#include <linux/vbus_notifier.h>
+#endif
+#include <linux/usb_notify.h>
+#include <linux/delay.h>
+#include <linux/ccic/s2mm005_ext.h>
+#include <linux/time.h>
+#include <linux/ktime.h>
+#include <linux/rtc.h>
+#include <linux/ccic/max77705_usbc.h>
+#include <linux/ccic/max77705_alternate.h>
+
+#define DEBUG
+#define SET_MANAGER_NOTIFIER_BLOCK(nb, fn, dev) do {   \
+               (nb)->notifier_call = (fn);             \
+               (nb)->priority = (dev);                 \
+       } while (0)
+
+#define DESTROY_MANAGER_NOTIFIER_BLOCK(nb)                     \
+               SET_MANAGER_NOTIFIER_BLOCK(nb, NULL, -1)
+
+typedef enum
+{
+       VBUS_NOTIFIER,
+       CCIC_NOTIFIER,
+       MUIC_NOTIFIER
+}notifier_register;
+
+static int manager_notifier_init_done = 0;
+static int confirm_manager_notifier_register = 0;
+static int manager_notifier_init(void);
+
+struct device *manager_device;
+extern struct device *ccic_device;
+manager_data_t typec_manager;
+void set_usb_enumeration_state(int state);
+static void cable_type_check_work(bool state, int time);
+void calc_duration_time(unsigned long sTime, unsigned long eTime, unsigned long *dTime);
+void wVbus_time_update(int mode);
+void water_dry_time_update(int mode);
+
+static int manager_notifier_notify(void *data)
+{
+       MANAGER_NOTI_TYPEDEF manager_noti = *(MANAGER_NOTI_TYPEDEF *)data;
+       int ret = 0;
+
+       pr_info("usb: [M] %s: src:%s dest:%s id:%s "
+               "sub1:%02x sub2:%02x sub3:%02x\n", __func__,
+               (manager_noti.src<CCIC_NOTI_DEST_NUM)?
+               CCIC_NOTI_DEST_Print[manager_noti.src]:"unknown",
+               (manager_noti.dest<CCIC_NOTI_DEST_NUM)?
+               CCIC_NOTI_DEST_Print[manager_noti.dest]:"unknown",
+               (manager_noti.id<CCIC_NOTI_ID_NUM)?
+               CCIC_NOTI_ID_Print[manager_noti.id]:"unknown",
+               manager_noti.sub1, manager_noti.sub2, manager_noti.sub3);
+
+       if (manager_noti.dest == CCIC_NOTIFY_DEV_DP) {
+               if (manager_noti.id == CCIC_NOTIFY_ID_DP_CONNECT) {
+                       typec_manager.dp_attach_state = manager_noti.sub1;
+                       typec_manager.dp_is_connect = 0;
+                       typec_manager.dp_hs_connect = 0;
+               } else if (manager_noti.id == CCIC_NOTIFY_ID_DP_HPD) {
+                       typec_manager.dp_hpd_state = manager_noti.sub1;
+               } else if (manager_noti.id == CCIC_NOTIFY_ID_DP_LINK_CONF) {
+                       typec_manager.dp_cable_type = manager_noti.sub1;
+               }
+       }
+
+       if (manager_noti.dest == CCIC_NOTIFY_DEV_USB_DP) {
+               if (manager_noti.id == CCIC_NOTIFY_ID_USB_DP) {
+                       typec_manager.dp_is_connect = manager_noti.sub1;
+                       typec_manager.dp_hs_connect = manager_noti.sub2;
+               }
+       }
+
+       if (manager_noti.dest == CCIC_NOTIFY_DEV_USB) {
+               if (typec_manager.ccic_drp_state == manager_noti.sub2)
+                       return 0;
+               typec_manager.ccic_drp_state = manager_noti.sub2;
+               if (typec_manager.ccic_drp_state == USB_STATUS_NOTIFY_DETACH)
+                       set_usb_enumeration_state(0);
+       }
+
+       if (manager_noti.dest == CCIC_NOTIFY_DEV_BATTERY
+               && manager_noti.sub3 == ATTACHED_DEV_UNDEFINED_RANGE_MUIC) {
+               if (manager_noti.sub1 != typec_manager.wVbus_det) {
+                       typec_manager.wVbus_det = manager_noti.sub1;
+                       typec_manager.waterChg_count += manager_noti.sub1;
+                       wVbus_time_update(typec_manager.wVbus_det);
+               } else {
+                       return 0;
+               }
+       }
+
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+       store_usblog_notify(NOTIFY_MANAGER, (void*)data , NULL);
+#endif
+
+       if (manager_noti.dest == CCIC_NOTIFY_DEV_MUIC) {
+               ret = blocking_notifier_call_chain(&(typec_manager.manager_muic_notifier),
+                                       manager_noti.id, &manager_noti);
+       } else {
+               ret = blocking_notifier_call_chain(&(typec_manager.manager_ccic_notifier),
+                                       manager_noti.id, &manager_noti);
+       }
+
+       switch (ret) {
+       case NOTIFY_DONE:
+       case NOTIFY_OK:
+               pr_info("usb: [M] %s: notify done(0x%x)\n", __func__, ret);
+               break;
+       case NOTIFY_STOP_MASK:
+       case NOTIFY_BAD:
+       default:
+               if ( manager_noti.dest == CCIC_NOTIFY_DEV_USB) {
+                       pr_info("usb: [M] %s: UPSM case (0x%x)\n", __func__, ret);
+                       typec_manager.is_UFPS = 1;
+               } else {
+                       pr_info("usb: [M] %s: notify error occur(0x%x)\n", __func__, ret);
+               }
+               break;
+       }
+
+       return ret;
+}
+
+void set_usb_enumeration_state(int state)
+{
+       if(typec_manager.usb_enum_state != state) {
+               typec_manager.usb_enum_state = state;
+
+               if(typec_manager.usb_enum_state == 0x310)
+                       typec_manager.usb310_count++;
+               else if(typec_manager.usb_enum_state == 0x210)
+                       typec_manager.usb210_count++;
+       }
+}
+EXPORT_SYMBOL(set_usb_enumeration_state);
+
+bool get_usb_enumeration_state(void)
+{
+       return typec_manager.usb_enum_state? 1: 0;
+}
+EXPORT_SYMBOL(get_usb_enumeration_state);
+
+int get_ccic_water_count(void)
+{
+       int ret;
+       ret = typec_manager.water_count;
+       typec_manager.water_count = 0;
+       return ret;
+}
+EXPORT_SYMBOL(get_ccic_water_count);
+
+int get_ccic_dry_count(void)
+{
+       int ret;
+       ret = typec_manager.dry_count;
+       typec_manager.dry_count = 0;
+       return ret;
+}
+EXPORT_SYMBOL(get_ccic_dry_count);
+
+int get_usb210_count(void)
+{
+       int ret;
+       ret = typec_manager.usb210_count;
+       typec_manager.usb210_count = 0;
+       return ret;
+}
+EXPORT_SYMBOL(get_usb210_count);
+
+int get_usb310_count(void)
+{
+       int ret;
+       ret = typec_manager.usb310_count;
+       typec_manager.usb310_count = 0;
+       return ret;
+}
+EXPORT_SYMBOL(get_usb310_count);
+
+int get_waterChg_count(void)
+{
+       unsigned int ret;
+       ret = typec_manager.waterChg_count;
+       typec_manager.waterChg_count = 0;
+       return ret;
+}
+EXPORT_SYMBOL(get_waterChg_count);
+
+unsigned long get_waterDet_duration(void)
+{
+       unsigned long ret;
+       struct timeval time;
+
+       if (typec_manager.water_det) {
+               do_gettimeofday(&time);
+               calc_duration_time(typec_manager.waterDet_time,
+                       time.tv_sec, &typec_manager.waterDet_duration);
+               typec_manager.waterDet_time = time.tv_sec;
+       }
+
+       ret = typec_manager.waterDet_duration/60;  /* min */
+       typec_manager.waterDet_duration -= ret*60;
+       return ret;
+}
+EXPORT_SYMBOL(get_waterDet_duration);
+
+unsigned long get_wVbus_duration(void)
+{
+       unsigned long ret;
+       struct timeval time;
+
+       if (typec_manager.wVbus_det) {
+               do_gettimeofday(&time); /* time.tv_sec */
+               calc_duration_time(typec_manager.wVbusHigh_time,
+                       time.tv_sec, &typec_manager.wVbus_duration);
+               typec_manager.wVbusHigh_time = time.tv_sec;
+       }
+
+       ret = typec_manager.wVbus_duration;  /* sec */
+       typec_manager.wVbus_duration = 0;
+       return ret;
+}
+EXPORT_SYMBOL(get_wVbus_duration);
+
+void set_usb_enable_state(void)
+{
+       if (!typec_manager.usb_enable_state) {
+               typec_manager.usb_enable_state = true;
+               if (typec_manager.pd_con_state) {
+                       cable_type_check_work(true, 120);
+               }
+       }
+}
+EXPORT_SYMBOL(set_usb_enable_state);
+
+void calc_duration_time(unsigned long sTime, unsigned long eTime, unsigned long *dTime)
+{
+       unsigned long calcDtime;
+
+       calcDtime = eTime - sTime;
+
+       /* check for exception case. */
+       if ((calcDtime < 0) || (calcDtime > 86400))
+               calcDtime = 0;
+
+       *dTime += calcDtime;
+}
+
+void manager_notifier_usbdp_support(void)
+{
+
+       MANAGER_NOTI_TYPEDEF m_noti;
+       if( typec_manager.dp_check_done == 1 ) {
+               m_noti.src = CCIC_NOTIFY_DEV_MANAGER;
+               m_noti.dest = CCIC_NOTIFY_DEV_USB_DP;
+               m_noti.id = CCIC_NOTIFY_ID_USB_DP;
+               m_noti.sub1 = typec_manager.dp_is_connect;
+               m_noti.sub2 = typec_manager.dp_hs_connect;
+               m_noti.sub3 = 0;
+               m_noti.pd = NULL;
+               manager_notifier_notify(&m_noti);
+               typec_manager.dp_check_done = 0;
+       }
+       return;
+}
+
+static void cable_type_check(struct work_struct *work)
+{
+       CC_NOTI_USB_STATUS_TYPEDEF p_usb_noti;
+       CC_NOTI_ATTACH_TYPEDEF p_batt_noti;
+
+       if ( (typec_manager.ccic_drp_state != USB_STATUS_NOTIFY_ATTACH_UFP) ||
+               typec_manager.is_UFPS ){
+               pr_info("usb: [M] %s: skip case\n", __func__);
+               return;
+       }
+
+       pr_info("usb: [M] %s: usb=%d, pd=%d\n", __func__, typec_manager.usb_enum_state, typec_manager.pd_con_state);
+       if(!typec_manager.usb_enum_state ||
+               (typec_manager.muic_data_refresh
+               && typec_manager.cable_type==MANAGER_NOTIFY_MUIC_CHARGER)) {
+
+               /* TA cable Type */
+               p_usb_noti.src = CCIC_NOTIFY_DEV_MANAGER;
+               p_usb_noti.dest = CCIC_NOTIFY_DEV_USB;
+               p_usb_noti.id = CCIC_NOTIFY_ID_USB;
+               p_usb_noti.attach = CCIC_NOTIFY_DETACH;
+               p_usb_noti.drp = USB_STATUS_NOTIFY_DETACH;
+               p_usb_noti.sub3 = 0;
+               p_usb_noti.pd = NULL;
+               manager_notifier_notify(&p_usb_noti);
+
+       } else {
+               /* USB cable Type */
+               p_batt_noti.src = CCIC_NOTIFY_DEV_MANAGER;
+               p_batt_noti.dest = CCIC_NOTIFY_DEV_BATTERY;
+               p_batt_noti.id = CCIC_NOTIFY_ID_USB;
+               p_batt_noti.attach = 0;
+               p_batt_noti.rprd = 0;
+               p_batt_noti.cable_type = PD_USB_TYPE;
+               p_batt_noti.pd = NULL;
+               manager_notifier_notify(&p_batt_noti);
+       }
+}
+
+static void cable_type_check_work(bool state, int time) {
+       if(typec_manager.usb_enable_state) {
+               cancel_delayed_work_sync(&typec_manager.cable_check_work);
+               if(state) {
+                       schedule_delayed_work(&typec_manager.cable_check_work, msecs_to_jiffies(time*100));
+               }
+       }
+}
+
+static void muic_work_without_ccic(struct work_struct *work)
+{
+       CC_NOTI_USB_STATUS_TYPEDEF p_usb_noti;
+
+       pr_info("usb: [M] %s: working state=%d, vbus=%s\n", __func__,
+               typec_manager.muic_attach_state_without_ccic,
+               typec_manager.vbus_state == STATUS_VBUS_HIGH ? "HIGH" : "LOW");
+
+       if (typec_manager.muic_attach_state_without_ccic) {
+               switch (typec_manager.muic_action) {
+                       case MUIC_NOTIFY_CMD_ATTACH:
+#if defined(CONFIG_VBUS_NOTIFIER)
+                               if(typec_manager.vbus_state == STATUS_VBUS_HIGH)
+#endif
+                               {
+                                       p_usb_noti.src = CCIC_NOTIFY_DEV_MUIC;
+                                       p_usb_noti.dest = CCIC_NOTIFY_DEV_USB;
+                                       p_usb_noti.id = CCIC_NOTIFY_ID_USB;
+                                       p_usb_noti.attach = CCIC_NOTIFY_ATTACH;
+                                       p_usb_noti.drp = USB_STATUS_NOTIFY_ATTACH_UFP;
+                                       p_usb_noti.sub3 = 0;
+                                       p_usb_noti.pd = NULL;
+                                       manager_notifier_notify(&p_usb_noti);
+                                       typec_manager.ccic_drp_state = USB_STATUS_NOTIFY_ATTACH_UFP;
+                               }
+                               break;
+                       case MUIC_NOTIFY_CMD_DETACH:
+                               typec_manager.muic_attach_state_without_ccic = 0;
+                               p_usb_noti.src = CCIC_NOTIFY_DEV_MUIC;
+                               p_usb_noti.dest = CCIC_NOTIFY_DEV_USB;
+                               p_usb_noti.id = CCIC_NOTIFY_ID_USB;
+                               p_usb_noti.attach = CCIC_NOTIFY_DETACH;
+                               p_usb_noti.drp = USB_STATUS_NOTIFY_DETACH;
+                               p_usb_noti.sub3 = 0;
+                               p_usb_noti.pd = NULL;
+                               manager_notifier_notify(&p_usb_noti);
+                               typec_manager.ccic_drp_state = USB_STATUS_NOTIFY_DETACH;
+                               break;
+                       default :
+                               break;
+               }
+       }
+}
+
+void water_dry_time_update(int mode)
+{
+       struct timeval time;
+       struct rtc_time det_time;
+       static int rtc_update_check = 1;
+
+       do_gettimeofday(&time);
+       if (rtc_update_check) {
+               rtc_update_check = 0;
+               rtc_time_to_tm(time.tv_sec, &det_time);
+               pr_info("%s: year=%d\n", __func__,  det_time.tm_year);
+               if (det_time.tm_year == 70) { /* (1970-01-01 00:00:00) */
+                       schedule_delayed_work(&typec_manager.rtctime_update_work, msecs_to_jiffies(5000));
+               }
+       }
+
+       if (mode) {
+               /* WATER */
+               typec_manager.waterDet_time = time.tv_sec;
+       } else {
+               /* DRY */
+               typec_manager.dryDet_time = time.tv_sec;
+               calc_duration_time(typec_manager.waterDet_time,
+                       typec_manager.dryDet_time, &typec_manager.waterDet_duration);
+       }
+}
+
+static void water_det_rtc_time_update(struct work_struct *work)
+{
+       struct timeval time;
+       struct rtc_time rtctime;
+       static int max_retry = 1;
+
+       do_gettimeofday(&time);
+       rtc_time_to_tm(time.tv_sec, &rtctime);
+       if ((rtctime.tm_year == 70) && (max_retry<5)) {
+               /* (1970-01-01 00:00:00) */
+               if (typec_manager.wVbus_det) {
+                       calc_duration_time(typec_manager.wVbusHigh_time,
+                               time.tv_sec, &typec_manager.wVbus_duration);
+                       typec_manager.wVbusHigh_time = time.tv_sec;
+               }
+               max_retry++;
+               schedule_delayed_work(&typec_manager.rtctime_update_work, msecs_to_jiffies(5000));
+       } else {
+               if (typec_manager.water_det) {
+                       typec_manager.waterDet_time = time.tv_sec;
+                       typec_manager.waterDet_duration += max_retry*5;
+                       if (typec_manager.wVbus_det) {
+                               typec_manager.wVbusHigh_time = time.tv_sec;
+                               typec_manager.wVbus_duration += 5;
+                       }
+               }
+       }
+}
+
+void wVbus_time_update(int mode)
+{
+       struct timeval time;
+
+       do_gettimeofday(&time);
+
+       if (mode) {
+               /* WVBUS HIGH */
+               typec_manager.wVbusHigh_time = time.tv_sec;
+       } else {
+               /* WVBUS LOW */
+               typec_manager.wVbusLow_time = time.tv_sec;
+               calc_duration_time(typec_manager.wVbusHigh_time,
+                       typec_manager.wVbusLow_time, &typec_manager.wVbus_duration);
+       }
+}
+
+#if defined(CONFIG_VBUS_NOTIFIER)
+void handle_muic_fake_event(int event)
+{
+
+       if (typec_manager.muic_fake_event_wq_processing) {
+               typec_manager.muic_fake_event_wq_processing = 0;
+               cancel_delayed_work_sync(&typec_manager.vbus_noti_work);
+       }
+
+       switch (event) {
+               case EVENT_CANCEL:
+                       typec_manager.muic_attach_state_without_ccic = 0;
+                       break;
+               case EVENT_LOAD:
+                       if(typec_manager.muic_attach_state_without_ccic
+                               || typec_manager.ccic_drp_state == USB_STATUS_NOTIFY_ATTACH_UFP) {
+                               schedule_delayed_work(&typec_manager.vbus_noti_work, msecs_to_jiffies(1000));
+                               typec_manager.muic_fake_event_wq_processing = 1;
+                       }
+                       break;
+               default :
+                       break;
+       }
+}
+
+
+static void muic_fake_event_work(struct work_struct *work)
+{
+       CC_NOTI_ATTACH_TYPEDEF muic_noti;
+
+       pr_info("usb: [M] %s: drp=%d, rid=%d, without_ccic=%d\n", __func__,
+               typec_manager.ccic_drp_state,
+               typec_manager.ccic_rid_state,
+               typec_manager.muic_attach_state_without_ccic);
+
+       typec_manager.muic_fake_event_wq_processing = 0;
+
+       if( typec_manager.ccic_rid_state == RID_523K ||  typec_manager.ccic_rid_state == RID_619K
+               || typec_manager.ccic_drp_state == USB_STATUS_NOTIFY_ATTACH_DFP
+               || typec_manager.vbus_state == STATUS_VBUS_HIGH) {
+               return;
+       } else if (typec_manager.muic_action == MUIC_NOTIFY_CMD_DETACH) {
+               typec_manager.muic_attach_state_without_ccic = 1;
+               schedule_delayed_work(&typec_manager.muic_noti_work, msecs_to_jiffies(0));
+               return;
+       }
+
+       typec_manager.muic_attach_state_without_ccic = 1;
+       muic_noti.src = CCIC_NOTIFY_DEV_MANAGER;
+       muic_noti.dest = CCIC_NOTIFY_DEV_MUIC;
+       muic_noti.id = CCIC_NOTIFY_ID_ATTACH;
+       muic_noti.attach = 0;
+       muic_noti.rprd = 0;
+       muic_noti.cable_type = typec_manager.muic_cable_type;
+       muic_noti.pd = NULL;
+       manager_notifier_notify(&muic_noti);
+}
+#endif
+
+static int manager_handle_ccic_notification(struct notifier_block *nb,
+                               unsigned long action, void *data)
+{
+       MANAGER_NOTI_TYPEDEF p_noti = *(MANAGER_NOTI_TYPEDEF *)data;
+       CC_NOTI_ATTACH_TYPEDEF bat_noti;
+       CC_NOTI_ATTACH_TYPEDEF muic_noti;
+       int ret = 0;
+
+       pr_info("usb: [M] %s: src:%s dest:%s id:%s attach/rid:%d\n", __func__,
+               (p_noti.src<CCIC_NOTI_DEST_NUM)? CCIC_NOTI_DEST_Print[p_noti.src]:"unknown",
+               (p_noti.dest<CCIC_NOTI_DEST_NUM)? CCIC_NOTI_DEST_Print[p_noti.dest]:"unknown",
+               (p_noti.id<CCIC_NOTI_ID_NUM)? CCIC_NOTI_ID_Print[p_noti.id]:"unknown",
+               p_noti.sub1);
+
+#if defined(CONFIG_VBUS_NOTIFIER)
+       handle_muic_fake_event(EVENT_CANCEL);
+#endif
+
+       switch (p_noti.id) {
+       case CCIC_NOTIFY_ID_POWER_STATUS:
+               if(p_noti.sub1) { /*attach*/
+                       typec_manager.pd_con_state = 1; // PDIC_NOTIFY_EVENT_PD_SINK
+                       if( (typec_manager.ccic_drp_state == USB_STATUS_NOTIFY_ATTACH_UFP) &&
+                               !typec_manager.is_UFPS){
+                               pr_info("usb: [M] %s: PD charger + UFP\n", __func__);
+                               cable_type_check_work(true, 60);
+                       }
+               }
+               p_noti.dest = CCIC_NOTIFY_DEV_BATTERY;
+               if(typec_manager.pd == NULL)
+                       typec_manager.pd = p_noti.pd;
+               break;
+       case CCIC_NOTIFY_ID_ATTACH:             // for MUIC
+                       if (typec_manager.ccic_attach_state != p_noti.sub1) {
+                               typec_manager.ccic_attach_state = p_noti.sub1;
+                               typec_manager.muic_data_refresh = 0;
+                               typec_manager.is_UFPS = 0;
+                               if(typec_manager.ccic_attach_state == CCIC_NOTIFY_ATTACH){
+                                       pr_info("usb: [M] %s: CCIC_NOTIFY_ATTACH\n", __func__);
+                                       typec_manager.water_det = 0;
+                                       typec_manager.pd_con_state = 0;
+                               }
+                       }
+
+                       if (typec_manager.ccic_attach_state == CCIC_NOTIFY_DETACH) {
+                               pr_info("usb: [M] %s: CCIC_NOTIFY_DETACH (pd=%d, cable_type=%d)\n", __func__,
+                                       typec_manager.pd_con_state, typec_manager.cable_type);
+                               cable_type_check_work(false, 0);
+                               if (typec_manager.pd_con_state) {
+                                       typec_manager.pd_con_state = 0;
+                                       bat_noti.src = CCIC_NOTIFY_DEV_CCIC;
+                                       bat_noti.dest = CCIC_NOTIFY_DEV_BATTERY;
+                                       bat_noti.id = CCIC_NOTIFY_ID_ATTACH;
+                                       bat_noti.attach = CCIC_NOTIFY_DETACH;
+                                       bat_noti.rprd = 0;
+                                       bat_noti.cable_type = ATTACHED_DEV_UNOFFICIAL_ID_ANY_MUIC; // temp
+                                       bat_noti.pd = NULL;
+                                       manager_notifier_notify(&bat_noti);
+                               }
+                       }
+               break;
+       case CCIC_NOTIFY_ID_RID:        // for MUIC (FAC)
+               typec_manager.ccic_rid_state = p_noti.sub1;
+               break;
+       case CCIC_NOTIFY_ID_USB:        // for USB3
+               if ((typec_manager.cable_type == MANAGER_NOTIFY_MUIC_CHARGER)
+                       || (p_noti.sub2 != USB_STATUS_NOTIFY_DETACH && /*drp */
+                       (typec_manager.ccic_rid_state == RID_523K || typec_manager.ccic_rid_state == RID_619K))) {
+                       return 0;
+               }
+               break;
+       case CCIC_NOTIFY_ID_WATER:
+               if (p_noti.sub1) {      /* attach */
+                       if(!typec_manager.water_det) {
+                                       typec_manager.water_det = 1;
+                                       typec_manager.water_count++;
+
+                                       muic_noti.src = CCIC_NOTIFY_DEV_CCIC;
+                                       muic_noti.dest = CCIC_NOTIFY_DEV_MUIC;
+                                       muic_noti.id = CCIC_NOTIFY_ID_WATER;
+                                       muic_noti.attach = CCIC_NOTIFY_ATTACH;
+                                       muic_noti.rprd = 0;
+                                       muic_noti.cable_type = 0;
+                                       muic_noti.pd = NULL;
+                                       manager_notifier_notify(&muic_noti);
+
+                                       /*update water time */
+                                       water_dry_time_update((int)p_noti.sub1);
+
+                                       if (typec_manager.muic_action == MUIC_NOTIFY_CMD_ATTACH) {
+                                               p_noti.sub3 = ATTACHED_DEV_UNDEFINED_RANGE_MUIC; /* cable_type */
+                                       } else {
+                                               /* If the cable is not connected, skip the battery event. */
+                                               return 0;
+                                       }
+                       } else {
+                               /* Ignore duplicate events */
+                               return 0;
+                       }
+               } else {
+                       typec_manager.water_det = 0;
+                       typec_manager.dry_count++;
+
+                       /* update run_dry time */
+                       water_dry_time_update((int)p_noti.sub1);
+
+                       if (typec_manager.wVbus_det)
+                               p_noti.sub3 = ATTACHED_DEV_UNDEFINED_RANGE_MUIC;
+                       else
+                               return 0;
+               }
+               break;
+       default:
+               break;
+       }
+
+       ret = manager_notifier_notify(&p_noti);
+
+       return ret;
+}
+
+static int manager_handle_muic_notification(struct notifier_block *nb,
+                               unsigned long action, void *data)
+{
+       CC_NOTI_ATTACH_TYPEDEF p_noti = *(CC_NOTI_ATTACH_TYPEDEF *)data;
+       CC_NOTI_USB_STATUS_TYPEDEF usb_noti;
+
+       pr_info("usb: [M] %s: attach:%d, cable_type:%d\n", __func__,
+               p_noti.attach, p_noti.cable_type);
+
+       typec_manager.muic_action = p_noti.attach;
+       typec_manager.muic_cable_type = p_noti.cable_type;
+       typec_manager.muic_data_refresh = 1;
+
+       if(typec_manager.water_det){
+               /* If Water det irq case is ignored */
+               if(p_noti.attach) typec_manager.muic_attach_state_without_ccic = 1;
+               pr_info("usb: [M] %s: Water detected case\n", __func__);
+               return 0;
+       }
+
+       if (p_noti.attach &&  typec_manager.ccic_drp_state == USB_STATUS_NOTIFY_DETACH) {
+               if(typec_manager.ccic_rid_state != RID_523K &&  typec_manager.ccic_rid_state != RID_619K)
+               typec_manager.muic_attach_state_without_ccic = 1;
+       }
+
+       switch (p_noti.cable_type) {
+       case ATTACHED_DEV_USB_MUIC:
+       case ATTACHED_DEV_CDP_MUIC:
+       case ATTACHED_DEV_UNOFFICIAL_ID_USB_MUIC:
+       case ATTACHED_DEV_UNOFFICIAL_ID_CDP_MUIC:
+       case ATTACHED_DEV_JIG_USB_OFF_MUIC:
+       case ATTACHED_DEV_JIG_USB_ON_MUIC:
+               pr_info("usb: [M] %s: USB(%d) %s, CCIC: %s \n", __func__,
+                       p_noti.cable_type, p_noti.attach ? "Attached": "Detached",
+                       typec_manager.ccic_attach_state? "Attached": "Detached");
+
+               if(typec_manager.muic_action) {
+                       typec_manager.cable_type = MANAGER_NOTIFY_MUIC_USB;
+               }
+
+               if(typec_manager.muic_attach_state_without_ccic) {
+                       if (p_noti.attach) {
+                               schedule_delayed_work(&typec_manager.muic_noti_work, msecs_to_jiffies(2000));
+                       } else {
+                               schedule_delayed_work(&typec_manager.muic_noti_work, 0);
+                       }
+               }
+               break;
+
+       case ATTACHED_DEV_TA_MUIC:
+               pr_info("usb: [M] %s: TA(%d) %s \n", __func__, p_noti.cable_type,
+                       p_noti.attach ? "Attached": "Detached");
+
+               if(typec_manager.muic_action) {
+                       typec_manager.cable_type = MANAGER_NOTIFY_MUIC_CHARGER;
+               }
+
+               if(p_noti.attach && typec_manager.ccic_drp_state == USB_STATUS_NOTIFY_ATTACH_UFP ) {
+                       if(typec_manager.pd_con_state) {
+                               cable_type_check_work(false, 0);
+                       }
+                       /* Turn off the USB Phy when connected to the charger */
+                       usb_noti.src = CCIC_NOTIFY_DEV_MUIC;
+                       usb_noti.dest = CCIC_NOTIFY_DEV_USB;
+                       usb_noti.id = CCIC_NOTIFY_ID_USB;
+                       usb_noti.attach = CCIC_NOTIFY_DETACH;
+                       usb_noti.drp = USB_STATUS_NOTIFY_DETACH;
+                       usb_noti.sub3 = 0;
+                       usb_noti.pd = NULL;
+                       manager_notifier_notify(&usb_noti);
+               }
+               break;
+
+       case ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC:
+       case ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC:
+               pr_info("usb: [M] %s: AFC or QC Prepare(%d) %s \n", __func__,
+                       p_noti.cable_type, p_noti.attach ? "Attached": "Detached");
+               break;
+
+       case ATTACHED_DEV_TIMEOUT_OPEN_MUIC:
+               pr_info("usb: [M] %s: DCD Timeout device is detected(%d) %s \n",
+                       __func__, p_noti.cable_type,
+                       p_noti.attach ? "Attached": "Detached");
+
+               if(typec_manager.muic_action) {
+                       typec_manager.cable_type = MANAGER_NOTIFY_MUIC_TIMEOUT_OPEN_DEVICE;
+               }
+               break;
+
+       default:
+               pr_info("usb: [M] %s: Cable(%d) %s \n", __func__, p_noti.cable_type,
+                       p_noti.attach ? "Attached": "Detached");
+               break;
+       }
+       if(!typec_manager.muic_action) {
+               typec_manager.cable_type = MANAGER_NOTIFY_MUIC_NONE;
+       }
+
+       if (!(p_noti.attach) && typec_manager.ccic_attach_state && typec_manager.pd_con_state) {
+               /* If PD charger + detach case is ignored */
+               pr_info("usb: [M] %s: PD charger detached case\n", __func__);
+       } else {
+               p_noti.src = CCIC_NOTIFY_DEV_MUIC;
+               p_noti.dest = CCIC_NOTIFY_DEV_BATTERY;
+               manager_notifier_notify(&p_noti);
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_VBUS_NOTIFIER)
+static int manager_handle_vbus_notification(struct notifier_block *nb,
+                               unsigned long action, void *data)
+{
+       vbus_status_t vbus_type = *(vbus_status_t *)data;
+       CC_NOTI_ATTACH_TYPEDEF bat_noti;
+
+       pr_info("usb: [M] %s: cmd=%lu, vbus_type=%s, WATER DET=%d ATTACH=%s (%d)\n", __func__,
+               action, vbus_type == STATUS_VBUS_HIGH ? "HIGH" : "LOW", typec_manager.water_det,
+               typec_manager.ccic_attach_state == CCIC_NOTIFY_ATTACH ? "ATTACH":"DETATCH",
+               typec_manager.muic_attach_state_without_ccic);
+
+       typec_manager.vbus_state = vbus_type;
+
+       switch (vbus_type) {
+       case STATUS_VBUS_HIGH:
+               if (typec_manager.water_det) {
+                       bat_noti.src = CCIC_NOTIFY_DEV_CCIC;
+                       bat_noti.dest = CCIC_NOTIFY_DEV_BATTERY;
+                       bat_noti.id = CCIC_NOTIFY_ID_WATER;
+                       bat_noti.attach = CCIC_NOTIFY_ATTACH;
+                       bat_noti.rprd = 0;
+                       bat_noti.cable_type = ATTACHED_DEV_UNDEFINED_RANGE_MUIC;
+                       bat_noti.pd = NULL;
+                       manager_notifier_notify(&bat_noti);
+               }
+               break;
+       case STATUS_VBUS_LOW:
+               if (typec_manager.water_det) {
+                       bat_noti.src = CCIC_NOTIFY_DEV_CCIC;
+                       bat_noti.dest = CCIC_NOTIFY_DEV_BATTERY;
+                       bat_noti.id = CCIC_NOTIFY_ID_ATTACH;
+                       bat_noti.attach = CCIC_NOTIFY_DETACH;
+                       bat_noti.rprd = 0;
+                       bat_noti.cable_type = ATTACHED_DEV_UNDEFINED_RANGE_MUIC;
+                       bat_noti.pd = NULL;
+                       manager_notifier_notify(&bat_noti);
+               }
+               handle_muic_fake_event(EVENT_LOAD);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+#endif
+
+int manager_notifier_register(struct notifier_block *nb, notifier_fn_t notifier,
+                       manager_notifier_device_t listener)
+{
+       int ret = 0;
+       MANAGER_NOTI_TYPEDEF m_noti;
+       static int alternate_mode_start_wait = 0;
+       pccic_data_t pccic_data;
+
+       pr_info("usb: [M] %s: listener=%d register\n", __func__, listener);
+       if(!manager_notifier_init_done)
+               manager_notifier_init();
+
+       ccic_notifier_init();
+       pccic_data = dev_get_drvdata(ccic_device);
+
+       /* Check if MANAGER Notifier is ready. */
+       if (!manager_device) {
+               pr_err("usb: [M] %s: Not Initialized...\n", __func__);
+               return -1;
+       }
+
+       if (listener == MANAGER_NOTIFY_CCIC_MUIC) {
+               SET_MANAGER_NOTIFIER_BLOCK(nb, notifier, listener);
+               ret = blocking_notifier_chain_register(&(typec_manager.manager_muic_notifier), nb);
+               if (ret < 0)
+                       pr_err("usb: [M] %s: muic blocking_notifier_chain_register error(%d)\n",
+                                       __func__, ret);
+       } else {
+               SET_MANAGER_NOTIFIER_BLOCK(nb, notifier, listener);
+               ret = blocking_notifier_chain_register(&(typec_manager.manager_ccic_notifier), nb);
+               if (ret < 0)
+                       pr_err("usb: [M] %s: ccic blocking_notifier_chain_register error(%d)\n",
+                                       __func__, ret);
+       }
+
+               /* current manager's attached_device status notify */
+       if(listener == MANAGER_NOTIFY_CCIC_BATTERY) {
+               /* CC_NOTI_ATTACH_TYPEDEF */
+               m_noti.src = CCIC_NOTIFY_DEV_MANAGER;
+               m_noti.dest = CCIC_NOTIFY_DEV_BATTERY;
+               m_noti.sub1 = (typec_manager.ccic_attach_state || typec_manager.muic_action);
+               m_noti.sub2 = 0;
+               m_noti.sub3 = 0;
+               m_noti.pd = typec_manager.pd;
+               if(typec_manager.water_det && m_noti.sub1) {
+                       m_noti.id = CCIC_NOTIFY_ID_WATER;
+                       m_noti.sub3 = ATTACHED_DEV_UNDEFINED_RANGE_MUIC;
+               } else {
+                       m_noti.id = CCIC_NOTIFY_ID_ATTACH;
+                       if(typec_manager.pd_con_state) {
+                               pr_info("usb: [M] %s: PD is attached already\n", __func__);
+                               m_noti.id = CCIC_NOTIFY_ID_POWER_STATUS;
+                       } else if(typec_manager.muic_cable_type != ATTACHED_DEV_NONE_MUIC) {
+                               m_noti.sub3= typec_manager.muic_cable_type;
+                       } else {
+                               switch(typec_manager.ccic_drp_state){
+                                       case USB_STATUS_NOTIFY_ATTACH_UFP:
+                                               m_noti.sub3 = ATTACHED_DEV_USB_MUIC;
+                                               break;
+                                       case USB_STATUS_NOTIFY_ATTACH_DFP:
+                                               m_noti.sub3 = ATTACHED_DEV_OTG_MUIC;
+                                               break;
+                                       default:
+                                               m_noti.sub3 = ATTACHED_DEV_NONE_MUIC;
+                                               break;
+                               }
+                       }
+               }
+               pr_info("usb: [M] %s BATTERY: cable_type=%d (%s) \n", __func__, m_noti.sub3,
+                       typec_manager.muic_cable_type? "MUIC" : "CCIC");
+               nb->notifier_call(nb, m_noti.id, &(m_noti));
+
+       } else if(listener == MANAGER_NOTIFY_CCIC_USB) {
+               /* CC_NOTI_USB_STATUS_TYPEDEF */
+               m_noti.src = CCIC_NOTIFY_DEV_MANAGER;
+               m_noti.dest = CCIC_NOTIFY_DEV_USB;
+               m_noti.id = CCIC_NOTIFY_ID_USB;
+               if (typec_manager.water_det)
+                       m_noti.sub1 = 0;
+               else
+                       m_noti.sub1 = typec_manager.ccic_attach_state || typec_manager.muic_action;
+
+               if (m_noti.sub1) {
+                       if (typec_manager.ccic_drp_state &&
+                               (typec_manager.cable_type != MANAGER_NOTIFY_MUIC_CHARGER)) {
+                               m_noti.sub2 = typec_manager.ccic_drp_state;
+                       } else if (typec_manager.cable_type == MANAGER_NOTIFY_MUIC_USB) {
+                               typec_manager.ccic_drp_state = USB_STATUS_NOTIFY_ATTACH_UFP;
+                               m_noti.sub2 = USB_STATUS_NOTIFY_ATTACH_UFP;
+                       } else {
+                               typec_manager.ccic_drp_state = USB_STATUS_NOTIFY_DETACH;
+                               m_noti.sub2 = USB_STATUS_NOTIFY_DETACH;
+                       }
+               } else {
+                               m_noti.sub2 = USB_STATUS_NOTIFY_DETACH;
+               }
+               m_noti.sub3 = 0;
+               pr_info("usb: [M] %s USB: attach=%d, drp=%s \n", __func__,      m_noti.sub1,
+                       CCIC_NOTI_USB_STATUS_Print[m_noti.sub2]);
+               nb->notifier_call(nb, m_noti.id, &(m_noti));
+               alternate_mode_start_wait |= 0x1;
+               if (alternate_mode_start_wait == 0x11) {
+                       pr_info("usb: [M] %s USB & DP driver is registered! Alternate mode Start!\n", __func__);
+#if defined(CONFIG_CCIC_ALTERNATE_MODE)
+                       if (pccic_data && pccic_data->set_enable_alternate_mode)
+                               pccic_data->set_enable_alternate_mode(ALTERNATE_MODE_READY | ALTERNATE_MODE_START);
+#endif
+               }
+       } else if(listener == MANAGER_NOTIFY_CCIC_DP) {
+               m_noti.src = CCIC_NOTIFY_DEV_MANAGER;
+               m_noti.dest = CCIC_NOTIFY_DEV_DP;
+               m_noti.sub2 = 0;
+               m_noti.sub3 = 0;
+               if (typec_manager.dp_attach_state == CCIC_NOTIFY_ATTACH) {
+                       m_noti.id = CCIC_NOTIFY_ID_DP_CONNECT;
+                       m_noti.sub1 = typec_manager.dp_attach_state;
+                       nb->notifier_call(nb, m_noti.id, &(m_noti));
+
+                       m_noti.id = CCIC_NOTIFY_ID_DP_LINK_CONF;
+                       m_noti.sub1 = typec_manager.dp_cable_type;
+                       nb->notifier_call(nb, m_noti.id, &(m_noti));
+
+                       if (typec_manager.dp_hpd_state == CCIC_NOTIFY_HIGH) {
+                               m_noti.id = CCIC_NOTIFY_ID_DP_HPD;
+                               m_noti.sub1 = typec_manager.dp_hpd_state;
+                               nb->notifier_call(nb, m_noti.id, &(m_noti));
+                       }
+               }
+               alternate_mode_start_wait |= 0x10;
+               if (alternate_mode_start_wait == 0x11) {
+                       pr_info("usb: [M] %s USB & DP driver is registered! Alternate mode Start!\n", __func__);
+#if defined(CONFIG_CCIC_ALTERNATE_MODE)
+                       if (pccic_data && pccic_data->set_enable_alternate_mode)
+                               pccic_data->set_enable_alternate_mode(ALTERNATE_MODE_READY | ALTERNATE_MODE_START);
+#endif
+               }
+       }
+
+       return ret;
+}
+
+int manager_notifier_unregister(struct notifier_block *nb)
+{
+       int ret = 0;
+       pr_info("usb: [M] %s: listener=%d unregister\n", __func__, nb->priority);
+
+       if (nb->priority == MANAGER_NOTIFY_CCIC_MUIC) {
+               ret = blocking_notifier_chain_unregister(&(typec_manager.manager_muic_notifier), nb);
+               if (ret < 0)
+                       pr_err("usb: [M] %s: muic blocking_notifier_chain_unregister error(%d)\n",
+                                       __func__, ret);
+               DESTROY_MANAGER_NOTIFIER_BLOCK(nb);
+       } else {
+               ret = blocking_notifier_chain_unregister(&(typec_manager.manager_ccic_notifier), nb);
+               if (ret < 0)
+                       pr_err("usb: [M] %s: ccic blocking_notifier_chain_unregister error(%d)\n",
+                                       __func__, ret);
+               DESTROY_MANAGER_NOTIFIER_BLOCK(nb);
+       }
+       return ret;
+}
+
+static void delayed_manger_notifier_init(struct work_struct *work)
+{
+       int ret = 0;
+       int notifier_result = 0;
+       static int retry_count = 1;
+       int max_retry_count = 5;
+
+       pr_info("%s : %d = times!\n",__func__,retry_count);
+#if defined(CONFIG_VBUS_NOTIFIER)
+       if(confirm_manager_notifier_register & (1 << VBUS_NOTIFIER))
+       {
+               ret = vbus_notifier_register(&typec_manager.vbus_nb, manager_handle_vbus_notification,VBUS_NOTIFY_DEV_MANAGER);
+               if(ret)
+                       notifier_result |= (1 << VBUS_NOTIFIER);
+       }
+#endif
+       if(confirm_manager_notifier_register & (1 << CCIC_NOTIFIER))
+       {
+               ret = ccic_notifier_register(&typec_manager.ccic_nb, manager_handle_ccic_notification,CCIC_NOTIFY_DEV_MANAGER);
+               if(ret)
+                       notifier_result |= (1 << CCIC_NOTIFIER);
+       }
+
+       if(confirm_manager_notifier_register & (1 << MUIC_NOTIFIER))
+       {
+               ret = muic_notifier_register(&typec_manager.muic_nb, manager_handle_muic_notification,MUIC_NOTIFY_DEV_MANAGER);
+               if(ret)
+                       notifier_result |= (1 << MUIC_NOTIFIER);
+       }
+
+       confirm_manager_notifier_register = notifier_result;
+       pr_info("%s : result of register = %d!\n",__func__, confirm_manager_notifier_register);
+
+       if(confirm_manager_notifier_register)
+       {
+               pr_err("Manager notifier init time is %d.\n",retry_count);
+               if(retry_count++ != max_retry_count)
+                       schedule_delayed_work(&typec_manager.manager_init_work, msecs_to_jiffies(2000));
+               else
+                       pr_err("fail to init manager notifier\n");
+       }
+       else
+       {
+               pr_info("%s : done!\n",__func__);
+       }
+}
+
+
+static int manager_notifier_init(void)
+{
+       int ret = 0;
+       int notifier_result = 0;
+       pccic_data_t pccic_data;
+
+       pr_info("usb: [M] %s\n", __func__);
+       ccic_notifier_init();
+       pccic_data = dev_get_drvdata(ccic_device);
+
+       if(manager_notifier_init_done)
+       {
+               pr_err("%s already registered\n", __func__);
+               goto out;
+       }
+       manager_notifier_init_done = 1;
+
+       manager_device = sec_device_create(NULL, "typec_manager");
+       if (IS_ERR(manager_device)) {
+               pr_err("usb: [M] %s Failed to create device(switch)!\n", __func__);
+               ret = -ENODEV;
+               goto out;
+       }
+
+       typec_manager.ccic_attach_state = CCIC_NOTIFY_DETACH;
+       typec_manager.ccic_drp_state = USB_STATUS_NOTIFY_DETACH;
+       typec_manager.muic_action = MUIC_NOTIFY_CMD_DETACH;
+       typec_manager.muic_cable_type = ATTACHED_DEV_NONE_MUIC;
+       typec_manager.cable_type = MANAGER_NOTIFY_MUIC_NONE;
+       typec_manager.muic_data_refresh = 0;
+       typec_manager.usb_enum_state = 0;
+       typec_manager.water_det = 0;
+       typec_manager.wVbus_det = 0;
+       typec_manager.water_count =0;
+       typec_manager.dry_count = 0;
+       typec_manager.usb210_count = 0;
+       typec_manager.usb310_count = 0;
+       typec_manager.waterChg_count = 0;
+       typec_manager.waterDet_duration = 0;
+       typec_manager.wVbus_duration = 0;
+       typec_manager.dp_is_connect = 0;
+       typec_manager.dp_hs_connect = 0;
+       typec_manager.dp_check_done = 1;
+       typec_manager.muic_attach_state_without_ccic = 0;
+#if defined(CONFIG_VBUS_NOTIFIER)
+       typec_manager.muic_fake_event_wq_processing = 0;
+#endif
+       typec_manager.vbus_state = 0;
+       typec_manager.is_UFPS = 0;
+       typec_manager.ccic_rid_state = RID_UNDEFINED;
+       typec_manager.pd = NULL;
+
+       BLOCKING_INIT_NOTIFIER_HEAD(&(typec_manager.manager_ccic_notifier));
+       BLOCKING_INIT_NOTIFIER_HEAD(&(typec_manager.manager_muic_notifier));
+
+       INIT_DELAYED_WORK(&typec_manager.manager_init_work,
+               delayed_manger_notifier_init);
+
+       INIT_DELAYED_WORK(&typec_manager.cable_check_work,
+               cable_type_check);
+
+       INIT_DELAYED_WORK(&typec_manager.muic_noti_work,
+               muic_work_without_ccic);
+
+       INIT_DELAYED_WORK(&typec_manager.rtctime_update_work,
+               water_det_rtc_time_update);
+
+#if defined(CONFIG_CCIC_ALTERNATE_MODE)
+       if (pccic_data && pccic_data->set_enable_alternate_mode)
+               pccic_data->set_enable_alternate_mode(ALTERNATE_MODE_NOT_READY);
+#endif
+#if defined(CONFIG_VBUS_NOTIFIER)
+       INIT_DELAYED_WORK(&typec_manager.vbus_noti_work,
+               muic_fake_event_work);
+#endif
+
+       // Register manager handler to ccic notifier block list
+#if defined(CONFIG_VBUS_NOTIFIER)
+       ret = vbus_notifier_register(&typec_manager.vbus_nb, manager_handle_vbus_notification,VBUS_NOTIFY_DEV_MANAGER);
+       if(ret)
+               notifier_result |= (1 << VBUS_NOTIFIER);
+#endif
+       ret = ccic_notifier_register(&typec_manager.ccic_nb, manager_handle_ccic_notification,CCIC_NOTIFY_DEV_MANAGER);
+       if(ret)
+               notifier_result |= (1 << CCIC_NOTIFIER);
+       ret = muic_notifier_register(&typec_manager.muic_nb, manager_handle_muic_notification,MUIC_NOTIFY_DEV_MANAGER);
+       if(ret)
+               notifier_result |= (1 << MUIC_NOTIFIER);
+
+       confirm_manager_notifier_register = notifier_result;
+       pr_info("%s : result of register = %d!\n",__func__, confirm_manager_notifier_register);
+
+       if(confirm_manager_notifier_register)
+       {
+               schedule_delayed_work(&typec_manager.manager_init_work, msecs_to_jiffies(2000));
+       }
+       else
+       {
+               pr_info("%s : done!\n",__func__);
+       }
+
+       pr_info("usb: [M] %s end\n", __func__);
+out:
+       return ret;
+}
+
+static void __exit manager_notifier_exit(void)
+{
+       pr_info("usb: [M] %s exit\n", __func__);
+#if defined(CONFIG_VBUS_NOTIFIER)
+       vbus_notifier_unregister(&typec_manager.vbus_nb);
+#endif
+       ccic_notifier_unregister(&typec_manager.ccic_nb);
+       muic_notifier_unregister(&typec_manager.muic_nb);
+}
+
+late_initcall(manager_notifier_init);
+module_exit(manager_notifier_exit);
+
diff --git a/drivers/usb/notify/Kconfig b/drivers/usb/notify/Kconfig
new file mode 100644 (file)
index 0000000..44dac2f
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# USB notify configuration
+#
+
+comment "USB Notify features"
+config USB_HOST_NOTIFY
+       boolean "USB Host notify Driver"
+       depends on USB_NOTIFY_LAYER
+       help
+         Android framework needs uevents for usb host operation.
+         Host notify Driver serves uevent format
+         that is used by usb host or otg.
+
+config USB_NOTIFY_LAYER
+       boolean "USB notify layer"
+       depends on USB
+       help
+         Added usb notify layer on gadget,host,otg drivers.
+          The usb notify layer controls otg mode and vbus draw
+          and vbus detect irq.
+
+config USB_NOTIFIER
+       boolean "USB notifier"
+       depends on USB_NOTIFY_LAYER
+       help
+         Added platform driver to call usb notify.
+         The usb_notifier.c can be fixed for each models.
+
+config USB_DEBUG_DETAILED_LOG
+       boolean "USB detailed log for debugging"
+       depends on USB
+       help
+         Add detailed log for debugging.
+
+config USB_STORAGE_DETECT
+       boolean "USB storage detect function"
+       depends on USB && SCSI
+       depends on USB_STORAGE
+       help
+         This feature enables to detect inserting or removing
+          sd card in sd reader device.
+          This must to be defined in /usb/storage/Kconfig 
+          directory originally. But this feature is defined
+          in this Kconfig to gather samsung feature about usb host.
+
+config USB_HMT_SAMSUNG_INPUT
+       boolean "USB HMT inputs for samsung hmt devices"
+       depends on HID
+       help
+         Some samsung smart phones support gear vr.
+          The samsung gear vr need some special hid input codes.
+          This feature enables special hid input codes.
+
+config USB_EXTERNAL_NOTIFY
+       boolean "USB external notify"
+       depends on USB_NOTIFY_LAYER
+       help
+         Added usb external notify.
+         The usb external notify broadcast special situation
+         to muic and charger.
+
+config USB_NOTIFY_PROC_LOG
+       boolean "USB proc log"
+       depends on USB_NOTIFY_LAYER
+       depends on USB_HOST_NOTIFY
+       help
+         Added proc usblog.
+         The USB STATE, The USB MODE, Cable event 
+         are saved in usblog heap.
+
+config USB_HOST_SAMSUNG_FEATURE
+       boolean "USB Host Samsung Feature"
+       depends on USB
+       help
+         USB Host Samsung Feature.
+         It is different from LSI BSP code.
+
+config USB_HW_PARAM
+    boolean "USB H/W Parameter"
+    depends on USB_NOTIFY_LAYER
+    depends on USB_HOST_NOTIFY
+    help
+      Added USB H/W Parameter for DQA Agent.
+      You need more works for USB PDIC driver.
diff --git a/drivers/usb/notify/Makefile b/drivers/usb/notify/Makefile
new file mode 100644 (file)
index 0000000..8da21a7
--- /dev/null
@@ -0,0 +1,9 @@
+
+# usb notify driver
+obj-$(CONFIG_USB_HOST_NOTIFY)          += host_notify_class.o
+obj-$(CONFIG_USB_EXTERNAL_NOTIFY)      += external_notify.o
+obj-$(CONFIG_USB_NOTIFY_PROC_LOG)      += usblog_proc_notify.o
+obj-$(CONFIG_USB_NOTIFY_LAYER)         += usb_notify_layer.o
+usb_notify_layer-y                     := usb_notify.o  usb_notify_sysfs.o dock_notify.o
+obj-$(CONFIG_USB_NOTIFIER)             += usb_notifier.o
+
diff --git a/drivers/usb/notify/dock_notify.c b/drivers/usb/notify/dock_notify.c
new file mode 100644 (file)
index 0000000..e9bb93d
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2015-2017 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+ /* usb notify layer v3.1 */
+
+#define pr_fmt(fmt) "usb_notify: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/usb.h>
+#include <linux/notifier.h>
+#include <linux/version.h>
+#include <linux/usb_notify.h>
+#include "../core/hub.h"
+
+#define SMARTDOCK_INDEX        1
+#define MMDOCK_INDEX   2
+
+struct dev_table {
+       struct usb_device_id dev;
+       int index;
+};
+
+static struct dev_table enable_notify_hub_table[] = {
+       { .dev = { USB_DEVICE(0x0424, 0x2514), },
+          .index = SMARTDOCK_INDEX,
+       }, /* SMART DOCK HUB 1 */
+       { .dev = { USB_DEVICE(0x1a40, 0x0101), },
+          .index = SMARTDOCK_INDEX,
+       }, /* SMART DOCK HUB 2 */
+       { .dev = { USB_DEVICE(0x0424, 0x9512), },
+          .index = MMDOCK_INDEX,
+       }, /* SMSC USB LAN HUB 9512 */
+       {}
+};
+
+static struct dev_table essential_device_table[] = {
+       { .dev = { USB_DEVICE(0x08bb, 0x2704), },
+          .index = SMARTDOCK_INDEX,
+       }, /* TI USB Audio DAC 1 */
+       { .dev = { USB_DEVICE(0x08bb, 0x27c4), },
+          .index = SMARTDOCK_INDEX,
+       }, /* TI USB Audio DAC 2 */
+       { .dev = { USB_DEVICE(0x0424, 0xec00), },
+          .index = MMDOCK_INDEX,
+       }, /* SMSC LAN Driver */
+       {}
+};
+
+static struct dev_table update_autotimer_device_table[] = {
+       { .dev = { USB_DEVICE(0x04e8, 0xa500), },
+          .index = 5, /* 5 sec timer */
+       }, /* GearVR1 */
+       { .dev = { USB_DEVICE(0x04e8, 0xa501), },
+          .index = 5,
+       }, /* GearVR2 */
+       { .dev = { USB_DEVICE(0x04e8, 0xa502), },
+          .index = 5,
+       }, /* GearVR3 */
+       {}
+};
+
+static int check_essential_device(struct usb_device *dev, int index)
+{
+       struct dev_table *id;
+       int ret = 0;
+
+       /* check VID, PID */
+       for (id = essential_device_table; id->dev.match_flags; id++) {
+               if ((id->dev.match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+               (id->dev.match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+               id->dev.idVendor == le16_to_cpu(dev->descriptor.idVendor) &&
+               id->dev.idProduct == le16_to_cpu(dev->descriptor.idProduct) &&
+               id->index == index) {
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int check_gamepad_device(struct usb_device *dev)
+{
+       int ret = 0;
+
+       pr_info("%s : product=%s\n", __func__, dev->product);
+
+       if (!dev->product)
+               return ret;
+
+       if (!strncmp(dev->product, "Gamepad for SAMSUNG", 19))
+               ret = 1;
+
+       return ret;
+}
+
+static int check_lanhub_device(struct usb_device *dev)
+{
+       int ret = 0;
+
+       pr_info("%s : product=%s\n", __func__, dev->product);
+
+       if (!dev->product)
+               return ret;
+
+       if (!strncmp(dev->product, "LAN9512", 8))
+               ret = 1;
+
+       return ret;
+}
+
+static int is_notify_hub(struct usb_device *dev)
+{
+       struct dev_table *id;
+       struct usb_device *hdev;
+       int ret = 0;
+
+       hdev = dev->parent;
+       if (!hdev)
+               goto skip;
+       /* check VID, PID */
+       for (id = enable_notify_hub_table; id->dev.match_flags; id++) {
+               if ((id->dev.match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+               (id->dev.match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+               id->dev.idVendor == le16_to_cpu(hdev->descriptor.idVendor) &&
+               id->dev.idProduct == le16_to_cpu(hdev->descriptor.idProduct)) {
+                       ret = (hdev->parent &&
+                       (hdev->parent == dev->bus->root_hub)) ? id->index : 0;
+                       break;
+               }
+       }
+skip:
+       return ret;
+}
+
+static int get_autosuspend_time(struct usb_device *dev)
+{
+       struct dev_table *id;
+       int ret = 0;
+
+       /* check VID, PID */
+       for (id = update_autotimer_device_table; id->dev.match_flags; id++) {
+               if ((id->dev.match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+               (id->dev.match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+               id->dev.idVendor == le16_to_cpu(dev->descriptor.idVendor) &&
+               id->dev.idProduct == le16_to_cpu(dev->descriptor.idProduct)) {
+                       ret = id->index;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int call_battery_notify(struct usb_device *dev, bool on)
+{
+       struct usb_device *hdev;
+       struct usb_device *udev;
+       struct usb_hub *hub;
+       struct otg_notify *o_notify = get_otg_notify();
+       int index = 0;
+       int count = 0;
+       int port;
+
+       index = is_notify_hub(dev);
+       if (!index)
+               goto skip;
+       if (check_essential_device(dev, index))
+               goto skip;
+
+       hdev = dev->parent;
+       hub = usb_hub_to_struct_hub(hdev);
+       if (!hub)
+               goto skip;
+
+       for (port = 1; port <= hdev->maxchild; port++) {
+               udev = hub->ports[port-1]->child;
+               if (udev) {
+                       if (!check_essential_device(udev, index)) {
+                               if (!on && (udev == dev))
+                                       continue;
+                               else
+                                       count++;
+                       }
+               }
+       }
+
+       pr_info("%s : VID : 0x%x, PID : 0x%x, on=%d, count=%d\n", __func__,
+               dev->descriptor.idVendor, dev->descriptor.idProduct,
+                       on, count);
+       if (on) {
+               if (count == 1) {
+                       if (index == SMARTDOCK_INDEX)
+                               send_otg_notify(o_notify,
+                                       NOTIFY_EVENT_SMTD_EXT_CURRENT, 1);
+                       else if (index == MMDOCK_INDEX)
+                               send_otg_notify(o_notify,
+                                       NOTIFY_EVENT_MMD_EXT_CURRENT, 1);
+               }
+       } else {
+               if (!count) {
+                       if (index == SMARTDOCK_INDEX)
+                               send_otg_notify(o_notify,
+                                       NOTIFY_EVENT_SMTD_EXT_CURRENT, 0);
+                       else if (index == MMDOCK_INDEX)
+                               send_otg_notify(o_notify,
+                                       NOTIFY_EVENT_MMD_EXT_CURRENT, 0);
+               }
+       }
+skip:
+       return 0;
+}
+
+static int call_device_notify(struct usb_device *dev)
+{
+       struct otg_notify *o_notify = get_otg_notify();
+
+       if (dev->bus->root_hub != dev) {
+               pr_info("%s device\n", __func__);
+               send_otg_notify(o_notify, NOTIFY_EVENT_DEVICE_CONNECT, 1);
+
+               if (check_gamepad_device(dev))
+                       send_otg_notify(o_notify,
+                               NOTIFY_EVENT_GAMEPAD_CONNECT, 1);
+               else if (check_lanhub_device(dev))
+                       send_otg_notify(o_notify,
+                               NOTIFY_EVENT_LANHUB_CONNECT, 1);
+               else
+                       ;
+       } else
+               pr_info("%s root hub\n", __func__);
+
+       return 0;
+}
+
+static int update_hub_autosuspend_timer(struct usb_device *dev)
+{
+       struct usb_device *hdev;
+       int time = 0;
+
+       if (!dev)
+               goto skip;
+
+       hdev = dev->parent;
+
+       if (hdev == NULL || dev->bus->root_hub != hdev)
+               goto skip;
+
+       /* hdev is root hub */
+       time = get_autosuspend_time(dev);
+       if (time == hdev->dev.power.autosuspend_delay)
+               goto skip;
+
+       pm_runtime_set_autosuspend_delay(&hdev->dev, time*1000);
+       pr_info("set autosuspend delay time=%d sec\n", time);
+skip:
+       return 0;
+}
+
+static void check_device_speed(struct usb_device *dev, bool on)
+{
+       struct otg_notify *o_notify = get_otg_notify();
+       struct usb_device *hdev;
+       int speed = USB_SPEED_UNKNOWN;
+
+       if (!o_notify) {
+               pr_err("%s otg_notify is null\n", __func__);
+               return;
+       }
+
+       hdev = dev->parent;
+       if (!hdev)
+               return;
+       if (on)
+               speed = dev->speed;
+
+       o_notify->speed = speed;
+
+       switch (speed) {
+       case USB_SPEED_SUPER:
+               pr_info("%s : %s superspeed device\n",
+                       __func__, (on ? "attached" : "detached"));
+               break;
+       case USB_SPEED_HIGH:
+               pr_info("%s : %s highspeed device\n",
+                       __func__, (on ? "attached" : "detached"));
+               break;
+       case USB_SPEED_FULL:
+               pr_info("%s : %s fullspeed device\n",
+                       __func__, (on ? "attached" : "detached"));
+               break;
+       case USB_SPEED_LOW:
+               pr_info("%s : %s lowspeed device\n",
+                       __func__, (on ? "attached" : "detached"));
+               break;
+       }
+}
+
+#if defined(CONFIG_USB_HW_PARAM)
+static int set_hw_param(struct usb_device *dev)
+{
+       struct otg_notify *o_notify = get_otg_notify();
+       int ret = 0;
+       int bInterfaceClass = 0, speed = 0;
+
+       if (o_notify == NULL || dev->config->interface[0] == NULL) {
+               ret =  -EFAULT;
+               goto err;
+       }
+
+       if (dev->bus->root_hub != dev) {
+               bInterfaceClass = dev->config->interface[0]->
+                                       cur_altsetting->desc.bInterfaceClass;
+               speed = dev->speed;
+
+               pr_info("%s USB device connected - Class : 0x%x, speed : 0x%x\n",
+                       __func__, bInterfaceClass, speed);
+
+               if (bInterfaceClass == USB_CLASS_AUDIO)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_AUDIO_COUNT);
+               else if (bInterfaceClass == USB_CLASS_COMM)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_COMM_COUNT);
+               else if (bInterfaceClass == USB_CLASS_HID)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_HID_COUNT);
+               else if (bInterfaceClass == USB_CLASS_PHYSICAL)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_PHYSICAL_COUNT);
+               else if (bInterfaceClass == USB_CLASS_STILL_IMAGE)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_IMAGE_COUNT);
+               else if (bInterfaceClass == USB_CLASS_PRINTER)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_PRINTER_COUNT);
+               else if (bInterfaceClass == USB_CLASS_MASS_STORAGE)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_STORAGE_COUNT);
+               else if (bInterfaceClass == USB_CLASS_HUB)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_HUB_COUNT);
+               else if (bInterfaceClass == USB_CLASS_CDC_DATA)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_CDC_COUNT);
+               else if (bInterfaceClass == USB_CLASS_CSCID)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_CSCID_COUNT);
+               else if (bInterfaceClass == USB_CLASS_CONTENT_SEC)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_CONTENT_COUNT);
+               else if (bInterfaceClass == USB_CLASS_VIDEO)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_VIDEO_COUNT);
+               else if (bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_WIRELESS_COUNT);
+               else if (bInterfaceClass == USB_CLASS_MISC)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_MISC_COUNT);
+               else if (bInterfaceClass == USB_CLASS_APP_SPEC)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_APP_COUNT);
+               else if (bInterfaceClass == USB_CLASS_VENDOR_SPEC)
+                       inc_hw_param(o_notify, USB_HOST_CLASS_VENDOR_COUNT);
+
+               if (speed == USB_SPEED_SUPER)
+                       inc_hw_param(o_notify, USB_HOST_SUPER_SPEED_COUNT);
+               else if (speed == USB_SPEED_HIGH)
+                       inc_hw_param(o_notify, USB_HOST_HIGH_SPEED_COUNT);
+               else if (speed == USB_SPEED_FULL)
+                       inc_hw_param(o_notify, USB_HOST_FULL_SPEED_COUNT);
+               else if (speed == USB_SPEED_LOW)
+                       inc_hw_param(o_notify, USB_HOST_LOW_SPEED_COUNT);
+       }
+err:
+       return ret;
+}
+#endif
+static int dev_notify(struct notifier_block *self,
+                              unsigned long action, void *dev)
+{
+       switch (action) {
+       case USB_DEVICE_ADD:
+               call_device_notify(dev);
+               call_battery_notify(dev, 1);
+               check_device_speed(dev, 1);
+               update_hub_autosuspend_timer(dev);
+#if defined(CONFIG_USB_HW_PARAM)
+               set_hw_param(dev);
+#endif
+               break;
+       case USB_DEVICE_REMOVE:
+               call_battery_notify(dev, 0);
+               check_device_speed(dev, 0);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block dev_nb = {
+       .notifier_call = dev_notify,
+};
+
+void register_usbdev_notify(void)
+{
+       usb_register_notify(&dev_nb);
+}
+EXPORT_SYMBOL(register_usbdev_notify);
+
+void unregister_usbdev_notify(void)
+{
+       usb_unregister_notify(&dev_nb);
+}
+EXPORT_SYMBOL(unregister_usbdev_notify);
+
diff --git a/drivers/usb/notify/dock_notify.h b/drivers/usb/notify/dock_notify.h
new file mode 100644 (file)
index 0000000..b9e90b5
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015-2017 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+  /* usb notify layer v3.1 */
+
+#ifndef __LINUX_DOCK_NOTIFY_H__
+#define __LINUX_DOCK_NOTIFY_H__
+
+extern void register_usbdev_notify(void);
+extern void unregister_usbdev_notify(void);
+#endif
+
diff --git a/drivers/usb/notify/external_notify.c b/drivers/usb/notify/external_notify.c
new file mode 100644 (file)
index 0000000..917c97c
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016-2017 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+ /* usb notify layer v3.1 */
+
+#define pr_fmt(fmt) "usb_notify: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/usb.h>
+#include <linux/usb_notify.h>
+
+struct external_notify_struct {
+       struct blocking_notifier_head notifier_call_chain;
+       int call_chain_init;
+};
+
+#define SET_EXTERNAL_NOTIFY_BLOCK(nb, fn, dev) do {    \
+               (nb)->notifier_call = (fn);             \
+               (nb)->priority = (dev);                 \
+       } while (0)
+
+#define DESTROY_EXTERNAL_NOTIFY_BLOCK(nb)                      \
+               SET_EXTERNAL_NOTIFY_BLOCK(nb, NULL, -1)
+
+static struct external_notify_struct external_notifier;
+
+static const char *cmd_string(unsigned long cmd)
+{
+       switch (cmd) {
+       case EXTERNAL_NOTIFY_3S_NODEVICE:
+               return "3s_no_device";
+       case EXTERNAL_NOTIFY_DEVICE_CONNECT:
+               return "device_connect";
+       case EXTERNAL_NOTIFY_HOSTBLOCK_PRE:
+               return "host_block_pre";
+       case EXTERNAL_NOTIFY_HOSTBLOCK_POST:
+               return "host_block_post";
+       case EXTERNAL_NOTIFY_MDMBLOCK_PRE:
+               return "mdm_block_pre";
+       case EXTERNAL_NOTIFY_MDMBLOCK_POST:
+               return "mdm_block_post";
+       case EXTERNAL_NOTIFY_POWERROLE:
+               return "power_role_notify";
+       default:
+               return "undefined";
+       }
+}
+
+static const char *listener_string(int  listener)
+{
+       switch (listener) {
+       case EXTERNAL_NOTIFY_DEV_MUIC:
+               return "muic";
+       case EXTERNAL_NOTIFY_DEV_CHARGER:
+               return "charger";
+       case EXTERNAL_NOTIFY_DEV_PDIC:
+               return "pdic";
+       default:
+               return "undefined";
+       }
+}
+
+static int create_external_notify(void)
+{
+       if (!external_notifier.call_chain_init) {
+               pr_info("%s\n", __func__);
+               BLOCKING_INIT_NOTIFIER_HEAD
+                               (&(external_notifier.notifier_call_chain));
+               external_notifier.call_chain_init = 1;
+       }
+       return 0;
+}
+
+int usb_external_notify_register(struct notifier_block *nb,
+                       notifier_fn_t notifier, int listener)
+{
+       int ret = 0;
+
+       pr_info("%s: listener=(%s)%d register\n", __func__,
+                       listener_string(listener), listener);
+
+       create_external_notify();
+
+       SET_EXTERNAL_NOTIFY_BLOCK(nb, notifier, listener);
+       ret = blocking_notifier_chain_register
+                               (&(external_notifier.notifier_call_chain), nb);
+       if (ret < 0)
+               pr_err("%s: blocking_notifier_chain_register error(%d)\n",
+                               __func__, ret);
+
+       return ret;
+}
+
+int usb_external_notify_unregister(struct notifier_block *nb)
+{
+       int ret = 0;
+
+       pr_info("%s: listener=(%s)%d unregister\n", __func__,
+                       listener_string(nb->priority),
+                               nb->priority);
+
+       ret = blocking_notifier_chain_unregister
+                               (&(external_notifier.notifier_call_chain), nb);
+       if (ret < 0)
+               pr_err("%s: blocking_notifier_chain_unregister error(%d)\n",
+                               __func__, ret);
+       DESTROY_EXTERNAL_NOTIFY_BLOCK(nb);
+
+       return ret;
+}
+
+int send_external_notify(unsigned long cmd, int data)
+{
+       int ret = 0;
+
+       pr_info("%s: cmd=%s(%lu), data=%d\n", __func__, cmd_string(cmd),
+                                               cmd, data);
+
+       create_external_notify();
+
+       ret = blocking_notifier_call_chain
+               (&(external_notifier.notifier_call_chain),
+                       cmd, (void *)&(data));
+
+       switch (ret) {
+       case NOTIFY_STOP_MASK:
+       case NOTIFY_BAD:
+               pr_err("%s: notify error occur(0x%x)\n", __func__, ret);
+               break;
+       case NOTIFY_DONE:
+       case NOTIFY_OK:
+               pr_info("%s: notify done(0x%x)\n", __func__, ret);
+               break;
+       default:
+               pr_info("%s: notify status unknown(0x%x)\n", __func__, ret);
+               break;
+       }
+
+       return ret;
+}
+
+static int __init external_notifier_init(void)
+{
+       int ret = 0;
+
+       pr_info("%s\n", __func__);
+       create_external_notify();
+
+       return ret;
+}
+module_init(external_notifier_init);
diff --git a/drivers/usb/notify/host_notify_class.c b/drivers/usb/notify/host_notify_class.c
new file mode 100644 (file)
index 0000000..2db648c
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ *  drivers/usb/notify/host_notify_class.c
+ *
+ * Copyright (C) 2011-2017 Samsung, Inc.
+ * Author: Dongrak Shin <dongrak.shin@samsung.com>
+ *
+*/
+
+ /* usb notify layer v3.1 */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/host_notify.h>
+#if defined(CONFIG_USB_HW_PARAM)
+#include <linux/usb_notify.h>
+#endif
+
+struct notify_data {
+       struct class *host_notify_class;
+       atomic_t device_count;
+};
+
+static struct notify_data host_notify;
+
+static ssize_t mode_show(
+       struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct host_notify_dev *ndev = (struct host_notify_dev *)
+               dev_get_drvdata(dev);
+       char *mode;
+
+       switch (ndev->mode) {
+       case NOTIFY_HOST_MODE:
+               mode = "HOST";
+               break;
+       case NOTIFY_PERIPHERAL_MODE:
+               mode = "PERIPHERAL";
+               break;
+       case NOTIFY_TEST_MODE:
+               mode = "TEST";
+               break;
+       case NOTIFY_NONE_MODE:
+       default:
+               mode = "NONE";
+               break;
+       }
+
+       return snprintf(buf, sizeof(mode)+1, "%s\n", mode);
+}
+
+static ssize_t mode_store(
+               struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct host_notify_dev *ndev = (struct host_notify_dev *)
+               dev_get_drvdata(dev);
+
+       char *mode;
+       size_t ret = -ENOMEM;
+       int sret = 0;
+
+       mode = kzalloc(size+1, GFP_KERNEL);
+       if (!mode)
+               goto error;
+
+       sret = sscanf(buf, "%s", mode);
+       if (sret != 1)
+               goto error1;
+
+       if (ndev->set_mode) {
+               pr_info("host_notify: set mode %s\n", mode);
+               if (!strncmp(mode, "HOST", 4))
+                       ndev->set_mode(NOTIFY_SET_ON);
+               else if (!strncmp(mode, "NONE", 4))
+                       ndev->set_mode(NOTIFY_SET_OFF);
+       }
+       ret = size;
+error1:
+       kfree(mode);
+error:
+       return ret;
+}
+
+static ssize_t booster_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct host_notify_dev *ndev = (struct host_notify_dev *)
+               dev_get_drvdata(dev);
+       char *booster;
+
+       switch (ndev->booster) {
+       case NOTIFY_POWER_ON:
+               booster = "ON";
+               break;
+       case NOTIFY_POWER_OFF:
+       default:
+               booster = "OFF";
+               break;
+       }
+
+       pr_info("host_notify: read booster %s\n", booster);
+       return snprintf(buf,  sizeof(booster)+1, "%s\n", booster);
+}
+
+static ssize_t booster_store(
+               struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct host_notify_dev *ndev = (struct host_notify_dev *)
+               dev_get_drvdata(dev);
+
+       char *booster;
+       size_t ret = -ENOMEM;
+       int sret = 0;
+
+       booster = kzalloc(size+1, GFP_KERNEL);
+       if (!booster)
+               goto error;
+
+       sret = sscanf(buf, "%s", booster);
+       if (sret != 1)
+               goto error1;
+
+       if (ndev->set_booster) {
+               pr_info("host_notify: set booster %s\n", booster);
+               if (!strncmp(booster, "ON", 2)) {
+                       ndev->set_booster(NOTIFY_SET_ON);
+                       ndev->mode = NOTIFY_TEST_MODE;
+               } else if (!strncmp(booster, "OFF", 3)) {
+                       ndev->set_booster(NOTIFY_SET_OFF);
+                       ndev->mode = NOTIFY_NONE_MODE;
+               }
+       }
+       ret = size;
+error1:
+       kfree(booster);
+error:
+       return ret;
+}
+
+static DEVICE_ATTR(mode, 0664, mode_show, mode_store);
+static DEVICE_ATTR(booster, 0664, booster_show, booster_store);
+
+static struct attribute *host_notify_attrs[] = {
+       &dev_attr_mode.attr,
+       &dev_attr_booster.attr,
+       NULL,
+};
+
+static struct attribute_group host_notify_attr_grp = {
+       .attrs = host_notify_attrs,
+};
+
+char *host_state_string(int type)
+{
+       switch (type) {
+       case NOTIFY_HOST_NONE:                  return "none";
+       case NOTIFY_HOST_ADD:                   return "add";
+       case NOTIFY_HOST_REMOVE:                return "remove";
+       case NOTIFY_HOST_OVERCURRENT:   return "overcurrent";
+       case NOTIFY_HOST_LOWBATT:               return "lowbatt";
+       case NOTIFY_HOST_BLOCK:                 return "block";
+       case NOTIFY_HOST_UNKNOWN:
+       default:        return "unknown";
+       }
+}
+
+int host_state_notify(struct host_notify_dev *ndev, int state)
+{
+       pr_info("host_notify: ndev name=%s: (%s --> %s)\n",
+               ndev->name,
+               host_state_string(ndev->state),
+               host_state_string(state));
+
+       if (ndev->state != state) {
+               ndev->state = state;
+               if (state != NOTIFY_HOST_NONE)
+                       kobject_uevent(&ndev->dev->kobj, KOBJ_CHANGE);
+#if defined(CONFIG_USB_HW_PARAM)
+               if (state == NOTIFY_HOST_ADD)
+                       inc_hw_param_host(ndev, USB_CCIC_OTG_USE_COUNT);
+               else if (state == NOTIFY_HOST_OVERCURRENT)
+                       inc_hw_param_host(ndev, USB_CCIC_OVC_COUNT);
+               else
+                       ;
+#endif
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(host_state_notify);
+
+static int
+host_notify_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct host_notify_dev *ndev = (struct host_notify_dev *)
+               dev_get_drvdata(dev);
+       char *state;
+
+       if (!ndev) {
+               /* this happens when the device is first created */
+               return 0;
+       }
+       switch (ndev->state) {
+       case NOTIFY_HOST_ADD:
+               state = "ADD";
+               break;
+       case NOTIFY_HOST_REMOVE:
+               state = "REMOVE";
+               break;
+       case NOTIFY_HOST_OVERCURRENT:
+               state = "OVERCURRENT";
+               break;
+       case NOTIFY_HOST_LOWBATT:
+               state = "LOWBATT";
+               break;
+       case NOTIFY_HOST_BLOCK:
+               state = "BLOCK";
+               break;
+       case NOTIFY_HOST_UNKNOWN:
+               state = "UNKNOWN";
+               break;
+       case NOTIFY_HOST_NONE:
+       default:
+               return 0;
+       }
+       if (add_uevent_var(env, "DEVNAME=%s", ndev->dev->kobj.name))
+               return -ENOMEM;
+       if (add_uevent_var(env, "STATE=%s", state))
+               return -ENOMEM;
+       return 0;
+}
+
+static int create_notify_class(void)
+{
+       if (!host_notify.host_notify_class) {
+               host_notify.host_notify_class
+                       = class_create(THIS_MODULE, "host_notify");
+               if (IS_ERR(host_notify.host_notify_class))
+                       return PTR_ERR(host_notify.host_notify_class);
+               atomic_set(&host_notify.device_count, 0);
+               host_notify.host_notify_class->dev_uevent = host_notify_uevent;
+       }
+
+       return 0;
+}
+
+int host_notify_dev_register(struct host_notify_dev *ndev)
+{
+       int ret;
+
+       if (!host_notify.host_notify_class) {
+               ret = create_notify_class();
+               if (ret < 0)
+                       return ret;
+       }
+
+       ndev->index = atomic_inc_return(&host_notify.device_count);
+       ndev->dev = device_create(host_notify.host_notify_class, NULL,
+               MKDEV(0, ndev->index), NULL, ndev->name);
+       if (IS_ERR(ndev->dev))
+               return PTR_ERR(ndev->dev);
+
+       ret = sysfs_create_group(&ndev->dev->kobj, &host_notify_attr_grp);
+       if (ret < 0) {
+               device_destroy(host_notify.host_notify_class,
+                               MKDEV(0, ndev->index));
+               return ret;
+       }
+
+       dev_set_drvdata(ndev->dev, ndev);
+       ndev->state = 0;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(host_notify_dev_register);
+
+void host_notify_dev_unregister(struct host_notify_dev *ndev)
+{
+       ndev->state = NOTIFY_HOST_NONE;
+       sysfs_remove_group(&ndev->dev->kobj, &host_notify_attr_grp);
+       device_destroy(host_notify.host_notify_class, MKDEV(0, ndev->index));
+       dev_set_drvdata(ndev->dev, NULL);
+}
+EXPORT_SYMBOL_GPL(host_notify_dev_unregister);
+
+static int __init notify_class_init(void)
+{
+       return create_notify_class();
+}
+
+static void __exit notify_class_exit(void)
+{
+       class_destroy(host_notify.host_notify_class);
+}
+
+module_init(notify_class_init);
+module_exit(notify_class_exit);
+
+MODULE_AUTHOR("Dongrak Shin <dongrak.shin@samsung.com>");
+MODULE_DESCRIPTION("Usb host notify driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/notify/usb_notifier.c b/drivers/usb/notify/usb_notifier.c
new file mode 100644 (file)
index 0000000..c54c440
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co. Ltd.
+ *  Inchul Im <inchul.im@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#define pr_fmt(fmt) "usb_notifier: " fmt
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/usb_notify.h>
+#ifdef CONFIG_OF
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#endif
+#if defined(CONFIG_IFCONN_NOTIFIER)
+#include <linux/ifconn/ifconn_notifier.h>
+#endif
+#if defined(CONFIG_CCIC_NOTIFIER)
+#include <linux/ccic/ccic_notifier.h>
+#endif
+#if defined(CONFIG_MUIC_NOTIFIER) || defined(CONFIG_IFCONN_NOTIFIER)
+#include <linux/muic/muic.h>
+#endif
+#if defined(CONFIG_MUIC_NOTIFIER)
+#include <linux/muic/muic_notifier.h>
+#endif
+#if defined(CONFIG_VBUS_NOTIFIER)
+#include <linux/vbus_notifier.h>
+#endif
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+#include <linux/usb/manager/usb_typec_manager_notifier.h>
+#endif
+#if defined(CONFIG_BATTERY_SAMSUNG_V2)
+#include "../../battery_v2/include/sec_charging_common.h"
+#else
+#include <linux/battery/sec_charging_common.h>
+#endif
+#include "usb_notifier.h"
+
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+
+struct usb_notifier_platform_data {
+#if defined(CONFIG_CCIC_NOTIFIER) || defined(CONFIG_IFCONN_NOTIFIER)
+       struct  notifier_block ccic_usb_nb;
+       int is_host;
+#endif
+#if defined(CONFIG_MUIC_NOTIFIER) || defined(CONFIG_IFCONN_NOTIFIER)
+       struct  notifier_block muic_usb_nb;
+#endif
+#if defined(CONFIG_VBUS_NOTIFIER) || defined(CONFIG_IFCONN_NOTIFIER)
+       struct  notifier_block vbus_nb;
+#endif
+       int     gpio_redriver_en;
+       int can_disable_usb;
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+       struct delayed_work usb_ldo_work;
+       unsigned int usb_ldocontrol;
+       unsigned int usb_ldo_onoff;
+       bool usb_ldo_off_working;
+       const char *hs_vdd;
+       const char *ss_vdd;
+       const char *dp_vdd;
+#endif
+};
+
+#ifdef CONFIG_OF
+static void of_get_usb_redriver_dt(struct device_node *np,
+               struct usb_notifier_platform_data *pdata)
+{
+       int gpio = 0;
+
+       gpio = of_get_named_gpio(np, "gpios_redriver_en", 0);
+       if (!gpio_is_valid(gpio)) {
+               pdata->gpio_redriver_en = -1;
+               pr_err("%s: usb30_redriver_en: Invalied gpio pins\n", __func__);
+       } else
+               pdata->gpio_redriver_en = gpio;
+
+       pr_info("%s, gpios_redriver_en %d\n", __func__, gpio);
+
+       pdata->can_disable_usb =
+               !(of_property_read_bool(np, "samsung,unsupport-disable-usb"));
+       pr_info("%s, can_disable_usb %d\n", __func__, pdata->can_disable_usb);
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+       if (of_property_read_string(np, "hs-regulator", &pdata->hs_vdd) < 0) {
+               pr_err("%s - get hs_vdd error\n", __func__);
+               pdata->hs_vdd = NULL;
+       }
+       if (of_property_read_string(np, "ss-regulator", &pdata->ss_vdd) < 0) {
+               pr_err("%s - get ss_vdd error\n", __func__);
+               pdata->ss_vdd = NULL;
+       }
+       if (of_property_read_string(np, "dp-regulator", &pdata->dp_vdd) < 0) {
+               pr_err("%s - get dp_vdd error\n", __func__);
+               pdata->dp_vdd = NULL;
+       }
+
+       if (of_property_read_u32(np, "usb-ldocontrol", &pdata->usb_ldocontrol))
+               pdata->usb_ldocontrol = 0;
+
+       pr_info("%s, usb_ldocontrol %d\n", __func__, pdata->usb_ldocontrol);
+#endif
+}
+
+static int of_usb_notifier_dt(struct device *dev,
+               struct usb_notifier_platform_data *pdata)
+{
+       struct device_node *np = dev->of_node;
+
+       if (!np)
+               return -EINVAL;
+
+       of_get_usb_redriver_dt(np, pdata);
+       return 0;
+}
+#endif
+
+static struct device_node *exynos_udc_parse_dt(void)
+{
+       struct platform_device *pdev = NULL;
+       struct device *dev = NULL;
+       struct device_node *np = NULL;
+
+       /**
+        * For previous chips such as Exynos7420 and Exynos7890
+       */
+       np = of_find_compatible_node(NULL, NULL, "samsung,exynos5-dwusb3");
+       if (np)
+               goto find;
+
+       np = of_find_compatible_node(NULL, NULL, "samsung,usb-notifier");
+       if (!np) {
+               pr_err("%s: failed to get the usb-notifier device node\n",
+                       __func__);
+               goto err;
+       }
+
+       pdev = of_find_device_by_node(np);
+       if (!pdev) {
+               pr_err("%s: failed to get platform_device\n", __func__);
+               goto err;
+       }
+
+       dev = &pdev->dev;
+       np = of_parse_phandle(dev->of_node, "udc", 0);
+       if (!np) {
+               dev_info(dev, "udc device is not available\n");
+               goto err;
+       }
+find:
+       return np;
+err:
+       return NULL;
+}
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+static void usb_hs_regulator_onoff(struct usb_notifier_platform_data *pdata,
+                                  unsigned int onoff)
+{
+       struct regulator *avdd33_usb;
+       int ret;
+
+       if (!pdata->hs_vdd) {
+               pr_err("%s hs_vdd is null\n", __func__);
+               return;
+       }
+
+       avdd33_usb = regulator_get(NULL, pdata->hs_vdd);
+       if (IS_ERR(avdd33_usb) || avdd33_usb == NULL) {
+               pr_err("%s - avdd33_usb regulator_get fail\n", __func__);
+               return;
+       }
+
+       if (onoff) {
+               ret = regulator_enable(avdd33_usb);
+               if (ret) {
+                       pr_err("%s - enable avdd33_usb ldo enable failed, ret=%d\n",
+                               __func__, ret);
+               }
+       } else {
+               ret = regulator_disable(avdd33_usb);
+               if (ret) {
+                       pr_err("%s - enable avdd33_usb ldo disable failed, ret=%d\n",
+                               __func__, ret);
+               }
+       }
+
+       regulator_put(avdd33_usb);
+}
+
+static void usb_ss_regulator_onoff(struct usb_notifier_platform_data *pdata,
+                                  bool onoff)
+{
+       struct regulator *vdd085_usb;
+       int ret;
+
+       if (!pdata->ss_vdd) {
+               pr_err("%s ss_vdd is null\n", __func__);
+               return;
+       }
+
+       vdd085_usb = regulator_get(NULL, pdata->ss_vdd);
+       if (IS_ERR(vdd085_usb) || vdd085_usb == NULL) {
+               pr_err("%s - vdd085_usb regulator_get fail\n", __func__);
+               return;
+       }
+
+       if (onoff) {
+               ret = regulator_enable(vdd085_usb);
+               if (ret) {
+                       pr_err("%s - enable vdd085_usb ldo enable failed, ret=%d\n",
+                               __func__, ret);
+               }
+       } else {
+               ret = regulator_disable(vdd085_usb);
+               if (ret) {
+                       pr_err("%s - enable vdd085_usb ldo disable failed, ret=%d\n",
+                               __func__, ret);
+               }
+       }
+
+       regulator_put(vdd085_usb);
+}
+
+static void usb_dp_regulator_onoff(struct usb_notifier_platform_data *pdata,
+                                  unsigned int onoff)
+{
+       struct regulator *vdd3p3_dp;
+       int ret;
+
+       if (!pdata->dp_vdd) {
+               pr_err("%s dp_vdd is null\n", __func__);
+               return;
+       }
+
+       vdd3p3_dp = regulator_get(NULL, pdata->dp_vdd);
+       if (IS_ERR(vdd3p3_dp) || vdd3p3_dp == NULL) {
+               pr_err("%s - dp_3p3 regulator_get fail\n", __func__);
+               return;
+       }
+
+       if (onoff) {
+               ret = regulator_enable(vdd3p3_dp);
+               if (ret) {
+                       pr_err("%s - enable dp_3p3 ldo enable failed, ret=%d\n",
+                               __func__, ret);
+               }
+       } else {
+               ret = regulator_disable(vdd3p3_dp);
+               if (ret) {
+                       pr_err("%s - enable dp_3p3 ldo disable failed, ret=%d\n",
+                               __func__, ret);
+               }
+       }
+
+       regulator_put(vdd3p3_dp);
+}
+
+static void usb_regulator_onoff(void *data, unsigned int onoff)
+{
+       struct usb_notifier_platform_data *pdata =
+               (struct usb_notifier_platform_data *)(data);
+       pr_info("usb: %s - Turn %s (ldocontrol=%d, usb_ldo_off_working=%d)\n", __func__,
+               onoff ? "on":"off", pdata->usb_ldocontrol, pdata->usb_ldo_off_working);
+
+       if (pdata->usb_ldocontrol) {
+               if (onoff) {
+                       if (!pdata->usb_ldo_onoff) {
+                               if (pdata->usb_ldo_off_working) {
+                                       cancel_delayed_work_sync(&pdata->usb_ldo_work);
+                                       pdata->usb_ldo_off_working = false;
+                               } else {
+                                       usb_ss_regulator_onoff(pdata, onoff);
+                                       usb_dp_regulator_onoff(pdata, onoff);
+                                       usb_hs_regulator_onoff(pdata, onoff);
+                               }
+                       } else {
+                               pr_err("%s already on\n", __func__);
+                       }
+               } else {
+                       if (pdata->usb_ldo_onoff) {
+                               pdata->usb_ldo_off_working = true;
+                               schedule_delayed_work(&pdata->usb_ldo_work, msecs_to_jiffies(2000));
+                       } else {
+                               pr_err("%s already off\n", __func__);
+                       }
+               }
+               pdata->usb_ldo_onoff = onoff;
+       } else {
+               pr_err("%s: can't control\n", __func__);
+       }
+}
+
+static void usb_ldo_off_control(struct work_struct *work)
+{
+       struct usb_notifier_platform_data *pdata = container_of(work,
+                                                struct usb_notifier_platform_data,
+                                                usb_ldo_work.work);
+
+       pr_info("usb: %s - working=%d\n", __func__, pdata->usb_ldo_off_working);
+       if (pdata->usb_ldo_off_working) {
+               pdata->usb_ldo_off_working = false;
+               usb_hs_regulator_onoff(pdata, false);
+               usb_dp_regulator_onoff(pdata, false);
+               usb_ss_regulator_onoff(pdata, false);
+       }
+}
+#endif
+
+static void check_usb_vbus_state(int state)
+{
+       struct device_node *np = NULL;
+       struct platform_device *pdev = NULL;
+
+       pr_info("%s vbus state = %d\n", __func__, state);
+
+       np = exynos_udc_parse_dt();
+       if (np) {
+               pdev = of_find_device_by_node(np);
+               of_node_put(np);
+               if (pdev) {
+                       pr_info("%s: get the %s platform_device\n",
+                               __func__, pdev->name);
+                       dwc3_exynos_vbus_event(&pdev->dev, state);
+                       goto end;
+               }
+       }
+
+       pr_err("%s: failed to get the platform_device\n", __func__);
+end:
+       return;
+}
+
+static void check_usb_id_state(int state)
+{
+       struct device_node *np = NULL;
+       struct platform_device *pdev = NULL;
+
+       pr_info("%s id state = %d\n", __func__, state);
+
+       np = exynos_udc_parse_dt();
+       if (np) {
+               pdev = of_find_device_by_node(np);
+               of_node_put(np);
+               if (pdev) {
+                       pr_info("%s: get the %s platform_device\n",
+                       __func__, pdev->name);
+                       dwc3_exynos_id_event(&pdev->dev, state);
+                       goto end;
+               }
+       }
+       pr_err("%s: failed to get the platform_device\n", __func__);
+end:
+       return;
+}
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+static int ccic_usb_handle_notification(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+       struct ifconn_notifier_template usb_status = *(struct ifconn_notifier_template *)data;
+       struct otg_notify *o_notify = get_otg_notify();
+       struct usb_notifier_platform_data *pdata =
+               container_of(nb, struct usb_notifier_platform_data, ccic_usb_nb);
+
+       if(usb_status.dest != IFCONN_NOTIFY_USB) {
+               return 0;
+       }
+
+       switch (usb_status.event){
+               case IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP:
+                       pr_info("%s: Turn On Host(DFP)\n", __func__);
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HOST, 1);
+                       pdata->is_host = 1;
+                       break;
+               case IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP:
+                       pr_info("%s: Turn On Device(UFP)\n", __func__);
+                       send_otg_notify(o_notify, NOTIFY_EVENT_VBUS, 1);
+                       if(is_blocked(o_notify, NOTIFY_BLOCK_TYPE_CLIENT))
+                               return -EPERM;
+                       break;
+               case IFCONN_NOTIFY_EVENT_DETACH:
+                       if(pdata->is_host) {
+                               pr_info("%s: Turn Off Host(DFP)\n", __func__);
+                               send_otg_notify(o_notify, NOTIFY_EVENT_HOST, 0);
+                               pdata->is_host = 0;
+                       } else {
+                               pr_info("%s: Turn Off Device(UFP)\n", __func__);
+                               send_otg_notify(o_notify, NOTIFY_EVENT_VBUS, 0);
+                       }
+                       break;
+               default:
+                       pr_info("%s: unsupported DRP type : %d.\n", __func__, usb_status.drp);
+                       break;
+               }
+       return 0;
+}
+
+static int muic_usb_handle_notification(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+       struct ifconn_notifier_template *p_noti = (struct ifconn_notifier_template *)data;
+       muic_attached_dev_t attached_dev = (muic_attached_dev_t)p_noti->event;
+       struct otg_notify *o_notify = get_otg_notify();
+
+       pr_info("%s action=%lu, attached_dev=%d\n",
+               __func__, action, attached_dev);
+
+       switch (attached_dev) {
+       case ATTACHED_DEV_USB_MUIC:
+       case ATTACHED_DEV_CDP_MUIC:
+       case ATTACHED_DEV_UNOFFICIAL_ID_USB_MUIC:
+       case ATTACHED_DEV_UNOFFICIAL_ID_CDP_MUIC:
+       case ATTACHED_DEV_JIG_USB_OFF_MUIC:
+       case ATTACHED_DEV_JIG_USB_ON_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_VBUS, 0);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_VBUS, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_OTG_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HOST, 0);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HOST, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_HMT_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HMT, 0);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HMT, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       pr_info("%s - USB_HOST_TEST_DETACHED\n", __func__);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       pr_info("%s - USB_HOST_TEST_ATTACHED\n", __func__);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_SMARTDOCK_TA_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_SMARTDOCK_TA, 0);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_SMARTDOCK_TA, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_SMARTDOCK_USB_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       send_otg_notify
+                               (o_notify, NOTIFY_EVENT_SMARTDOCK_USB, 0);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       send_otg_notify
+                               (o_notify, NOTIFY_EVENT_SMARTDOCK_USB, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_AUDIODOCK_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_AUDIODOCK, 0);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_AUDIODOCK, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_UNIVERSAL_MMDOCK_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_MMDOCK, 0);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_MMDOCK, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_USB_LANHUB_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_LANHUB, 0);
+               else if (action == IFCONN_NOTIFY_ID_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_LANHUB, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_GAMEPAD_MUIC:
+               if (action == IFCONN_NOTIFY_ID_DETACH) {
+                       send_otg_notify(o_notify, NOTIFY_EVENT_GAMEPAD, 0);
+               } else if (action == IFCONN_NOTIFY_ID_ATTACH) {
+                       send_otg_notify(o_notify, NOTIFY_EVENT_GAMEPAD, 1);
+               } else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int vbus_handle_notification(struct notifier_block *nb,
+               unsigned long cmd, void *data)
+{
+       struct ifconn_notifier_template *p_noti = (struct ifconn_notifier_template *)data;
+       ifconn_notifier_vbus_t vbus_type = p_noti->vbus_type;
+       struct otg_notify *o_notify;
+
+       o_notify = get_otg_notify();
+
+       pr_info("%s cmd=%lu, vbus_type=%s\n",
+               __func__, cmd, vbus_type == IFCONN_NOTIFY_VBUS_HIGH ? "HIGH" : "LOW");
+       if (vbus_type == IFCONN_NOTIFY_VBUS_HIGH) {
+               send_otg_notify(o_notify, NOTIFY_EVENT_VBUSPOWER, 1);
+       } else if (vbus_type == IFCONN_NOTIFY_VBUS_LOW) {
+               send_otg_notify(o_notify, NOTIFY_EVENT_VBUSPOWER, 0);
+       }
+       return 0;
+}
+
+static int otg_accessory_power(bool enable)
+{
+#if !defined(CONFIG_CCIC_S2MM005)
+       u8 on = (u8)!!enable;
+       union power_supply_propval val;
+
+       pr_info("otg accessory power = %d\n", on);
+
+       val.intval = enable;
+       psy_do_property("otg", set,
+                       POWER_SUPPLY_PROP_ONLINE, val);
+#endif
+       return 0;
+}
+#else
+#if defined(CONFIG_CCIC_NOTIFIER)
+static int ccic_usb_handle_notification(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+       CC_NOTI_USB_STATUS_TYPEDEF usb_status = *(CC_NOTI_USB_STATUS_TYPEDEF *)data;
+       struct otg_notify *o_notify = get_otg_notify();
+       struct usb_notifier_platform_data *pdata =
+               container_of(nb, struct usb_notifier_platform_data, ccic_usb_nb);
+
+       if (usb_status.dest != CCIC_NOTIFY_DEV_USB)
+               return 0;
+
+       switch (usb_status.drp) {
+       case USB_STATUS_NOTIFY_ATTACH_DFP:
+               pr_info("%s: Turn On Host(DFP)\n", __func__);
+               send_otg_notify(o_notify, NOTIFY_EVENT_HOST, 1);
+               pdata->is_host = 1;
+               break;
+       case USB_STATUS_NOTIFY_ATTACH_UFP:
+               pr_info("%s: Turn On Device(UFP)\n", __func__);
+               send_otg_notify(o_notify, NOTIFY_EVENT_VBUS, 1);
+               if (is_blocked(o_notify, NOTIFY_BLOCK_TYPE_CLIENT))
+                       return -EPERM;
+               break;
+       case USB_STATUS_NOTIFY_DETACH:
+               if (pdata->is_host) {
+                       pr_info("%s: Turn Off Host(DFP)\n", __func__);
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HOST, 0);
+                       pdata->is_host = 0;
+               } else {
+                       pr_info("%s: Turn Off Device(UFP)\n", __func__);
+                       send_otg_notify(o_notify, NOTIFY_EVENT_VBUS, 0);
+               }
+               break;
+       default:
+               pr_info("%s: unsupported DRP type : %d.\n", __func__, usb_status.drp);
+               break;
+       }
+       return 0;
+}
+#endif
+#if defined(CONFIG_MUIC_NOTIFIER)
+static int muic_usb_handle_notification(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+#ifdef CONFIG_CCIC_NOTIFIER
+       CC_NOTI_ATTACH_TYPEDEF *p_noti = (CC_NOTI_ATTACH_TYPEDEF *)data;
+       muic_attached_dev_t attached_dev = p_noti->cable_type;
+#else
+       muic_attached_dev_t attached_dev = *(muic_attached_dev_t *)data;
+#endif
+       struct otg_notify *o_notify = get_otg_notify();
+
+       pr_info("%s action=%lu, attached_dev=%d\n",
+               __func__, action, attached_dev);
+
+       switch (attached_dev) {
+       case ATTACHED_DEV_USB_MUIC:
+       case ATTACHED_DEV_CDP_MUIC:
+       case ATTACHED_DEV_UNOFFICIAL_ID_USB_MUIC:
+       case ATTACHED_DEV_UNOFFICIAL_ID_CDP_MUIC:
+       case ATTACHED_DEV_JIG_USB_OFF_MUIC:
+       case ATTACHED_DEV_JIG_USB_ON_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_VBUS, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_VBUS, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_OTG_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HOST, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HOST, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_HMT_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HMT, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_HMT, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       pr_info("%s - USB_HOST_TEST_DETACHED\n", __func__);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       pr_info("%s - USB_HOST_TEST_ATTACHED\n", __func__);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_SMARTDOCK_TA_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_SMARTDOCK_TA, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_SMARTDOCK_TA, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_SMARTDOCK_USB_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify
+                               (o_notify, NOTIFY_EVENT_SMARTDOCK_USB, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify
+                               (o_notify, NOTIFY_EVENT_SMARTDOCK_USB, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_AUDIODOCK_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_AUDIODOCK, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_AUDIODOCK, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_UNIVERSAL_MMDOCK_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_MMDOCK, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_MMDOCK, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_USB_LANHUB_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_LANHUB, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_LANHUB, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       case ATTACHED_DEV_GAMEPAD_MUIC:
+               if (action == MUIC_NOTIFY_CMD_DETACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_GAMEPAD, 0);
+               else if (action == MUIC_NOTIFY_CMD_ATTACH)
+                       send_otg_notify(o_notify, NOTIFY_EVENT_GAMEPAD, 1);
+               else
+                       pr_err("%s - ACTION Error!\n", __func__);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+#endif
+#if defined(CONFIG_VBUS_NOTIFIER)
+static int vbus_handle_notification(struct notifier_block *nb,
+               unsigned long cmd, void *data)
+{
+       vbus_status_t vbus_type = *(vbus_status_t *)data;
+       struct otg_notify *o_notify;
+
+       o_notify = get_otg_notify();
+
+       pr_info("%s cmd=%lu, vbus_type=%s\n",
+               __func__, cmd, vbus_type == STATUS_VBUS_HIGH ? "HIGH" : "LOW");
+
+       switch (vbus_type) {
+       case STATUS_VBUS_HIGH:
+               send_otg_notify(o_notify, NOTIFY_EVENT_VBUSPOWER, 1);
+               break;
+       case STATUS_VBUS_LOW:
+               send_otg_notify(o_notify, NOTIFY_EVENT_VBUSPOWER, 0);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+#endif
+
+static int otg_accessory_power(bool enable)
+{
+       u8 on = (u8)!!enable;
+       union power_supply_propval val;
+
+       pr_info("otg accessory power = %d\n", on);
+
+       val.intval = enable;
+       psy_do_property("otg", set,
+                       POWER_SUPPLY_PROP_ONLINE, val);
+
+       return 0;
+}
+#endif
+
+static int set_online(int event, int state)
+{
+       union power_supply_propval val;
+       struct device_node *np_charger = NULL;
+       char *charger_name;
+
+       if (event == NOTIFY_EVENT_SMTD_EXT_CURRENT)
+               pr_info("request smartdock charging current = %s\n",
+                       state ? "1000mA" : "1700mA");
+       else if (event == NOTIFY_EVENT_MMD_EXT_CURRENT)
+               pr_info("request mmdock charging current = %s\n",
+                       state ? "900mA" : "1400mA");
+
+       np_charger = of_find_node_by_name(NULL, "battery");
+       if (!np_charger) {
+               pr_err("%s: failed to get the battery device node\n", __func__);
+               return 0;
+       } else {
+               if (!of_property_read_string(np_charger, "battery,charger_name",
+                                       (char const **)&charger_name)) {
+                       pr_info("%s: charger_name = %s\n", __func__,
+                                       charger_name);
+               } else {
+                       pr_err("%s: failed to get the charger name\n",
+                                                                __func__);
+                       return 0;
+               }
+       }
+       // for KNOX DT charging
+       pr_info("Knox Desktop connection state = %s\n", state ? "Connected" : "Disconnected");
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       if (state)
+               val.intval = POWER_SUPPLY_TYPE_SMART_NOTG;
+       else
+               val.intval = POWER_SUPPLY_TYPE_BATTERY;
+#else
+       if (state)
+               val.intval = SEC_BATTERY_CABLE_SMART_NOTG;
+       else
+               val.intval = SEC_BATTERY_CABLE_NONE;
+#endif
+
+       psy_do_property("battery", set,
+                       POWER_SUPPLY_PROP_ONLINE, val);
+
+       return 0;
+}
+
+static int exynos_set_host(bool enable)
+{
+       if (!enable) {
+               pr_info("%s USB_HOST_DETACHED\n", __func__);
+#ifdef CONFIG_OF
+               check_usb_id_state(1);
+#endif
+       } else {
+               pr_info("%s USB_HOST_ATTACHED\n", __func__);
+#ifdef CONFIG_OF
+               check_usb_id_state(0);
+#endif
+       }
+
+       return 0;
+}
+
+static int exynos_set_peripheral(bool enable)
+{
+       if (enable) {
+               pr_info("%s usb attached\n", __func__);
+               check_usb_vbus_state(1);
+       } else {
+               pr_info("%s usb detached\n", __func__);
+               check_usb_vbus_state(0);
+       }
+       return 0;
+}
+
+#if defined(CONFIG_BATTERY_SAMSUNG_V2)
+static int usb_blocked_chg_control(int set)
+{
+       union power_supply_propval val;
+       struct device_node *np_charger = NULL;
+       char *charger_name;
+
+       np_charger = of_find_node_by_name(NULL, "battery");
+       if (!np_charger) {
+               pr_err("%s: failed to get the battery device node\n", __func__);
+               return 0;
+       }
+
+       if (!of_property_read_string(np_charger, "battery,charger_name",
+                               (char const **)&charger_name)) {
+               pr_info("%s: charger_name = %s\n", __func__,
+                               charger_name);
+       } else {
+               pr_err("%s: failed to get the charger name\n",  __func__);
+               return 0;
+       }
+
+       /* current setting for upsm */
+       pr_info("usb blocked : charing current set = %d\n", set);
+
+       if (set)
+               val.intval = USB_CURRENT_HIGH_SPEED;
+       else
+               val.intval = USB_CURRENT_UNCONFIGURED;
+
+       psy_do_property("battery", set,
+                       POWER_SUPPLY_EXT_PROP_USB_CONFIGURE, val);
+
+       return 0;
+
+}
+#endif
+
+static struct otg_notify dwc_lsi_notify = {
+       .vbus_drive     = otg_accessory_power,
+       .set_host = exynos_set_host,
+       .set_peripheral = exynos_set_peripheral,
+       .vbus_detect_gpio = -1,
+       .is_wakelock = 0,
+       .booting_delay_sec = 10,
+#if !defined(CONFIG_CCIC_NOTIFIER)
+       .auto_drive_vbus = NOTIFY_OP_POST,
+#endif
+       .disable_control = 1,
+       .device_check_sec = 3,
+       .set_battcall = set_online,
+#if defined(CONFIG_CCIC_NOTIFIER)
+       .set_ldo_onoff = usb_regulator_onoff,
+#endif
+#if defined(CONFIG_BATTERY_SAMSUNG_V2)
+       .set_chg_current = usb_blocked_chg_control,
+#endif
+       .pre_peri_delay_us = 6,
+#if defined(CONFIG_USB_OTG_WHITELIST_FOR_MDM)
+       .sec_whitelist_enable = 0,
+#endif
+};
+
+static int usb_notifier_probe(struct platform_device *pdev)
+{
+       struct usb_notifier_platform_data *pdata = NULL;
+       int ret = 0;
+
+       if (pdev->dev.of_node) {
+               pdata = devm_kzalloc(&pdev->dev,
+                       sizeof(struct usb_notifier_platform_data), GFP_KERNEL);
+               if (!pdata) {
+                       dev_err(&pdev->dev, "Failed to allocate memory\n");
+                       return -ENOMEM;
+               }
+
+               ret = of_usb_notifier_dt(&pdev->dev, pdata);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Failed to get device of_node\n");
+                       return ret;
+               }
+
+               pdev->dev.platform_data = pdata;
+       } else
+               pdata = pdev->dev.platform_data;
+
+       dwc_lsi_notify.redriver_en_gpio = pdata->gpio_redriver_en;
+       dwc_lsi_notify.disable_control = pdata->can_disable_usb;
+       set_otg_notify(&dwc_lsi_notify);
+       set_notify_data(&dwc_lsi_notify, pdata);
+#if defined(CONFIG_CCIC_NOTIFIER)
+       pdata->usb_ldo_onoff = 0;
+       INIT_DELAYED_WORK(&pdata->usb_ldo_work,
+                 usb_ldo_off_control);
+       pdata->is_host = 0;
+#endif
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       ifconn_notifier_register(&pdata->muic_usb_nb,
+                                       muic_usb_handle_notification,
+                                       IFCONN_NOTIFY_USB,
+                                       IFCONN_NOTIFY_MUIC);
+       ifconn_notifier_register(&pdata->ccic_usb_nb,
+                                       ccic_usb_handle_notification,
+                                       IFCONN_NOTIFY_USB,
+                                       IFCONN_NOTIFY_CCIC);
+       ifconn_notifier_register(&pdata->vbus_nb,
+                                       vbus_handle_notification,
+                                       IFCONN_NOTIFY_USB,
+                                       IFCONN_NOTIFY_VBUS);
+#else
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       manager_notifier_register(&pdata->ccic_usb_nb, ccic_usb_handle_notification,
+                                       MANAGER_NOTIFY_CCIC_USB);
+#else
+       ccic_notifier_register(&pdata->ccic_usb_nb, ccic_usb_handle_notification,
+                                  CCIC_NOTIFY_DEV_USB);
+#endif
+#if defined(CONFIG_MUIC_NOTIFIER)
+       muic_notifier_register(&pdata->muic_usb_nb, muic_usb_handle_notification,
+                              MUIC_NOTIFY_DEV_USB);
+#endif
+#if defined(CONFIG_VBUS_NOTIFIER)
+       vbus_notifier_register(&pdata->vbus_nb, vbus_handle_notification,
+                              VBUS_NOTIFY_DEV_MANAGER);
+#endif
+#endif
+
+       dev_info(&pdev->dev, "usb notifier probe\n");
+       return 0;
+}
+
+static int usb_notifier_remove(struct platform_device *pdev)
+{
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       ifconn_notifier_unregister(IFCONN_NOTIFY_USB, IFCONN_NOTIFY_CCIC);
+       ifconn_notifier_unregister(IFCONN_NOTIFY_USB, IFCONN_NOTIFY_MUIC);
+       ifconn_notifier_unregister(IFCONN_NOTIFY_USB, IFCONN_NOTIFY_VBUS);
+#else
+       struct usb_notifier_platform_data *pdata = dev_get_platdata(&pdev->dev);
+#if defined(CONFIG_CCIC_NOTIFIER)
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       manager_notifier_unregister(&pdata->ccic_usb_nb);
+#else
+       ccic_notifier_unregister(&pdata->ccic_usb_nb);
+#endif
+#elif defined(CONFIG_MUIC_NOTIFIER)
+       muic_notifier_unregister(&pdata->muic_usb_nb);
+#endif
+#if defined(CONFIG_VBUS_NOTIFIER)
+       vbus_notifier_unregister(&pdata->vbus_nb);
+#endif
+#endif
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id usb_notifier_dt_ids[] = {
+       { .compatible = "samsung,usb-notifier",
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, usb_notifier_dt_ids);
+#endif
+
+static struct platform_driver usb_notifier_driver = {
+       .probe          = usb_notifier_probe,
+       .remove         = usb_notifier_remove,
+       .driver         = {
+               .name   = "usb_notifier",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_OF
+               .of_match_table = of_match_ptr(usb_notifier_dt_ids),
+#endif
+       },
+};
+
+static int __init usb_notifier_init(void)
+{
+       return platform_driver_register(&usb_notifier_driver);
+}
+
+static void __init usb_notifier_exit(void)
+{
+       platform_driver_unregister(&usb_notifier_driver);
+}
+
+late_initcall(usb_notifier_init);
+module_exit(usb_notifier_exit);
+
+MODULE_AUTHOR("inchul.im <inchul.im@samsung.com>");
+MODULE_DESCRIPTION("USB notifier");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/notify/usb_notifier.h b/drivers/usb/notify/usb_notifier.h
new file mode 100644 (file)
index 0000000..487be0a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __LINUX_USB_NOTIFIER_H__
+#define __LINUX_USB_NOTIFIER_H__
+
+#ifdef CONFIG_USB_DWC3
+extern int dwc3_exynos_id_event(struct device *dev, int state);
+extern int dwc3_exynos_vbus_event(struct device *dev, int state);
+#else
+static inline int dwc3_exynos_id_event
+               (struct device *dev, int state) {return 0; }
+static inline int dwc3_exynos_vbus_event
+               (struct device *dev, int state) {return 0; }
+#endif
+#ifdef CONFIG_USB_S3C_OTGD
+extern int exynos_otg_vbus_event(struct platform_device *pdev, int state);
+#else
+static inline int exynos_otg_vbus_event(
+               struct platform_device *pdev, int state) {return 0; }
+#endif
+#endif
+
diff --git a/drivers/usb/notify/usb_notify.c b/drivers/usb/notify/usb_notify.c
new file mode 100644 (file)
index 0000000..018aa2d
--- /dev/null
@@ -0,0 +1,2027 @@
+/*
+ * Copyright (C) 2014-2017 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+ /* usb notify layer v3.1 */
+
+#define pr_fmt(fmt) "usb_notify: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/kthread.h>
+#include <linux/usb_notify.h>
+#include "dock_notify.h"
+#include "usb_notify_sysfs.h"
+
+#define DEFAULT_OVC_POLL_SEC 3
+
+struct  ovc {
+       struct otg_notify *o_notify;
+       wait_queue_head_t        delay_wait;
+       struct completion       scanning_done;
+       struct task_struct *th;
+       struct mutex ovc_lock;
+       int thread_remove;
+       int can_ovc;
+       int poll_period;
+       int prev_state;
+       void *data;
+       int (*check_state)(void *);
+};
+
+struct vbus_gpio {
+       spinlock_t lock;
+       int gpio_status;
+};
+
+struct otg_state_work {
+       struct otg_notify *o_notify;
+       struct work_struct otg_work;
+       unsigned long event;
+       int enable;
+};
+
+struct otg_booting_delay {
+       struct delayed_work booting_work;
+       unsigned long reserve_state;
+};
+
+struct typec_info {
+       int data_role;
+       int power_role;
+};
+
+struct usb_notify {
+       struct otg_notify *o_notify;
+       struct atomic_notifier_head     otg_notifier;
+       struct blocking_notifier_head extra_notifier;
+       struct notifier_block otg_nb;
+       struct notifier_block extra_nb;
+       struct vbus_gpio v_gpio;
+       struct host_notify_dev ndev;
+       struct usb_notify_dev udev;
+       struct workqueue_struct *notifier_wq;
+       struct wake_lock wlock;
+       struct otg_booster *booster;
+       struct ovc ovc_info;
+       struct otg_booting_delay b_delay;
+       struct delayed_work check_work;
+       struct typec_info typec_status;
+       int is_device;
+       int check_work_complete;
+       int oc_noti;
+       int disable_v_drive;
+       unsigned long c_type;
+       int c_status;
+#if defined(CONFIG_USB_HW_PARAM)
+       unsigned long long hw_param[USB_CCIC_HW_PARAM_MAX];
+#endif
+};
+
+struct usb_notify_core {
+       struct otg_notify *o_notify;
+};
+
+static struct usb_notify_core *u_notify_core;
+
+/*
+ *  Define event types.
+ *  NOTIFY_EVENT_STATE can be called in both interrupt context
+ *             and process context. But it executes queue_work.
+ *  NOTIFY_EVENT_EXTRA can be called directly without queue_work.
+ *           But it must be called in process context.
+ *  NOTIFY_EVENT_DELAY events can not run inner booting delay.
+ *  NOTIFY_EVENT_NEED_VBUSDRIVE events need to drive 5v out
+ *           from phone charger ic
+ *  NOTIFY_EVENT_NOBLOCKING events are not blocked by disable sysfs.
+ *  NOTIFY_EVENT_NOSAVE events are not saved in cable type.
+ */
+static int check_event_type(enum otg_notify_events event)
+{
+       int ret = 0;
+
+       switch (event) {
+       case NOTIFY_EVENT_OVERCURRENT:
+       case NOTIFY_EVENT_VBUSPOWER:
+       case NOTIFY_EVENT_SMSC_OVC:
+       case NOTIFY_EVENT_SMTD_EXT_CURRENT:
+       case NOTIFY_EVENT_MMD_EXT_CURRENT:
+       case NOTIFY_EVENT_DEVICE_CONNECT:
+       case NOTIFY_EVENT_GAMEPAD_CONNECT:
+       case NOTIFY_EVENT_LANHUB_CONNECT:
+       case NOTIFY_EVENT_POWER_SOURCE:
+               ret |= NOTIFY_EVENT_EXTRA;
+               break;
+       case NOTIFY_EVENT_VBUS:
+       case NOTIFY_EVENT_SMARTDOCK_USB:
+               ret |= (NOTIFY_EVENT_STATE | NOTIFY_EVENT_DELAY
+                               | NOTIFY_EVENT_NEED_CLIENT);
+               break;
+       case NOTIFY_EVENT_HOST:
+       case NOTIFY_EVENT_HMT:
+       case NOTIFY_EVENT_GAMEPAD:
+               ret |= (NOTIFY_EVENT_STATE | NOTIFY_EVENT_NEED_VBUSDRIVE
+                               | NOTIFY_EVENT_DELAY | NOTIFY_EVENT_NEED_HOST);
+               break;
+       case NOTIFY_EVENT_POGO:
+               ret |= (NOTIFY_EVENT_STATE | NOTIFY_EVENT_DELAY
+                               | NOTIFY_EVENT_NEED_HOST);
+               break;
+       case NOTIFY_EVENT_ALL_DISABLE:
+       case NOTIFY_EVENT_HOST_DISABLE:
+       case NOTIFY_EVENT_CLIENT_DISABLE:
+       case NOTIFY_EVENT_MDM_ON_OFF:
+               ret |= (NOTIFY_EVENT_STATE | NOTIFY_EVENT_NOBLOCKING
+                               | NOTIFY_EVENT_NOSAVE);
+               break;
+       case NOTIFY_EVENT_DRIVE_VBUS:
+       case NOTIFY_EVENT_LANHUB_TA:
+               ret |= (NOTIFY_EVENT_STATE | NOTIFY_EVENT_NOSAVE
+                               | NOTIFY_EVENT_NEED_HOST);
+               break;
+       case NOTIFY_EVENT_SMARTDOCK_TA:
+       case NOTIFY_EVENT_AUDIODOCK:
+       case NOTIFY_EVENT_LANHUB:
+       case NOTIFY_EVENT_MMDOCK:
+               ret |= (NOTIFY_EVENT_DELAY | NOTIFY_EVENT_NEED_HOST);
+       case NOTIFY_EVENT_CHARGER:
+       case NOTIFY_EVENT_NONE:
+       default:
+               ret |= NOTIFY_EVENT_STATE;
+               break;
+       }
+       return ret;
+}
+
+static int check_same_event_type(enum otg_notify_events event1,
+               enum otg_notify_events event2)
+{
+       return (check_event_type(event1)
+                       == check_event_type(event2));
+}
+
+const char *event_string(enum otg_notify_events event)
+{
+       int virt;
+
+       virt = IS_VIRTUAL(event);
+       event = PHY_EVENT(event);
+
+       switch (event) {
+       case NOTIFY_EVENT_NONE:
+               return "none";
+       case NOTIFY_EVENT_VBUS:
+               return virt ? "vbus(virtual)" : "vbus";
+       case NOTIFY_EVENT_HOST:
+               return virt ? "host_id(virtual)" : "host_id";
+       case NOTIFY_EVENT_CHARGER:
+               return virt ? "charger(virtual)" : "charger";
+       case NOTIFY_EVENT_SMARTDOCK_TA:
+               return virt ? "smartdock_ta(virtual)" : "smartdock_ta";
+       case NOTIFY_EVENT_SMARTDOCK_USB:
+               return virt ? "smartdock_usb(virtual)" : "smartdock_usb";
+       case NOTIFY_EVENT_AUDIODOCK:
+               return virt ? "audiodock(virtual)" : "audiodock";
+       case NOTIFY_EVENT_LANHUB:
+               return virt ? "lanhub(virtual)" : "lanhub";
+       case NOTIFY_EVENT_LANHUB_TA:
+               return virt ? "lanhub_ta(virtual)" : "lanhub_ta";
+       case NOTIFY_EVENT_MMDOCK:
+               return virt ? "mmdock(virtual)" : "mmdock";
+       case NOTIFY_EVENT_HMT:
+               return virt ? "hmt(virtual)" : "hmt";
+       case NOTIFY_EVENT_GAMEPAD:
+               return virt ? "gamepad(virtual)" : "gamepad";
+       case NOTIFY_EVENT_POGO:
+               return virt ? "pogo(virtual)" : "pogo";
+       case NOTIFY_EVENT_DRIVE_VBUS:
+               return "drive_vbus";
+       case NOTIFY_EVENT_ALL_DISABLE:
+               return "disable_all_notify";
+       case NOTIFY_EVENT_HOST_DISABLE:
+               return "disable_host_notify";
+       case NOTIFY_EVENT_CLIENT_DISABLE:
+               return "disable_client_notify";
+       case NOTIFY_EVENT_MDM_ON_OFF:
+               return "mdm control_notify";
+       case NOTIFY_EVENT_OVERCURRENT:
+               return "overcurrent";
+       case NOTIFY_EVENT_VBUSPOWER:
+               return "vbus_power";
+       case NOTIFY_EVENT_SMSC_OVC:
+               return "smsc_ovc";
+       case NOTIFY_EVENT_SMTD_EXT_CURRENT:
+               return "smtd_ext_current";
+       case NOTIFY_EVENT_MMD_EXT_CURRENT:
+               return "mmd_ext_current";
+       case NOTIFY_EVENT_DEVICE_CONNECT:
+               return "device_connect";
+       case NOTIFY_EVENT_GAMEPAD_CONNECT:
+               return "gamepad_connect";
+       case NOTIFY_EVENT_LANHUB_CONNECT:
+               return "lanhub_connect";
+       case NOTIFY_EVENT_POWER_SOURCE:
+               return "power_role_source";
+       default:
+               return "undefined";
+       }
+}
+EXPORT_SYMBOL(event_string);
+
+const char *status_string(enum otg_notify_event_status status)
+{
+       switch (status) {
+       case NOTIFY_EVENT_DISABLED:
+               return "disabled";
+       case NOTIFY_EVENT_DISABLING:
+               return "disabling";
+       case NOTIFY_EVENT_ENABLED:
+               return "enabled";
+       case NOTIFY_EVENT_ENABLING:
+               return "enabling";
+       case NOTIFY_EVENT_BLOCKED:
+               return "blocked";
+       case NOTIFY_EVENT_BLOCKING:
+               return "blocking";
+       default:
+               return "undefined";
+       }
+}
+EXPORT_SYMBOL(status_string);
+
+static const char *block_string(enum otg_notify_block_type type)
+{
+       switch (type) {
+       case NOTIFY_BLOCK_TYPE_NONE:
+               return "block_off";
+       case NOTIFY_BLOCK_TYPE_HOST:
+               return "block_host";
+       case NOTIFY_BLOCK_TYPE_CLIENT:
+               return "block_client";
+       case NOTIFY_BLOCK_TYPE_ALL:
+               return "block_all";
+       default:
+               return "undefined";
+       }
+}
+
+static bool is_host_cable_block(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+       if ((check_event_type(u_notify->c_type)
+               & NOTIFY_EVENT_NEED_HOST) &&
+                       (u_notify->c_status == NOTIFY_EVENT_BLOCKED
+                               || u_notify->c_status == NOTIFY_EVENT_BLOCKING))
+               return true;
+       else
+               return false;
+}
+
+static bool is_host_cable_enable(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+       if ((check_event_type(u_notify->c_type)
+               & NOTIFY_EVENT_NEED_HOST) &&
+                       (u_notify->c_status == NOTIFY_EVENT_ENABLED
+                               || u_notify->c_status == NOTIFY_EVENT_ENABLING))
+               return true;
+       else
+               return false;
+}
+
+static bool is_client_cable_block(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+       if ((check_event_type(u_notify->c_type)
+               & NOTIFY_EVENT_NEED_CLIENT) &&
+                       (u_notify->c_status == NOTIFY_EVENT_BLOCKED
+                               || u_notify->c_status == NOTIFY_EVENT_BLOCKING))
+               return true;
+       else
+               return false;
+}
+
+static bool is_client_cable_enable(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+       if ((check_event_type(u_notify->c_type)
+               & NOTIFY_EVENT_NEED_CLIENT) &&
+                       (u_notify->c_status == NOTIFY_EVENT_ENABLED
+                               || u_notify->c_status == NOTIFY_EVENT_ENABLING))
+               return true;
+       else
+               return false;
+}
+
+static bool check_block_event(struct otg_notify *n, unsigned long event)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+       if ((test_bit(NOTIFY_BLOCK_TYPE_HOST, &u_notify->udev.disable_state)
+               && (check_event_type(event) & NOTIFY_EVENT_NEED_HOST))
+               || (test_bit(NOTIFY_BLOCK_TYPE_CLIENT,
+                               &u_notify->udev.disable_state)
+               && (check_event_type(event) & NOTIFY_EVENT_NEED_CLIENT)))
+               return true;
+       else
+               return false;
+}
+
+static void enable_ovc(struct usb_notify *u_noti, int enable)
+{
+       u_noti->ovc_info.can_ovc = enable;
+}
+
+static int ovc_scan_thread(void *data)
+{
+       struct ovc *ovcinfo = (struct ovc *)data;
+       struct otg_notify *o_notify = ovcinfo->o_notify;
+       struct usb_notify *u_notify = (struct usb_notify *)(o_notify->u_notify);
+       int state;
+
+       while (!kthread_should_stop()) {
+               wait_event_interruptible_timeout(ovcinfo->delay_wait,
+                       ovcinfo->thread_remove, (ovcinfo->poll_period)*HZ);
+               if (ovcinfo->thread_remove)
+                       break;
+               mutex_lock(&ovcinfo->ovc_lock);
+               if (ovcinfo->check_state
+                       && ovcinfo->data
+                               && ovcinfo->can_ovc) {
+
+                       state = ovcinfo->check_state(ovcinfo->data);
+
+                       if (ovcinfo->prev_state != state) {
+                               if (state == HNOTIFY_LOW) {
+                                       pr_err("%s overcurrent detected\n",
+                                                       __func__);
+                                       host_state_notify(&u_notify->ndev,
+                                               NOTIFY_HOST_OVERCURRENT);
+                               } else if (state == HNOTIFY_HIGH) {
+                                       pr_info("%s vbus draw detected\n",
+                                                       __func__);
+                                       host_state_notify(&u_notify->ndev,
+                                               NOTIFY_HOST_NONE);
+                               }
+                       }
+                       ovcinfo->prev_state = state;
+               }
+               mutex_unlock(&ovcinfo->ovc_lock);
+               if (!ovcinfo->can_ovc)
+                       ovcinfo->thread_remove = 1;
+       }
+
+       pr_info("%s exit\n", __func__);
+       complete_and_exit(&ovcinfo->scanning_done, 0);
+       return 0;
+}
+
+void ovc_start(struct usb_notify *u_noti)
+{
+       struct otg_notify *o_notify = u_noti->o_notify;
+
+       if (!u_noti->ovc_info.can_ovc)
+               goto skip;
+
+       u_noti->ovc_info.prev_state = HNOTIFY_INITIAL;
+       u_noti->ovc_info.poll_period = (o_notify->smsc_ovc_poll_sec) ?
+                       o_notify->smsc_ovc_poll_sec : DEFAULT_OVC_POLL_SEC;
+       reinit_completion(&u_noti->ovc_info.scanning_done);
+       u_noti->ovc_info.thread_remove = 0;
+       u_noti->ovc_info.th = kthread_run(ovc_scan_thread,
+                       &u_noti->ovc_info, "ovc-scan-thread");
+       if (IS_ERR(u_noti->ovc_info.th)) {
+               pr_err("Unable to start the ovc-scanning thread\n");
+               complete(&u_noti->ovc_info.scanning_done);
+       }
+       pr_info("%s on\n", __func__);
+       return;
+skip:
+       complete(&u_noti->ovc_info.scanning_done);
+       pr_info("%s skip\n", __func__);
+}
+
+void ovc_stop(struct usb_notify *u_noti)
+{
+       u_noti->ovc_info.thread_remove = 1;
+       wake_up_interruptible(&u_noti->ovc_info.delay_wait);
+       wait_for_completion(&u_noti->ovc_info.scanning_done);
+       mutex_lock(&u_noti->ovc_info.ovc_lock);
+       u_noti->ovc_info.check_state = NULL;
+       u_noti->ovc_info.data = 0;
+       mutex_unlock(&u_noti->ovc_info.ovc_lock);
+       pr_info("%s\n", __func__);
+}
+
+static void ovc_init(struct usb_notify *u_noti)
+{
+       init_waitqueue_head(&u_noti->ovc_info.delay_wait);
+       init_completion(&u_noti->ovc_info.scanning_done);
+       mutex_init(&u_noti->ovc_info.ovc_lock);
+       u_noti->ovc_info.prev_state = HNOTIFY_INITIAL;
+       u_noti->ovc_info.o_notify = u_noti->o_notify;
+       pr_info("%s\n", __func__);
+}
+
+static irqreturn_t vbus_irq_isr(int irq, void *data)
+{
+       struct otg_notify *notify = (struct otg_notify *)(data);
+       struct usb_notify *u_notify = (struct usb_notify *)(notify->u_notify);
+       unsigned long flags = 0;
+       int gpio_value = 0;
+       irqreturn_t ret = IRQ_NONE;
+
+       spin_lock_irqsave(&u_notify->v_gpio.lock, flags);
+       gpio_value = gpio_get_value(notify->vbus_detect_gpio);
+       if (u_notify->v_gpio.gpio_status != gpio_value) {
+               u_notify->v_gpio.gpio_status = gpio_value;
+               ret = IRQ_WAKE_THREAD;
+       } else
+               ret = IRQ_HANDLED;
+       spin_unlock_irqrestore(&u_notify->v_gpio.lock, flags);
+
+       return ret;
+}
+
+static irqreturn_t vbus_irq_thread(int irq, void *data)
+{
+       struct otg_notify *notify = (struct otg_notify *)(data);
+       struct usb_notify *u_notify = (struct usb_notify *)(notify->u_notify);
+       unsigned long flags = 0;
+       int gpio_value = 0;
+
+       spin_lock_irqsave(&u_notify->v_gpio.lock, flags);
+       gpio_value = u_notify->v_gpio.gpio_status;
+       spin_unlock_irqrestore(&u_notify->v_gpio.lock, flags);
+
+       if (gpio_value) {
+               u_notify->ndev.booster = NOTIFY_POWER_ON;
+               pr_info("vbus on detect\n");
+               if (notify->post_vbus_detect)
+                       notify->post_vbus_detect(NOTIFY_POWER_ON);
+       } else {
+               if ((u_notify->ndev.mode == NOTIFY_HOST_MODE)
+                       && (u_notify->ndev.booster == NOTIFY_POWER_ON
+                               && u_notify->oc_noti)) {
+                       host_state_notify(&u_notify->ndev,
+                                       NOTIFY_HOST_OVERCURRENT);
+                       pr_err("OTG overcurrent!!!!!!\n");
+               } else {
+                       pr_info("vbus off detect\n");
+                       if (notify->post_vbus_detect)
+                               notify->post_vbus_detect(NOTIFY_POWER_OFF);
+               }
+               u_notify->ndev.booster = NOTIFY_POWER_OFF;
+       }
+       return IRQ_HANDLED;
+}
+
+int register_gpios(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       int ret = 0;
+       int vbus_irq = 0;
+       int vbus_gpio = -1;
+       int redriver_gpio = -1;
+
+       if (!gpio_is_valid(n->vbus_detect_gpio))
+               goto redriver_en_gpio_phase;
+
+       vbus_gpio = n->vbus_detect_gpio;
+
+       spin_lock_init(&u_notify->v_gpio.lock);
+
+       if (n->pre_gpio)
+               n->pre_gpio(vbus_gpio, NOTIFY_VBUS);
+
+       ret = gpio_request(vbus_gpio, "vbus_detect_notify");
+       if (ret) {
+               pr_err("failed to request %d\n", vbus_gpio);
+               goto err;
+       }
+       gpio_direction_input(vbus_gpio);
+
+       u_notify->v_gpio.gpio_status
+               = gpio_get_value(vbus_gpio);
+       vbus_irq = gpio_to_irq(vbus_gpio);
+       ret = request_threaded_irq(vbus_irq,
+                       vbus_irq_isr,
+                       vbus_irq_thread,
+                       (IRQF_TRIGGER_FALLING |
+                               IRQF_TRIGGER_RISING |
+                                       IRQF_ONESHOT),
+                       "vbus_irq_notify",
+                       n);
+       if (ret) {
+               pr_err("Failed to register IRQ\n");
+               goto err;
+       }
+       if (n->post_gpio)
+               n->post_gpio(vbus_gpio, NOTIFY_VBUS);
+
+       pr_info("vbus detect gpio %d is registered.\n", vbus_gpio);
+redriver_en_gpio_phase:
+       if (!gpio_is_valid(n->redriver_en_gpio))
+               goto err;
+
+       redriver_gpio = n->redriver_en_gpio;
+
+       if (n->pre_gpio)
+               n->pre_gpio(redriver_gpio, NOTIFY_REDRIVER);
+
+       ret = gpio_request(redriver_gpio, "usb30_redriver_en");
+       if (ret) {
+               pr_err("failed to request %d\n", redriver_gpio);
+               goto err;
+       }
+       gpio_direction_output(redriver_gpio, 0);
+       if (n->post_gpio)
+               n->post_gpio(redriver_gpio, NOTIFY_REDRIVER);
+
+       pr_info("redriver en gpio %d is registered.\n", redriver_gpio);
+err:
+       return ret;
+}
+
+int do_notify_blockstate(struct otg_notify *n, unsigned long event,
+                                       int type, int enable)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       int ret = 0;
+
+       switch (event) {
+       case NOTIFY_EVENT_NONE:
+       case NOTIFY_EVENT_CHARGER:
+               break;
+       case NOTIFY_EVENT_SMARTDOCK_USB:
+       case NOTIFY_EVENT_VBUS:
+               if (enable)
+                       if (n->set_chg_current)
+                               n->set_chg_current(1);
+               break;
+       case NOTIFY_EVENT_LANHUB:
+       case NOTIFY_EVENT_HMT:
+       case NOTIFY_EVENT_HOST:
+       case NOTIFY_EVENT_MMDOCK:
+       case NOTIFY_EVENT_SMARTDOCK_TA:
+       case NOTIFY_EVENT_AUDIODOCK:
+       case NOTIFY_EVENT_GAMEPAD:
+       case NOTIFY_EVENT_POGO:
+               if (n->unsupport_host) {
+                       pr_err("This model doesn't support usb host\n");
+                       goto skip;
+               }
+               if (enable)
+                       host_state_notify(&u_notify->ndev, NOTIFY_HOST_BLOCK);
+               else
+                       host_state_notify(&u_notify->ndev, NOTIFY_HOST_NONE);
+               break;
+       case NOTIFY_EVENT_DRIVE_VBUS:
+               ret = -ESRCH;
+               break;
+       default:
+               break;
+       }
+
+skip:
+       return ret;
+}
+
+static void update_cable_status(struct otg_notify *n, unsigned long event,
+               int virtual, int enable, int start)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+       if (enable) {
+               u_notify->c_type = event;
+               if (check_block_event(n, event) ||
+                       (check_event_type(u_notify->c_type)
+                               & NOTIFY_EVENT_NEED_HOST &&
+                                       n->unsupport_host))
+                       u_notify->c_status = (start) ?
+                               NOTIFY_EVENT_BLOCKING : NOTIFY_EVENT_BLOCKED;
+               else
+                       u_notify->c_status = (start) ?
+                               NOTIFY_EVENT_ENABLING : NOTIFY_EVENT_ENABLED;
+       } else {
+               if (virtual)
+                       u_notify->c_status = (start) ?
+                               NOTIFY_EVENT_BLOCKING : NOTIFY_EVENT_BLOCKED;
+               else {
+                       u_notify->c_type = NOTIFY_EVENT_NONE;
+                       u_notify->c_status = (start) ?
+                               NOTIFY_EVENT_DISABLING : NOTIFY_EVENT_DISABLED;
+               }
+       }
+}
+
+static void otg_notify_state(struct otg_notify *n,
+                       unsigned long event, int enable)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       int type = 0;
+       int virtual = 0;
+       unsigned long prev_c_type = 0;
+
+       pr_info("%s+ event=%s(%lu), enable=%s\n", __func__,
+               event_string(event), event, enable == 0 ? "off" : "on");
+
+       prev_c_type = u_notify->c_type;
+       virtual = IS_VIRTUAL(event);
+       event = PHY_EVENT(event);
+
+       type = check_event_type(event);
+
+       if (!(type & NOTIFY_EVENT_NOSAVE)) {
+               update_cable_status(n, event, virtual, enable, 1);
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+               store_usblog_notify(NOTIFY_EVENT,
+                       (void *)&event, (void *)&u_notify->c_status);
+#endif
+       }
+
+       if (check_block_event(n, event) &&
+                       !(type & NOTIFY_EVENT_NOBLOCKING)) {
+               pr_err("%s usb notify is blocked. cause %s\n", __func__,
+                                       u_notify->udev.disable_state_cmd);
+               if (do_notify_blockstate(n, event, type, enable))
+                       goto no_save_event;
+               else
+                       goto err;
+       }
+
+       switch (event) {
+       case NOTIFY_EVENT_NONE:
+               break;
+       case NOTIFY_EVENT_SMARTDOCK_USB:
+       case NOTIFY_EVENT_VBUS:
+               if (enable) {
+                       u_notify->ndev.mode = NOTIFY_PERIPHERAL_MODE;
+                       if (n->is_wakelock)
+                               wake_lock(&u_notify->wlock);
+                       if (gpio_is_valid(n->redriver_en_gpio))
+                               gpio_direction_output
+                                       (n->redriver_en_gpio, 1);
+                       if (n->pre_peri_delay_us)
+                               usleep_range(n->pre_peri_delay_us * 1000,
+                                       n->pre_peri_delay_us * 1000);
+                       if (n->set_peripheral)
+                               n->set_peripheral(true);
+               } else {
+                       u_notify->ndev.mode = NOTIFY_NONE_MODE;
+                       if (n->set_peripheral)
+                               n->set_peripheral(false);
+                       if (gpio_is_valid(n->redriver_en_gpio))
+                               gpio_direction_output
+                                       (n->redriver_en_gpio, 0);
+                       if (n->is_wakelock)
+                               wake_unlock(&u_notify->wlock);
+               }
+               break;
+       case NOTIFY_EVENT_LANHUB_TA:
+               u_notify->disable_v_drive = enable;
+               if (enable)
+                       u_notify->oc_noti = 0;
+               if (n->set_lanhubta)
+                       n->set_lanhubta(enable);
+               break;
+       case NOTIFY_EVENT_LANHUB:
+               if (n->unsupport_host) {
+                       pr_err("This model doesn't support usb host\n");
+                       goto err;
+               }
+               u_notify->disable_v_drive = enable;
+               if (enable) {
+                       u_notify->oc_noti = 0;
+                       u_notify->ndev.mode = NOTIFY_HOST_MODE;
+                       if (n->is_wakelock)
+                               wake_lock(&u_notify->wlock);
+                       host_state_notify(&u_notify->ndev, NOTIFY_HOST_ADD);
+                       if (gpio_is_valid(n->redriver_en_gpio))
+                               gpio_direction_output
+                                       (n->redriver_en_gpio, 1);
+                       if (n->set_host)
+                               n->set_host(true);
+               } else {
+                       u_notify->ndev.mode = NOTIFY_NONE_MODE;
+                       if (n->set_host)
+                               n->set_host(false);
+                       if (gpio_is_valid(n->redriver_en_gpio))
+                               gpio_direction_output
+                                       (n->redriver_en_gpio, 0);
+                       host_state_notify(&u_notify->ndev, NOTIFY_HOST_REMOVE);
+                       if (n->is_wakelock)
+                               wake_unlock(&u_notify->wlock);
+               }
+               break;
+       case NOTIFY_EVENT_HMT:
+       case NOTIFY_EVENT_HOST:
+       case NOTIFY_EVENT_GAMEPAD:
+               if (n->unsupport_host) {
+                       pr_err("This model doesn't support usb host\n");
+                       goto err;
+               }
+               u_notify->disable_v_drive = 0;
+               if (enable) {
+                       if (check_same_event_type(prev_c_type, event)
+                               && !virtual) {
+                               pr_err("now host mode, skip this command\n");
+                               goto err;
+                       }
+                       u_notify->ndev.mode = NOTIFY_HOST_MODE;
+                       if (n->is_wakelock)
+                               wake_lock(&u_notify->wlock);
+                       host_state_notify(&u_notify->ndev, NOTIFY_HOST_ADD);
+                       if (gpio_is_valid(n->redriver_en_gpio))
+                               gpio_direction_output
+                                       (n->redriver_en_gpio, 1);
+                       if (n->auto_drive_vbus == NOTIFY_OP_PRE) {
+                               u_notify->oc_noti = 1;
+                               if (n->vbus_drive)
+                                       n->vbus_drive(1);
+                               u_notify->typec_status.power_role
+                                                       = HNOTIFY_SOURCE;
+                       }
+                       if (n->set_host)
+                               n->set_host(true);
+                       if (n->auto_drive_vbus == NOTIFY_OP_POST) {
+                               u_notify->oc_noti = 1;
+                               if (n->vbus_drive)
+                                       n->vbus_drive(1);
+                               u_notify->typec_status.power_role
+                                                       = HNOTIFY_SOURCE;
+                       }
+               } else { /* disable */
+                       u_notify->ndev.mode = NOTIFY_NONE_MODE;
+                       if (n->auto_drive_vbus == NOTIFY_OP_POST) {
+                               u_notify->oc_noti = 0;
+                               if (n->vbus_drive)
+                                       n->vbus_drive(0);
+                               u_notify->typec_status.power_role
+                                                       = HNOTIFY_SINK;
+                       }
+                       if (n->set_host)
+                               n->set_host(false);
+                       if (n->auto_drive_vbus == NOTIFY_OP_PRE) {
+                               u_notify->oc_noti = 0;
+                               if (n->vbus_drive)
+                                       n->vbus_drive(0);
+                               u_notify->typec_status.power_role
+                                                       = HNOTIFY_SINK;
+                       }
+                       if (gpio_is_valid(n->redriver_en_gpio))
+                               gpio_direction_output
+                                       (n->redriver_en_gpio, 0);
+                       host_state_notify(&u_notify->ndev, NOTIFY_HOST_REMOVE);
+                       if (n->is_wakelock)
+                               wake_unlock(&u_notify->wlock);
+               }
+               break;
+       case NOTIFY_EVENT_CHARGER:
+               if (n->set_charger)
+                       n->set_charger(enable);
+               break;
+       case NOTIFY_EVENT_MMDOCK:
+               enable_ovc(u_notify, enable);
+               /* To detect overcurrent, ndev state is initialized */
+               if (enable)
+                       host_state_notify(&u_notify->ndev,
+                                                       NOTIFY_HOST_NONE);
+       case NOTIFY_EVENT_POGO:
+       case NOTIFY_EVENT_SMARTDOCK_TA:
+       case NOTIFY_EVENT_AUDIODOCK:
+               if (n->unsupport_host) {
+                       pr_err("This model doesn't support usb host\n");
+                       goto err;
+               }
+               u_notify->disable_v_drive = enable;
+               if (enable) {
+                       u_notify->ndev.mode = NOTIFY_HOST_MODE;
+                       if (n->is_wakelock)
+                               wake_lock(&u_notify->wlock);
+                       if (n->set_host)
+                               n->set_host(true);
+               } else {
+                       u_notify->ndev.mode = NOTIFY_NONE_MODE;
+                       if (n->set_host)
+                               n->set_host(false);
+                       if (n->is_wakelock)
+                               wake_unlock(&u_notify->wlock);
+               }
+               break;
+       case NOTIFY_EVENT_DRIVE_VBUS:
+               if (n->unsupport_host) {
+                       pr_err("This model doesn't support usb host\n");
+                       goto no_save_event;
+               }
+               if (u_notify->disable_v_drive) {
+                       pr_info("cable type=%s disable vbus draw\n",
+                                       event_string(u_notify->c_type));
+                       goto no_save_event;
+               }
+               u_notify->oc_noti = enable;
+               if (n->vbus_drive)
+                       n->vbus_drive((bool)enable);
+               goto no_save_event;
+       case NOTIFY_EVENT_ALL_DISABLE:
+               if (!n->disable_control) {
+                       pr_err("This model doesn't support disable_control\n");
+                       goto no_save_event;
+               }
+               if (enable) {
+                       send_external_notify(EXTERNAL_NOTIFY_HOSTBLOCK_PRE, 1);
+
+                       set_bit(NOTIFY_BLOCK_TYPE_HOST,
+                               &u_notify->udev.disable_state);
+                       set_bit(NOTIFY_BLOCK_TYPE_CLIENT,
+                               &u_notify->udev.disable_state);
+
+                       send_external_notify(EXTERNAL_NOTIFY_HOSTBLOCK_POST, 1);
+               } else {
+                       send_external_notify(EXTERNAL_NOTIFY_HOSTBLOCK_PRE, 0);
+
+                       clear_bit(NOTIFY_BLOCK_TYPE_HOST,
+                               &u_notify->udev.disable_state);
+                       clear_bit(NOTIFY_BLOCK_TYPE_CLIENT,
+                               &u_notify->udev.disable_state);
+
+                       send_external_notify(EXTERNAL_NOTIFY_HOSTBLOCK_POST, 0);
+               }
+               goto no_save_event;
+       case NOTIFY_EVENT_HOST_DISABLE:
+               if (!n->disable_control) {
+                       pr_err("This model doesn't support disable_control\n");
+                       goto no_save_event;
+               }
+               if (enable) {
+                       send_external_notify(EXTERNAL_NOTIFY_HOSTBLOCK_PRE, 1);
+
+                       clear_bit(NOTIFY_BLOCK_TYPE_CLIENT,
+                               &u_notify->udev.disable_state);
+                       set_bit(NOTIFY_BLOCK_TYPE_HOST,
+                               &u_notify->udev.disable_state);
+
+                       send_external_notify(EXTERNAL_NOTIFY_HOSTBLOCK_POST, 1);
+               }
+               goto no_save_event;
+       case NOTIFY_EVENT_CLIENT_DISABLE:
+               if (!n->disable_control) {
+                       pr_err("This model doesn't support disable_control\n");
+                       goto no_save_event;
+               }
+               if (enable) {
+                       clear_bit(NOTIFY_BLOCK_TYPE_HOST,
+                               &u_notify->udev.disable_state);
+                       set_bit(NOTIFY_BLOCK_TYPE_CLIENT,
+                               &u_notify->udev.disable_state);
+               }
+               goto no_save_event;
+       case NOTIFY_EVENT_MDM_ON_OFF:
+               pr_info("%s : mdm block enable for usb whiltelist = %d\n",
+                       __func__, enable);
+               if (enable) {
+                       send_external_notify(EXTERNAL_NOTIFY_MDMBLOCK_PRE, 1);
+                       /*whilte list start*/
+                       n->sec_whitelist_enable = 1;
+                       send_external_notify(EXTERNAL_NOTIFY_MDMBLOCK_POST, 1);
+               } else {
+                       /*whilte list end*/
+                       n->sec_whitelist_enable = 0;
+               }
+               goto no_save_event;
+       default:
+               break;
+       }
+
+       if (((type & NOTIFY_EVENT_NEED_VBUSDRIVE)
+                               && event != NOTIFY_EVENT_HOST)
+                               || event == NOTIFY_EVENT_POGO) {
+               if (enable) {
+                       if (n->device_check_sec) {
+                               if (prev_c_type != NOTIFY_EVENT_HOST)
+                                       u_notify->is_device = 0;
+                               u_notify->check_work_complete = 0;
+                               schedule_delayed_work(&u_notify->check_work,
+                                       n->device_check_sec*HZ);
+                               pr_info("%s check work start\n", __func__);
+                       }
+               } else {
+                       if (n->device_check_sec &&
+                               !u_notify->check_work_complete) {
+                               pr_info("%s check work cancel\n", __func__);
+                               cancel_delayed_work_sync(&u_notify->check_work);
+                       }
+                       u_notify->is_device = 0;
+               }
+       }
+err:
+       update_cable_status(n, event, virtual, enable, 0);
+
+no_save_event:
+       pr_info("%s- event=%s, cable=%s\n", __func__,
+               event_string(event),
+                       event_string(u_notify->c_type));
+}
+
+static void extra_notify_state(struct otg_notify *n,
+                       unsigned long event, int enable)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       int status = 0;
+
+       pr_info("%s+ event=%s(%lu), enable=%s\n", __func__,
+               event_string(event), event, enable == 0 ? "off" : "on");
+
+       switch (event) {
+       case NOTIFY_EVENT_NONE:
+               break;
+       case NOTIFY_EVENT_OVERCURRENT:
+               if (!u_notify->ndev.dev) {
+                       pr_err("ndev is NULL. Maybe usb host is not supported.\n");
+                       break;
+               }
+               host_state_notify(&u_notify->ndev,
+                                               NOTIFY_HOST_OVERCURRENT);
+               pr_err("OTG overcurrent!!!!!!\n");
+               break;
+       case NOTIFY_EVENT_VBUSPOWER:
+               if (enable) {
+                       u_notify->ndev.booster = NOTIFY_POWER_ON;
+                       status = NOTIFY_EVENT_ENABLED;
+               } else {
+                       u_notify->ndev.booster = NOTIFY_POWER_OFF;
+                       status = NOTIFY_EVENT_DISABLED;
+               }
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+               store_usblog_notify(NOTIFY_EVENT,
+                       (void *)&event, (void *)&status);
+#endif
+               break;
+       case NOTIFY_EVENT_SMSC_OVC:
+               if (enable)
+                       ovc_start(u_notify);
+               else
+                       ovc_stop(u_notify);
+               break;
+       case NOTIFY_EVENT_SMTD_EXT_CURRENT:
+               if (u_notify->c_type != NOTIFY_EVENT_SMARTDOCK_TA) {
+                       pr_err("No smart dock!!!!!!\n");
+                       break;
+               }
+               if (n->set_battcall)
+                       n->set_battcall
+                               (NOTIFY_EVENT_SMTD_EXT_CURRENT, enable);
+               break;
+       case NOTIFY_EVENT_MMD_EXT_CURRENT:
+               if (u_notify->c_type != NOTIFY_EVENT_MMDOCK) {
+                       pr_err("No mmdock!!!!!!\n");
+                       break;
+               }
+               if (n->set_battcall)
+                       n->set_battcall
+                               (NOTIFY_EVENT_MMD_EXT_CURRENT, enable);
+               break;
+       case NOTIFY_EVENT_DEVICE_CONNECT:
+               u_notify->is_device = 1;
+               break;
+       case NOTIFY_EVENT_GAMEPAD_CONNECT:
+               if (u_notify->c_type == NOTIFY_EVENT_HOST ||
+                       u_notify->c_type == NOTIFY_EVENT_GAMEPAD)
+                       send_external_notify(EXTERNAL_NOTIFY_DEVICE_CONNECT,
+                                       EXTERNAL_NOTIFY_GPAD);
+               break;
+       case NOTIFY_EVENT_LANHUB_CONNECT:
+               if (u_notify->c_type == NOTIFY_EVENT_HOST ||
+                       u_notify->c_type == NOTIFY_EVENT_LANHUB)
+                       send_external_notify(EXTERNAL_NOTIFY_DEVICE_CONNECT,
+                                       EXTERNAL_NOTIFY_LANHUB);
+               break;
+       case NOTIFY_EVENT_POWER_SOURCE:
+               if (enable)
+                       u_notify->typec_status.power_role = HNOTIFY_SOURCE;
+               else
+                       u_notify->typec_status.power_role = HNOTIFY_SINK;
+               send_external_notify(EXTERNAL_NOTIFY_POWERROLE,
+                               u_notify->typec_status.power_role);
+               break;
+       default:
+               break;
+       }
+       pr_info("%s- event=%s(%lu), cable=%s\n", __func__,
+               event_string(event), event,
+               event_string(u_notify->c_type));
+}
+
+static void otg_notify_work(struct work_struct *data)
+{
+       struct otg_state_work *state_work =
+               container_of(data, struct otg_state_work, otg_work);
+
+       otg_notify_state(state_work->o_notify,
+                       state_work->event, state_work->enable);
+
+       kfree(state_work);
+}
+
+static int otg_notifier_callback(struct notifier_block *nb,
+               unsigned long event, void *param)
+{
+       struct usb_notify *u_noti = container_of(nb,
+                       struct usb_notify, otg_nb);
+       struct otg_notify *n = NULL;
+       struct otg_state_work *state_work = NULL;
+
+       n = u_noti->o_notify;
+
+       pr_info("%s event=%s(%lu)\n", __func__,
+                       event_string(event), event);
+
+       if (event > VIRT_EVENT(NOTIFY_EVENT_VBUSPOWER)) {
+               pr_err("%s event is invalid\n", __func__);
+               return NOTIFY_DONE;
+       }
+
+       state_work = kmalloc(sizeof(struct otg_state_work), GFP_ATOMIC);
+       if (!state_work)
+               return notifier_from_errno(-ENOMEM);
+
+       INIT_WORK(&state_work->otg_work, otg_notify_work);
+       state_work->o_notify = n;
+       state_work->event = event;
+       state_work->enable = *(int *)param;
+       queue_work(u_noti->notifier_wq, &state_work->otg_work);
+       return NOTIFY_OK;
+}
+
+static int extra_notifier_callback(struct notifier_block *nb,
+               unsigned long event, void *param)
+{
+       struct usb_notify *u_noti = container_of(nb,
+                       struct usb_notify, extra_nb);
+       struct otg_notify *n = NULL;
+
+       n = u_noti->o_notify;
+
+       pr_info("%s event=%s(%lu)\n", __func__,
+                       event_string(event), event);
+
+       if (event > VIRT_EVENT(NOTIFY_EVENT_VBUSPOWER)) {
+               pr_err("%s event is invalid\n", __func__);
+               return NOTIFY_DONE;
+       }
+
+       extra_notify_state(n, event, *(int *)param);
+
+       return NOTIFY_OK;
+}
+
+static int create_usb_notify(void)
+{
+       int ret = 0;
+
+       if (u_notify_core)
+               goto err;
+
+       u_notify_core = kzalloc(sizeof(struct usb_notify_core), GFP_KERNEL);
+       if (!u_notify_core) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = usb_notify_class_init();
+       if (ret) {
+               pr_err("unable to do usb_notify_class_init\n");
+               goto err1;
+       }
+       return 0;
+err1:
+       kfree(u_notify_core);
+err:
+       return ret;
+}
+
+static void reserve_state_check(struct work_struct *work)
+{
+       struct otg_booting_delay *o_b_d = container_of(work,
+                       struct otg_booting_delay, booting_work.work);
+       struct usb_notify *u_noti = container_of(o_b_d,
+                       struct usb_notify, b_delay);
+       int enable = 1;
+       unsigned long state = 0;
+
+       state = u_noti->b_delay.reserve_state;
+       u_noti->o_notify->booting_delay_sec = 0;
+       pr_info("%s booting delay finished\n", __func__);
+
+       if (u_noti->b_delay.reserve_state != NOTIFY_EVENT_NONE) {
+               pr_info("%s event=%s(%lu) enable=%d\n", __func__,
+                               event_string(state), state, enable);
+               if (check_event_type(state) & NOTIFY_EVENT_EXTRA)
+                       blocking_notifier_call_chain
+                               (&u_noti->extra_notifier,
+                                               state, &enable);
+               else
+                       atomic_notifier_call_chain
+                               (&u_noti->otg_notifier,
+                                               state, &enable);
+       }
+}
+
+static void device_connect_check(struct work_struct *work)
+{
+       struct usb_notify *u_notify = container_of(work,
+                       struct usb_notify, check_work.work);
+
+       pr_info("%s start. is_device=%d\n", __func__, u_notify->is_device);
+       if (!u_notify->is_device) {
+               send_external_notify(EXTERNAL_NOTIFY_3S_NODEVICE, 1);
+
+               if (u_notify->o_notify->vbus_drive)
+                       u_notify->o_notify->vbus_drive(0);
+               u_notify->typec_status.power_role = HNOTIFY_SINK;
+       }
+       u_notify->check_work_complete = 1;
+       pr_info("%s finished\n", __func__);
+}
+
+int set_notify_disable(struct usb_notify_dev *udev, int disable)
+{
+       struct otg_notify *n = udev->o_notify;
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+       unsigned long usb_notify;
+       int usb_notify_state;
+#endif
+
+       if (!n->disable_control) {
+               pr_err("%s disable_control is not supported\n", __func__);
+               goto skip;
+       }
+
+       pr_info("%s disable=%s(%d)\n", __func__,
+                       block_string(disable), disable);
+
+       switch (disable) {
+       case NOTIFY_BLOCK_TYPE_ALL:
+               if (is_host_cable_enable(n) ||
+                       is_client_cable_enable(n)) {
+
+                       pr_info("%s event=%s(%lu) disable\n", __func__,
+                               event_string(VIRT_EVENT(u_notify->c_type)),
+                                       VIRT_EVENT(u_notify->c_type));
+
+                       if (!n->auto_drive_vbus &&
+                               (u_notify->typec_status.power_role
+                                               == HNOTIFY_SOURCE) &&
+                               check_event_type(u_notify->c_type)
+                                               & NOTIFY_EVENT_NEED_VBUSDRIVE)
+                               send_otg_notify(n, NOTIFY_EVENT_DRIVE_VBUS, 0);
+
+                       send_otg_notify(n, VIRT_EVENT(u_notify->c_type), 0);
+               }
+               send_otg_notify(n, NOTIFY_EVENT_ALL_DISABLE, 1);
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+               usb_notify = NOTIFY_EVENT_ALL_DISABLE;
+               usb_notify_state = NOTIFY_EVENT_BLOCKED;
+               store_usblog_notify(NOTIFY_EVENT,
+                       (void *)&usb_notify, (void *)&usb_notify_state);
+#endif
+               break;
+       case NOTIFY_BLOCK_TYPE_HOST:
+               if (is_host_cable_enable(n)) {
+
+                       pr_info("%s event=%s(%lu) disable\n", __func__,
+                               event_string(VIRT_EVENT(u_notify->c_type)),
+                                       VIRT_EVENT(u_notify->c_type));
+
+                       if (!n->auto_drive_vbus &&
+                               (u_notify->typec_status.power_role
+                                       == HNOTIFY_SOURCE) &&
+                               check_event_type(u_notify->c_type)
+                                               & NOTIFY_EVENT_NEED_VBUSDRIVE)
+                               send_otg_notify(n, NOTIFY_EVENT_DRIVE_VBUS, 0);
+
+                       send_otg_notify(n, VIRT_EVENT(u_notify->c_type), 0);
+               }
+
+               send_otg_notify(n, NOTIFY_EVENT_HOST_DISABLE, 1);
+
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+               usb_notify = NOTIFY_EVENT_HOST_DISABLE;
+               usb_notify_state = NOTIFY_EVENT_BLOCKED;
+               store_usblog_notify(NOTIFY_EVENT,
+                       (void *)&usb_notify, (void *)&usb_notify_state);
+#endif
+
+               if (!is_client_cable_block(n))
+                       goto skip;
+
+               pr_info("%s event=%s(%lu) enable\n", __func__,
+                       event_string(VIRT_EVENT(u_notify->c_type)),
+                               VIRT_EVENT(u_notify->c_type));
+
+               send_otg_notify(n, VIRT_EVENT(u_notify->c_type), 1);
+               break;
+       case NOTIFY_BLOCK_TYPE_CLIENT:
+               if (is_client_cable_enable(n)) {
+
+                       pr_info("%s event=%s(%lu) disable\n", __func__,
+                               event_string(VIRT_EVENT(u_notify->c_type)),
+                                       VIRT_EVENT(u_notify->c_type));
+
+                       send_otg_notify(n, VIRT_EVENT(u_notify->c_type), 0);
+               }
+
+               send_otg_notify(n, NOTIFY_EVENT_CLIENT_DISABLE, 1);
+
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+               usb_notify = NOTIFY_EVENT_CLIENT_DISABLE;
+               usb_notify_state = NOTIFY_EVENT_BLOCKED;
+               store_usblog_notify(NOTIFY_EVENT,
+                       (void *)&usb_notify, (void *)&usb_notify_state);
+#endif
+
+               if (!is_host_cable_block(n))
+                       goto skip;
+
+               if (n->unsupport_host)
+                       goto skip;
+
+               pr_info("%s event=%s(%lu) enable\n", __func__,
+                       event_string(VIRT_EVENT(u_notify->c_type)),
+                               VIRT_EVENT(u_notify->c_type));
+               if (!n->auto_drive_vbus &&
+                       (u_notify->typec_status.power_role
+                                       == HNOTIFY_SOURCE) &&
+                       check_event_type(u_notify->c_type)
+                                       & NOTIFY_EVENT_NEED_VBUSDRIVE)
+                       send_otg_notify(n, NOTIFY_EVENT_DRIVE_VBUS, 1);
+
+               send_otg_notify(n, VIRT_EVENT(u_notify->c_type), 1);
+               break;
+       case NOTIFY_BLOCK_TYPE_NONE:
+               send_otg_notify(n, NOTIFY_EVENT_ALL_DISABLE, 0);
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+               usb_notify = NOTIFY_EVENT_ALL_DISABLE;
+               usb_notify_state = NOTIFY_EVENT_DISABLED;
+               store_usblog_notify(NOTIFY_EVENT,
+                       (void *)&usb_notify, (void *)&usb_notify_state);
+#endif
+               if (!is_host_cable_block(n) && !is_client_cable_block(n))
+                       goto skip;
+
+               if (check_event_type(u_notify->c_type)
+                               & NOTIFY_EVENT_NEED_HOST && n->unsupport_host)
+                       goto skip;
+
+               pr_info("%s event=%s(%lu) enable\n", __func__,
+                       event_string(VIRT_EVENT(u_notify->c_type)),
+                               VIRT_EVENT(u_notify->c_type));
+               if (!n->auto_drive_vbus &&
+                       (u_notify->typec_status.power_role
+                                               == HNOTIFY_SOURCE) &&
+                       check_event_type(u_notify->c_type)
+                                       & NOTIFY_EVENT_NEED_VBUSDRIVE)
+                       send_otg_notify(n, NOTIFY_EVENT_DRIVE_VBUS, 1);
+
+               send_otg_notify(n, VIRT_EVENT(u_notify->c_type), 1);
+               break;
+       }
+skip:
+       return 0;
+}
+
+int get_class_index(int ch9_class_num)
+{
+       int internal_class_index;
+
+       switch (ch9_class_num) {
+       case USB_CLASS_PER_INTERFACE:
+               internal_class_index = 1;
+               break;
+       case USB_CLASS_AUDIO:
+               internal_class_index = 2;
+               break;
+       case USB_CLASS_COMM:
+               internal_class_index = 3;
+               break;
+       case USB_CLASS_HID:
+               internal_class_index = 4;
+               break;
+       case USB_CLASS_PHYSICAL:
+               internal_class_index = 5;
+               break;
+       case USB_CLASS_STILL_IMAGE:
+               internal_class_index = 6;
+               break;
+       case USB_CLASS_PRINTER:
+               internal_class_index = 7;
+               break;
+       case USB_CLASS_MASS_STORAGE:
+               internal_class_index = 8;
+               break;
+       case USB_CLASS_HUB:
+               internal_class_index = 9;
+               break;
+       case USB_CLASS_CDC_DATA:
+               internal_class_index = 10;
+               break;
+       case USB_CLASS_CSCID:
+               internal_class_index = 11;
+               break;
+       case USB_CLASS_CONTENT_SEC:
+               internal_class_index = 12;
+               break;
+       case USB_CLASS_VIDEO:
+               internal_class_index = 13;
+               break;
+       case USB_CLASS_WIRELESS_CONTROLLER:
+               internal_class_index = 14;
+               break;
+       case USB_CLASS_MISC:
+               internal_class_index = 15;
+               break;
+       case USB_CLASS_APP_SPEC:
+               internal_class_index = 16;
+               break;
+       case USB_CLASS_VENDOR_SPEC:
+               internal_class_index = 17;
+               break;
+       default:
+               internal_class_index = 0;
+               break;
+       }
+       return internal_class_index;
+}
+
+static bool usb_match_any_interface_for_mdm(struct usb_device *udev,
+                                   int *whitelist_array)
+{
+       unsigned int i;
+
+       for (i = 0; i < udev->descriptor.bNumConfigurations; ++i) {
+               struct usb_host_config *cfg = &udev->config[i];
+               unsigned int j;
+
+               for (j = 0; j < cfg->desc.bNumInterfaces; ++j) {
+                       struct usb_interface_cache *cache;
+                       struct usb_host_interface *intf;
+                       int intf_class;
+
+                       cache = cfg->intf_cache[j];
+                       if (cache->num_altsetting == 0)
+                               continue;
+
+                       intf = &cache->altsetting[0];
+                       intf_class = intf->desc.bInterfaceClass;
+                       if (!whitelist_array[get_class_index(intf_class)]) {
+                               pr_info("%s : FAIL,%x interface, it's not in whitelist\n",
+                                       __func__, intf_class);
+                               return false;
+                       }
+                       pr_info("%s : SUCCESS,%x interface, it's in whitelist\n",
+                               __func__, intf_class);
+               }
+       }
+       return true;
+}
+
+int usb_check_whitelist_for_mdm(struct usb_device *dev)
+{
+       int *whitelist_array;
+       struct otg_notify *o_notify;
+       struct usb_notify *u_notify;
+       /* return 1 if the enumeration will be going . */
+       /* return 0 if the enumeration will be skept . */
+       o_notify = get_otg_notify();
+       if (o_notify == NULL) {
+               pr_err("o_notify is NULL\n");
+               return 1;
+       }
+
+       u_notify = (struct usb_notify *)(o_notify->u_notify);
+       if (u_notify == NULL) {
+               pr_err("u_notify is NULL\n");
+               return 1;
+       }
+
+       if (o_notify->sec_whitelist_enable) {
+               whitelist_array = u_notify->udev.whitelist_array_for_mdm;
+               if (usb_match_any_interface_for_mdm(dev, whitelist_array)) {
+                       dev_info(&dev->dev, "the device is matched with whitelist!\n");
+                       return 1;
+               }
+               return 0;
+       }
+       return 1;
+}
+
+void set_notify_mdm(struct usb_notify_dev *udev, int disable)
+{
+       struct otg_notify *n = udev->o_notify;
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+       switch (disable) {
+       case NOTIFY_MDM_TYPE_ON:
+               send_otg_notify(n, NOTIFY_EVENT_MDM_ON_OFF, 1);
+               if (is_host_cable_enable(n)) {
+                       pr_info("%s event=%s(%lu) disable\n", __func__,
+                               event_string(VIRT_EVENT(u_notify->c_type)),
+                                       VIRT_EVENT(u_notify->c_type));
+
+                       if (!n->auto_drive_vbus &&
+                               (u_notify->typec_status.power_role
+                                               == HNOTIFY_SOURCE)
+                               && check_event_type(u_notify->c_type)
+                               & NOTIFY_EVENT_NEED_VBUSDRIVE)
+                               send_otg_notify(n, NOTIFY_EVENT_DRIVE_VBUS, 0);
+
+                       send_otg_notify(n, VIRT_EVENT(u_notify->c_type), 0);
+               }
+               break;
+       case NOTIFY_MDM_TYPE_OFF:
+               send_otg_notify(n, NOTIFY_EVENT_MDM_ON_OFF, 0);
+               break;
+       }
+}
+
+void send_otg_notify(struct otg_notify *n,
+                               unsigned long event, int enable)
+{
+       struct usb_notify *u_notify = NULL;
+       int type = 0;
+
+       if (!n) {
+               pr_err("%s otg_notify is null\n", __func__);
+               goto end;
+       }
+
+       u_notify = (struct usb_notify *)(n->u_notify);
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               goto end;
+       }
+       pr_info("%s event=%s(%lu) enable=%d\n", __func__,
+                       event_string(event), event, enable);
+
+       type = check_event_type(event);
+
+       if (type & NOTIFY_EVENT_DELAY) {
+               if (n->booting_delay_sec) {
+                       if (u_notify) {
+                               u_notify->b_delay.reserve_state =
+                                       (enable) ? event : NOTIFY_EVENT_NONE;
+                               pr_info("%s reserve event\n", __func__);
+                       } else
+                               pr_err("%s u_notify is null\n", __func__);
+                       goto end;
+               }
+       }
+
+       if (type & NOTIFY_EVENT_EXTRA)
+               blocking_notifier_call_chain
+                       (&u_notify->extra_notifier, event, &enable);
+       else if (type & NOTIFY_EVENT_STATE)
+               atomic_notifier_call_chain
+                       (&u_notify->otg_notifier, event, &enable);
+       else
+               goto end;
+end:
+       return;
+}
+EXPORT_SYMBOL(send_otg_notify);
+
+void *get_notify_data(struct otg_notify *n)
+{
+       if (n)
+               return n->o_data;
+       else
+               return NULL;
+}
+EXPORT_SYMBOL(get_notify_data);
+
+void set_notify_data(struct otg_notify *n, void *data)
+{
+       n->o_data = data;
+}
+EXPORT_SYMBOL(set_notify_data);
+
+struct otg_notify *get_otg_notify(void)
+{
+       if (!u_notify_core)
+               return NULL;
+       if (!u_notify_core->o_notify)
+               return NULL;
+       return u_notify_core->o_notify;
+}
+EXPORT_SYMBOL(get_otg_notify);
+
+struct otg_booster *find_get_booster(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       int ret = 0;
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               goto err;
+       }
+
+       if (!u_notify_core) {
+               ret = create_usb_notify();
+               if (ret) {
+                       pr_err("unable create_usb_notify\n");
+                       goto err;
+               }
+       }
+
+       if (!u_notify->booster) {
+               pr_err("error. No matching booster\n");
+               goto err;
+       }
+
+       return u_notify->booster;
+err:
+       return NULL;
+}
+EXPORT_SYMBOL(find_get_booster);
+
+int register_booster(struct otg_notify *n, struct otg_booster *b)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       int ret = 0;
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               goto err;
+       }
+
+       u_notify->booster = b;
+err:
+       return ret;
+}
+EXPORT_SYMBOL(register_booster);
+
+int register_ovc_func(struct otg_notify *n,
+                       int (*check_state)(void *), void *data)
+{
+       struct usb_notify *u_notify;
+       int ret = 0;
+
+       if (!n) {
+               pr_err("%s otg_notify is null\n", __func__);
+               return -ENODEV;
+       }
+
+       u_notify = (struct usb_notify *)(n->u_notify);
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               return -EFAULT;
+       }
+
+       mutex_lock(&u_notify->ovc_info.ovc_lock);
+       u_notify->ovc_info.check_state = check_state;
+       u_notify->ovc_info.data = data;
+       mutex_unlock(&u_notify->ovc_info.ovc_lock);
+       pr_info("%s\n", __func__);
+       return ret;
+}
+EXPORT_SYMBOL(register_ovc_func);
+
+int get_usb_mode(struct otg_notify *n)
+{
+       struct usb_notify *u_notify;
+       int ret = 0;
+
+       if (!n) {
+               pr_err("%s otg_notify is null\n", __func__);
+               return -ENODEV;
+       }
+
+       u_notify = (struct usb_notify *)(n->u_notify);
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               return NOTIFY_NONE_MODE;
+       }
+
+       if (!u_notify_core) {
+               ret = create_usb_notify();
+               if (ret) {
+                       pr_err("unable create_usb_notify\n");
+                       return -EFAULT;
+               }
+       }
+       pr_info("%s usb mode=%d\n", __func__, u_notify->ndev.mode);
+       ret = u_notify->ndev.mode;
+       return ret;
+}
+EXPORT_SYMBOL(get_usb_mode);
+
+unsigned long get_cable_type(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       unsigned long ret = 0;
+       int noti_ret = 0;
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               return NOTIFY_EVENT_NONE;
+       }
+
+       if (!u_notify_core) {
+               noti_ret = create_usb_notify();
+               if (noti_ret) {
+                       pr_err("unable create_usb_notify\n");
+                       return NOTIFY_EVENT_NONE;
+               }
+       }
+       pr_info("%s cable type =%s\n", __func__,
+                       event_string(u_notify->c_type));
+       ret = u_notify->c_type;
+       return ret;
+}
+EXPORT_SYMBOL(get_cable_type);
+
+int is_usb_host(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       int ret = 0;
+       int noti_ret = 0;
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               return NOTIFY_EVENT_NONE;
+       }
+
+       if (!u_notify_core) {
+               noti_ret = create_usb_notify();
+               if (noti_ret) {
+                       pr_err("unable create_usb_notify\n");
+                       return NOTIFY_EVENT_NONE;
+               }
+       }
+
+       if (n->unsupport_host || !IS_ENABLED(CONFIG_USB_HOST_NOTIFY))
+               ret = 0;
+       else
+               ret = 1;
+
+       pr_info("%s %d\n", __func__, ret);
+       return ret;
+}
+EXPORT_SYMBOL(is_usb_host);
+
+int set_otg_notify(struct otg_notify *n)
+{
+       struct usb_notify *u_notify;
+       int ret = 0;
+
+       if (!u_notify_core) {
+               ret = create_usb_notify();
+               if (ret) {
+                       pr_err("unable create_usb_notify\n");
+                       goto err;
+               }
+       }
+
+       if (u_notify_core->o_notify && n) {
+               pr_err("error : already set o_notify\n");
+               goto err;
+       }
+
+       pr_info("registered otg_notify +\n");
+       if (!n) {
+               pr_err("otg notify structure is null\n");
+               ret = -EFAULT;
+               goto err1;
+       }
+       u_notify_core->o_notify = n;
+
+       u_notify = kzalloc(sizeof(struct usb_notify), GFP_KERNEL);
+       if (!u_notify) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       u_notify->o_notify = n;
+
+       n->u_notify = (void *)u_notify;
+
+       u_notify->notifier_wq
+               = create_singlethread_workqueue("usb_notify");
+        if (!u_notify->notifier_wq) {
+               pr_err("%s failed to create work queue\n", __func__);
+               ret = -ENOMEM;
+               goto err2;
+        }
+
+       ovc_init(u_notify);
+
+       ATOMIC_INIT_NOTIFIER_HEAD(&u_notify->otg_notifier);
+       u_notify->otg_nb.notifier_call = otg_notifier_callback;
+       ret = atomic_notifier_chain_register(&u_notify->otg_notifier,
+                               &u_notify->otg_nb);
+       if (ret < 0) {
+               pr_err("atomic_notifier_chain_register failed\n");
+               goto err3;
+       }
+
+       BLOCKING_INIT_NOTIFIER_HEAD(&u_notify->extra_notifier);
+       u_notify->extra_nb.notifier_call = extra_notifier_callback;
+       ret = blocking_notifier_chain_register
+               (&u_notify->extra_notifier, &u_notify->extra_nb);
+       if (ret < 0) {
+               pr_err("blocking_notifier_chain_register failed\n");
+               goto err4;
+       }
+
+       if (!n->unsupport_host) {
+               u_notify->ndev.name = "usb_otg";
+               u_notify->ndev.set_booster = n->vbus_drive;
+               ret = host_notify_dev_register(&u_notify->ndev);
+               if (ret < 0) {
+                       pr_err("host_notify_dev_register is failed\n");
+                       goto err5;
+               }
+
+               if (!n->vbus_drive) {
+                       pr_err("vbus_drive is null\n");
+                       goto err6;
+               }
+       }
+
+       u_notify->udev.name = "usb_control";
+       u_notify->udev.set_disable = set_notify_disable;
+       u_notify->udev.set_mdm = set_notify_mdm;
+       u_notify->udev.o_notify = n;
+
+       ret = usb_notify_dev_register(&u_notify->udev);
+       if (ret < 0) {
+               pr_err("usb_notify_dev_register is failed\n");
+               goto err6;
+       }
+
+       if (gpio_is_valid(n->vbus_detect_gpio) ||
+                       gpio_is_valid(n->redriver_en_gpio)) {
+               ret = register_gpios(n);
+               if (ret < 0) {
+                       pr_err("register_gpios is failed\n");
+                       goto err7;
+               }
+       }
+
+       if (n->is_wakelock)
+               wake_lock_init(&u_notify->wlock,
+                       WAKE_LOCK_SUSPEND, "usb_notify");
+
+       if (n->booting_delay_sec) {
+               INIT_DELAYED_WORK(&u_notify->b_delay.booting_work,
+                                 reserve_state_check);
+               schedule_delayed_work(&u_notify->b_delay.booting_work,
+                               n->booting_delay_sec*HZ);
+       }
+
+       if (n->device_check_sec)
+               INIT_DELAYED_WORK(&u_notify->check_work,
+                                 device_connect_check);
+
+       register_usbdev_notify();
+
+       register_usblog_proc();
+
+       pr_info("registered otg_notify -\n");
+       return 0;
+err7:
+       usb_notify_dev_unregister(&u_notify->udev);
+err6:
+       if (!n->unsupport_host)
+               host_notify_dev_unregister(&u_notify->ndev);
+err5:
+       blocking_notifier_chain_unregister(&u_notify->extra_notifier,
+                               &u_notify->extra_nb);
+err4:
+       atomic_notifier_chain_unregister(&u_notify->otg_notifier,
+                               &u_notify->otg_nb);
+err3:
+       flush_workqueue(u_notify->notifier_wq);
+       destroy_workqueue(u_notify->notifier_wq);
+err2:
+       kfree(u_notify);
+err1:
+       u_notify_core->o_notify = NULL;
+err:
+       return ret;
+}
+EXPORT_SYMBOL(set_otg_notify);
+
+void put_otg_notify(struct otg_notify *n)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               return;
+       }
+       unregister_usblog_proc();
+       unregister_usbdev_notify();
+       if (n->booting_delay_sec)
+               cancel_delayed_work_sync(&u_notify->b_delay.booting_work);
+       if (n->is_wakelock)
+               wake_lock_destroy(&u_notify->wlock);
+       if (gpio_is_valid(n->vbus_detect_gpio))
+               free_irq(gpio_to_irq(n->vbus_detect_gpio), NULL);
+       usb_notify_dev_unregister(&u_notify->udev);
+       if (!n->unsupport_host)
+               host_notify_dev_unregister(&u_notify->ndev);
+       blocking_notifier_chain_unregister(&u_notify->extra_notifier,
+                               &u_notify->extra_nb);
+       atomic_notifier_chain_unregister(&u_notify->otg_notifier,
+                               &u_notify->otg_nb);
+       flush_workqueue(u_notify->notifier_wq);
+       destroy_workqueue(u_notify->notifier_wq);
+       u_notify->o_notify = NULL;
+       kfree(u_notify);
+}
+EXPORT_SYMBOL(put_otg_notify);
+
+bool is_blocked(struct otg_notify *n, int type)
+{
+       struct usb_notify *u_notify = NULL;
+       int ret = 0;
+
+       if (!n) {
+               pr_err("%s otg_notify is null\n", __func__);
+               goto end;
+       }
+       u_notify = (struct usb_notify *)(n->u_notify);
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               goto end;
+       }
+
+       if (!u_notify_core) {
+               ret = create_usb_notify();
+               if (ret) {
+                       pr_err("unable create_usb_notify\n");
+                       goto end;
+               }
+       }
+       pr_info("%s type=%d, disable_state=%lu\n",
+               __func__, type, u_notify->udev.disable_state);
+
+       if (type == NOTIFY_BLOCK_TYPE_HOST) {
+               if (test_bit(NOTIFY_BLOCK_TYPE_HOST,
+                               &u_notify->udev.disable_state))
+                       goto end2;
+       } else if (type == NOTIFY_BLOCK_TYPE_CLIENT) {
+               if (test_bit(NOTIFY_BLOCK_TYPE_CLIENT,
+                               &u_notify->udev.disable_state))
+                       goto end2;
+       } else if (type == NOTIFY_BLOCK_TYPE_ALL) {
+               if (test_bit(NOTIFY_BLOCK_TYPE_HOST,
+                       &u_notify->udev.disable_state) &&
+                               test_bit(NOTIFY_BLOCK_TYPE_CLIENT,
+                                       &u_notify->udev.disable_state))
+                       goto end2;
+       }
+
+end:
+       return false;
+end2:
+       return true;
+}
+EXPORT_SYMBOL(is_blocked);
+
+#if defined(CONFIG_USB_HW_PARAM)
+unsigned long long *get_hw_param(struct otg_notify *n,
+       enum usb_hw_param index)
+{
+       struct usb_notify *u_notify = (struct usb_notify *)(n->u_notify);
+       int ret = 0;
+
+       if (index < 0 || index >= USB_CCIC_HW_PARAM_MAX) {
+               pr_err("%s usb_hw_param is out of bound\n", __func__);
+               return NULL;
+       }
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               return NULL;
+       }
+
+       if (!u_notify_core) {
+               ret = create_usb_notify();
+               if (ret) {
+                       pr_err("unable create_usb_notify\n");
+                       return NULL;
+               }
+       }
+       return &(u_notify->hw_param[index]);
+}
+EXPORT_SYMBOL(get_hw_param);
+
+int inc_hw_param(struct otg_notify *n,
+       enum usb_hw_param index)
+{
+       struct usb_notify *u_notify;
+       int ret = 0;
+
+       if (!n) {
+               pr_err("%s otg_notify is null\n", __func__);
+               return -ENODEV;
+       }
+
+       u_notify = (struct usb_notify *)(n->u_notify);
+
+       if (index < 0 || index >= USB_CCIC_HW_PARAM_MAX) {
+               pr_err("%s usb_hw_param is out of bound\n", __func__);
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               ret = -ENOENT;
+               return ret;
+       }
+
+       if (!u_notify_core) {
+               ret = create_usb_notify();
+               if (ret) {
+                       pr_err("unable create_usb_notify\n");
+                       return ret;
+               }
+       }
+       u_notify->hw_param[index]++;
+       return ret;
+}
+EXPORT_SYMBOL(inc_hw_param);
+
+int inc_hw_param_host(struct host_notify_dev *dev,
+       enum usb_hw_param index)
+{
+       struct usb_notify *u_notify = container_of(dev,
+                       struct usb_notify, ndev);
+       int ret = 0;
+
+       if (index < 0 || index >= USB_CCIC_HW_PARAM_MAX) {
+               pr_err("%s usb_hw_param is out of bound\n", __func__);
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       if (!u_notify) {
+               pr_err("%s u_notify structure is null\n", __func__);
+               ret = -ENOENT;
+               return ret;
+       }
+
+       if (!u_notify_core) {
+               ret = create_usb_notify();
+               if (ret) {
+                       pr_err("unable create_usb_notify\n");
+                       return ret;
+               }
+       }
+       u_notify->hw_param[index]++;
+       return ret;
+}
+EXPORT_SYMBOL(inc_hw_param_host);
+#endif
+
+static int __init usb_notify_init(void)
+{
+       return create_usb_notify();
+}
+
+static void __exit usb_notify_exit(void)
+{
+       if (!u_notify_core)
+               return;
+       usb_notify_class_exit();
+}
+
+module_init(usb_notify_init);
+module_exit(usb_notify_exit);
+
+MODULE_AUTHOR("Samsung USB Team");
+MODULE_DESCRIPTION("USB Notify Layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/notify/usb_notify_sysfs.c b/drivers/usb/notify/usb_notify_sysfs.c
new file mode 100644 (file)
index 0000000..65bda87
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+ *  drivers/usb/notify/usb_notify_sysfs.c
+ *
+ * Copyright (C) 2015-2017 Samsung, Inc.
+ * Author: Dongrak Shin <dongrak.shin@samsung.com>
+ *
+*/
+
+ /* usb notify layer v3.1 */
+
+#define pr_fmt(fmt) "usb_notify: " fmt
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/usb.h>
+#include <linux/usb_notify.h>
+#include <linux/string.h>
+#include "usb_notify_sysfs.h"
+
+#if defined(CONFIG_USB_HW_PARAM)
+const char
+usb_hw_param_print[USB_CCIC_HW_PARAM_MAX][MAX_HWPARAM_STRING] = {
+       {"CC_WATER"},
+       {"CC_DRY"},
+       {"CC_I2C"},
+       {"CC_OVC"},
+       {"CC_OTG"},
+       {"CC_DP"},
+       {"CC_VR"},
+       {"H_SUPER"},
+       {"H_HIGH"},
+       {"H_FULL"},
+       {"H_LOW"},
+       {"C_SUPER"},
+       {"C_HIGH"},
+       {"H_AUDIO"},
+       {"H_COMM"},
+       {"H_HID"},
+       {"H_PHYSIC"},
+       {"H_IMAGE"},
+       {"H_PRINTER"},
+       {"H_STORAGE"},
+       {"H_HUB"},
+       {"H_CDC"},
+       {"H_CSCID"},
+       {"H_CONTENT"},
+       {"H_VIDEO"},
+       {"H_WIRE"},
+       {"H_MISC"},
+       {"H_APP"},
+       {"H_VENDOR"},
+       {"CC_DEX"},
+       {"CC_WTIME"},
+       {"CC_WVBUS"},
+       {"CC_WVTIME"},
+       {"CC_CSHORT"},
+       {"M_AFCNAK"},
+       {"M_AFCERR"},
+       {"M_DCDTMO"},
+       {"CC_VER"},
+};
+#endif
+
+struct notify_data {
+       struct class *usb_notify_class;
+       atomic_t device_count;
+};
+
+static struct notify_data usb_notify_data;
+
+static int is_valid_cmd(char *cur_cmd, char *prev_cmd)
+{
+       pr_info("%s : current state=%s, previous state=%s\n",
+               __func__, cur_cmd, prev_cmd);
+
+       if (!strcmp(cur_cmd, "ON") ||
+                       !strncmp(cur_cmd, "ON_ALL_", 7)) {
+               if (!strcmp(prev_cmd, "ON") ||
+                               !strncmp(prev_cmd, "ON_ALL_", 7)) {
+                       goto ignore;
+               } else if (!strncmp(prev_cmd, "ON_HOST_", 8)) {
+                       goto all;
+               } else if (!strncmp(prev_cmd, "ON_CLIENT_", 10)) {
+                       goto all;
+               } else if (!strcmp(prev_cmd, "OFF")) {
+                       goto all;
+               } else {
+                       goto invalid;
+               }
+       } else if (!strcmp(cur_cmd, "OFF")) {
+               if (!strcmp(prev_cmd, "ON") ||
+                               !strncmp(prev_cmd, "ON_ALL_", 7)) {
+                       goto off;
+               } else if (!strncmp(prev_cmd, "ON_HOST_", 8)) {
+                       goto off;
+               } else if (!strncmp(prev_cmd, "ON_CLIENT_", 10)) {
+                       goto off;
+               } else if (!strcmp(prev_cmd, "OFF")) {
+                       goto ignore;
+               } else {
+                       goto invalid;
+               }
+       } else if (!strncmp(cur_cmd, "ON_HOST_", 8)) {
+               if (!strcmp(prev_cmd, "ON") ||
+                               !strncmp(prev_cmd, "ON_ALL_", 7)) {
+                       goto host;
+               } else if (!strncmp(prev_cmd, "ON_HOST_", 8)) {
+                       goto ignore;
+               } else if (!strncmp(prev_cmd, "ON_CLIENT_", 10)) {
+                       goto host;
+               } else if (!strcmp(prev_cmd, "OFF")) {
+                       goto host;
+               } else {
+                       goto invalid;
+               }
+       } else if (!strncmp(cur_cmd, "ON_CLIENT_", 10)) {
+               if (!strcmp(prev_cmd, "ON") ||
+                               !strncmp(prev_cmd, "ON_ALL_", 7)) {
+                       goto client;
+               } else if (!strncmp(prev_cmd, "ON_HOST_", 8)) {
+                       goto client;
+               } else if (!strncmp(prev_cmd, "ON_CLIENT_", 10)) {
+                       goto ignore;
+               } else if (!strcmp(prev_cmd, "OFF")) {
+                       goto client;
+               } else {
+                       goto invalid;
+               }
+       } else {
+               goto invalid;
+       }
+host:
+       pr_info("%s cmd=%s is accepted.\n", __func__, cur_cmd);
+       return NOTIFY_BLOCK_TYPE_HOST;
+client:
+       pr_info("%s cmd=%s is accepted.\n", __func__, cur_cmd);
+       return NOTIFY_BLOCK_TYPE_CLIENT;
+all:
+       pr_info("%s cmd=%s is accepted.\n", __func__, cur_cmd);
+       return NOTIFY_BLOCK_TYPE_ALL;
+off:
+       pr_info("%s cmd=%s is accepted.\n", __func__, cur_cmd);
+       return NOTIFY_BLOCK_TYPE_NONE;
+ignore:
+       pr_err("%s cmd=%s is ignored but saved.\n", __func__, cur_cmd);
+       return -EEXIST;
+invalid:
+       pr_err("%s cmd=%s is invalid.\n", __func__, cur_cmd);
+       return -EINVAL;
+}
+
+static ssize_t disable_show(
+       struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+
+       pr_info("read disable_state %s\n", udev->disable_state_cmd);
+       return sprintf(buf, "%s\n", udev->disable_state_cmd);
+}
+
+static ssize_t disable_store(
+               struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+
+       char *disable;
+       int sret, param = -EINVAL;
+       size_t ret = -ENOMEM;
+
+       if (size > MAX_DISABLE_STR_LEN) {
+               pr_err("%s size(%zu) is too long.\n", __func__, size);
+               goto error;
+       }
+
+       disable = kzalloc(size+1, GFP_KERNEL);
+       if (!disable)
+               goto error;
+
+       sret = sscanf(buf, "%s", disable);
+       if (sret != 1)
+               goto error1;
+
+       if (udev->set_disable) {
+               param = is_valid_cmd(disable, udev->disable_state_cmd);
+               if (param == -EINVAL) {
+                       ret = param;
+               } else {
+                       if (param != -EEXIST)
+                               udev->set_disable(udev, param);
+                       strncpy(udev->disable_state_cmd,
+                               disable, sizeof(udev->disable_state_cmd)-1);
+                       ret = size;
+               }
+       } else
+               pr_err("set_disable func is NULL\n");
+error1:
+       kfree(disable);
+error:
+       return ret;
+}
+
+static ssize_t support_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+       struct otg_notify *n = udev->o_notify;
+       char *support;
+
+       if (n->unsupport_host || !IS_ENABLED(CONFIG_USB_HOST_NOTIFY))
+               support = "CLIENT";
+       else
+               support = "ALL";
+
+       pr_info("read support %s\n", support);
+       return snprintf(buf,  sizeof(support)+1, "%s\n", support);
+}
+
+static ssize_t otg_speed_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+       struct otg_notify *n = udev->o_notify;
+       char *speed;
+
+       switch (n->speed) {
+       case USB_SPEED_SUPER:
+               speed = "SUPER";
+               break;
+       case USB_SPEED_HIGH:
+               speed = "HIGH";
+               break;
+       case USB_SPEED_FULL:
+               speed = "FULL";
+               break;
+       case USB_SPEED_LOW:
+               speed = "LOW";
+               break;
+       default:
+               speed = "UNKNOWN";
+               break;
+       }
+       pr_info("%s : read otg speed %s\n", __func__, speed);
+       return snprintf(buf,  sizeof(speed)+1, "%s\n", speed);
+}
+
+#if defined(CONFIG_USB_HW_PARAM)
+static unsigned long long strtoull(char *ptr, char **end, int base)
+{
+       unsigned long long ret = 0;
+
+       if (base > 36)
+               goto out;
+
+       while (*ptr) {
+               int digit;
+
+               if (*ptr >= '0' && *ptr <= '9' && *ptr < '0' + base)
+                       digit = *ptr - '0';
+               else if (*ptr >= 'A' && *ptr < 'A' + base - 10)
+                       digit = *ptr - 'A' + 10;
+               else if (*ptr >= 'a' && *ptr < 'a' + base - 10)
+                       digit = *ptr - 'a' + 10;
+               else
+                       break;
+
+               ret *= base;
+               ret += digit;
+               ptr++;
+       }
+
+out:
+       if (end)
+               *end = (char *)ptr;
+
+       return ret;
+}
+
+static ssize_t usb_hw_param_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+       struct otg_notify *n = udev->o_notify;
+       int index, ret = 0;
+       unsigned long long *p_param = NULL;
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       p_param = get_hw_param(n, USB_CCIC_WATER_INT_COUNT);
+       if (p_param)
+               *p_param += get_ccic_water_count();
+       p_param = get_hw_param(n, USB_CCIC_DRY_INT_COUNT);
+       if (p_param)
+               *p_param += get_ccic_dry_count();
+       p_param = get_hw_param(n, USB_CLIENT_SUPER_SPEED_COUNT);
+       if (p_param)
+               *p_param += get_usb310_count();
+       p_param = get_hw_param(n, USB_CLIENT_HIGH_SPEED_COUNT);
+       if (p_param)
+               *p_param += get_usb210_count();
+       p_param = get_hw_param(n, USB_CCIC_WATER_TIME_DURATION);
+       if (p_param)
+               *p_param += get_waterDet_duration();
+       p_param = get_hw_param(n, USB_CCIC_WATER_VBUS_COUNT);
+       if (p_param)
+               *p_param += get_waterChg_count();
+       p_param = get_hw_param(n, USB_CCIC_WATER_VBUS_TIME_DURATION);
+       if (p_param)
+               *p_param += get_wVbus_duration();
+       p_param = get_hw_param(n, USB_CCIC_VERSION);
+#if defined(CONFIG_USB_NOTIFY_PROC_LOG)
+       if (p_param)
+               *p_param = show_ccic_version();
+#endif
+#endif
+       for (index = 0; index < USB_CCIC_HW_PARAM_MAX - 1; index++) {
+               p_param = get_hw_param(n, index);
+               if (p_param)
+                       ret += sprintf(buf + ret, "%llu ", *p_param);
+               else
+                       ret += sprintf(buf + ret, "0 ");
+       }
+       p_param = get_hw_param(n, index);
+       if (p_param)
+               ret += sprintf(buf + ret, "%llu\n", *p_param);
+       else
+               ret += sprintf(buf + ret, "0\n");
+       pr_info("%s - ret : %d\n", __func__, ret);
+
+       return ret;
+}
+
+static ssize_t usb_hw_param_store(
+               struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+       struct otg_notify *n = udev->o_notify;
+       unsigned long long prev_hw_param[USB_CCIC_HW_PARAM_MAX] = {0, };
+
+       int index = 0;
+       size_t ret = -ENOMEM;
+       char *token, *str = (char *)buf;
+
+       if (size > MAX_HWPARAM_STR_LEN) {
+               pr_err("%s size(%zu) is too long.\n", __func__, size);
+               goto error;
+       }
+       ret = size;
+       if (size < USB_CCIC_HW_PARAM_MAX) {
+               pr_err("%s efs file is not created correctly.\n", __func__);
+               goto error;
+       }
+
+       for (index = 0; index < (USB_CCIC_HW_PARAM_MAX - 1); index++) {
+               token = strsep(&str, " ");
+               if (token)
+                       prev_hw_param[index] = strtoull(token, NULL, 10);
+
+               if (!token || (prev_hw_param[index] > HWPARAM_DATA_LIMIT))
+                       goto error;
+       }
+
+       for (index = 0; index < (USB_CCIC_HW_PARAM_MAX - 1); index++)
+               *(get_hw_param(n, index)) += prev_hw_param[index];
+       pr_info("%s - ret : %zu\n", __func__, ret);
+error:
+       return ret;
+}
+
+static ssize_t hw_param_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+       struct otg_notify *n = udev->o_notify;
+       int index, ret = 0;
+       unsigned long long *p_param = NULL;
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       p_param = get_hw_param(n, USB_CCIC_WATER_INT_COUNT);
+       if (p_param)
+               *p_param += get_ccic_water_count();
+       p_param = get_hw_param(n, USB_CCIC_DRY_INT_COUNT);
+       if (p_param)
+               *p_param += get_ccic_dry_count();
+       p_param = get_hw_param(n, USB_CLIENT_SUPER_SPEED_COUNT);
+       if (p_param)
+               *p_param += get_usb310_count();
+       p_param = get_hw_param(n, USB_CLIENT_HIGH_SPEED_COUNT);
+       if (p_param)
+               *p_param += get_usb210_count();
+       p_param = get_hw_param(n, USB_CCIC_WATER_TIME_DURATION);
+       if (p_param)
+               *p_param += get_waterDet_duration();
+       p_param = get_hw_param(n, USB_CCIC_WATER_VBUS_COUNT);
+       if (p_param)
+               *p_param += get_waterChg_count();
+       p_param = get_hw_param(n, USB_CCIC_WATER_VBUS_TIME_DURATION);
+       if (p_param)
+               *p_param += get_wVbus_duration();
+       p_param = get_hw_param(n, USB_CCIC_VERSION);
+#if defined(CONFIG_USB_NOTIFY_PROC_LOG)
+       if (p_param)
+               *p_param = show_ccic_version();
+#endif
+#endif
+       for (index = 0; index < USB_CCIC_HW_PARAM_MAX - 1; index++) {
+               p_param = get_hw_param(n, index);
+               if (p_param)
+                       ret += sprintf(buf + ret, "\"%s\":\"%llu\",",
+                               usb_hw_param_print[index], *p_param);
+               else
+                       ret += sprintf(buf + ret, "\"%s\":\"0\",",
+                               usb_hw_param_print[index]);
+       }
+       /* CCIC FW version */
+       ret += sprintf(buf + ret, "\"%s\":\"",
+               usb_hw_param_print[index]);
+       p_param = get_hw_param(n, index);
+       if (p_param) {
+               /* HW Version */
+               ret += sprintf(buf + ret, "%02X%02X%02X%02X",
+                       *((unsigned char *)p_param + 3),
+                       *((unsigned char *)p_param + 2),
+                       *((unsigned char *)p_param + 1),
+                       *((unsigned char *)p_param));
+               /* SW Main Version */
+               ret += sprintf(buf + ret, "%02X%02X%02X",
+                       *((unsigned char *)p_param + 6),
+                       *((unsigned char *)p_param + 5),
+                       *((unsigned char *)p_param + 4));
+               /* SW Boot Version */
+               ret += sprintf(buf + ret, "%02X",
+                       *((unsigned char *)p_param + 7));
+               ret += sprintf(buf + ret, "\"\n");
+       } else
+               ret += sprintf(buf + ret, "0000000000000000\"\n");
+
+       pr_info("%s - ret : %d\n", __func__, ret);
+       return ret;
+}
+
+static ssize_t hw_param_store(
+               struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+       struct otg_notify *n = udev->o_notify;
+       int index = 0;
+       size_t ret = -ENOMEM;
+       char *str = (char *)buf;
+
+       if (size > 2) {
+               pr_err("%s size(%zu) is too long.\n", __func__, size);
+               goto error;
+       }
+       ret = size;
+       pr_info("%s : %s\n", __func__, str);
+       if (!strncmp(str, "c", 1))
+               for (index = 0; index < USB_CCIC_HW_PARAM_MAX; index++)
+                       *(get_hw_param(n, index)) = 0;
+error:
+       return ret;
+}
+#endif
+
+char interface_class_name[USB_CLASS_VENDOR_SPEC][4] = {
+       {"PER"},
+       {"AUD"},
+       {"COM"},
+       {"HID"},
+       {"PHY"},
+       {"STI"},
+       {"PRI"},
+       {"MAS"},
+       {"HUB"},
+       {"CDC"},
+       {"CSC"},
+       {"CON"},
+       {"VID"},
+       {"WIR"},
+       {"MIS"},
+       {"APP"},
+       {"VEN"}
+};
+
+void init_usb_whitelist_array(int *whitelist_array)
+{
+       int i;
+
+       for (i = 1; i <= MAX_CLASS_TYPE_NUM; i++)
+               whitelist_array[i] = 0;
+}
+
+int set_usb_whitelist_array(const char *buf, int *whitelist_array)
+{
+       int valid_class_count = 0;
+       char *ptr = NULL;
+       int i;
+       char *source;
+
+       source = (char *)buf;
+       while ((ptr = strsep(&source, ":")) != NULL) {
+               pr_info("%s token = %c%c%c!\n", __func__,
+                       ptr[0], ptr[1], ptr[2]);
+               for (i = 1; i <= USB_CLASS_VENDOR_SPEC; i++) {
+                       if (!strncmp(ptr, interface_class_name[i-1], 3))
+                               whitelist_array[i] = 1;
+               }
+       }
+
+       for (i = 1; i <= U_CLASS_VENDOR_SPEC; i++) {
+               if (whitelist_array[i])
+                       valid_class_count++;
+       }
+       pr_info("%s valid_class_count = %d!\n", __func__, valid_class_count);
+       return valid_class_count;
+}
+
+static ssize_t whitelist_for_mdm_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+
+       if (udev == NULL) {
+               pr_err("udev is NULL\n");
+               return -EINVAL;
+       }
+       pr_info("%s read whitelist_classes %s\n",
+               __func__, udev->whitelist_str);
+       return sprintf(buf, "%s\n", udev->whitelist_str);
+}
+
+static ssize_t whitelist_for_mdm_store(
+               struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct usb_notify_dev *udev = (struct usb_notify_dev *)
+               dev_get_drvdata(dev);
+       char *disable;
+       int sret;
+       size_t ret = -ENOMEM;
+       int mdm_disable;
+       int valid_whilelist_count;
+
+       if (udev == NULL) {
+               pr_err("udev is NULL\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (size > MAX_WHITELIST_STR_LEN) {
+               pr_err("%s size(%zu) is too long.\n", __func__, size);
+               goto error;
+       }
+
+       disable = kzalloc(size+1, GFP_KERNEL);
+       if (!disable)
+               goto error;
+
+       sret = sscanf(buf, "%s", disable);
+       if (sret != 1)
+               goto error1;
+       pr_info("%s buf=%s\n", __func__, disable);
+
+       init_usb_whitelist_array(udev->whitelist_array_for_mdm);
+       /* To active displayport, hub class must be enabled */
+       if (!strncmp(buf, "ABL", 3)) {
+               udev->whitelist_array_for_mdm[USB_CLASS_HUB] = 1;
+               mdm_disable = NOTIFY_MDM_TYPE_ON;
+       } else if (!strncmp(buf, "OFF", 3))
+               mdm_disable = NOTIFY_MDM_TYPE_OFF;
+       else {
+               valid_whilelist_count = set_usb_whitelist_array
+                       (buf, udev->whitelist_array_for_mdm);
+               if (valid_whilelist_count > 0) {
+                       udev->whitelist_array_for_mdm[USB_CLASS_HUB] = 1;
+                       mdm_disable = NOTIFY_MDM_TYPE_ON;
+               } else
+                       mdm_disable = NOTIFY_MDM_TYPE_OFF;
+       }
+
+       strncpy(udev->whitelist_str,
+               disable, sizeof(udev->whitelist_str)-1);
+
+       if (udev->set_mdm) {
+               udev->set_mdm(udev, mdm_disable);
+               ret = size;
+       } else {
+               pr_err("set_mdm func is NULL\n");
+               ret = -EINVAL;
+       }
+error1:
+       kfree(disable);
+error:
+       return ret;
+}
+
+static DEVICE_ATTR(disable, 0664, disable_show, disable_store);
+static DEVICE_ATTR(support, 0444, support_show, NULL);
+static DEVICE_ATTR(otg_speed, 0444, otg_speed_show, NULL);
+static DEVICE_ATTR(whitelist_for_mdm, 0664,
+       whitelist_for_mdm_show, whitelist_for_mdm_store);
+#if defined(CONFIG_USB_HW_PARAM)
+static DEVICE_ATTR(usb_hw_param, 0664, usb_hw_param_show, usb_hw_param_store);
+static DEVICE_ATTR(hw_param, 0664, hw_param_show, hw_param_store);
+#endif
+
+static struct attribute *usb_notify_attrs[] = {
+       &dev_attr_disable.attr,
+       &dev_attr_support.attr,
+       &dev_attr_otg_speed.attr,
+       &dev_attr_whitelist_for_mdm.attr,
+#if defined(CONFIG_USB_HW_PARAM)
+       &dev_attr_usb_hw_param.attr,
+       &dev_attr_hw_param.attr,
+#endif
+       NULL,
+};
+
+static struct attribute_group usb_notify_attr_grp = {
+       .attrs = usb_notify_attrs,
+};
+
+static int create_usb_notify_class(void)
+{
+       if (!usb_notify_data.usb_notify_class) {
+               usb_notify_data.usb_notify_class
+                       = class_create(THIS_MODULE, "usb_notify");
+               if (IS_ERR(usb_notify_data.usb_notify_class))
+                       return PTR_ERR(usb_notify_data.usb_notify_class);
+               atomic_set(&usb_notify_data.device_count, 0);
+       }
+
+       return 0;
+}
+
+int usb_notify_dev_register(struct usb_notify_dev *udev)
+{
+       int ret;
+
+       if (!usb_notify_data.usb_notify_class) {
+               ret = create_usb_notify_class();
+               if (ret < 0)
+                       return ret;
+       }
+
+       udev->index = atomic_inc_return(&usb_notify_data.device_count);
+       udev->dev = device_create(usb_notify_data.usb_notify_class, NULL,
+               MKDEV(0, udev->index), NULL, udev->name);
+       if (IS_ERR(udev->dev))
+               return PTR_ERR(udev->dev);
+
+       udev->disable_state = 0;
+       strncpy(udev->disable_state_cmd, "OFF",
+                       sizeof(udev->disable_state_cmd)-1);
+       ret = sysfs_create_group(&udev->dev->kobj, &usb_notify_attr_grp);
+       if (ret < 0) {
+               device_destroy(usb_notify_data.usb_notify_class,
+                               MKDEV(0, udev->index));
+               return ret;
+       }
+
+       dev_set_drvdata(udev->dev, udev);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_notify_dev_register);
+
+void usb_notify_dev_unregister(struct usb_notify_dev *udev)
+{
+       sysfs_remove_group(&udev->dev->kobj, &usb_notify_attr_grp);
+       device_destroy(usb_notify_data.usb_notify_class, MKDEV(0, udev->index));
+       dev_set_drvdata(udev->dev, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_notify_dev_unregister);
+
+int usb_notify_class_init(void)
+{
+       return create_usb_notify_class();
+}
+EXPORT_SYMBOL_GPL(usb_notify_class_init);
+
+void usb_notify_class_exit(void)
+{
+       class_destroy(usb_notify_data.usb_notify_class);
+}
+EXPORT_SYMBOL_GPL(usb_notify_class_exit);
+
diff --git a/drivers/usb/notify/usb_notify_sysfs.h b/drivers/usb/notify/usb_notify_sysfs.h
new file mode 100644 (file)
index 0000000..d001ecc
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015-2017 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+  /* usb notify layer v3.1 */
+
+#ifndef __LINUX_USB_NOTIFY_SYSFS_H__
+#define __LINUX_USB_NOTIFY_SYSFS_H__
+
+#define MAX_DISABLE_STR_LEN 32
+#define MAX_WHITELIST_STR_LEN 256
+#define MAX_CLASS_TYPE_NUM     USB_CLASS_VENDOR_SPEC
+
+enum u_interface_class_type {
+       U_CLASS_PER_INTERFACE = 1,
+       U_CLASS_AUDIO,
+       U_CLASS_COMM,
+       U_CLASS_HID,
+       U_CLASS_PHYSICAL,
+       U_CLASS_STILL_IMAGE,
+       U_CLASS_PRINTER,
+       U_CLASS_MASS_STORAGE,
+       U_CLASS_HUB,
+       U_CLASS_CDC_DATA,
+       U_CLASS_CSCID,
+       U_CLASS_CONTENT_SEC,
+       U_CLASS_VIDEO,
+       U_CLASS_WIRELESS_CONTROLLER,
+       U_CLASS_MISC,
+       U_CLASS_APP_SPEC,
+       U_CLASS_VENDOR_SPEC,
+};
+
+struct usb_notify_dev {
+       const char *name;
+       struct device *dev;
+       struct otg_notify *o_notify;
+       int index;
+       unsigned long disable_state;
+       char disable_state_cmd[MAX_DISABLE_STR_LEN];
+       int (*set_disable)(struct usb_notify_dev *, int);
+       void (*set_mdm)(struct usb_notify_dev *udev, int mdm_disable);
+       char whitelist_str[MAX_WHITELIST_STR_LEN];
+       int whitelist_array_for_mdm[MAX_CLASS_TYPE_NUM+1];
+};
+
+extern int usb_notify_dev_register(struct usb_notify_dev *ndev);
+extern void usb_notify_dev_unregister(struct usb_notify_dev *ndev);
+extern int usb_notify_class_init(void);
+extern void usb_notify_class_exit(void);
+#endif
+
diff --git a/drivers/usb/notify/usblog_proc_notify.c b/drivers/usb/notify/usblog_proc_notify.c
new file mode 100644 (file)
index 0000000..25a2329
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+ *  drivers/usb/notify/usblog_proc_notify.c
+ *
+ * Copyright (C) 2016-2017 Samsung, Inc.
+ * Author: Dongrak Shin <dongrak.shin@samsung.com>
+ *
+*/
+
+ /* usb notify layer v3.1 */
+
+ #define pr_fmt(fmt) "usb_notify: " fmt
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
+#include <linux/usb_notify.h>
+
+#define USBLOG_MAX_BUF_SIZE    (1 << 7) /* 128 */
+#define USBLOG_MAX_BUF2_SIZE   (1 << 8) /* 256 */
+#define USBLOG_MAX_BUF3_SIZE   (1 << 9) /* 512 */
+#define USBLOG_MAX_STRING_SIZE (1 << 4) /* 16 */
+#define USBLOG_CMP_INDEX       3
+
+#define USBLOG_CCIC_BUFFER_SIZE        USBLOG_MAX_BUF3_SIZE
+#define USBLOG_MODE_BUFFER_SIZE        USBLOG_MAX_BUF_SIZE
+#define USBLOG_STATE_BUFFER_SIZE       USBLOG_MAX_BUF2_SIZE
+#define USBLOG_EVENT_BUFFER_SIZE       USBLOG_MAX_BUF_SIZE
+
+struct ccic_buf {
+       unsigned long long ts_nsec;
+       int cc_type;
+       uint64_t noti;
+};
+
+struct mode_buf {
+       unsigned long long ts_nsec;
+       char usbmode_str[USBLOG_MAX_STRING_SIZE];
+};
+
+struct state_buf {
+       unsigned long long ts_nsec;
+       int usbstate;
+};
+
+struct event_buf {
+       unsigned long long ts_nsec;
+       unsigned long event;
+       int enable;
+};
+
+struct usblog_buf {
+       unsigned long long ccic_count;
+       unsigned long long mode_count;
+       unsigned long long state_count;
+       unsigned long long event_count;
+       unsigned long ccic_index;
+       unsigned long mode_index;
+       unsigned long state_index;
+       unsigned long event_index;
+       struct ccic_buf ccic_buffer[USBLOG_CCIC_BUFFER_SIZE];
+       struct mode_buf mode_buffer[USBLOG_MODE_BUFFER_SIZE];
+       struct state_buf state_buffer[USBLOG_STATE_BUFFER_SIZE];
+       struct event_buf event_buffer[USBLOG_EVENT_BUFFER_SIZE];
+};
+
+struct ccic_version {
+       unsigned char hw_version[4];
+       unsigned char sw_main[3];
+       unsigned char sw_boot;
+};
+
+struct usblog_root_str {
+       struct usblog_buf *usblog_buffer;
+       struct ccic_version ccic_ver;
+       spinlock_t usblog_lock;
+       int init;
+};
+
+struct ccic_type {
+       uint64_t src:4;
+       uint64_t dest:4;
+       uint64_t id:8;
+       uint64_t sub1:16;
+       uint64_t sub2:16;
+       uint64_t sub3:16;
+};
+
+static struct usblog_root_str usblog_root;
+
+static const char *usbstate_string(enum usblog_state usbstate)
+{
+       switch (usbstate) {
+       case NOTIFY_CONFIGURED:
+               return "CONFIGURED";
+       case NOTIFY_CONNECTED:
+               return "CONNECTED";
+       case NOTIFY_DISCONNECTED:
+               return "DISCONNECTED";
+       case NOTIFY_RESET:
+               return "RESET";
+       case NOTIFY_RESET_FULL:
+               return "RESET : FULL";
+       case NOTIFY_RESET_HIGH:
+               return "RESET: HIGH";
+       case NOTIFY_RESET_SUPER:
+               return "RESET : SUPER";
+       case NOTIFY_PULLUP:
+               return "VBUS_PULLUP (EN OR DIS)";
+       case NOTIFY_PULLUP_ENABLE:
+               return "VBUS_PULLUP_EN";
+       case NOTIFY_PULLUP_EN_SUCCESS:
+               return "VBUS_PULLUP_EN : S";
+       case NOTIFY_PULLUP_EN_FAIL:
+               return "VBUS_PULLUP_EN : F";
+       case NOTIFY_PULLUP_DISABLE:
+               return "VBUS_PULLUP_DIS";
+       case NOTIFY_PULLUP_DIS_SUCCESS:
+               return "VBUS_PULLUP_DIS : S";
+       case NOTIFY_PULLUP_DIS_FAIL:
+               return "VBUS_PULLUP_DIS : F";
+       case NOTIFY_VBUS_SESSION:
+               return "VBUS_SESSION (EN OR DIS)";
+       case NOTIFY_VBUS_SESSION_ENABLE:
+               return "VBUS_SESSION_EN";
+       case NOTIFY_VBUS_EN_SUCCESS:
+               return "VBUS_SESSION_EN : S";
+       case NOTIFY_VBUS_EN_FAIL:
+               return "VBUS_SESSION_EN : F";
+       case NOTIFY_VBUS_SESSION_DISABLE:
+               return "VBUS_SESSIOIN_DIS";
+       case NOTIFY_VBUS_DIS_SUCCESS:
+               return "VBUS_SESSION_DIS : S";
+       case NOTIFY_VBUS_DIS_FAIL:
+               return "VBUS_SESSION_DIS : F";
+       case NOTIFY_ACCSTART:
+               return "ACCSTART";
+       case NOTIFY_HIGH:
+               return "HIGH SPEED";
+       case NOTIFY_SUPER:
+               return "SUPER SPEED";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *usbstatus_string(enum usblog_status usbstatus)
+{
+       switch (usbstatus) {
+       case NOTIFY_DETACH:
+               return "DETACH";
+       case NOTIFY_ATTACH_DFP:
+               return "ATTACH_DFP";
+       case NOTIFY_ATTACH_UFP:
+               return "ATTACH_UFP";
+       case NOTIFY_ATTACH_DRP:
+               return "ATTACH_DRP";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *ccic_dev_string(enum ccic_device dev)
+{
+       switch (dev) {
+       case NOTIFY_DEV_INITIAL:
+               return "INITIAL";
+       case NOTIFY_DEV_USB:
+               return "USB";
+       case NOTIFY_DEV_BATTERY:
+               return "BATTERY";
+       case NOTIFY_DEV_PDIC:
+               return "PDIC";
+       case NOTIFY_DEV_MUIC:
+               return "MUIC";
+       case NOTIFY_DEV_CCIC:
+               return "CCIC";
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       case NOTIFY_DEV_MANAGER:
+               return "MANAGER";
+#endif
+       case NOTIFY_DEV_DP:
+               return "DP";
+       case NOTIFY_DEV_USB_DP:
+               return "USB_DP";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *ccic_id_string(enum ccic_id id)
+{
+       switch (id) {
+       case NOTIFY_ID_INITIAL:
+               return "ID_INITIAL";
+       case NOTIFY_ID_ATTACH:
+               return "ID_CONNECT";
+       case NOTIFY_ID_RID:
+               return "ID_RID";
+       case NOTIFY_ID_USB:
+               return "ID_USB";
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       case NOTIFY_ID_POWER_STATUS:
+               return "ID_POWER_STATUS";
+#endif
+       case NOTIFY_ID_WATER:
+               return "ID_WATER";
+       case NOTIFY_ID_VCONN:
+               return "ID_VCONN";
+       case NOTIFY_ID_DP_CONNECT:
+               return "ID_DP_CONNECT";
+       case NOTIFY_ID_DP_HPD:
+               return "ID_DP_HPD";
+       case NOTIFY_ID_DP_LINK_CONF:
+               return "ID_DP_LINK_CONF";
+       case NOTIFY_ID_USB_DP:
+               return "ID_USB_DP";
+       case NOTIFY_ID_ROLE_SWAP:
+               return "ID_ROLE_SWAP";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *ccic_rid_string(enum ccic_rid rid)
+{
+       switch (rid) {
+       case NOTIFY_RID_UNDEFINED:
+               return "RID_UNDEFINED";
+       case NOTIFY_RID_000K:
+               return "RID_000K";
+       case NOTIFY_RID_001K:
+               return "RID_001K";
+       case NOTIFY_RID_255K:
+               return "RID_255K";
+       case NOTIFY_RID_301K:
+               return "RID_301K";
+       case NOTIFY_RID_523K:
+               return "RID_523K";
+       case NOTIFY_RID_619K:
+               return "RID_619K";
+       case NOTIFY_RID_OPEN:
+               return "RID_OPEN";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *ccic_con_string(enum ccic_con con)
+{
+       switch (con) {
+       case NOTIFY_CON_DETACH:
+               return "DETACHED";
+       case NOTIFY_CON_ATTACH:
+               return "ATTACHED";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *ccic_rprd_string(enum ccic_rprd rprd)
+{
+       switch (rprd) {
+       case NOTIFY_RD:
+               return "RD";
+       case NOTIFY_RP:
+               return "RP";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *ccic_rpstatus_string(enum ccic_rpstatus rprd)
+{
+       switch (rprd) {
+       case NOTIFY_RP_NONE:
+               return "NONE";
+       case NOTIFY_RP_56K:
+               return "RP_56K";
+       case NOTIFY_RP_22K:
+               return "RP_22K";
+       case NOTIFY_RP_10K:
+               return "RP_10K";
+       case NOTIFY_RP_ABNORMAL:
+               return "RP_ABNORMAL";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *ccic_hpd_string(enum ccic_hpd hpd)
+{
+       switch (hpd) {
+       case NOTIFY_HPD_LOW:
+               return "LOW";
+       case NOTIFY_HPD_HIGH:
+               return "HIGH";
+       case NOTIFY_HPD_IRQ:
+               return "IRQ";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+static const char *ccic_pinA_string(enum ccic_pin_assignment pin)
+{
+       switch (pin) {
+       case NOTIFY_DP_PIN_UNKNOWN:
+               return "UNKNOWN";
+       case NOTIFY_DP_PIN_A:
+               return "DP_PIN_A";
+       case NOTIFY_DP_PIN_B:
+               return "DP_PIN_B";
+       case NOTIFY_DP_PIN_C:
+               return "DP_PIN_C";
+       case NOTIFY_DP_PIN_D:
+               return "DP_PIN_D";
+       case NOTIFY_DP_PIN_E:
+               return "DP_PIN_E";
+       case NOTIFY_DP_PIN_F:
+               return "DP_PIN_F";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static const char *ccic_alternatemode_string(uint64_t id)
+{
+       if ((id & ALTERNATE_MODE_READY) && (id & ALTERNATE_MODE_START))
+               return "READY & START";
+       else if ((id & ALTERNATE_MODE_READY) && (id & ALTERNATE_MODE_STOP))
+               return "READY & STOP";
+       else if (id & ALTERNATE_MODE_READY)
+               return "MODE READY";
+       else if (id & ALTERNATE_MODE_START)
+               return "START";
+       else if (id & ALTERNATE_MODE_STOP)
+               return "STOP";
+       else if (id & ALTERNATE_MODE_RESET)
+               return "RESET";
+       else
+               return "UNDEFINED";
+}
+
+static void print_ccic_event(struct seq_file *m, unsigned long long ts,
+               unsigned long rem_nsec, int cc_type, uint64_t *noti)
+{
+       struct ccic_type type = *(struct ccic_type *)noti;
+       int cable = type.sub3;
+
+       switch (cc_type) {
+       case NOTIFY_FUNCSTATE:
+               seq_printf(m, "[%5lu.%06lu] function state = %llu\n",
+                       (unsigned long)ts, rem_nsec / 1000, *noti);
+               break;
+       case NOTIFY_ALTERNATEMODE:
+               seq_printf(m, "[%5lu.%06lu] ccic alternate mode is %s 0x%04llx\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_alternatemode_string(*noti), *noti);
+               break;
+       case NOTIFY_CCIC_EVENT:
+               if (type.id == NOTIFY_ID_ATTACH)
+                       seq_printf(m,
+                               "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s rprd=%s rpstatus=%s cable=%d %s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_rprd_string(type.sub2),
+                       ccic_rpstatus_string(type.sub3),
+                       cable, ccic_con_string(type.sub1));
+               else if (type.id  == NOTIFY_ID_RID)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s rid=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_rid_string(type.sub1));
+               else if (type.id  == NOTIFY_ID_USB)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s status=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       usbstatus_string(type.sub2));
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+               else if (type.id  == NOTIFY_ID_POWER_STATUS)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s %s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_con_string(type.sub1));
+#endif
+               else if (type.id  == NOTIFY_ID_WATER)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:   id=%s src=%s dest=%s    %s detected\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       type.sub1 ? "WATER":"DRY");
+               else if (type.id  == NOTIFY_ID_VCONN)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest));
+               else if (type.id  == NOTIFY_ID_DP_CONNECT)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s 0x%04x/0x%04x %s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       type.sub2,
+                       type.sub3,
+                       ccic_con_string(type.sub1));
+               else if (type.id  == NOTIFY_ID_DP_HPD)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s hpd=%s irq=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_hpd_string(type.sub1),
+                       type.sub2 ? "VALID":"NONE");
+               else if (type.id  == NOTIFY_ID_DP_LINK_CONF)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s PIN-assign=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_pinA_string(type.sub1));
+               else if (type.id  == NOTIFY_ID_USB_DP)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s CON=%d HS=%d\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       type.sub1,
+                       type.sub2);
+               else if (type.id  == NOTIFY_ID_ROLE_SWAP)
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:        id=%s src=%s dest=%s sub1=%d sub2=%d\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       type.sub1,
+                       type.sub2);
+               else
+                       seq_printf(m, "[%5lu.%06lu] ccic notify:    id=%s src=%s dest=%s rprd=%s %s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_rprd_string(type.sub2),
+                       ccic_con_string(type.sub1));
+               break;
+       case NOTIFY_MANAGER:
+               if (type.id == NOTIFY_ID_ATTACH)
+                       seq_printf(m,
+                               "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s rprd=%s rpstatus=%s cable=%d %s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_rprd_string(type.sub2),
+                       ccic_rpstatus_string(type.sub3),
+                       cable, ccic_con_string(type.sub1));
+               else if (type.id  == NOTIFY_ID_RID)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s rid=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_rid_string(type.sub1));
+               else if (type.id  == NOTIFY_ID_USB)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s status=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       usbstatus_string(type.sub2));
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+               else if (type.id  == NOTIFY_ID_POWER_STATUS)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s %s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_con_string(type.sub1));
+#endif
+               else if (type.id  == NOTIFY_ID_WATER)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s    %s detected\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       type.sub1 ? "WATER":"DRY");
+               else if (type.id  == NOTIFY_ID_VCONN)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest));
+               else if (type.id  == NOTIFY_ID_DP_CONNECT)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s 0x%04x/0x%04x %s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       type.sub2,
+                       type.sub3,
+                       ccic_con_string(type.sub1));
+               else if (type.id  == NOTIFY_ID_DP_HPD)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s hpd=%s irq=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_hpd_string(type.sub1),
+                       type.sub2 ? "VALID":"NONE");
+               else if (type.id  == NOTIFY_ID_DP_LINK_CONF)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s PIN-assign=%s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_pinA_string(type.sub1));
+               else if (type.id  == NOTIFY_ID_USB_DP)
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s CON=%d HS=%d\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       type.sub1,
+                       type.sub2);
+               else if (type.id  == NOTIFY_ID_ROLE_SWAP)
+                       seq_printf(m, "[%5lu.%06lu] manager notify:     id=%s src=%s dest=%s syb1=%d sub2=%d\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       type.sub1,
+                       type.sub2);
+               else
+                       seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s rprd=%s %s\n",
+                       (unsigned long)ts, rem_nsec / 1000,
+                       ccic_id_string(type.id),
+                       ccic_dev_string(type.src),
+                       ccic_dev_string(type.dest),
+                       ccic_rprd_string(type.sub2),
+                       ccic_con_string(type.sub1));
+               break;
+       default:
+               pr_info("%s undefined event\n", __func__);
+               break;
+       }
+}
+
+static int usblog_proc_show(struct seq_file *m, void *v)
+{
+       struct usblog_buf *temp_usblog_buffer;
+       unsigned long long ts;
+       unsigned long rem_nsec;
+       unsigned long i;
+
+       temp_usblog_buffer = usblog_root.usblog_buffer;
+
+       if (!temp_usblog_buffer)
+               goto err;
+
+       seq_printf(m,
+               "usblog CC IC version:\n");
+
+       seq_printf(m,
+               "hw version =%2x %2x %2x %2x\n",
+               usblog_root.ccic_ver.hw_version[3],
+               usblog_root.ccic_ver.hw_version[2],
+               usblog_root.ccic_ver.hw_version[1],
+               usblog_root.ccic_ver.hw_version[0]);
+
+       seq_printf(m,
+               "sw version =%2x %2x %2x %2x\n",
+               usblog_root.ccic_ver.sw_main[2],
+               usblog_root.ccic_ver.sw_main[1],
+               usblog_root.ccic_ver.sw_main[0],
+               usblog_root.ccic_ver.sw_boot);
+
+       seq_printf(m,
+               "\n\n");
+       seq_printf(m,
+               "usblog CCIC EVENT: count=%llu maxline=%d\n",
+                       temp_usblog_buffer->ccic_count,
+                                       USBLOG_CCIC_BUFFER_SIZE);
+
+       if (temp_usblog_buffer->ccic_count >= USBLOG_CCIC_BUFFER_SIZE) {
+               for (i = temp_usblog_buffer->ccic_index;
+                       i < USBLOG_CCIC_BUFFER_SIZE; i++) {
+                       ts = temp_usblog_buffer->ccic_buffer[i].ts_nsec;
+                       rem_nsec = do_div(ts, 1000000000);
+                       print_ccic_event(m, ts, rem_nsec,
+                               temp_usblog_buffer->ccic_buffer[i].cc_type,
+                               &temp_usblog_buffer->ccic_buffer[i].noti);
+               }
+       }
+
+       for (i = 0; i < temp_usblog_buffer->ccic_index; i++) {
+               ts = temp_usblog_buffer->ccic_buffer[i].ts_nsec;
+               rem_nsec = do_div(ts, 1000000000);
+               print_ccic_event(m, ts, rem_nsec,
+                               temp_usblog_buffer->ccic_buffer[i].cc_type,
+                               &temp_usblog_buffer->ccic_buffer[i].noti);
+       }
+
+       seq_printf(m,
+               "\n\n");
+       seq_printf(m,
+               "usblog USB_MODE: count=%llu maxline=%d\n",
+                       temp_usblog_buffer->mode_count,
+                                       USBLOG_MODE_BUFFER_SIZE);
+
+       if (temp_usblog_buffer->mode_count >= USBLOG_MODE_BUFFER_SIZE) {
+               for (i = temp_usblog_buffer->mode_index;
+                       i < USBLOG_MODE_BUFFER_SIZE; i++) {
+                       ts = temp_usblog_buffer->mode_buffer[i].ts_nsec;
+                       rem_nsec = do_div(ts, 1000000000);
+                       seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts,
+                               rem_nsec / 1000,
+                       temp_usblog_buffer->mode_buffer[i].usbmode_str);
+               }
+       }
+
+       for (i = 0; i < temp_usblog_buffer->mode_index; i++) {
+               ts = temp_usblog_buffer->mode_buffer[i].ts_nsec;
+               rem_nsec = do_div(ts, 1000000000);
+               seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts,
+                       rem_nsec / 1000,
+               temp_usblog_buffer->mode_buffer[i].usbmode_str);
+       }
+       seq_printf(m,
+               "\n\n");
+       seq_printf(m,
+               "usblog USB STATE: count=%llu maxline=%d\n",
+                       temp_usblog_buffer->state_count,
+                               USBLOG_STATE_BUFFER_SIZE);
+
+       if (temp_usblog_buffer->state_count >= USBLOG_STATE_BUFFER_SIZE) {
+               for (i = temp_usblog_buffer->state_index;
+                       i < USBLOG_STATE_BUFFER_SIZE; i++) {
+                       ts = temp_usblog_buffer->state_buffer[i].ts_nsec;
+                       rem_nsec = do_div(ts, 1000000000);
+                       seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts,
+                               rem_nsec / 1000,
+                       usbstate_string(temp_usblog_buffer->
+                                               state_buffer[i].usbstate));
+               }
+       }
+
+       for (i = 0; i < temp_usblog_buffer->state_index; i++) {
+               ts = temp_usblog_buffer->state_buffer[i].ts_nsec;
+               rem_nsec = do_div(ts, 1000000000);
+               seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts,
+                       rem_nsec / 1000,
+               usbstate_string(temp_usblog_buffer->state_buffer[i].usbstate));
+       }
+       seq_printf(m,
+               "\n\n");
+       seq_printf(m,
+               "usblog USB EVENT: count=%llu maxline=%d\n",
+                       temp_usblog_buffer->event_count,
+                               USBLOG_EVENT_BUFFER_SIZE);
+
+       if (temp_usblog_buffer->event_count >= USBLOG_EVENT_BUFFER_SIZE) {
+               for (i = temp_usblog_buffer->event_index;
+                       i < USBLOG_EVENT_BUFFER_SIZE; i++) {
+                       ts = temp_usblog_buffer->event_buffer[i].ts_nsec;
+                       rem_nsec = do_div(ts, 1000000000);
+                       seq_printf(m, "[%5lu.%06lu] %s %s\n", (unsigned long)ts,
+                               rem_nsec / 1000,
+                       event_string(temp_usblog_buffer->event_buffer[i].event),
+                       status_string(temp_usblog_buffer->
+                                       event_buffer[i].enable));
+               }
+       }
+
+       for (i = 0; i < temp_usblog_buffer->event_index; i++) {
+               ts = temp_usblog_buffer->event_buffer[i].ts_nsec;
+               rem_nsec = do_div(ts, 1000000000);
+               seq_printf(m, "[%5lu.%06lu] %s %s\n", (unsigned long)ts,
+                       rem_nsec / 1000,
+               event_string(temp_usblog_buffer->event_buffer[i].event),
+               status_string(temp_usblog_buffer->event_buffer[i].enable));
+       }
+err:
+       return 0;
+}
+
+static int usblog_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, usblog_proc_show, NULL);
+}
+
+static const struct file_operations usblog_proc_fops = {
+       .open           = usblog_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+void ccic_store_usblog_notify(int type, uint64_t *param1)
+{
+       struct ccic_buf *ccic_buffer;
+       unsigned long long *target_count;
+       unsigned long *target_index;
+
+       target_count = &usblog_root.usblog_buffer->ccic_count;
+       target_index = &usblog_root.usblog_buffer->ccic_index;
+       ccic_buffer = &usblog_root.usblog_buffer->ccic_buffer[*target_index];
+       if (ccic_buffer == NULL) {
+               pr_err("%s target_buffer error\n", __func__);
+               goto err;
+       }
+       ccic_buffer->ts_nsec = local_clock();
+       ccic_buffer->cc_type = type;
+       ccic_buffer->noti = *param1;
+
+       *target_index = (*target_index+1)%USBLOG_CCIC_BUFFER_SIZE;
+       (*target_count)++;
+err:
+       return;
+}
+
+void mode_store_usblog_notify(int type, char *param1)
+{
+       struct mode_buf *md_buffer;
+       unsigned long long *target_count;
+       unsigned long *target_index;
+       char buf[256], buf2[4];
+       char *b, *name;
+       int param_len;
+
+       target_count = &usblog_root.usblog_buffer->mode_count;
+       target_index = &usblog_root.usblog_buffer->mode_index;
+       md_buffer = &usblog_root.usblog_buffer->mode_buffer[*target_index];
+       if (md_buffer == NULL) {
+               pr_err("%s target_buffer error\n", __func__);
+               goto err;
+       }
+       md_buffer->ts_nsec = local_clock();
+
+       strlcpy(buf, param1, sizeof(buf));
+       b = strim(buf);
+
+       if (type == NOTIFY_USBMODE_EXTRA) {
+               param_len = strlen(b);
+               if (param_len >= USBLOG_MAX_STRING_SIZE)
+                       param_len = USBLOG_MAX_STRING_SIZE-1;
+               strncpy(md_buffer->usbmode_str, b, param_len);
+       } else if (type == NOTIFY_USBMODE) {
+               if (b) {
+                       name = strsep(&b, ",");
+                       strlcpy(buf2, name, sizeof(buf2));
+                       strncpy(md_buffer->usbmode_str, buf2,
+                               sizeof(md_buffer->usbmode_str)-1);
+               }
+               while (b) {
+                       name = strsep(&b, ",");
+                       if (!name)
+                               continue;
+                       if (USBLOG_MAX_STRING_SIZE
+                               - strlen(md_buffer->usbmode_str) < 5) {
+                               strncpy(md_buffer->usbmode_str, "overflow",
+                                       sizeof(md_buffer->usbmode_str)-1);
+                               b = NULL;
+                       } else {
+                               strncat(md_buffer->usbmode_str, ",", 1);
+                               strncat(md_buffer->usbmode_str, name, 3);
+                       }
+               }
+       }
+
+       *target_index = (*target_index+1)%USBLOG_MODE_BUFFER_SIZE;
+       (*target_count)++;
+err:
+       return;
+}
+
+void state_store_usblog_notify(int type, char *param1)
+{
+       struct state_buf *st_buffer;
+       unsigned long long *target_count;
+       unsigned long *target_index;
+       char buf[256], index, index2, index3;
+       char *b, *name;
+       int usbstate;
+
+       target_count = &usblog_root.usblog_buffer->state_count;
+       target_index = &usblog_root.usblog_buffer->state_index;
+       st_buffer = &usblog_root.usblog_buffer->state_buffer[*target_index];
+       if (st_buffer == NULL) {
+               pr_err("%s target_buffer error\n", __func__);
+               goto err;
+       }
+       st_buffer->ts_nsec = local_clock();
+
+       strlcpy(buf, param1, sizeof(buf));
+       b = strim(buf);
+       name = strsep(&b, "=");
+
+       index = *(b+USBLOG_CMP_INDEX);
+
+       switch (index) {
+       case 'F': /* CONFIGURED */
+               usbstate = NOTIFY_CONFIGURED;
+               break;
+       case 'N':  /* CONNECTED */
+               usbstate = NOTIFY_CONNECTED;
+               break;
+       case 'C':  /* DISCONNECTED */
+               usbstate = NOTIFY_DISCONNECTED;
+               break;
+       case 'E':  /* RESET */
+               name = strsep(&b, ":");
+               if (b) {
+                       index2 = *b;
+                       switch (index2) {
+                       case 'L': /* FULL SPEED */
+                               usbstate = NOTIFY_RESET_FULL;
+                               break;
+                       case 'H':  /* HIGH SPEED */
+                               usbstate = NOTIFY_RESET_HIGH;
+                               break;
+                       case 'S': /* SUPER SPEED */
+                               usbstate = NOTIFY_RESET_SUPER;
+                               break;
+                       default:
+                               usbstate = NOTIFY_RESET;
+                               break;
+                       }
+               } else
+                       usbstate = NOTIFY_RESET;
+               break;
+       case 'L': /* GADGET PULL UP/DN */
+               name = strsep(&b, ":");
+               if (b) {
+                       index2 = *b;
+                       name = strsep(&b, ":");
+                       if (b)
+                               index3 = *b;
+                       else /* X means none */
+                               index3 = 'X';
+               } else /* X means none */
+                       index2 = 'X';
+
+               switch (index2) {
+               case 'E': /* VBUS SESSION ENABLE */
+                       if (index3 == 'S')
+                               usbstate = NOTIFY_PULLUP_EN_SUCCESS;
+                       else if (index3 == 'F')
+                               usbstate = NOTIFY_PULLUP_EN_FAIL;
+                       else
+                               usbstate = NOTIFY_PULLUP_ENABLE;
+                       break;
+               case 'D': /* VBUS SESSION DISABLE */
+                       if (index3 == 'S')
+                               usbstate = NOTIFY_PULLUP_DIS_SUCCESS;
+                       else if (index3 == 'F')
+                               usbstate = NOTIFY_PULLUP_DIS_FAIL;
+                       else
+                               usbstate = NOTIFY_PULLUP_DISABLE;
+                       break;
+               default:
+                       usbstate = NOTIFY_PULLUP;
+                       break;
+               }
+               break;
+       case 'R':  /* ACCESSORY START */
+               usbstate = NOTIFY_ACCSTART;
+               break;
+       case 'S':  /* GADGET_VBUS EN/DN*/
+               name = strsep(&b, ":");
+               if (b) {
+                       index2 = *b;
+                       name = strsep(&b, ":");
+                       if (b)
+                               index3 = *b;
+                       else /* X means none */
+                               index3 = 'X';
+               } else /* X means none */
+                       index2 = 'X';
+
+               switch (index2) {
+               case 'E': /* VBUS SESSION ENABLE */
+                       if (index3 == 'S')
+                               usbstate = NOTIFY_VBUS_EN_SUCCESS;
+                       else if (index3 == 'F')
+                               usbstate = NOTIFY_VBUS_EN_FAIL;
+                       else
+                               usbstate = NOTIFY_VBUS_SESSION_ENABLE;
+                       break;
+               case 'D': /* VBUS SESSION DISABLE */
+                       if (index3 == 'S')
+                               usbstate = NOTIFY_VBUS_DIS_SUCCESS;
+                       else if (index3 == 'F')
+                               usbstate = NOTIFY_VBUS_DIS_FAIL;
+                       else
+                               usbstate = NOTIFY_VBUS_SESSION_DISABLE;
+                       break;
+               default:
+                       usbstate = NOTIFY_VBUS_SESSION;
+                       break;
+               }
+               break;
+       case 'D': /* SUPER SPEED */
+               usbstate = NOTIFY_SUPER;
+               break;
+       case 'H': /*HIGH SPEED */
+               usbstate = NOTIFY_HIGH;
+               break;
+       default:
+               pr_err("%s state param error. state=%s\n", __func__, param1);
+               goto err;
+       }
+
+       st_buffer->usbstate = usbstate;
+
+       *target_index = (*target_index+1)%USBLOG_STATE_BUFFER_SIZE;
+       (*target_count)++;
+err:
+       return;
+}
+
+void event_store_usblog_notify(int type, unsigned long *param1, int *param2)
+{
+       struct event_buf *ev_buffer;
+       unsigned long long *target_count;
+       unsigned long *target_index;
+
+       target_count = &usblog_root.usblog_buffer->event_count;
+       target_index = &usblog_root.usblog_buffer->event_index;
+       ev_buffer = &usblog_root.usblog_buffer->event_buffer[*target_index];
+       if (ev_buffer == NULL) {
+               pr_err("%s target_buffer error\n", __func__);
+               goto err;
+       }
+       ev_buffer->ts_nsec = local_clock();
+       ev_buffer->event = *param1;
+       ev_buffer->enable = *param2;
+
+       *target_index = (*target_index+1)%USBLOG_EVENT_BUFFER_SIZE;
+       (*target_count)++;
+err:
+       return;
+}
+
+void store_usblog_notify(int type, void *param1, void *param2)
+{
+       unsigned long flags = 0;
+       uint64_t temp = 0;
+
+       if (!usblog_root.init)
+               register_usblog_proc();
+
+       spin_lock_irqsave(&usblog_root.usblog_lock, flags);
+
+       if (!usblog_root.usblog_buffer) {
+               pr_err("%s usblog_buffer is null\n", __func__);
+               spin_unlock_irqrestore(&usblog_root.usblog_lock, flags);
+               return;
+       }
+
+       if (type == NOTIFY_FUNCSTATE || type == NOTIFY_ALTERNATEMODE) {
+               temp = *(int *)param1;
+               ccic_store_usblog_notify(type, &temp);
+       } else if (type == NOTIFY_CCIC_EVENT
+               || type == NOTIFY_MANAGER)
+               ccic_store_usblog_notify(type, (uint64_t *)param1);
+       else if (type == NOTIFY_EVENT)
+               event_store_usblog_notify(type,
+                       (unsigned long *)param1, (int *)param2);
+       else  if (type == NOTIFY_USBMODE
+               || type == NOTIFY_USBMODE_EXTRA)
+               mode_store_usblog_notify(type, (char *)param1);
+       else if (type == NOTIFY_USBSTATE)
+               state_store_usblog_notify(type, (char *)param1);
+       else
+               pr_err("%s type error %d\n", __func__, type);
+
+       spin_unlock_irqrestore(&usblog_root.usblog_lock, flags);
+}
+EXPORT_SYMBOL(store_usblog_notify);
+
+void store_ccic_version(unsigned char *hw, unsigned char *sw_main,
+                       unsigned char *sw_boot)
+{
+       if (!hw || !sw_main || !sw_boot) {
+               pr_err("%s null buffer\n", __func__);
+               return;
+       }
+
+       memcpy(&usblog_root.ccic_ver.hw_version, hw, 4);
+       memcpy(&usblog_root.ccic_ver.sw_main, sw_main, 3);
+       memcpy(&usblog_root.ccic_ver.sw_boot, sw_boot, 1);
+}
+EXPORT_SYMBOL(store_ccic_version);
+
+#if defined(CONFIG_USB_HW_PARAM)
+unsigned long long show_ccic_version(void)
+{
+       unsigned long long ret = 0;
+
+       memcpy(&ret, &usblog_root.ccic_ver, sizeof(unsigned long long));
+       return ret;
+}
+EXPORT_SYMBOL(show_ccic_version);
+#endif
+
+int register_usblog_proc(void)
+{
+       int ret = 0;
+       struct otg_notify *o_notify = get_otg_notify();
+
+       if (usblog_root.init) {
+               pr_err("%s already registered\n", __func__);
+               if (o_notify != NULL)
+                       goto err;
+       }
+
+       spin_lock_init(&usblog_root.usblog_lock);
+
+       usblog_root.init = 1;
+
+       proc_create("usblog", 0, NULL, &usblog_proc_fops);
+
+       usblog_root.usblog_buffer
+               = kzalloc(sizeof(struct usblog_buf), GFP_KERNEL);
+       if (!usblog_root.usblog_buffer) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       pr_info("%s size=%zu\n", __func__, sizeof(struct usblog_buf));
+err:
+       return ret;
+}
+EXPORT_SYMBOL(register_usblog_proc);
+
+void unregister_usblog_proc(void)
+{
+       kfree(usblog_root.usblog_buffer);
+       usblog_root.usblog_buffer = NULL;
+       remove_proc_entry("usblog", NULL);
+       usblog_root.init = 0;
+}
+EXPORT_SYMBOL(unregister_usblog_proc);
+
diff --git a/include/linux/battery/sec_charging_common.h b/include/linux/battery/sec_charging_common.h
new file mode 100644 (file)
index 0000000..e02ed6b
--- /dev/null
@@ -0,0 +1,941 @@
+/*
+ * sec_charging_common.h
+ * Samsung Mobile Charging Common Header
+ *
+ * Copyright (C) 2012 Samsung Electronics, Inc.
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SEC_CHARGING_COMMON_H
+#define __SEC_CHARGING_COMMON_H __FILE__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+
+/* definitions */
+#define        SEC_SIZEOF_POWER_SUPPLY_TYPE    POWER_SUPPLY_TYPE_MAX
+
+enum sec_battery_voltage_mode {
+       /* average voltage */
+       SEC_BATTERY_VOLTAGE_AVERAGE = 0,
+       /* open circuit voltage */
+       SEC_BATTERY_VOLTAGE_OCV,
+};
+
+enum sec_battery_current_mode {
+       /* uA */
+       SEC_BATTERY_CURRENT_UA = 0,
+       /* mA */
+       SEC_BATTERY_CURRENT_MA,
+};
+
+enum sec_battery_capacity_mode {
+       /* designed capacity */
+       SEC_BATTERY_CAPACITY_DESIGNED = 0,
+       /* absolute capacity by fuel gauge */
+       SEC_BATTERY_CAPACITY_ABSOLUTE,
+       /* temperary capacity in the time */
+       SEC_BATTERY_CAPACITY_TEMPERARY,
+       /* current capacity now */
+       SEC_BATTERY_CAPACITY_CURRENT,
+       /* cell aging information */
+       SEC_BATTERY_CAPACITY_AGEDCELL,
+       /* charge count */
+       SEC_BATTERY_CAPACITY_CYCLE,
+};
+
+enum sec_wireless_info_mode {
+       SEC_WIRELESS_OTP_FIRM_RESULT = 0,
+       SEC_WIRELESS_IC_GRADE,
+       SEC_WIRELESS_IC_REVISION,
+       SEC_WIRELESS_OTP_FIRM_VER_BIN,
+       SEC_WIRELESS_OTP_FIRM_VER,
+       SEC_WIRELESS_TX_FIRM_RESULT,
+       SEC_WIRELESS_TX_FIRM_VER,
+       SEC_TX_FIRMWARE,
+       SEC_WIRELESS_OTP_FIRM_VERIFY,
+};
+
+enum sec_wireless_firm_update_mode {
+       SEC_WIRELESS_RX_SDCARD_MODE = 0,
+       SEC_WIRELESS_RX_BUILT_IN_MODE,
+       SEC_WIRELESS_TX_ON_MODE,
+       SEC_WIRELESS_TX_OFF_MODE,
+       SEC_WIRELESS_RX_INIT,
+};
+
+enum sec_tx_firmware_mode {
+       SEC_TX_OFF = 0,
+       SEC_TX_STANDBY,
+       SEC_TX_POWER_TRANSFER,
+       SEC_TX_ERROR,
+};
+
+enum sec_wireless_control_mode {
+       WIRELESS_VOUT_OFF = 0,
+       WIRELESS_VOUT_NORMAL_VOLTAGE,   /* 5V , reserved by factory */
+       WIRELESS_VOUT_RESERVED,                 /* 6V */
+       WIRELESS_VOUT_HIGH_VOLTAGE,             /* 9V , reserved by factory */
+       WIRELESS_VOUT_CC_CV_VOUT,
+       WIRELESS_VOUT_CV_CALL,
+       WIRELESS_VOUT_CC_CALL,
+       WIRELESS_VOUT_5V,
+       WIRELESS_VOUT_9V,
+       WIRELESS_VOUT_9V_OTG,
+       WIRELESS_PAD_FAN_OFF,
+       WIRELESS_PAD_FAN_ON,
+       WIRELESS_PAD_LED_OFF,
+       WIRELESS_PAD_LED_ON,
+       WIRELESS_VRECT_ADJ_ON,
+       WIRELESS_VRECT_ADJ_OFF,
+       WIRELESS_VRECT_ADJ_ROOM_0,
+       WIRELESS_VRECT_ADJ_ROOM_1,
+       WIRELESS_VRECT_ADJ_ROOM_2,
+       WIRELESS_VRECT_ADJ_ROOM_3,
+       WIRELESS_VRECT_ADJ_ROOM_4,
+       WIRELESS_VRECT_ADJ_ROOM_5,
+       WIRELESS_CLAMP_ENABLE,
+};
+
+enum sec_siop_event_mode {
+       SIOP_EVENT_IDLE = 0,
+       SIOP_EVENT_WPC_CALL_START,              /* 5V wireless charging + Call */
+       SIOP_EVENT_WPC_CALL_END,                /* 5V wireless charging + Call */
+       SIOP_EVENT_MAX,                                 /* end */
+};
+
+enum sec_wireless_pad_mode {
+       SEC_WIRELESS_PAD_NONE = 0,
+       SEC_WIRELESS_PAD_WPC,
+       SEC_WIRELESS_PAD_WPC_HV,
+       SEC_WIRELESS_PAD_WPC_PACK,
+       SEC_WIRELESS_PAD_WPC_PACK_TA,
+       SEC_WIRELESS_PAD_WPC_STAND,
+       SEC_WIRELESS_PAD_WPC_STAND_HV,
+       SEC_WIRELESS_PAD_PMA,
+};
+
+/* ADC type */
+enum sec_battery_adc_type {
+       /* NOT using this ADC channel */
+       SEC_BATTERY_ADC_TYPE_NONE = 0,
+       /* ADC in AP */
+       SEC_BATTERY_ADC_TYPE_AP,
+       /* ADC by additional IC */
+       SEC_BATTERY_ADC_TYPE_IC,
+       SEC_BATTERY_ADC_TYPE_NUM
+};
+
+enum sec_battery_adc_channel {
+       SEC_BAT_ADC_CHANNEL_CABLE_CHECK = 0,
+       SEC_BAT_ADC_CHANNEL_BAT_CHECK,
+       SEC_BAT_ADC_CHANNEL_TEMP,
+       SEC_BAT_ADC_CHANNEL_TEMP_AMBIENT,
+       SEC_BAT_ADC_CHANNEL_FULL_CHECK,
+       SEC_BAT_ADC_CHANNEL_VOLTAGE_NOW,
+       SEC_BAT_ADC_CHANNEL_CHG_TEMP,
+       SEC_BAT_ADC_CHANNEL_INBAT_VOLTAGE,
+       SEC_BAT_ADC_CHANNEL_DISCHARGING_CHECK,
+       SEC_BAT_ADC_CHANNEL_DISCHARGING_NTC,
+       SEC_BAT_ADC_CHANNEL_WPC_TEMP,
+       SEC_BAT_ADC_CHANNEL_SLAVE_CHG_TEMP,
+       SEC_BAT_ADC_CHANNEL_NUM,
+};
+
+enum sec_battery_charge_mode {
+       SEC_BAT_CHG_MODE_CHARGING = 0,
+       SEC_BAT_CHG_MODE_CHARGING_OFF,
+       SEC_BAT_CHG_MODE_BUCK_OFF,
+};
+
+/* charging mode */
+enum sec_battery_charging_mode {
+       /* no charging */
+       SEC_BATTERY_CHARGING_NONE = 0,
+       /* 1st charging */
+       SEC_BATTERY_CHARGING_1ST,
+       /* 2nd charging */
+       SEC_BATTERY_CHARGING_2ND,
+       /* recharging */
+       SEC_BATTERY_CHARGING_RECHARGING,
+};
+
+/* chg_temp state */
+enum sec_battery_chg_temp_state {
+       SEC_BATTERY_CHG_TEMP_NONE = 0,
+       SEC_BATTERY_CHG_TEMP_HIGH_1ST,
+       SEC_BATTERY_CHG_TEMP_HIGH_2ND,
+};
+
+/* pad_limit state */
+enum sec_battery_wpc_pad_state {
+       SEC_BATTERY_WPC_TEMP_NONE = 0,
+       SEC_BATTERY_WPC_TEMP_HIGH,
+};
+
+/* bat_temp state */
+enum sec_battery_bat_temp_state {
+       SEC_BATTERY_MIX_TEMP_NONE = 0,
+       SEC_BATTERY_MIX_TEMP_HIGH,
+};
+
+/* heat_limit state */
+enum sec_battery_wc_heat_state {
+       SEC_BATTERY_WC_HEAT_NONE = 0, /* (9V, 1A), (9V, 600mA) */
+       SEC_BATTERY_WC_HEAT_HIGH, /* (5V, 400mA) */
+};
+struct sec_bat_adc_api {
+       bool (*init)(struct platform_device *);
+       bool (*exit)(void);
+       int (*read)(unsigned int);
+};
+#define sec_bat_adc_api_t struct sec_bat_adc_api
+
+/* monitor activation */
+enum sec_battery_polling_time_type {
+       /* same order with power supply status */
+       SEC_BATTERY_POLLING_TIME_BASIC = 0,
+       SEC_BATTERY_POLLING_TIME_CHARGING,
+       SEC_BATTERY_POLLING_TIME_DISCHARGING,
+       SEC_BATTERY_POLLING_TIME_NOT_CHARGING,
+       SEC_BATTERY_POLLING_TIME_SLEEP,
+};
+
+enum sec_battery_monitor_polling {
+       /* polling work queue */
+       SEC_BATTERY_MONITOR_WORKQUEUE,
+       /* alarm polling */
+       SEC_BATTERY_MONITOR_ALARM,
+       /* timer polling (NOT USE) */
+       SEC_BATTERY_MONITOR_TIMER,
+};
+#define sec_battery_monitor_polling_t \
+       enum sec_battery_monitor_polling
+
+/* full charged check : POWER_SUPPLY_PROP_STATUS */
+enum sec_battery_full_charged {
+       SEC_BATTERY_FULLCHARGED_NONE = 0,
+       /* current check by ADC */
+       SEC_BATTERY_FULLCHARGED_ADC,
+       /* fuel gauge current check */
+       SEC_BATTERY_FULLCHARGED_FG_CURRENT,
+       /* time check */
+       SEC_BATTERY_FULLCHARGED_TIME,
+       /* SOC check */
+       SEC_BATTERY_FULLCHARGED_SOC,
+       /* charger GPIO, NO additional full condition */
+       SEC_BATTERY_FULLCHARGED_CHGGPIO,
+       /* charger interrupt, NO additional full condition */
+       SEC_BATTERY_FULLCHARGED_CHGINT,
+       /* charger power supply property, NO additional full condition */
+       SEC_BATTERY_FULLCHARGED_CHGPSY,
+};
+
+/* Self discharger type */
+enum sec_battery_discharger_type {
+       /* type ADC */
+       SEC_BAT_SELF_DISCHARGING_BY_ADC = 0,
+       /* type Fuel Gauge */
+       SEC_BAT_SELF_DISCHARGING_BY_FG,
+};
+
+#define sec_battery_full_charged_t \
+       enum sec_battery_full_charged
+
+/* full check condition type (can be used overlapped) */
+#define sec_battery_full_condition_t unsigned int
+/* SEC_BATTERY_FULL_CONDITION_NOTIMEFULL
+  * full-charged by absolute-timer only in high voltage
+  */
+#define SEC_BATTERY_FULL_CONDITION_NOTIMEFULL  1
+/* SEC_BATTERY_FULL_CONDITION_NOSLEEPINFULL
+  * do not set polling time as sleep polling time in full-charged
+  */
+#define SEC_BATTERY_FULL_CONDITION_NOSLEEPINFULL       2
+/* SEC_BATTERY_FULL_CONDITION_SOC
+  * use capacity for full-charged check
+  */
+#define SEC_BATTERY_FULL_CONDITION_SOC         4
+/* SEC_BATTERY_FULL_CONDITION_VCELL
+  * use VCELL for full-charged check
+  */
+#define SEC_BATTERY_FULL_CONDITION_VCELL       8
+/* SEC_BATTERY_FULL_CONDITION_AVGVCELL
+  * use average VCELL for full-charged check
+  */
+#define SEC_BATTERY_FULL_CONDITION_AVGVCELL    16
+/* SEC_BATTERY_FULL_CONDITION_OCV
+  * use OCV for full-charged check
+  */
+#define SEC_BATTERY_FULL_CONDITION_OCV         32
+
+/* recharge check condition type (can be used overlapped) */
+#define sec_battery_recharge_condition_t unsigned int
+/* SEC_BATTERY_RECHARGE_CONDITION_SOC
+  * use capacity for recharging check
+  */
+#define SEC_BATTERY_RECHARGE_CONDITION_SOC             1
+/* SEC_BATTERY_RECHARGE_CONDITION_AVGVCELL
+  * use average VCELL for recharging check
+  */
+#define SEC_BATTERY_RECHARGE_CONDITION_AVGVCELL                2
+/* SEC_BATTERY_RECHARGE_CONDITION_VCELL
+  * use VCELL for recharging check
+  */
+#define SEC_BATTERY_RECHARGE_CONDITION_VCELL           4
+
+/* battery check : POWER_SUPPLY_PROP_PRESENT */
+enum sec_battery_check {
+       /* No Check for internal battery */
+       SEC_BATTERY_CHECK_NONE,
+       /* by ADC */
+       SEC_BATTERY_CHECK_ADC,
+       /* by callback function (battery certification by 1 wired)*/
+       SEC_BATTERY_CHECK_CALLBACK,
+       /* by PMIC */
+       SEC_BATTERY_CHECK_PMIC,
+       /* by fuel gauge */
+       SEC_BATTERY_CHECK_FUELGAUGE,
+       /* by charger */
+       SEC_BATTERY_CHECK_CHARGER,
+       /* by interrupt (use check_battery_callback() to check battery) */
+       SEC_BATTERY_CHECK_INT,
+};
+#define sec_battery_check_t \
+       enum sec_battery_check
+
+/* OVP, UVLO check : POWER_SUPPLY_PROP_HEALTH */
+enum sec_battery_ovp_uvlo {
+       /* by callback function */
+       SEC_BATTERY_OVP_UVLO_CALLBACK,
+       /* by PMIC polling */
+       SEC_BATTERY_OVP_UVLO_PMICPOLLING,
+       /* by PMIC interrupt */
+       SEC_BATTERY_OVP_UVLO_PMICINT,
+       /* by charger polling */
+       SEC_BATTERY_OVP_UVLO_CHGPOLLING,
+       /* by charger interrupt */
+       SEC_BATTERY_OVP_UVLO_CHGINT,
+};
+#define sec_battery_ovp_uvlo_t \
+       enum sec_battery_ovp_uvlo
+
+/* thermal source */
+enum sec_battery_thermal_source {
+       /* by fuel gauge */
+       SEC_BATTERY_THERMAL_SOURCE_FG,
+       /* by external source */
+       SEC_BATTERY_THERMAL_SOURCE_CALLBACK,
+       /* by ADC */
+       SEC_BATTERY_THERMAL_SOURCE_ADC,
+};
+#define sec_battery_thermal_source_t \
+       enum sec_battery_thermal_source
+
+/* temperature check type */
+enum sec_battery_temp_check {
+       SEC_BATTERY_TEMP_CHECK_NONE = 0,        /* no temperature check */
+       SEC_BATTERY_TEMP_CHECK_ADC,     /* by ADC value */
+       SEC_BATTERY_TEMP_CHECK_TEMP,    /* by temperature */
+};
+#define sec_battery_temp_check_t \
+       enum sec_battery_temp_check
+
+/* cable check (can be used overlapped) */
+#define sec_battery_cable_check_t unsigned int
+/* SEC_BATTERY_CABLE_CHECK_NOUSBCHARGE
+  * for USB cable in tablet model,
+  * status is stuck into discharging,
+  * but internal charging logic is working
+  */
+#define SEC_BATTERY_CABLE_CHECK_NOUSBCHARGE            1
+/* SEC_BATTERY_CABLE_CHECK_NOINCOMPATIBLECHARGE
+  * for incompatible charger
+  * (Not compliant to USB specification,
+  *  cable type is POWER_SUPPLY_TYPE_UNKNOWN),
+  * do NOT charge and show message to user
+  * (only for VZW)
+  */
+#define SEC_BATTERY_CABLE_CHECK_NOINCOMPATIBLECHARGE   2
+/* SEC_BATTERY_CABLE_CHECK_PSY
+  * check cable by power supply set_property
+  */
+#define SEC_BATTERY_CABLE_CHECK_PSY                    4
+/* SEC_BATTERY_CABLE_CHECK_INT
+  * check cable by interrupt
+  */
+#define SEC_BATTERY_CABLE_CHECK_INT                    8
+/* SEC_BATTERY_CABLE_CHECK_CHGINT
+  * check cable by charger interrupt
+  */
+#define SEC_BATTERY_CABLE_CHECK_CHGINT                 16
+/* SEC_BATTERY_CABLE_CHECK_POLLING
+  * check cable by GPIO polling
+  */
+#define SEC_BATTERY_CABLE_CHECK_POLLING                        32
+
+/* check cable source (can be used overlapped) */
+#define sec_battery_cable_source_t unsigned int
+/* SEC_BATTERY_CABLE_SOURCE_EXTERNAL
+ * already given by external argument
+ */
+#define        SEC_BATTERY_CABLE_SOURCE_EXTERNAL       1
+/* SEC_BATTERY_CABLE_SOURCE_CALLBACK
+ * by callback (MUIC, USB switch)
+ */
+#define        SEC_BATTERY_CABLE_SOURCE_CALLBACK       2
+/* SEC_BATTERY_CABLE_SOURCE_ADC
+ * by ADC
+ */
+#define        SEC_BATTERY_CABLE_SOURCE_ADC            4
+
+/* capacity calculation type (can be used overlapped) */
+#define sec_fuelgauge_capacity_type_t int
+/* SEC_FUELGAUGE_CAPACITY_TYPE_RESET
+  * use capacity information to reset fuel gauge
+  * (only for driver algorithm, can NOT be set by user)
+  */
+#define SEC_FUELGAUGE_CAPACITY_TYPE_RESET      (-1)
+/* SEC_FUELGAUGE_CAPACITY_TYPE_RAW
+  * use capacity information from fuel gauge directly
+  */
+#define SEC_FUELGAUGE_CAPACITY_TYPE_RAW                1
+/* SEC_FUELGAUGE_CAPACITY_TYPE_SCALE
+  * rescale capacity by scaling, need min and max value for scaling
+  */
+#define SEC_FUELGAUGE_CAPACITY_TYPE_SCALE      2
+/* SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE
+  * change only maximum capacity dynamically
+  * to keep time for every SOC unit
+  */
+#define SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE      4
+/* SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC
+  * change capacity value by only -1 or +1
+  * no sudden change of capacity
+  */
+#define SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC     8
+/* SEC_FUELGAUGE_CAPACITY_TYPE_SKIP_ABNORMAL
+  * skip current capacity value
+  * if it is abnormal value
+  */
+#define SEC_FUELGAUGE_CAPACITY_TYPE_SKIP_ABNORMAL      16
+
+/* charger function settings (can be used overlapped) */
+#define sec_charger_functions_t unsigned int
+/* SEC_CHARGER_NO_GRADUAL_CHARGING_CURRENT
+ * disable gradual charging current setting
+ * SUMMIT:AICL, MAXIM:regulation loop
+ */
+#define SEC_CHARGER_NO_GRADUAL_CHARGING_CURRENT                1
+
+/* SEC_CHARGER_MINIMUM_SIOP_CHARGING_CURRENT
+ * charging current should be over than USB charging current
+ */
+#define SEC_CHARGER_MINIMUM_SIOP_CHARGING_CURRENT      2
+
+/**
+ * struct sec_bat_adc_table_data - adc to temperature table for sec battery
+ * driver
+ * @adc: adc value
+ * @temperature: temperature(C) * 10
+ */
+struct sec_bat_adc_table_data {
+       int adc;
+       int data;
+};
+#define sec_bat_adc_table_data_t \
+       struct sec_bat_adc_table_data
+
+struct sec_bat_adc_region {
+       int min;
+       int max;
+};
+#define sec_bat_adc_region_t \
+       struct sec_bat_adc_region
+
+struct sec_charging_current {
+#ifdef CONFIG_OF
+       unsigned int input_current_limit;
+       unsigned int fast_charging_current;
+       unsigned int full_check_current_1st;
+       unsigned int full_check_current_2nd;
+#else
+       int input_current_limit;
+       int fast_charging_current;
+       int full_check_current_1st;
+       int full_check_current_2nd;
+#endif
+};
+
+#define sec_charging_current_t \
+       struct sec_charging_current
+
+#if defined(CONFIG_BATTERY_AGE_FORECAST)
+struct sec_age_data {
+       unsigned int cycle;
+       unsigned int float_voltage;
+       unsigned int recharge_condition_vcell;
+       unsigned int full_condition_vcell;
+       unsigned int full_condition_soc;
+};
+
+#define sec_age_data_t \
+       struct sec_age_data
+#endif
+
+struct sec_battery_platform_data {
+       /* NO NEED TO BE CHANGED */
+       /* callback functions */
+       void (*initial_check)(void);
+       void (*monitor_additional_check)(void);
+       bool (*bat_gpio_init)(void);
+       bool (*fg_gpio_init)(void);
+       bool (*is_lpm)(void);
+       bool (*check_jig_status)(void);
+       bool (*is_interrupt_cable_check_possible)(int);
+       int (*check_cable_callback)(void);
+       int (*get_cable_from_extended_cable_type)(int);
+       bool (*cable_switch_check)(void);
+       bool (*cable_switch_normal)(void);
+       bool (*check_cable_result_callback)(int);
+       bool (*check_battery_callback)(void);
+       bool (*check_battery_result_callback)(void);
+       int (*ovp_uvlo_callback)(void);
+       bool (*ovp_uvlo_result_callback)(int);
+       bool (*fuelalert_process)(bool);
+       bool (*get_temperature_callback)(
+                       enum power_supply_property,
+                       union power_supply_propval*);
+
+       /* ADC API for each ADC type */
+       sec_bat_adc_api_t adc_api[SEC_BATTERY_ADC_TYPE_NUM];
+       /* ADC region by power supply type
+        * ADC region should be exclusive
+        */
+       sec_bat_adc_region_t *cable_adc_value;
+       /* charging current for type (0: not use) */
+       sec_charging_current_t *charging_current;
+#ifdef CONFIG_OF
+       unsigned int *polling_time;
+       char *chip_vendor;
+       unsigned int temp_adc_type;
+#else
+       int *polling_time;
+#endif
+       /* NO NEED TO BE CHANGED */
+       unsigned int pre_afc_input_current;
+       unsigned int pre_wc_afc_input_current;
+       unsigned int store_mode_afc_input_current;
+       unsigned int store_mode_hv_wireless_input_current;
+
+       char *pmic_name;
+
+       /* battery */
+       char *vendor;
+       int technology;
+       int battery_type;
+       void *battery_data;
+
+       int bat_gpio_ta_nconnected;
+       /* 1 : active high, 0 : active low */
+       int bat_polarity_ta_nconnected;
+       int bat_irq;
+       int bat_irq_gpio;
+       unsigned long bat_irq_attr;
+       int jig_irq;
+       unsigned long jig_irq_attr;
+       sec_battery_cable_check_t cable_check_type;
+       sec_battery_cable_source_t cable_source_type;
+
+       bool use_LED;                           /* use charging LED */
+
+       /* flag for skipping the swelling mode */
+       bool swelling_mode_skip_in_high_temp;
+       /* sustaining event after deactivated (second) */
+       unsigned int event_waiting_time;
+
+       /* battery swelling */
+       int swelling_high_temp_block;
+       int swelling_high_temp_recov;
+       int swelling_low_temp_block;
+       int swelling_low_temp_recov;
+       unsigned int swelling_low_temp_current;
+       unsigned int swelling_low_temp_topoff;
+       unsigned int swelling_high_temp_current;
+       unsigned int swelling_high_temp_topoff;
+       unsigned int swelling_normal_float_voltage;
+       unsigned int swelling_drop_float_voltage;
+       unsigned int swelling_high_rechg_voltage;
+       unsigned int swelling_low_rechg_voltage;
+
+#if defined(CONFIG_CALC_TIME_TO_FULL)
+       unsigned int ttf_hv_charge_current;
+       unsigned int ttf_hv_wireless_charge_current;
+#endif
+
+#if defined(CONFIG_STEP_CHARGING)
+       /* step charging */
+       unsigned int *step_charging_condition;
+       unsigned int *step_charging_current;
+#endif
+
+       /* self discharging */
+       bool self_discharging_en;
+       unsigned int discharging_adc_max;
+       unsigned int discharging_adc_min;
+       unsigned int self_discharging_voltage_limit;
+       unsigned int discharging_ntc_limit;
+       int force_discharging_limit;
+       int force_discharging_recov;
+       int factory_discharging;
+       unsigned int self_discharging_type;
+#if defined(CONFIG_SW_SELF_DISCHARGING)
+       /* sw self discharging */
+       int self_discharging_temp_block;
+       int self_discharging_volt_block;
+       int self_discharging_temp_recov;
+       int self_discharging_temp_pollingtime;
+#endif
+
+       /* Monitor setting */
+       sec_battery_monitor_polling_t polling_type;
+       /* for initial check */
+       unsigned int monitor_initial_count;
+
+       /* Battery check */
+       sec_battery_check_t battery_check_type;
+       /* how many times do we need to check battery */
+       unsigned int check_count;
+       /* ADC */
+       /* battery check ADC maximum value */
+       unsigned int check_adc_max;
+       /* battery check ADC minimum value */
+       unsigned int check_adc_min;
+
+       /* OVP/UVLO check */
+       sec_battery_ovp_uvlo_t ovp_uvlo_check_type;
+
+       sec_battery_thermal_source_t thermal_source;
+
+       /*
+        * inbat_adc_table
+        * in-battery voltage check for table models:
+        * To read real battery voltage with Jig cable attached,
+        * dedicated hw pin & conversion table of adc-voltage are required
+        */
+#ifdef CONFIG_OF
+       sec_bat_adc_table_data_t *temp_adc_table;
+       sec_bat_adc_table_data_t *temp_amb_adc_table;
+       sec_bat_adc_table_data_t *chg_temp_adc_table;
+       sec_bat_adc_table_data_t *wpc_temp_adc_table;
+       sec_bat_adc_table_data_t *slave_chg_temp_adc_table;
+       sec_bat_adc_table_data_t *inbat_adc_table;
+#else
+       const sec_bat_adc_table_data_t *temp_adc_table;
+       const sec_bat_adc_table_data_t *temp_amb_adc_table;
+#endif
+       unsigned int temp_adc_table_size;
+       unsigned int temp_amb_adc_table_size;
+       unsigned int chg_temp_adc_table_size;
+       unsigned int wpc_temp_adc_table_size;
+       unsigned int slave_chg_temp_adc_table_size;
+       unsigned int inbat_adc_table_size;
+
+       sec_battery_temp_check_t temp_check_type;
+       unsigned int temp_check_count;
+       unsigned int chg_temp_check; /* Control the charging current depending on the chg_thm */
+       unsigned int chg_thermal_source; /* To confirm the charger temperature */
+       unsigned int wpc_temp_check;
+       unsigned int mix_temp_check;
+       unsigned int wpc_thermal_source; /* To confirm the wpc temperature */
+       unsigned int slave_chg_temp_check;
+       unsigned int slave_thermal_source; /* To confirm the slave charger temperature */
+       unsigned int inbat_voltage;
+
+       /*
+        * limit can be ADC value or Temperature
+        * depending on temp_check_type
+        * temperature should be temp x 10 (0.1 degree)
+        */
+       int temp_highlimit_threshold_normal;
+       int temp_highlimit_recovery_normal;
+       int temp_high_threshold_normal;
+       int temp_high_recovery_normal;
+       int temp_low_threshold_normal;
+       int temp_low_recovery_normal;
+       int temp_highlimit_threshold_lpm;
+       int temp_highlimit_recovery_lpm;
+       int temp_high_threshold_lpm;
+       int temp_high_recovery_lpm;
+       int temp_low_threshold_lpm;
+       int temp_low_recovery_lpm;
+       int chg_high_temp_1st;
+       int chg_high_temp_2nd;
+       int chg_high_temp_recovery;
+       unsigned int chg_charging_limit_current;
+       unsigned int chg_charging_limit_current_2nd;
+       unsigned int chg_skip_check_time;
+       unsigned int chg_skip_check_capacity;
+       int wpc_high_temp;
+       int wpc_high_temp_recovery;
+       int wpc_heat_temp_recovery;
+       int wpc_lcd_on_high_temp;
+       int wpc_lcd_on_high_temp_rec;
+       unsigned int wpc_hv_lcd_on_input_limit_current;
+       unsigned int wpc_charging_limit_current;
+       unsigned int sleep_mode_limit_current;
+       unsigned int wc_full_input_limit_current;
+       unsigned int wc_heating_input_limit_current;
+       unsigned int wc_heating_time;
+       unsigned int wc_cv_current;
+       unsigned int wpc_skip_check_time;
+       unsigned int wpc_skip_check_capacity;
+       int mix_high_tbat;
+       int mix_high_tchg;
+       int mix_high_tbat_recov;
+       unsigned int mix_input_limit_current;
+       int mix_high_tbat_hv;
+       int mix_high_tchg_hv;
+       int mix_high_tbat_recov_hv;
+       unsigned int mix_input_limit_current_hv;
+
+       /* If these is NOT full check type or NONE full check type,
+        * it is skipped
+        */
+       /* 1st full check */
+       sec_battery_full_charged_t full_check_type;
+       /* 2nd full check */
+       sec_battery_full_charged_t full_check_type_2nd;
+       unsigned int full_check_count;
+       int chg_gpio_full_check;
+       /* 1 : active high, 0 : active low */
+       int chg_polarity_full_check;
+       sec_battery_full_condition_t full_condition_type;
+       unsigned int full_condition_soc;
+       unsigned int full_condition_vcell;
+       unsigned int full_condition_avgvcell;
+       unsigned int full_condition_ocv;
+
+       unsigned int recharge_check_count;
+       sec_battery_recharge_condition_t recharge_condition_type;
+       unsigned int recharge_condition_soc;
+       unsigned int recharge_condition_avgvcell;
+       unsigned int recharge_condition_vcell;
+
+       /* for absolute timer (second) */
+       unsigned long charging_total_time;
+       /* for recharging timer (second) */
+       unsigned long recharging_total_time;
+       /* reset charging for abnormal malfunction (0: not use) */
+       unsigned long charging_reset_time;
+
+       /* fuel gauge */
+       char *fuelgauge_name;
+       int fg_irq;
+       unsigned long fg_irq_attr;
+       /* fuel alert SOC (-1: not use) */
+       int fuel_alert_soc;
+       /* fuel alert can be repeated */
+       bool repeated_fuelalert;
+       sec_fuelgauge_capacity_type_t capacity_calculation_type;
+       /* soc should be soc x 10 (0.1% degree)
+        * only for scaling
+        */
+       int capacity_max;
+       int capacity_max_hv;
+
+       int capacity_max_margin;
+       int capacity_min;
+
+       /* charger */
+       char *charger_name;
+       char *fgsrc_switch_name;
+       bool support_fgsrc_change;
+
+       /* wireless charger */
+       char *wireless_charger_name;
+       int wireless_cc_cv;
+       int wpc_det;
+       int wpc_en;
+
+       int chg_gpio_en;
+       int chg_irq;
+       unsigned long chg_irq_attr;
+       /* float voltage (mV) */
+#ifdef CONFIG_OF
+       unsigned int chg_float_voltage;
+#else
+       int chg_float_voltage;
+#endif
+#if defined(CONFIG_BATTERY_AGE_FORECAST)
+       int num_age_step;
+       int age_step;
+       int age_data_length;
+       sec_age_data_t* age_data;
+#endif
+       unsigned int siop_event_check_type;
+       unsigned int siop_call_cc_current;
+       unsigned int siop_call_cv_current;
+
+       int siop_input_limit_current;
+       int siop_charging_limit_current;
+       int siop_hv_input_limit_current;
+       int siop_hv_charging_limit_current;
+       int siop_wireless_input_limit_current;
+       int siop_wireless_charging_limit_current;
+       int siop_hv_wireless_input_limit_current;
+       int siop_hv_wireless_charging_limit_current;
+
+       sec_charger_functions_t chg_functions_setting;
+
+       bool fake_capacity;
+
+       /* ADC setting */
+       unsigned int adc_check_count;
+       /* ADC type for each channel */
+       unsigned int adc_type[];
+};
+
+struct sec_charger_platform_data {
+       bool (*chg_gpio_init)(void);
+
+       /* charging current for type (0: not use) */
+       sec_charging_current_t *charging_current;
+
+       /* wirelss charger */
+       char *wireless_charger_name;
+       int wireless_cc_cv;
+
+       int vbus_ctrl_gpio;
+       int chg_gpio_en;
+       /* float voltage (mV) */
+       int chg_float_voltage;
+       int irq_gpio;
+       int chg_irq;
+       unsigned long chg_irq_attr;
+
+       /* otg_en setting */
+       int otg_en;
+
+       /* OVP/UVLO check */
+       sec_battery_ovp_uvlo_t ovp_uvlo_check_type;
+       /* 1st full check */
+       sec_battery_full_charged_t full_check_type;
+       /* 2nd full check */
+       sec_battery_full_charged_t full_check_type_2nd;
+
+       sec_charger_functions_t chg_functions_setting;
+};
+
+struct sec_fuelgauge_platform_data {
+       bool (*fg_gpio_init)(void);
+       bool (*check_jig_status)(void);
+       int (*check_cable_callback)(void);
+       bool (*fuelalert_process)(bool);
+
+       /* charging current for type (0: not use) */
+       sec_charging_current_t *charging_current;
+
+       int jig_irq;
+       int jig_gpio;
+       unsigned long jig_irq_attr;
+
+       sec_battery_thermal_source_t thermal_source;
+
+       int fg_irq;
+       unsigned long fg_irq_attr;
+       /* fuel alert SOC (-1: not use) */
+       int fuel_alert_soc;
+       int fuel_alert_vol;
+       /* fuel alert can be repeated */
+       bool repeated_fuelalert;
+       sec_fuelgauge_capacity_type_t capacity_calculation_type;
+       /* soc should be soc x 10 (0.1% degree)
+        * only for scaling
+        */
+       int capacity_max;
+       int capacity_max_hv;
+       int capacity_max_margin;
+       int capacity_min;
+
+#if defined(CONFIG_BATTERY_AGE_FORECAST)
+       unsigned int full_condition_soc;
+#endif
+};
+
+#define sec_battery_platform_data_t \
+       struct sec_battery_platform_data
+
+#define sec_charger_platform_data_t \
+       struct sec_charger_platform_data
+
+#define sec_fuelgauge_platform_data_t \
+       struct sec_fuelgauge_platform_data
+
+static inline struct power_supply *get_power_supply_by_name(char *name)
+{
+       if (!name)
+               return (struct power_supply *)NULL;
+       else
+               return power_supply_get_by_name(name);
+}
+
+#define psy_do_property(name, function, property, value) \
+{      \
+       struct power_supply *psy;       \
+       int ret;        \
+       psy = get_power_supply_by_name((name)); \
+       if (!psy) {     \
+               pr_err("%s: Fail to "#function" psy (%s)\n",    \
+                       __func__, (name));      \
+               value.intval = 0;       \
+       } else {        \
+               if (psy->desc->function##_property != NULL) { \
+                       ret = psy->desc->function##_property(psy, (property), &(value)); \
+                       if (ret < 0) {  \
+                               pr_err("%s: Fail to %s "#function" (%d=>%d)\n", \
+                                               __func__, name, (property), ret);       \
+                               value.intval = 0;       \
+                       }       \
+               }       \
+       }       \
+}
+
+#ifndef CONFIG_OF
+#define adc_init(pdev, pdata, channel) \
+       (((pdata)->adc_api)[((((pdata)->adc_type[(channel)]) <  \
+       SEC_BATTERY_ADC_TYPE_NUM) ? ((pdata)->adc_type[(channel)]) :    \
+       SEC_BATTERY_ADC_TYPE_NONE)].init((pdev)))
+
+#define adc_exit(pdata, channel)       \
+       (((pdata)->adc_api)[((pdata)->adc_type[(channel)])].exit())
+
+#define adc_read(pdata, channel)       \
+       (((pdata)->adc_api)[((pdata)->adc_type[(channel)])].read((channel)))
+#endif
+
+#define get_battery_data(driver)       \
+       (((struct battery_data_t *)(driver)->pdata->battery_data)       \
+       [(driver)->pdata->battery_type])
+
+#endif /* __SEC_CHARGING_COMMON_H */
diff --git a/include/linux/external_notify.h b/include/linux/external_notify.h
new file mode 100644 (file)
index 0000000..ce8c5da
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * include/linux/external_notify.h
+ *
+ * header file supporting usb notify layer
+ * external notify call chain information
+ *
+ * Copyright (C) 2016-2017 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+  /* usb notify layer v3.1 */
+
+#ifndef __EXTERNAL_NOTIFY_H__
+#define __EXTERNAL_NOTIFY_H__
+
+#include <linux/notifier.h>
+
+/* external notifier call chain command */
+enum external_notify_cmd {
+       EXTERNAL_NOTIFY_3S_NODEVICE = 1,
+       EXTERNAL_NOTIFY_DEVICE_CONNECT,
+       EXTERNAL_NOTIFY_HOSTBLOCK_PRE,
+       EXTERNAL_NOTIFY_HOSTBLOCK_POST,
+       EXTERNAL_NOTIFY_MDMBLOCK_PRE,
+       EXTERNAL_NOTIFY_MDMBLOCK_POST,
+       EXTERNAL_NOTIFY_POWERROLE,
+};
+
+/* external notifier call sequence,
+ * largest priority number device will be called first. */
+enum external_notify_device {
+       EXTERNAL_NOTIFY_DEV_MUIC,
+       EXTERNAL_NOTIFY_DEV_CHARGER,
+       EXTERNAL_NOTIFY_DEV_PDIC,
+};
+
+enum external_notify_condev {
+       EXTERNAL_NOTIFY_NONE = 0,
+       EXTERNAL_NOTIFY_GPAD,
+       EXTERNAL_NOTIFY_LANHUB,
+};
+
+#ifdef CONFIG_USB_EXTERNAL_NOTIFY
+extern int send_external_notify(unsigned long cmd, int data);
+extern int usb_external_notify_register(struct notifier_block *nb,
+               notifier_fn_t notifier, int listener);
+extern int usb_external_notify_unregister(struct notifier_block *nb);
+#else
+static inline int send_external_notify(unsigned long cmd,
+                       int data) {return 0; }
+static inline int usb_external_notify_register(struct notifier_block *nb,
+                       notifier_fn_t notifier, int listener) {return 0; }
+static inline int usb_external_notify_unregister(struct notifier_block *nb)
+                       {return 0; }
+#endif
+
+#endif /* __EXTERNAL_NOTIFY_H__ */
diff --git a/include/linux/host_notify.h b/include/linux/host_notify.h
new file mode 100644 (file)
index 0000000..1dba703
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  Host notify class driver
+ *
+ * Copyright (C) 2011-2017 Samsung, Inc.
+ * Author: Dongrak Shin <dongrak.shin@samsung.com>
+ *
+*/
+
+ /* usb notify layer v3.1 */
+
+#ifndef __LINUX_HOST_NOTIFY_H__
+#define __LINUX_HOST_NOTIFY_H__
+
+enum host_uevent_state {
+       NOTIFY_HOST_NONE,
+       NOTIFY_HOST_ADD,
+       NOTIFY_HOST_REMOVE,
+       NOTIFY_HOST_OVERCURRENT,
+       NOTIFY_HOST_LOWBATT,
+       NOTIFY_HOST_BLOCK,
+       NOTIFY_HOST_UNKNOWN,
+};
+
+enum otg_hostnotify_mode {
+       NOTIFY_NONE_MODE,
+       NOTIFY_HOST_MODE,
+       NOTIFY_PERIPHERAL_MODE,
+       NOTIFY_TEST_MODE,
+};
+
+enum booster_power {
+       NOTIFY_POWER_OFF,
+       NOTIFY_POWER_ON,
+};
+
+enum set_command {
+       NOTIFY_SET_OFF,
+       NOTIFY_SET_ON,
+};
+
+struct host_notify_dev {
+       const char *name;
+       struct device *dev;
+       int index;
+       int state;
+       int mode;
+       int booster;
+       int (*set_mode)(bool);
+       int (*set_booster)(bool);
+};
+
+#ifdef CONFIG_USB_HOST_NOTIFY
+extern int host_state_notify(struct host_notify_dev *ndev, int state);
+extern int host_notify_dev_register(struct host_notify_dev *ndev);
+extern void host_notify_dev_unregister(struct host_notify_dev *ndev);
+#else
+static inline int host_state_notify(struct host_notify_dev *ndev, int state)
+       {return 0; }
+static inline int host_notify_dev_register(struct host_notify_dev *ndev)
+       {return 0; }
+static inline void host_notify_dev_unregister(struct host_notify_dev *ndev) {}
+#endif
+
+#endif /* __LINUX_HOST_NOTIFY_H__ */
diff --git a/include/linux/mfd/samsung/s2mps18-private.h b/include/linux/mfd/samsung/s2mps18-private.h
new file mode 100644 (file)
index 0000000..3bbad8b
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * s2mps18-private.h - Voltage regulator driver for the s2mps18
+ *
+ *  Copyright (C) 2015 Samsung Electrnoics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_MFD_S2MPS18_PRIV_H
+#define __LINUX_MFD_S2MPS18_PRIV_H
+
+#include <linux/i2c.h>
+#define S2MPS18_REG_INVALID             (0xff)
+#define S2MPS18_IRQSRC_PMIC            (1 << 0)
+
+/* PMIC Top-Level Registers */
+#define        S2MPS18_PMIC_REG_PMICID         0x00
+#define        S2MPS18_PMIC_REG_INTSRC         0x01
+#define        S2MPS18_PMIC_REG_INTSRC_MASK    0x02
+
+/* Slave addr = 0xCC */
+/* PMIC Registers */
+#define S2MPS18_PMIC_REG_INT1          0x00
+#define S2MPS18_PMIC_REG_INT2          0x01
+#define S2MPS18_PMIC_REG_INT3          0x02
+#define S2MPS18_PMIC_REG_INT4          0x03
+#define S2MPS18_PMIC_REG_INT5          0x04
+#define S2MPS18_PMIC_REG_INT6          0x05
+#define S2MPS18_PMIC_REG_INT7          0x06
+#define S2MPS18_PMIC_REG_INT1M         0x07
+#define S2MPS18_PMIC_REG_INT2M         0x08
+#define S2MPS18_PMIC_REG_INT3M         0x09
+#define S2MPS18_PMIC_REG_INT4M         0x0A
+#define S2MPS18_PMIC_REG_INT5M         0x0B
+#define S2MPS18_PMIC_REG_INT6M         0x0C
+#define S2MPS18_PMIC_REG_INT7M         0x0D
+#define S2MPS18_PMIC_REG_STATUS1       0x0E
+#define S2MPS18_PMIC_REG_STATUS2       0x0F
+#define S2MPS18_PMIC_REG_PWRONSRC      0x10
+#define S2MPS18_PMIC_REG_OFFSRC                0x11
+
+#define S2MPS18_PMIC_REG_BUCHG         0x12
+#define S2MPS18_PMIC_REG_RTCBUF                0x13
+#define S2MPS18_PMIC_REG_CTRL1         0x14
+#define S2MPS18_PMIC_REG_CTRL2         0x15
+#define S2MPS18_PMIC_REG_CTRL3         0x16
+
+#define S2MPS18_PMIC_REG_B1CTRL                0x1C
+#define S2MPS18_PMIC_REG_B1OUT1                0x1D
+#define S2MPS18_PMIC_REG_B1OUT2                0x1E
+#define S2MPS18_PMIC_REG_B2CTRL                0x1F
+#define S2MPS18_PMIC_REG_B2OUT1                0x20
+#define S2MPS18_PMIC_REG_B2OUT2                0x21
+#define S2MPS18_PMIC_REG_B3CTRL                0x22
+#define S2MPS18_PMIC_REG_B3OUT1                0x23
+#define S2MPS18_PMIC_REG_B3OUT2                0x24
+#define S2MPS18_PMIC_REG_B4CTRL                0x25
+#define S2MPS18_PMIC_REG_B4OUT1                0x26
+#define S2MPS18_PMIC_REG_B4OUT2                0x27
+#define S2MPS18_PMIC_REG_B5CTRL                0x28
+#define S2MPS18_PMIC_REG_B5OUT         0x29
+#define S2MPS18_PMIC_REG_B6CTRL                0x2A
+#define S2MPS18_PMIC_REG_B6OUT         0x2B
+#define S2MPS18_PMIC_REG_B7CTRL                0x2C
+#define S2MPS18_PMIC_REG_B7OUT         0x2D
+#define S2MPS18_PMIC_REG_B8CTRL                0x2E
+#define S2MPS18_PMIC_REG_B8OUT         0x2F
+#define S2MPS18_PMIC_REG_B9CTRL                0x30
+#define S2MPS18_PMIC_REG_B9OUT         0x31
+#define S2MPS18_PMIC_REG_B10CTRL       0x32
+#define S2MPS18_PMIC_REG_B10OUT                0x33
+#define S2MPS18_PMIC_REG_B11CTRL       0x34
+#define S2MPS18_PMIC_REG_B11OUT1       0x35
+#define S2MPS18_PMIC_REG_B11OUT2       0x36
+#define S2MPS18_PMIC_REG_B12CTRL       0x37
+#define S2MPS18_PMIC_REG_B12OUT                0x38
+#define S2MPS18_PMIC_REG_B13CTRL       0x39
+#define S2MPS18_PMIC_REG_B13OUT                0x3A
+#define S2MPS18_PMIC_REG_B14CTRL       0x3B
+#define S2MPS18_PMIC_REG_B14OUT                0x3C
+#define S2MPS18_PMIC_REG_BB1CTRL       0x3D
+#define S2MPS18_PMIC_REG_BB1OUT                0x3E
+
+#define S2MPS18_PMIC_REG_BUCKRAMP      0x3F
+#define S2MPS18_PMIC_REG_BUCKRAMP2     0x40
+#define S2MPS18_PMIC_REG_BUCK2_PH_DVS  0x41
+#define S2MPS18_PMIC_REG_BUCK5_PH_DVS  0x42
+#define S2MPS18_PMIC_REG_BUCK6_PH_DVS  0x43
+#define S2MPS18_PMIC_REG_LDO6_DVS      0x44
+#define S2MPS18_PMIC_REG_LDO7_DVS      0x45
+#define S2MPS18_PMIC_REG_LDO11_DVS     0x46
+#define S2MPS18_PMIC_REG_LDO29_DVS     0x47
+#define S2MPS18_PMIC_REG_BUCK7_DVS     0x48
+
+#define S2MPS18_PMIC_REG_L1CTRL                0x49
+#define S2MPS18_PMIC_REG_L2CTRL1       0x4A
+#define S2MPS18_PMIC_REG_L2CTRL2       0x4B
+#define S2MPS18_PMIC_REG_L3CTRL                0x4C
+#define S2MPS18_PMIC_REG_L4CTRL                0x4D
+#define S2MPS18_PMIC_REG_L5CTRL                0x4E
+#define S2MPS18_PMIC_REG_L6CTRL                0x4F
+#define S2MPS18_PMIC_REG_L7CTRL                0x50
+#define S2MPS18_PMIC_REG_L8CTRL                0x51
+#define S2MPS18_PMIC_REG_L9CTRL                0x52
+#define S2MPS18_PMIC_REG_L10CTRL       0x53
+#define S2MPS18_PMIC_REG_L11CTRL       0x54
+#define S2MPS18_PMIC_REG_L12CTRL       0x55
+#define S2MPS18_PMIC_REG_L13CTRL       0x56
+#define S2MPS18_PMIC_REG_L14CTRL       0x57
+#define S2MPS18_PMIC_REG_L15CTRL       0x58
+#define S2MPS18_PMIC_REG_L16CTRL       0x59
+#define S2MPS18_PMIC_REG_L17CTRL       0x5A
+#define S2MPS18_PMIC_REG_L18CTRL       0x5B
+#define S2MPS18_PMIC_REG_L19CTRL       0x5C
+#define S2MPS18_PMIC_REG_L20CTRL       0x5D
+#define S2MPS18_PMIC_REG_L21CTRL       0x5E
+#define S2MPS18_PMIC_REG_L22CTRL       0x5F
+#define S2MPS18_PMIC_REG_L23CTRL       0x60
+#define S2MPS18_PMIC_REG_L24CTRL       0x61
+#define S2MPS18_PMIC_REG_L25CTRL       0x62
+#define S2MPS18_PMIC_REG_L26CTRL       0x63
+#define S2MPS18_PMIC_REG_L27CTRL       0x64
+#define S2MPS18_PMIC_REG_L28CTRL       0x65
+#define S2MPS18_PMIC_REG_L29CTRL       0x66
+#define S2MPS18_PMIC_REG_L30CTRL       0x67
+#define S2MPS18_PMIC_REG_L31CTRL       0x68
+#define S2MPS18_PMIC_REG_L32CTRL       0x69
+#define S2MPS18_PMIC_REG_L33CTRL       0x6A
+#define S2MPS18_PMIC_REG_L34CTRL       0x6B
+#define S2MPS18_PMIC_REG_L35CTRL       0x6C
+#define S2MPS18_PMIC_REG_L36CTRL       0x6D
+#define S2MPS18_PMIC_REG_L37CTRL       0x6E
+#define S2MPS18_PMIC_REG_L38CTRL       0x6F
+#define S2MPS18_PMIC_REG_L39CTRL       0x70
+#define S2MPS18_PMIC_REG_L40CTRL       0x71
+#define S2MPS18_PMIC_REG_L41CTRL       0x72
+#define S2MPS18_PMIC_REG_L42CTRL       0x73
+#define S2MPS18_PMIC_REG_L43CTRL       0x74
+#define S2MPS18_PMIC_REG_L44CTRL       0x75
+#define S2MPS18_PMIC_REG_L45CTRL       0x76
+
+#define S2MPS18_PMIC_REG_LDO_DSCH1     0x78
+#define S2MPS18_PMIC_REG_LDO_DSCH2     0x79
+#define S2MPS18_PMIC_REG_LDO_DSCH3     0x7A
+#define S2MPS18_PMIC_REG_LDO_DSCH4     0x7B
+#define S2MPS18_PMIC_REG_LDO_DSCH5     0x7C
+#define S2MPS18_PMIC_REG_LDO_DSCH6     0x7D
+#define S2MPS18_PMIC_REG_LDO_DSCH7     0x7E
+#define S2MPS18_PMIC_REG_TCXO_CTRL     0x88
+#define S2MPS18_PMIC_REG_PWREN_SEL1    0xC8
+#define S2MPS18_PMIC_REG_PWREN_SEL2    0xC9
+#define S2MPS18_PMIC_REG_LPM_MODE0     0xCC
+#define S2MPS18_PMIC_REG_LPM_MODE1     0xCD
+#define S2MPS18_PMIC_REG_LPM_MODE2     0xCE
+#define S2MPS18_REG_ADC_CTRL1          0xCF
+#define S2MPS18_REG_ADC_CTRL2          0xD0
+#define S2MPS18_REG_ADC_CTRL3          0xD1
+#define S2MPS18_REG_ADC_DATA           0xD2
+#define S2MPS18_PMIC_REG_OCP_WARN1     0xD3
+#define S2MPS18_PMIC_REG_OCP_WARN2     0xD4
+
+/* S2MPS18regulator ids */
+enum S2MPS18_regulators {
+       S2MPS18_LDO1,
+       S2MPS18_LDO2,
+       S2MPS18_LDO3,
+       S2MPS18_LDO4,
+       S2MPS18_LDO5,
+       S2MPS18_LDO6,
+       S2MPS18_LDO7,
+       S2MPS18_LDO8,
+       S2MPS18_LDO9,
+       S2MPS18_LDO10,
+       S2MPS18_LDO11,
+       S2MPS18_LDO12,
+       S2MPS18_LDO13,
+       S2MPS18_LDO14,
+/*     S2MPS18_LDO15,
+       S2MPS18_LDO16,
+       S2MPS18_LDO17,
+       S2MPS18_LDO18,
+       S2MPS18_LDO19,
+       S2MPS18_LDO20,
+       S2MPS18_LDO21,
+*/     S2MPS18_LDO22,
+/*     S2MPS18_LDO23,
+       S2MPS18_LDO24,
+       S2MPS18_LDO25,
+       S2MPS18_LDO26,
+       S2MPS18_LDO27,
+       S2MPS18_LDO28,
+       S2MPS18_LDO29,
+*/     S2MPS18_LDO30,
+       S2MPS18_LDO31,
+       S2MPS18_LDO32,
+       S2MPS18_LDO33,
+       S2MPS18_LDO34,
+       S2MPS18_LDO35,
+       S2MPS18_LDO36,
+       S2MPS18_LDO37,
+       S2MPS18_LDO38,
+       S2MPS18_LDO39,
+       S2MPS18_LDO40,
+       S2MPS18_LDO41,
+       S2MPS18_LDO42,
+       S2MPS18_LDO43,
+       S2MPS18_LDO44,
+       S2MPS18_LDO45,
+       S2MPS18_BUCK1,
+       S2MPS18_BUCK2,
+       S2MPS18_BUCK3,
+       S2MPS18_BUCK4,
+       S2MPS18_BUCK5,
+       S2MPS18_BUCK6,
+       S2MPS18_BUCK7,
+       S2MPS18_BUCK8,
+       S2MPS18_BUCK9,
+       S2MPS18_BUCK10,
+       S2MPS18_BUCK11,
+       S2MPS18_BUCK12,
+       S2MPS18_BUCK13,
+/*     S2MPS18_BUCK14,
+       S2MPS18_BB1, */
+       S2MPS18_REG_MAX,
+};
+
+#define S2MPS18_BUCK_MIN1      300000
+#define S2MPS18_BUCK_MIN2      600000
+#define S2MPS18_LDO_MIN1       700000
+#define S2MPS18_LDO_MIN2       400000
+#define S2MPS18_LDO_MIN3       1800000
+#define S2MPS18_LDO_MIN4       300000
+#define S2MPS18_BUCK_STEP1     6250
+#define S2MPS18_BUCK_STEP2     12500
+#define S2MPS18_LDO_STEP1      12500
+#define S2MPS18_LDO_STEP2      25000
+#define S2MPS18_LDO_VSEL_MASK  0x3F
+#define S2MPS18_BUCK_VSEL_MASK 0xFF
+#define S2MPS18_ENABLE_MASK    (0x03 << S2MPS18_ENABLE_SHIFT)
+#define S2MPS18_SW_ENABLE_MASK 0x03
+#define S2MPS18_RAMP_DELAY     12000
+
+#define S2MPS18_ENABLE_TIME_LDO                128
+#define S2MPS18_ENABLE_TIME_BUCK1      130
+#define S2MPS18_ENABLE_TIME_BUCK2      130
+#define S2MPS18_ENABLE_TIME_BUCK3      130
+#define S2MPS18_ENABLE_TIME_BUCK4      130
+#define S2MPS18_ENABLE_TIME_BUCK5      130
+#define S2MPS18_ENABLE_TIME_BUCK6      130
+#define S2MPS18_ENABLE_TIME_BUCK7      130
+#define S2MPS18_ENABLE_TIME_BUCK8      130
+#define S2MPS18_ENABLE_TIME_BUCK9      130
+#define S2MPS18_ENABLE_TIME_BUCK10     130
+#define S2MPS18_ENABLE_TIME_BUCK11     130
+#define S2MPS18_ENABLE_TIME_BUCK12     130
+#define S2MPS18_ENABLE_TIME_BUCK13     130
+#define S2MPS18_ENABLE_TIME_BUCK14     130
+#define S2MPS18_ENABLE_TIME_BB         160
+
+#define S2MPS18_ENABLE_SHIFT   0x06
+#define S2MPS18_LDO_N_VOLTAGES (S2MPS18_LDO_VSEL_MASK + 1)
+#define S2MPS18_BUCK_N_VOLTAGES (S2MPS18_BUCK_VSEL_MASK + 1)
+
+#define S2MPS18_PMIC_EN_SHIFT  6
+#define S2MPS18_REGULATOR_MAX (S2MPS18_REG_MAX)
+#define SEC_PMIC_REV(iodev)    (iodev)->pmic_rev
+
+#define S2MPS18_OCP_WARN_EN_SHIFT      7
+#define S2MPS18_OCP_WARN_RESET_SHIFT   6
+#define S2MPS18_OCP_WARN_LEVEL_SHIFT   0
+
+#define CURRENT_BS                     15625
+#define CURRENT_BD                     31250
+#define CURRENT_BT                     46875
+#define CURRENT_BB                     15625
+#define CURRENT_BV                     15625
+#define CURRENT_L150                   879
+#define CURRENT_L300                   1758
+#define CURRENT_L450                   2637
+#define CURRENT_L600                   3516
+#define CURRENT_L800                   4688
+
+#define POWER_CMS                      977
+#define        POWER_CMD                       1953
+#define POWER_CMT                      2930
+#define POWER_VM                       1953
+#define POWER_BB                       3906
+#define POWER_N150HL                   110
+#define POWER_N300H                    220
+#define POWER_N450H                    330
+#define POWER_N600HL                   439
+#define POWER_P150HL                   220
+#define POWER_P300HL                   439
+#define POWER_P450HL                   659
+#define POWER_P800L                    1172
+#define POWER_N150DVS                  220
+#define POWER_N300DVS                  439
+#define POWER_N450DVS                  659
+
+#define HIGH_ACC_CURRENT_BS            977
+#define HIGH_ACC_CURRENT_BD            1953
+#define HIGH_ACC_CURRENT_BT            2930
+#define HIGH_ACC_CURRENT_BB            977
+#define HIGH_ACC_CURRENT_BV            977
+#define HIGH_ACC_CURRENT_L150          55
+#define HIGH_ACC_CURRENT_L300          110
+#define HIGH_ACC_CURRENT_L450          165
+#define HIGH_ACC_CURRENT_L600          220
+#define HIGH_ACC_CURRENT_L800          293
+
+#define ADC_EN_MASK                    0x80
+#define ADC_ASYNCRD_MASK       0x80
+#define ADC_PTR_MASK                   0x0F
+#define ADC_PGEN_MASK                  0x30
+#define CURRENT_MODE                   0x00
+#define CHANNELSET_MODE                        0x20
+#define POWER_MODE                     0x10
+#define RAWCURRENT_MODE                        0x30
+
+#define S2MPS18_LDO_START              0x41
+#define S2MPS18_LDO_END                        0x6D
+#define S2MPS18_BUCK_START             0x01
+#define S2MPS18_BUCK_END               0x0E
+
+#define SMPNUM_MASK                    0x0F
+
+#define SEC_PMIC_REV(iodev)    (iodev)->pmic_rev
+#define S2MPS18_MAX_ADC_CHANNEL                8
+/*
+ * sec_opmode_data - regulator operation mode data
+ * @id: regulator id
+ * @mode: regulator operation mode
+ */
+
+enum s2mps18_irq_source {
+       PMIC_INT1 = 0,
+       PMIC_INT2,
+       PMIC_INT3,
+       PMIC_INT4,
+       PMIC_INT5,
+       PMIC_INT6,
+       PMIC_INT7,
+
+       S2MPS18_IRQ_GROUP_NR,
+};
+
+#define S2MPS18_NUM_IRQ_PMIC_REGS      7
+
+enum s2mps18_irq {
+       /* PMIC */
+       S2MPS18_PMIC_IRQ_PWRONR_INT1,
+       S2MPS18_PMIC_IRQ_PWRONF_INT1,
+       S2MPS18_PMIC_IRQ_JIGONBF_INT1,
+       S2MPS18_PMIC_IRQ_JIGONBR_INT1,
+       S2MPS18_PMIC_IRQ_ACOKBF_INT1,
+       S2MPS18_PMIC_IRQ_ACOKBR_INT1,
+       S2MPS18_PMIC_IRQ_PWRON1S_INT1,
+       S2MPS18_PMIC_IRQ_MRB_INT1,
+
+       S2MPS18_PMIC_IRQ_RTC60S_INT2,
+       S2MPS18_PMIC_IRQ_RTCA1_INT2,
+       S2MPS18_PMIC_IRQ_RTCA0_INT2,
+       S2MPS18_PMIC_IRQ_SMPL_INT2,
+       S2MPS18_PMIC_IRQ_RTC1S_INT2,
+       S2MPS18_PMIC_IRQ_WTSR_INT2,
+       S2MPS18_PMIC_IRQ_WRSTB_INT2,
+
+       S2MPS18_PMIC_IRQ_120C_INT3,
+       S2MPS18_PMIC_IRQ_140C_INT3,
+       S2MPS18_PMIC_IRQ_TSD_INT3,
+       S2MPS18_PMIC_IRQ_ADCDONE_INT3,
+
+       S2MPS18_PMIC_IRQ_OC0_INT4,
+       S2MPS18_PMIC_IRQ_OC1_INT4,
+       S2MPS18_PMIC_IRQ_OC2_INT4,
+       S2MPS18_PMIC_IRQ_OC3_INT4,
+       S2MPS18_PMIC_IRQ_OC4_INT4,
+       S2MPS18_PMIC_IRQ_OC5_INT4,
+       S2MPS18_PMIC_IRQ_OC6_INT4,
+       S2MPS18_PMIC_IRQ_OC7_INT4,
+
+       S2MPS18_PMIC_IRQ_OCPB1_INT5,
+       S2MPS18_PMIC_IRQ_OCPB2_INT5,
+       S2MPS18_PMIC_IRQ_OCPB3_INT5,
+       S2MPS18_PMIC_IRQ_OCPB4_INT5,
+       S2MPS18_PMIC_IRQ_OCPB5_INT5,
+       S2MPS18_PMIC_IRQ_OCPB6_INT5,
+       S2MPS18_PMIC_IRQ_OCPB7_INT5,
+       S2MPS18_PMIC_IRQ_OCPB8_INT5,
+
+       S2MPS18_PMIC_IRQ_OCPB9_INT6,
+       S2MPS18_PMIC_IRQ_OCPB10_INT6,
+       S2MPS18_PMIC_IRQ_OCPB11_INT6,
+       S2MPS18_PMIC_IRQ_OCPB12_INT6,
+       S2MPS18_PMIC_IRQ_OCPB13_INT6,
+       S2MPS18_PMIC_IRQ_OCPB14_INT6,
+       S2MPS18_PMIC_IRQ_OCPBB_INT6,
+
+       S2MPS18_PMIC_IRQ_SCLDO20_INT7,
+       S2MPS18_PMIC_IRQ_SCLDO21_INT7,
+       S2MPS18_PMIC_IRQ_SCLDO31_INT7,
+       S2MPS18_PMIC_IRQ_SCLDO44_INT7,
+       S2MPS18_PMIC_IRQ_SCLDO2_INT7,
+       S2MPS18_PMIC_IRQ_MASKSCLDOINT_INT7,
+
+       S2MPS18_IRQ_NR,
+};
+
+
+enum sec_device_type {
+       S2MPS18X,
+};
+
+struct s2mps18_dev {
+       struct device *dev;
+       struct i2c_client *i2c;
+       struct i2c_client *pmic;
+       struct i2c_client *rtc;
+       struct i2c_client *debug_i2c;
+       struct mutex i2c_lock;
+       struct apm_ops *ops;
+
+       int type;
+       int device_type;
+       int irq;
+       int irq_base;
+       int irq_gpio;
+       bool wakeup;
+       struct mutex irqlock;
+       int irq_masks_cur[S2MPS18_IRQ_GROUP_NR];
+       int irq_masks_cache[S2MPS18_IRQ_GROUP_NR];
+
+       /* pmic VER/REV register */
+       u8 pmic_rev;    /* pmic Rev */
+       int adc_mode;
+       int adc_sync_mode;
+
+       struct s2mps18_platform_data *pdata;
+};
+
+enum s2mps18_types {
+       TYPE_S2MPS18,
+};
+
+extern int s2mps18_irq_init(struct s2mps18_dev *s2mps18);
+extern void s2mps18_irq_exit(struct s2mps18_dev *s2mps18);
+
+extern void s2mps18_powermeter_init(struct s2mps18_dev *s2mps18);
+extern void s2mps18_powermeter_deinit(struct s2mps18_dev *s2mps18);
+
+/* S2MPS18 shared i2c API function */
+extern int s2mps18_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
+extern int s2mps18_bulk_read(struct i2c_client *i2c, u8 reg, int count,
+                               u8 *buf);
+extern int s2mps18_write_reg(struct i2c_client *i2c, u8 reg, u8 value);
+extern int s2mps18_bulk_write(struct i2c_client *i2c, u8 reg, int count,
+                               u8 *buf);
+extern int s2mps18_write_word(struct i2c_client *i2c, u8 reg, u16 value);
+extern int s2mps18_read_word(struct i2c_client *i2c, u8 reg);
+
+extern int s2mps18_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask);
+
+extern int s2m_ldo_set_mode(int ldo_num, unsigned int mode);
+
+#ifdef CONFIG_EXYNOS_OCP
+extern void get_s2mps18_i2c(struct i2c_client **i2c);
+#endif
+
+#endif /* __LINUX_MFD_S2MPS18_PRIV_H */
+
diff --git a/include/linux/usb/manager/usb_typec_manager_notifier.h b/include/linux/usb/manager/usb_typec_manager_notifier.h
new file mode 100644 (file)
index 0000000..4e6d497
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * include/linux/muic/ccic_notifier.h
+ *
+ * header file supporting CCIC notifier call chain information
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Seung-Jin Hahn <sjin.hahn@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef __USB_TYPEC_MANAGER_NOTIFIER_H__
+#define __USB_TYPEC_MANAGER_NOTIFIER_H__
+
+#include <linux/ccic/ccic_notifier.h>
+#include <linux/muic/muic.h>
+#include <linux/muic/muic_notifier.h>
+#ifdef CONFIG_VBUS_NOTIFIER
+#include <linux/vbus_notifier.h>
+#endif
+
+
+/* USB TypeC Manager notifier call sequence,
+ * largest priority number device will be called first. */
+
+
+/* CCIC notifier call sequence,
+ * largest priority number device will be called first. */
+typedef enum {
+/* MUIC */
+       MANAGER_NOTIFY_MUIC_NONE = 0,
+       MANAGER_NOTIFY_MUIC_DOCK,
+       MANAGER_NOTIFY_MUIC_MHL,
+       MANAGER_NOTIFY_MUIC_USB,
+       MANAGER_NOTIFY_MUIC_TSP,
+       MANAGER_NOTIFY_MUIC_CHARGER,
+       MANAGER_NOTIFY_MUIC_CPUIDLE,
+       MANAGER_NOTIFY_MUIC_CPUFREQ,
+       MANAGER_NOTIFY_MUIC_TIMEOUT_OPEN_DEVICE,
+
+/* CCIC */
+       MANAGER_NOTIFY_CCIC_INITIAL = 20,
+       MANAGER_NOTIFY_CCIC_MUIC,
+       MANAGER_NOTIFY_CCIC_USB,
+       MANAGER_NOTIFY_CCIC_BATTERY,
+       MANAGER_NOTIFY_CCIC_DP,
+       MANAGER_NOTIFY_CCIC_USBDP,
+       MANAGER_NOTIFY_CCIC_SENSORHUB,
+
+/* VBUS */
+       MANAGER_NOTIFY_VBUS_USB = 30,
+       MANAGER_NOTIFY_VBUS_CHARGER,
+} manager_notifier_device_t;
+
+typedef enum {
+       CCIC_NOTY,
+       MUIC_NOTY,
+       VBUS_NOTY,
+       USB_STATE_NOTY,
+} manager_notify_t;
+
+typedef enum {
+       PD_USB_TYPE,
+       PD_TA_TYPE,
+} pd_usb_state_t;
+
+#if defined(CONFIG_VBUS_NOTIFIER)
+typedef enum {
+       EVENT_LOAD = 0,
+       EVENT_CANCEL,
+} muic_fake_event;
+#endif
+
+typedef struct
+{
+       uint64_t src:4;
+       uint64_t dest:4;
+       uint64_t id:8;
+       uint64_t sub1:16;
+       uint64_t sub2:16;
+       uint64_t sub3:16;
+       void *pd;
+} MANAGER_NOTI_TYPEDEF;
+
+typedef struct _manager_data_t
+{
+       struct blocking_notifier_head manager_muic_notifier;
+       struct blocking_notifier_head manager_ccic_notifier;
+       struct notifier_block ccic_nb;
+       struct notifier_block muic_nb;
+//     struct notifier_block usb_nb;
+//     struct notifier_block batter_nb;
+#if defined(CONFIG_VBUS_NOTIFIER)
+       struct notifier_block vbus_nb;
+#endif
+
+       struct delayed_work manager_init_work;
+//     struct workqueue_struct *typec_manager_wq;
+       struct delayed_work cable_check_work;
+       struct delayed_work muic_noti_work;
+       struct delayed_work rtctime_update_work;
+#if defined(CONFIG_VBUS_NOTIFIER)
+       struct delayed_work vbus_noti_work;
+#endif
+
+       int muic_action;
+       int muic_cable_type;
+       int muic_data_refresh;
+       int muic_attach_state_without_ccic;
+#if defined(CONFIG_VBUS_NOTIFIER)
+       int muic_fake_event_wq_processing;
+#endif
+       int vbus_state;
+
+       int ccic_attach_state;  // USB_STATUS_NOTIFY_DETACH, UFP, DFP, DRP, NO_USB
+       int ccic_drp_state;
+       int ccic_rid_state;
+       int cable_type;
+       int usb_enum_state;
+       bool usb_enable_state;
+       int pd_con_state;
+       int water_det;
+       int wVbus_det;
+       int is_UFPS;
+       void *pd;
+       int water_count;
+       int dry_count;
+       int usb210_count;
+       int usb310_count;
+       int waterChg_count;
+       unsigned long waterDet_duration;
+       unsigned long waterDet_time;
+       unsigned long dryDet_time;
+
+       unsigned long wVbus_duration;
+       unsigned long wVbusHigh_time;
+       unsigned long wVbusLow_time;
+
+       int dp_attach_state;
+       int dp_cable_type;
+       int dp_hpd_state;
+       int dp_is_connect;
+       int dp_hs_connect;
+       int dp_check_done;
+}manager_data_t;
+
+
+#define MANAGER_NOTIFIER_BLOCK(name)   \
+       struct notifier_block (name)
+
+extern void manager_notifier_usbdp_support(void);
+extern void manager_notifier_test(void *);
+
+
+/* ccic notifier register/unregister API
+ * for used any where want to receive ccic attached device attach/detach. */
+extern int manager_notifier_register(struct notifier_block *nb,
+               notifier_fn_t notifier, manager_notifier_device_t listener);
+extern int manager_notifier_unregister(struct notifier_block *nb);
+
+#endif /* __USB_TYPEC_MANAGER_NOTIFIER_H__ */
diff --git a/include/linux/usb_hw_param.h b/include/linux/usb_hw_param.h
new file mode 100644 (file)
index 0000000..29b9e5d
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* usb hw param */
+/* usb notify layer v3.1 */
+
+#define MAX_HWPARAM_STR_LEN 1024
+#define MAX_HWPARAM_STRING 10
+#define HWPARAM_DATA_LIMIT 100000
+
+enum usb_hw_param {
+       USB_CCIC_WATER_INT_COUNT,
+       USB_CCIC_DRY_INT_COUNT,
+       USB_CCIC_I2C_ERROR_COUNT,
+       USB_CCIC_OVC_COUNT,
+       USB_CCIC_OTG_USE_COUNT,
+       USB_CCIC_DP_USE_COUNT,
+       USB_CCIC_VR_USE_COUNT,
+       USB_HOST_SUPER_SPEED_COUNT,
+       USB_HOST_HIGH_SPEED_COUNT,
+       USB_HOST_FULL_SPEED_COUNT,
+       USB_HOST_LOW_SPEED_COUNT,
+       USB_CLIENT_SUPER_SPEED_COUNT,
+       USB_CLIENT_HIGH_SPEED_COUNT,
+       USB_HOST_CLASS_AUDIO_COUNT,
+       USB_HOST_CLASS_COMM_COUNT,
+       USB_HOST_CLASS_HID_COUNT,
+       USB_HOST_CLASS_PHYSICAL_COUNT,
+       USB_HOST_CLASS_IMAGE_COUNT,
+       USB_HOST_CLASS_PRINTER_COUNT,
+       USB_HOST_CLASS_STORAGE_COUNT,
+       USB_HOST_CLASS_HUB_COUNT,
+       USB_HOST_CLASS_CDC_COUNT,
+       USB_HOST_CLASS_CSCID_COUNT,
+       USB_HOST_CLASS_CONTENT_COUNT,
+       USB_HOST_CLASS_VIDEO_COUNT,
+       USB_HOST_CLASS_WIRELESS_COUNT,
+       USB_HOST_CLASS_MISC_COUNT,
+       USB_HOST_CLASS_APP_COUNT,
+       USB_HOST_CLASS_VENDOR_COUNT,
+       USB_CCIC_DEX_USE_COUNT,
+       USB_CCIC_WATER_TIME_DURATION,
+       USB_CCIC_WATER_VBUS_COUNT,
+       USB_CCIC_WATER_VBUS_TIME_DURATION,
+       USB_CCIC_VBUS_CC_SHORT_COUNT,
+       USB_MUIC_AFC_NACK_COUNT,
+       USB_MUIC_AFC_ERROR_COUNT,
+       USB_MUIC_DCD_TIMEOUT_COUNT,
+       USB_CCIC_VERSION,
+       USB_CCIC_HW_PARAM_MAX,
+};
+
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+int get_ccic_water_count(void);
+int get_ccic_dry_count(void);
+int get_usb310_count(void);
+int get_usb210_count(void);
+unsigned long get_waterDet_duration(void);
+unsigned long get_wVbus_duration(void);
+int get_waterChg_count(void);
+unsigned long long show_ccic_version(void);
+#endif
diff --git a/include/linux/usb_notify.h b/include/linux/usb_notify.h
new file mode 100644 (file)
index 0000000..443beff
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ *  usb notify header
+ *
+ * Copyright (C) 2011-2017 Samsung, Inc.
+ * Author: Dongrak Shin <dongrak.shin@samsung.com>
+ *
+*/
+
+ /* usb notify layer v3.1 */
+
+#ifndef __LINUX_USB_NOTIFY_H__
+#define __LINUX_USB_NOTIFY_H__
+
+#include <linux/notifier.h>
+#include <linux/host_notify.h>
+#include <linux/external_notify.h>
+#include <linux/usblog_proc_notify.h>
+#if defined(CONFIG_USB_HW_PARAM)
+#include <linux/usb_hw_param.h>
+#endif
+#include <linux/usb.h>
+
+enum otg_notify_events {
+       NOTIFY_EVENT_NONE,
+       NOTIFY_EVENT_VBUS,
+       NOTIFY_EVENT_HOST,
+       NOTIFY_EVENT_CHARGER,
+       NOTIFY_EVENT_SMARTDOCK_TA,
+       NOTIFY_EVENT_SMARTDOCK_USB,
+       NOTIFY_EVENT_AUDIODOCK,
+       NOTIFY_EVENT_LANHUB,
+       NOTIFY_EVENT_LANHUB_TA,
+       NOTIFY_EVENT_MMDOCK,
+       NOTIFY_EVENT_HMT,
+       NOTIFY_EVENT_GAMEPAD,
+       NOTIFY_EVENT_DRIVE_VBUS,
+       NOTIFY_EVENT_ALL_DISABLE,
+       NOTIFY_EVENT_HOST_DISABLE,
+       NOTIFY_EVENT_CLIENT_DISABLE,
+       NOTIFY_EVENT_MDM_ON_OFF,
+       NOTIFY_EVENT_OVERCURRENT,
+       NOTIFY_EVENT_SMSC_OVC,
+       NOTIFY_EVENT_SMTD_EXT_CURRENT,
+       NOTIFY_EVENT_MMD_EXT_CURRENT,
+       NOTIFY_EVENT_DEVICE_CONNECT,
+       NOTIFY_EVENT_GAMEPAD_CONNECT,
+       NOTIFY_EVENT_LANHUB_CONNECT,
+       NOTIFY_EVENT_POWER_SOURCE,
+       NOTIFY_EVENT_VBUSPOWER,
+       NOTIFY_EVENT_POGO,
+       NOTIFY_EVENT_VIRTUAL,
+};
+
+#define VIRT_EVENT(a) (a+NOTIFY_EVENT_VIRTUAL)
+#define PHY_EVENT(a) (a%NOTIFY_EVENT_VIRTUAL)
+#define IS_VIRTUAL(a) (a >= NOTIFY_EVENT_VIRTUAL ? 1 : 0)
+
+enum otg_notify_event_status {
+       NOTIFY_EVENT_DISABLED,
+       NOTIFY_EVENT_DISABLING,
+       NOTIFY_EVENT_ENABLED,
+       NOTIFY_EVENT_ENABLING,
+       NOTIFY_EVENT_BLOCKED,
+       NOTIFY_EVENT_BLOCKING,
+};
+
+enum otg_notify_evt_type {
+       NOTIFY_EVENT_EXTRA = (1 << 0),
+       NOTIFY_EVENT_STATE = (1 << 1),
+       NOTIFY_EVENT_DELAY = (1 << 2),
+       NOTIFY_EVENT_NEED_VBUSDRIVE = (1 << 3),
+       NOTIFY_EVENT_NOBLOCKING = (1 << 4),
+       NOTIFY_EVENT_NOSAVE = (1 << 5),
+       NOTIFY_EVENT_NEED_HOST = (1 << 6),
+       NOTIFY_EVENT_NEED_CLIENT = (1 << 7),
+};
+
+enum otg_notify_block_type {
+       NOTIFY_BLOCK_TYPE_NONE = 0,
+       NOTIFY_BLOCK_TYPE_HOST = (1 << 0),
+       NOTIFY_BLOCK_TYPE_CLIENT = (1 << 1),
+       NOTIFY_BLOCK_TYPE_ALL = (1 << 0 | 1 << 1),
+};
+
+enum otg_notify_mdm_type {
+       NOTIFY_MDM_TYPE_OFF,
+       NOTIFY_MDM_TYPE_ON,
+};
+
+enum otg_notify_gpio {
+       NOTIFY_VBUS,
+       NOTIFY_REDRIVER,
+};
+
+enum otg_op_pos {
+       NOTIFY_OP_OFF,
+       NOTIFY_OP_POST,
+       NOTIFY_OP_PRE,
+};
+
+enum ovc_check_value {
+       HNOTIFY_LOW,
+       HNOTIFY_HIGH,
+       HNOTIFY_INITIAL,
+};
+
+enum otg_notify_power_role {
+       HNOTIFY_SINK,
+       HNOTIFY_SOURCE,
+};
+
+enum otg_notify_data_role {
+       HNOTIFY_UFP,
+       HNOTIFY_DFP,
+};
+
+struct otg_notify {
+       int vbus_detect_gpio;
+       int redriver_en_gpio;
+       int is_wakelock;
+       int unsupport_host;
+       int smsc_ovc_poll_sec;
+       int auto_drive_vbus;
+       int booting_delay_sec;
+       int disable_control;
+       int device_check_sec;
+       int pre_peri_delay_us;
+       int sec_whitelist_enable;
+       int speed;
+       const char *muic_name;
+       int (*pre_gpio)(int gpio, int use);
+       int (*post_gpio)(int gpio, int use);
+       int (*vbus_drive)(bool);
+       int (*set_host)(bool);
+       int (*set_peripheral)(bool);
+       int (*set_charger)(bool);
+       int (*post_vbus_detect)(bool);
+       int (*set_lanhubta)(int);
+       int (*set_battcall)(int, int);
+       int (*set_chg_current)(int);
+       void (*set_ldo_onoff)(void *, unsigned int);
+       void *o_data;
+       void *u_notify;
+};
+
+struct otg_booster {
+       char *name;
+       int (*booster)(bool);
+};
+
+#ifdef CONFIG_USB_NOTIFY_LAYER
+extern const char *event_string(enum otg_notify_events event);
+extern const char *status_string(enum otg_notify_event_status status);
+extern void send_otg_notify(struct otg_notify *n,
+                                       unsigned long event, int enable);
+extern struct otg_booster *find_get_booster(struct otg_notify *n);
+extern int register_booster(struct otg_notify *n, struct otg_booster *b);
+extern int register_ovc_func(struct otg_notify *n,
+                               int (*check_state)(void *), void *data);
+extern int get_usb_mode(struct otg_notify *n);
+extern unsigned long get_cable_type(struct otg_notify *n);
+extern int is_usb_host(struct otg_notify *n);
+extern void *get_notify_data(struct otg_notify *n);
+extern void set_notify_data(struct otg_notify *n, void *data);
+extern struct otg_notify *get_otg_notify(void);
+extern int set_otg_notify(struct otg_notify *n);
+extern void put_otg_notify(struct otg_notify *n);
+extern bool is_blocked(struct otg_notify *n, int type);
+extern int usb_check_whitelist_for_mdm(struct usb_device *dev);
+#if defined(CONFIG_USB_HW_PARAM)
+extern unsigned long long *get_hw_param(struct otg_notify *n,
+                                       enum usb_hw_param index);
+extern int inc_hw_param(struct otg_notify *n,
+                                       enum usb_hw_param index);
+extern int inc_hw_param_host(struct host_notify_dev *dev,
+                                       enum usb_hw_param index);
+#endif
+#else
+static inline const char *event_string(enum otg_notify_events event)
+                       {return NULL; }
+static inline const char *status_string(enum otg_notify_event_status status)
+                       {return NULL; }
+static inline void send_otg_notify(struct otg_notify *n,
+                                       unsigned long event, int enable) { }
+static inline struct otg_booster *find_get_booster(struct otg_notify *n)
+                       {return NULL; }
+static inline int register_booster(struct otg_notify *n,
+                                       struct otg_booster *b) {return 0; }
+static inline int register_ovc_func(struct otg_notify *n,
+                       int (*check_state)(void *), void *data) {return 0; }
+static inline int get_usb_mode(struct otg_notify *n) {return 0; }
+static inline unsigned long get_cable_type(struct otg_notify *n) {return 0; }
+static inline int is_usb_host(struct otg_notify *n) {return 0; }
+static inline void *get_notify_data(struct otg_notify *n) {return NULL; }
+static inline void set_notify_data(struct otg_notify *n, void *data) {}
+static inline struct otg_notify *get_otg_notify(void) {return NULL; }
+static inline int set_otg_notify(struct otg_notify *n) {return 0; }
+static inline void put_otg_notify(struct otg_notify *n) {}
+static inline bool is_blocked(struct otg_notify *n, int type) {return false; }
+static inline int usb_check_whitelist_for_mdm(struct usb_device *dev)
+                       {return 0; }
+#if defined(CONFIG_USB_HW_PARAM)
+static unsigned long long *get_hw_param(struct otg_notify *n,
+                       enum usb_hw_param index) {return NULL; }
+static int inc_hw_param(struct otg_notify *n,
+                       enum usb_hw_param index) {return 0; }
+static int inc_hw_param_host(struct host_notify_dev *dev,
+                       enum usb_hw_param index) {return 0; }
+#endif
+#endif
+#endif /* __LINUX_USB_NOTIFY_H__ */
diff --git a/include/linux/usblog_proc_notify.h b/include/linux/usblog_proc_notify.h
new file mode 100644 (file)
index 0000000..4840ea1
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2016-2017 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+  /* usb notify layer v3.1 */
+
+#ifndef __LINUX_USBLOG_PROC_NOTIFY_H__
+#define __LINUX_USBLOG_PROC_NOTIFY_H__
+
+enum usblog_type {
+       NOTIFY_FUNCSTATE,
+       NOTIFY_ALTERNATEMODE,
+       NOTIFY_CCIC_EVENT,
+       NOTIFY_MANAGER,
+       NOTIFY_USBMODE,
+       NOTIFY_USBMODE_EXTRA,
+       NOTIFY_USBSTATE,
+       NOTIFY_EVENT,
+};
+
+enum usblog_state {
+       NOTIFY_CONFIGURED = 1,
+       NOTIFY_CONNECTED,
+       NOTIFY_DISCONNECTED,
+       NOTIFY_RESET,
+       NOTIFY_RESET_FULL,
+       NOTIFY_RESET_HIGH,
+       NOTIFY_RESET_SUPER,
+       NOTIFY_ACCSTART,
+       NOTIFY_PULLUP,
+       NOTIFY_PULLUP_ENABLE,
+       NOTIFY_PULLUP_EN_SUCCESS,
+       NOTIFY_PULLUP_EN_FAIL,
+       NOTIFY_PULLUP_DISABLE,
+       NOTIFY_PULLUP_DIS_SUCCESS,
+       NOTIFY_PULLUP_DIS_FAIL,
+       NOTIFY_VBUS_SESSION,
+       NOTIFY_VBUS_SESSION_ENABLE,
+       NOTIFY_VBUS_EN_SUCCESS,
+       NOTIFY_VBUS_EN_FAIL,
+       NOTIFY_VBUS_SESSION_DISABLE,
+       NOTIFY_VBUS_DIS_SUCCESS,
+       NOTIFY_VBUS_DIS_FAIL,
+       NOTIFY_HIGH,
+       NOTIFY_SUPER,
+};
+
+enum usblog_status {
+       NOTIFY_DETACH = 0,
+       NOTIFY_ATTACH_DFP,
+       NOTIFY_ATTACH_UFP,
+       NOTIFY_ATTACH_DRP,
+};
+
+enum ccic_device {
+       NOTIFY_DEV_INITIAL = 0,
+       NOTIFY_DEV_USB,
+       NOTIFY_DEV_BATTERY,
+       NOTIFY_DEV_PDIC,
+       NOTIFY_DEV_MUIC,
+       NOTIFY_DEV_CCIC,
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       NOTIFY_DEV_MANAGER,
+#endif
+       NOTIFY_DEV_DP,
+       NOTIFY_DEV_USB_DP,
+};
+
+enum ccic_id {
+       NOTIFY_ID_INITIAL = 0,
+       NOTIFY_ID_ATTACH,
+       NOTIFY_ID_RID,
+       NOTIFY_ID_USB,
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       NOTIFY_ID_POWER_STATUS,
+#endif
+       NOTIFY_ID_WATER,
+       NOTIFY_ID_VCONN,
+       NOTIFY_ID_DP_CONNECT,
+       NOTIFY_ID_DP_HPD,
+       NOTIFY_ID_DP_LINK_CONF,
+       NOTIFY_ID_USB_DP,
+       NOTIFY_ID_ROLE_SWAP,
+};
+
+enum ccic_rid {
+       NOTIFY_RID_UNDEFINED = 0,
+       NOTIFY_RID_000K,
+       NOTIFY_RID_001K,
+       NOTIFY_RID_255K,
+       NOTIFY_RID_301K,
+       NOTIFY_RID_523K,
+       NOTIFY_RID_619K,
+       NOTIFY_RID_OPEN,
+};
+
+enum ccic_con {
+       NOTIFY_CON_DETACH = 0,
+       NOTIFY_CON_ATTACH,
+};
+
+enum ccic_rprd {
+       NOTIFY_RD = 0,
+       NOTIFY_RP,
+};
+
+enum ccic_rpstatus {
+       NOTIFY_RP_NONE = 0,
+       NOTIFY_RP_56K,  /* 80uA */
+       NOTIFY_RP_22K,          /* 180uA */
+       NOTIFY_RP_10K,          /* 330uA */
+       NOTIFY_RP_ABNORMAL,
+};
+
+enum ccic_hpd {
+       NOTIFY_HPD_LOW = 0,
+       NOTIFY_HPD_HIGH,
+       NOTIFY_HPD_IRQ,
+};
+
+enum ccic_pin_assignment {
+       NOTIFY_DP_PIN_UNKNOWN = 0,
+       NOTIFY_DP_PIN_A,
+       NOTIFY_DP_PIN_B,
+       NOTIFY_DP_PIN_C,
+       NOTIFY_DP_PIN_D,
+       NOTIFY_DP_PIN_E,
+       NOTIFY_DP_PIN_F,
+};
+
+#define ALTERNATE_MODE_NOT_READY       (1 << 0)
+#define ALTERNATE_MODE_READY           (1 << 1)
+#define ALTERNATE_MODE_STOP            (1 << 2)
+#define ALTERNATE_MODE_START           (1 << 3)
+#define ALTERNATE_MODE_RESET           (1 << 4)
+
+#ifdef CONFIG_USB_NOTIFY_PROC_LOG
+extern void store_usblog_notify(int type, void *param1, void *parma2);
+extern void store_ccic_version(unsigned char *hw, unsigned char *sw_main,
+                       unsigned char *sw_boot);
+extern int register_usblog_proc(void);
+extern void unregister_usblog_proc(void);
+#else
+static inline void store_usblog_notify(int type, void *param1, void *parma2) {}
+static inline void store_ccic_version(unsigned char *hw, unsigned char *sw_main,
+                       unsigned char *sw_boot) {}
+static inline int register_usblog_proc(void)
+                       {return 0; }
+static inline void unregister_usblog_proc(void) {}
+#endif
+#endif
+