[RAMEN9610-12059] ccic : sync s2mu106 ccic code
authorJunhan Bae <junhan84.bae@samsung.com>
Tue, 12 Feb 2019 04:53:33 +0000 (13:53 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:23:16 +0000 (20:23 +0300)
Change-Id: I3fc4fee2eccd286d6dad4eab33746c2a30ba7261
Signed-off-by: Junhan Bae <junhan84.bae@samsung.com>
15 files changed:
drivers/ccic/Makefile
drivers/ccic/s2mm005_usbpd_phy.c
drivers/ccic/s2mu106-usbpd.c [new file with mode: 0644]
drivers/ccic/usbpd-manager.c
drivers/ccic/usbpd.c [new file with mode: 0644]
drivers/ccic/usbpd_cc.c [new file with mode: 0644]
drivers/ccic/usbpd_manager.c [new file with mode: 0644]
drivers/ccic/usbpd_policy.c [new file with mode: 0644]
drivers/ccic/usbpd_sysfs.c
include/linux/ccic/core.h
include/linux/ccic/s2mm005_usbpd_msg.h [new file with mode: 0644]
include/linux/ccic/usbpd-s2mu106.h [new file with mode: 0644]
include/linux/ccic/usbpd.h [new file with mode: 0644]
include/linux/ccic/usbpd_ext.h [new file with mode: 0644]
include/linux/ccic/usbpd_msg.h

index 1502c7a3c8c6292cf11548e4aa2f497059cfde31..5c422fc5620a4e7c647928f01e03575b5bfcd15f 100644 (file)
@@ -10,3 +10,7 @@ obj-$(CONFIG_CCIC_S2MM005)            += s2mm005_fw.o s2mm005_cc.o s2mm005_pd.o sec_pd.o s
 obj-$(CONFIG_CCIC_MAX77705)            += max77705_cc.o max77705_pd.o sec_pd.o max77705_usbc.o max77705_alternate.o
 obj-$(CONFIG_CCIC_MAX77705_DEBUG)      += max77705_debug.o
 obj-$(CONFIG_USBPD_S2MM005)            += s2mm005_usbpd_fw.o s2mm005_usbpd_phy.o s2mm005_usbpd.o s2mm005_usbpd_i2c.o s2mm005_usbpd_interface.o usbpd_sysfs.o
+obj-$(CONFIG_CCIC_S2MU106)  += s2mu106-usbpd.o
+obj-$(CONFIG_USE_CCIC)      += usbpd.o usbpd_cc.o
+obj-$(CONFIG_USE_CCIC)      += usbpd_policy.o usbpd_manager.o
+obj-$(CONFIG_CCIC_SYSFS)        += usbpd_sysfs.o
index 5b9ed2e1d2af566cd3b521df7cf7a58cef6e0ab8..60b792dddead1122dd342a7b8a12b5da6e9c4879 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/ccic/s2mm005_usbpd.h>
 #include <linux/ccic/s2mm005_usbpd_phy.h>
 #include <linux/ccic/usbpd_typec.h>
-#include <linux/ccic/usbpd_msg.h>
+#include <linux/ccic/s2mm005_usbpd_msg.h>
 
 static char VDM_MSG_IRQ_State_Print[9][40] = {
     {"bFLAG_Vdm_Reserve_b0"},
diff --git a/drivers/ccic/s2mu106-usbpd.c b/drivers/ccic/s2mu106-usbpd.c
new file mode 100644 (file)
index 0000000..133ce1c
--- /dev/null
@@ -0,0 +1,2886 @@
+/*
+ driver/usbpd/s2mu106.c - s2mu106 USB PD(Power Delivery) device driver
+ *
+ * Copyright (C) 2018 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.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+
+#include <linux/ccic/usbpd.h>
+#include <linux/ccic/usbpd-s2mu106.h>
+
+#include <linux/muic/muic.h>
+#if defined(CONFIG_MUIC_NOTIFIER)
+#include <linux/muic/muic_notifier.h>
+#endif /* CONFIG_MUIC_NOTIFIER */
+#ifdef CONFIG_BATTERY_SAMSUNG
+#include <linux/sec_batt.h>
+#include <linux/battery/sec_charging_common.h>
+#else
+#include <linux/power_supply.h>
+#endif
+#if defined(CONFIG_USB_HOST_NOTIFY) || defined(CONFIG_USB_HW_PARAM)
+#include <linux/usb_notify.h>
+#endif
+#include <linux/regulator/consumer.h>
+
+#if (defined CONFIG_IFCONN_NOTIFIER || defined CONFIG_DUAL_ROLE_USB_INTF)
+#include <linux/ccic/usbpd_ext.h>
+#endif
+#if defined CONFIG_IFCONN_NOTIFIER
+struct pdic_notifier_data pd_noti;
+#endif
+/*
+*VARIABLE DEFINITION
+*/
+static usbpd_phy_ops_type s2mu106_ops;
+struct i2c_client *test_i2c;
+
+static enum power_supply_property ccic_props[] = {
+};
+
+static char *ccic_supplied_to[] = {
+       "battery",
+};
+/*
+*FUNCTION DEFINITION
+*/
+static int s2mu106_receive_message(void *data);
+static int s2mu106_check_port_detect(struct s2mu106_usbpd_data *pdic_data);
+static int s2mu106_usbpd_reg_init(struct s2mu106_usbpd_data *_data);
+static void s2mu106_dfp(struct i2c_client *i2c);
+static void s2mu106_ufp(struct i2c_client *i2c);
+#ifdef CONFIG_CCIC_VDM
+static int s2mu106_usbpd_check_vdm_msg(void *_data, u64 *val);
+#endif
+static void s2mu106_src(struct i2c_client *i2c);
+static void s2mu106_snk(struct i2c_client *i2c);
+static void s2mu106_assert_rd(void *_data);
+static void s2mu106_assert_rp(void *_data);
+static int s2mu106_set_attach(struct s2mu106_usbpd_data *pdic_data, u8 mode);
+static int s2mu106_set_detach(struct s2mu106_usbpd_data *pdic_data, u8 mode);
+static void s2mu106_usbpd_check_rid(struct s2mu106_usbpd_data *pdic_data);
+static int s2mu106_usbpd_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
+static int s2mu106_usbpd_write_reg(struct i2c_client *i2c, u8 reg, u8 value);
+#ifndef CONFIG_SEC_FACTORY
+static void s2mu106_usbpd_set_threshold(struct s2mu106_usbpd_data *pdic_data,
+                       CCIC_RP_RD_SEL port_sel, CCIC_THRESHOLD_SEL threshold_sel);
+static void s2mu106_usbpd_notify_detach(struct s2mu106_usbpd_data *pdic_data);
+#endif
+static void s2mu106_usbpd_detach_init(struct s2mu106_usbpd_data *pdic_data);
+static int s2mu106_usbpd_set_cc_control(struct s2mu106_usbpd_data  *pdic_data, int val);
+
+char *rid_text[] = {
+       "UNDEFINED",
+       "RID ERROR",
+       "RID ERROR",
+       "RID 255K",
+       "RID 301K",
+       "RID 523K",
+       "RID 619K"
+};
+
+static void s2mu106_usbpd_test_read(struct s2mu106_usbpd_data *usbpd_data)
+{
+       struct i2c_client *i2c = usbpd_data->i2c;
+       u8 data[10];
+
+       s2mu106_usbpd_read_reg(i2c, 0x1, &data[0]);
+       s2mu106_usbpd_read_reg(i2c, 0x18, &data[1]);
+       s2mu106_usbpd_read_reg(i2c, 0x27, &data[2]);
+       s2mu106_usbpd_read_reg(i2c, 0x28, &data[3]);
+       s2mu106_usbpd_read_reg(i2c, 0x40, &data[4]);
+       s2mu106_usbpd_read_reg(i2c, 0xe2, &data[5]);
+       s2mu106_usbpd_read_reg(i2c, 0xb3, &data[6]);
+       s2mu106_usbpd_read_reg(i2c, 0xb4, &data[7]);
+
+       pr_info("%s, 0x1(%x) 0x18(%x) 0x27(%x) 0x28(%x) 0x40(%x) 0xe2(%x) 0xb3(%x) 0xb4(%x)\n",
+                       __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+}
+
+void s2mu106_rprd_mode_change(struct s2mu106_usbpd_data *usbpd_data, u8 mode)
+{
+       u8 data = 0;
+       struct i2c_client *i2c = usbpd_data->i2c;
+       pr_info("%s, mode=0x%x\n", __func__, mode);
+
+       mutex_lock(&usbpd_data->lpm_mutex);
+       if (usbpd_data->lpm_mode)
+               goto skip;
+
+       switch (mode) {
+       case TYPE_C_ATTACH_DFP: /* SRC */
+               s2mu106_set_detach(usbpd_data, mode);
+               msleep(S2MU106_ROLE_SWAP_TIME_MS);
+               s2mu106_set_attach(usbpd_data, mode);
+               break;
+       case TYPE_C_ATTACH_UFP: /* SNK */
+               s2mu106_set_detach(usbpd_data, mode);
+               msleep(S2MU106_ROLE_SWAP_TIME_MS);
+               s2mu106_set_attach(usbpd_data, mode);
+               break;
+       case TYPE_C_ATTACH_DRP: /* DRP */
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+               data |= S2MU106_REG_PLUG_CTRL_DRP;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+               break;
+       };
+skip:
+       mutex_unlock(&usbpd_data->lpm_mutex);
+}
+
+void vbus_turn_on_ctrl(struct s2mu106_usbpd_data *usbpd_data, bool enable)
+{
+       struct power_supply *psy_otg;
+       union power_supply_propval val;
+       int on = !!enable;
+       int ret = 0, retry_cnt = 0;
+
+       pr_info("%s %d, enable=%d\n", __func__, __LINE__, enable);
+       psy_otg = power_supply_get_by_name("otg");
+
+       if (psy_otg) {
+               val.intval = enable;
+               usbpd_data->is_otg_vboost = enable;
+               ret = psy_otg->desc->set_property(psy_otg, POWER_SUPPLY_PROP_ONLINE, &val);
+       } else {
+               pr_err("%s: Fail to get psy battery\n", __func__);
+
+               return;
+       }
+       if (ret) {
+               pr_err("%s: fail to set power_suppy ONLINE property(%d)\n",
+                       __func__, ret);
+       } else {
+               if (enable == VBUS_ON) {
+                       for (retry_cnt = 0; retry_cnt < 5; retry_cnt++) {
+                               psy_otg->desc->get_property(psy_otg, POWER_SUPPLY_PROP_ONLINE, &val);
+                               if (val.intval == VBUS_OFF) {
+                                       msleep(100);
+                                       val.intval = enable;
+                                       psy_otg->desc->set_property(psy_otg, POWER_SUPPLY_PROP_ONLINE, &val);
+                               } else
+                                       break;
+                       }
+               }
+               pr_info("otg accessory power = %d\n", on);
+       }
+
+}
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+static void process_dr_swap(struct s2mu106_usbpd_data *usbpd_data)
+{
+       struct i2c_client *i2c = usbpd_data->i2c;
+       dev_info(&i2c->dev, "%s : before - is_host : %d, is_client : %d\n",
+               __func__, usbpd_data->is_host, usbpd_data->is_client);
+       if (usbpd_data->is_host == HOST_ON) {
+               ifconn_event_work(usbpd_data, IFCONN_NOTIFY_USB,
+                                       IFCONN_NOTIFY_ID_USB, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+               ifconn_event_work(usbpd_data, IFCONN_NOTIFY_MUIC,
+                                       IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+               ifconn_event_work(usbpd_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                                               IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP, NULL);
+               usbpd_data->is_host = HOST_OFF;
+               usbpd_data->is_client = CLIENT_ON;
+       } else if (usbpd_data->is_client == CLIENT_ON) {
+               ifconn_event_work(usbpd_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                                                       IFCONN_NOTIFY_EVENT_DETACH, NULL);
+               ifconn_event_work(usbpd_data, IFCONN_NOTIFY_MUIC, IFCONN_NOTIFY_ID_ATTACH,
+                                                                       IFCONN_NOTIFY_EVENT_ATTACH, NULL);
+               ifconn_event_work(usbpd_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                                       IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP, NULL);
+               usbpd_data->is_host = HOST_ON;
+               usbpd_data->is_client = CLIENT_OFF;
+       }
+       dev_info(&i2c->dev, "%s : after - is_host : %d, is_client : %d\n",
+               __func__, usbpd_data->is_host, usbpd_data->is_client);
+}
+#endif
+
+static int s2mu106_usbpd_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
+{
+       int ret;
+       struct device *dev = &i2c->dev;
+#if defined(CONFIG_USB_HW_PARAM)
+       struct otg_notify *o_notify = get_otg_notify();
+#endif
+
+       ret = i2c_smbus_read_byte_data(i2c, reg);
+       if (ret < 0) {
+               dev_err(dev, "%s reg(0x%x), ret(%d)\n", __func__, reg, ret);
+#if defined(CONFIG_USB_HW_PARAM)
+               if (o_notify)
+                       inc_hw_param(o_notify, USB_CCIC_I2C_ERROR_COUNT);
+#endif
+               return ret;
+       }
+       ret &= 0xff;
+       *dest = ret;
+       return 0;
+}
+
+static int s2mu106_usbpd_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
+{
+       int ret;
+       struct device *dev = &i2c->dev;
+#if defined(CONFIG_USB_HW_PARAM)
+       struct otg_notify *o_notify = get_otg_notify();
+#endif
+#ifdef CONFIG_SEC_FACTORY
+       int retry = 0;
+#endif
+
+       ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
+#ifdef CONFIG_SEC_FACTORY
+       for (retry = 0; retry < 5; retry++) {
+               if (ret < 0) {
+                       dev_err(dev, "%s reg(0x%x), ret(%d) retry(%d) after now\n",
+                                                       __func__, reg, ret, retry);
+                       msleep(40);
+                       ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
+               } else
+                       break;
+       }
+
+       if (ret < 0) {
+               dev_err(dev, "%s failed to read reg, ret(%d)\n", __func__, ret);
+#else
+       if (ret < 0) {
+               dev_err(dev, "%s reg(0x%x), ret(%d)\n", __func__, reg, ret);
+#endif
+
+#if defined(CONFIG_USB_HW_PARAM)
+               if (o_notify)
+                       inc_hw_param(o_notify, USB_CCIC_I2C_ERROR_COUNT);
+#endif
+               return ret;
+       }
+
+       return 0;
+}
+
+static int s2mu106_usbpd_write_reg(struct i2c_client *i2c, u8 reg, u8 value)
+{
+       int ret;
+       struct device *dev = &i2c->dev;
+#if defined(CONFIG_USB_HW_PARAM)
+       struct otg_notify *o_notify = get_otg_notify();
+#endif
+
+       ret = i2c_smbus_write_byte_data(i2c, reg, value);
+       if (ret < 0) {
+               dev_err(dev, "%s reg(0x%x), ret(%d)\n", __func__, reg, ret);
+#if defined(CONFIG_USB_HW_PARAM)
+               if (o_notify)
+                       inc_hw_param(o_notify, USB_CCIC_I2C_ERROR_COUNT);
+#endif
+       }
+       return ret;
+}
+
+static int s2mu106_usbpd_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
+{
+       int ret;
+       struct device *dev = &i2c->dev;
+#if defined(CONFIG_USB_HW_PARAM)
+       struct otg_notify *o_notify = get_otg_notify();
+#endif
+
+       ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);
+       if (ret < 0) {
+               dev_err(dev, "%s reg(0x%x), ret(%d)\n", __func__, reg, ret);
+#if defined(CONFIG_USB_HW_PARAM)
+               if (o_notify)
+                       inc_hw_param(o_notify, USB_CCIC_I2C_ERROR_COUNT);
+#endif
+               return ret;
+       }
+       return 0;
+}
+
+static int s2mu106_usbpd_update_bit(struct i2c_client *i2c,
+                       u8 reg, u8 mask, u8 shift, u8 value)
+{
+       int ret;
+       u8 reg_val = 0;
+
+       ret = s2mu106_usbpd_read_reg(i2c, reg, &reg_val);
+       if (ret < 0) {
+               pr_err("%s: Reg = 0x%X, val = 0x%X, read err : %d\n",
+                       __func__, reg, reg_val, ret);
+       }
+       reg_val &= ~mask;
+       reg_val |= value << shift;
+       ret = s2mu106_usbpd_write_reg(i2c, reg, reg_val);
+       if (ret < 0) {
+               pr_err("%s: Reg = 0x%X, mask = 0x%X, val = 0x%X, write err : %d\n",
+                       __func__, reg, mask, value, ret);
+       }
+
+       return ret;
+}
+
+static int s2mu106_write_msg_header(struct i2c_client *i2c, u8 *buf)
+{
+       int ret;
+
+       ret = s2mu106_usbpd_bulk_write(i2c, S2MU106_REG_MSG_TX_HEADER_L, 2, buf);
+
+       return ret;
+}
+
+static int s2mu106_write_msg_obj(struct i2c_client *i2c, int count, data_obj_type *obj)
+{
+       int ret = 0;
+       int i = 0;
+       struct device *dev = &i2c->dev;
+
+       if (count > S2MU106_MAX_NUM_MSG_OBJ)
+               dev_err(dev, "%s, not invalid obj count number\n", __func__);
+       else
+               for (i = 0; i < count; i++) {
+                       ret = s2mu106_usbpd_bulk_write(i2c,
+                               S2MU106_REG_MSG_TX_OBJECT0_0_L + (4 * i),
+                                                       4, obj[i].byte);
+               }
+
+       return ret;
+}
+
+static int s2mu106_send_msg(struct i2c_client *i2c)
+{
+       int ret;
+       u8 reg = S2MU106_REG_MSG_SEND_CON;
+       u8 val = S2MU106_REG_MSG_SEND_CON_OP_MODE
+                       | S2MU106_REG_MSG_SEND_CON_SEND_MSG_EN;
+
+       s2mu106_usbpd_write_reg(i2c, reg, val);
+
+       ret = s2mu106_usbpd_write_reg(i2c, reg, S2MU106_REG_MSG_SEND_CON_OP_MODE);
+
+       return ret;
+}
+
+static int s2mu106_read_msg_header(struct i2c_client *i2c, msg_header_type *header)
+{
+       int ret;
+
+       ret = s2mu106_usbpd_bulk_read(i2c, S2MU106_REG_MSG_RX_HEADER_L, 2, header->byte);
+
+       return ret;
+}
+
+static int s2mu106_read_msg_obj(struct i2c_client *i2c, int count, data_obj_type *obj)
+{
+       int ret = 0;
+       int i = 0;
+       struct device *dev = &i2c->dev;
+
+       if (count > S2MU106_MAX_NUM_MSG_OBJ) {
+               dev_err(dev, "%s, not invalid obj count number\n", __func__);
+               ret = -EINVAL; /*TODO: check fail case */
+       } else {
+               for (i = 0; i < count; i++) {
+                       ret = s2mu106_usbpd_bulk_read(i2c,
+                               S2MU106_REG_MSG_RX_OBJECT0_0_L + (4 * i),
+                                                       4, obj[i].byte);
+               }
+       }
+
+       return ret;
+}
+
+static void s2mu106_set_irq_enable(struct s2mu106_usbpd_data *_data,
+               u8 int0, u8 int1, u8 int2, u8 int3, u8 int4, u8 int5)
+{
+       u8 int_mask[S2MU106_MAX_NUM_INT_STATUS]
+               = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+       int ret = 0;
+       struct i2c_client *i2c = _data->i2c;
+       struct device *dev = &i2c->dev;
+
+       int_mask[0] &= ~int0;
+       int_mask[1] &= ~int1;
+       int_mask[2] &= ~int2;
+       int_mask[3] &= ~int3;
+       int_mask[4] &= ~int4;
+       int_mask[5] &= ~int5;
+
+       ret = i2c_smbus_write_i2c_block_data(i2c, S2MU106_REG_INT_MASK0,
+                       S2MU106_MAX_NUM_INT_STATUS, int_mask);
+
+       if (ret < 0)
+               dev_err(dev, "err write interrupt mask \n");
+}
+
+static void s2mu106_self_soft_reset(struct i2c_client *i2c)
+{
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_ETC,
+                       S2MU106_REG_ETC_SOFT_RESET_EN);
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_ETC,
+                       S2MU106_REG_ETC_SOFT_RESET_DIS);
+}
+
+static void s2mu106_driver_reset(void *_data)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       int i;
+
+       pdic_data->status_reg = 0;
+       data->wait_for_msg_arrived = 0;
+       pdic_data->header.word = 0;
+       for (i = 0; i < S2MU106_MAX_NUM_MSG_OBJ; i++)
+               pdic_data->obj[i].object = 0;
+
+       s2mu106_set_irq_enable(pdic_data, ENABLED_INT_0, ENABLED_INT_1,
+                       ENABLED_INT_2, ENABLED_INT_3, ENABLED_INT_4, ENABLED_INT_5);
+}
+
+static void s2mu106_assert_drp(void *_data)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 val;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &val);
+       val &= ~S2MU106_REG_PLUG_CTRL_FSM_MANUAL_EN;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, val);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, &val);
+       val &= ~S2MU106_REG_PLUG_CTRL_FSM_MANUAL_INPUT_MASK;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, val);
+}
+
+static void s2mu106_assert_rd(void *_data)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 val;
+       u8 cc1_val, cc2_val;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON1, &val);
+
+       cc1_val = val & S2MU106_REG_CTRL_MON_CC1_MASK;
+       cc2_val = (val & S2MU106_REG_CTRL_MON_CC2_MASK) >> S2MU106_REG_CTRL_MON_CC2_SHIFT;
+
+       if (cc1_val == 2) {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, &val);
+               val = (val & ~S2MU106_REG_PLUG_CTRL_CC_MANUAL_MASK) |
+                               S2MU106_REG_PLUG_CTRL_CC1_MANUAL_ON;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, val);
+
+               if (pdic_data->vconn_en) {
+                       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &val);
+                       val = (val & ~S2MU106_REG_PLUG_CTRL_CC_MANUAL_MASK) |
+                                       S2MU106_REG_PLUG_CTRL_RpRd_CC2_VCONN |
+                                       S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN;
+                       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, val);
+               }
+       }
+
+       if (cc2_val == 2) {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, &val);
+               val = (val & ~S2MU106_REG_PLUG_CTRL_CC_MANUAL_MASK) |
+                               S2MU106_REG_PLUG_CTRL_CC2_MANUAL_ON;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, val);
+
+               if (pdic_data->vconn_en) {
+                       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &val);
+                       val = (val & ~S2MU106_REG_PLUG_CTRL_CC_MANUAL_MASK) |
+                                       S2MU106_REG_PLUG_CTRL_RpRd_CC1_VCONN |
+                                       S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN;
+                       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, val);
+               }
+       }
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, &val);
+       val &= ~S2MU106_REG_PLUG_CTRL_FSM_MANUAL_INPUT_MASK;
+       val |= S2MU106_REG_PLUG_CTRL_FSM_ATTACHED_SNK;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, val);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &val);
+       val |= S2MU106_REG_PLUG_CTRL_FSM_MANUAL_EN;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, val);
+}
+
+static void s2mu106_assert_rp(void *_data)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 val;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, &val);
+       val &= ~S2MU106_REG_PLUG_CTRL_FSM_MANUAL_INPUT_MASK;
+       val |= S2MU106_REG_PLUG_CTRL_FSM_ATTACHED_SRC;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, val);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &val);
+       val |= S2MU106_REG_PLUG_CTRL_FSM_MANUAL_EN;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, val);
+}
+
+static unsigned s2mu106_get_status(void *_data, unsigned flag)
+{
+       unsigned ret;
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+
+       if (pdic_data->status_reg & flag) {
+               ret = pdic_data->status_reg & flag;
+               pdic_data->status_reg &= ~flag; /* clear the flag */
+               return ret;
+       } else {
+               return 0;
+       }
+}
+
+static bool s2mu106_poll_status(void *_data)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct policy_data *policy = &data->policy;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+       u8 intr[S2MU106_MAX_NUM_INT_STATUS] = {0};
+       int ret = 0, retry = 0;
+       u64 status_reg_val = 0;
+
+       ret = s2mu106_usbpd_bulk_read(i2c, S2MU106_REG_INT_STATUS0,
+                       S2MU106_MAX_NUM_INT_STATUS, intr);
+
+       dev_info(dev, "%s status[0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x]\n",
+                       __func__, intr[0], intr[1], intr[2], intr[3], intr[4], intr[5], intr[6]);
+
+       if ((intr[0] | intr[1] | intr[2] | intr[3] | intr[4] | intr[5]) == 0) {
+               status_reg_val |= MSG_NONE;
+               goto out;
+       }
+
+       if ((intr[2] & S2MU106_REG_INT_STATUS2_WAKEUP) ||
+               (intr[4] & S2MU106_REG_INT_STATUS4_CC12_DET_IRQ))
+               s2mu106_set_irq_enable(pdic_data, ENABLED_INT_0, ENABLED_INT_1,
+                               ENABLED_INT_2, ENABLED_INT_3, ENABLED_INT_4, ENABLED_INT_5);
+
+       if (intr[5] & S2MU106_REG_INT_STATUS5_HARD_RESET) {
+               status_reg_val |= MSG_HARDRESET;
+               goto out;
+       }
+
+       /* when occur detach & attach atomic */
+       if (intr[4] & S2MU106_REG_INT_STATUS4_USB_DETACH) {
+               status_reg_val |= PLUG_DETACH;
+       }
+
+       mutex_lock(&pdic_data->lpm_mutex);
+       if ((intr[4] & S2MU106_REG_INT_STATUS4_PLUG_IRQ) &&
+                       !pdic_data->lpm_mode && !pdic_data->is_water_detect)
+               status_reg_val |= PLUG_ATTACH;
+       else if (pdic_data->lpm_mode &&
+                               (intr[4] & S2MU106_REG_INT_STATUS4_PLUG_IRQ) &&
+                                                                       !pdic_data->is_water_detect)
+               retry = 1;
+       mutex_unlock(&pdic_data->lpm_mutex);
+
+       if (retry) {
+               msleep(40);
+               mutex_lock(&pdic_data->lpm_mutex);
+               if ((intr[4] & S2MU106_REG_INT_STATUS4_PLUG_IRQ) &&
+                               !pdic_data->lpm_mode && !pdic_data->is_water_detect)
+                       status_reg_val |= PLUG_ATTACH;
+               mutex_unlock(&pdic_data->lpm_mutex);
+       }
+
+#ifdef CONFIG_CCIC_VDM
+       /* function that support dp control */
+       if (pdic_data->check_msg_pass) {
+               if (intr[4] & S2MU106_REG_INT_STATUS4_MSG_PASS)
+                       status_reg_val |= MSG_PASS;
+       }
+#endif
+/* #if defined(CONFIG_CCIC_FACTORY) */
+       if ((intr[4] & S2MU106_REG_INT_STATUS4_MSG_PASS) &&
+               (intr[3] & S2MU106_REG_INT_STATUS3_UNS_CMD_DATA)) {
+               status_reg_val |= MSG_RID;
+       }
+/* #endif */
+
+       if (intr[0] & S2MU106_REG_INT_STATUS0_MSG_GOODCRC
+                       || intr[4] & S2MU106_REG_INT_STATUS4_MSG_SENT)
+               status_reg_val |= MSG_GOODCRC;
+
+       if (intr[0] & S2MU106_REG_INT_STATUS0_MSG_ACCEPT)
+               status_reg_val |= MSG_ACCEPT;
+
+       if (intr[1] & S2MU106_REG_INT_STATUS1_MSG_PSRDY)
+               status_reg_val |= MSG_PSRDY;
+
+       if (intr[2] & S2MU106_REG_INT_STATUS2_MSG_REQUEST)
+               status_reg_val |= MSG_REQUEST;
+
+       if (intr[1] & S2MU106_REG_INT_STATUS1_MSG_REJECT)
+               status_reg_val |= MSG_REJECT;
+
+       if (intr[2] & S2MU106_REG_INT_STATUS2_MSG_WAIT)
+               status_reg_val |= MSG_WAIT;
+
+       if (intr[4] & S2MU106_REG_INT_STATUS4_MSG_ERROR)
+               status_reg_val |= MSG_ERROR;
+
+       if (intr[1] & S2MU106_REG_INT_STATUS1_MSG_PING)
+               status_reg_val |= MSG_PING;
+
+       if (intr[1] & S2MU106_REG_INT_STATUS1_MSG_GETSNKCAP)
+               status_reg_val |= MSG_GET_SNK_CAP;
+
+       if (intr[1] & S2MU106_REG_INT_STATUS1_MSG_GETSRCCAP)
+               status_reg_val |= MSG_GET_SRC_CAP;
+
+       if (intr[2] & S2MU106_REG_INT_STATUS2_MSG_SRC_CAP) {
+               if (!policy->plug_valid)
+                       pdic_data->status_reg |= PLUG_ATTACH;
+               status_reg_val |= MSG_SRC_CAP;
+       }
+
+       if (intr[2] & S2MU106_REG_INT_STATUS2_MSG_SNK_CAP)
+               status_reg_val |= MSG_SNK_CAP;
+
+       if (intr[2] & S2MU106_REG_INT_STATUS2_MSG_SOFTRESET)
+               status_reg_val |= MSG_SOFTRESET;
+
+       if (intr[1] & S2MU106_REG_INT_STATUS1_MSG_PR_SWAP)
+               status_reg_val |= MSG_PR_SWAP;
+
+       if (intr[2] & S2MU106_REG_INT_STATUS2_MSG_VCONN_SWAP)
+               status_reg_val |= MSG_VCONN_SWAP;
+
+       if (intr[1] & S2MU106_REG_INT_STATUS1_MSG_DR_SWAP)
+               status_reg_val |= MSG_DR_SWAP;
+
+       if (intr[0] & S2MU106_REG_INT_STATUS0_VDM_DISCOVER_ID)
+               status_reg_val |= VDM_DISCOVER_IDENTITY;
+
+       if (intr[0] & S2MU106_REG_INT_STATUS0_VDM_DISCOVER_SVID)
+               status_reg_val |= VDM_DISCOVER_SVID;
+
+       if (intr[0] & S2MU106_REG_INT_STATUS0_VDM_DISCOVER_MODE)
+               status_reg_val |= VDM_DISCOVER_MODE;
+
+       if (intr[0] & S2MU106_REG_INT_STATUS0_VDM_ENTER)
+               status_reg_val |= VDM_ENTER_MODE;
+
+       if (intr[0] & S2MU106_REG_INT_STATUS0_VDM_EXIT)
+               status_reg_val |= VDM_EXIT_MODE;
+
+       if (intr[0] & S2MU106_REG_INT_STATUS0_VDM_ATTENTION)
+               status_reg_val |= VDM_ATTENTION;
+/* disable function that support dp control */
+#ifdef CONFIG_CCIC_VDM
+       /* read message if data object message */
+       if (status_reg_val &
+                       (MSG_REQUEST | MSG_SNK_CAP
+                       | VDM_DISCOVER_IDENTITY | VDM_DISCOVER_SVID
+                       | VDM_DISCOVER_MODE | VDM_ENTER_MODE | VDM_EXIT_MODE
+                       | VDM_ATTENTION | MSG_PASS)) {
+               usbpd_protocol_rx(data);
+               if (status_reg_val & MSG_PASS)
+                       s2mu106_usbpd_check_vdm_msg(data, &status_reg_val);
+       }
+#else
+       /* read message if data object message */
+       if (status_reg_val &
+                       (MSG_REQUEST | MSG_SNK_CAP
+                       | VDM_DISCOVER_IDENTITY | VDM_DISCOVER_SVID
+                       | VDM_DISCOVER_MODE | VDM_ENTER_MODE | VDM_EXIT_MODE
+                       | VDM_ATTENTION)) {
+               usbpd_protocol_rx(data);
+       }
+#endif
+out:
+       pdic_data->status_reg |= status_reg_val;
+
+       /* complete wait msg */
+       if (pdic_data->status_reg & data->wait_for_msg_arrived) {
+               data->wait_for_msg_arrived = 0;
+               complete(&data->msg_arrived);
+       }
+
+       return 0;
+}
+
+static int s2mu106_hard_reset(void *_data)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       int ret;
+       u8 reg;
+
+       if (pdic_data->rid != REG_RID_UNDF && pdic_data->rid != REG_RID_MAX)
+               return 0;
+
+       reg = S2MU106_REG_MSG_SEND_CON;
+
+       ret = s2mu106_usbpd_write_reg(i2c, reg, S2MU106_REG_MSG_SEND_CON_SOP_HardRST
+                       | S2MU106_REG_MSG_SEND_CON_OP_MODE);
+       if (ret < 0)
+               goto fail;
+       udelay(5);
+       ret = s2mu106_usbpd_write_reg(i2c, reg, S2MU106_REG_MSG_SEND_CON_SOP_HardRST
+                       | S2MU106_REG_MSG_SEND_CON_OP_MODE
+                       | S2MU106_REG_MSG_SEND_CON_SEND_MSG_EN);
+       if (ret < 0)
+               goto fail;
+       udelay(1);
+       ret = s2mu106_usbpd_write_reg(i2c, reg, S2MU106_REG_MSG_SEND_CON_OP_MODE);
+       udelay(1);
+       ret = s2mu106_usbpd_write_reg(i2c, reg, S2MU106_RESET_REG_00);
+       if (ret < 0)
+               goto fail;
+
+       s2mu106_self_soft_reset(i2c);
+
+       pdic_data->status_reg = 0;
+
+       return 0;
+
+fail:
+       return -EIO;
+}
+
+static int s2mu106_receive_message(void *data)
+{
+       struct s2mu106_usbpd_data *pdic_data = data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+       int obj_num = 0;
+       int ret = 0;
+
+       ret = s2mu106_read_msg_header(i2c, &pdic_data->header);
+       if (ret < 0)
+               dev_err(dev, "%s read msg header error\n", __func__);
+
+       obj_num = pdic_data->header.num_data_objs;
+
+       if (obj_num > 0) {
+               ret = s2mu106_read_msg_obj(i2c,
+                       obj_num, &pdic_data->obj[0]);
+       }
+
+       return ret;
+}
+
+static int s2mu106_tx_msg(void *_data,
+               msg_header_type *header, data_obj_type *obj)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       int ret = 0;
+       int count = 0;
+       u8 reg_data = 0;
+       u8 msg_id = 0;
+
+       mutex_lock(&pdic_data->_mutex);
+
+       /* if there is no attach, skip tx msg */
+       if (pdic_data->detach_valid)
+               goto done;
+
+       /* using msg id counter at s2mu106 */
+       s2mu106_usbpd_read_reg(pdic_data->i2c, S2MU106_REG_ID_MONITOR, &reg_data);
+       msg_id = reg_data & S2MU106_REG_ID_MONITOR_MSG_ID_MASK;
+       header->msg_id = msg_id;
+
+       ret = s2mu106_write_msg_header(i2c, header->byte);
+       if (ret < 0)
+               goto done;
+
+       count = header->num_data_objs;
+
+       if (count > 0) {
+               ret = s2mu106_write_msg_obj(i2c, count, obj);
+               if (ret < 0)
+                       goto done;
+       }
+
+       s2mu106_send_msg(i2c);
+
+       pdic_data->status_reg = 0;
+       data->wait_for_msg_arrived = 0;
+
+done:
+       mutex_unlock(&pdic_data->_mutex);
+       return ret;
+}
+
+static int s2mu106_rx_msg(void *_data,
+               msg_header_type *header, data_obj_type *obj)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       int i;
+       int count = 0;
+
+       if (!s2mu106_receive_message(pdic_data)) {
+               header->word = pdic_data->header.word;
+               count = pdic_data->header.num_data_objs;
+               if (count > 0) {
+                       for (i = 0; i < count; i++)
+                               obj[i].object = pdic_data->obj[i].object;
+               }
+               pdic_data->header.word = 0; /* To clear for duplicated call */
+               return 0;
+       } else {
+               return -EINVAL;
+       }
+}
+
+static int s2mu106_set_otg_control(void *_data, int val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+
+       if (val)
+               vbus_turn_on_ctrl(pdic_data, VBUS_ON);
+       else
+               vbus_turn_on_ctrl(pdic_data, VBUS_OFF);
+
+       return 0;
+}
+
+static int s2mu106_set_cc_control(void *_data, int val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+
+       return s2mu106_usbpd_set_cc_control(pdic_data, val);
+}
+
+#if defined(CONFIG_CHECK_CTYPE_SIDE) || defined(CONFIG_CCIC_SYSFS)
+static int s2mu106_get_side_check(void *_data)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 val, cc1_val, cc2_val;
+
+       s2mu106_usbpd_test_read(pdic_data);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON1, &val);
+
+       cc1_val = val & S2MU106_REG_CTRL_MON_CC1_MASK;
+       cc2_val = (val & S2MU106_REG_CTRL_MON_CC2_MASK) >> S2MU106_REG_CTRL_MON_CC2_SHIFT;
+
+       if (cc1_val == USBPD_Rd)
+               return USBPD_UP_SIDE;
+       else if (cc2_val == USBPD_Rd)
+               return USBPD_DOWN_SIDE;
+       else
+               return USBPD_UNDEFFINED_SIDE;
+}
+#endif
+static int s2mu106_set_vconn_source(void *_data, int val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 reg_data = 0, reg_val = 0, cc1_val = 0, cc2_val = 0;
+
+       if (!pdic_data->vconn_en) {
+               pr_err("%s, not support vconn source\n", __func__);
+               return -1;
+       }
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON1, &reg_val);
+       cc1_val = (reg_val & S2MU106_REG_CTRL_MON_CC1_MASK) >> S2MU106_REG_CTRL_MON_CC1_SHIFT;
+       cc2_val = (reg_val & S2MU106_REG_CTRL_MON_CC2_MASK) >> S2MU106_REG_CTRL_MON_CC2_SHIFT;
+
+       if (val == USBPD_VCONN_ON) {
+               if (cc1_val == USBPD_Rd) {
+                       if (cc2_val == USBPD_Ra) {
+                               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &reg_data);
+                               reg_data &= ~S2MU106_REG_PLUG_CTRL_RpRd_VCONN_MASK;
+                               reg_data |= (S2MU106_REG_PLUG_CTRL_RpRd_CC2_VCONN |
+                                               S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN);
+                               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, reg_data);
+                       }
+               }
+               if (cc2_val == USBPD_Rd) {
+                       if (cc1_val == USBPD_Ra) {
+                               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &reg_data);
+                               reg_data &= ~S2MU106_REG_PLUG_CTRL_RpRd_VCONN_MASK;
+                               reg_data |= (S2MU106_REG_PLUG_CTRL_RpRd_CC1_VCONN |
+                                               S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN);
+                               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, reg_data);
+                       }
+               }
+       } else if (val == USBPD_VCONN_OFF) {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &reg_data);
+                               reg_data &= ~S2MU106_REG_PLUG_CTRL_RpRd_VCONN_MASK;
+               reg_data |= S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, reg_data);
+       } else
+               return(-1);
+
+       pdic_data->vconn_source = val;
+       return 0;
+}
+
+static void s2mu106_usbpd_set_vconn_manual(struct s2mu106_usbpd_data *pdic_data, bool enable)
+{
+       u8 reg_data = 0;
+
+       s2mu106_usbpd_read_reg(pdic_data->i2c, S2MU106_REG_PLUG_CTRL_RpRd, &reg_data);
+       reg_data &= ~S2MU106_REG_PLUG_CTRL_RpRd_VCONN_MASK;
+
+       if (enable)
+               reg_data |= S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN;
+
+       s2mu106_usbpd_write_reg(pdic_data->i2c, S2MU106_REG_PLUG_CTRL_RpRd, reg_data);
+}
+
+static int s2mu106_get_vconn_source(void *_data, int *val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+
+       /* TODO
+               set s2mu106 pdic register control */
+
+       if (pdic_data->vconn_source != *val) {
+               dev_info(pdic_data->dev, "%s, vconn_source(%d) != gpio val(%d)\n",
+                               __func__, pdic_data->vconn_source, *val);
+               pdic_data->vconn_source = *val;
+       }
+
+       return 0;
+}
+
+/* val : sink(0) or source(1) */
+static int s2mu106_set_power_role(void *_data, int val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+
+       pr_info("%s, power_role(%d)\n", __func__, val);
+
+       if (val == USBPD_SINK) {
+               pdic_data->is_pr_swap = true;
+               s2mu106_assert_rd(data);
+               s2mu106_snk(pdic_data->i2c);
+       } else if (val == USBPD_SOURCE) {
+               pdic_data->is_pr_swap = true;
+               s2mu106_assert_rp(data);
+               s2mu106_src(pdic_data->i2c);
+       } else if (val == USBPD_DRP) {
+               pdic_data->is_pr_swap = false;
+               s2mu106_assert_drp(data);
+               return 0;
+       } else
+               return(-1);
+
+       pdic_data->power_role = val;
+       return 0;
+}
+
+static int s2mu106_get_power_role(void *_data, int *val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+
+       *val = pdic_data->power_role;
+
+       return 0;
+}
+
+static int s2mu106_set_data_role(void *_data, int val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 val_port, data_role;
+
+       /* DATA_ROLE (0x18[2])
+        * 0 : UFP
+        * 1 : DFP
+        */
+       if (val == USBPD_UFP) {
+               data_role = S2MU106_REG_MSG_DATA_ROLE_UFP;
+               s2mu106_ufp(i2c);
+       } else {/* (val == USBPD_DFP) */
+               data_role = S2MU106_REG_MSG_DATA_ROLE_DFP;
+               s2mu106_dfp(i2c);
+       }
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, &val_port);
+       val_port = (val_port & ~S2MU106_REG_MSG_DATA_ROLE_MASK) | data_role;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, val_port);
+
+       pdic_data->data_role = val;
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       process_dr_swap(pdic_data);
+#endif
+       return 0;
+}
+
+static int s2mu106_get_data_role(void *_data, int *val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       *val = pdic_data->data_role;
+       return 0;
+}
+
+static void s2mu106_get_vbus_short_check(void *_data, bool *val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+       *val = pdic_data->vbus_short;
+}
+
+static int s2mu106_set_check_msg_pass(void *_data, int val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+
+       dev_info(pdic_data->dev, "%s: check_msg_pass val(%d)\n", __func__, val);
+
+       pdic_data->check_msg_pass = val;
+
+       return 0;
+}
+#ifndef CONFIG_SEC_FACTORY
+static void s2mu106_usbpd_set_threshold(struct s2mu106_usbpd_data *pdic_data,
+                       CCIC_RP_RD_SEL port_sel, CCIC_THRESHOLD_SEL threshold_sel)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+
+       if (threshold_sel > S2MU106_THRESHOLD_MAX) {
+               dev_err(pdic_data->dev, "%s : threshold overflow!!\n", __func__);
+               return;
+       } else {
+               if (port_sel == PLUG_CTRL_RD)
+                       s2mu106_usbpd_write_reg(i2c,
+                               S2MU106_REG_PLUG_CTRL_SET_RD, threshold_sel);
+               else if (port_sel == PLUG_CTRL_RP)
+                       s2mu106_usbpd_write_reg(i2c,
+                               S2MU106_REG_PLUG_CTRL_SET_RP, threshold_sel);
+       }
+}
+
+static void s2mu106_usbpd_set_rp_scr_sel(struct s2mu106_usbpd_data *pdic_data,
+                                                       CCIC_RP_SCR_SEL scr_sel)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 data = 0;
+       pr_info("%s: scr_sel : (%d)\n", __func__, scr_sel);
+       switch (scr_sel) {
+       case PLUG_CTRL_RP80:
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+               data &= ~S2MU106_REG_PLUG_CTRL_RP_SEL_MASK;
+               data |= S2MU106_REG_PLUG_CTRL_RP80;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+               s2mu106_usbpd_set_threshold(pdic_data, PLUG_CTRL_RD,
+                                               S2MU106_THRESHOLD_214MV);
+               s2mu106_usbpd_set_threshold(pdic_data, PLUG_CTRL_RP,
+                                               S2MU106_THRESHOLD_1628MV);
+               break;
+       case PLUG_CTRL_RP180:
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+               data &= ~S2MU106_REG_PLUG_CTRL_RP_SEL_MASK;
+               data |= S2MU106_REG_PLUG_CTRL_RP180;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+               s2mu106_usbpd_set_threshold(pdic_data, PLUG_CTRL_RD,
+                                               S2MU106_THRESHOLD_428MV);
+               s2mu106_usbpd_set_threshold(pdic_data, PLUG_CTRL_RP,
+                                               S2MU106_THRESHOLD_2057MV);
+               break;
+       default:
+               break;
+       }
+       return;
+}
+#endif
+
+#ifdef CONFIG_CCIC_VDM
+int s2mu106_usbpd_check_vdm_msg(void *_data, u64 *val)
+{
+       struct usbpd_data *data = (struct usbpd_data *) _data;
+       int vdm_command = 0, vdm_type = 0;
+
+       dev_info(data->dev, "%s ++\n", __func__);
+       if (data->protocol_rx.msg_header.num_data_objs == 0) {
+               dev_info(data->dev, "%s data_obj null\n", __func__);
+               return 0;
+       }
+
+       if (data->protocol_rx.msg_header.msg_type != USBPD_Vendor_Defined) {
+               dev_info(data->dev, "%s msg type is wrong\n", __func__);
+               return 0;
+       }
+
+       vdm_command = data->protocol_rx.data_obj[0].structured_vdm.command;
+       vdm_type = data->protocol_rx.data_obj[0].structured_vdm.vdm_type;
+
+       if (vdm_type == Unstructured_VDM) {
+               dev_info(data->dev, "%s : uvdm msg received!\n", __func__);
+               *val |=  UVDM_MSG;
+               return 0;
+       }
+
+#if 0
+       switch (vdm_command) {
+       case DisplayPort_Status_Update:
+               *val |= VDM_DP_STATUS_UPDATE;
+               break;
+       case DisplayPort_Configure:
+               *val |= VDM_DP_CONFIGURE;
+               break;
+       default:
+               return 0;
+       }
+#endif
+       dev_info(data->dev, "%s: check vdm mag val(%d)\n", __func__, vdm_command);
+
+       return 0;
+}
+#endif
+
+static int s2mu106_usbpd_set_cc_control(struct s2mu106_usbpd_data  *pdic_data, int val)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 data = 0;
+
+       dev_info(pdic_data->dev, "%s, (%d)\n", __func__, val);
+       mutex_lock(&pdic_data->cc_mutex);
+
+       if (pdic_data->detach_valid)
+               goto out;
+
+       val = 1;
+
+       if (val) {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, &data);
+               data &= ~S2MU106_REG_PLUG_CTRL_CC_MANUAL_MASK;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, data);
+       } else {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, &data);
+               data &= ~S2MU106_REG_PLUG_CTRL_CC_MANUAL_MASK;
+               data |= S2MU106_REG_PLUG_CTRL_CC_MANUAL_EN;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC12, data);
+       }
+out:
+       mutex_unlock(&pdic_data->cc_mutex);
+
+       return 0;
+}
+
+static void s2mu106_dfp(struct i2c_client *i2c)
+{
+       u8 data;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, &data);
+       data |= S2MU106_REG_MSG_DATA_ROLE_MASK;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, data);
+}
+
+static void s2mu106_ufp(struct i2c_client *i2c)
+{
+       u8 data;
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, &data);
+       data &= ~S2MU106_REG_MSG_DATA_ROLE_MASK;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, data);
+}
+
+static void s2mu106_src(struct i2c_client *i2c)
+{
+       u8 data;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, &data);
+       data = (data & ~S2MU106_REG_MSG_POWER_ROLE_MASK) | S2MU106_REG_MSG_POWER_ROLE_SOURCE;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, data);
+}
+
+static void s2mu106_snk(struct i2c_client *i2c)
+{
+       u8 data;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, &data);
+       data = (data & ~S2MU106_REG_MSG_POWER_ROLE_MASK) | S2MU106_REG_MSG_POWER_ROLE_SINK;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_MSG, data);
+}
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+static void s2mu106_notify_pdic_rid(struct s2mu106_usbpd_data *pdic_data, int rid)
+{
+       pdic_data->is_factory_mode = false;
+       if (rid == RID_523K)
+               pdic_data->is_factory_mode = true;
+       /* rid */
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+                               IFCONN_NOTIFY_ID_RID, rid, NULL);
+
+       if (rid == REG_RID_523K || rid == REG_RID_619K || rid == REG_RID_OPEN) {
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                       IFCONN_NOTIFY_EVENT_ATTACH, NULL);
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB,
+                                       IFCONN_NOTIFY_ID_USB, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+               pdic_data->is_host = HOST_OFF;
+               pdic_data->is_client = CLIENT_OFF;
+       } else if (rid == REG_RID_301K) {
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                       IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP, NULL);
+               pdic_data->is_host = HOST_OFF;
+               pdic_data->is_client = CLIENT_ON;
+       }
+
+       dev_info(pdic_data->dev, "%s : attached rid state(%d)", __func__, rid);
+}
+#endif
+
+static void s2mu106_usbpd_check_rid(struct s2mu106_usbpd_data *pdic_data)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 rid;
+       int prev_rid = pdic_data->rid;
+
+       msleep(200);
+
+       if (pdic_data->check_rid_wa)
+               rid = REG_RID_619K;
+       else {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_ADC_STATUS, &rid);
+               rid = (rid & S2MU106_PDIC_RID_MASK) >> S2MU106_PDIC_RID_SHIFT;
+       }
+       dev_info(pdic_data->dev, "%s : attached rid state(%d)", __func__, rid);
+
+       if (rid) {
+               if (pdic_data->rid != rid) {
+                       pdic_data->rid = rid;
+                       if (prev_rid >= REG_RID_OPEN && rid >= REG_RID_OPEN)
+                               dev_err(pdic_data->dev,
+                                 "%s : rid is not changed, skip notify(%d)", __func__, rid);
+                       else
+                               s2mu106_notify_pdic_rid(pdic_data, rid);
+               }
+
+               if (rid >= REG_RID_MAX) {
+                       dev_err(pdic_data->dev, "%s : overflow rid value", __func__);
+                       return;
+               }
+       }
+}
+
+static int s2mu106_set_attach(struct s2mu106_usbpd_data *pdic_data, u8 mode)
+{
+       u8 data;
+       int ret = 0;
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+       data &= ~(S2MU106_REG_PLUG_CTRL_MODE_MASK | S2MU106_REG_PLUG_CTRL_RP_SEL_MASK);
+       data |= mode | S2MU106_REG_PLUG_CTRL_RP180;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &data);
+       data &= ~S2MU106_REG_LPM_EN;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_CTRL, data);
+
+       dev_info(dev, "%s s2mu106 force to attach\n", __func__);
+
+       return ret;
+}
+
+static int s2mu106_set_detach(struct s2mu106_usbpd_data *pdic_data, u8 mode)
+{
+       u8 data;
+       int ret = 0;
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+
+       if (mode == TYPE_C_ATTACH_DFP) {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &data);
+               data |= S2MU106_REG_PLUG_CTRL_RpRd_Rp_Source_Mode;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, data);
+       } else if (mode == TYPE_C_ATTACH_UFP) {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &data);
+               data |= S2MU106_REG_PLUG_CTRL_RpRd_Rd_Sink_Mode;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, data);
+       }
+
+       msleep(50);
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, S2MU106_RESET_REG_00);
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+       data &= ~(S2MU106_REG_PLUG_CTRL_MODE_MASK | S2MU106_REG_PLUG_CTRL_RP_SEL_MASK);
+       data |= S2MU106_REG_PLUG_CTRL_DFP | S2MU106_REG_PLUG_CTRL_RP0;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &data);
+       data |= S2MU106_REG_LPM_EN;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_CTRL, data);
+
+       dev_info(dev, "%s s2mu106 force to detach\n", __func__);
+
+       return ret;
+}
+
+int s2mu106_set_normal_mode(struct s2mu106_usbpd_data *pdic_data)
+{
+       u8 data;
+       u8 data_lpm;
+       int ret = 0;
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+       data &= ~(S2MU106_REG_PLUG_CTRL_MODE_MASK | S2MU106_REG_PLUG_CTRL_RP_SEL_MASK);
+       data |= S2MU106_REG_PLUG_CTRL_DRP | S2MU106_REG_PLUG_CTRL_RP180;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &data_lpm);
+       data_lpm &= ~S2MU106_REG_LPM_EN;
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_CTRL, data_lpm);
+
+       pdic_data->lpm_mode = false;
+
+       s2mu106_set_irq_enable(pdic_data, 0, 0,
+               S2MU106_REG_INT_STATUS2_MSG_SRC_CAP, ENABLED_INT_3,
+                               ENABLED_INT_4, 0);
+
+       dev_info(dev, "%s s2mu106 exit lpm mode\n", __func__);
+
+       return ret;
+}
+
+int s2mu106_usbpd_lpm_check(struct s2mu106_usbpd_data *pdic_data)
+{
+       u8 data_lpm = 0;
+       struct i2c_client *i2c = pdic_data->i2c;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &data_lpm);
+
+       return (data_lpm & S2MU106_REG_LPM_EN);
+}
+
+void s2mu106_usbpd_set_mode(struct s2mu106_usbpd_data *pdic_data,
+                                                                                                       CCIC_LPM_MODE_SEL mode)
+{
+       u8 data_lpm = 0;
+       struct i2c_client *i2c = pdic_data->i2c;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &data_lpm);
+       if (mode == PD_LPM_MODE)
+               data_lpm |= S2MU106_REG_LPM_EN;
+       else if (mode == PD_NORMAL_MODE)
+               data_lpm &= ~S2MU106_REG_LPM_EN;
+       else {
+               pr_info("%s mode val(%d) is invalid\n", __func__, mode);
+               return;
+       }
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_CTRL, data_lpm);
+}
+
+void s2mu106_usbpd_set_vbus_wakeup(struct s2mu106_usbpd_data *pdic_data,
+                                                                                                       CCIC_VBUS_WAKEUP_SEL sel)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 data = 0;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_TRIM, &data);
+       if (sel == VBUS_WAKEUP_ENABLE)
+               data &= ~S2MU106_REG_VBUS_WAKEUP_DIS;
+       else if (sel == VBUS_WAKEUP_DISABLE)
+               data |= S2MU106_REG_VBUS_WAKEUP_DIS;
+       else {
+               pr_info("%s sel val(%d) is invalid\n", __func__, sel);
+               return;
+       }
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_TRIM, data);
+}
+
+int s2mu106_get_plug_monitor(struct s2mu106_usbpd_data *pdic_data, u8 *data)
+{
+       u8 reg_val;
+       int ret = 0;
+       struct i2c_client *i2c = pdic_data->i2c;
+
+       if (&data[0] == NULL || &data[1] == NULL) {
+               pr_err("%s NULL point data\n", __func__);
+               return -1;
+       }
+
+       ret = s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON1, &reg_val);
+       if (ret < 0) {
+               pr_err("%s: S2MU106_REG_PLUG_MON1 Read err : %d\n",     __func__, ret);
+               return ret;
+       }
+
+       data[0] = reg_val & S2MU106_REG_CTRL_MON_CC1_MASK;
+       data[1] = (reg_val & S2MU106_REG_CTRL_MON_CC2_MASK) >> S2MU106_REG_CTRL_MON_CC2_SHIFT;
+       pr_info("%s, water cc mon cc1 : 0x%X, cc2 : 0x%X\n", __func__, data[0], data[1]);
+
+       return ret;
+}
+
+int s2mu106_set_lpm_mode(struct s2mu106_usbpd_data *pdic_data)
+{
+       u8 data, data_lpm;
+       int ret = 0;
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+       u8 intr[S2MU106_MAX_NUM_INT_STATUS] = {0};
+
+       pdic_data->lpm_mode = true;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+       data &= ~(S2MU106_REG_PLUG_CTRL_MODE_MASK | S2MU106_REG_PLUG_CTRL_RP_SEL_MASK);
+       data |= S2MU106_REG_PLUG_CTRL_DFP | S2MU106_REG_PLUG_CTRL_RP0;
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &data_lpm);
+       data_lpm |= S2MU106_REG_LPM_EN;
+
+       s2mu106_set_irq_enable(pdic_data, 0, 0, 0, 0, 0, 0);
+
+       ret = s2mu106_usbpd_bulk_read(i2c, S2MU106_REG_INT_STATUS0,
+                       S2MU106_MAX_NUM_INT_STATUS, intr);
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_CTRL, data_lpm);
+
+       if (pdic_data->detach_valid == false) {
+               s2mu106_usbpd_detach_init(pdic_data);
+               s2mu106_usbpd_notify_detach(pdic_data);
+       }
+
+       dev_info(dev, "%s s2mu106 enter lpm mode\n", __func__);
+
+       return ret;
+}
+
+void s2mu106_set_water_detect_pre_cond(struct s2mu106_usbpd_data *pdic_data)
+{
+       int i;
+       u8 cc_val[2] = {0,};
+
+       s2mu106_set_normal_mode(pdic_data);
+       mdelay(10);
+
+       for (i = 0; i < 14; i++) {
+               if (s2mu106_get_plug_monitor(pdic_data, cc_val) < 0) {
+                       pr_info("%s abnormal", __func__);
+                       mdelay(10);
+               } else {
+                       if (IS_CC_RP(cc_val[0], cc_val[1]))
+                               break;
+                       else {
+                               pr_info("%s Not Rp yet. ", __func__);
+                               mdelay(10);
+                       }
+               }
+       }
+}
+
+void s2mu106_set_water_1st_detect(struct s2mu106_usbpd_data *pdic_data)
+{
+       u8 data, data_lpm;
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+
+       pdic_data->lpm_mode = true;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RP, S2MU106_THRESHOLD_MAX);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+       data &= ~(S2MU106_REG_PLUG_CTRL_MODE_MASK | S2MU106_REG_PLUG_CTRL_RP_SEL_MASK);
+       data |= S2MU106_REG_PLUG_CTRL_DFP | S2MU106_REG_PLUG_CTRL_RP80
+                       | S2MU106_REG_PLUG_CTRL_DETECT_BAT_DISABLE_MASK
+                       | S2MU106_REG_PLUG_CTRL_DETECT_OCP_DISABLE_MASK;
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &data_lpm);
+       data_lpm |= S2MU106_REG_LPM_EN;
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_CTRL, data_lpm);
+
+       s2mu106_set_irq_enable(pdic_data, 0, 0, 0, 0, 0, 0);
+
+       usleep_range(500, 900);
+
+       data &= ~(S2MU106_REG_PLUG_CTRL_MODE_MASK | S2MU106_REG_PLUG_CTRL_RP_SEL_MASK);
+       data |= S2MU106_REG_PLUG_CTRL_DFP | S2MU106_REG_PLUG_CTRL_RP0;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+
+       dev_info(dev, "%s s2mu106 enter water chk lpm mode\n", __func__);
+}
+
+static bool s2mu106_is_water_detected_2nd_seq(struct s2mu106_usbpd_data *pdic_data, u8 *cc_val)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 cc_chk[2] = {0,};
+
+       if (cc_val[0] == USBPD_Rp)
+               cc_chk[0] = 1;
+       if (cc_val[1] == USBPD_Rp)
+               cc_chk[1] = 1;
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RD,
+                                                       S2MU106_THRESHOLD_214MV);
+       s2mu106_set_lpm_mode(pdic_data);
+       s2mu106_usbpd_update_bit(i2c, S2MU106_REG_PD_CTRL,
+                                               S2MU106_REG_LPM_EN, 0, 0);
+       msleep(300);
+
+       if (s2mu106_get_plug_monitor(pdic_data, cc_val) < 0) {
+               pr_err("%s Failed to get the plug monitor.\n", __func__);
+               return false;
+       }
+
+       /* Rd is detected due to the water CAPACITOR. */
+       if (((cc_chk[0] && !cc_chk[1]) && (cc_val[0] == USBPD_Rd)) ||
+               ((cc_chk[1] && !cc_chk[0]) && (cc_val[1] == USBPD_Rd)) ||
+               ((cc_chk[0] && cc_chk[1]) && ((cc_val[0] == USBPD_Rd) && (cc_val[1] == USBPD_Rd)))) {
+                       return true;
+       }
+
+       return false;
+}
+
+static void _S2MU106_PDIC_enter_to_water(struct s2mu106_usbpd_data *pdic_data)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+#if defined(CONFIG_USB_HW_PARAM) && !defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       struct otg_notify *o_notify = get_otg_notify();
+#endif
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+       ccic_event_work(pdic_data,
+               CCIC_NOTIFY_DEV_MUIC, CCIC_NOTIFY_ID_WATER, CCIC_NOTIFY_ATTACH, 0);
+#endif
+       pdic_data->is_water_detect = true;
+       pdic_data->water_detect_cnt = 0;
+       s2mu106_set_lpm_mode(pdic_data);
+       s2mu106_usbpd_update_bit(i2c, S2MU106_REG_PD_CTRL,
+                                                                       S2MU106_REG_LPM_EN, 0, 0);
+#if defined(CONFIG_USB_HW_PARAM) && !defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       if (o_notify)
+               inc_hw_param(o_notify, USB_CCIC_WATER_INT_COUNT);
+#endif
+}
+
+static void S2MU106_PDIC_water_detect_handler(struct work_struct *work)
+{
+       struct s2mu106_usbpd_data *pdic_data =
+               container_of(work, struct s2mu106_usbpd_data, water_detect_handler.work);
+       struct i2c_client *i2c = pdic_data->i2c;
+
+       u8 cc_val[2] = {0,};
+
+       pr_info("%s enter", __func__);
+       mutex_lock(&pdic_data->_mutex);
+
+       /*
+        * Cancel the detect handler,
+        * in case the muic notifies cable attach or dry signal,
+        * or the water chk cnt is over,
+        * or ccic already detected the water.
+        */
+       if (!pdic_data->is_muic_water_detect
+               || pdic_data->water_detect_cnt > WATER_CHK_RETRY_CNT
+               || pdic_data->is_water_detect) {
+               pr_info("%s: detect handler is canceled", __func__);
+               goto WATER_OUT;
+       }
+
+       s2mu106_set_water_detect_pre_cond(pdic_data);
+       s2mu106_set_water_1st_detect(pdic_data);
+       msleep(400);
+
+       if (s2mu106_get_plug_monitor(pdic_data, cc_val) < 0) {
+               pr_err("%s Failed to get the plug monitor.\n", __func__);
+               goto WATER_MODE_OUT;
+       }
+
+       if (IS_CC_WATER(cc_val[0], cc_val[1]))  {
+               pr_info("%s, water is detected, cc1 : 0x%X, cc2 : 0x%X\n",
+                               __func__, cc_val[0], cc_val[1]);
+               _S2MU106_PDIC_enter_to_water(pdic_data);
+               goto WATER_MODE_OUT;
+       } else {
+               pr_info("%s, 1st chk is not water, cc1 : 0x%X, cc2 : 0x%X\n",
+                                                               __func__, cc_val[0], cc_val[1]);
+               if (s2mu106_is_water_detected_2nd_seq(pdic_data, cc_val)) {
+                       pr_info("%s, 2nd seq, water is detected, cc1 : 0x%X, cc2 : 0x%X\n",
+                                       __func__, cc_val[0], cc_val[1]);
+                       _S2MU106_PDIC_enter_to_water(pdic_data);
+                       goto WATER_MODE_OUT;
+               }
+
+               pr_info("%s, 2nd chk : not water, cc1 : 0x%X, cc2 : 0x%X\n",
+                                                               __func__, cc_val[0], cc_val[1]);
+
+               if (pdic_data->water_detect_cnt++ >= WATER_CHK_RETRY_CNT) {
+                       pdic_data->is_water_detect = false;
+                       pdic_data->water_detect_cnt = 0;
+#if defined(CONFIG_CCIC_NOTIFIER)
+                       ccic_event_work(pdic_data,
+                               CCIC_NOTIFY_DEV_MUIC, CCIC_NOTIFY_ID_WATER, CCIC_NOTIFY_DETACH, 0);
+#endif
+               } else {
+                       /*
+                        * Retry the cc check,
+                        * in case of invalid status.
+                        * (200ms interval + 175ms check duration) * 5 times
+                        */
+                       cancel_delayed_work(&pdic_data->water_detect_handler);
+                       schedule_delayed_work(&pdic_data->water_detect_handler,
+                                                       msecs_to_jiffies(S2MU106_WATER_CHK_INTERVAL_TIME));
+               }
+       }
+WATER_MODE_OUT:
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RD,
+                                                               S2MU106_THRESHOLD_428MV);
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RP,
+                                                               S2MU106_THRESHOLD_2057MV);
+WATER_OUT:
+       mutex_unlock(&pdic_data->_mutex);
+       return;
+}
+
+static void S2MU106_PDIC_water_dry_handler(struct work_struct *work)
+{
+       struct s2mu106_usbpd_data *pdic_data =
+               container_of(work, struct s2mu106_usbpd_data, water_dry_handler.work);
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 cc_val[2] = {0,};
+
+       pr_info("%s enter", __func__);
+       mutex_lock(&pdic_data->_mutex);
+
+       s2mu106_set_water_detect_pre_cond(pdic_data);
+       s2mu106_set_water_1st_detect(pdic_data);
+       msleep(400);
+
+       if (s2mu106_get_plug_monitor(pdic_data, cc_val) < 0) {
+               pr_err("%s Failed to get the plug monitor.\n", __func__);
+       }
+
+       if (IS_CC_RP(cc_val[0], cc_val[1]))     {
+               pr_info("%s, 1st, water DRY is detected, cc1 : 0x%X, cc2 : 0x%X\n",
+                               __func__, cc_val[0], cc_val[1]);
+
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RD,
+                                                                       S2MU106_THRESHOLD_428MV);
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RP,
+                                                                       S2MU106_THRESHOLD_2057MV);
+#if defined(CONFIG_CCIC_NOTIFIER)
+               ccic_event_work(pdic_data,
+                       CCIC_NOTIFY_DEV_MUIC, CCIC_NOTIFY_ID_WATER, CCIC_NOTIFY_DETACH, 0);
+#endif
+       } else {
+               pr_info("%s, It is not DRIED yet, cc1 : 0x%X, cc2 : 0x%X\n",
+                                                               __func__, cc_val[0], cc_val[1]);
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+               ccic_event_work(pdic_data,
+                       CCIC_NOTIFY_DEV_MUIC, CCIC_NOTIFY_ID_WATER, CCIC_NOTIFY_ATTACH, 0);
+#endif
+               s2mu106_set_lpm_mode(pdic_data);
+               s2mu106_usbpd_update_bit(i2c, S2MU106_REG_PD_CTRL,
+                                                                               S2MU106_REG_LPM_EN, 0, 0);
+       }
+
+       mutex_unlock(&pdic_data->_mutex);
+       return;
+}
+
+static void s2mu106_usbpd_otg_attach(struct s2mu106_usbpd_data *pdic_data)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+       
+       /* otg */
+       pdic_data->is_host = HOST_ON;
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+       pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_SRC;
+#endif
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       /* USB */
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                                               IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP, NULL);
+#endif
+       /* add to turn on external 5V */
+       vbus_turn_on_ctrl(pdic_data, VBUS_ON);
+
+       usbpd_manager_acc_handler_cancel(dev);
+}
+
+#if defined(CONFIG_MUIC_NOTIFIER)
+static int type3_handle_notification(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+#if defined(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 s2mu106_usbpd_data *pdic_data =
+               container_of(nb, struct s2mu106_usbpd_data,
+                            type3_nb);
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 reg_data = 0;
+
+#if (defined(CONFIG_USB_HW_PARAM) && !defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)) || \
+       (!defined(CONFIG_SEC_FACTORY) && defined(CONFIG_USB_HOST_NOTIFY))
+       struct otg_notify *o_notify = get_otg_notify();
+#endif
+       mutex_lock(&pdic_data->lpm_mutex);
+       pr_info("%s action:%d, attached_dev:%d, lpm:%d, pdic_data->is_otg_vboost:%d, pdic_data->is_otg_reboost:%d\n",
+               __func__, (int)action, (int)attached_dev, pdic_data->lpm_mode,
+               (int)pdic_data->is_otg_vboost, (int)pdic_data->is_otg_reboost);
+
+       if ((action == MUIC_PDIC_NOTIFY_CMD_ATTACH) &&
+               (attached_dev == ATTACHED_DEV_TYPE3_MUIC)) {
+               pdic_data->is_muic_water_detect = false;
+               pdic_data->water_detect_cnt = 0;
+               if (pdic_data->lpm_mode) {
+                       pr_info("%s try to exit lpm mode-->\n", __func__);
+                       s2mu106_set_normal_mode(pdic_data);
+                       pr_info("%s after exit lpm mode<--\n", __func__);
+               }
+       } else if ((action == MUIC_PDIC_NOTIFY_CMD_ATTACH) &&
+               attached_dev == ATTACHED_DEV_CHK_WATER_REQ) {
+               pr_info("%s, ATTACH : MUIC REQUESTED WATER CHECK\n", __func__);
+               s2mu106_usbpd_set_vconn_manual(pdic_data, true);
+               pdic_data->is_muic_water_detect = true;
+               pdic_data->water_detect_cnt = 0;
+               pdic_data->is_water_detect = false;
+               cancel_delayed_work(&pdic_data->water_detect_handler);
+               schedule_delayed_work(&pdic_data->water_detect_handler, msecs_to_jiffies(100));
+       } else if ((action == MUIC_PDIC_NOTIFY_CMD_ATTACH) &&
+               attached_dev == ATTACHED_DEV_CHK_WATER_DRY_REQ) {
+               pr_info("%s, ATTACH : MUIC REQUESTED WATER DRY CHECK\n", __func__);
+               cancel_delayed_work(&pdic_data->water_dry_handler);
+               schedule_delayed_work(&pdic_data->water_dry_handler, msecs_to_jiffies(100));
+       } else if ((action == MUIC_PDIC_NOTIFY_CMD_ATTACH) &&
+               attached_dev == ATTACHED_DEV_OTG_MUIC) {
+               s2mu106_usbpd_otg_attach(pdic_data);
+       } else if ((action == MUIC_PDIC_NOTIFY_CMD_DETACH) &&
+               attached_dev == ATTACHED_DEV_UNDEFINED_RANGE_MUIC) {
+               pr_info("%s, DETACH : ATTACHED_DEV_UNDEFINED_RANGE_MUIC(Water DRY)\n", __func__);
+               pdic_data->is_muic_water_detect = false;
+               pdic_data->water_detect_cnt = 0;
+               pdic_data->is_water_detect = false;
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &reg_data);
+               reg_data |= S2MU106_REG_LPM_EN;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_CTRL, reg_data);
+#if defined(CONFIG_USB_HW_PARAM) && !defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+               if (o_notify)
+                       inc_hw_param(o_notify, USB_CCIC_DRY_INT_COUNT);
+#endif
+#if defined(CONFIG_CCIC_NOTIFIER)
+               ccic_event_work(pdic_data,
+                       CCIC_NOTIFY_DEV_MUIC, CCIC_NOTIFY_ID_WATER, CCIC_NOTIFY_DETACH, 0);
+#endif
+       } else if (action == MUIC_PDIC_NOTIFY_CMD_DETACH) {
+               if (!pdic_data->lpm_mode) {
+                       pr_info("%s try to enter lpm mode-->\n", __func__);
+                       s2mu106_set_lpm_mode(pdic_data);
+                       pr_info("%s after enter lpm mode<--\n", __func__);
+               }
+       }
+#if !defined(CONFIG_SEC_FACTORY) && defined(CONFIG_USB_HOST_NOTIFY)
+       else if ((action == MUIC_PDIC_NOTIFY_CMD_ATTACH)
+                       && (attached_dev == ATTACHED_DEV_CHECK_OCP)
+                       && pdic_data->is_otg_vboost
+                       && pdic_data->data_role_dual ==
+                                                               IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP) {
+               if (o_notify) {
+                       if (is_blocked(o_notify, NOTIFY_BLOCK_TYPE_HOST)) {
+                               pr_info("%s, upsm mode, skip OCP handling\n", __func__);
+                               goto EOH;
+                       }
+               }
+               if (pdic_data->is_otg_reboost) {
+                       /* todo : over current event to platform */
+                       pr_info("%s, CHECK_OCP, Can't afford it(OVERCURRENT)\n", __func__);
+                       if (o_notify)
+                               send_otg_notify(o_notify, NOTIFY_EVENT_OVERCURRENT, 0);
+                       goto EOH;
+               }
+               ccic_event_work(pdic_data,
+                       CCIC_NOTIFY_DEV_MUIC, CCIC_NOTIFY_ID_ATTACH, 1/*attach*/, 1/*rprd*/);
+
+               pr_info("%s, CHECK_OCP, start OCP W/A\n", __func__);
+               pdic_data->is_otg_reboost = true;
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC_HOLD, &reg_data);
+               reg_data |= S2MU106_REG_PLUG_CTRL_CC_HOLD_BIT;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC_HOLD, reg_data);
+
+               s2mu106_usbpd_set_rp_scr_sel(pdic_data, PLUG_CTRL_RP80);
+               vbus_turn_on_ctrl(pdic_data, VBUS_OFF);
+               vbus_turn_on_ctrl(pdic_data, VBUS_ON);
+
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_CC_HOLD, &reg_data);
+               reg_data &= ~S2MU106_REG_PLUG_CTRL_CC_HOLD_BIT;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_CC_HOLD, reg_data);
+       }
+EOH:
+#endif
+       mutex_unlock(&pdic_data->lpm_mutex);
+
+       return 0;
+}
+#endif
+
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+static void s2mu106_usbpd_control_cc12_rd(struct s2mu106_usbpd_data *pdic_data,
+                                                                       bool enable)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 data = 0;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+       dev_info(pdic_data->dev, "%s, enable : %s current reg value(%x)\n", __func__,
+                                       enable ? "ON" : "OFF", data);
+
+       if (enable) {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+               data &= ~S2MU106_REG_PLUG_CTRL_MODE_MASK;
+               data |= S2MU106_REG_PLUG_CTRL_UFP;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+       } else {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+               data &= ~S2MU106_REG_PLUG_CTRL_MODE_MASK;
+               data |= S2MU106_REG_PLUG_CTRL_DRP;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+       }
+}
+#endif
+
+static void s2mu106_usbpd_prevent_watchdog_reset(
+                        struct s2mu106_usbpd_data *pdic_data)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 val = 0;
+
+       mutex_lock(&pdic_data->lpm_mutex);
+       wake_lock(&pdic_data->wake_lock);
+       if (!pdic_data->lpm_mode) {
+               if (s2mu106_usbpd_lpm_check(pdic_data) == 0) {
+                       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_INT_STATUS2, &val);
+                       s2mu106_usbpd_set_vbus_wakeup(pdic_data, VBUS_WAKEUP_DISABLE);
+                       pr_info("%s force to lpm mode\n", __func__);
+                       s2mu106_usbpd_set_mode(pdic_data, PD_LPM_MODE);
+                       /* enable wakeup to check prevent function */
+                       s2mu106_set_irq_enable(pdic_data, ENABLED_INT_0, ENABLED_INT_1,
+                                               ENABLED_INT_2_WAKEUP, ENABLED_INT_3, ENABLED_INT_4,
+                                                                                                                       ENABLED_INT_5);
+                       s2mu106_usbpd_set_vbus_wakeup(pdic_data, VBUS_WAKEUP_ENABLE);
+                       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_INT_STATUS2, &val);
+                       if (val & S2MU106_REG_INT_STATUS2_WAKEUP)
+                               pr_info("%s auto wakeup success\n", __func__);
+                       else
+                               s2mu106_usbpd_set_mode(pdic_data, PD_NORMAL_MODE);
+                               s2mu106_set_irq_enable(pdic_data, ENABLED_INT_0, ENABLED_INT_1,
+                                                                       ENABLED_INT_2, ENABLED_INT_3, ENABLED_INT_4,
+                                                                                                                               ENABLED_INT_5);
+               }
+       }
+       wake_unlock(&pdic_data->wake_lock);
+       mutex_unlock(&pdic_data->lpm_mutex);
+}
+
+static void s2mu106_vbus_short_check(struct s2mu106_usbpd_data *pdic_data)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = pdic_data->dev;
+       u8 val = 0;
+       u8 cc1_val = 0, cc2_val = 0;
+       u8 rp_currentlvl = 0;
+
+       if (pdic_data->vbus_short_check)
+               return;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_FSM_MON, &val);
+
+       cc1_val = val & S2MU106_REG_CTRL_MON_CC1_MASK;
+       cc2_val = (val & S2MU106_REG_CTRL_MON_CC2_MASK) >> S2MU106_REG_CTRL_MON_CC2_SHIFT;
+
+       dev_info(dev, "%s, 10k check : cc1_val(%x), cc2_val(%x)\n",
+                                       __func__, cc1_val, cc2_val);
+
+       if (cc1_val == USBPD_10k || cc2_val == USBPD_10k)
+               rp_currentlvl = RP_CURRENT_LEVEL3;
+       else if (cc1_val == USBPD_22k || cc2_val == USBPD_22k)
+               rp_currentlvl = RP_CURRENT_LEVEL2;
+       else if (cc1_val == USBPD_56k || cc2_val == USBPD_56k)
+               rp_currentlvl = RP_CURRENT_LEVEL_DEFAULT;
+
+#ifdef CONFIG_IFCONN_NOTIFIER
+       pd_noti.sink_status.rp_currentlvl = rp_currentlvl;
+       pd_noti.event = IFCONN_NOTIFY_EVENT_ATTACH;
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_BATTERY,
+                                               IFCONN_NOTIFY_ID_POWER_STATUS,
+                                               IFCONN_NOTIFY_EVENT_ATTACH, &pd_noti);
+#endif
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON1, &val);
+
+       cc1_val = val & S2MU106_REG_CTRL_MON_CC1_MASK;
+       cc2_val = (val & S2MU106_REG_CTRL_MON_CC2_MASK) >> S2MU106_REG_CTRL_MON_CC2_SHIFT;
+
+       dev_info(dev, "%s, vbus short check : cc1_val(%x), cc2_val(%x)\n",
+                                       __func__, cc1_val, cc2_val);
+
+       if (cc1_val == USBPD_Rp || cc2_val == USBPD_Rp) {
+               pdic_data->vbus_short = true;
+       } else {
+               pdic_data->vbus_short = false;
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+                       IFCONN_NOTIFY_ID_TA, IFCONN_NOTIFY_EVENT_ATTACH, NULL);
+       }
+
+       pdic_data->vbus_short_check = true;
+}
+
+static void s2mu106_usbpd_detach_init(struct s2mu106_usbpd_data *pdic_data)
+{
+       struct device *dev = pdic_data->dev;
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       struct i2c_client *i2c = pdic_data->i2c;
+       int ret = 0;
+
+       dev_info(dev, "%s\n", __func__);
+
+       s2mu106_usbpd_set_cc_control(pdic_data, USBPD_CC_OFF);
+
+       usbpd_manager_plug_detach(dev, 0);
+       pdic_data->status_reg = 0;
+       usbpd_reinit(dev);
+       /* for ccic hw detect */
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_MSG_SEND_CON, S2MU106_RESET_REG_00);
+       pdic_data->rid = REG_RID_MAX;
+       pdic_data->check_rid_wa = false;
+       pdic_data->detach_valid = true;
+       pdic_data->is_factory_mode = false;
+       pdic_data->is_pr_swap = false;
+       pdic_data->vbus_short_check = false;
+       pdic_data->vbus_short = false;
+       if (pdic_data->regulator_en)
+               ret = regulator_disable(pdic_data->regulator);
+#ifdef CONFIG_BATTERY_SAMSUNG
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       pd_noti.sink_status.current_pdo_num = 0;
+       pd_noti.sink_status.selected_pdo_num = 0;
+       pd_noti.sink_status.rp_currentlvl = RP_CURRENT_LEVEL_NONE;
+#endif
+#endif
+       s2mu106_usbpd_reg_init(pdic_data);
+       s2mu106_set_vconn_source(pd_data, USBPD_VCONN_OFF);
+}
+
+static void s2mu106_usbpd_notify_detach(struct s2mu106_usbpd_data *pdic_data)
+{
+       struct device *dev = pdic_data->dev;
+       struct usbpd_data *pd_data = dev_get_drvdata(pdic_data->dev);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       if (manager->dp_is_connect == 1)
+               usbpd_dp_detach(pd_data);
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       /* MUIC */
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC, IFCONN_NOTIFY_ID_ATTACH,
+                                                               IFCONN_NOTIFY_EVENT_DETACH, NULL);
+
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC, IFCONN_NOTIFY_ID_RID,
+                                                               IFCONN_NOTIFY_EVENT_DETACH, NULL);
+
+       if (pdic_data->is_host > HOST_OFF || pdic_data->is_client > CLIENT_OFF) {
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+               if (pdic_data->is_host > HOST_OFF ||
+                       pdic_data->power_role_dual == DUAL_ROLE_PROP_PR_SRC) {
+#else
+               if (pdic_data->is_host > HOST_OFF) {
+#endif
+                       vbus_turn_on_ctrl(pdic_data, VBUS_OFF);
+               }
+               usbpd_manager_acc_detach(dev);
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+               pr_info("%s, data_role (%d)\n", __func__, pdic_data->data_role_dual);
+               if (pdic_data->data_role_dual == IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP &&
+                       !pdic_data->try_state_change) {
+                       s2mu106_usbpd_control_cc12_rd(pdic_data, true);
+                       msleep(S2MU106_WAIT_RD_DETACH_DELAY_MS);
+                       s2mu106_usbpd_control_cc12_rd(pdic_data, false);
+               }
+#endif
+               /* usb or otg */
+               dev_info(dev, "%s %d: is_host = %d, is_client = %d\n", __func__,
+                               __LINE__, pdic_data->is_host, pdic_data->is_client);
+               pdic_data->is_host = HOST_OFF;
+               pdic_data->is_client = CLIENT_OFF;
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+               pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_NONE;
+#endif
+               /* USB */
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                                                               IFCONN_NOTIFY_EVENT_DETACH, NULL);
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+               if (!pdic_data->try_state_change)
+                       s2mu106_rprd_mode_change(pdic_data, TYPE_C_ATTACH_DRP);
+#else
+       s2mu106_rprd_mode_change(pdic_data, TYPE_C_ATTACH_DRP);
+#endif
+       }
+#else
+       usbpd_manager_plug_detach(dev, 1);
+#endif
+}
+#ifdef CONFIG_CCIC_TRY_SNK
+static void s2mu106_usbpd_try_snk(struct s2mu106_usbpd_data *pdic_data)
+{
+       struct device *dev = pdic_data->dev;
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 data;
+       u8 intr[S2MU106_MAX_NUM_INT_STATUS] = {0};
+
+       dev_info(dev, "%s\n", __func__);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+       data &= ~ S2MU106_REG_PLUG_CTRL_MODE_MASK;
+       data |= S2MU106_REG_PLUG_CTRL_UFP;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+
+       msleep(250);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON2, &data);
+       if ((data & S2MU106_PR_MASK) != S2MU106_PDIC_SINK) {
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+               data &= ~ S2MU106_REG_PLUG_CTRL_MODE_MASK;
+               data |= S2MU106_REG_PLUG_CTRL_DFP;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+
+               msleep(200);
+       }
+
+       s2mu106_usbpd_bulk_read(i2c, S2MU106_REG_INT_STATUS0,
+                                               S2MU106_MAX_NUM_INT_STATUS, intr);
+}
+#endif
+static void s2mu106_usbpd_check_host(struct s2mu106_usbpd_data *pdic_data,
+                                                       CCIC_HOST_REASON host)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(pdic_data->dev);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       if (host == HOST_ON && pdic_data->is_host == HOST_ON) {
+               if (manager->dp_is_connect == 1)
+                       usbpd_dp_detach(pd_data);
+
+               dev_info(pdic_data->dev, "%s %d: turn off host\n", __func__, __LINE__);
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+                               IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+               pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_NONE;
+#endif
+               /* add to turn off external 5V */
+               vbus_turn_on_ctrl(pdic_data, VBUS_OFF);
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                                                               IFCONN_NOTIFY_EVENT_DETACH, NULL);
+               pdic_data->is_host = HOST_OFF;
+               msleep(300);
+       } else if (host == HOST_OFF && pdic_data->is_host == HOST_OFF) {
+               /* muic */
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+                               IFCONN_NOTIFY_ID_OTG, IFCONN_NOTIFY_EVENT_ATTACH, NULL);
+               s2mu106_usbpd_otg_attach(pdic_data);
+       }
+}
+
+static void s2mu106_usbpd_check_client(struct s2mu106_usbpd_data *pdic_data,
+                                                       CCIC_DEVICE_REASON client)
+{
+       if (client == CLIENT_ON && pdic_data->is_client == CLIENT_ON) {
+               dev_info(pdic_data->dev, "%s %d: turn off client\n", __func__, __LINE__);
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+                               IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+               pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_NONE;
+#endif
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB,
+                               IFCONN_NOTIFY_ID_USB, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+               pdic_data->is_client = CLIENT_OFF;
+       }
+}
+
+static int s2mu106_check_port_detect(struct s2mu106_usbpd_data *pdic_data)
+{
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       u8 data, val;
+       u8 cc1_val = 0, cc2_val = 0;
+       int ret = 0;
+
+       ret = s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON2, &data);
+       if (ret < 0)
+               dev_err(dev, "%s, i2c read PLUG_MON2 error\n", __func__);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON1, &val);
+
+       cc1_val = val & S2MU106_REG_CTRL_MON_CC1_MASK;
+       cc2_val = (val & S2MU106_REG_CTRL_MON_CC2_MASK) >> S2MU106_REG_CTRL_MON_CC2_SHIFT;
+
+       dev_info(dev, "%s, attach cc pin check cc1_val(%x), cc2_val(%x)\n",
+                                       __func__, cc1_val, cc2_val);
+
+#ifdef CONFIG_CCIC_DP
+       if (cc1_val == USBPD_Rd)
+               gpio_direction_output(pdic_data->usb_sw_sel, 1);
+       else if (cc2_val == USBPD_Rd)
+               gpio_direction_output(pdic_data->usb_sw_sel, 0);
+#endif
+#ifdef CONFIG_CCIC_TRY_SNK
+       if ((data & S2MU106_PR_MASK) == S2MU106_PDIC_SOURCE) {
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+               if (!pdic_data->try_state_change) {
+                       s2mu106_usbpd_try_snk(pdic_data);
+                       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON2, &data);
+               }
+#else
+               s2mu106_usbpd_try_snk(pdic_data);
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_MON2, &data);
+#endif
+       }
+#endif
+       if ((data & S2MU106_PR_MASK) == S2MU106_PDIC_SINK) {
+               dev_info(dev, "SINK\n");
+               pdic_data->power_role = PDIC_SINK;
+               pdic_data->data_role = USBPD_UFP;
+               s2mu106_snk(i2c);
+               s2mu106_ufp(i2c);
+               s2mu106_usbpd_prevent_watchdog_reset(pdic_data);
+               usbpd_policy_reset(pd_data, PLUG_EVENT);
+#if defined(CONFIG_IFCONN_NOTIFIER)
+               dev_info(&i2c->dev, "%s %d: is_host = %d, is_client = %d\n", __func__,
+                                       __LINE__, pdic_data->is_host, pdic_data->is_client);
+               if (pdic_data->regulator_en) {
+                       ret = regulator_enable(pdic_data->regulator);
+                       if (ret)
+                               dev_err(&i2c->dev, "Failed to enable vconn LDO: %d\n", ret);
+               }
+
+               s2mu106_usbpd_check_host(pdic_data, HOST_ON);
+               /* muic */
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+                               IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_ATTACH, NULL);
+               if (!(pdic_data->rid == REG_RID_523K || pdic_data->rid == REG_RID_619K)) {
+                       if (pdic_data->is_client == CLIENT_OFF && pdic_data->is_host == HOST_OFF) {
+                               /* usb */
+                               pdic_data->is_client = CLIENT_ON;
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+                               pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_SNK;
+#endif
+                               ifconn_event_work(pdic_data,
+                                               IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB,
+                                                               IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP, NULL);
+                       }
+               }
+#endif
+               s2mu106_vbus_short_check(pdic_data);
+       } else if ((data & S2MU106_PR_MASK) == S2MU106_PDIC_SOURCE) {
+               dev_info(dev, "SOURCE\n");
+               pdic_data->power_role = PDIC_SOURCE;
+               pdic_data->data_role = USBPD_DFP;
+               s2mu106_dfp(i2c);
+               s2mu106_src(i2c);
+               usbpd_policy_reset(pd_data, PLUG_EVENT);
+#if defined(CONFIG_IFCONN_NOTIFIER)
+               dev_info(&i2c->dev, "%s %d: is_host = %d, is_client = %d\n", __func__,
+                                       __LINE__, pdic_data->is_host, pdic_data->is_client);
+               s2mu106_usbpd_check_client(pdic_data, CLIENT_ON);
+               s2mu106_usbpd_check_host(pdic_data, HOST_OFF);
+#endif
+               if (pdic_data->regulator_en) {
+                       ret = regulator_enable(pdic_data->regulator);
+                       if (ret)
+                               dev_err(&i2c->dev, "Failed to enable vconn LDO: %d\n", ret);
+               }
+
+               s2mu106_set_vconn_source(pd_data, USBPD_VCONN_ON);
+
+               msleep(tTypeCSinkWaitCap); /* dont over 310~620ms(tTypeCSinkWaitCap) */
+       } else {
+               dev_err(dev, "%s, PLUG Error\n", __func__);
+#ifdef CONFIG_CCIC_TRY_SNK
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
+               data &= ~(S2MU106_REG_PLUG_CTRL_MODE_MASK | S2MU106_REG_PLUG_CTRL_RP_SEL_MASK);
+               data |= S2MU106_REG_PLUG_CTRL_DRP | S2MU106_REG_PLUG_CTRL_RP180;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
+#endif
+               return -1;
+       }
+
+       pdic_data->detach_valid = false;
+
+       s2mu106_set_irq_enable(pdic_data, ENABLED_INT_0, ENABLED_INT_1,
+                               ENABLED_INT_2, ENABLED_INT_3, ENABLED_INT_4, ENABLED_INT_5);
+
+       return ret;
+}
+
+#if defined(CONFIG_SEC_FACTORY)
+static int s2mu106_usbpd_check_619k(struct s2mu106_usbpd_data *pdic_data)
+{
+       u8 rid = 0;
+
+       if (pdic_data->rid != REG_RID_619K)
+               return false;
+
+       msleep(250);
+       s2mu106_usbpd_read_reg(pdic_data->i2c, S2MU106_REG_ADC_STATUS, &rid);
+       rid = (rid & S2MU106_PDIC_RID_MASK) >> S2MU106_PDIC_RID_SHIFT;
+       dev_info(pdic_data->dev, "%s %d: Detached, check if still 619K? => 0x%X\n",
+                                       __func__, __LINE__, rid);
+
+       if (rid == REG_RID_619K)
+               return true;
+       return false;
+}
+#endif
+
+#ifndef CONFIG_SEC_FACTORY
+static void s2mu106_usbpd_check_reboost(struct s2mu106_usbpd_data *pdic_data)
+{
+       if (!pdic_data->is_otg_reboost)
+               return;
+
+       dev_info(pdic_data->dev, "%s %d: Detached, go back to 180uA\n",
+                                       __func__, __LINE__);
+       s2mu106_usbpd_set_rp_scr_sel(pdic_data, PLUG_CTRL_RP180);
+       pdic_data->is_otg_reboost = false;
+
+       return;
+}
+#endif
+
+static irqreturn_t s2mu106_irq_thread(int irq, void *data)
+{
+       struct s2mu106_usbpd_data *pdic_data = data;
+       struct i2c_client *i2c = pdic_data->i2c;
+       struct device *dev = &i2c->dev;
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       int ret = 0;
+       unsigned attach_status = 0, rid_status = 0;
+
+       dev_info(dev, "%s\n", __func__);
+
+       mutex_lock(&pdic_data->_mutex);
+
+       s2mu106_poll_status(pd_data);
+
+#ifndef CONFIG_SEC_FACTORY
+       if (pdic_data->lpcharge_water)
+               goto out;
+#endif
+
+       if (s2mu106_get_status(pd_data, MSG_NONE))
+               goto out;
+
+       if (s2mu106_get_status(pd_data, MSG_HARDRESET)) {
+               s2mu106_usbpd_set_cc_control(pdic_data, USBPD_CC_OFF);
+               s2mu106_self_soft_reset(i2c);
+               pdic_data->status_reg = 0;
+               usbpd_rx_hard_reset(dev);
+               usbpd_kick_policy_work(dev);
+               goto out;
+       }
+
+       if (s2mu106_get_status(pd_data, MSG_SOFTRESET))
+               usbpd_rx_soft_reset(pd_data);
+
+       if (s2mu106_get_status(pd_data, PLUG_DETACH)) {
+#if defined(CONFIG_SEC_FACTORY)
+               ret = s2mu106_usbpd_check_619k(pdic_data);
+               if (ret)
+                       goto skip_detach;
+#endif /* CONFIG_SEC_FACTORY */
+#ifndef CONFIG_SEC_FACTORY
+               s2mu106_usbpd_check_reboost(pdic_data);
+#endif
+               attach_status = s2mu106_get_status(pd_data, PLUG_ATTACH);
+               rid_status = s2mu106_get_status(pd_data, MSG_RID);
+               s2mu106_usbpd_detach_init(pdic_data);
+               if (attach_status) {
+                       ret = s2mu106_check_port_detect(pdic_data);
+                       if (ret >= 0) {
+                               if (rid_status) {
+                                       pdic_data->check_rid_wa = true;
+                                       s2mu106_usbpd_check_rid(pdic_data);
+                               }
+                               goto hard_reset;
+                       }
+               }
+               s2mu106_usbpd_notify_detach(pdic_data);
+               mutex_lock(&pdic_data->lpm_mutex);
+               if (!pdic_data->lpm_mode) {
+                       if (s2mu106_usbpd_lpm_check(pdic_data) > 0) {
+                               pr_info("%s force to normal mode\n", __func__);
+                               s2mu106_usbpd_set_mode(pdic_data, PD_NORMAL_MODE);
+                       }
+                       s2mu106_set_irq_enable(pdic_data, ENABLED_INT_0, ENABLED_INT_1,
+                               ENABLED_INT_2, ENABLED_INT_3, ENABLED_INT_4, ENABLED_INT_5);
+               }
+               mutex_unlock(&pdic_data->lpm_mutex);
+               goto out;
+       }
+#if defined(CONFIG_SEC_FACTORY)
+skip_detach:
+#endif /* CONFIG_SEC_FACTORY */
+       if (s2mu106_get_status(pd_data, PLUG_ATTACH) && !pdic_data->is_pr_swap) {
+               if (s2mu106_check_port_detect(data) < 0)
+                       goto out;
+       }
+
+       if (s2mu106_get_status(pd_data, MSG_RID)) {
+               pdic_data->check_rid_wa = true;
+               s2mu106_usbpd_check_rid(pdic_data);
+       }
+
+hard_reset:
+       mutex_lock(&pdic_data->lpm_mutex);
+       if (!pdic_data->lpm_mode)
+               usbpd_kick_policy_work(dev);
+       mutex_unlock(&pdic_data->lpm_mutex);
+out:
+       mutex_unlock(&pdic_data->_mutex);
+
+       return IRQ_HANDLED;
+}
+
+static int s2mu106_usbpd_get_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_AUTHENTIC:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int s2mu106_usbpd_set_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               const union power_supply_propval *val)
+{
+       struct s2mu106_usbpd_data *pdic_data =
+               power_supply_get_drvdata(psy);
+       struct i2c_client *i2c = pdic_data->i2c;
+       u8 data = 0;
+
+       switch (psp) {
+               case POWER_SUPPLY_PROP_AUTHENTIC:
+                       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_VBUS_MUX, &data);
+                       data &= ~(S2MU106_REG_RD_OR_VBUS_MUX_SEL);
+                       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_VBUS_MUX, data);
+                       break;
+               case POWER_SUPPLY_PROP_USBPD_RESET:
+                       s2mu106_usbpd_set_vbus_wakeup(pdic_data, VBUS_WAKEUP_DISABLE);
+                       s2mu106_usbpd_set_vbus_wakeup(pdic_data, VBUS_WAKEUP_ENABLE);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+int s2mu106_usbpd_psy_init(struct s2mu106_usbpd_data *_data, struct device *parent)
+{
+       struct power_supply_config psy_cfg = {};
+       int ret = 0;
+
+       if (_data == NULL || parent == NULL) {
+               pr_err("%s NULL data\n", __func__);
+               return -1;
+       }
+
+       _data->ccic_desc.name           = "s2mu106-usbpd";
+       _data->ccic_desc.type           = POWER_SUPPLY_TYPE_UNKNOWN;
+       _data->ccic_desc.get_property   = s2mu106_usbpd_get_property;
+       _data->ccic_desc.set_property   = s2mu106_usbpd_set_property;
+       _data->ccic_desc.properties     = ccic_props;
+       _data->ccic_desc.num_properties = ARRAY_SIZE(ccic_props);
+
+       psy_cfg.drv_data = _data;
+       psy_cfg.supplied_to = ccic_supplied_to;
+       psy_cfg.num_supplicants = ARRAY_SIZE(ccic_supplied_to);
+
+       _data->psy_ccic = power_supply_register(parent, &_data->ccic_desc, &psy_cfg);
+       if (IS_ERR(_data->psy_ccic)) {
+               ret = (int)PTR_ERR(_data->psy_ccic);
+               pr_err("%s: Failed to Register psy_ccic, ret : %d\n", __func__, ret);
+       }
+       return ret;
+}
+
+static int s2mu106_usbpd_reg_init(struct s2mu106_usbpd_data *_data)
+{
+       struct i2c_client *i2c = _data->i2c;
+       u8 data = 0;
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL, &data);
+       data |= S2MU106_REG_PLUG_CTRL_VDM_DISABLE |
+                                       S2MU106_REG_PLUG_CTRL_ECO_SRC_CAP_RDY;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL, data);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PHY_CTRL_IFG, &data);
+       data |= S2MU106_PHY_IFG_35US << S2MU106_REG_IFG_SHIFT;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PHY_CTRL_IFG, data);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL_2, &data);
+       data &= ~S2MU106_REG_CC_OCP_MASK;
+       data |= S2MU106_CC_OCP_575MV << S2MU106_REG_CC_OCP_SHIFT;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PD_CTRL_2, data);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_VBUS_MUX, &data);
+       data &= ~S2MU106_REG_DET_RD_OR_VBUS;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_VBUS_MUX, data);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RD, &data);
+       data |= S2MU106_REG_USB31_EN;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RD, data);
+
+       s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL, &data);
+       data &= ~S2MU106_REG_PLUG_CTRL_UFP_ATTACH_OPT;
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL, data);
+
+       /* set Rd threshold to 400mV */
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RD_2, S2MU106_THRESHOLD_600MV);
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RP_2, S2MU106_THRESHOLD_1200MV);
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RD, S2MU106_THRESHOLD_214MV);
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_SET_RP, S2MU106_THRESHOLD_2057MV);
+
+       if (_data->vconn_en) {
+               /* Off Manual Rd setup & On Manual Vconn setup */
+               s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, &data);
+               data &= ~(S2MU106_REG_PLUG_CTRL_RpRd_MANUAL_EN_MASK);
+               data |= S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN;
+               s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, data);
+       }
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, S2MU106_RESET_REG_00);
+
+       s2mu106_usbpd_write_reg(i2c, S2MU106_REG_MSG_SEND_CON, S2MU106_RESET_REG_00);
+
+       s2mu106_usbpd_set_vconn_manual(_data, true);
+
+       return 0;
+}
+
+static irqreturn_t s2mu106_irq_isr(int irq, void *data)
+{
+       return IRQ_WAKE_THREAD;
+}
+
+static int s2mu106_usbpd_irq_init(struct s2mu106_usbpd_data *_data)
+{
+       struct i2c_client *i2c = _data->i2c;
+       struct device *dev = &i2c->dev;
+       int ret = 0;
+
+       if (!_data->irq_gpio) {
+               dev_err(dev, "%s No interrupt specified\n", __func__);
+               return -ENXIO;
+       }
+
+/*     s2mu106_usbpd_bulk_read(i2c, S2MU106_REG_INT_STATUS0,
+                       S2MU106_MAX_NUM_INT_STATUS, intr);
+
+       pr_info("%s status[0x%x 0x%x 0x%x 0x%x 0x%x]\n",
+                       __func__, intr[0], intr[1], intr[2], intr[3], intr[4]);
+*/
+       i2c->irq = gpio_to_irq(_data->irq_gpio);
+
+       if (i2c->irq) {
+               ret = request_threaded_irq(i2c->irq, s2mu106_irq_isr,
+                               s2mu106_irq_thread,
+                               (IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_NO_SUSPEND),
+                               "s2mu106-usbpd", _data);
+               if (ret < 0) {
+                       dev_err(dev, "%s failed to request irq(%d)\n",
+                                       __func__, i2c->irq);
+                       return ret;
+               }
+
+               ret = enable_irq_wake(i2c->irq);
+               if (ret < 0)
+                       dev_err(dev, "%s failed to enable wakeup src\n",
+                                       __func__);
+       }
+
+       if (_data->lpm_mode)
+               s2mu106_set_irq_enable(_data, 0, 0, 0, 0, 0, 0);
+       else
+               s2mu106_set_irq_enable(_data, 0, 0, 0, 0, ENABLED_INT_4, 0);
+
+       return ret;
+}
+
+static void s2mu106_usbpd_init_configure(struct s2mu106_usbpd_data *_data)
+{
+       s2mu106_set_normal_mode(_data);
+       msleep(25);
+       _data->detach_valid = true;
+       s2mu106_set_lpm_mode(_data);
+       _data->detach_valid = false;
+       s2mu106_usbpd_set_cc_control(_data, USBPD_CC_OFF);
+       _data->lpm_mode = true;
+       msleep(150); /* for abnormal PD TA */
+       _data->is_factory_mode = false;
+       s2mu106_set_normal_mode(_data);
+       _data->lpm_mode = false;
+}
+
+static void s2mu106_usbpd_pdic_data_init(struct s2mu106_usbpd_data *_data)
+{
+       _data->check_msg_pass = false;
+       _data->vconn_source = USBPD_VCONN_OFF;
+       _data->rid = REG_RID_MAX;
+       _data->is_host = 0;
+       _data->is_client = 0;
+       _data->data_role_dual = 0;
+       _data->power_role_dual = 0;
+       _data->is_water_detect = false;
+       _data->is_muic_water_detect = false;
+       _data->detach_valid = true;
+       _data->is_otg_vboost = false;
+       _data->is_otg_reboost = false;
+       _data->is_pr_swap = false;
+       _data->vbus_short = false;
+       _data->vbus_short_check = false;
+#ifndef CONFIG_SEC_FACTORY
+       _data->lpcharge_water = false;
+#endif
+       _data->check_rid_wa = false;
+}
+
+static int of_s2mu106_dt(struct device *dev,
+                       struct s2mu106_usbpd_data *_data)
+{
+       struct device_node *np_usbpd = dev->of_node;
+       int ret = 0;
+
+       if (np_usbpd == NULL) {
+               dev_err(dev, "%s np NULL\n", __func__);
+               return -EINVAL;
+       } else {
+               _data->irq_gpio = of_get_named_gpio(np_usbpd,
+                                                       "usbpd,usbpd_int", 0);
+               if (_data->irq_gpio < 0) {
+                       dev_err(dev, "error reading usbpd irq = %d\n",
+                                               _data->irq_gpio);
+                       _data->irq_gpio = 0;
+               }
+               if (of_find_property(np_usbpd, "vconn-en", NULL))
+                       _data->vconn_en = true;
+               else
+                       _data->vconn_en = false;
+
+               if (of_find_property(np_usbpd, "regulator-en", NULL))
+                       _data->regulator_en = true;
+               else
+                       _data->regulator_en = false;
+#ifdef CONFIG_CCIC_DP
+               _data->usb_sw_sel = of_get_named_gpio(np_usbpd, "usb_sw_sel", 0);
+
+               if (!gpio_is_valid(_data->usb_sw_sel))
+                       dev_err(dev, "failed to get gpio usb_sw_sel\n");
+#endif
+               }
+       return ret;
+}
+
+static int s2mu106_usbpd_probe(struct i2c_client *i2c,
+                               const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent);
+       struct s2mu106_usbpd_data *pdic_data;
+       struct device *dev = &i2c->dev;
+       int ret = 0;
+
+       dev_info(dev, "%s\n", __func__);
+       test_i2c = i2c;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(dev, "%s: i2c functionality check error\n", __func__);
+               ret = -EIO;
+               goto err_return;
+       }
+
+       pdic_data = kzalloc(sizeof(struct s2mu106_usbpd_data), GFP_KERNEL);
+       if (!pdic_data) {
+               dev_err(dev, "%s: failed to allocate driver data\n", __func__);
+               ret = -ENOMEM;
+               goto err_return;
+       }
+
+       /* save platfom data for gpio control functions */
+       pdic_data->dev = &i2c->dev;
+       pdic_data->i2c = i2c;
+       i2c_set_clientdata(i2c, pdic_data);
+
+       ret = of_s2mu106_dt(&i2c->dev, pdic_data);
+       if (ret < 0)
+               dev_err(dev, "%s: not found dt!\n", __func__);
+
+       mutex_init(&pdic_data->_mutex);
+       mutex_init(&pdic_data->lpm_mutex);
+       mutex_init(&pdic_data->cc_mutex);
+       wake_lock_init(&pdic_data->wake_lock, WAKE_LOCK_SUSPEND, "pdic_wake");
+
+       s2mu106_usbpd_init_configure(pdic_data);
+       s2mu106_usbpd_pdic_data_init(pdic_data);
+
+       if (pdic_data->regulator_en) {
+               pdic_data->regulator = devm_regulator_get(dev, "vconn");
+               if (IS_ERR(pdic_data->regulator)) {
+                       dev_err(dev, "%s: not found regulator vconn\n", __func__);
+                       pdic_data->regulator_en = false;
+               } else
+                       ret = regulator_disable(pdic_data->regulator);
+       }
+
+       ret = usbpd_init(dev, pdic_data);
+       if (ret < 0) {
+               dev_err(dev, "failed on usbpd_init\n");
+               goto err_return;
+       }
+
+       usbpd_set_ops(dev, &s2mu106_ops);
+
+       s2mu106_usbpd_reg_init(pdic_data);
+
+       pdic_data->pdic_queue =
+           alloc_workqueue(dev_name(dev), WQ_MEM_RECLAIM, 1);
+       if (!pdic_data->pdic_queue) {
+               dev_err(dev,
+                       "%s: Fail to Create Workqueue\n", __func__);
+               goto err_return;
+       }
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       /* Create a work queue for the ccic irq thread */
+       pdic_data->ifconn_wq
+               = create_singlethread_workqueue("ifconn_notify_event");
+       if (!pdic_data->ifconn_wq) {
+               pr_err("%s failed to create work queue for ccic notifier\n",
+                                                                  __func__);
+               goto err_return;
+       }
+#endif
+       if (pdic_data->rid == REG_RID_UNDF)
+               pdic_data->rid = REG_RID_MAX;
+
+       ret = s2mu106_usbpd_irq_init(pdic_data);
+       if (ret) {
+               dev_err(dev, "%s: failed to init irq(%d)\n", __func__, ret);
+               goto fail_init_irq;
+       }
+       INIT_DELAYED_WORK(&pdic_data->water_detect_handler, S2MU106_PDIC_water_detect_handler);
+       INIT_DELAYED_WORK(&pdic_data->water_dry_handler, S2MU106_PDIC_water_dry_handler);
+
+       if (pdic_data->detach_valid) {
+               mutex_lock(&pdic_data->_mutex);
+               s2mu106_check_port_detect(pdic_data);
+               s2mu106_usbpd_check_rid(pdic_data);
+               mutex_unlock(&pdic_data->_mutex);
+       }
+
+       s2mu106_irq_thread(-1, pdic_data);
+
+#if defined(CONFIG_MUIC_NOTIFIER)
+       muic_ccic_notifier_register(&pdic_data->type3_nb,
+                              type3_handle_notification,
+                              MUIC_NOTIFY_DEV_PDIC);
+#endif
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+       ret = dual_role_init(pdic_data);
+       if (ret < 0) {
+               pr_err("unable to allocate dual role descriptor\n");
+               goto fail_init_irq;
+       }
+
+#endif
+       ret = s2mu106_usbpd_psy_init(pdic_data, &i2c->dev);
+       if (ret < 0) {
+               pr_err("faled to register the ccic psy.\n");
+       }
+
+       dev_info(dev, "%s s2mu106 usbpd driver uploaded!\n", __func__);
+
+       return 0;
+
+fail_init_irq:
+       if (i2c->irq)
+               free_irq(i2c->irq, pdic_data);
+err_return:
+       return ret;
+}
+
+#if defined CONFIG_PM
+static int s2mu106_usbpd_suspend(struct device *dev)
+{
+       struct usbpd_data *_data = dev_get_drvdata(dev);
+       struct s2mu106_usbpd_data *pdic_data = _data->phy_driver_data;
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(pdic_data->i2c->irq);
+
+#ifndef CONFIG_SEC_FACTORY
+       disable_irq(pdic_data->i2c->irq);
+#endif
+       return 0;
+}
+
+static int s2mu106_usbpd_resume(struct device *dev)
+{
+       struct usbpd_data *_data = dev_get_drvdata(dev);
+       struct s2mu106_usbpd_data *pdic_data = _data->phy_driver_data;
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(pdic_data->i2c->irq);
+
+#ifndef CONFIG_SEC_FACTORY
+       enable_irq(pdic_data->i2c->irq);
+#endif
+       return 0;
+}
+#else
+#define s2mu106_muic_suspend NULL
+#define s2mu106_muic_resume NULL
+#endif
+
+static int s2mu106_usbpd_remove(struct i2c_client *i2c)
+{
+       struct s2mu106_usbpd_data *_data = i2c_get_clientdata(i2c);
+
+       if (_data) {
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+               devm_dual_role_instance_unregister(_data->dev,
+                                               _data->dual_role);
+               devm_kfree(_data->dev, _data->desc);
+#endif
+               disable_irq_wake(_data->i2c->irq);
+               free_irq(_data->i2c->irq, _data);
+               mutex_destroy(&_data->_mutex);
+               i2c_set_clientdata(_data->i2c, NULL);
+               kfree(_data);
+       }
+       return 0;
+}
+
+static const struct i2c_device_id s2mu106_usbpd_i2c_id[] = {
+       { USBPD_DEV_NAME, 1 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, s2mu106_i2c_id);
+
+static struct of_device_id sec_usbpd_i2c_dt_ids[] = {
+       { .compatible = "sec-usbpd,i2c" },
+       { }
+};
+
+static void s2mu106_usbpd_shutdown(struct i2c_client *i2c)
+{
+       struct s2mu106_usbpd_data *_data = i2c_get_clientdata(i2c);
+
+       if (!_data->i2c)
+               return;
+}
+
+static usbpd_phy_ops_type s2mu106_ops = {
+       .tx_msg                 = s2mu106_tx_msg,
+       .rx_msg                 = s2mu106_rx_msg,
+       .hard_reset             = s2mu106_hard_reset,
+       .set_power_role         = s2mu106_set_power_role,
+       .get_power_role         = s2mu106_get_power_role,
+       .set_data_role          = s2mu106_set_data_role,
+       .get_data_role          = s2mu106_get_data_role,
+       .set_vconn_source       = s2mu106_set_vconn_source,
+       .get_vconn_source       = s2mu106_get_vconn_source,
+       .set_check_msg_pass     = s2mu106_set_check_msg_pass,
+       .get_status             = s2mu106_get_status,
+       .poll_status            = s2mu106_poll_status,
+       .driver_reset           = s2mu106_driver_reset,
+       .set_otg_control        = s2mu106_set_otg_control,
+       .get_vbus_short_check   = s2mu106_get_vbus_short_check,
+       .set_cc_control         = s2mu106_set_cc_control,
+       .get_side_check         = s2mu106_get_side_check,
+};
+
+#if defined CONFIG_PM
+const struct dev_pm_ops s2mu106_usbpd_pm = {
+       .suspend = s2mu106_usbpd_suspend,
+       .resume = s2mu106_usbpd_resume,
+};
+#endif
+
+static struct i2c_driver s2mu106_usbpd_driver = {
+       .driver         = {
+               .name   = USBPD_DEV_NAME,
+               .of_match_table = sec_usbpd_i2c_dt_ids,
+#if defined CONFIG_PM
+               .pm     = &s2mu106_usbpd_pm,
+#endif /* CONFIG_PM */
+       },
+       .probe          = s2mu106_usbpd_probe,
+       .remove         = s2mu106_usbpd_remove,
+       .shutdown       = s2mu106_usbpd_shutdown,
+       .id_table       = s2mu106_usbpd_i2c_id,
+};
+
+static int __init s2mu106_usbpd_init(void)
+{
+       return i2c_add_driver(&s2mu106_usbpd_driver);
+}
+late_initcall(s2mu106_usbpd_init);
+
+static void __exit s2mu106_usbpd_exit(void)
+{
+       i2c_del_driver(&s2mu106_usbpd_driver);
+}
+module_exit(s2mu106_usbpd_exit);
+
+MODULE_DESCRIPTION("s2mu106 USB PD driver");
+MODULE_LICENSE("GPL");
index 9db290a8b6b3b42f5366d660d8158bae3b3ae74f..c646773d05491f07bc3994e875d546710a461978 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/ccic/core.h>
-#include <linux/ccic/usbpd_msg.h>
+#include <linux/ccic/s2mm005_usbpd_msg.h>
 #include <linux/ccic/usbpd_typec.h>
 #include <linux/power_supply.h>
 #include <linux/delay.h>
diff --git a/drivers/ccic/usbpd.c b/drivers/ccic/usbpd.c
new file mode 100644 (file)
index 0000000..37cd769
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+*      USB PD Driver - Protocol Layer
+*/
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/ccic/usbpd.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#ifdef CONFIG_CCIC_SYSFS
+#include <linux/ccic/usbpd_sysfs.h>
+#include <linux/sec_sysfs.h>
+#endif
+#ifdef CONFIG_IFCONN_NOTIFIER
+#include <linux/ifconn/ifconn_notifier.h>
+
+extern struct pdic_notifier_data pd_noti;
+#endif
+
+static void increase_message_id_counter(struct usbpd_data *pd_data)
+{
+       pd_data->counter.message_id_counter++;
+       pd_data->counter.message_id_counter %= 8;
+/*
+       if (pd_data->counter.message_id_counter++ > USBPD_nMessageIDCount)
+               pd_data->counter.message_id_counter = 0;
+*/
+}
+
+static void rx_layer_init(struct protocol_data *rx)
+{
+       int i;
+
+       rx->stored_message_id = USBPD_nMessageIDCount+1;
+       rx->msg_header.word = 0;
+       rx->state = 0;
+       rx->status = DEFAULT_PROTOCOL_NONE;
+       for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++)
+               rx->data_obj[i].object = 0;
+}
+
+static void tx_layer_init(struct protocol_data *tx)
+{
+       int i;
+
+       tx->stored_message_id = USBPD_nMessageIDCount+1;
+       tx->msg_header.word = 0;
+       tx->state = 0;
+       tx->status = DEFAULT_PROTOCOL_NONE;
+       for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++)
+               tx->data_obj[i].object = 0;
+}
+
+static void tx_discard_message(struct protocol_data *tx)
+{
+       int i;
+
+       tx->msg_header.word = 0;
+       for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++)
+               tx->data_obj[i].object = 0;
+}
+
+void usbpd_init_protocol(struct usbpd_data *pd_data)
+{
+       rx_layer_init(&pd_data->protocol_rx);
+       tx_layer_init(&pd_data->protocol_tx);
+}
+
+void usbpd_init_counters(struct usbpd_data *pd_data)
+{
+       pr_info("%s: init counter\n", __func__);
+       pd_data->counter.retry_counter = 0;
+       pd_data->counter.message_id_counter = 0;
+       pd_data->counter.caps_counter = 0;
+       pd_data->counter.hard_reset_counter = 0;
+       pd_data->counter.swap_hard_reset_counter = 0;
+       pd_data->counter.discover_identity_counter = 0;
+}
+
+void usbpd_policy_reset(struct usbpd_data *pd_data, unsigned flag)
+{
+       if (flag == HARDRESET_RECEIVED) {
+               pd_data->policy.rx_hardreset = 1;
+               dev_info(pd_data->dev, "%s Hard reset\n", __func__);
+       } else if (flag == SOFTRESET_RECEIVED) {
+               pd_data->policy.rx_softreset = 1;
+               dev_info(pd_data->dev, "%s Soft reset\n", __func__);
+       } else if (flag == PLUG_EVENT) {
+               if (!pd_data->policy.plug_valid)
+                       pd_data->policy.plug = 1;
+               pd_data->policy.plug_valid = 1;
+               dev_info(pd_data->dev, "%s ATTACHED\n", __func__);
+       } else if (flag == PLUG_DETACHED) {
+               pd_data->policy.plug_valid = 0;
+               dev_info(pd_data->dev, "%s DETACHED\n", __func__);
+       }
+}
+
+protocol_state usbpd_protocol_tx_phy_layer_reset(struct protocol_data *tx)
+{
+       return PRL_Tx_Wait_for_Message_Request;
+}
+
+protocol_state usbpd_protocol_tx_wait_for_message_request(struct protocol_data
+                                                               *tx)
+{
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx);
+       protocol_state state = PRL_Tx_Wait_for_Message_Request;
+
+       /* S2MM004 PDIC already retry.
+       if (pd_data->counter.retry_counter > USBPD_nRetryCount) {
+               pd_data->counter.retry_counter = 0;
+               return state;
+       }
+       */
+       if (pd_data->counter.retry_counter > 0) {
+               pd_data->counter.retry_counter = 0;
+               return state;
+       }
+
+       pd_data->counter.retry_counter = 0;
+
+       if (!tx->msg_header.word)
+               return state;
+
+       if (tx->msg_header.num_data_objs == 0 &&
+                       tx->msg_header.msg_type == USBPD_Soft_Reset)
+               state = PRL_Tx_Layer_Reset_for_Transmit;
+       else
+               state = PRL_Tx_Construct_Message;
+
+       return state;
+}
+
+protocol_state usbpd_protocol_tx_layer_reset_for_transmit(struct protocol_data *tx)
+{
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->counter.message_id_counter = 0;
+       pd_data->protocol_rx.state = PRL_Rx_Wait_for_PHY_Message;
+
+       /* TODO: check Layer Reset Complete */
+       return PRL_Tx_Construct_Message;
+}
+
+protocol_state usbpd_protocol_tx_construct_message(struct protocol_data *tx)
+{
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx);
+
+       tx->msg_header.msg_id = pd_data->counter.message_id_counter;
+       tx->status = DEFAULT_PROTOCOL_NONE;
+
+       if (pd_data->phy_ops.tx_msg(pd_data, &tx->msg_header, tx->data_obj)) {
+               dev_err(pd_data->dev, "%s error\n", __func__);
+               return PRL_Tx_Construct_Message;
+       }
+       return PRL_Tx_Wait_for_PHY_Response;
+}
+
+protocol_state usbpd_protocol_tx_wait_for_phy_response(struct protocol_data *tx)
+{
+#if 0
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx);
+       protocol_state state = PRL_Tx_Wait_for_PHY_Response;
+       u8 CrcCheck_cnt = 0;
+
+       /* wait to get goodcrc */
+       /* mdelay(1); */
+
+       /* polling */
+       /* pd_data->phy_ops.poll_status(pd_data); */
+
+       for (CrcCheck_cnt = 0; CrcCheck_cnt < 2; CrcCheck_cnt++) {
+               if (pd_data->phy_ops.get_status(pd_data, MSG_GOODCRC)) {
+                       pr_info("%s : %p\n", __func__, pd_data);
+                       state = PRL_Tx_Message_Sent;
+                       dev_info(pd_data->dev, "got GoodCRC.\n");
+                       return state;
+               }
+
+               if (!CrcCheck_cnt)
+                       pd_data->phy_ops.poll_status(pd_data); /* polling */
+       }
+
+       return PRL_Tx_Check_RetryCounter;
+#endif
+       return PRL_Tx_Message_Sent;
+}
+
+protocol_state usbpd_protocol_tx_match_messageid(struct protocol_data *tx)
+{
+       /* We don't use this function.
+          S2MM004 PDIC already check message id for incoming GoodCRC.
+
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(protocol_tx);
+       protocol_state state = PRL_Tx_Match_MessageID;
+
+       dev_info(pd_data->dev, "%s\n",__func__);
+
+       if (pd_data->protocol_rx.msg_header.msg_id
+                       == pd_data->counter.message_id_counter)
+               state = PRL_Tx_Message_Sent;
+       else
+               state = PRL_Tx_Check_RetryCounter;
+
+       return state;
+       */
+       return PRL_Tx_Message_Sent;
+}
+
+protocol_state usbpd_protocol_tx_message_sent(struct protocol_data *tx)
+{
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx);
+
+       increase_message_id_counter(pd_data);
+       tx->status = MESSAGE_SENT;
+       /* clear protocol header buffer */
+       tx->msg_header.word = 0;
+
+       return PRL_Tx_Wait_for_Message_Request;
+}
+
+protocol_state usbpd_protocol_tx_check_retrycounter(struct protocol_data *tx)
+{
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx);
+
+       /* S2MM004 PDIC already do retry.
+          Driver SW doesn't do retry.
+
+       if (++pd_data->counter.retry_counter > USBPD_nRetryCount) {
+               state = PRL_Tx_Transmission_Error;
+       } else {
+               state = PRL_Tx_Construct_Message;
+       }
+
+       return PRL_Tx_Check_RetryCounter;
+       */
+       ++pd_data->counter.retry_counter;
+       return PRL_Tx_Transmission_Error;
+}
+
+protocol_state usbpd_protocol_tx_transmission_error(struct protocol_data *tx)
+{
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx);
+
+       dev_err(pd_data->dev, "%s\n", __func__);
+
+       increase_message_id_counter(pd_data);
+       tx->status = TRANSMISSION_ERROR;
+
+       return PRL_Tx_Wait_for_Message_Request;
+}
+
+protocol_state usbpd_protocol_tx_discard_message(struct protocol_data *tx)
+{
+       /* This state is for Only Ping message */
+       struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx);
+
+       dev_err(pd_data->dev, "%s\n", __func__);
+       tx_discard_message(tx);
+       increase_message_id_counter(pd_data);
+
+       return PRL_Tx_PHY_Layer_Reset;
+}
+
+void usbpd_set_ops(struct device *dev, usbpd_phy_ops_type *ops)
+{
+       struct usbpd_data *pd_data = (struct usbpd_data *) dev_get_drvdata(dev);
+
+       pd_data->phy_ops.tx_msg = ops->tx_msg;
+       pd_data->phy_ops.rx_msg = ops->rx_msg;
+       pd_data->phy_ops.hard_reset = ops->hard_reset;
+       pd_data->phy_ops.set_power_role = ops->set_power_role;
+       pd_data->phy_ops.get_power_role = ops->get_power_role;
+       pd_data->phy_ops.set_data_role = ops->set_data_role;
+       pd_data->phy_ops.get_data_role = ops->get_data_role;
+       pd_data->phy_ops.get_vconn_source = ops->get_vconn_source;
+       pd_data->phy_ops.set_vconn_source = ops->set_vconn_source;
+       pd_data->phy_ops.set_check_msg_pass = ops->set_check_msg_pass;
+       pd_data->phy_ops.get_status = ops->get_status;
+       pd_data->phy_ops.poll_status = ops->poll_status;
+       pd_data->phy_ops.driver_reset = ops->driver_reset;
+       pd_data->phy_ops.set_otg_control = ops->set_otg_control;
+       pd_data->phy_ops.get_vbus_short_check = ops->get_vbus_short_check;
+       pd_data->phy_ops.set_cc_control = ops->set_cc_control;
+       pd_data->phy_ops.get_side_check = ops->get_side_check;
+}
+
+protocol_state usbpd_protocol_rx_layer_reset_for_receive(struct protocol_data *rx)
+{
+       struct usbpd_data *pd_data = protocol_rx_to_usbpd(rx);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       /*
+       rx_layer_init(protocol_rx);
+       pd_data->protocol_tx.state = PRL_Tx_PHY_Layer_Reset;
+       */
+
+       usbpd_rx_soft_reset(pd_data);
+       return PRL_Rx_Layer_Reset_for_Receive;
+
+       /*return PRL_Rx_Send_GoodCRC;*/
+}
+
+protocol_state usbpd_protocol_rx_wait_for_phy_message(struct protocol_data *rx)
+{
+       struct usbpd_data *pd_data = protocol_rx_to_usbpd(rx);
+       protocol_state state = PRL_Rx_Wait_for_PHY_Message;
+
+       if (pd_data->phy_ops.rx_msg(pd_data, &rx->msg_header, rx->data_obj)) {
+               dev_err(pd_data->dev, "%s IO Error\n", __func__);
+               return state;
+       } else {
+               if (rx->msg_header.word == 0) {
+                       dev_err(pd_data->dev, "%s No Message\n", __func__);
+                       return state; /* no message */
+               } else if (pd_data->phy_ops.get_status(pd_data, MSG_SOFTRESET)) {
+                       dev_err(pd_data->dev, "[Rx] Got SOFTRESET.\n");
+                       state = PRL_Rx_Layer_Reset_for_Receive;
+               } else {
+                       if (rx->stored_message_id == rx->msg_header.msg_id)
+                               return state;
+
+                       dev_err(pd_data->dev, "[Rx] [0x%x] [0x%x]\n",
+                                       rx->msg_header.word, rx->data_obj[0].object);
+                       /* new message is coming */
+                       state = PRL_Rx_Send_GoodCRC;
+               }
+       }
+       return state;
+}
+
+protocol_state usbpd_protocol_rx_send_goodcrc(struct protocol_data *rx)
+{
+       /* Goodcrc sent by PDIC(HW) */
+       return PRL_Rx_Check_MessageID;
+}
+
+protocol_state usbpd_protocol_rx_store_messageid(struct protocol_data *rx)
+{
+       struct usbpd_data *pd_data = protocol_rx_to_usbpd(rx);
+
+       rx->stored_message_id = rx->msg_header.msg_id;
+       usbpd_read_msg(pd_data);
+/*
+       return PRL_Rx_Wait_for_PHY_Message;
+*/
+       return PRL_Rx_Store_MessageID;
+}
+
+protocol_state usbpd_protocol_rx_check_messageid(struct protocol_data *rx)
+{
+       protocol_state state;
+
+       if (rx->stored_message_id == rx->msg_header.msg_id)
+               state = PRL_Rx_Wait_for_PHY_Message;
+       else
+               state = PRL_Rx_Store_MessageID;
+       return state;
+}
+
+void usbpd_protocol_tx(struct usbpd_data *pd_data)
+{
+       struct protocol_data *tx = &pd_data->protocol_tx;
+       protocol_state next_state = tx->state;
+       protocol_state saved_state;
+
+       do {
+               saved_state = next_state;
+               switch (next_state) {
+               case PRL_Tx_PHY_Layer_Reset:
+                       next_state = usbpd_protocol_tx_phy_layer_reset(tx);
+                       break;
+               case PRL_Tx_Wait_for_Message_Request:
+                       next_state = usbpd_protocol_tx_wait_for_message_request(tx);
+                       break;
+               case PRL_Tx_Layer_Reset_for_Transmit:
+                       next_state = usbpd_protocol_tx_layer_reset_for_transmit(tx);
+                       break;
+               case PRL_Tx_Construct_Message:
+                       next_state = usbpd_protocol_tx_construct_message(tx);
+                       break;
+               case PRL_Tx_Wait_for_PHY_Response:
+                       next_state = usbpd_protocol_tx_wait_for_phy_response(tx);
+                       break;
+               case PRL_Tx_Match_MessageID:
+                       next_state = usbpd_protocol_tx_match_messageid(tx);
+                       break;
+               case PRL_Tx_Message_Sent:
+                       next_state = usbpd_protocol_tx_message_sent(tx);
+                       break;
+               case PRL_Tx_Check_RetryCounter:
+                       next_state = usbpd_protocol_tx_check_retrycounter(tx);
+                       break;
+               case PRL_Tx_Transmission_Error:
+                       next_state = usbpd_protocol_tx_transmission_error(tx);
+                       break;
+               case PRL_Tx_Discard_Message:
+                       next_state = usbpd_protocol_tx_discard_message(tx);
+                       break;
+               default:
+                       next_state = PRL_Tx_Wait_for_Message_Request;
+                       break;
+               }
+       } while (saved_state != next_state);
+
+       tx->state = next_state;
+}
+
+void usbpd_protocol_rx(struct usbpd_data *pd_data)
+{
+       struct protocol_data *rx = &pd_data->protocol_rx;
+       protocol_state next_state = rx->state;
+       protocol_state saved_state;
+
+       do {
+               saved_state = next_state;
+               switch (next_state) {
+               case PRL_Rx_Layer_Reset_for_Receive:
+                       next_state = usbpd_protocol_rx_layer_reset_for_receive(rx);
+                       break;
+               case PRL_Rx_Wait_for_PHY_Message:
+                       next_state = usbpd_protocol_rx_wait_for_phy_message(rx);
+                       break;
+               case PRL_Rx_Send_GoodCRC:
+                       next_state = usbpd_protocol_rx_send_goodcrc(rx);
+                       break;
+               case PRL_Rx_Store_MessageID:
+                       next_state = usbpd_protocol_rx_store_messageid(rx);
+                       break;
+               case PRL_Rx_Check_MessageID:
+                       next_state = usbpd_protocol_rx_check_messageid(rx);
+                       break;
+               default:
+                       next_state = PRL_Rx_Wait_for_PHY_Message;
+                       break;
+               }
+       } while (saved_state != next_state);
+/*
+       rx->state = next_state;
+*/
+       rx->state = PRL_Rx_Wait_for_PHY_Message;
+}
+
+void usbpd_read_msg(struct usbpd_data *pd_data)
+{
+       int i;
+
+       pd_data->policy.rx_msg_header.word
+               = pd_data->protocol_rx.msg_header.word;
+       for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++) {
+               pd_data->policy.rx_data_obj[i].object
+                       = pd_data->protocol_rx.data_obj[i].object;
+       }
+}
+
+/* return 1: sent with goodcrc, 0: fail */
+bool usbpd_send_msg(struct usbpd_data *pd_data, msg_header_type *header,
+               data_obj_type *obj)
+{
+       int i;
+
+       if (obj)
+               for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++)
+                       pd_data->protocol_tx.data_obj[i].object = obj[i].object;
+       else
+               header->num_data_objs = 0;
+
+       header->spec_revision = USBPD_REV_20;
+       pd_data->protocol_tx.msg_header.word = header->word;
+       usbpd_protocol_tx(pd_data);
+
+       if (pd_data->protocol_tx.status == MESSAGE_SENT)
+               return true;
+       else
+               return false;
+}
+
+inline bool usbpd_send_ctrl_msg(struct usbpd_data *d, msg_header_type *h,
+               unsigned msg, unsigned dr, unsigned pr)
+{
+       h->msg_type = msg;
+       h->port_data_role = dr;
+       h->port_power_role = pr;
+       h->num_data_objs = 0;
+       return usbpd_send_msg(d, h, 0);
+}
+
+/* return: 0 if timed out, positive is status */
+inline unsigned usbpd_wait_msg(struct usbpd_data *pd_data,
+                               unsigned msg_status, unsigned ms)
+{
+       unsigned long ret;
+
+       ret = pd_data->phy_ops.get_status(pd_data, msg_status);
+       if (ret) {
+               pd_data->policy.abnormal_state = false;
+               return ret;
+       }
+
+       pr_info("%s, %d\n", __func__, __LINE__);
+       /* wait */
+       reinit_completion(&pd_data->msg_arrived);
+       pd_data->wait_for_msg_arrived = msg_status;
+       ret = wait_for_completion_timeout(&pd_data->msg_arrived,
+                       msecs_to_jiffies(ms));
+
+       if (!pd_data->policy.state) {
+               dev_err(pd_data->dev, "%s : return for policy state error\n", __func__);
+               pd_data->policy.abnormal_state = true;
+               return 0;
+       }
+
+       pd_data->policy.abnormal_state = false;
+
+       return pd_data->phy_ops.get_status(pd_data, msg_status);
+}
+
+void usbpd_rx_hard_reset(struct device *dev)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+
+       usbpd_reinit(dev);
+       usbpd_policy_reset(pd_data, HARDRESET_RECEIVED);
+}
+
+void usbpd_rx_soft_reset(struct usbpd_data *pd_data)
+{
+       usbpd_reinit(pd_data->dev);
+       usbpd_policy_reset(pd_data, SOFTRESET_RECEIVED);
+}
+
+void usbpd_reinit(struct device *dev)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+
+       usbpd_init_counters(pd_data);
+       usbpd_init_protocol(pd_data);
+       usbpd_init_policy(pd_data);
+       usbpd_init_manager_val(pd_data);
+       reinit_completion(&pd_data->msg_arrived);
+       pd_data->wait_for_msg_arrived = 0;
+       complete(&pd_data->msg_arrived);
+}
+
+/*
+ * usbpd_init - alloc usbpd data
+ *
+ * Returns 0 on success; negative errno on failure
+*/
+int usbpd_init(struct device *dev, void *phy_driver_data)
+{
+       struct usbpd_data *pd_data;
+#ifdef CONFIG_CCIC_SYSFS
+       int ret = 0;
+#endif
+
+       if (!dev)
+               return -EINVAL;
+
+       pd_data = kzalloc(sizeof(struct usbpd_data), GFP_KERNEL);
+
+       if (!pd_data)
+               return -ENOMEM;
+
+       pd_data->dev = dev;
+       pd_data->phy_driver_data = phy_driver_data;
+       dev_set_drvdata(dev, pd_data);
+
+#ifdef CONFIG_CCIC_SYSFS
+       /* create sysfs group */
+       pd_data->ccic_dev = sec_device_create(NULL, "ccic");
+       if (IS_ERR(pd_data->ccic_dev))
+               pr_err("%s Failed to create device(switch)!\n", __func__);
+       else {
+               /* create sysfs group */
+               ret = sysfs_create_group(&pd_data->ccic_dev->kobj, &ccic_sysfs_group);
+               if (ret)
+                       pr_err("%s: ccic sysfs fail, ret %d", __func__, ret);
+               else 
+                       dev_set_drvdata(pd_data->ccic_dev, pd_data);
+       }
+#endif
+
+#ifdef CONFIG_IFCONN_NOTIFIER
+       pd_noti.pd_data = pd_data;
+       pd_noti.sink_status.current_pdo_num = 0;
+       pd_noti.sink_status.selected_pdo_num = 0;
+#endif
+       usbpd_init_counters(pd_data);
+       usbpd_init_protocol(pd_data);
+       usbpd_init_policy(pd_data);
+       usbpd_init_manager(pd_data);
+
+       INIT_WORK(&pd_data->worker, usbpd_policy_work);
+       init_completion(&pd_data->msg_arrived);
+
+       return 0;
+}
diff --git a/drivers/ccic/usbpd_cc.c b/drivers/ccic/usbpd_cc.c
new file mode 100644 (file)
index 0000000..4c472c2
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ driver/usbpd/usbpd_cc.c - USB PD(Power Delivery) device driver
+ *
+ * Copyright (C) 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.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/usb_notify.h>
+
+#if (defined CONFIG_CCIC_NOTIFIER || defined CONFIG_DUAL_ROLE_USB_INTF \
+                       || defined CONFIG_IFCONN_NOTIFIER)
+#include <linux/ccic/usbpd_ext.h>
+#endif
+#if defined CONFIG_IFCONN_NOTIFIER
+#include <linux/ifconn/ifconn_notifier.h>
+#endif
+#include <linux/ccic/usbpd.h>
+#include <linux/ccic/usbpd-s2mu106.h>
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+static void ccic_event_notifier(struct work_struct *data)
+{
+       struct ccic_state_work *event_work =
+               container_of(data, struct ccic_state_work, ccic_work);
+       CC_NOTI_TYPEDEF ccic_noti;
+
+       switch (event_work->dest) {
+       case CCIC_NOTIFY_DEV_USB:
+               pr_info("usb:%s, dest=%s, id=%s, attach=%s, drp=%s, event_work=%p\n", __func__,
+                               CCIC_NOTI_DEST_Print[event_work->dest],
+                               CCIC_NOTI_ID_Print[event_work->id],
+                               event_work->attach ? "Attached" : "Detached",
+                               CCIC_NOTI_USB_STATUS_Print[event_work->event],
+                               event_work);
+               break;
+       default:
+               pr_info("usb:%s, dest=%s, id=%s, attach=%d, event=%d, event_work=%p\n", __func__,
+                       CCIC_NOTI_DEST_Print[event_work->dest],
+                       CCIC_NOTI_ID_Print[event_work->id],
+                       event_work->attach,
+                       event_work->event,
+                       event_work);
+               break;
+       }
+       ccic_noti.src = CCIC_NOTIFY_DEV_CCIC;
+       ccic_noti.dest = event_work->dest;
+       ccic_noti.id = event_work->id;
+       ccic_noti.sub1 = event_work->attach;
+       ccic_noti.sub2 = event_work->event;
+       ccic_noti.sub3 = 0;
+#ifdef CONFIG_BATTERY_SAMSUNG
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       ccic_noti.pd = &pd_noti;
+#endif
+#endif
+       ccic_notifier_notify((CC_NOTI_TYPEDEF *)&ccic_noti, NULL, 0);
+
+       kfree(event_work);
+}
+
+extern void ccic_event_work(void *data, int dest, int id, int attach, int event)
+{
+       struct s2mu106_usbpd_data *usbpd_data = data;
+       struct ccic_state_work *event_work;
+
+
+       event_work = kmalloc(sizeof(struct ccic_state_work), GFP_ATOMIC);
+       pr_info("usb: %s,event_work(%p)\n", __func__, event_work);
+       INIT_WORK(&event_work->ccic_work, ccic_event_notifier);
+
+       event_work->dest = dest;
+       event_work->id = id;
+       event_work->attach = attach;
+       event_work->event = event;
+
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+       if (id == CCIC_NOTIFY_ID_USB) {
+               pr_info("usb: %s, dest=%d, event=%d, usbpd_data->data_role_dual=%d, usbpd_data->try_state_change=%d\n",
+                       __func__, dest, event, usbpd_data->data_role_dual, usbpd_data->try_state_change);
+
+               usbpd_data->data_role_dual = event;
+
+               if (usbpd_data->dual_role != NULL)
+                       dual_role_instance_changed(usbpd_data->dual_role);
+
+               if (usbpd_data->try_state_change &&
+                       (usbpd_data->data_role_dual != IFCONN_NOTIFY_EVENT_DETACH)) {
+                       /* Role change try and new mode detected */
+                       pr_info("usb: %s, reverse_completion\n", __func__);
+                       complete(&usbpd_data->reverse_completion);
+               }
+       }
+#endif
+
+       if (queue_work(usbpd_data->ccic_wq, &event_work->ccic_work) == 0) {
+               pr_info("usb: %s, event_work(%p) is dropped\n", __func__, event_work);
+               kfree(event_work);
+       }
+}
+#endif
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+static void ifconn_event_notifier(struct work_struct *data)
+{
+       struct ifconn_state_work *event_work =
+               container_of(data, struct ifconn_state_work, ifconn_work);
+
+       switch (event_work->id) {
+       case IFCONN_NOTIFY_ID_POWER_STATUS:
+       case IFCONN_NOTIFY_ID_DP_CONNECT:
+       case IFCONN_NOTIFY_ID_DP_HPD:
+       case IFCONN_NOTIFY_ID_DP_LINK_CONF:
+               ifconn_notifier_notify(IFCONN_NOTIFY_PDIC, event_work->dest,
+                                                       event_work->id, event_work->event,
+                                               IFCONN_NOTIFY_PARAM_DATA, event_work->data);
+               break;
+       default:
+               ifconn_notifier_notify(IFCONN_NOTIFY_CCIC, event_work->dest,
+                                                       event_work->id, event_work->event,
+                                               IFCONN_NOTIFY_PARAM_DATA, event_work->data);
+               break;
+       }
+
+       kfree(event_work);
+}
+
+extern void ifconn_event_work(void *pd_data, int dest, int id, int event, void *data)
+{
+       struct s2mu106_usbpd_data *usbpd_data = pd_data;
+       struct ifconn_state_work *event_work;
+
+       event_work = kmalloc(sizeof(struct ifconn_state_work), GFP_ATOMIC);
+       INIT_WORK(&event_work->ifconn_work, ifconn_event_notifier);
+
+       event_work->dest = dest;
+       event_work->id = id;
+       event_work->event = event;
+       event_work->data = data;
+
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+       if (id == IFCONN_NOTIFY_ID_USB) {
+               pr_info("usb: %s, dest=%d, event=%d, usbpd_data->data_role_dual=%d, usbpd_data->try_state_change=%d\n",
+                       __func__, dest, event, usbpd_data->data_role_dual, usbpd_data->try_state_change);
+
+               usbpd_data->data_role_dual = event;
+
+               if (usbpd_data->dual_role != NULL)
+                       dual_role_instance_changed(usbpd_data->dual_role);
+
+               if (usbpd_data->try_state_change &&
+                       (usbpd_data->data_role_dual != IFCONN_NOTIFY_EVENT_DETACH)) {
+                       /* Role change try and new mode detected */
+                       pr_info("usb: %s, reverse_completion\n", __func__);
+                       complete(&usbpd_data->reverse_completion);
+               }
+       }
+#endif
+
+       if (queue_work(usbpd_data->ifconn_wq, &event_work->ifconn_work) == 0) {
+               pr_info("usb: %s, event_work(%p) is dropped\n", __func__, event_work);
+               kfree(event_work);
+       }
+}
+#endif
+
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+static enum dual_role_property fusb_drp_properties[] = {
+       DUAL_ROLE_PROP_MODE,
+       DUAL_ROLE_PROP_PR,
+       DUAL_ROLE_PROP_DR,
+       DUAL_ROLE_PROP_VCONN_SUPPLY,
+};
+
+void role_swap_check(struct work_struct *wk)
+{
+       struct delayed_work *delay_work =
+               container_of(wk, struct delayed_work, work);
+       struct s2mu106_usbpd_data *usbpd_data =
+               container_of(delay_work, struct s2mu106_usbpd_data, role_swap_work);
+       int mode = 0;
+
+       pr_info("%s: ccic_set_dual_role check again.\n", __func__);
+       usbpd_data->try_state_change = 0;
+
+       if (usbpd_data->detach_valid) { /* modify here using pd_state */
+               pr_err("%s: ccic_set_dual_role reverse failed, set mode to DRP\n", __func__);
+               disable_irq(usbpd_data->irq);
+               /* exit from Disabled state and set mode to DRP */
+               mode =  TYPE_C_ATTACH_DRP;
+               s2mu106_rprd_mode_change(usbpd_data, mode);
+               enable_irq(usbpd_data->irq);
+       }
+}
+
+static int ccic_set_dual_role(struct dual_role_phy_instance *dual_role,
+                                  enum dual_role_property prop,
+                                  const unsigned int *val)
+{
+       struct s2mu106_usbpd_data *usbpd_data = dual_role_get_drvdata(dual_role);
+       struct i2c_client *i2c;
+
+       ifconn_notifier_event_t attached_state;
+       int mode;
+       int timeout = 0;
+       int ret = 0;
+
+       if (!usbpd_data) {
+               pr_err("%s : usbpd_data is null \n", __func__);
+               return -EINVAL;
+       }
+
+       i2c = usbpd_data->i2c;
+
+       /* Get Current Role */
+       attached_state = usbpd_data->data_role_dual;
+       pr_info("%s : request prop = %d , attached_state = %d\n", __func__, prop, attached_state);
+
+       if (attached_state != IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP
+           && attached_state != IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP) {
+               pr_err("%s : current mode : %d - just return \n", __func__, attached_state);
+               return 0;
+       }
+
+       if (attached_state == IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP
+           && *val == DUAL_ROLE_PROP_MODE_DFP) {
+               pr_err("%s : current mode : %d - request mode : %d just return \n",
+                       __func__, attached_state, *val);
+               return 0;
+       }
+
+       if (attached_state == IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP
+           && *val == DUAL_ROLE_PROP_MODE_UFP) {
+               pr_err("%s : current mode : %d - request mode : %d just return \n",
+                       __func__, attached_state, *val);
+               return 0;
+       }
+
+       if (attached_state == IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP) {
+               /* Current mode DFP and Source  */
+               pr_info("%s: try reversing, from Source to Sink\n", __func__);
+               /* turns off VBUS first */
+               vbus_turn_on_ctrl(usbpd_data, 0);
+#if defined(CONFIG_IFCONN_NOTIFIER)
+               /* muic */
+               ifconn_event_work(usbpd_data, IFCONN_NOTIFY_MUIC,
+                                       IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+#endif
+               /* exit from Disabled state and set mode to UFP */
+               mode =  TYPE_C_ATTACH_UFP;
+               usbpd_data->try_state_change = TYPE_C_ATTACH_UFP;
+               s2mu106_rprd_mode_change(usbpd_data, mode);
+       } else {
+               /* Current mode UFP and Sink  */
+               pr_info("%s: try reversing, from Sink to Source\n", __func__);
+               /* exit from Disabled state and set mode to UFP */
+               mode =  TYPE_C_ATTACH_DFP;
+               usbpd_data->try_state_change = TYPE_C_ATTACH_DFP;
+               s2mu106_rprd_mode_change(usbpd_data, mode);
+       }
+
+       reinit_completion(&usbpd_data->reverse_completion);
+       timeout =
+           wait_for_completion_timeout(&usbpd_data->reverse_completion,
+                                       msecs_to_jiffies
+                                       (DUAL_ROLE_SET_MODE_WAIT_MS));
+
+       if (!timeout) {
+               usbpd_data->try_state_change = 0;
+               pr_err("%s: reverse failed, set mode to DRP\n", __func__);
+               disable_irq(usbpd_data->irq);
+               /* exit from Disabled state and set mode to DRP */
+               mode =  TYPE_C_ATTACH_DRP;
+               s2mu106_rprd_mode_change(usbpd_data, mode);
+               enable_irq(usbpd_data->irq);
+               ret = -EIO;
+       } else {
+               pr_err("%s: reverse success, one more check\n", __func__);
+               schedule_delayed_work(&usbpd_data->role_swap_work, msecs_to_jiffies(DUAL_ROLE_SET_MODE_WAIT_MS));
+       }
+
+       dev_info(&i2c->dev, "%s -> data role : %d\n", __func__, *val);
+       return ret;
+}
+
+/* Decides whether userspace can change a specific property */
+int dual_role_is_writeable(struct dual_role_phy_instance *drp,
+                                 enum dual_role_property prop)
+{
+       if (prop == DUAL_ROLE_PROP_MODE)
+               return 1;
+       else
+               return 0;
+}
+
+/* Callback for "cat /sys/class/dual_role_usb/otg_default/<property>" */
+int dual_role_get_local_prop(struct dual_role_phy_instance *dual_role,
+                                   enum dual_role_property prop,
+                                   unsigned int *val)
+{
+       struct s2mu106_usbpd_data *usbpd_data = dual_role_get_drvdata(dual_role);
+
+       ifconn_notifier_event_t attached_state;
+       int power_role_dual;
+
+       if (!usbpd_data) {
+               pr_err("%s : usbpd_data is null : request prop = %d \n", __func__, prop);
+               return -EINVAL;
+       }
+       attached_state = usbpd_data->data_role_dual;
+       power_role_dual = usbpd_data->power_role_dual;
+
+       pr_info("%s : request prop = %d , attached_state = %d, power_role_dual = %d\n",
+               __func__, prop, attached_state, power_role_dual);
+
+       if (prop == DUAL_ROLE_PROP_VCONN_SUPPLY) {
+               if (usbpd_data->vconn_en)
+                       *val = DUAL_ROLE_PROP_VCONN_SUPPLY_YES;
+               else
+                       *val = DUAL_ROLE_PROP_VCONN_SUPPLY_NO;
+               return 0;
+       }
+
+       if (attached_state == IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP) {
+               if (prop == DUAL_ROLE_PROP_MODE)
+                       *val = DUAL_ROLE_PROP_MODE_DFP;
+               else if (prop == DUAL_ROLE_PROP_PR)
+                       *val = power_role_dual;
+               else if (prop == DUAL_ROLE_PROP_DR)
+                       *val = DUAL_ROLE_PROP_DR_HOST;
+               else
+                       return -EINVAL;
+       } else if (attached_state == IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP) {
+               if (prop == DUAL_ROLE_PROP_MODE)
+                       *val = DUAL_ROLE_PROP_MODE_UFP;
+               else if (prop == DUAL_ROLE_PROP_PR)
+                       *val = power_role_dual;
+               else if (prop == DUAL_ROLE_PROP_DR)
+                       *val = DUAL_ROLE_PROP_DR_DEVICE;
+               else
+                       return -EINVAL;
+       } else {
+               if (prop == DUAL_ROLE_PROP_MODE)
+                       *val = DUAL_ROLE_PROP_MODE_NONE;
+               else if (prop == DUAL_ROLE_PROP_PR)
+                       *val = DUAL_ROLE_PROP_PR_NONE;
+               else if (prop == DUAL_ROLE_PROP_DR)
+                       *val = DUAL_ROLE_PROP_DR_NONE;
+               else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Callback for "echo <value> >
+ *                      /sys/class/dual_role_usb/<name>/<property>"
+ * Block until the entire final state is reached.
+ * Blocking is one of the better ways to signal when the operation
+ * is done.
+ * This function tries to switch to Attached.SRC or Attached.SNK
+ * by forcing the mode into SRC or SNK.
+ * On failure, we fall back to Try.SNK state machine.
+ */
+int dual_role_set_prop(struct dual_role_phy_instance *dual_role,
+                             enum dual_role_property prop,
+                             const unsigned int *val)
+{
+       pr_info("%s : request prop = %d , *val = %d \n", __func__, prop, *val);
+       if (prop == DUAL_ROLE_PROP_MODE)
+               return ccic_set_dual_role(dual_role, prop, val);
+       else
+               return -EINVAL;
+}
+
+int dual_role_init(void *_data)
+{
+       struct s2mu106_usbpd_data *pdic_data = _data;
+       struct dual_role_phy_desc *desc;
+       struct dual_role_phy_instance *dual_role;
+
+       desc = devm_kzalloc(pdic_data->dev,
+                        sizeof(struct dual_role_phy_desc), GFP_KERNEL);
+       if (!desc) {
+               pr_err("unable to allocate dual role descriptor\n");
+               return -1;
+       }
+
+       desc->name = "otg_default";
+       desc->supported_modes = DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP;
+       desc->get_property = dual_role_get_local_prop;
+       desc->set_property = dual_role_set_prop;
+       desc->properties = fusb_drp_properties;
+       desc->num_properties = ARRAY_SIZE(fusb_drp_properties);
+       desc->property_is_writeable = dual_role_is_writeable;
+       dual_role =
+               devm_dual_role_instance_register(pdic_data->dev, desc);
+       dual_role->drv_data = pdic_data;
+       pdic_data->dual_role = dual_role;
+       pdic_data->desc = desc;
+       init_completion(&pdic_data->reverse_completion);
+       INIT_DELAYED_WORK(&pdic_data->role_swap_work, role_swap_check);
+
+       return 0;
+}
+#endif
diff --git a/drivers/ccic/usbpd_manager.c b/drivers/ccic/usbpd_manager.c
new file mode 100644 (file)
index 0000000..bbdce41
--- /dev/null
@@ -0,0 +1,1123 @@
+/*
+*      USB PD Driver - Device Policy Manager
+*/
+
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/ccic/usbpd.h>
+#include <linux/ccic/usbpd-s2mu106.h>
+#include <linux/of_gpio.h>
+
+#include <linux/muic/muic.h>
+#if defined(CONFIG_MUIC_NOTIFIER)
+#include <linux/muic/muic_notifier.h>
+#endif /* CONFIG_MUIC_NOTIFIER */
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+#include <linux/ccic/ccic_notifier.h>
+#endif
+
+#if (defined CONFIG_CCIC_NOTIFIER || defined CONFIG_DUAL_ROLE_USB_INTF\
+       || CONFIG_IFCONN_NOTIFIER)
+#include <linux/ccic/usbpd_ext.h>
+#endif
+
+/* switch device header */
+#if defined(CONFIG_SWITCH)
+#include <linux/switch.h>
+#endif /* CONFIG_SWITCH */
+
+#ifdef CONFIG_USB_HOST_NOTIFY
+#include <linux/usb_notify.h>
+#endif
+
+#include <linux/completion.h>
+#if defined(CONFIG_SWITCH)
+static struct switch_dev switch_dock = {
+       .name = "ccic_dock",
+};
+#endif
+
+static char DP_Pin_Assignment_Print[7][40] = {
+    {"DP_Pin_Assignment_None"},
+    {"DP_Pin_Assignment_A"},
+    {"DP_Pin_Assignment_B"},
+    {"DP_Pin_Assignment_C"},
+    {"DP_Pin_Assignment_D"},
+    {"DP_Pin_Assignment_E"},
+    {"DP_Pin_Assignment_F"},
+
+};
+
+#ifdef CONFIG_IFCONN_NOTIFIER
+void select_pdo(int num);
+void s2mu106_select_pdo(int num);
+void (*fp_select_pdo)(int num);
+
+void s2mu106_select_pdo(int num)
+{
+       struct usbpd_data *pd_data = pd_noti.pd_data;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       bool vbus_short;
+
+       pd_data->phy_ops.get_vbus_short_check(pd_data, &vbus_short);
+
+       if (vbus_short) {
+               pr_info(" %s : PDO(%d) is ignored becasue of vbus short\n",
+                               __func__, pd_noti.sink_status.selected_pdo_num);
+               return;
+       }
+
+       if (pd_noti.sink_status.selected_pdo_num == num)
+               return;
+       else if (num > pd_noti.sink_status.available_pdo_num)
+               pd_noti.sink_status.selected_pdo_num = pd_noti.sink_status.available_pdo_num;
+       else if (num < 1)
+               pd_noti.sink_status.selected_pdo_num = 1;
+       else
+               pd_noti.sink_status.selected_pdo_num = num;
+       pr_info(" %s : PDO(%d) is selected to change\n", __func__, pd_noti.sink_status.selected_pdo_num);
+
+       schedule_delayed_work(&manager->select_pdo_handler, msecs_to_jiffies(50));
+}
+
+void select_pdo(int num)
+{
+       if (fp_select_pdo)
+               fp_select_pdo(num);
+}
+#endif
+
+#ifdef CONFIG_CHECK_CTYPE_SIDE
+int usbpd_manager_get_side_check(void)
+{
+       struct usbpd_data *pd_data = pd_noti.pd_data;
+       int ret = 0;
+
+       ret = pd_data->phy_ops.get_side_check(pd_data);
+
+       return ret;
+}
+#endif
+void usbpd_manager_select_pdo_handler(struct work_struct *work)
+{
+       pr_info("%s: call select pdo handler\n", __func__);
+
+       usbpd_manager_inform_event(pd_noti.pd_data,
+                                                       MANAGER_NEW_POWER_SRC);
+
+}
+
+void usbpd_manager_select_pdo_cancel(struct device *dev)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       cancel_delayed_work_sync(&manager->select_pdo_handler);
+}
+
+void usbpd_manager_start_discover_msg_handler(struct work_struct *work)
+{
+       struct usbpd_manager_data *manager =
+               container_of(work, struct usbpd_manager_data,
+                                                                               start_discover_msg_handler.work);
+       pr_info("%s: call handler\n", __func__);
+
+       mutex_lock(&manager->vdm_mutex);
+       if (manager->alt_sended == 0 && manager->vdm_en == 1) {
+               usbpd_manager_inform_event(pd_noti.pd_data,
+                                               MANAGER_START_DISCOVER_IDENTITY);
+               manager->alt_sended = 1;
+       }
+       mutex_unlock(&manager->vdm_mutex);
+}
+
+void usbpd_manager_start_discover_msg_cancel(struct device *dev)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       cancel_delayed_work_sync(&manager->start_discover_msg_handler);
+}
+
+static void init_source_cap_data(struct usbpd_manager_data *_data)
+{
+/*     struct usbpd_data *pd_data = manager_to_usbpd(_data);
+       int val;                                                */
+       msg_header_type *msg_header = &_data->pd_data->source_msg_header;
+       data_obj_type *data_obj = &_data->pd_data->source_data_obj;
+
+       msg_header->msg_type = USBPD_Source_Capabilities;
+/*     pd_data->phy_ops.get_power_role(pd_data, &val);         */
+       msg_header->port_data_role = USBPD_DFP;
+       msg_header->spec_revision = 1;
+       msg_header->port_power_role = USBPD_SOURCE;
+       msg_header->num_data_objs = 1;
+
+       data_obj->power_data_obj.max_current = 500 / 10;
+       data_obj->power_data_obj.voltage = 5000 / 50;
+       data_obj->power_data_obj.supply = POWER_TYPE_FIXED;
+       data_obj->power_data_obj.data_role_swap = 1;
+       data_obj->power_data_obj.dual_role_power = 1;
+       data_obj->power_data_obj.usb_suspend_support = 1;
+       data_obj->power_data_obj.usb_comm_capable = 1;
+
+}
+
+static void init_sink_cap_data(struct usbpd_manager_data *_data)
+{
+/*     struct usbpd_data *pd_data = manager_to_usbpd(_data);
+       int val;                                                */
+       msg_header_type *msg_header = &_data->pd_data->sink_msg_header;
+       data_obj_type *data_obj = _data->pd_data->sink_data_obj;
+
+       msg_header->msg_type = USBPD_Sink_Capabilities;
+/*     pd_data->phy_ops.get_power_role(pd_data, &val);         */
+       msg_header->port_data_role = USBPD_UFP;
+       msg_header->spec_revision = 1;
+       msg_header->port_power_role = USBPD_SINK;
+       msg_header->num_data_objs = 2;
+
+       data_obj->power_data_obj_sink.supply_type = POWER_TYPE_FIXED;
+       data_obj->power_data_obj_sink.dual_role_power = 1;
+       data_obj->power_data_obj_sink.higher_capability = 1;
+       data_obj->power_data_obj_sink.externally_powered = 0;
+       data_obj->power_data_obj_sink.usb_comm_capable = 1;
+       data_obj->power_data_obj_sink.data_role_swap = 1;
+       data_obj->power_data_obj_sink.voltage = 5000/50;
+       data_obj->power_data_obj_sink.op_current = 500/10;
+
+       (data_obj + 1)->power_data_obj_variable.supply_type = POWER_TYPE_VARIABLE;
+       (data_obj + 1)->power_data_obj_variable.max_voltage = _data->sink_cap_max_volt / 50;
+       (data_obj + 1)->power_data_obj_variable.min_voltage = 5000 / 50;
+       (data_obj + 1)->power_data_obj_variable.max_current = 500 / 10;
+}
+
+void usbpd_manager_receive_samsung_uvdm_message(struct usbpd_data *pd_data)
+{
+}
+
+void usbpd_manager_plug_attach(struct device *dev)
+{
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       struct s2mu106_usbpd_data *pdic_data = pd_data->phy_driver_data;
+       struct policy_data *policy = &pd_data->policy;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       if (policy->send_sink_cap) {
+               pd_noti.event = IFCONN_NOTIFY_EVENT_PD_SINK_CAP;
+               policy->send_sink_cap = 0;
+       } else
+               pd_noti.event = IFCONN_NOTIFY_EVENT_PD_SINK;
+       manager->template.data = &pd_noti.sink_status;
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MANAGER,
+               IFCONN_NOTIFY_ID_POWER_STATUS, IFCONN_NOTIFY_EVENT_ATTACH, &pd_noti);
+#endif
+}
+
+void usbpd_manager_plug_detach(struct device *dev, bool notify)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+
+       pr_info("%s: usbpd plug detached\n", __func__);
+
+       usbpd_policy_reset(pd_data, PLUG_DETACHED);
+}
+
+void usbpd_manager_acc_detach(struct device *dev)
+{      
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       pr_info("%s\n", __func__);
+       if ( manager->acc_type != CCIC_DOCK_DETACHED ) {
+               pr_info("%s: schedule_delayed_work \n", __func__);
+               if ( manager->acc_type == CCIC_DOCK_HMT )
+                       schedule_delayed_work(&manager->acc_detach_handler, msecs_to_jiffies(1000));
+               else
+                       schedule_delayed_work(&manager->acc_detach_handler, msecs_to_jiffies(0));
+       }       
+}
+
+int usbpd_manager_command_to_policy(struct device *dev,
+               usbpd_manager_command_type command)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       manager->cmd |= command;
+
+       usbpd_kick_policy_work(dev);
+
+       /* TODO: check result
+       if (manager->event) {
+        ...
+       }
+       */
+       return 0;
+}
+
+void usbpd_manager_inform_event(struct usbpd_data *pd_data,
+               usbpd_manager_event_type event)
+{
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       int ret = 0;
+
+       manager->event = event;
+
+       switch (event) {
+       case MANAGER_DISCOVER_IDENTITY_ACKED:
+               usbpd_manager_get_identity(pd_data);
+               usbpd_manager_command_to_policy(pd_data->dev,
+                               MANAGER_REQ_VDM_DISCOVER_SVID);
+               break;
+       case MANAGER_DISCOVER_SVID_ACKED:
+               usbpd_manager_get_svids(pd_data);
+               usbpd_manager_command_to_policy(pd_data->dev,
+                               MANAGER_REQ_VDM_DISCOVER_MODE);
+               break;
+       case MANAGER_DISCOVER_MODE_ACKED:
+               ret = usbpd_manager_get_modes(pd_data);
+               if (ret == USBPD_DP_SUPPORT)
+                       usbpd_manager_command_to_policy(pd_data->dev,
+                                                               MANAGER_REQ_VDM_ENTER_MODE);
+               break;
+       case MANAGER_ENTER_MODE_ACKED:
+               usbpd_manager_enter_mode(pd_data);
+               usbpd_manager_command_to_policy(pd_data->dev,
+                       MANAGER_REQ_VDM_STATUS_UPDATE);
+               break;
+       case MANAGER_STATUS_UPDATE_ACKED:
+               usbpd_manager_get_status(pd_data);
+               usbpd_manager_command_to_policy(pd_data->dev,
+                       MANAGER_REQ_VDM_DisplayPort_Configure);
+               break;
+       case MANAGER_DisplayPort_Configure_ACKED:
+               usbpd_manager_get_configure(pd_data);
+               break;
+       case MANAGER_ATTENTION_REQUEST:
+               usbpd_manager_get_attention(pd_data);
+               break;
+       case MANAGER_NEW_POWER_SRC:
+               usbpd_manager_command_to_policy(pd_data->dev,
+                               MANAGER_REQ_NEW_POWER_SRC);
+               break;
+       case MANAGER_UVDM_SEND_MESSAGE:
+               usbpd_manager_command_to_policy(pd_data->dev,
+                               MANAGER_REQ_UVDM_SEND_MESSAGE);
+               break;
+       case MANAGER_UVDM_RECEIVE_MESSAGE:
+               usbpd_manager_receive_samsung_uvdm_message(pd_data);
+               break;
+       case MANAGER_START_DISCOVER_IDENTITY:
+               usbpd_manager_command_to_policy(pd_data->dev,
+                                       MANAGER_REQ_VDM_DISCOVER_IDENTITY);
+               break;
+       default:
+               pr_info("%s: not matched event(%d)\n", __func__, event);
+       }
+}
+
+bool usbpd_manager_vdm_request_enabled(struct usbpd_data *pd_data)
+{
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       /* TODO : checking cable discovering
+          if (pd_data->counter.discover_identity_counter
+                  < USBPD_nDiscoverIdentityCount)
+
+          struct usbpd_manager_data *manager = &pd_data->manager;
+          if (manager->event != MANAGER_DISCOVER_IDENTITY_ACKED
+             || manager->event != MANAGER_DISCOVER_IDENTITY_NAKED)
+
+          return(1);
+       */
+
+       manager->vdm_en = 1;
+
+       schedule_delayed_work(&manager->start_discover_msg_handler,
+                                                                                       msecs_to_jiffies(50));
+       return true;
+}
+
+bool usbpd_manager_power_role_swap(struct usbpd_data *pd_data)
+{
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       return manager->power_role_swap;
+}
+
+bool usbpd_manager_vconn_source_swap(struct usbpd_data *pd_data)
+{
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       return manager->vconn_source_swap;
+}
+
+void usbpd_manager_turn_off_vconn(struct usbpd_data *pd_data)
+{
+       /* TODO : Turn off vconn */
+}
+
+void usbpd_manager_turn_on_source(struct usbpd_data *pd_data)
+{
+       pr_info("%s: usbpd plug attached\n", __func__);
+
+       /* TODO : Turn on source */
+}
+
+void usbpd_manager_turn_off_power_supply(struct usbpd_data *pd_data)
+{
+       pr_info("%s: usbpd plug detached\n", __func__);
+
+       /* TODO : Turn off power supply */
+}
+
+void usbpd_manager_turn_off_power_sink(struct usbpd_data *pd_data)
+{
+       struct s2mu106_usbpd_data *pdic_data = pd_data->phy_driver_data;
+
+       pr_info("%s: usbpd sink turn off\n", __func__);
+
+       /* TODO : Turn off power sink */
+       pd_noti.event = IFCONN_NOTIFY_EVENT_DETACH;
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_BATTERY,
+                                       IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+}
+
+bool usbpd_manager_data_role_swap(struct usbpd_data *pd_data)
+{
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       return manager->data_role_swap;
+}
+
+int usbpd_manager_register_switch_device(int mode)
+{
+#ifdef CONFIG_SWITCH
+       int ret = 0;
+       if (mode) {
+               ret = switch_dev_register(&switch_dock);
+               if (ret < 0) {
+                       pr_err("%s: Failed to register dock switch(%d)\n",
+                              __func__, ret);
+                       return -ENODEV;
+               }
+       } else {
+               switch_dev_unregister(&switch_dock);
+       }
+#endif /* CONFIG_SWITCH */
+       return 0;
+}
+
+static void usbpd_manager_send_dock_intent(int type)
+{
+       pr_info("%s: CCIC dock type(%d)\n", __func__, type);
+#ifdef CONFIG_SWITCH
+       switch_set_state(&switch_dock, type);
+#endif /* CONFIG_SWITCH */
+}
+
+void usbpd_manager_send_dock_uevent(u32 vid, u32 pid, int state)
+{
+       char switch_string[32];
+       char pd_ids_string[32];
+
+       pr_info("%s: CCIC dock : USBPD_IPS=%04x:%04x SWITCH_STATE=%d\n",
+                       __func__,
+                       le16_to_cpu(vid),
+                       le16_to_cpu(pid),
+                       state);
+
+
+       snprintf(switch_string, 32, "SWITCH_STATE=%d", state);
+       snprintf(pd_ids_string, 32, "USBPD_IDS=%04x:%04x",
+                       le16_to_cpu(vid),
+                       le16_to_cpu(pid));
+}
+
+void usbpd_manager_acc_detach_handler(struct work_struct *wk)
+{
+       struct usbpd_manager_data *manager =
+               container_of(wk, struct usbpd_manager_data, acc_detach_handler.work);
+
+       pr_info("%s: ccic dock type %d\n", __func__,
+                                                                                               manager->acc_type);
+       if (manager->acc_type != CCIC_DOCK_DETACHED) {
+               if (manager->acc_type != CCIC_DOCK_NEW)
+                       usbpd_manager_send_dock_intent(CCIC_DOCK_DETACHED);
+               usbpd_manager_send_dock_uevent(manager->Vendor_ID, manager->Product_ID,
+                               CCIC_DOCK_DETACHED);
+               manager->acc_type = CCIC_DOCK_DETACHED;
+               manager->Vendor_ID = 0;
+               manager->Product_ID = 0;
+               manager->is_samsung_accessory_enter_mode = false;
+       }
+}
+
+void usbpd_manager_acc_handler_cancel(struct device *dev)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       if (manager->acc_type != CCIC_DOCK_DETACHED) {
+               pr_info("%s: cancel_delayed_work_sync \n", __func__);
+               cancel_delayed_work_sync(&manager->acc_detach_handler);
+       }
+}
+
+static int usbpd_manager_check_accessory(struct usbpd_manager_data *manager)
+{
+#if defined(CONFIG_USB_HW_PARAM)
+       struct otg_notify *o_notify = get_otg_notify();
+#endif
+       uint16_t vid = manager->Vendor_ID;
+       uint16_t pid = manager->Product_ID;
+       uint16_t acc_type = CCIC_DOCK_DETACHED;
+
+       /* detect Gear VR */
+       if (manager->acc_type == CCIC_DOCK_DETACHED) {
+               if (vid == SAMSUNG_VENDOR_ID) {
+                       switch (pid) {
+                       /* GearVR: Reserved GearVR PID+6 */
+                       case GEARVR_PRODUCT_ID:
+                       case GEARVR_PRODUCT_ID_1:
+                       case GEARVR_PRODUCT_ID_2:
+                       case GEARVR_PRODUCT_ID_3:
+                       case GEARVR_PRODUCT_ID_4:
+                       case GEARVR_PRODUCT_ID_5:
+                               acc_type = CCIC_DOCK_HMT;
+                               pr_info("%s : Samsung Gear VR connected.\n", __func__);
+#if defined(CONFIG_USB_HW_PARAM)
+                               if (o_notify)
+                                       inc_hw_param(o_notify, USB_CCIC_VR_USE_COUNT);
+#endif
+                               break;
+                       case DEXDOCK_PRODUCT_ID:
+                               acc_type = CCIC_DOCK_DEX;
+                               pr_info("%s : Samsung DEX connected.\n", __func__);
+#if defined(CONFIG_USB_HW_PARAM)
+                               if (o_notify)
+                                       inc_hw_param(o_notify, USB_CCIC_DEX_USE_COUNT);
+#endif
+                               break;
+                       case HDMI_PRODUCT_ID:
+                               acc_type = CCIC_DOCK_HDMI;
+                               pr_info("%s : Samsung HDMI connected.\n", __func__);
+                               break;
+                       default:
+                               acc_type = CCIC_DOCK_NEW;
+                               pr_info("%s : default device connected.\n", __func__);
+                               break;
+                       }
+               } else if (vid == SAMSUNG_MPA_VENDOR_ID) {
+                       switch(pid) {
+                       case MPA_PRODUCT_ID:
+                               acc_type = CCIC_DOCK_MPA;
+                               pr_info("%s : Samsung MPA connected.\n", __func__);
+                               break;
+                       default:
+                               acc_type = CCIC_DOCK_NEW;
+                               pr_info("%s : default device connected.\n", __func__);
+                               break;
+                       }
+               }
+               manager->acc_type = acc_type;
+       } else 
+               acc_type = manager->acc_type;
+
+       if (acc_type != CCIC_DOCK_NEW) 
+               usbpd_manager_send_dock_intent(acc_type);
+
+       usbpd_manager_send_dock_uevent(vid, pid, acc_type);
+       return 1;
+}
+
+/* Ok : 0, NAK: -1 */
+int usbpd_manager_get_identity(struct usbpd_data *pd_data)
+{
+       struct policy_data *policy = &pd_data->policy;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       manager->Vendor_ID = policy->rx_data_obj[1].id_header_vdo.USB_Vendor_ID;
+       manager->Product_ID = policy->rx_data_obj[3].product_vdo.USB_Product_ID;
+       manager->Device_Version = policy->rx_data_obj[3].product_vdo.Device_Version;
+
+       pr_info("%s, Vendor_ID : 0x%x, Product_ID : 0x%x, Device Version : 0x%x\n",
+                       __func__, manager->Vendor_ID, manager->Product_ID, manager->Device_Version);
+
+       if (usbpd_manager_check_accessory(manager))
+               pr_info("%s, Samsung Accessory Connected.\n", __func__);
+
+       return 0;
+}
+
+/* Ok : 0, NAK: -1 */
+int usbpd_manager_get_svids(struct usbpd_data *pd_data)
+{
+       struct policy_data *policy = &pd_data->policy;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       struct s2mu106_usbpd_data *pdic_data = pd_data->phy_driver_data;
+
+       manager->SVID_0 = policy->rx_data_obj[1].vdm_svid.svid_0;
+       manager->SVID_1 = policy->rx_data_obj[1].vdm_svid.svid_1;
+
+       pr_info("%s, SVID_0 : 0x%x, SVID_1 : 0x%x\n", __func__,
+                               manager->SVID_0, manager->SVID_1);
+
+       if (manager->SVID_0 == TypeC_DP_SUPPORT) {
+#if defined(CONFIG_IFCONN_NOTIFIER)
+               if (pdic_data->is_client == CLIENT_ON) {
+                       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+                               IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+                       pdic_data->power_role = DUAL_ROLE_PROP_PR_NONE;
+#endif
+                       ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB,
+                               IFCONN_NOTIFY_ID_USB, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+                       pdic_data->is_client = CLIENT_OFF;
+               }
+
+               if (pdic_data->is_host == HOST_OFF) {
+                       /* muic */
+                       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+                               IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_ATTACH, NULL);
+                       /* otg */
+                       pdic_data->is_host = HOST_ON;
+
+                       ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB,
+                                       IFCONN_NOTIFY_ID_USB,
+                                       IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP, NULL);
+               }
+#endif
+               manager->dp_is_connect = 1;
+               /* If you want to support USB SuperSpeed when you connect
+                * Display port dongle, You should change dp_hs_connect depend
+                * on Pin assignment.If DP use 4lane(Pin Assignment C,E,A),
+                * dp_hs_connect is 1. USB can support HS.If DP use 2lane(Pin Assigment B,D,F), dp_hs_connect is 0. USB
+                * can support SS */
+               manager->dp_hs_connect = 1;
+
+               /* sub is only used here to pass the Product_ID */
+               /* template->sub1 = pd_info->Product_ID; */
+               /* USBPD_SEND_DATA_NOTI_DP(DP_CONNECT,
+                               pd_info->Vendor_ID, &pd_info->Product_ID); */
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_MANAGER,
+                               IFCONN_NOTIFY_ID_DP_CONNECT,
+                               IFCONN_NOTIFY_EVENT_ATTACH, manager);
+
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_MANAGER,
+                               IFCONN_NOTIFY_ID_USB_DP, manager->dp_hs_connect, manager);
+       }
+
+       return 0;
+}
+
+/* Ok : 0, NAK: -1 */
+int usbpd_manager_get_modes(struct usbpd_data *pd_data)
+{
+       struct policy_data *policy = &pd_data->policy;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       data_obj_type *pd_obj = &policy->rx_data_obj[1];
+
+       manager->Standard_Vendor_ID = policy->rx_data_obj[0].structured_vdm.svid;
+
+       pr_info("%s, Standard_Vendor_ID = 0x%x\n", __func__,
+                               manager->Standard_Vendor_ID);
+
+       if (manager->Standard_Vendor_ID == TypeC_DP_SUPPORT &&
+                       manager->SVID_0 == TypeC_DP_SUPPORT) {
+               if (policy->rx_msg_header.num_data_objs > 1) {
+                       if (((pd_obj->displayport_capabilities.port_capability == num_UFP_D_Capable)
+                               && (pd_obj->displayport_capabilities.receptacle_indication == num_USB_TYPE_C_Receptacle))
+                               || ((pd_obj->displayport_capabilities.port_capability == num_DFP_D_Capable)
+                               && (pd_obj->displayport_capabilities.receptacle_indication == num_USB_TYPE_C_PLUG))) {
+
+                               manager->pin_assignment = pd_obj->displayport_capabilities.ufp_d_pin_assignments;
+                               pr_info("%s, support UFP_D %d\n", __func__, manager->pin_assignment);
+                       } else if (((pd_obj->displayport_capabilities.port_capability == num_DFP_D_Capable)
+                               && (pd_obj->displayport_capabilities.receptacle_indication == num_USB_TYPE_C_Receptacle))
+                               || ((pd_obj->displayport_capabilities.port_capability == num_UFP_D_Capable)
+                               && (pd_obj->displayport_capabilities.receptacle_indication == num_USB_TYPE_C_PLUG))) {
+
+                               manager->pin_assignment = pd_obj->displayport_capabilities.dfp_d_pin_assignments;
+                               pr_info("%s, support DFP_D %d\n", __func__, manager->pin_assignment);
+                       } else if (pd_obj->displayport_capabilities.port_capability == num_DFP_D_and_UFP_D_Capable) {
+                               if (pd_obj->displayport_capabilities.receptacle_indication == num_USB_TYPE_C_PLUG) {
+
+                                       manager->pin_assignment = pd_obj->displayport_capabilities.dfp_d_pin_assignments;
+                                       pr_info("%s, support DFP_D %d\n", __func__, manager->pin_assignment);
+                               } else {
+                                       manager->pin_assignment = pd_obj->displayport_capabilities.ufp_d_pin_assignments;
+                                       pr_info("%s, support UFP_D %d\n", __func__, manager->pin_assignment);
+                               }
+                       } else {
+                               manager->pin_assignment = DP_PIN_ASSIGNMENT_NODE;
+                               pr_info("%s, there is not valid object %d\n", __func__, manager->pin_assignment);
+                       }
+               }
+
+               return USBPD_DP_SUPPORT;
+       }
+
+       return USBPD_NOT_DP;
+}
+
+int usbpd_manager_enter_mode(struct usbpd_data *pd_data)
+{
+       struct policy_data *policy = &pd_data->policy;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       manager->Standard_Vendor_ID = policy->rx_data_obj[0].structured_vdm.svid;
+       manager->is_samsung_accessory_enter_mode = true;
+       return 0;
+}
+
+int usbpd_manager_exit_mode(struct usbpd_data *pd_data, unsigned mode)
+{
+       return 0;
+}
+
+int usbpd_manager_get_status(struct usbpd_data *pd_data)
+{
+       struct policy_data *policy = &pd_data->policy;
+       struct s2mu106_usbpd_data *pdic_data = pd_data->phy_driver_data;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       bool multi_func_preference = 0;
+       int pin_assignment = 0;
+       data_obj_type *pd_obj = &policy->rx_data_obj[1];
+
+       if (manager->SVID_0 != TypeC_DP_SUPPORT)
+               return 0;
+
+       if (pd_obj->displayport_status.port_connected == 0) {
+               pr_info("%s, port disconnected!\n", __func__);
+       }
+
+       if (manager->is_sent_pin_configuration) {
+               pr_info("%s, already sent pin configuration\n", __func__);
+       }
+
+       if (pd_obj->displayport_status.port_connected &&
+                       !manager->is_sent_pin_configuration) {
+               multi_func_preference = pd_obj->displayport_status.multi_function_preferred;
+
+               if (multi_func_preference) {
+                       if(manager->pin_assignment & DP_PIN_ASSIGNMENT_D) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_D;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_B) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_B;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_F) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_F;
+                       } else {
+                               pr_info("wrong pin assignment value\n");
+                       }
+               } else {
+                       if(manager->pin_assignment & DP_PIN_ASSIGNMENT_C) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_C;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_E) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_E;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_A) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_A;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_D) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_D;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_B) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_B;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_F) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_F;
+                       } else {
+                               pr_info("wrong pin assignment value\n");
+                       }
+               }
+               manager->dp_selected_pin = pin_assignment;
+
+               manager->is_sent_pin_configuration = 1;
+
+               pr_info("%s multi_func_preference %d  %s\n", __func__,
+                       multi_func_preference, DP_Pin_Assignment_Print[pin_assignment]);
+       }
+
+       if (pd_obj->displayport_status.hpd_state)
+               manager->hpd = IFCONN_NOTIFY_HIGH;
+       else
+               manager->hpd = IFCONN_NOTIFY_LOW;
+
+       if (pd_obj->displayport_status.irq_hpd)
+               manager->hpdirq = IFCONN_NOTIFY_IRQ;
+
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MANAGER,
+                                       IFCONN_NOTIFY_ID_DP_HPD, manager->hpdirq, manager);
+
+       return 0;
+}
+
+int usbpd_manager_get_configure(struct usbpd_data *pd_data)
+{
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       struct s2mu106_usbpd_data *pdic_data = pd_data->phy_driver_data;
+
+       if (manager->SVID_0 == TypeC_DP_SUPPORT)
+               ifconn_event_work(pdic_data, IFCONN_NOTIFY_MANAGER,
+                                               IFCONN_NOTIFY_ID_DP_LINK_CONF,
+                                               IFCONN_NOTIFY_EVENT_ATTACH, manager);
+       
+       return 0;
+}
+
+int usbpd_manager_get_attention(struct usbpd_data *pd_data)
+{
+       struct policy_data *policy = &pd_data->policy;
+       struct s2mu106_usbpd_data *pdic_data = pd_data->phy_driver_data;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       bool multi_func_preference = 0;
+       int pin_assignment = 0;
+       data_obj_type *pd_obj = &policy->rx_data_obj[1];
+
+       if (manager->SVID_0 != TypeC_DP_SUPPORT)
+               return 0;
+
+       if (pd_obj->displayport_status.port_connected == 0) {
+               pr_info("%s, port disconnected!\n", __func__);
+       }
+
+       if (manager->is_sent_pin_configuration) {
+               pr_info("%s, already sent pin configuration\n", __func__);
+       }
+
+       if (pd_obj->displayport_status.port_connected &&
+                       !manager->is_sent_pin_configuration) {
+               multi_func_preference = pd_obj->displayport_status.multi_function_preferred;
+
+               if (multi_func_preference) {
+                       if(manager->pin_assignment & DP_PIN_ASSIGNMENT_D) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_D;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_B) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_B;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_F) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_F;
+                       } else {
+                               pr_info("wrong pin assignment value\n");
+                       }
+               } else {
+                       if(manager->pin_assignment & DP_PIN_ASSIGNMENT_C) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_C;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_E) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_E;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_A) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_A;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_D) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_D;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_B) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_B;
+                       } else if(manager->pin_assignment & DP_PIN_ASSIGNMENT_F) {
+                               pin_assignment = IFCONN_NOTIFY_DP_PIN_F;
+                       } else {
+                               pr_info("wrong pin assignment value\n");
+                       }
+               }
+               manager->dp_selected_pin = pin_assignment;
+
+               manager->is_sent_pin_configuration = 1;
+
+               pr_info("%s multi_func_preference %d  %s\n", __func__,
+                       multi_func_preference, DP_Pin_Assignment_Print[pin_assignment]);
+       }
+
+       if (pd_obj->displayport_status.hpd_state)
+               manager->hpd = IFCONN_NOTIFY_HIGH;
+       else
+               manager->hpd = IFCONN_NOTIFY_LOW;
+
+       if (pd_obj->displayport_status.irq_hpd)
+               manager->hpdirq = IFCONN_NOTIFY_IRQ;
+
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MANAGER,
+                                       IFCONN_NOTIFY_ID_DP_HPD, manager->hpdirq, manager);
+
+       return 0;
+}
+
+void usbpd_dp_detach(struct usbpd_data *pd_data)
+{
+       struct s2mu106_usbpd_data *pdic_data = pd_data->phy_driver_data;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       dev_info(pd_data->dev, "%s: dp_is_connect %d\n", __func__, manager->dp_is_connect);
+
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MANAGER,
+                               IFCONN_NOTIFY_ID_USB_DP, manager->dp_hs_connect, NULL);
+       ifconn_event_work(pdic_data, IFCONN_NOTIFY_MANAGER,
+                               IFCONN_NOTIFY_ID_DP_CONNECT, IFCONN_NOTIFY_EVENT_DETACH, NULL);
+
+       manager->dp_is_connect = 0;
+       manager->dp_hs_connect = 0;
+       manager->is_sent_pin_configuration = 0;
+
+       return;
+}
+
+data_obj_type usbpd_manager_select_capability(struct usbpd_data *pd_data)
+{
+       /* TODO: Request from present capabilities
+               indicate if other capabilities would be required */
+       data_obj_type obj;
+#ifdef CONFIG_IFCONN_NOTIFIER
+       int pdo_num = pd_noti.sink_status.selected_pdo_num;
+#endif
+       obj.request_data_object.no_usb_suspend = 1;
+       obj.request_data_object.usb_comm_capable = 1;
+       obj.request_data_object.capability_mismatch = 0;
+       obj.request_data_object.give_back = 0;
+#ifdef CONFIG_IFCONN_NOTIFIER
+       obj.request_data_object.min_current = pd_noti.sink_status.power_list[pdo_num].max_current / USBPD_CURRENT_UNIT;
+       obj.request_data_object.op_current = pd_noti.sink_status.power_list[pdo_num].max_current / USBPD_CURRENT_UNIT;
+       obj.request_data_object.object_position = pd_noti.sink_status.selected_pdo_num;
+#endif
+
+       return obj;
+}
+
+/*
+   usbpd_manager_evaluate_capability
+   : Policy engine ask Device Policy Manager to evaluate option
+     based on supplied capabilities
+       return  >0      : request object number
+               0       : no selected option
+*/
+int usbpd_manager_evaluate_capability(struct usbpd_data *pd_data)
+{
+       struct policy_data *policy = &pd_data->policy;
+       int i = 0;
+       int power_type = 0;
+       int pd_volt = 0, pd_current;
+#ifdef CONFIG_IFCONN_NOTIFIER
+       int available_pdo_num = 0;
+       ifconn_pd_sink_status_t *pdic_sink_status = &pd_noti.sink_status;
+#endif
+       data_obj_type *pd_obj;
+
+       for (i = 0; i < policy->rx_msg_header.num_data_objs; i++) {
+               pd_obj = &policy->rx_data_obj[i];
+               power_type = pd_obj->power_data_obj_supply_type.supply_type;
+               switch (power_type) {
+               case POWER_TYPE_FIXED:
+                       pd_volt = pd_obj->power_data_obj.voltage;
+                       pd_current = pd_obj->power_data_obj.max_current;
+                       dev_info(pd_data->dev, "[%d] FIXED volt(%d)mV, max current(%d)\n",
+                                       i+1, pd_volt * USBPD_VOLT_UNIT, pd_current * USBPD_CURRENT_UNIT);
+#ifdef CONFIG_IFCONN_NOTIFIER
+                       if (pd_volt * USBPD_VOLT_UNIT <= MAX_CHARGING_VOLT)
+                               available_pdo_num = i + 1;
+                       pdic_sink_status->power_list[i + 1].max_voltage = pd_volt * USBPD_VOLT_UNIT;
+                       pdic_sink_status->power_list[i + 1].max_current = pd_current * USBPD_CURRENT_UNIT;
+#endif
+                       break;
+               case POWER_TYPE_BATTERY:
+                       pd_volt = pd_obj->power_data_obj_battery.max_voltage;
+                       dev_info(pd_data->dev, "[%d] BATTERY volt(%d)mV\n",
+                                       i+1, pd_volt * USBPD_VOLT_UNIT);
+                       break;
+               case POWER_TYPE_VARIABLE:
+                       pd_volt = pd_obj->power_data_obj_variable.max_voltage;
+                       dev_info(pd_data->dev, "[%d] VARIABLE volt(%d)mV\n",
+                                       i+1, pd_volt * USBPD_VOLT_UNIT);
+                       break;
+               default:
+                       dev_err(pd_data->dev, "[%d] Power Type Error\n", i+1);
+                       break;
+               }
+       }
+#ifdef CONFIG_IFCONN_NOTIFIER
+       pdic_sink_status->available_pdo_num = available_pdo_num;
+       return available_pdo_num;
+#else
+       return 1; /* select default first obj */
+#endif
+}
+
+/* return: 0: cab be met, -1: cannot be met, -2: could be met later */
+int usbpd_manager_match_request(struct usbpd_data *pd_data)
+{
+       /* TODO: Evaluation of sink request */
+
+       unsigned supply_type
+       = pd_data->source_request_obj.power_data_obj_supply_type.supply_type;
+       unsigned mismatch, max_min, op, pos;
+
+       if (supply_type == POWER_TYPE_FIXED) {
+               pr_info("REQUEST: FIXED\n");
+               goto log_fixed_variable;
+       } else if (supply_type == POWER_TYPE_VARIABLE) {
+               pr_info("REQUEST: VARIABLE\n");
+               goto log_fixed_variable;
+       } else if (supply_type == POWER_TYPE_BATTERY) {
+               pr_info("REQUEST: BATTERY\n");
+               goto log_battery;
+       } else {
+               pr_info("REQUEST: UNKNOWN Supply type.\n");
+               return -1;
+       }
+
+log_fixed_variable:
+       mismatch = pd_data->source_request_obj.request_data_object.capability_mismatch;
+       max_min = pd_data->source_request_obj.request_data_object.min_current;
+       op = pd_data->source_request_obj.request_data_object.op_current;
+       pos = pd_data->source_request_obj.request_data_object.object_position;
+       pr_info("Obj position: %d\n", pos);
+       pr_info("Mismatch: %d\n", mismatch);
+       pr_info("Operating Current: %d mA\n", op*10);
+       if (pd_data->source_request_obj.request_data_object.give_back)
+               pr_info("Min current: %d mA\n", max_min*10);
+       else
+               pr_info("Max current: %d mA\n", max_min*10);
+
+       return 0;
+
+log_battery:
+       mismatch = pd_data->source_request_obj.request_data_object_battery.capability_mismatch;
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static int of_usbpd_manager_dt(struct usbpd_manager_data *_data)
+{
+       int ret = 0;
+       struct device_node *np =
+               of_find_node_by_name(NULL, "pdic-manager");
+
+       if (np == NULL) {
+               pr_err("%s np NULL\n", __func__);
+               return -EINVAL;
+       } else {
+               ret = of_property_read_u32(np, "pdic,max_power",
+                               &_data->max_power);
+               if (ret < 0)
+                       pr_err("%s error reading max_power %d\n",
+                                       __func__, _data->max_power);
+
+               ret = of_property_read_u32(np, "pdic,op_power",
+                               &_data->op_power);
+               if (ret < 0)
+                       pr_err("%s error reading op_power %d\n",
+                                       __func__, _data->max_power);
+
+               ret = of_property_read_u32(np, "pdic,max_current",
+                               &_data->max_current);
+               if (ret < 0)
+                       pr_err("%s error reading max_current %d\n",
+                                       __func__, _data->max_current);
+
+               ret = of_property_read_u32(np, "pdic,min_current",
+                               &_data->min_current);
+               if (ret < 0)
+                       pr_err("%s error reading min_current %d\n",
+                                       __func__, _data->min_current);
+
+               _data->giveback = of_property_read_bool(np,
+                                                    "pdic,giveback");
+               _data->usb_com_capable = of_property_read_bool(np,
+                                                    "pdic,usb_com_capable");
+               _data->no_usb_suspend = of_property_read_bool(np,
+                                                    "pdic,no_usb_suspend");
+
+               /* source capability */
+               ret = of_property_read_u32(np, "source,max_voltage",
+                               &_data->source_max_volt);
+               ret = of_property_read_u32(np, "source,min_voltage",
+                               &_data->source_min_volt);
+               ret = of_property_read_u32(np, "source,max_power",
+                               &_data->source_max_power);
+
+               /* sink capability */
+               ret = of_property_read_u32(np, "sink,capable_max_voltage",
+                               &_data->sink_cap_max_volt);
+               if (ret < 0) {
+                       _data->sink_cap_max_volt = 5000;
+                       pr_err("%s error reading sink_cap_max_volt %d\n",
+                                       __func__, _data->sink_cap_max_volt);
+               }
+       }
+
+       return ret;
+}
+#endif
+
+void usbpd_init_manager_val(struct usbpd_data *pd_data)
+{
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       pr_info("%s\n", __func__);
+       manager->alt_sended = 0;
+       manager->cmd = 0;
+       manager->vdm_en = 0;
+       manager->Vendor_ID = 0;
+       manager->Product_ID = 0;
+       manager->Device_Version = 0;
+       manager->SVID_0 = 0;
+       manager->SVID_1 = 0;
+       manager->Standard_Vendor_ID = 0;
+       manager->dp_is_connect = 0;
+       manager->dp_hs_connect = 0;
+       manager->is_sent_pin_configuration = 0;
+       manager->pin_assignment = 0;
+       manager->dp_selected_pin = 0;
+       manager->hpd = 0;
+       manager->hpdirq = 0;
+       init_completion(&manager->uvdm_out_wait);
+       init_completion(&manager->uvdm_in_wait);
+       usbpd_manager_select_pdo_cancel(pd_data->dev);
+       usbpd_manager_start_discover_msg_cancel(pd_data->dev);
+}
+
+int usbpd_init_manager(struct usbpd_data *pd_data)
+{
+       int ret = 0;
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       pr_info("%s\n", __func__);
+       if (manager == NULL) {
+               pr_err("%s, usbpd manager data is error!!\n", __func__);
+               return -ENOMEM;
+       } else
+               ret = of_usbpd_manager_dt(manager);
+#ifdef CONFIG_BATTERY_SAMSUNG
+#ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER
+       fp_select_pdo = s2mu106_select_pdo;
+#endif
+#endif
+       mutex_init(&manager->vdm_mutex);
+       manager->pd_data = pd_data;
+       manager->power_role_swap = true;
+       manager->data_role_swap = true;
+       manager->vconn_source_swap = true;
+       manager->alt_sended = 0;
+       manager->vdm_en = 0;
+       manager->acc_type = 0;
+       manager->Vendor_ID = 0;
+       manager->Product_ID = 0;
+       manager->Device_Version = 0;
+       manager->SVID_0 = 0;
+       manager->SVID_1 = 0;
+       manager->Standard_Vendor_ID = 0;
+       manager->dp_is_connect = 0;
+       manager->dp_hs_connect = 0;
+       manager->is_sent_pin_configuration = 0;
+       manager->pin_assignment = 0;
+       manager->dp_selected_pin = 0;
+       manager->hpd = 0;
+       manager->hpdirq = 0;
+       init_completion(&manager->uvdm_out_wait);
+       init_completion(&manager->uvdm_in_wait);
+
+       usbpd_manager_register_switch_device(1);
+       init_source_cap_data(manager);
+       init_sink_cap_data(manager);
+       INIT_DELAYED_WORK(&manager->acc_detach_handler, usbpd_manager_acc_detach_handler);
+       INIT_DELAYED_WORK(&manager->select_pdo_handler, usbpd_manager_select_pdo_handler);
+       INIT_DELAYED_WORK(&manager->start_discover_msg_handler,
+                                                                       usbpd_manager_start_discover_msg_handler);
+
+       pr_info("%s done\n", __func__);
+       return ret;
+}
diff --git a/drivers/ccic/usbpd_policy.c b/drivers/ccic/usbpd_policy.c
new file mode 100644 (file)
index 0000000..88dccc4
--- /dev/null
@@ -0,0 +1,2783 @@
+/*
+*      USB PD Driver - Policy Engine
+*/
+
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/ccic/usbpd.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/time.h>
+
+#include <linux/muic/muic.h>
+#if defined(CONFIG_MUIC_NOTIFIER)
+#include <linux/muic/muic_notifier.h>
+#endif /* CONFIG_MUIC_NOTIFIER */
+
+#include <linux/usb_notify.h>
+
+#if (defined CONFIG_IFCONN_NOTIFIER || defined CONFIG_DUAL_ROLE_USB_INTF)
+#include <linux/ccic/usbpd_ext.h>
+#endif
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+#include <linux/ifconn/ifconn_notifier.h>
+#endif
+
+#define CHECK_MSG(pd, msg, ret) do {\
+       if (pd->phy_ops.get_status(pd, msg))\
+               return ret;\
+       } while (0);
+
+#define CHECK_CMD(pd, event, ret) do {\
+               if (pd->manager.cmd & event) {\
+                       pd->manager.cmd &= ~event; \
+                       return ret;\
+               } \
+       } while (0);
+
+policy_state usbpd_policy_src_startup(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       pd_data->counter.caps_counter = 0;
+       usbpd_init_protocol(pd_data);
+
+       pd_data->phy_ops.set_cc_control(pd_data, USBPD_CC_ON);
+
+       return PE_SRC_Send_Capabilities;
+}
+
+policy_state usbpd_policy_src_discovery(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       msleep(tSendSourceCap);
+       if (pd_data->counter.caps_counter <= USBPD_nCapsCount)
+               return PE_SRC_Send_Capabilities;
+       else
+               return PE_SRC_Disabled;
+}
+
+policy_state usbpd_policy_src_send_capabilities(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       policy->tx_msg_header.word = pd_data->source_msg_header.word;
+       policy->tx_data_obj[0].object = pd_data->source_data_obj.object;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->counter.caps_counter++;
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->policy.state = PE_SRC_Send_Capabilities;
+               if (usbpd_wait_msg(pd_data, MSG_REQUEST, tSenderResponseSRC)) {
+                       if (policy->rx_msg_header.msg_type == USBPD_Request &&
+                               policy->rx_msg_header.num_data_objs > 0) {
+                               pd_data->counter.hard_reset_counter = 0;
+                               pd_data->counter.caps_counter = 0;
+                               pd_data->source_request_obj.object
+                                       = policy->rx_data_obj[0].object;
+                               dev_info(pd_data->dev, "got Request.\n");
+                               return PE_SRC_Negotiate_Capability;
+
+                       } else {
+                               dev_err(pd_data->dev,
+                                       "Not get request object\n");
+                               goto hard_reset;
+                       }
+               } else if (pd_data->phy_ops.get_status(pd_data, MSG_GOODCRC)) {
+                       if (policy->abnormal_state)
+                               return PE_SRC_Send_Capabilities;
+                       pd_data->counter.caps_counter = 0;
+                       dev_err(pd_data->dev,
+                               "%s NoResponseTimer\n", __func__);
+                       goto hard_reset;
+               } else {        /* not receive good crc */
+                       if (policy->abnormal_state)
+                               return PE_SRC_Send_Capabilities;
+                       return PE_SRC_Discovery;
+               }
+       } else
+               return PE_SRC_Discovery;
+
+hard_reset:
+       if (pd_data->counter.hard_reset_counter > USBPD_nHardResetCount)
+               return Error_Recovery;
+
+       return PE_SRC_Hard_Reset;
+}
+#if 0
+policy_state usbpd_policy_src_send_capabilities(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       policy->tx_msg_header.word = pd_data->source_msg_header.word;
+       policy->tx_data_obj[0].object = pd_data->source_data_obj.object;
+
+       dev_info(pd_data->dev, "%s 0x%x 0x%x\n", __func__
+                       , policy->tx_msg_header.word
+                       , policy->tx_data_obj[0].object);
+
+       pd_data->counter.caps_counter++;
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->counter.hard_reset_counter = 0;
+               pd_data->counter.caps_counter = 0;
+               if (usbpd_wait_msg(pd_data, MSG_REQUEST, tSenderResponse)) {
+                       if (policy->rx_msg_header.msg_type == USBPD_Request &&
+                               policy->rx_msg_header.num_data_objs > 0) {
+                                       pd_data->source_request_obj.object
+                                               = policy->rx_data_obj[0].object;
+                                       dev_info(pd_data->dev, "got Request.\n");
+                                       return PE_SRC_Negotiate_Capability;
+                       } else {
+                               dev_err(pd_data->dev,
+                                       "Not get request object\n");
+                               return Error_Recovery;
+                       }
+               } else {
+                       dev_err(pd_data->dev,
+                               "%s NoResponseTimer\n", __func__);
+                       return PE_SRC_Hard_Reset;
+               }
+       } else
+               return PE_SRC_Discovery;
+
+       if (pd_data->counter.hard_reset_counter > USBPD_nHardResetCount)
+               return Error_Recovery;
+
+       return PE_SRC_Send_Capabilities;
+}
+#endif
+policy_state usbpd_policy_src_negotiate_capability(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       if (usbpd_manager_match_request(pd_data) == 0)
+               return PE_SRC_Transition_Supply; /* Accept */
+       else
+               return PE_SRC_Capability_Response; /* Reject */
+}
+
+policy_state usbpd_policy_src_transition_supply(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       /* TODO: If GotoMin send GotoMin message */
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header, USBPD_Accept,
+                       USBPD_DFP, USBPD_SOURCE)) {
+               msleep(tSrcTransition);
+
+               if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                       USBPD_PS_RDY, USBPD_DFP, USBPD_SOURCE))
+                       return PE_SRC_Ready;
+               else
+                       return PE_SRC_Send_Soft_Reset;
+       } else {
+               return PE_SRC_Send_Soft_Reset;
+       }
+       return PE_SRC_Transition_Supply;
+}
+
+policy_state usbpd_policy_src_ready(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int data_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       CHECK_MSG(pd_data, MSG_GET_SRC_CAP, PE_SRC_Give_Source_Cap);
+       CHECK_MSG(pd_data, MSG_REQUEST, PE_SRC_Negotiate_Capability);
+       CHECK_MSG(pd_data, MSG_PR_SWAP, PE_PRS_SRC_SNK_Evaluate_Swap);
+       CHECK_MSG(pd_data, MSG_DR_SWAP, PE_DRS_Evaluate_Port);
+       CHECK_MSG(pd_data, MSG_VCONN_SWAP, PE_VCS_Evaluate_Swap);
+       CHECK_MSG(pd_data, VDM_DISCOVER_IDENTITY, PE_UFP_VDM_Get_Identity);
+       CHECK_MSG(pd_data, VDM_DISCOVER_SVID, PE_UFP_VDM_Get_SVIDs);
+       CHECK_MSG(pd_data, VDM_DISCOVER_MODE, PE_UFP_VDM_Get_Modes);
+       CHECK_MSG(pd_data, VDM_ENTER_MODE, PE_UFP_VDM_Evaluate_Mode_Entry);
+       CHECK_MSG(pd_data, VDM_ATTENTION, PE_DFP_VDM_Attention_Request);
+       CHECK_MSG(pd_data, VDM_DP_STATUS_UPDATE, PE_UFP_VDM_Evaluate_Status);
+       CHECK_MSG(pd_data, VDM_DP_CONFIGURE, PE_UFP_VDM_Evaluate_Configure);
+       CHECK_MSG(pd_data, UVDM_MSG, PE_DFP_UVDM_Receive_Message);
+
+       CHECK_CMD(pd_data, MANAGER_REQ_GET_SNKCAP, PE_SRC_Get_Sink_Cap);
+       CHECK_CMD(pd_data, MANAGER_REQ_GOTOMIN, PE_SRC_Transition_Supply);
+       CHECK_CMD(pd_data, MANAGER_REQ_SRCCAP_CHANGE, PE_SRC_Send_Capabilities);
+       CHECK_CMD(pd_data, MANAGER_REQ_PR_SWAP, PE_PRS_SRC_SNK_Send_Swap);
+       CHECK_CMD(pd_data, MANAGER_REQ_DR_SWAP, PE_DRS_Evaluate_Send_Port);
+       CHECK_CMD(pd_data, MANAGER_REQ_VCONN_SWAP, PE_VCS_Send_Swap);
+       CHECK_CMD(pd_data, MANAGER_REQ_UVDM_SEND_MESSAGE,
+                                                                               PE_DFP_UVDM_Send_Message);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_DISCOVER_IDENTITY, PE_DFP_VDM_Identity_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_DISCOVER_SVID, PE_DFP_VDM_SVIDs_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_DISCOVER_MODE, PE_DFP_VDM_Modes_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_ENTER_MODE, PE_DFP_VDM_Mode_Entry_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_STATUS_UPDATE, PE_DFP_VDM_Status_Update);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_DisplayPort_Configure, PE_DFP_VDM_DisplayPort_Configure);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_ATTENTION, PE_UFP_VDM_Attention_Request);
+
+/*     for data role swap test
+       if (usbpd_manager_vdm_request_enabled(pd_data)) {
+               msleep(tDiscoverIdentity);
+               return PE_DRS_Evaluate_Send_Port;
+       }
+*/
+       pd_data->phy_ops.get_data_role(pd_data, &data_role);
+
+       if (data_role == USBPD_DFP)
+               usbpd_manager_vdm_request_enabled(pd_data);
+
+       return PE_SRC_Ready;
+}
+
+policy_state usbpd_policy_src_disabled(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       return PE_SRC_Disabled;
+}
+
+policy_state usbpd_policy_src_capability_response(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header, USBPD_Reject,
+                               USBPD_DFP, USBPD_SOURCE)) {
+               return PE_SRC_Ready;
+               /* TODO: if (Contract Invalid)
+                  return(PE_SRC_Hard_Reset) */
+       }
+       /*
+       else if (no Explicit Contract && Reject message sent
+                       || Wait message sent)
+               return(PE_SRC_Wait_New_Capabilities);
+       */
+       return PE_SRC_Capability_Response;
+}
+
+policy_state usbpd_policy_src_hard_reset(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       msleep(tPSHardReset);
+
+       pd_data->phy_ops.hard_reset(pd_data);
+       pd_data->phy_ops.set_cc_control(pd_data, USBPD_CC_OFF);
+       pd_data->counter.hard_reset_counter++;
+
+       return PE_SRC_Transition_to_default;
+}
+
+policy_state usbpd_policy_src_hard_reset_received(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       msleep(tPSHardReset);
+
+       return PE_SRC_Transition_to_default;
+}
+
+policy_state usbpd_policy_src_transition_to_default(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.driver_reset(pd_data);
+       /*
+       Request Device Policy Manager to request power
+       supply Hard Resets to vSafe5V via vSafe0V
+
+       If(Type-C request Device Policy Manager to set Port Data Role to DFP)
+               turn off VCONN
+       */
+
+       /*
+       Request Device Policy Manager to turn on VCONN
+       Initialize and start NoResponseTimer
+       Inform Protocol Layer Hard Reset complete
+       */
+       return PE_SRC_Startup;
+}
+
+policy_state usbpd_policy_src_give_source_cap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       /*
+       TODO: Request source capabilities from Device Policy Manager
+       Send Capabilities message
+       */
+
+       policy->tx_msg_header.msg_type = USBPD_Source_Capabilities;
+       policy->tx_msg_header.port_data_role = USBPD_DFP;
+       policy->tx_msg_header.port_power_role = USBPD_SOURCE;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].power_data_obj.max_current = 100;
+       policy->tx_data_obj[0].power_data_obj.voltage = 100;
+       policy->tx_data_obj[0].power_data_obj.peak_current = 0;
+       policy->tx_data_obj[0].power_data_obj.data_role_swap = 1;
+       policy->tx_data_obj[0].power_data_obj.usb_comm_capable = 1;
+       policy->tx_data_obj[0].power_data_obj.externally_powered = 0;
+       policy->tx_data_obj[0].power_data_obj.usb_suspend_support = 1;
+       policy->tx_data_obj[0].power_data_obj.dual_role_power = 1;
+       policy->tx_data_obj[0].power_data_obj.supply = 0;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj))
+               return PE_SRC_Ready;
+       else
+               return PE_SRC_Give_Source_Cap;
+}
+
+policy_state usbpd_policy_src_get_sink_cap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Get_Sink_Cap, USBPD_DFP, USBPD_SOURCE)) {
+               pd_data->policy.state = PE_SRC_Get_Sink_Cap;
+               if (usbpd_wait_msg(pd_data, MSG_SNK_CAP, tSenderResponse)) {
+                       /* TODO: pass sink cap to device policy manager */
+                       dev_info(pd_data->dev, "got SinkCap.\n");
+               }
+       }
+       return PE_SRC_Ready;
+}
+
+policy_state usbpd_policy_src_wait_new_capabilities(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return PE_SRC_Send_Capabilities;
+}
+
+policy_state usbpd_policy_src_send_soft_reset(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       usbpd_init_protocol(pd_data);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Soft_Reset, USBPD_DFP, USBPD_SOURCE)) {
+               pd_data->policy.state = PE_SRC_Send_Soft_Reset;
+               if (usbpd_wait_msg(pd_data, MSG_ACCEPT, tSenderResponse))
+                       return PE_SRC_Send_Capabilities;
+               if (policy->abnormal_state)
+                       return PE_SRC_Send_Soft_Reset;
+       }
+       return PE_SRC_Hard_Reset;
+}
+
+policy_state usbpd_policy_src_soft_reset(struct policy_data *policy)
+{
+#if 0
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Accept, USBPD_DFP, USBPD_SOURCE))
+               return PE_SRC_Send_Capabilities;
+       else
+               return PE_SRC_Hard_Reset;
+#endif
+       return PE_SRC_Send_Capabilities;
+}
+
+policy_state usbpd_policy_snk_startup(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       usbpd_init_protocol(pd_data);
+
+       pd_data->phy_ops.set_cc_control(pd_data, USBPD_CC_ON);
+
+       return PE_SNK_Discovery;
+}
+
+policy_state usbpd_policy_snk_discovery(struct policy_data *policy)
+{
+       /* TODO: wait vbus */
+       /* if coming from HardReset
+          && NoResponseTimer timeout
+          && HardResetCounter <= nHardResetCount,
+          return(PE_SNK_Hard_Reset) */
+       return PE_SNK_Wait_for_Capabilities;
+}
+
+policy_state usbpd_policy_snk_wait_for_capabilities(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->policy.state = PE_SNK_Wait_for_Capabilities;
+       if (usbpd_wait_msg(pd_data, MSG_SRC_CAP, tSinkWaitCap))
+               return PE_SNK_Evaluate_Capability;
+
+       if (policy->abnormal_state)
+               return PE_SNK_Wait_for_Capabilities;
+#if !defined(CONFIG_SEC_FACTORY)
+       if (pd_data->counter.hard_reset_counter <= USBPD_nHardResetCount)
+               return PE_SNK_Hard_Reset;
+       else
+               return Error_Recovery;
+#endif
+       return PE_SNK_Wait_for_Capabilities;
+}
+
+policy_state usbpd_policy_snk_evaluate_capability(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int sink_request_obj_num = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       usbpd_protocol_rx(pd_data);
+#ifdef CONFIG_IFCONN_NOTIFIER
+       if (pd_noti.sink_status.selected_pdo_num == 0) {
+               pd_noti.sink_status.selected_pdo_num = 1;
+               if (policy->sink_cap_received) {
+                       policy->send_sink_cap = 1;
+                       policy->sink_cap_received = 0;
+               }
+       }
+#endif
+       sink_request_obj_num = usbpd_manager_evaluate_capability(pd_data);
+
+       if (sink_request_obj_num > 0)
+               return PE_SNK_Select_Capability;
+       else
+               return PE_SNK_Hard_Reset;
+}
+
+policy_state usbpd_policy_snk_select_capability(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       policy->tx_msg_header.msg_type = USBPD_Request;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = USBPD_SINK;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0] = usbpd_manager_select_capability(pd_data);
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               unsigned msg;
+               pd_data->policy.state = PE_SNK_Select_Capability;
+               msg = usbpd_wait_msg(pd_data, MSG_ACCEPT | MSG_REJECT
+                               | MSG_WAIT, tSenderResponse);
+               if (policy->abnormal_state)
+                       return PE_SNK_Select_Capability;
+               if (msg & MSG_ACCEPT)
+                       return PE_SNK_Transition_Sink;
+               else if (msg & (MSG_REJECT | MSG_WAIT))
+                       return PE_SNK_Ready;
+               else
+                       return PE_SNK_Hard_Reset;
+
+               /* If no explicit contract
+                  policy->state = PE_SNK_Wait_for_Capabilities;
+                */
+       }
+       return Error_Recovery;
+}
+
+policy_state usbpd_policy_snk_transition_sink(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       policy->state = PE_SNK_Transition_Sink;
+       if (usbpd_wait_msg(pd_data, MSG_PSRDY, tPSTransition)) {
+               dev_info(pd_data->dev, "got PS_READY.\n");
+#ifdef CONFIG_IFCONN_NOTIFIER
+               pd_noti.sink_status.current_pdo_num = pd_noti.sink_status.selected_pdo_num;
+#endif
+               return PE_SNK_Ready;
+       }
+
+       if (policy->abnormal_state)
+               return PE_SNK_Transition_Sink;
+
+       return PE_SNK_Hard_Reset;
+}
+
+policy_state usbpd_policy_snk_ready(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int data_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       usbpd_manager_plug_attach(pd_data->dev);
+
+       CHECK_MSG(pd_data, MSG_GET_SNK_CAP, PE_SNK_Give_Sink_Cap);
+       CHECK_MSG(pd_data, MSG_SRC_CAP, PE_SNK_Evaluate_Capability);
+       CHECK_MSG(pd_data, MSG_PR_SWAP, PE_PRS_SNK_SRC_Evaluate_Swap);
+       CHECK_MSG(pd_data, MSG_DR_SWAP, PE_DRS_Evaluate_Port);
+       CHECK_MSG(pd_data, MSG_VCONN_SWAP, PE_VCS_Evaluate_Swap);
+       CHECK_MSG(pd_data, VDM_DISCOVER_IDENTITY, PE_UFP_VDM_Get_Identity);
+       CHECK_MSG(pd_data, VDM_DISCOVER_SVID, PE_UFP_VDM_Get_SVIDs);
+       CHECK_MSG(pd_data, VDM_DISCOVER_MODE, PE_UFP_VDM_Get_Modes);
+       CHECK_MSG(pd_data, VDM_ENTER_MODE, PE_UFP_VDM_Evaluate_Mode_Entry);
+       CHECK_MSG(pd_data, VDM_ATTENTION, PE_DFP_VDM_Attention_Request);
+       CHECK_MSG(pd_data, VDM_DP_STATUS_UPDATE, PE_UFP_VDM_Evaluate_Status);
+       CHECK_MSG(pd_data, VDM_DP_CONFIGURE, PE_UFP_VDM_Evaluate_Configure);
+       CHECK_MSG(pd_data, UVDM_MSG, PE_DFP_UVDM_Receive_Message);
+
+       CHECK_CMD(pd_data, MANAGER_REQ_NEW_POWER_SRC, PE_SNK_Select_Capability);
+       CHECK_CMD(pd_data, MANAGER_REQ_PR_SWAP, PE_PRS_SNK_SRC_Send_Swap);
+       CHECK_CMD(pd_data, MANAGER_REQ_DR_SWAP, PE_DRS_Evaluate_Send_Port);
+       CHECK_CMD(pd_data, MANAGER_REQ_VCONN_SWAP, PE_VCS_Send_Swap);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_DISCOVER_IDENTITY, PE_DFP_VDM_Identity_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_DISCOVER_SVID, PE_DFP_VDM_SVIDs_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_DISCOVER_MODE, PE_DFP_VDM_Modes_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_ATTENTION, PE_UFP_VDM_Attention_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_ENTER_MODE, PE_DFP_VDM_Mode_Entry_Request);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_STATUS_UPDATE, PE_DFP_VDM_Status_Update);
+       CHECK_CMD(pd_data, MANAGER_REQ_VDM_DisplayPort_Configure, PE_DFP_VDM_DisplayPort_Configure);
+       CHECK_CMD(pd_data, MANAGER_REQ_UVDM_SEND_MESSAGE,PE_DFP_UVDM_Send_Message);
+
+       pd_data->phy_ops.get_data_role(pd_data, &data_role);
+
+       if (data_role == USBPD_DFP)
+               usbpd_manager_vdm_request_enabled(pd_data);
+
+       return PE_SNK_Ready;
+}
+
+policy_state usbpd_policy_snk_hard_reset(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.hard_reset(pd_data);
+       pd_data->phy_ops.set_cc_control(pd_data, USBPD_CC_OFF);
+       /* increase hard reset counter */
+       pd_data->counter.hard_reset_counter++;
+
+       return PE_SNK_Transition_to_default;
+}
+
+policy_state usbpd_policy_snk_transition_to_default(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.driver_reset(pd_data);
+
+       usbpd_manager_turn_off_vconn(pd_data);
+
+/*     pd_data->phy_ops.set_data_role(pd_data, USBPD_UFP);   */
+
+       return PE_SNK_Startup;
+}
+
+policy_state usbpd_policy_snk_give_sink_cap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+#ifdef CONFIG_IFCONN_NOTIFIER
+       pd_noti.sink_status.selected_pdo_num = 0;
+#endif
+       policy->tx_msg_header.word = pd_data->sink_msg_header.word;
+       policy->tx_data_obj[0].object = pd_data->sink_data_obj[0].object;
+       policy->tx_data_obj[1].object = pd_data->sink_data_obj[1].object;
+
+       policy->sink_cap_received = 1;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj))
+               return PE_SNK_Ready;
+       else
+               return PE_SNK_Give_Sink_Cap;
+}
+
+policy_state usbpd_policy_snk_get_source_cap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Get_Source_Cap, USBPD_UFP, USBPD_SINK))
+               return PE_SNK_Ready;
+       else
+               return PE_SNK_Get_Source_Cap;
+}
+
+policy_state usbpd_policy_snk_soft_reset(struct policy_data *policy)
+{
+#if 0
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Accept, USBPD_UFP, USBPD_SINK))
+               return PE_SNK_Wait_for_Capabilities;
+       else
+               return PE_SNK_Hard_Reset;
+#endif
+       return PE_SNK_Wait_for_Capabilities;
+}
+
+policy_state usbpd_policy_drs_evaluate_port(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int data_role = 0;
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (policy->modal_operation) {
+               pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+               if (power_role == USBPD_SOURCE)
+                       return PE_SRC_Hard_Reset;
+               else
+                       return PE_SNK_Hard_Reset;
+       }
+
+       pd_data->phy_ops.get_data_role(pd_data, &data_role);
+
+       if (data_role == USBPD_DFP)
+               return PE_DRS_DFP_UFP_Evaluate_DR_Swap;
+       else
+               return PE_DRS_UFP_DFP_Evaluate_DR_Swap;
+}
+
+policy_state usbpd_policy_drs_evaluate_send_port(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int data_role = 0;
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (policy->modal_operation) {
+               pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+               if (power_role == USBPD_SOURCE)
+                       return PE_SRC_Hard_Reset;
+               else
+                       return PE_SNK_Hard_Reset;
+       }
+
+       pd_data->phy_ops.get_data_role(pd_data, &data_role);
+
+       if (data_role == USBPD_DFP)
+               return PE_DRS_DFP_UFP_Send_DR_Swap;
+       else
+               return PE_DRS_UFP_DFP_Send_DR_Swap;
+}
+
+policy_state usbpd_policy_drs_dfp_ufp_evaluate_dr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       bool drs_ok;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       drs_ok = usbpd_manager_data_role_swap(pd_data);
+
+       if (drs_ok)
+               return PE_DRS_DFP_UFP_Accept_DR_Swap;
+       else
+               return PE_DRS_DFP_UFP_Reject_DR_Swap;
+}
+
+policy_state usbpd_policy_drs_dfp_ufp_accept_dr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                       USBPD_Accept, USBPD_DFP, power_role)) {
+               return PE_DRS_DFP_UFP_Change_to_UFP;
+       }
+
+       return PE_DRS_DFP_UFP_Accept_DR_Swap;
+}
+
+policy_state usbpd_policy_drs_dfp_ufp_change_to_ufp(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.set_data_role(pd_data, USBPD_UFP);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (power_role == USBPD_SOURCE)
+               return PE_SRC_Ready;
+       else
+               return PE_SNK_Ready;
+}
+
+policy_state usbpd_policy_drs_dfp_ufp_send_dr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_DR_Swap, USBPD_DFP, power_role)) {
+               unsigned msg;
+               pd_data->policy.state = PE_DRS_DFP_UFP_Send_DR_Swap;
+               msg = usbpd_wait_msg(pd_data, MSG_ACCEPT | MSG_REJECT
+                               | MSG_WAIT, tSenderResponse);
+               if (policy->abnormal_state)
+                       return PE_DRS_DFP_UFP_Send_DR_Swap;
+
+               if (msg & MSG_ACCEPT)
+                       return PE_DRS_DFP_UFP_Change_to_UFP;
+       }
+
+       if (power_role == USBPD_SOURCE)
+               return PE_SRC_Ready;
+       else
+               return PE_SNK_Ready;
+}
+
+policy_state usbpd_policy_drs_dfp_ufp_reject_dr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Reject, USBPD_DFP, power_role)) {
+               if (power_role == USBPD_SOURCE)
+                       return PE_SRC_Ready;
+               else
+                       return PE_SNK_Ready;
+       }
+
+       return PE_DRS_DFP_UFP_Reject_DR_Swap;
+}
+
+policy_state usbpd_policy_drs_ufp_dfp_evaluate_dr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       bool drs_ok;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       drs_ok = usbpd_manager_data_role_swap(pd_data);
+
+       if (drs_ok)
+               return PE_DRS_UFP_DFP_Accept_DR_Swap;
+       else
+               return PE_DRS_UFP_DFP_Reject_DR_Swap;
+}
+
+policy_state usbpd_policy_drs_ufp_dfp_accept_dr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Accept, USBPD_UFP, power_role)) {
+               return PE_DRS_UFP_DFP_Change_to_DFP;
+       }
+       return PE_DRS_UFP_DFP_Accept_DR_Swap;
+}
+
+policy_state usbpd_policy_drs_ufp_dfp_change_to_dfp(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.set_data_role(pd_data, USBPD_DFP);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (power_role == USBPD_SOURCE)
+               return PE_SRC_Ready;
+       else
+               return PE_SNK_Ready;
+}
+
+policy_state usbpd_policy_drs_ufp_dfp_send_dr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_DR_Swap, USBPD_UFP, power_role)) {
+               unsigned msg;
+               pd_data->policy.state = PE_DRS_UFP_DFP_Send_DR_Swap;
+               msg = usbpd_wait_msg(pd_data, MSG_ACCEPT | MSG_REJECT
+                               | MSG_WAIT, tSenderResponse);
+               if (policy->abnormal_state)
+                       return PE_DRS_UFP_DFP_Send_DR_Swap;
+
+               if (msg & MSG_ACCEPT)
+                       return PE_DRS_UFP_DFP_Change_to_DFP;
+       }
+
+       if (power_role == USBPD_SOURCE)
+               return PE_SRC_Ready;
+       else
+               return PE_SNK_Ready;
+}
+
+policy_state usbpd_policy_drs_ufp_dfp_reject_dr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Reject, USBPD_UFP, USBPD_SINK)) {
+               if (power_role == USBPD_SOURCE)
+                       return PE_SRC_Ready;
+               else
+                       return PE_SNK_Ready;
+       }
+
+       return PE_DRS_UFP_DFP_Reject_DR_Swap;
+}
+
+policy_state usbpd_policy_prs_src_snk_reject_pr_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Reject, USBPD_DFP, USBPD_SOURCE))
+               return PE_SRC_Ready;
+
+       return PE_PRS_SRC_SNK_Reject_PR_Swap;
+}
+
+policy_state usbpd_policy_prs_src_snk_evaluate_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       bool prs_ok;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       prs_ok = usbpd_manager_power_role_swap(pd_data);
+
+       if (prs_ok)
+               return PE_PRS_SRC_SNK_Accept_Swap;
+       else
+               return PE_PRS_SRC_SNK_Reject_PR_Swap;
+}
+
+policy_state usbpd_policy_prs_src_snk_send_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_PR_Swap, USBPD_DFP, USBPD_SOURCE)) {
+               unsigned msg;
+
+               pd_data->policy.state = PE_PRS_SRC_SNK_Send_Swap;
+               msg = usbpd_wait_msg(pd_data, MSG_ACCEPT | MSG_REJECT
+                               | MSG_WAIT, tSenderResponse);
+               if (policy->abnormal_state)
+                       return PE_PRS_SRC_SNK_Send_Swap;
+
+               if (msg & MSG_ACCEPT)
+                       return PE_PRS_SRC_SNK_Transition_off;
+       }
+       return PE_SRC_Ready;
+}
+
+policy_state usbpd_policy_prs_src_snk_accept_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Accept, USBPD_DFP, USBPD_SOURCE))
+               return PE_PRS_SRC_SNK_Transition_off;
+
+       return PE_PRS_SRC_SNK_Accept_Swap;
+}
+
+policy_state usbpd_policy_prs_src_snk_transition_to_off(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+
+       pd_data->phy_ops.set_otg_control(pd_data, 0);
+
+       pr_info("%s, %d\n", __func__, manager->acc_type);
+
+       /* skip delay when GEARVR is attached */
+       if (manager->acc_type != CCIC_DOCK_HMT || manager->SVID_0 == 0)
+               msleep(150);
+
+       return PE_PRS_SRC_SNK_Assert_Rd;
+}
+
+policy_state usbpd_policy_prs_src_snk_assert_rd(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       pd_data->phy_ops.set_power_role(pd_data, USBPD_SINK);
+
+       return PE_PRS_SRC_SNK_Wait_Source_on;
+}
+
+policy_state usbpd_policy_prs_src_snk_wait_source_on(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       int wait_time = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_PS_RDY, USBPD_DFP, USBPD_SINK)) {
+               pd_data->policy.state = PE_PRS_SRC_SNK_Wait_Source_on;
+               if (manager->acc_type == CCIC_DOCK_HMT)
+                       wait_time = 2000;
+               else
+                       wait_time = tPSSourceOn;
+               if (usbpd_wait_msg(pd_data, MSG_PSRDY, tPSSourceOn)) {
+                       pd_data->counter.swap_hard_reset_counter = 0;
+                       dev_info(pd_data->dev, "got PSRDY.\n");
+                       mdelay(10);
+                       pd_data->phy_ops.set_power_role(pd_data, USBPD_DRP);
+                       return PE_SNK_Startup;
+               } else {
+                       if (policy->abnormal_state)
+                               return PE_PRS_SRC_SNK_Wait_Source_on;
+                       goto hard_reset;
+               }
+       }
+       return PE_PRS_SRC_SNK_Wait_Source_on;
+
+hard_reset:
+       if (pd_data->counter.swap_hard_reset_counter > USBPD_nHardResetCount)
+               return Error_Recovery;
+
+       return PE_SNK_Hard_Reset;
+}
+
+policy_state usbpd_policy_prs_snk_src_reject_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Reject, USBPD_UFP, USBPD_SINK))
+               return PE_SNK_Ready;
+
+       return PE_PRS_SNK_SRC_Reject_Swap;
+}
+
+policy_state usbpd_policy_prs_snk_src_evaluate_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       bool prs_ok;
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       prs_ok = usbpd_manager_power_role_swap(pd_data);
+
+       if (prs_ok)
+               return PE_PRS_SNK_SRC_Accept_Swap;
+       else
+               return PE_PRS_SNK_SRC_Reject_Swap;
+}
+
+policy_state usbpd_policy_prs_snk_src_send_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_PR_Swap, USBPD_UFP, USBPD_SINK)) {
+               unsigned msg;
+
+               pd_data->policy.state = PE_PRS_SNK_SRC_Send_Swap;
+               msg = usbpd_wait_msg(pd_data, MSG_ACCEPT | MSG_REJECT
+                               | MSG_WAIT, tSenderResponse);
+               if (policy->abnormal_state)
+                       return PE_PRS_SNK_SRC_Send_Swap;
+               if (msg & MSG_ACCEPT)
+                       return PE_PRS_SNK_SRC_Transition_off;
+       }
+       return PE_SNK_Ready;
+}
+
+policy_state usbpd_policy_prs_snk_src_accept_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Accept, USBPD_DFP, USBPD_SINK))
+               return PE_PRS_SNK_SRC_Transition_off;
+
+       return PE_PRS_SNK_SRC_Accept_Swap;
+}
+
+policy_state usbpd_policy_prs_snk_src_transition_to_off(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       usbpd_manager_turn_off_power_sink(pd_data);
+
+       pd_data->policy.state = PE_PRS_SNK_SRC_Transition_off;
+       if (usbpd_wait_msg(pd_data, MSG_PSRDY, tPSSourceOff)) {
+               pd_data->counter.swap_hard_reset_counter = 0;
+               dev_info(pd_data->dev, "got PSRDY.\n");
+               return PE_PRS_SNK_SRC_Assert_Rp;
+       }
+       if (policy->abnormal_state)
+               return PE_PRS_SNK_SRC_Transition_off;
+
+       if (pd_data->counter.swap_hard_reset_counter > USBPD_nHardResetCount)
+               return Error_Recovery;
+
+       return PE_SRC_Hard_Reset;
+}
+
+policy_state usbpd_policy_prs_snk_src_assert_rp(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.set_power_role(pd_data, USBPD_SOURCE);
+
+       return PE_PRS_SNK_SRC_Source_on;
+}
+
+policy_state usbpd_policy_prs_snk_src_source_on(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.set_otg_control(pd_data, 1);
+
+       msleep(150);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_PS_RDY, USBPD_DFP, USBPD_SOURCE)) {
+               msleep(tSwapSourceStart); /* 20ms */
+               pd_data->phy_ops.set_power_role(pd_data, USBPD_DRP);
+               return PE_SRC_Startup;
+       }
+       return PE_PRS_SNK_SRC_Source_on;
+}
+
+policy_state usbpd_policy_vcs_evaluate_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       bool vcs_ok;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+       vcs_ok = usbpd_manager_vconn_source_swap(pd_data);
+
+       if (vcs_ok)
+               return PE_VCS_Accept_Swap;
+       else
+               return PE_VCS_Reject_VCONN_Swap;
+}
+
+policy_state usbpd_policy_vcs_accept_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int vconn_source = 0;
+       int power_role = 0;
+       int data_role = 0;
+
+       pd_data->phy_ops.get_vconn_source(pd_data, &vconn_source);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+       pd_data->phy_ops.get_data_role(pd_data, &data_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Accept, data_role, power_role)) {
+               if (vconn_source)
+                       return PE_VCS_Wait_for_VCONN;
+               else
+                       return PE_VCS_Turn_On_VCONN;
+       }
+
+       return PE_VCS_Accept_Swap;
+}
+
+policy_state usbpd_policy_vcs_send_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int vconn_source = 0;
+       int power_role = 0;
+
+       pd_data->phy_ops.get_vconn_source(pd_data, &vconn_source);
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_VCONN_Swap, USBPD_DFP, power_role)) {
+               if (vconn_source)
+                       return PE_VCS_Wait_for_VCONN;
+               else
+                       return PE_VCS_Turn_On_VCONN;
+       }
+
+       return PE_VCS_Send_Swap;
+}
+
+policy_state usbpd_policy_vcs_wait_for_vconn(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->policy.state = PE_VCS_Wait_for_VCONN;
+       if (usbpd_wait_msg(pd_data, MSG_PSRDY, tVCONNSourceOn)) {
+               pd_data->counter.swap_hard_reset_counter = 0;
+               dev_info(pd_data->dev, "got PSRDY.\n");
+               return PE_VCS_Turn_Off_VCONN;
+       }
+       if (policy->abnormal_state)
+               return PE_VCS_Wait_for_VCONN;
+
+       if (pd_data->counter.swap_hard_reset_counter > USBPD_nHardResetCount)
+               return Error_Recovery;
+
+       return PE_SNK_Hard_Reset;
+}
+
+policy_state usbpd_policy_vcs_turn_off_vconn(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.set_vconn_source(pd_data, USBPD_VCONN_OFF);
+
+       if (power_role == USBPD_SOURCE)
+               return PE_SRC_Ready;
+       else
+               return PE_SNK_Ready;
+}
+
+policy_state usbpd_policy_vcs_turn_on_vconn(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.set_vconn_source(pd_data, USBPD_VCONN_ON);
+
+       return PE_VCS_Send_PS_RDY;
+}
+
+policy_state usbpd_policy_vcs_send_ps_rdy(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+       int data_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+       pd_data->phy_ops.get_data_role(pd_data, &data_role);
+
+       mdelay(5);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_PS_RDY, data_role, data_role)) {
+               if (power_role == USBPD_SOURCE)
+                       return PE_SRC_Ready;
+               else
+                       return PE_SNK_Ready;
+       }
+
+       return PE_VCS_Send_PS_RDY;
+}
+
+policy_state usbpd_policy_vcs_reject_vconn_swap(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
+                               USBPD_Reject, USBPD_DFP, power_role)) {
+               if (power_role == USBPD_SOURCE)
+                       return PE_SRC_Ready;
+               else
+                       return PE_SNK_Ready;
+       }
+
+       return PE_VCS_Reject_VCONN_Swap;
+}
+
+policy_state usbpd_policy_ufp_vdm_get_identity(struct policy_data *policy)
+{
+       return PE_UFP_VDM_Get_Identity_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_send_identity(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_ACK;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_Identity;
+
+       /* TODO: data object should be prepared from device manager */
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Send_Identity;
+}
+
+policy_state usbpd_policy_ufp_vdm_get_identity_nak(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_NAK;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_Identity;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Get_Identity_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_get_svids(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       if (usbpd_manager_get_svids(pd_data) == 0)
+               return PE_UFP_VDM_Send_SVIDs;
+       else
+               return PE_UFP_VDM_Get_SVIDs_NAK;
+
+}
+
+policy_state usbpd_policy_ufp_vdm_send_svids(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 2;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_ACK;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_SVIDs;
+
+       policy->tx_data_obj[1].vdm_svid.svid_0 = PD_SID;
+       policy->tx_data_obj[1].vdm_svid.svid_1 = 0xFF01;
+
+       /* TODO: data object should be prepared from device manager */
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+
+       return PE_UFP_VDM_Send_SVIDs;
+}
+
+policy_state usbpd_policy_ufp_vdm_get_svids_nak(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_NAK;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_SVIDs;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Get_SVIDs_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_get_modes(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       if (usbpd_manager_get_modes(pd_data) == 0)
+               return PE_UFP_VDM_Send_Modes;
+       else
+               return PE_UFP_VDM_Get_Modes_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_send_modes(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 2;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_ACK;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_Modes;
+
+       /* TODO: data object should be prepared from device manager */
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Send_Modes;
+}
+
+policy_state usbpd_policy_ufp_vdm_get_modes_nak(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_NAK;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_Modes;
+
+       /* TODO: data object should be prepared from device manager */
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Get_Modes_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_evaluate_mode_entry(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       /* Todo
+       check DPM evaluate request to enter a mode
+       */
+/*
+       if (usbpd_manager_enter_mode(pd_data, mode_pos,
+                               mode_vdo) == 0)
+               return PE_UFP_VDM_Mode_Entry_ACK;
+       else
+               return PE_UFP_VDM_Mode_Entry_NAK;
+*/
+       return PE_UFP_VDM_Evaluate_Mode_Entry;
+}
+
+policy_state usbpd_policy_ufp_vdm_mode_entry_ack(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_ACK;
+       policy->tx_data_obj[0].structured_vdm.command = Enter_Mode;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Mode_Entry_ACK;
+}
+
+policy_state usbpd_policy_ufp_vdm_mode_entry_nak(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_NAK;
+       policy->tx_data_obj[0].structured_vdm.command = Enter_Mode;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Mode_Entry_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_mode_exit(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       if (pd_data->phy_ops.get_status(pd_data, VDM_EXIT_MODE)) {
+               if (policy->rx_data_obj[0].structured_vdm.command
+                               == Exit_Mode) {
+                       unsigned mode_pos;
+
+                       /* get mode to exit */
+                       mode_pos = policy->rx_data_obj[0].structured_vdm.obj_pos;
+                       if (usbpd_manager_exit_mode(pd_data, mode_pos) == 0)
+                               return PE_UFP_VDM_Mode_Exit_ACK;
+                       else
+                               return PE_UFP_VDM_Mode_Exit_NAK;
+               }
+       }
+       return PE_UFP_VDM_Mode_Exit;
+
+}
+
+policy_state usbpd_policy_ufp_vdm_mode_exit_ack(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_ACK;
+       policy->tx_data_obj[0].structured_vdm.command = Exit_Mode;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Mode_Exit_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_mode_exit_nak(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_NAK;
+       policy->tx_data_obj[0].structured_vdm.command = Exit_Mode;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Mode_Exit_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_attention_request(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+/*     policy->tx_msg_header.num_data_objs = 1; number of objects*/
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 0;
+       policy->tx_data_obj[0].structured_vdm.command_type = Initiator;
+       policy->tx_data_obj[0].structured_vdm.command = Attention;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Attention_Request;
+
+}
+
+policy_state usbpd_policy_ufp_vdm_evaluate_status(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (power_role == USBPD_SINK)
+               return PE_SNK_Ready;
+       else
+               return PE_SRC_Ready;
+
+       /* Todo
+       check DPM evaluate request to inform status
+       */
+/*
+       if (usbpd_manager_enter_mode(pd_data, mode_pos,
+                               mode_vdo) == 0)
+               return PE_UFP_VDM_Mode_Entry_ACK;
+       else
+               return PE_UFP_VDM_Mode_Entry_NAK;
+*/
+}
+
+policy_state usbpd_policy_ufp_vdm_status_ack(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_ACK;
+       policy->tx_data_obj[0].structured_vdm.command = DisplayPort_Status_Update;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Status_ACK;
+}
+
+policy_state usbpd_policy_ufp_vdm_status_nak(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_NAK;
+       policy->tx_data_obj[0].structured_vdm.command = DisplayPort_Status_Update;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Status_NAK;
+}
+
+policy_state usbpd_policy_ufp_vdm_evaluate_configure(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (power_role == USBPD_SINK)
+               return PE_SNK_Ready;
+       else
+               return PE_SRC_Ready;
+
+       /* Todo
+       check DPM evaluate request to inform status
+       */
+/*
+       if (usbpd_manager_enter_mode(pd_data, mode_pos,
+                               mode_vdo) == 0)
+               return PE_UFP_VDM_Mode_Entry_ACK;
+       else
+               return PE_UFP_VDM_Mode_Entry_NAK;
+*/
+}
+
+policy_state usbpd_policy_ufp_vdm_configure_ack(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_ACK;
+       policy->tx_data_obj[0].structured_vdm.command = DisplayPort_Configure;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Configure_ACK;
+}
+
+policy_state usbpd_policy_ufp_vdm_configure_nak(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_UFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Responder_NAK;
+       policy->tx_data_obj[0].structured_vdm.command = DisplayPort_Configure;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               if (power_role == USBPD_SINK)
+                       return PE_SNK_Ready;
+               else
+                       return PE_SRC_Ready;
+       }
+       return PE_UFP_VDM_Configure_NAK;
+}
+
+/* the end ufp */
+
+policy_state usbpd_policy_dfp_vdm_identity_request(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_DFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Initiator;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_Identity;
+
+       pd_data->counter.discover_identity_counter++;
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->policy.state = PE_DFP_VDM_Identity_Request;
+               if (usbpd_wait_msg(pd_data, VDM_DISCOVER_IDENTITY,
+                                       tVDMSenderResponse)) {
+                       pd_data->counter.discover_identity_counter = 0;
+
+                       if (policy->rx_data_obj[0].structured_vdm.command_type
+                                       == Responder_ACK)
+                               return PE_DFP_VDM_Identity_ACKed;
+               }
+       }
+       return PE_DFP_VDM_Identity_NAKed;
+}
+
+static policy_state usbpd_policy_dfp_vdm_response(struct policy_data *policy,
+                                       usbpd_manager_event_type event)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       usbpd_manager_inform_event(pd_data, event);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (power_role == USBPD_SINK)
+               return PE_SNK_Ready;
+       else
+               return PE_SRC_Ready;
+}
+
+policy_state usbpd_policy_dfp_vdm_identity_acked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy,
+                               MANAGER_DISCOVER_IDENTITY_ACKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_identity_naked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy,
+                               MANAGER_DISCOVER_IDENTITY_NAKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_svids_request(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_DFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Initiator;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_SVIDs;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->policy.state = PE_DFP_VDM_SVIDs_Request;
+               if (usbpd_wait_msg(pd_data, VDM_DISCOVER_SVID,
+                                       tVDMSenderResponse)) {
+                       if (policy->rx_data_obj[0].structured_vdm.command_type
+                                       == Responder_ACK)
+                               return PE_DFP_VDM_SVIDs_ACKed;
+               }
+       }
+       return PE_DFP_VDM_SVIDs_NAKed;
+}
+
+policy_state usbpd_policy_dfp_vdm_svids_acked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy,
+                               MANAGER_DISCOVER_SVID_ACKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_svids_naked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy,
+                               MANAGER_DISCOVER_SVID_NAKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_modes_request(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_DFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = manager->SVID_0;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;
+       policy->tx_data_obj[0].structured_vdm.command_type = Initiator;
+       policy->tx_data_obj[0].structured_vdm.command = Discover_Modes;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->policy.state = PE_DFP_VDM_Modes_Request;
+               if (usbpd_wait_msg(pd_data, VDM_DISCOVER_MODE,
+                                       tVDMSenderResponse)) {
+                       if (policy->rx_data_obj[0].structured_vdm.command_type
+                                       == Responder_ACK)
+                               return PE_DFP_VDM_Modes_ACKed;
+               }
+       }
+       return PE_DFP_VDM_Modes_NAKed;
+}
+
+policy_state usbpd_policy_dfp_vdm_modes_acked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy,
+                               MANAGER_DISCOVER_MODE_ACKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_modes_naked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy,
+                               MANAGER_DISCOVER_MODE_NAKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_entry_request(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_DFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].object = 0;
+       policy->tx_data_obj[0].structured_vdm.svid = manager->SVID_0;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;/* Todo select which_mode */
+       policy->tx_data_obj[0].structured_vdm.command_type = Initiator;
+       policy->tx_data_obj[0].structured_vdm.command = Enter_Mode;
+
+       /* TODO: obj_pos , vdo should be set by device manager */
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->policy.state = PE_DFP_VDM_Mode_Entry_Request;
+               if (usbpd_wait_msg(pd_data, VDM_ENTER_MODE,
+                                       tVDMWaitModeEntry)) {
+                       if (policy->rx_data_obj[0].structured_vdm.command_type
+                                       == Responder_ACK)
+                               return PE_DFP_VDM_Mode_Entry_ACKed;
+               }
+       }
+       return PE_DFP_VDM_Mode_Entry_NAKed;
+}
+
+policy_state usbpd_policy_dfp_vdm_entry_acked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_ENTER_MODE_ACKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_entry_naked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_ENTER_MODE_NAKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_exit_request(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_DFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 1;
+
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+/*     policy->tx_data_obj[0].structured_vdm.obj_pos = which_mode; */
+       policy->tx_data_obj[0].structured_vdm.command_type = Initiator;
+       policy->tx_data_obj[0].structured_vdm.command = Exit_Mode;
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->policy.state = PE_DFP_VDM_Mode_Exit_Request;
+               if (usbpd_wait_msg(pd_data, VDM_EXIT_MODE,
+                                       tVDMWaitModeExit)) {
+                       if (policy->rx_data_obj[0].structured_vdm.command_type
+                                       == Responder_ACK)
+                               return PE_DFP_VDM_Mode_Exit_ACKed;
+               }
+       }
+       return PE_DFP_VDM_Mode_Exit_NAKed;
+}
+
+policy_state usbpd_policy_dfp_vdm_exit_acked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_EXIT_MODE_ACKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_exit_naked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_EXIT_MODE_NAKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_attention_request(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_ATTENTION_REQUEST);
+}
+
+policy_state usbpd_policy_dfp_vdm_status_update(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+       pd_data->phy_ops.set_check_msg_pass(pd_data, CHECK_MSG_PASS);
+
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_DFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 2;
+
+       policy->tx_data_obj[0].object = 0;
+       policy->tx_data_obj[0].structured_vdm.svid = PD_SID_1;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;/* Todo select which_mode */
+       policy->tx_data_obj[0].structured_vdm.command_type = Initiator;
+       policy->tx_data_obj[0].structured_vdm.command = DisplayPort_Status_Update;
+
+       /* second object for vdo */
+       policy->tx_data_obj[1].object = 0;
+       policy->tx_data_obj[1].displayport_status.port_connected = 1;
+
+       /* TODO: obj_pos , vdo should be set by device manager */
+
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->policy.state = PE_DFP_VDM_Status_Update;
+               if (usbpd_wait_msg(pd_data, MSG_PASS,
+                                       tVDMWaitModeEntry)) {
+                       pd_data->phy_ops.set_check_msg_pass(pd_data, NONE_CHECK_MSG_PASS);
+                       pr_info("%s : command(%d), command_type(%d), obj_pos(%d), version(%d), vdm_type(%d)\n",
+                       __func__, policy->rx_data_obj[0].structured_vdm.command,
+                       policy->rx_data_obj[0].structured_vdm.command_type,
+                       policy->rx_data_obj[0].structured_vdm.obj_pos,
+                       policy->rx_data_obj[0].structured_vdm.version,
+                       policy->rx_data_obj[0].structured_vdm.vdm_type);
+
+                       if (policy->rx_data_obj[0].structured_vdm.command_type
+                                       == Responder_ACK)
+                               return PE_DFP_VDM_Status_Update_ACKed;
+               }
+       }
+       pd_data->phy_ops.set_check_msg_pass(pd_data, NONE_CHECK_MSG_PASS);
+
+       return PE_DFP_VDM_Status_Update_NAKed;
+}
+
+policy_state usbpd_policy_dfp_vdm_status_update_acked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_STATUS_UPDATE_ACKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_status_update_naked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_STATUS_UPDATE_NAKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_displayport_configure(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+       pd_data->phy_ops.set_check_msg_pass(pd_data, CHECK_MSG_PASS);
+
+       policy->tx_msg_header.msg_type = USBPD_Vendor_Defined;
+       policy->tx_msg_header.port_data_role = USBPD_DFP;
+       policy->tx_msg_header.port_power_role = power_role;
+       policy->tx_msg_header.num_data_objs = 2;
+
+       policy->tx_data_obj[0].structured_vdm.svid = manager->SVID_0;
+       policy->tx_data_obj[0].structured_vdm.vdm_type = Structured_VDM;
+       policy->tx_data_obj[0].structured_vdm.version = 0;
+       policy->tx_data_obj[0].structured_vdm.obj_pos = 1;/* Todo select which_mode */
+       policy->tx_data_obj[0].structured_vdm.command_type = Initiator;
+       policy->tx_data_obj[0].structured_vdm.command = DisplayPort_Configure;
+
+       /* second object for vdo */
+       policy->tx_data_obj[1].object = 0;
+       policy->tx_data_obj[1].displayport_configurations.select_configuration =
+                                                                                                                               USB_U_AS_UFP_D;
+       policy->tx_data_obj[1].displayport_configurations.displayport_protocol =
+                                                                                                                               DP_V_1_3;
+//     policy->tx_data_obj[1].displayport_configurations.ufp_u_pin_assignment =
+//                                                                                                     manager->pin_assignment;
+       policy->tx_data_obj[1].displayport_configurations.ufp_u_pin_assignment =
+                                                                                                       4;
+
+       /* TODO: obj_pos , vdo should be set by device manager */
+       if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
+                               policy->tx_data_obj)) {
+               pd_data->policy.state = PE_DFP_VDM_DisplayPort_Configure;
+               if (usbpd_wait_msg(pd_data, MSG_PASS,
+                                       tVDMWaitModeEntry)) {
+                       pd_data->phy_ops.set_check_msg_pass(pd_data, NONE_CHECK_MSG_PASS);
+                       if (policy->rx_data_obj[0].structured_vdm.command_type
+                                       == Responder_ACK)
+                               return PE_DFP_VDM_DisplayPort_Configure_ACKed;
+               }
+       }
+       pd_data->phy_ops.set_check_msg_pass(pd_data, NONE_CHECK_MSG_PASS);
+
+       return PE_DFP_VDM_DisplayPort_Configure_NAKed;
+}
+
+policy_state usbpd_policy_dfp_vdm_displayport_configure_acked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_DisplayPort_Configure_ACKED);
+}
+
+policy_state usbpd_policy_dfp_vdm_displayport_configure_naked(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       return usbpd_policy_dfp_vdm_response(policy, MANAGER_DisplayPort_Configure_NACKED);
+}
+
+policy_state usbpd_policy_dfp_uvdm_send_message(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       struct usbpd_manager_data *manager = &pd_data->manager;
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       pd_data->phy_ops.set_check_msg_pass(pd_data, CHECK_MSG_PASS);
+
+       usbpd_send_msg(pd_data, &manager->uvdm_msg_header, manager->uvdm_data_obj);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (power_role == USBPD_SOURCE)
+               return PE_SRC_Ready;
+       else
+               return PE_SNK_Ready;
+}
+
+policy_state usbpd_policy_dfp_uvdm_receive_message(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+       int power_role = 0;
+
+       dev_info(pd_data->dev, "%s\n", __func__);
+
+       usbpd_manager_inform_event(pd_data, MANAGER_UVDM_RECEIVE_MESSAGE);
+
+       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+
+       if (power_role == USBPD_SOURCE)
+               return PE_SRC_Ready;
+       else
+               return PE_SNK_Ready;
+}
+
+policy_state usbpd_error_recovery(struct policy_data *policy)
+{
+       struct usbpd_data *pd_data = policy_to_usbpd(policy);
+
+       dev_err(pd_data->dev, "%s\n", __func__);
+
+       return Error_Recovery;
+}
+
+void usbpd_policy_work(struct work_struct *work)
+{
+       struct usbpd_data *pd_data = container_of(work, struct usbpd_data,
+                       worker);
+       struct policy_data *policy = &pd_data->policy;
+       int power_role = 0;
+       policy_state next_state = policy->state;
+       policy_state saved_state;
+
+       do {
+               if (!policy->plug_valid) {
+                       pr_info("%s : usbpd cable is empty\n", __func__);
+                       break;
+               }
+
+               if (policy->rx_hardreset || policy->rx_softreset
+                               || policy->plug) {
+                       saved_state = 0;
+                       next_state = 0; /* default */
+               }
+               saved_state = next_state;
+               switch (next_state) {
+               case PE_SRC_Startup:
+                       next_state = usbpd_policy_src_startup(policy);
+                       break;
+               case PE_SRC_Discovery:
+                       next_state = usbpd_policy_src_discovery(policy);
+                       break;
+               case PE_SRC_Send_Capabilities:
+                       next_state = usbpd_policy_src_send_capabilities(policy);
+                       break;
+               case PE_SRC_Negotiate_Capability:
+                       next_state = usbpd_policy_src_negotiate_capability(policy);
+                       break;
+               case PE_SRC_Transition_Supply:
+                       next_state = usbpd_policy_src_transition_supply(policy);
+                       break;
+               case PE_SRC_Ready:
+                       next_state = usbpd_policy_src_ready(policy);
+                       break;
+               case PE_SRC_Disabled:
+                       next_state = usbpd_policy_src_disabled(policy);
+                       break;
+               case PE_SRC_Capability_Response:
+                       next_state = usbpd_policy_src_capability_response(policy);
+                       break;
+               case PE_SRC_Hard_Reset:
+                       next_state = usbpd_policy_src_hard_reset(policy);
+                       break;
+               case PE_SRC_Hard_Reset_Received:
+                       next_state = usbpd_policy_src_hard_reset_received(policy);
+                       break;
+               case PE_SRC_Transition_to_default:
+                       next_state = usbpd_policy_src_transition_to_default(policy);
+                       break;
+               case PE_SRC_Give_Source_Cap:
+                       next_state = usbpd_policy_src_give_source_cap(policy);
+                       break;
+               case PE_SRC_Get_Sink_Cap:
+                       next_state = usbpd_policy_src_get_sink_cap(policy);
+                       break;
+               case PE_SRC_Wait_New_Capabilities:
+                       next_state = usbpd_policy_src_wait_new_capabilities(policy);
+                       break;
+               case PE_SRC_Send_Soft_Reset:
+                       next_state = usbpd_policy_src_send_soft_reset(policy);
+                       break;
+               case PE_SRC_Soft_Reset:
+                       next_state = usbpd_policy_src_soft_reset(policy);
+                       break;
+
+               case PE_SNK_Startup:
+                       next_state = usbpd_policy_snk_startup(policy);
+                       break;
+               case PE_SNK_Discovery:
+                       next_state = usbpd_policy_snk_discovery(policy);
+                       break;
+               case PE_SNK_Wait_for_Capabilities:
+                       next_state = usbpd_policy_snk_wait_for_capabilities(policy);
+                       break;
+               case PE_SNK_Evaluate_Capability:
+                       next_state = usbpd_policy_snk_evaluate_capability(policy);
+                       break;
+               case PE_SNK_Select_Capability:
+                       next_state = usbpd_policy_snk_select_capability(policy);
+                       break;
+               case PE_SNK_Transition_Sink:
+                       next_state = usbpd_policy_snk_transition_sink(policy);
+                       break;
+               case PE_SNK_Ready:
+                       next_state = usbpd_policy_snk_ready(policy);
+                       break;
+               case PE_SNK_Hard_Reset:
+                       next_state = usbpd_policy_snk_hard_reset(policy);
+                       break;
+               case PE_SNK_Transition_to_default:
+                       next_state = usbpd_policy_snk_transition_to_default(policy);
+                       break;
+               case PE_SNK_Give_Sink_Cap:
+                       next_state = usbpd_policy_snk_give_sink_cap(policy);
+                       break;
+               case PE_SNK_Get_Source_Cap:
+                       next_state = usbpd_policy_snk_get_source_cap(policy);
+                       break;
+               case PE_SNK_Soft_Reset:
+                       next_state = usbpd_policy_snk_soft_reset(policy);
+                       break;
+
+               case PE_DRS_Evaluate_Port:
+                       next_state = usbpd_policy_drs_evaluate_port(policy);
+                       break;
+               case PE_DRS_Evaluate_Send_Port:
+                       next_state = usbpd_policy_drs_evaluate_send_port(policy);
+                       break;
+               case PE_DRS_DFP_UFP_Evaluate_DR_Swap:
+                       next_state = usbpd_policy_drs_dfp_ufp_evaluate_dr_swap(policy);
+                       break;
+               case PE_DRS_DFP_UFP_Accept_DR_Swap:
+                       next_state = usbpd_policy_drs_dfp_ufp_accept_dr_swap(policy);
+                       break;
+               case PE_DRS_DFP_UFP_Change_to_UFP:
+                       next_state = usbpd_policy_drs_dfp_ufp_change_to_ufp(policy);
+                       break;
+               case PE_DRS_DFP_UFP_Send_DR_Swap:
+                       next_state = usbpd_policy_drs_dfp_ufp_send_dr_swap(policy);
+                       break;
+               case PE_DRS_DFP_UFP_Reject_DR_Swap:
+                       next_state = usbpd_policy_drs_dfp_ufp_reject_dr_swap(policy);
+                       break;
+               case PE_DRS_UFP_DFP_Evaluate_DR_Swap:
+                       next_state = usbpd_policy_drs_ufp_dfp_evaluate_dr_swap(policy);
+                       break;
+               case PE_DRS_UFP_DFP_Accept_DR_Swap:
+                       next_state = usbpd_policy_drs_ufp_dfp_accept_dr_swap(policy);
+                       break;
+               case PE_DRS_UFP_DFP_Change_to_DFP:
+                       next_state = usbpd_policy_drs_ufp_dfp_change_to_dfp(policy);
+                       break;
+               case PE_DRS_UFP_DFP_Send_DR_Swap:
+                       next_state = usbpd_policy_drs_ufp_dfp_send_dr_swap(policy);
+                       break;
+               case PE_DRS_UFP_DFP_Reject_DR_Swap:
+                       next_state = usbpd_policy_drs_ufp_dfp_reject_dr_swap(policy);
+                       break;
+
+               case PE_PRS_SRC_SNK_Reject_PR_Swap:
+                       next_state = usbpd_policy_prs_src_snk_reject_pr_swap(policy);
+                       break;
+               case PE_PRS_SRC_SNK_Evaluate_Swap:
+                       next_state = usbpd_policy_prs_src_snk_evaluate_swap(policy);
+                       break;
+               case PE_PRS_SRC_SNK_Send_Swap:
+                       next_state = usbpd_policy_prs_src_snk_send_swap(policy);
+                       break;
+               case PE_PRS_SRC_SNK_Accept_Swap:
+                       next_state = usbpd_policy_prs_src_snk_accept_swap(policy);
+                       break;
+               case PE_PRS_SRC_SNK_Transition_off:
+                       next_state = usbpd_policy_prs_src_snk_transition_to_off(policy);
+                       break;
+               case PE_PRS_SRC_SNK_Assert_Rd:
+                       next_state = usbpd_policy_prs_src_snk_assert_rd(policy);
+                       break;
+               case PE_PRS_SRC_SNK_Wait_Source_on:
+                       next_state = usbpd_policy_prs_src_snk_wait_source_on(policy);
+                       break;
+               case PE_PRS_SNK_SRC_Reject_Swap:
+                       next_state = usbpd_policy_prs_snk_src_reject_swap(policy);
+                       break;
+               case PE_PRS_SNK_SRC_Evaluate_Swap:
+                       next_state = usbpd_policy_prs_snk_src_evaluate_swap(policy);
+                       break;
+               case PE_PRS_SNK_SRC_Send_Swap:
+                       next_state = usbpd_policy_prs_snk_src_send_swap(policy);
+                       break;
+               case PE_PRS_SNK_SRC_Accept_Swap:
+                       next_state = usbpd_policy_prs_snk_src_accept_swap(policy);
+                       break;
+               case PE_PRS_SNK_SRC_Transition_off:
+                       next_state = usbpd_policy_prs_snk_src_transition_to_off(policy);
+                       break;
+               case PE_PRS_SNK_SRC_Assert_Rp:
+                       next_state = usbpd_policy_prs_snk_src_assert_rp(policy);
+                       break;
+               case PE_PRS_SNK_SRC_Source_on:
+                       next_state = usbpd_policy_prs_snk_src_source_on(policy);
+                       break;
+               case PE_VCS_Evaluate_Swap:
+                       next_state = usbpd_policy_vcs_evaluate_swap(policy);
+                       break;
+               case PE_VCS_Accept_Swap:
+                       next_state = usbpd_policy_vcs_accept_swap(policy);
+                       break;
+               case PE_VCS_Wait_for_VCONN:
+                       next_state = usbpd_policy_vcs_wait_for_vconn(policy);
+                       break;
+               case PE_VCS_Turn_Off_VCONN:
+                       next_state = usbpd_policy_vcs_turn_off_vconn(policy);
+                       break;
+               case PE_VCS_Turn_On_VCONN:
+                       next_state = usbpd_policy_vcs_turn_on_vconn(policy);
+                       break;
+               case PE_VCS_Send_PS_RDY:
+                       next_state = usbpd_policy_vcs_send_ps_rdy(policy);
+                       break;
+               case PE_VCS_Send_Swap:
+                       next_state = usbpd_policy_vcs_send_swap(policy);
+                       break;
+               case PE_VCS_Reject_VCONN_Swap:
+                       next_state = usbpd_policy_vcs_reject_vconn_swap(policy);
+                       break;
+
+               case PE_UFP_VDM_Get_Identity:
+                       next_state = usbpd_policy_ufp_vdm_get_identity(policy);
+                       break;
+               case PE_UFP_VDM_Send_Identity:
+                       next_state = usbpd_policy_ufp_vdm_send_identity(policy);
+                       break;
+               case PE_UFP_VDM_Get_Identity_NAK:
+                       next_state = usbpd_policy_ufp_vdm_get_identity_nak(policy);
+                       break;
+               case PE_UFP_VDM_Get_SVIDs:
+                       next_state = usbpd_policy_ufp_vdm_get_svids(policy);
+                       break;
+               case PE_UFP_VDM_Send_SVIDs:
+                       next_state = usbpd_policy_ufp_vdm_send_svids(policy);
+                       break;
+               case PE_UFP_VDM_Get_SVIDs_NAK:
+                       next_state = usbpd_policy_ufp_vdm_get_svids_nak(policy);
+                       break;
+               case PE_UFP_VDM_Get_Modes:
+                       next_state = usbpd_policy_ufp_vdm_get_modes(policy);
+                       break;
+               case PE_UFP_VDM_Send_Modes:
+                       next_state = usbpd_policy_ufp_vdm_send_modes(policy);
+                       break;
+               case PE_UFP_VDM_Get_Modes_NAK:
+                       next_state = usbpd_policy_ufp_vdm_get_modes_nak(policy);
+                       break;
+               case PE_UFP_VDM_Evaluate_Mode_Entry:
+                       next_state = usbpd_policy_ufp_vdm_evaluate_mode_entry(policy);
+                       break;
+               case PE_UFP_VDM_Mode_Entry_ACK:
+                       next_state = usbpd_policy_ufp_vdm_mode_entry_ack(policy);
+                       break;
+               case PE_UFP_VDM_Mode_Entry_NAK:
+                       next_state = usbpd_policy_ufp_vdm_mode_entry_nak(policy);
+                       break;
+               case PE_UFP_VDM_Mode_Exit:
+                       next_state = usbpd_policy_ufp_vdm_mode_exit(policy);
+                       break;
+               case PE_UFP_VDM_Mode_Exit_ACK:
+                       next_state = usbpd_policy_ufp_vdm_mode_exit_ack(policy);
+                       break;
+               case PE_UFP_VDM_Mode_Exit_NAK:
+                       next_state = usbpd_policy_ufp_vdm_mode_exit_nak(policy);
+                       break;
+               case PE_UFP_VDM_Attention_Request:
+                       next_state = usbpd_policy_ufp_vdm_attention_request(policy);
+                       break;
+               case PE_UFP_VDM_Evaluate_Status:
+                       next_state = usbpd_policy_ufp_vdm_evaluate_status(policy);
+                       break;
+               case PE_UFP_VDM_Status_ACK:
+                       next_state = usbpd_policy_ufp_vdm_status_ack(policy);
+                       break;
+               case PE_UFP_VDM_Status_NAK:
+                       next_state = usbpd_policy_ufp_vdm_status_nak(policy);
+                       break;
+               case PE_UFP_VDM_Evaluate_Configure:
+                       next_state = usbpd_policy_ufp_vdm_evaluate_configure(policy);
+                       break;
+               case PE_UFP_VDM_Configure_ACK:
+                       next_state = usbpd_policy_ufp_vdm_configure_ack(policy);
+                       break;
+               case PE_UFP_VDM_Configure_NAK:
+                       next_state = usbpd_policy_ufp_vdm_configure_nak(policy);
+                       break;
+               case PE_DFP_VDM_Identity_Request:
+                       next_state = usbpd_policy_dfp_vdm_identity_request(policy);
+                       break;
+               case PE_DFP_VDM_Identity_ACKed:
+                       next_state = usbpd_policy_dfp_vdm_identity_acked(policy);
+                       break;
+               case PE_DFP_VDM_Identity_NAKed:
+                       next_state = usbpd_policy_dfp_vdm_identity_naked(policy);
+                       break;
+               case PE_DFP_VDM_SVIDs_Request:
+                       next_state = usbpd_policy_dfp_vdm_svids_request(policy);
+                       break;
+               case PE_DFP_VDM_SVIDs_ACKed:
+                       next_state = usbpd_policy_dfp_vdm_svids_acked(policy);
+                       break;
+               case PE_DFP_VDM_SVIDs_NAKed:
+                       next_state = usbpd_policy_dfp_vdm_svids_naked(policy);
+                       break;
+               case PE_DFP_VDM_Modes_Request:
+                       next_state = usbpd_policy_dfp_vdm_modes_request(policy);
+                       break;
+               case PE_DFP_VDM_Modes_ACKed:
+                       next_state = usbpd_policy_dfp_vdm_modes_acked(policy);
+                       break;
+               case PE_DFP_VDM_Modes_NAKed:
+                       next_state = usbpd_policy_dfp_vdm_modes_naked(policy);
+                       break;
+               case PE_DFP_VDM_Mode_Entry_Request:
+                       next_state = usbpd_policy_dfp_vdm_entry_request(policy);
+                       break;
+               case PE_DFP_VDM_Mode_Entry_ACKed:
+                       next_state = usbpd_policy_dfp_vdm_entry_acked(policy);
+                       break;
+               case PE_DFP_VDM_Mode_Entry_NAKed:
+                       next_state = usbpd_policy_dfp_vdm_entry_naked(policy);
+                       break;
+               case PE_DFP_VDM_Mode_Exit_Request:
+                       next_state = usbpd_policy_dfp_vdm_exit_request(policy);
+                       break;
+               case PE_DFP_VDM_Mode_Exit_ACKed:
+                       next_state = usbpd_policy_dfp_vdm_exit_acked(policy);
+                       break;
+               case PE_DFP_VDM_Mode_Exit_NAKed:
+                       next_state = usbpd_policy_dfp_vdm_exit_naked(policy);
+                       break;
+               case PE_DFP_VDM_Attention_Request:
+                       next_state = usbpd_policy_dfp_vdm_attention_request(policy);
+                       break;
+               case PE_DFP_VDM_Status_Update:
+                       next_state = usbpd_policy_dfp_vdm_status_update(policy);
+                       break;
+               case PE_DFP_VDM_Status_Update_ACKed:
+                       next_state = usbpd_policy_dfp_vdm_status_update_acked(policy);
+                       break;
+               case PE_DFP_VDM_Status_Update_NAKed:
+                       next_state = usbpd_policy_dfp_vdm_status_update_naked(policy);
+                       break;
+               case PE_DFP_VDM_DisplayPort_Configure:
+                       next_state = usbpd_policy_dfp_vdm_displayport_configure(policy);
+                       break;
+               case PE_DFP_VDM_DisplayPort_Configure_ACKed:
+                       next_state = usbpd_policy_dfp_vdm_displayport_configure_acked(policy);
+                       break;
+               case PE_DFP_VDM_DisplayPort_Configure_NAKed:
+                       next_state = usbpd_policy_dfp_vdm_displayport_configure_naked(policy);
+                       break;
+               case PE_DFP_UVDM_Send_Message:
+                       next_state = usbpd_policy_dfp_uvdm_send_message(policy);
+                       break;
+               case PE_DFP_UVDM_Receive_Message:
+                       next_state = usbpd_policy_dfp_uvdm_receive_message(policy);
+                       break;
+               case Error_Recovery:
+                       next_state = usbpd_error_recovery(policy);
+                       break;
+
+               default:
+                       pd_data->phy_ops.get_power_role(pd_data, &power_role);
+                       pr_info("%s, %d\n", __func__, power_role);
+
+                       if (power_role == USBPD_SINK) {
+                               pr_info("%s, SINK\n", __func__);
+                               if (policy->rx_hardreset) {
+                                       policy->rx_hardreset = 0;
+                                       next_state = PE_SNK_Transition_to_default;
+                               } else if (policy->rx_softreset) {
+                                       policy->rx_softreset = 0;
+                                       next_state = PE_SNK_Soft_Reset;
+                               } else if (policy->plug) {
+                                       policy->plug = 0;
+                                       next_state = PE_SNK_Startup;
+                               } else {
+                                       next_state = PE_SNK_Startup;
+                               }
+                       } else {
+                               pr_info("%s, SOURCE\n", __func__);
+                               if (policy->rx_hardreset) {
+                                       policy->rx_hardreset = 0;
+                                       next_state = PE_SRC_Hard_Reset_Received;
+                               } else if (policy->rx_softreset) {
+                                       policy->rx_softreset = 0;
+                                       next_state = PE_SRC_Soft_Reset;
+                               } else if (policy->plug) {
+                                       policy->plug = 0;
+                                       next_state = PE_SRC_Startup;
+                               } else {
+                                       next_state = PE_SRC_Startup;
+                               }
+                       }
+                       break;
+               }
+       dev_info(pd_data->dev, "%s saved state %x next_state %x \n", __func__, saved_state, next_state);
+       } while (saved_state != next_state);
+
+       policy->state = next_state;
+       dev_info(pd_data->dev, "%s Finished\n", __func__);
+}
+
+void usbpd_init_policy(struct usbpd_data *pd_data)
+{
+       int i;
+       struct policy_data *policy = &pd_data->policy;
+
+       policy->state = 0;
+       policy->rx_hardreset = 0;
+       policy->rx_softreset = 0;
+       policy->plug = 0;
+       policy->rx_msg_header.word = 0;
+       policy->tx_msg_header.word = 0;
+       policy->modal_operation = 0;
+       policy->sink_cap_received = 0;
+       policy->send_sink_cap = 0;
+       for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++) {
+               policy->rx_data_obj[i].object = 0;
+               policy->tx_data_obj[i].object = 0;
+       }
+}
+
+void usbpd_kick_policy_work(struct device *dev)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+
+       schedule_work(&pd_data->worker);
+}
+
index f83e74c75fb131a831b4d53c3c2c15a107b34435..1bf5076a58ecd45d64192f3c14cf5eefc4e22913 100644 (file)
 #include <linux/fs.h>
 #include <linux/uaccess.h>
 #include <linux/ccic/usbpd_sysfs.h>
+#ifdef CONFIG_CCIC_S2MM005
 #include <linux/ccic/s2mm005_usbpd.h>
 #include <linux/ccic/s2mm005_usbpd_fw.h>
 #include <linux/ccic/s2mm005_usbpd_phy.h>
+#endif
+#ifdef CONFIG_CCIC_S2MU106
+#include <linux/ccic/usbpd.h>
+#endif
 
+#ifdef CONFIG_CCIC_S2MM005
 static ssize_t s2mm005_cur_ver_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -204,11 +210,34 @@ static ssize_t ccic_store_firmware_update(struct device *dev,
        return size;
 }
 static DEVICE_ATTR(fw_update, 0220, NULL, ccic_store_firmware_update);
+#endif
+#ifdef CONFIG_CCIC_S2MU106
+static ssize_t ccic_connector_side_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct usbpd_data *pd_data = dev_get_drvdata(dev);
+       int ret = 0;
+       if (!pd_data) {
+               pr_err("%s pd_data is null!!\n", __func__);
+               return -ENODEV;
+       }
+
+       ret = pd_data->phy_ops.get_side_check(pd_data);
+       pr_info("%s usbpd side check: %d\n", __func__, ret);
 
+       return sprintf(buf, "%d\n", ret);
+}
+static DEVICE_ATTR(usb_direction, 0444, ccic_connector_side_show, NULL);
+#endif
 static struct attribute *ccic_attributes[] = {
+#ifdef CONFIG_CCIC_S2MM005
        &dev_attr_cur_version.attr,
        &dev_attr_fw_update.attr,
        &dev_attr_fw_update_status.attr,
+#endif
+#ifdef CONFIG_CCIC_S2MU106
+       &dev_attr_usb_direction.attr,
+#endif
        NULL
 };
 
index c3735a6f3d05126ed5394e97e8f67565988fdfc1..3983b0b1f52a533e1bb1b4b52afc21566158fd7b 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <linux/device.h>
 #include <linux/types.h>
-#include <linux/ccic/usbpd_msg.h>
+#include <linux/ccic/s2mm005_usbpd_msg.h>
 #include <linux/ccic/usbpd_typec.h>
 #include <linux/ccic/usbpd_config.h>
 #if defined(CONFIG_SAMSUNG_BATTERY)
diff --git a/include/linux/ccic/s2mm005_usbpd_msg.h b/include/linux/ccic/s2mm005_usbpd_msg.h
new file mode 100644 (file)
index 0000000..4643f81
--- /dev/null
@@ -0,0 +1,188 @@
+#ifndef __USBPD_MSG_H__
+#define __USBPD_MSG_H__
+
+typedef union {
+       u16 word;
+       u8  byte[2];
+
+       struct {
+               unsigned msg_type:4;
+               unsigned:1;
+               unsigned port_data_role:1;
+               unsigned spec_revision:2;
+               unsigned port_power_role:1;
+               unsigned msg_id:3;
+               unsigned num_data_objs:3;
+               unsigned:1;
+       };
+} msg_header_type;
+
+typedef union {
+       u32 object;
+       u16 word[2];
+       u8  byte[4];
+
+       struct {
+               unsigned:30;
+               unsigned supply_type:2;
+       } power_data_obj_supply_type;
+
+       struct {
+               unsigned max_current:10;        /* 10mA units */
+               unsigned voltage:10;            /* 50mV units */
+               unsigned peak_current:2;
+               unsigned:3;
+               unsigned data_role_swap:1;
+               unsigned usb_comm_capable:1;
+               unsigned externally_powered:1;
+               unsigned usb_suspend_support:1;
+               unsigned dual_role_power:1;
+               unsigned supply:2;
+       } power_data_obj;
+
+       struct {
+               unsigned op_current:10; /* 10mA units */
+               unsigned voltage:10;    /* 50mV units */
+               unsigned:5;
+               unsigned data_role_swap:1;
+               unsigned usb_comm_capable:1;
+               unsigned externally_powered:1;
+               unsigned higher_capability:1;
+               unsigned dual_role_power:1;
+               unsigned supply_type:2;
+       } power_data_obj_sink;
+
+       struct {
+               unsigned max_current:10;        /* 10mA units */
+               unsigned voltage:10;            /* 50mV units */
+               unsigned peak_current:2;
+               unsigned:3;
+               unsigned data_role_swap:1;
+               unsigned usb_comm_capable:1;
+               unsigned externally_powered:1;
+               unsigned usb_suspend_support:1;
+               unsigned dual_role_power:1;
+               unsigned supply_type:2;
+       } power_data_obj_fixed;
+
+       struct {
+               unsigned max_current:10;        /* 10mA units */
+               unsigned min_voltage:10;        /* 50mV units */
+               unsigned max_voltage:10;        /* 50mV units */
+               unsigned supply_type:2;
+       } power_data_obj_variable;
+
+       struct {
+               unsigned max_power:10;          /* 250mW units */
+               unsigned min_voltage:10;        /* 50mV units  */
+               unsigned max_voltage:10;        /* 50mV units  */
+               unsigned supply_type:2;
+       } power_data_obj_battery;
+
+       struct {
+               unsigned min_current:10;        /* 10mA units */
+               unsigned op_current:10;         /* 10mA units */
+               unsigned:4;
+               unsigned no_usb_suspend:1;
+               unsigned usb_comm_capable:1;
+               unsigned capability_mismatch:1;
+               unsigned give_back:1;
+               unsigned object_position:3;
+               unsigned:1;
+       } request_data_object;
+
+       struct {
+               unsigned max_power:10;          /* 250mW units */
+               unsigned op_power:10;           /* 250mW units */
+               unsigned:4;
+               unsigned no_usb_suspend:1;
+               unsigned usb_comm_capable:1;
+               unsigned capability_mismatch:1;
+               unsigned give_back:1;
+               unsigned object_position:3;
+               unsigned:1;
+       } request_data_object_battery;
+
+       struct {
+               unsigned vendor_defined:15;
+               unsigned vdm_type:1;
+               unsigned vendor_id:16;
+       } unstructured_vdm;
+
+       struct {
+               unsigned command:5;
+               unsigned:1;
+               unsigned command_type:2;
+               unsigned obj_pos:3;
+               unsigned:2;
+               unsigned version:2;
+               unsigned vdm_type:1;
+               unsigned svid:16;
+       } structured_vdm;
+
+       struct {
+               unsigned usb_vendor_id:16;
+               unsigned:10;
+               unsigned modal_operation:1;
+               unsigned product_type:3;
+               unsigned data_capable_usb_device:1;
+               unsigned data_capable_usb_host:1;
+       } discover_identity_id_header;
+
+       struct {
+               unsigned device_version:16;
+               unsigned usb_product_id:16;
+       } discover_identity_product_vdo;
+
+       struct {
+               unsigned svid_1:16;
+               unsigned svid_0:16;
+       } discover_svids_vdo;
+
+       struct {
+               unsigned port_capability:2;
+               unsigned signalling_dp:4;
+               unsigned receptacle_indication:1;
+               unsigned usb_2p0_not_used:1;
+               unsigned dfp_d_pin_assignments:8;
+               unsigned ufp_d_pin_assignments:8;
+               unsigned dp_mode_vdo_reserved:8;
+       } discover_mode_dp_capability;
+
+       struct {
+               unsigned port_capability:2;
+               unsigned displayport_protocol:4;
+               unsigned receptacle_indication:1;
+               unsigned usb_r2_signaling:1;
+               unsigned dfp_d_pin_assignments:8;
+               unsigned ufp_d_pin_assignments:8;
+               unsigned rsvd:8;
+       } displayport_capabilities;
+
+       struct {
+               unsigned port_connected:2;
+               unsigned power_low:1;
+               unsigned enabled:1;
+               unsigned multi_function_preferred:1;
+               unsigned usb_configuration_request:1;
+               unsigned exit_displayport_mode_request:1;
+               unsigned hpd_state:1;
+               unsigned irq_hpd:1;
+               unsigned rsvd:23;
+       } dp_status;
+
+       struct{
+               unsigned select_configuration:2;
+               unsigned displayport_protocol:4;
+               unsigned rsvd1:2;
+               unsigned ufp_u_pin_assignment:8;
+               unsigned rsvd2:16;
+       } dp_configurations;
+
+       struct{
+               unsigned svid_1:16;
+               unsigned svid_0:16;
+       } vdm_svid;
+} data_obj_type;
+#endif
+
diff --git a/include/linux/ccic/usbpd-s2mu106.h b/include/linux/ccic/usbpd-s2mu106.h
new file mode 100644 (file)
index 0000000..13d1b37
--- /dev/null
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2016 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.
+ *
+ */
+#include <linux/wakelock.h>
+#include <linux/ccic/usbpd_msg.h>
+#if defined CONFIG_IFCONN_NOTIFIER
+#include <linux/ifconn/ifconn_notifier.h>
+#endif
+
+#include <linux/power_supply.h>
+
+#ifndef __USBPD_S2MU106_H__
+#define __USBPD_S2MU106_H__
+
+#define USBPD_DEV_NAME "usbpd-s2mu106"
+
+/* message buffer */
+#define S2MU106_MAX_NUM_MSG_OBJ (7)
+/* INTERRUPT STATUS NUM */
+#define S2MU106_MAX_NUM_INT_STATUS (7)
+
+#define S2MU106_REG_TYPEC_DIS (1 << 2)
+
+#define TA_WATER_CHK_DURATION_MS       5000
+
+/* define timer */
+#define S2MU106_ROLE_SWAP_TIME_MS              (1350)
+#define S2MU106_HARD_RESET_DELAY_MS            (300)
+#define S2MU106_WAIT_RD_DETACH_DELAY_MS                (200)
+#define S2MU106_WAIT_ATTACH_DELAY_MS           (30)
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+#define DUAL_ROLE_SET_MODE_WAIT_MS             (2000)
+#endif
+#define S2MU106_WATER_CHK_INTERVAL_TIME                (300)
+#define S2MU106_ATTACH_STATE_CHECK_TIME                (1000)
+
+#define WATER_CHK_RETRY_CNT    2
+#define IS_CC_RP(cc1, cc2)     ((cc1 == USBPD_Rp) && (cc2 == USBPD_Rp))
+#define IS_CC_WATER(cc1, cc2)  ((cc1 != USBPD_Rp) && (cc2 != USBPD_Rp))
+#define IS_ONLY_CC1_WATER(cc1, cc2)    ((cc1 != USBPD_Rp) && (cc2 == USBPD_Rp))
+#define IS_ONLY_CC2_WATER(cc1, cc2)    ((cc1 == USBPD_Rp) && (cc2 != USBPD_Rp))
+
+/*****************************************/
+/***********DEFINITION REGISTER***********/
+/*****************************************/
+#define S2MU106_RESET_REG_00           (0x00)
+
+/* reg 0x00 VBUS WAKEUP CONTROL */
+#define S2MU106_REG_VBUS_WAKEUP_DIS_SHIFT (1)
+#define S2MU106_REG_VBUS_WAKEUP_DIS \
+                       (0x1 << S2MU106_REG_VBUS_WAKEUP_DIS_SHIFT) /* 0x02 */
+
+/* reg 0x01 LPM MODE ENABLE */
+#define S2MU106_REG_LP_LDO_D_SHIFT (0)
+#define S2MU106_REG_LPM_EN_SHIFT (1)
+#define S2MU106_REG_LP_LDO_D \
+               (1 << S2MU106_REG_LP_LDO_D_SHIFT) /* 0x01 */
+#define S2MU106_REG_LPM_EN \
+               (0x1 << S2MU106_REG_LPM_EN_SHIFT) /* 0x02 */
+
+/* reg 0x02 */
+#define S2MU106_REG_CC_OCP_SHIFT (4)
+#define S2MU106_REG_CC_OCP_MASK  (0xf << S2MU106_REG_CC_OCP_SHIFT)
+
+#define S2MU106_REG_IFG_SHIFT (4)
+#define S2MU106_REG_IFG_MASK (0xf << S2MU106_REG_IFG_SHIFT) /* 0xf0 */
+
+/* reg 0x18 */
+#define S2MU106_REG_PLUG_CTRL_MODE_SHIFT       (0)
+#define S2MU106_REG_PLUG_CTRL_RP_SEL_SHIFT     (4)
+#define S2MU106_REG_PLUG_CTRL_DETECT_BAT_DISABLE_SHIFT (6)
+#define S2MU106_REG_PLUG_CTRL_DETECT_OCP_DISABLE_SHIFT (7)
+#define S2MU106_REG_PLUG_CTRL_DFP \
+               (0x1 << S2MU106_REG_PLUG_CTRL_MODE_SHIFT) /* 0x01 */
+#define S2MU106_REG_PLUG_CTRL_UFP \
+               (0x2 << S2MU106_REG_PLUG_CTRL_MODE_SHIFT) /* 0x02 */
+#define S2MU106_REG_PLUG_CTRL_DRP \
+               (0x3 << S2MU106_REG_PLUG_CTRL_MODE_SHIFT) /* 0x03 */
+#define S2MU106_REG_PLUG_CTRL_RP0 \
+               (0x0 << S2MU106_REG_PLUG_CTRL_RP_SEL_SHIFT) /* 0x00 */
+#define S2MU106_REG_PLUG_CTRL_RP80 \
+               (0x1 << S2MU106_REG_PLUG_CTRL_RP_SEL_SHIFT) /* 0x10 */
+#define S2MU106_REG_PLUG_CTRL_RP180 \
+               (0x2 << S2MU106_REG_PLUG_CTRL_RP_SEL_SHIFT) /* 0x20 */
+#define S2MU106_REG_PLUG_CTRL_MODE_MASK        \
+               (0x3 << S2MU106_REG_PLUG_CTRL_MODE_SHIFT) /* 0x03 */
+#define S2MU106_REG_PLUG_CTRL_RP_SEL_MASK \
+               (0x3 << S2MU106_REG_PLUG_CTRL_RP_SEL_SHIFT)/* 0x30 */
+#define S2MU106_REG_PLUG_CTRL_DETECT_BAT_DISABLE_MASK \
+               (0x1 << S2MU106_REG_PLUG_CTRL_DETECT_BAT_DISABLE_SHIFT)/* 0x40 */
+#define S2MU106_REG_PLUG_CTRL_DETECT_OCP_DISABLE_MASK \
+               (0x1 << S2MU106_REG_PLUG_CTRL_DETECT_OCP_DISABLE_SHIFT)/* 0x80 */
+
+/* reg 0x19 */
+#define S2MU106_REG_MSG_DATA_ROLE_SHIFT                (5)
+#define S2MU106_REG_MSG_POWER_ROLE_SHIFT       (6)
+#define S2MU106_REG_MSG_DATA_ROLE_UFP \
+               (0x0 << S2MU106_REG_MSG_DATA_ROLE_SHIFT) /* 0x00 */
+#define S2MU106_REG_MSG_DATA_ROLE_DFP \
+               (0x1 << S2MU106_REG_MSG_DATA_ROLE_SHIFT) /* 0x20 */
+#define S2MU106_REG_MSG_DATA_ROLE_MASK \
+               (0x1 << S2MU106_REG_MSG_DATA_ROLE_SHIFT) /* 0x20 */
+#define S2MU106_REG_MSG_POWER_ROLE_SINK \
+               (0x0 << S2MU106_REG_MSG_POWER_ROLE_SHIFT) /* 0x00 */
+#define S2MU106_REG_MSG_POWER_ROLE_SOURCE \
+               (0x1 << S2MU106_REG_MSG_POWER_ROLE_SHIFT) /* 0x40 */
+#define S2MU106_REG_MSG_POWER_ROLE_MASK \
+               (0x1 << S2MU106_REG_MSG_POWER_ROLE_SHIFT) /* 0x40 */
+
+#define S2MU106_REG_RD_OR_VBUS_MUX_SEL_SHIFT    (4)
+#define S2MU106_REG_RD_OR_VBUS_MUX_SEL \
+               (0x1 << S2MU106_REG_RD_OR_VBUS_MUX_SEL_SHIFT)
+
+/* reg 0x1B */
+#define S2MU106_REG_DET_RD_OR_VBUS_SHIFT       (4)
+#define S2MU106_REG_DET_RD_OR_VBUS \
+               (0x1 << S2MU106_REG_DET_RD_OR_VBUS_SHIFT) /* 0x10 */
+
+/* reg 0x1E */
+#define S2MU106_REG_USB31_EN_SHIFT             (6)
+#define S2MU106_REG_USB31_EN \
+               (0x1 << S2MU106_REG_USB31_EN_SHIFT) /* 0x40 */
+
+/* reg 0x26 */
+#define S2MU106_REG_PLUG_CTRL_CC_HOLD_BIT     (0x1)
+
+/* reg 0x27 */
+#define S2MU106_REG_PLUG_CTRL_FSM_MANUAL_EN_SHIFT      (2)
+#define S2MU106_REG_PLUG_CTRL_RpRd_PLUG_SEL_SHIFT      (3)
+#define S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN_SHIFT    (4)
+#define S2MU106_REG_PLUG_CTRL_RpRd_CC1_VCONN_SHIFT     (5)
+#define S2MU106_REG_PLUG_CTRL_RpRd_CC2_VCONN_SHIFT     (6)
+#define S2MU106_REG_PLUG_CTRL_RpRd_MANUAL_EN_SHIFT     (7)
+
+#define S2MU106_REG_PLUG_CTRL_FSM_MANUAL_EN \
+               (0x1 << S2MU106_REG_PLUG_CTRL_FSM_MANUAL_EN_SHIFT) /* 0x04 */
+#define S2MU106_REG_PLUG_CTRL_RpRd_MANUAL_MASK \
+               (0x1 << S2MU106_REG_PLUG_CTRL_RpRd_PLUG_SEL_SHIFT | \
+                       0x1 << S2MU106_REG_PLUG_CTRL_RpRd_MANUAL_EN_SHIFT) /* 0x88 */
+#define S2MU106_REG_PLUG_CTRL_RpRd_Rp_Source_Mode \
+               (0x1 << S2MU106_REG_PLUG_CTRL_RpRd_PLUG_SEL_SHIFT | \
+                       0x1 << S2MU106_REG_PLUG_CTRL_RpRd_MANUAL_EN_SHIFT) /* 0x88 */
+#define S2MU106_REG_PLUG_CTRL_RpRd_Rd_Sink_Mode \
+               (0x1 << S2MU106_REG_PLUG_CTRL_RpRd_MANUAL_EN_SHIFT) /* 0x80 */
+#define S2MU106_REG_PLUG_CTRL_RpRd_MANUAL_EN_MASK \
+               (0x1 << S2MU106_REG_PLUG_CTRL_RpRd_MANUAL_EN_SHIFT) /* 0x80 */
+#define S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN \
+               (0x1 << S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN_SHIFT) /* 0x10 */
+#define S2MU106_REG_PLUG_CTRL_RpRd_CC1_VCONN \
+               (0x1 << S2MU106_REG_PLUG_CTRL_RpRd_CC1_VCONN_SHIFT) /* 0x20 */
+#define S2MU106_REG_PLUG_CTRL_RpRd_CC2_VCONN \
+               (0x1 << S2MU106_REG_PLUG_CTRL_RpRd_CC2_VCONN_SHIFT) /* 0x40 */
+#define S2MU106_REG_PLUG_CTRL_RpRd_VCONN_MASK \
+               (0x1 << S2MU106_REG_PLUG_CTRL_VCONN_MANUAL_EN_SHIFT | \
+               0x1 << S2MU106_REG_PLUG_CTRL_RpRd_CC1_VCONN_SHIFT | \
+               0x1 << S2MU106_REG_PLUG_CTRL_RpRd_CC2_VCONN_SHIFT) /* 0x70 */
+
+/* reg 0x28 */
+#define S2MU106_REG_PLUG_CTRL_CC_MANUAL_EN_SHIFT       (4)
+#define S2MU106_REG_PLUG_CTRL_CC1_MANUAL_EN_SHIFT      (5)
+#define S2MU106_REG_PLUG_CTRL_CC2_MANUAL_EN_SHIFT      (6)
+
+#define S2MU106_REG_PLUG_CTRL_FSM_MANUAL_INPUT_MASK    (0xf)
+#define S2MU106_REG_PLUG_CTRL_FSM_ATTACHED_SNK         (2)
+#define S2MU106_REG_PLUG_CTRL_FSM_ATTACHED_SRC         (6)
+#define S2MU106_REG_PLUG_CTRL_FSM_ATTACH_WAIT_SRC      (5)
+#define S2MU106_REG_PLUG_CTRL_CC_MANUAL_EN \
+               (0x1 << S2MU106_REG_PLUG_CTRL_CC_MANUAL_EN_SHIFT) /* 0x10 */
+#define S2MU106_REG_PLUG_CTRL_CC1_MANUAL_ON \
+               (0x1 << S2MU106_REG_PLUG_CTRL_CC_MANUAL_EN_SHIFT | \
+               0x1 << S2MU106_REG_PLUG_CTRL_CC1_MANUAL_EN_SHIFT) /* 0x30 */
+#define S2MU106_REG_PLUG_CTRL_CC2_MANUAL_ON \
+               (0x1 << S2MU106_REG_PLUG_CTRL_CC_MANUAL_EN_SHIFT | \
+               0x1 << S2MU106_REG_PLUG_CTRL_CC2_MANUAL_EN_SHIFT) /* 0x50 */
+#define S2MU106_REG_PLUG_CTRL_CC_MANUAL_MASK \
+               (0x1 << S2MU106_REG_PLUG_CTRL_CC_MANUAL_EN_SHIFT | \
+               0x1 << S2MU106_REG_PLUG_CTRL_CC1_MANUAL_EN_SHIFT | \
+               0x1 << S2MU106_REG_PLUG_CTRL_CC2_MANUAL_EN_SHIFT) /* 0x70 */
+
+/* reg 0x2E */
+#define S2MU106_REG_PLUG_CTRL_VDM_DISABLE_SHIFT                        (1)
+#define S2MU106_REG_PLUG_CTRL_UFP_ATTACH_OPT_SHIFT             (5)
+#define S2MU106_REG_PLUG_CTRL_ECO_SRC_CAP_RDY_SHIFT            (6)
+#define S2MU106_REG_PLUG_CTRL_UFP_ATTACH_OPT \
+               (0x1 << S2MU106_REG_PLUG_CTRL_UFP_ATTACH_OPT_SHIFT) /* 0x20 */
+
+#define S2MU106_REG_PLUG_CTRL_VDM_DISABLE \
+               (0x1 << S2MU106_REG_PLUG_CTRL_VDM_DISABLE_SHIFT) /* 0x02 */
+#define S2MU106_REG_PLUG_CTRL_ECO_SRC_CAP_RDY \
+               (0x1 << S2MU106_REG_PLUG_CTRL_ECO_SRC_CAP_RDY_SHIFT) /* 0x80 */
+
+/* reg 0x90 (For S2MU106_REG_MSG_SEND_CON) */
+#define S2MU106_REG_MSG_SEND_CON_SEND_MSG_EN_SHIFT     (0)
+#define S2MU106_REG_MSG_SEND_CON_OP_MODE_SHIFT         (1)
+#define S2MU106_REG_MSG_SEND_CON_SOP_SHIFT             (2)
+
+#define S2MU106_REG_MSG_SEND_CON_SEND_MSG_EN \
+               (0x1 << S2MU106_REG_MSG_SEND_CON_SEND_MSG_EN_SHIFT) /* 0x01 */
+#define S2MU106_REG_MSG_SEND_CON_OP_MODE \
+               (0x1 << S2MU106_REG_MSG_SEND_CON_OP_MODE_SHIFT) /* 0x02 */
+#define S2MU106_REG_MSG_SEND_CON_SOP \
+               (0x0 << S2MU106_REG_MSG_SEND_CON_SOP_SHIFT) /* 0x00 */
+#define S2MU106_REG_MSG_SEND_CON_SOP_Prime \
+               (0x1 << S2MU106_REG_MSG_SEND_CON_SOP_SHIFT) /* 0x04 */
+#define S2MU106_REG_MSG_SEND_CON_SOP_DPrime \
+               (0x2 << S2MU106_REG_MSG_SEND_CON_SOP_SHIFT) /* 0x08 */
+#define S2MU106_REG_MSG_SEND_CON_SOP_PDebug \
+               (0x3 << S2MU106_REG_MSG_SEND_CON_SOP_SHIFT) /* 0x0C */
+#define S2MU106_REG_MSG_SEND_CON_SOP_DPDebug \
+               (0x4 << S2MU106_REG_MSG_SEND_CON_SOP_SHIFT) /* 0x10 */
+#define S2MU106_REG_MSG_SEND_CON_SOP_HardRST \
+               (0x5 << S2MU106_REG_MSG_SEND_CON_SOP_SHIFT) /* 0x14 */
+#define S2MU106_REG_MSG_SEND_CON_SOP_CableRST \
+               (0x6 << S2MU106_REG_MSG_SEND_CON_SOP_SHIFT) /* 0x18 */
+
+/* reg 0xB2 */
+#define S2MU106_PDIC_RID_SHIFT         (5)
+#define S2MU106_PDIC_RID_MASK          (0x7 << S2MU106_PDIC_RID_SHIFT) /* 0xE0 */
+
+/* reg 0xB3 */
+#define S2MU106_REG_CTRL_MON_CC1_SHIFT         (0)
+#define S2MU106_REG_CTRL_MON_CC2_SHIFT         (3)
+#define S2MU106_REG_CTRL_MON_CC1_MASK \
+               (0x7 << S2MU106_REG_CTRL_MON_CC1_SHIFT) /* 0x07 */
+#define S2MU106_REG_CTRL_MON_CC2_MASK \
+               (0x7 << S2MU106_REG_CTRL_MON_CC2_SHIFT) /* 0x38 */
+
+/* reg 0xB4 */
+#define S2MU106_PDIC_PLUG_ATTACH_DONE_SHIFT    (1)
+#define S2MU106_PDIC_SINK_SEL_MONITOR_SHIFT    (2)
+#define S2MU106_PDIC_SOURCE_SEL_MONITOR_SHIFT  (3)
+
+#define S2MU106_PDIC_SINK (1 << S2MU106_PDIC_SINK_SEL_MONITOR_SHIFT \
+               | 1 << S2MU106_PDIC_PLUG_ATTACH_DONE_SHIFT) /* 0x06 */
+#define S2MU106_PDIC_SOURCE (1 << S2MU106_PDIC_SOURCE_SEL_MONITOR_SHIFT \
+               | 1 << S2MU106_PDIC_PLUG_ATTACH_DONE_SHIFT) /* 0x0A */
+#define S2MU106_PDIC_ATTACH_MASK (1 << S2MU106_PDIC_PLUG_ATTACH_DONE_SHIFT) /* 0x02 */
+#define S2MU106_PR_MASK (S2MU106_PDIC_SINK | S2MU106_PDIC_SOURCE) /* 0x0E */
+
+/* reg 0xF7 */
+#define S2MU106_REG_ETC_SOFT_RESET_EN_SHIFT    (1)
+#define S2MU106_REG_ETC_SOFT_RESET_EN \
+               (0x1 << S2MU106_REG_ETC_SOFT_RESET_EN_SHIFT) /* 0x02 */
+#define S2MU106_REG_ETC_SOFT_RESET_DIS \
+               (0x0 << S2MU106_REG_ETC_SOFT_RESET_EN_SHIFT) /* 0x00 */
+
+/* reg 0xF8 */
+#define S2MU106_REG_ID_MONITOR_MSG_ID_MASK     (0x07)
+
+
+/*****************************************/
+/***********DEFINITION INTERRUPT**********/
+/*****************************************/
+#define S2MU106_REG_INT_STATUS0_MSG_ACCEPT    (1<<0)
+#define S2MU106_REG_INT_STATUS0_MSG_GOODCRC   (1<<1)
+#define S2MU106_REG_INT_STATUS0_VDM_ATTENTION (1<<2)
+#define S2MU106_REG_INT_STATUS0_VDM_EXIT      (1<<3)
+#define S2MU106_REG_INT_STATUS0_VDM_ENTER     (1<<4)
+#define S2MU106_REG_INT_STATUS0_VDM_DISCOVER_MODE (1<<5)
+#define S2MU106_REG_INT_STATUS0_VDM_DISCOVER_SVID (1<<6)
+#define S2MU106_REG_INT_STATUS0_VDM_DISCOVER_ID   (1<<7)
+
+/* reg 0xE1 */
+#define S2MU106_REG_INT_STATUS1_MSG_PING      (1<<7)
+#define S2MU106_REG_INT_STATUS1_MSG_GOTOMIN   (1<<6)
+#define S2MU106_REG_INT_STATUS1_MSG_REJECT    (1<<5)
+#define S2MU106_REG_INT_STATUS1_MSG_PSRDY     (1<<4)
+#define S2MU106_REG_INT_STATUS1_MSG_GETSRCCAP (1<<3)
+#define S2MU106_REG_INT_STATUS1_MSG_GETSNKCAP (1<<2)
+#define S2MU106_REG_INT_STATUS1_MSG_DR_SWAP   (1<<1)
+#define S2MU106_REG_INT_STATUS1_MSG_PR_SWAP   (1<<0)
+
+/* reg 0xE2 */
+#define S2MU106_REG_INT_STATUS2_MSG_VCONN_SWAP (1<<7)
+#define S2MU106_REG_INT_STATUS2_MSG_WAIT       (1<<6)
+#define S2MU106_REG_INT_STATUS2_MSG_SRC_CAP    (1<<5)
+#define S2MU106_REG_INT_STATUS2_MSG_SNK_CAP    (1<<4)
+#define S2MU106_REG_INT_STATUS2_MSG_REQUEST    (1<<3)
+#define S2MU106_REG_INT_STATUS2_MSG_SOFTRESET  (1<<2)
+#define S2MU106_REG_INT_STATUS2_WAKEUP         (1<<0)
+
+/* reg 0xE3 */
+#define S2MU106_REG_INT_STATUS3_UNS_CMD_DATA   (1<<5)
+
+/* reg 0xE4 */
+#define S2MU106_REG_INT_STATUS4_CC12_DET_IRQ  (1<<6)
+#define S2MU106_REG_INT_STATUS4_PLUG_IRQ      (1<<5)
+#define S2MU106_REG_INT_STATUS4_USB_DETACH    (1<<4)
+#define S2MU106_REG_INT_STATUS4_MSG_PASS      (1<<3)
+#define S2MU106_REG_INT_STATUS4_MSG_SENT      (1<<2)
+#define S2MU106_REG_INT_STATUS4_MSG_ERROR     (1<<1)
+
+/* reg 0xE5 */
+#define S2MU106_REG_INT_STATUS5_HARD_RESET     (1<<2)
+
+/* interrupt for checking message */
+#define ENABLED_INT_0  (S2MU106_REG_INT_STATUS0_MSG_ACCEPT |\
+                       S2MU106_REG_INT_STATUS0_VDM_DISCOVER_ID |\
+                       S2MU106_REG_INT_STATUS0_VDM_DISCOVER_SVID |\
+                       S2MU106_REG_INT_STATUS0_VDM_DISCOVER_MODE)
+#define ENABLED_INT_1  (S2MU106_REG_INT_STATUS1_MSG_DR_SWAP |\
+                       S2MU106_REG_INT_STATUS1_MSG_PR_SWAP |\
+                       S2MU106_REG_INT_STATUS1_MSG_GETSRCCAP |\
+                       S2MU106_REG_INT_STATUS1_MSG_GETSNKCAP |\
+                       S2MU106_REG_INT_STATUS1_MSG_REJECT |\
+                       S2MU106_REG_INT_STATUS1_MSG_PSRDY)
+#define ENABLED_INT_2  (S2MU106_REG_INT_STATUS2_MSG_SRC_CAP |\
+                       S2MU106_REG_INT_STATUS2_MSG_SNK_CAP |\
+                       S2MU106_REG_INT_STATUS2_MSG_REQUEST |\
+                       S2MU106_REG_INT_STATUS2_MSG_SOFTRESET |\
+                       S2MU106_REG_INT_STATUS2_MSG_VCONN_SWAP)
+#define ENABLED_INT_2_WAKEUP    (S2MU106_REG_INT_STATUS2_MSG_SRC_CAP |\
+                       S2MU106_REG_INT_STATUS2_MSG_SNK_CAP |\
+                       S2MU106_REG_INT_STATUS2_MSG_REQUEST |\
+                       S2MU106_REG_INT_STATUS2_MSG_SOFTRESET |\
+                       S2MU106_REG_INT_STATUS2_MSG_VCONN_SWAP |\
+                       S2MU106_REG_INT_STATUS2_WAKEUP)
+#define ENABLED_INT_3  S2MU106_REG_INT_STATUS3_UNS_CMD_DATA
+#define ENABLED_INT_4  (S2MU106_REG_INT_STATUS4_USB_DETACH |\
+                               S2MU106_REG_INT_STATUS4_PLUG_IRQ |\
+                               S2MU106_REG_INT_STATUS4_MSG_PASS)
+#define ENABLED_INT_5  (S2MU106_REG_INT_STATUS5_HARD_RESET)
+
+/* S2MU106 I2C registers */
+enum s2mu106_usbpd_reg {
+       S2MU106_REG_PD_TRIM         = 0x00,
+       S2MU106_REG_PD_CTRL                 = 0x01,
+       S2MU106_REG_PD_CTRL_2               = 0x02,
+       S2MU106_REG_ANALOG_OTP_04           = 0x04,
+       S2MU106_REG_ANALOG_OTP_08           = 0x08,
+       S2MU106_REG_ANALOG_OTP_0A       = 0x0A,
+       S2MU106_REG_PHY_CTRL_IFG            = 0x13,
+       S2MU106_REG_PLUG_CTRL_PORT          = 0x18,
+       S2MU106_REG_PLUG_CTRL_MSG           = 0x19,
+       S2MU106_REG_PLUG_CTRL_VBUS_MUX      = 0x1B,
+       S2MU106_REG_PLUG_CTRL_SET_RD_2      = 0x1C,
+       S2MU106_REG_PLUG_CTRL_SET_RP_2      = 0x1D,
+       S2MU106_REG_PLUG_CTRL_SET_RD        = 0x1E,
+       S2MU106_REG_PLUG_CTRL_SET_RP        = 0x1F,
+       S2MU106_REG_PLUG_CTRL_CC_HOLD       = 0x26,
+       S2MU106_REG_PLUG_CTRL_RpRd          = 0x27,
+       S2MU106_REG_PLUG_CTRL_CC12          = 0x28,
+       S2MU106_REG_PLUG_CTRL               = 0x2E,
+       S2MU106_REG_CTRL                    = 0x2F,
+
+       S2MU106_REG_INT_MASK0               = 0x3E,
+       S2MU106_REG_INT_MASK1               = 0x3F,
+       S2MU106_REG_INT_MASK2               = 0x40,
+       S2MU106_REG_INT_MASK3               = 0x41,
+       S2MU106_REG_INT_MASK4               = 0x42,
+       S2MU106_REG_INT_STATUS0             = 0xE0,
+       S2MU106_REG_INT_STATUS1             = 0xE1,
+       S2MU106_REG_INT_STATUS2             = 0xE2,
+       S2MU106_REG_INT_STATUS3             = 0xE3,
+       S2MU106_REG_INT_STATUS4             = 0xE4,
+       S2MU106_REG_ADC_STATUS              = 0xB2,
+       S2MU106_REG_PLUG_MON1               = 0xB3,
+       S2MU106_REG_PLUG_MON2               = 0xB4,
+       S2MU106_REG_PLUG_FSM_MON            = 0xB7,
+
+       S2MU106_REG_MSG_SEND_CON            = 0x90,
+       S2MU106_REG_MSG_TX_HEADER_L            = 0x91,
+       S2MU106_REG_MSG_TX_HEADER_H            = 0x92,
+       S2MU106_REG_MSG_TX_OBJECT0_0_L         = 0x93,
+       S2MU106_REG_MSG_TX_OBJECT0_0_H         = 0x94,
+       S2MU106_REG_MSG_TX_OBJECT0_1_L         = 0x95,
+       S2MU106_REG_MSG_TX_OBJECT0_1_H         = 0x96,
+       S2MU106_REG_MSG_TX_OBJECT1_0_L         = 0x97,
+       S2MU106_REG_MSG_TX_OBJECT1_0_H         = 0x98,
+       S2MU106_REG_MSG_TX_OBJECT1_1_L         = 0x99,
+       S2MU106_REG_MSG_TX_OBJECT1_1_H         = 0x9A,
+       S2MU106_REG_MSG_TX_OBJECT2_0_L         = 0x9B,
+       S2MU106_REG_MSG_TX_OBJECT2_0_H         = 0x9C,
+       S2MU106_REG_MSG_TX_OBJECT2_1_L         = 0x9D,
+       S2MU106_REG_MSG_TX_OBJECT2_1_H         = 0x9E,
+       S2MU106_REG_MSG_TX_OBJECT3_0_L         = 0x9F,
+       S2MU106_REG_MSG_TX_OBJECT3_0_H         = 0xA0,
+       S2MU106_REG_MSG_TX_OBJECT3_1_L         = 0xA1,
+       S2MU106_REG_MSG_TX_OBJECT3_1_H         = 0xA2,
+       S2MU106_REG_MSG_TX_OBJECT4_0_L         = 0xA3,
+       S2MU106_REG_MSG_TX_OBJECT4_0_H         = 0xA4,
+       S2MU106_REG_MSG_TX_OBJECT4_1_L         = 0xA5,
+       S2MU106_REG_MSG_TX_OBJECT4_1_H         = 0xA6,
+       S2MU106_REG_MSG_TX_OBJECT5_0_L         = 0xA7,
+       S2MU106_REG_MSG_TX_OBJECT5_0_H         = 0xA8,
+       S2MU106_REG_MSG_TX_OBJECT5_1_L         = 0xA9,
+       S2MU106_REG_MSG_TX_OBJECT5_1_H         = 0xAA,
+       S2MU106_REG_MSG_TX_OBJECT6_0_L         = 0xAB,
+       S2MU106_REG_MSG_TX_OBJECT6_0_H         = 0xAC,
+       S2MU106_REG_MSG_TX_OBJECT6_1_L         = 0xAD,
+       S2MU106_REG_MSG_TX_OBJECT6_1_H         = 0xAE,
+
+       S2MU106_REG_MSG_RX_HEADER_L            = 0xC1,
+       S2MU106_REG_MSG_RX_HEADER_H            = 0xC2,
+       S2MU106_REG_MSG_RX_OBJECT0_0_L         = 0xC3,
+       S2MU106_REG_MSG_RX_OBJECT0_0_H         = 0xC4,
+       S2MU106_REG_MSG_RX_OBJECT0_1_L         = 0xC5,
+       S2MU106_REG_MSG_RX_OBJECT0_1_H         = 0xC6,
+       S2MU106_REG_MSG_RX_OBJECT1_0_L         = 0xC7,
+       S2MU106_REG_MSG_RX_OBJECT1_0_H         = 0xC8,
+       S2MU106_REG_MSG_RX_OBJECT1_1_L         = 0xC9,
+       S2MU106_REG_MSG_RX_OBJECT1_1_H         = 0xCA,
+       S2MU106_REG_MSG_RX_OBJECT2_0_L         = 0xCB,
+       S2MU106_REG_MSG_RX_OBJECT2_0_H         = 0xCC,
+       S2MU106_REG_MSG_RX_OBJECT2_1_L         = 0xCD,
+       S2MU106_REG_MSG_RX_OBJECT2_1_H         = 0xCE,
+       S2MU106_REG_MSG_RX_OBJECT3_0_L         = 0xCF,
+       S2MU106_REG_MSG_RX_OBJECT3_0_H         = 0xD0,
+       S2MU106_REG_MSG_RX_OBJECT3_1_L         = 0xD1,
+       S2MU106_REG_MSG_RX_OBJECT3_1_H         = 0xD2,
+       S2MU106_REG_MSG_RX_OBJECT4_0_L         = 0xD3,
+       S2MU106_REG_MSG_RX_OBJECT4_0_H         = 0xD4,
+       S2MU106_REG_MSG_RX_OBJECT4_1_L         = 0xD5,
+       S2MU106_REG_MSG_RX_OBJECT4_1_H         = 0xD6,
+       S2MU106_REG_MSG_RX_OBJECT5_0_L         = 0xD7,
+       S2MU106_REG_MSG_RX_OBJECT5_0_H         = 0xD8,
+       S2MU106_REG_MSG_RX_OBJECT5_1_L         = 0xD9,
+       S2MU106_REG_MSG_RX_OBJECT5_1_H         = 0xDA,
+       S2MU106_REG_MSG_RX_OBJECT6_0_L         = 0xDB,
+       S2MU106_REG_MSG_RX_OBJECT6_0_H         = 0xDC,
+       S2MU106_REG_MSG_RX_OBJECT6_1_L         = 0xDD,
+       S2MU106_REG_MSG_RX_OBJECT6_1_H         = 0xDE,
+
+       S2MU106_REG_ETC                     = 0xF7,
+       S2MU106_REG_ID_MONITOR              = 0xF8
+};
+
+typedef enum {
+       S2MU106_THRESHOLD_128MV = 2,
+       S2MU106_THRESHOLD_171MV = 3,
+       S2MU106_THRESHOLD_214MV = 4,
+       S2MU106_THRESHOLD_257MV = 5,
+       S2MU106_THRESHOLD_300MV = 6,
+       S2MU106_THRESHOLD_342MV = 7,
+       S2MU106_THRESHOLD_385MV = 8,
+       S2MU106_THRESHOLD_428MV = 9,
+       S2MU106_THRESHOLD_450MV = 10,
+       S2MU106_THRESHOLD_471MV = 11,
+       S2MU106_THRESHOLD_492MV = 12,
+       S2MU106_THRESHOLD_514MV = 13,
+       S2MU106_THRESHOLD_535MV = 14,
+       S2MU106_THRESHOLD_557MV = 15,
+       S2MU106_THRESHOLD_578MV = 16,
+       S2MU106_THRESHOLD_600MV = 17,
+       S2MU106_THRESHOLD_621MV = 18,
+       S2MU106_THRESHOLD_642MV = 19,
+       S2MU106_THRESHOLD_685MV = 20,
+       S2MU106_THRESHOLD_1000MV = 27,
+
+       S2MU106_THRESHOLD_1200MV = 32,
+       S2MU106_THRESHOLD_1242MV = 33,
+       S2MU106_THRESHOLD_1285MV = 34,
+       S2MU106_THRESHOLD_1328MV = 35,
+       S2MU106_THRESHOLD_1371MV = 36,
+       S2MU106_THRESHOLD_1414MV = 37,
+       S2MU106_THRESHOLD_1457MV = 38,
+       S2MU106_THRESHOLD_1500MV = 39,
+       S2MU106_THRESHOLD_1542MV = 40,
+       S2MU106_THRESHOLD_1587MV = 41,
+       S2MU106_THRESHOLD_1628MV = 42,
+       S2MU106_THRESHOLD_1671MV = 43,
+       S2MU106_THRESHOLD_1714MV = 44,
+       S2MU106_THRESHOLD_1757MV = 45,
+       S2MU106_THRESHOLD_1799MV = 46,
+       S2MU106_THRESHOLD_1842MV = 47,
+       S2MU106_THRESHOLD_1885MV = 48,
+       S2MU106_THRESHOLD_1928MV = 49,
+       S2MU106_THRESHOLD_1971MV = 50,
+       S2MU106_THRESHOLD_2014MV = 51,
+       S2MU106_THRESHOLD_2057MV = 52,
+       S2MU106_THRESHOLD_2099MV = 53,
+       S2MU106_THRESHOLD_2142MV = 54,
+       S2MU106_THRESHOLD_2185MV = 55,
+       S2MU106_THRESHOLD_2228MV = 56,
+       S2MU106_THRESHOLD_2271MV = 57,
+
+       S2MU106_THRESHOLD_MAX    = 63
+} CCIC_THRESHOLD_SEL;
+
+typedef enum {
+       S2MU106_CC_OCP_255MV = 0,
+       S2MU106_CC_OCP_262MV = 1,
+       S2MU106_CC_OCP_273MV = 2,
+       S2MU106_CC_OCP_282MV = 3,
+       S2MU106_CC_OCP_301MV = 4,
+       S2MU106_CC_OCP_311MV = 5,
+       S2MU106_CC_OCP_327MV = 6,
+       S2MU106_CC_OCP_339MV = 7,
+       S2MU106_CC_OCP_375MV = 8,
+       S2MU106_CC_OCP_390MV = 9,
+       S2MU106_CC_OCP_415MV = 10,
+       S2MU106_CC_OCP_433MV = 11,
+       S2MU106_CC_OCP_478MV = 12,
+       S2MU106_CC_OCP_502MV = 13,
+       S2MU106_CC_OCP_542MV = 14,
+       S2MU106_CC_OCP_575MV = 15,
+
+       S2MU106_CC_OCP_MAX   = 16
+} CCIC_CC_OCP_SEL;
+
+typedef enum {
+       S2MU106_PHY_IFG_25US = 0,
+       S2MU106_PHY_IFG_30US = 1,
+       S2MU106_PHY_IFG_35US = 2,
+} CCIC_PHY_IFG_SEL;
+
+enum s2mu106_power_role {
+       PDIC_SINK,
+       PDIC_SOURCE
+};
+
+enum s2mu106_pdic_rid {
+       REG_RID_UNDF = 0x00,
+       REG_RID_255K = 0x03,
+       REG_RID_301K = 0x04,
+       REG_RID_523K = 0x05,
+       REG_RID_619K = 0x06,
+       REG_RID_OPEN = 0x07,
+       REG_RID_MAX  = 0x08,
+};
+
+typedef enum {
+       CLIENT_OFF = 0,
+       CLIENT_ON = 1,
+} CCIC_DEVICE_REASON;
+
+typedef enum {
+       HOST_OFF = 0,
+       HOST_ON = 1,
+} CCIC_HOST_REASON;
+
+typedef enum {
+       VBUS_OFF = 0,
+       VBUS_ON = 1,
+} CCIC_VBUS_SEL;
+
+typedef enum {
+       DET_HARD_RESET = 0,
+       DET_DETACH = 1,
+} CCIC_DETACH_TYPE;
+
+typedef enum {
+       PLUG_CTRL_RP0 = 0,
+       PLUG_CTRL_RP80 = 1,
+       PLUG_CTRL_RP180 = 2,
+       PLUG_CTRL_RP330 = 3
+} CCIC_RP_SCR_SEL;
+
+typedef enum {
+       TYPE_C_DETACH = 0,
+       TYPE_C_ATTACH_DFP = 1, /* Host */
+       TYPE_C_ATTACH_UFP = 2, /* Device */
+       TYPE_C_ATTACH_DRP = 3, /* Dual role */
+} CCIC_OTP_MODE;
+
+typedef enum {
+       PLUG_CTRL_RD = 0,
+       PLUG_CTRL_RP = 1,
+} CCIC_RP_RD_SEL;
+
+typedef enum {
+       PD_LPM_MODE = 0,
+       PD_NORMAL_MODE = 1,
+} CCIC_LPM_MODE_SEL;
+
+typedef enum {
+       VBUS_WAKEUP_ENABLE = 0,
+       VBUS_WAKEUP_DISABLE = 1,
+} CCIC_VBUS_WAKEUP_SEL;
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+struct ccic_state_work {
+       struct work_struct ccic_work;
+       int dest;
+       int id;
+       int attach;
+       int event;
+};
+#endif
+
+#if defined(CONFIG_IFCONN_NOTIFIER)
+struct ifconn_state_work {
+       struct work_struct ifconn_work;
+       int dest;
+       int id;
+       int event;
+       void *data;
+};
+#endif
+
+struct s2mu106_usbpd_data {
+       struct device *dev;
+       struct i2c_client *i2c;
+#if defined(CONFIG_CCIC_NOTIFIER)
+       struct workqueue_struct *ccic_wq;
+#endif
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       struct workqueue_struct *ifconn_wq;
+#endif
+       struct mutex _mutex;
+       struct mutex poll_mutex;
+       struct mutex lpm_mutex;
+       struct mutex cc_mutex;
+       int vconn_en;
+       int regulator_en;
+       int irq_gpio;
+       int irq;
+       int power_role;
+       int data_role;
+       int vconn_source;
+       msg_header_type header;
+       data_obj_type obj[S2MU106_MAX_NUM_MSG_OBJ];
+       u64 status_reg;
+       bool lpm_mode;
+       bool detach_valid;
+       bool is_factory_mode;
+       bool is_water_detect;
+       bool is_muic_water_detect;
+       bool is_otg_vboost;
+       bool is_otg_reboost;
+       bool is_pr_swap;
+       bool is_muic_attached;
+       bool vbus_short_check;
+       bool vbus_short;
+#ifndef CONFIG_SEC_FACTORY
+       bool lpcharge_water;
+#endif
+       int check_rid_wa;
+
+       int vbus_short_check_cnt;
+       int water_detect_cnt;
+       int check_msg_pass;
+       int rid;
+       int is_host;
+       int is_client;
+       int data_role_dual; /* data_role for dual role swap */
+       int power_role_dual; /* power_role for dual role swap */
+       int is_attached;
+       int usb_sw_sel;
+
+       int dp_is_connect;
+
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+       struct dual_role_phy_instance *dual_role;
+       struct dual_role_phy_desc *desc;
+       struct completion reverse_completion;
+       int try_state_change;
+       struct delayed_work role_swap_work;
+#endif
+       struct notifier_block type3_nb;
+       struct workqueue_struct *pdic_queue;
+       struct delayed_work plug_work;
+       struct delayed_work water_detect_handler;
+       struct delayed_work ta_water_detect_handler;
+       struct delayed_work water_dry_handler;
+
+       struct power_supply_desc ccic_desc;
+       struct power_supply *psy_ccic;
+
+       struct regulator *regulator;
+
+       /* struct wakeup_source wakeup_src; */
+       struct wake_lock wake_lock;
+};
+
+extern int s2mu106_usbpd_get_adc(void);
+extern void s2mu106_usbpd_set_muic_type(int type);
+#if defined(CONFIG_CCIC_NOTIFIER)
+extern void s2mu106_control_option_command(struct s2mu106_usbpd_data *usbpd_data, int cmd);
+#endif
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+extern void s2mu106_rprd_mode_change(struct s2mu106_usbpd_data *usbpd_data, u8 mode);
+#endif
+extern void vbus_turn_on_ctrl(struct s2mu106_usbpd_data *usbpd_data, bool enable);
+extern int s2mu106_set_lpm_mode(struct s2mu106_usbpd_data *pdic_data);
+extern int s2mu106_set_normal_mode(struct s2mu106_usbpd_data *pdic_data);
+#endif /* __USBPD_S2MU106_H__ */
diff --git a/include/linux/ccic/usbpd.h b/include/linux/ccic/usbpd.h
new file mode 100644 (file)
index 0000000..50cb646
--- /dev/null
@@ -0,0 +1,533 @@
+#ifndef __USBPD_H__
+#define __USBPD_H__
+
+#include <linux/ccic/usbpd_msg.h>
+#include <linux/muic/muic.h>
+#ifdef CONFIG_IFCONN_NOTIFIER
+#include <linux/ifconn/ifconn_notifier.h>
+#endif
+
+#define MAX_CHARGING_VOLT              12000 /* 12V */
+#define USBPD_VOLT_UNIT                        50 /* 50mV */
+#define USBPD_CURRENT_UNIT             10 /* 10mA */
+
+#define USBPD_MAX_COUNT_MSG_OBJECT     (8) /* 0..7 */
+
+/* Counter */
+#define USBPD_nMessageIDCount          (7)
+#define USBPD_nRetryCount              (3)
+#define USBPD_nHardResetCount          (4)
+#define USBPD_nCapsCount               (16)
+#define USBPD_nDiscoverIdentityCount   (20)
+
+/* Timer */
+#define tSrcTransition         (35)    /* 25~35 ms */
+#define tPSSourceOn            (480)   /* 390~480 ms */
+#define tPSSourceOff           (750)   /* 750~960 ms */
+#define tSenderResponse                (1000)  /* 1000 ms */
+#define tSenderResponseSRC     (300)   /* 1000 ms */
+#define tSendSourceCap         (10)    /* 1~2 s */
+#define tPSHardReset           (25)    /* 25~35 ms */
+#define tSinkWaitCap           (2500)  /* 2.1~2.5 s  */
+#define tPSTransition          (5500)  /* 450~550 ms */
+#define tVCONNSourceOn         (100)   /* 24~30 ms */
+#define tVDMSenderResponse     (50)    /* 24~30 ms */
+#define tVDMWaitModeEntry      (50)    /* 40~50  ms */
+#define tVDMWaitModeExit       (50)    /* 40~50  ms */
+#define tDiscoverIdentity      (50)    /* 40~50  ms */
+#define tSwapSourceStart        (20)   /* 20  ms */
+#define tTypeCSinkWaitCap       (310)  /* 310~620 ms */
+
+/* Protocol States */
+typedef enum {
+       /* Rx */
+       PRL_Rx_Layer_Reset_for_Receive  = 0x11,
+       PRL_Rx_Wait_for_PHY_Message     = 0x12,
+       PRL_Rx_Send_GoodCRC             = 0x13,
+       PRL_Rx_Store_MessageID          = 0x14,
+       PRL_Rx_Check_MessageID          = 0x15,
+
+       /* Tx */
+       PRL_Tx_PHY_Layer_Reset          = 0x21,
+       PRL_Tx_Wait_for_Message_Request = 0x22,
+       PRL_Tx_Layer_Reset_for_Transmit = 0x23,
+       PRL_Tx_Construct_Message        = 0x24,
+       PRL_Tx_Wait_for_PHY_Response    = 0x25,
+       PRL_Tx_Match_MessageID          = 0x26,
+       PRL_Tx_Message_Sent             = 0x27,
+       PRL_Tx_Check_RetryCounter       = 0x28,
+       PRL_Tx_Transmission_Error       = 0x29,
+       PRL_Tx_Discard_Message          = 0x2A,
+} protocol_state;
+
+/* Policy Engine States */
+typedef enum {
+       /* Source */
+       PE_SRC_Startup                  = 0x30,
+       PE_SRC_Discovery                = 0x31,
+       PE_SRC_Send_Capabilities        = 0x32,
+       PE_SRC_Negotiate_Capability     = 0x33,
+       PE_SRC_Transition_Supply        = 0x34,
+       PE_SRC_Ready                    = 0x35,
+       PE_SRC_Disabled                 = 0x36,
+       PE_SRC_Capability_Response      = 0x37,
+       PE_SRC_Hard_Reset               = 0x38,
+       PE_SRC_Hard_Reset_Received      = 0x39,
+       PE_SRC_Transition_to_default    = 0x3A,
+       PE_SRC_Give_Source_Cap          = 0x3B,
+       PE_SRC_Get_Sink_Cap             = 0x3C,
+       PE_SRC_Wait_New_Capabilities    = 0x3D,
+
+       /* Sink */
+       PE_SNK_Startup                  = 0x40,
+       PE_SNK_Discovery                = 0x41,
+       PE_SNK_Wait_for_Capabilities    = 0x42,
+       PE_SNK_Evaluate_Capability      = 0x43,
+       PE_SNK_Select_Capability        = 0x44,
+       PE_SNK_Transition_Sink          = 0x45,
+       PE_SNK_Ready                    = 0x46,
+       PE_SNK_Hard_Reset               = 0x47,
+       PE_SNK_Transition_to_default    = 0x48,
+       PE_SNK_Give_Sink_Cap            = 0x49,
+       PE_SNK_Get_Source_Cap           = 0x4A,
+
+       /* Source Soft Reset */
+       PE_SRC_Send_Soft_Reset          = 0x50,
+       PE_SRC_Soft_Reset               = 0x51,
+
+       /* Sink Soft Reset */
+       PE_SNK_Send_Soft_Reset          = 0x60,
+       PE_SNK_Soft_Reset               = 0x61,
+
+       /* UFP VDM */
+       PE_UFP_VDM_Get_Identity         = 0x70,
+       PE_UFP_VDM_Send_Identity        = 0x71,
+       PE_UFP_VDM_Get_Identity_NAK     = 0x72,
+       PE_UFP_VDM_Get_SVIDs            = 0x73,
+       PE_UFP_VDM_Send_SVIDs           = 0x74,
+       PE_UFP_VDM_Get_SVIDs_NAK        = 0x75,
+       PE_UFP_VDM_Get_Modes            = 0x76,
+       PE_UFP_VDM_Send_Modes           = 0x77,
+       PE_UFP_VDM_Get_Modes_NAK        = 0x78,
+       PE_UFP_VDM_Evaluate_Mode_Entry  = 0x79,
+       PE_UFP_VDM_Mode_Entry_ACK       = 0x7A,
+       PE_UFP_VDM_Mode_Entry_NAK       = 0x7B,
+       PE_UFP_VDM_Mode_Exit            = 0x7C,
+       PE_UFP_VDM_Mode_Exit_ACK        = 0x7D,
+       PE_UFP_VDM_Mode_Exit_NAK        = 0x7E,
+       PE_UFP_VDM_Attention_Request    = 0x7F,
+       PE_UFP_VDM_Evaluate_Status      = 0x80,
+       PE_UFP_VDM_Status_ACK           = 0x81,
+       PE_UFP_VDM_Status_NAK           = 0x82,
+       PE_UFP_VDM_Evaluate_Configure   = 0x83,
+       PE_UFP_VDM_Configure_ACK        = 0x84,
+       PE_UFP_VDM_Configure_NAK        = 0x85,
+
+       /* DFP VDM */
+       PE_DFP_VDM_Identity_Request             = 0x8A,
+       PE_DFP_VDM_Identity_ACKed               = 0x8B,
+       PE_DFP_VDM_Identity_NAKed               = 0x8C,
+       PE_DFP_VDM_SVIDs_Request                = 0x8D,
+       PE_DFP_VDM_SVIDs_ACKed                  = 0x8E,
+       PE_DFP_VDM_SVIDs_NAKed                  = 0x8F,
+       PE_DFP_VDM_Modes_Request                = 0x90,
+       PE_DFP_VDM_Modes_ACKed                  = 0x91,
+       PE_DFP_VDM_Modes_NAKed                  = 0x92,
+       PE_DFP_VDM_Mode_Entry_Request           = 0x93,
+       PE_DFP_VDM_Mode_Entry_ACKed             = 0x94,
+       PE_DFP_VDM_Mode_Entry_NAKed             = 0x95,
+       PE_DFP_VDM_Mode_Exit_Request            = 0x96,
+       PE_DFP_VDM_Mode_Exit_ACKed              = 0x97,
+       PE_DFP_VDM_Mode_Exit_NAKed              = 0x98,
+       PE_DFP_VDM_Status_Update                = 0x99,
+       PE_DFP_VDM_Status_Update_ACKed          = 0x9A,
+       PE_DFP_VDM_Status_Update_NAKed          = 0x9B,
+       PE_DFP_VDM_DisplayPort_Configure        = 0x9C,
+       PE_DFP_VDM_DisplayPort_Configure_ACKed  = 0x9D,
+       PE_DFP_VDM_DisplayPort_Configure_NAKed  = 0x9E,
+       PE_DFP_VDM_Attention_Request            = 0x9F,
+
+       /* Power Role Swap */
+       PE_PRS_SRC_SNK_Reject_PR_Swap   = 0xA0,
+       PE_PRS_SRC_SNK_Evaluate_Swap    = 0xA1,
+       PE_PRS_SRC_SNK_Send_Swap        = 0xA2,
+       PE_PRS_SRC_SNK_Accept_Swap      = 0xA3,
+       PE_PRS_SRC_SNK_Transition_off   = 0xA4,
+       PE_PRS_SRC_SNK_Assert_Rd        = 0xA5,
+       PE_PRS_SRC_SNK_Wait_Source_on   = 0xA6,
+       PE_PRS_SNK_SRC_Reject_Swap      = 0xA7,
+       PE_PRS_SNK_SRC_Evaluate_Swap    = 0xA8,
+       PE_PRS_SNK_SRC_Send_Swap        = 0xA9,
+       PE_PRS_SNK_SRC_Accept_Swap      = 0xAA,
+       PE_PRS_SNK_SRC_Transition_off   = 0xAB,
+       PE_PRS_SNK_SRC_Assert_Rp        = 0xAC,
+       PE_PRS_SNK_SRC_Source_on        = 0xAD,
+
+       /* Data Role Swap */
+       PE_DRS_DFP_UFP_Evaluate_DR_Swap = 0xAE,
+       PE_DRS_DFP_UFP_Accept_DR_Swap   = 0xAF,
+       PE_DRS_DFP_UFP_Change_to_UFP    = 0xB0,
+       PE_DRS_DFP_UFP_Send_DR_Swap     = 0xB1,
+       PE_DRS_DFP_UFP_Reject_DR_Swap   = 0xB2,
+       PE_DRS_UFP_DFP_Evaluate_DR_Swap = 0xB3,
+       PE_DRS_UFP_DFP_Accept_DR_Swap   = 0xB4,
+       PE_DRS_UFP_DFP_Change_to_DFP    = 0xB5,
+       PE_DRS_UFP_DFP_Send_DR_Swap     = 0xB6,
+       PE_DRS_UFP_DFP_Reject_DR_Swap   = 0xB7,
+       PE_DRS_Evaluate_Port            = 0xB8,
+       PE_DRS_Evaluate_Send_Port       = 0xB9,
+
+       /* Vconn Source Swap */
+       PE_VCS_Evaluate_Swap            = 0xC0,
+       PE_VCS_Accept_Swap              = 0xC1,
+       PE_VCS_Wait_for_VCONN           = 0xC2,
+       PE_VCS_Turn_Off_VCONN           = 0xC3,
+       PE_VCS_Turn_On_VCONN            = 0xC4,
+       PE_VCS_Send_PS_RDY              = 0xC5,
+       PE_VCS_Send_Swap                = 0xC6,
+       PE_VCS_Reject_VCONN_Swap        = 0xC7,
+
+       /* UVDM Message */
+       PE_DFP_UVDM_Send_Message        = 0xD0,
+       PE_DFP_UVDM_Receive_Message     = 0xD1,
+
+       Error_Recovery                  = 0xFF
+} policy_state;
+
+typedef enum usbpd_manager_command {
+       MANAGER_REQ_GET_SNKCAP                  = 1,
+       MANAGER_REQ_GOTOMIN                     = 1 << 2,
+       MANAGER_REQ_SRCCAP_CHANGE               = 1 << 3,
+       MANAGER_REQ_PR_SWAP                     = 1 << 4,
+       MANAGER_REQ_DR_SWAP                     = 1 << 5,
+       MANAGER_REQ_VCONN_SWAP                  = 1 << 6,
+       MANAGER_REQ_VDM_DISCOVER_IDENTITY       = 1 << 7,
+       MANAGER_REQ_VDM_DISCOVER_SVID           = 1 << 8,
+       MANAGER_REQ_VDM_DISCOVER_MODE           = 1 << 9,
+       MANAGER_REQ_VDM_ENTER_MODE              = 1 << 10,
+       MANAGER_REQ_VDM_EXIT_MODE               = 1 << 11,
+       MANAGER_REQ_VDM_ATTENTION               = 1 << 12,
+       MANAGER_REQ_VDM_STATUS_UPDATE           = 1 << 13,
+       MANAGER_REQ_VDM_DisplayPort_Configure   = 1 << 14,
+       MANAGER_REQ_NEW_POWER_SRC               = 1 << 15,
+       MANAGER_REQ_UVDM_SEND_MESSAGE           = 1 << 16,
+       MANAGER_REQ_UVDM_RECEIVE_MESSAGE                = 1 << 17,
+} usbpd_manager_command_type;
+
+typedef enum usbpd_manager_event {
+       MANAGER_DISCOVER_IDENTITY_ACKED = 0,
+       MANAGER_DISCOVER_IDENTITY_NAKED = 1,
+       MANAGER_DISCOVER_SVID_ACKED     = 2,
+       MANAGER_DISCOVER_SVID_NAKED     = 3,
+       MANAGER_DISCOVER_MODE_ACKED     = 4,
+       MANAGER_DISCOVER_MODE_NAKED     = 5,
+       MANAGER_ENTER_MODE_ACKED        = 6,
+       MANAGER_ENTER_MODE_NAKED        = 7,
+       MANAGER_EXIT_MODE_ACKED         = 8,
+       MANAGER_EXIT_MODE_NAKED         = 9,
+       MANAGER_ATTENTION_REQUEST       = 10,
+       MANAGER_STATUS_UPDATE_ACKED     = 11,
+       MANAGER_STATUS_UPDATE_NAKED     = 12,
+       MANAGER_DisplayPort_Configure_ACKED     = 13,
+       MANAGER_DisplayPort_Configure_NACKED    = 14,
+       MANAGER_NEW_POWER_SRC           = 15,
+       MANAGER_UVDM_SEND_MESSAGE               = 16,
+       MANAGER_UVDM_RECEIVE_MESSAGE            = 17,
+       MANAGER_START_DISCOVER_IDENTITY = 18,
+} usbpd_manager_event_type;
+
+enum usbpd_msg_status {
+       MSG_GOODCRC     = 1<<0,
+       MSG_ACCEPT      = 1<<1,
+       MSG_PSRDY       = 1<<2,
+       MSG_REQUEST     = 1<<3,
+       MSG_REJECT      = 1<<4,
+       MSG_WAIT        = 1<<5,
+       MSG_ERROR       = 1<<6,
+       MSG_PING        = 1<<7,
+       MSG_GET_SNK_CAP = 1<<8,
+       MSG_GET_SRC_CAP = 1<<9,
+       MSG_SNK_CAP     = 1<<10,
+       MSG_SRC_CAP     = 1<<11,
+       MSG_PR_SWAP     = 1<<12,
+       MSG_DR_SWAP     = 1<<13,
+       MSG_VCONN_SWAP  = 1<<14,
+       VDM_DISCOVER_IDENTITY   = 1<<15,
+       VDM_DISCOVER_SVID       = 1<<16,
+       VDM_DISCOVER_MODE       = 1<<17,
+       VDM_ENTER_MODE          = 1<<18,
+       VDM_EXIT_MODE           = 1<<19,
+       VDM_ATTENTION           = 1<<20,
+       VDM_DP_STATUS_UPDATE    = 1<<21,
+       VDM_DP_CONFIGURE        = 1<<22,
+       MSG_SOFTRESET           = 1<<23,
+       PLUG_DETACH             = 1<<24,
+       PLUG_ATTACH             = 1<<25,
+       MSG_HARDRESET           = 1<<26,
+       CC_DETECT               = 1<<27,
+       UVDM_MSG                = 1<<28,
+       MSG_PASS                = 1<<29,
+       MSG_RID                 = 1<<30,
+       MSG_NONE                = 1<<31,
+};
+
+/* Timer */
+enum usbpd_timer_id {
+       DISCOVER_IDENTITY_TIMER   = 1,
+       HARD_RESET_COMPLETE_TIMER = 2,
+       NO_RESPONSE_TIMER         = 3,
+       PS_HARD_RESET_TIMER       = 4,
+       PS_SOURCE_OFF_TIMER       = 5,
+       PS_SOURCE_ON_TIMER        = 6,
+       PS_TRANSITION_TIMER       = 7,
+       SENDER_RESPONSE_TIMER     = 8,
+       SINK_ACTIVITY_TIMER       = 9,
+       SINK_REQUEST_TIMER        = 10,
+       SINK_WAIT_CAP_TIMER       = 11,
+       SOURCE_ACTIVITY_TIMER     = 12,
+       SOURCE_CAPABILITY_TIMER   = 13,
+       SWAP_RECOVERY_TIMER       = 14,
+       SWAP_SOURCE_START_TIMER   = 15,
+       VCONN_ON_TIMER            = 16,
+       VDM_MODE_ENTRY_TIMER      = 17,
+       VDM_MODE_EXIT_TIMER       = 18,
+       VDM_RESPONSE_TIMER        = 19,
+       USBPD_TIMER_MAX_COUNT
+};
+
+enum usbpd_protocol_status {
+       DEFAULT_PROTOCOL_NONE   = 0,
+       MESSAGE_SENT            = 1,
+       TRANSMISSION_ERROR      = 2
+};
+
+enum usbpd_policy_informed {
+       DEFAULT_POLICY_NONE     = 0,
+       HARDRESET_RECEIVED      = 1,
+       SOFTRESET_RECEIVED      = 2,
+       PLUG_EVENT              = 3,
+       PLUG_ATTACHED           = 4,
+       PLUG_DETACHED           = 5,
+};
+
+typedef struct usbpd_phy_ops {
+       /*    1st param should be 'usbpd_data *'    */
+       int    (*tx_msg)(void *, msg_header_type *, data_obj_type *);
+       int    (*rx_msg)(void *, msg_header_type *, data_obj_type *);
+       int    (*hard_reset)(void *);
+       int    (*set_power_role)(void *, int);
+       int    (*get_power_role)(void *, int *);
+       int    (*set_data_role)(void *, int);
+       int    (*get_data_role)(void *, int *);
+       int    (*set_vconn_source)(void *, int);
+       int    (*get_vconn_source)(void *, int *);
+       int    (*set_check_msg_pass)(void *, int);
+       unsigned   (*get_status)(void *, unsigned);
+       bool   (*poll_status)(void *);
+       void   (*driver_reset)(void *);
+       int    (*set_otg_control)(void *, int);
+       void    (*get_vbus_short_check)(void *, bool *);
+       int    (*set_cc_control)(void *, int);
+       int    (*get_side_check)(void *);
+} usbpd_phy_ops_type;
+
+struct policy_data {
+       policy_state            state;
+       msg_header_type         tx_msg_header;
+       msg_header_type         rx_msg_header;
+       data_obj_type           tx_data_obj[USBPD_MAX_COUNT_MSG_OBJECT];
+       data_obj_type           rx_data_obj[USBPD_MAX_COUNT_MSG_OBJECT];
+       bool                    rx_hardreset;
+       bool                    rx_softreset;
+       bool                    plug;
+       bool                    plug_valid;
+       bool                    modal_operation;
+       bool                    abnormal_state;
+       bool                    sink_cap_received;
+       bool                    send_sink_cap;
+};
+
+struct protocol_data {
+       protocol_state          state;
+       unsigned                stored_message_id;
+       msg_header_type         msg_header;
+       data_obj_type           data_obj[USBPD_MAX_COUNT_MSG_OBJECT];
+       unsigned                status;
+};
+
+struct usbpd_counter {
+       unsigned        retry_counter;
+       unsigned        message_id_counter;
+       unsigned        caps_counter;
+       unsigned        hard_reset_counter;
+       unsigned        discover_identity_counter;
+       unsigned        swap_hard_reset_counter;
+};
+
+struct usbpd_manager_data {
+       usbpd_manager_command_type cmd;  /* request to policy engine */
+       usbpd_manager_event_type   event;    /* policy engine infromed */
+
+       msg_header_type         uvdm_msg_header;
+       data_obj_type           uvdm_data_obj[USBPD_MAX_COUNT_MSG_OBJECT];
+#if defined(CONFIG_IFCONN_NOTIFIER)
+       struct ifconn_notifier_template template;
+#endif
+       int alt_sended;
+       int vdm_en;
+       /* request */
+       int     max_power;
+       int     op_power;
+       int     max_current;
+       int     op_current;
+       int     min_current;
+       bool    giveback;
+       bool    usb_com_capable;
+       bool    no_usb_suspend;
+
+       /* source */
+       int source_max_volt;
+       int source_min_volt;
+       int source_max_power;
+
+       /* sink */
+       int sink_max_volt;
+       int sink_min_volt;
+       int sink_max_power;
+
+       /* sink cap */
+       int sink_cap_max_volt;
+
+       /* power role swap*/
+       bool power_role_swap;
+       /* data role swap*/
+       bool data_role_swap;
+       bool vconn_source_swap;
+       bool vbus_short;
+
+       bool is_samsung_accessory_enter_mode;
+       bool uvdm_first_req;
+       bool uvdm_dir;
+       struct completion uvdm_out_wait;
+       struct completion uvdm_in_wait;
+
+       uint16_t Vendor_ID;
+       uint16_t Product_ID;
+       uint16_t Device_Version;
+       int acc_type;
+       uint16_t SVID_0;
+       uint16_t SVID_1;
+       uint16_t Standard_Vendor_ID;
+
+       /* dp */
+       int dp_selected_pin;
+       int hpd;
+       int hpdirq;
+       int dp_is_connect;
+       int dp_hs_connect;
+       int pin_assignment;
+       int is_sent_pin_configuration;
+
+       struct mutex vdm_mutex;
+
+       struct usbpd_data *pd_data;
+       struct delayed_work     acc_detach_handler;
+       struct delayed_work select_pdo_handler;
+       struct delayed_work start_discover_msg_handler;
+       muic_attached_dev_t     attached_dev;
+};
+
+struct usbpd_data {
+       struct device           *dev;
+       struct device           *ccic_dev;
+       void                    *phy_driver_data;
+       struct usbpd_counter    counter;
+       struct hrtimer          timers[USBPD_TIMER_MAX_COUNT];
+       unsigned                expired_timers;
+       usbpd_phy_ops_type      phy_ops;
+       struct protocol_data    protocol_tx;
+       struct protocol_data    protocol_rx;
+       struct policy_data      policy;
+       msg_header_type         source_msg_header;
+       data_obj_type           source_data_obj;
+       msg_header_type         sink_msg_header;
+       data_obj_type           sink_data_obj[2];
+       data_obj_type           source_request_obj;
+       struct usbpd_manager_data       manager;
+       struct work_struct      worker;
+       struct completion       msg_arrived;
+       unsigned                wait_for_msg_arrived;
+};
+
+static inline struct usbpd_data *protocol_rx_to_usbpd(struct protocol_data *rx)
+{
+       return container_of(rx, struct usbpd_data, protocol_rx);
+}
+
+static inline struct usbpd_data *protocol_tx_to_usbpd(struct protocol_data *tx)
+{
+       return container_of(tx, struct usbpd_data, protocol_tx);
+}
+
+static inline struct usbpd_data *policy_to_usbpd(struct policy_data *policy)
+{
+       return container_of(policy, struct usbpd_data, policy);
+}
+
+static inline struct usbpd_data *manager_to_usbpd(struct usbpd_manager_data *manager)
+{
+       return container_of(manager, struct usbpd_data, manager);
+}
+
+extern int usbpd_init(struct device *dev, void *phy_driver_data);
+extern void usbpd_init_policy(struct usbpd_data *);
+
+extern void  usbpd_init_manager_val(struct usbpd_data *);
+extern int  usbpd_init_manager(struct usbpd_data *);
+extern void usbpd_manager_plug_attach(struct device *);
+extern void usbpd_manager_plug_detach(struct device *dev, bool notify);
+extern void usbpd_manager_acc_detach(struct device *dev);
+extern int  usbpd_manager_match_request(struct usbpd_data *);
+extern bool usbpd_manager_power_role_swap(struct usbpd_data *);
+extern bool usbpd_manager_vconn_source_swap(struct usbpd_data *);
+extern void usbpd_manager_turn_on_source(struct usbpd_data *);
+extern void usbpd_manager_turn_off_power_supply(struct usbpd_data *);
+extern void usbpd_manager_turn_off_power_sink(struct usbpd_data *);
+extern void usbpd_manager_turn_off_vconn(struct usbpd_data *);
+extern bool usbpd_manager_data_role_swap(struct usbpd_data *);
+extern int usbpd_manager_get_identity(struct usbpd_data *);
+extern int usbpd_manager_get_svids(struct usbpd_data *);
+extern int usbpd_manager_get_modes(struct usbpd_data *);
+extern int usbpd_manager_enter_mode(struct usbpd_data *);
+extern int usbpd_manager_exit_mode(struct usbpd_data *, unsigned mode);
+extern int usbpd_manager_get_status(struct usbpd_data *pd_data);
+extern int usbpd_manager_get_configure(struct usbpd_data *pd_data);
+extern int usbpd_manager_get_attention(struct usbpd_data *pd_data);
+extern void usbpd_dp_detach(struct usbpd_data *pd_data);
+
+extern void usbpd_manager_inform_event(struct usbpd_data *,
+               usbpd_manager_event_type);
+extern int usbpd_manager_evaluate_capability(struct usbpd_data *);
+extern data_obj_type usbpd_manager_select_capability(struct usbpd_data *);
+extern bool usbpd_manager_vdm_request_enabled(struct usbpd_data *);
+extern void usbpd_manager_acc_handler_cancel(struct device *);
+extern void usbpd_manager_acc_detach_handler(struct work_struct *);
+extern void usbpd_policy_work(struct work_struct *);
+extern void usbpd_protocol_tx(struct usbpd_data *);
+extern void usbpd_protocol_rx(struct usbpd_data *);
+extern void usbpd_kick_policy_work(struct device *);
+extern void usbpd_rx_hard_reset(struct device *);
+extern void usbpd_rx_soft_reset(struct usbpd_data *);
+extern void usbpd_policy_reset(struct usbpd_data *, unsigned flag);
+
+extern void usbpd_set_ops(struct device *, usbpd_phy_ops_type *);
+extern void usbpd_read_msg(struct usbpd_data *);
+extern bool usbpd_send_msg(struct usbpd_data *, msg_header_type *,
+               data_obj_type *);
+extern bool usbpd_send_ctrl_msg(struct usbpd_data *d, msg_header_type *h,
+               unsigned msg, unsigned dr, unsigned pr);
+extern unsigned usbpd_wait_msg(struct usbpd_data *pd_data, unsigned msg_status,
+               unsigned ms);
+extern void usbpd_reinit(struct device *);
+extern void usbpd_init_protocol(struct usbpd_data *);
+#endif
diff --git a/include/linux/ccic/usbpd_ext.h b/include/linux/ccic/usbpd_ext.h
new file mode 100644 (file)
index 0000000..ef0e5a2
--- /dev/null
@@ -0,0 +1,119 @@
+#if defined(CONFIG_CCIC_NOTIFIER)
+#include <linux/ccic/ccic_notifier.h>
+#endif
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+#include <linux/usb/class-dual-role.h>
+#endif
+
+
+#ifndef __USBPD_EXT_H__
+#define __USBPD_EXT_H__
+
+#ifdef CONFIG_IFCONN_NOTIFIER
+extern struct pdic_notifier_data pd_noti;
+#endif
+
+/* CCIC Dock Observer Callback parameter */
+enum {
+       CCIC_DOCK_DETACHED      = 0,
+       CCIC_DOCK_HMT           = 105,  /* Samsung Gear VR */
+       CCIC_DOCK_ABNORMAL      = 106,
+       CCIC_DOCK_MPA           = 109,  /* Samsung Multi Port Adaptor */
+       CCIC_DOCK_DEX           = 110,  /* Samsung Dex */
+       CCIC_DOCK_HDMI          = 111,  /* Samsung HDMI Dongle */
+       CCIC_DOCK_NEW           = 200,  /* For New Event  */
+};
+
+#define GEAR_VR_DETACH_WAIT_MS         (1000)
+
+/* For DP */
+#define TypeC_POWER_SINK_INPUT     0
+#define TypeC_POWER_SOURCE_OUTPUT     1
+#define TypeC_DP_SUPPORT       (0xFF01)
+
+/* Samsung Acc VID */
+#define SAMSUNG_VENDOR_ID              0x04E8
+#define SAMSUNG_MPA_VENDOR_ID          0x04B4
+/* Samsung Acc PID */
+#define GEARVR_PRODUCT_ID              0xA500
+#define GEARVR_PRODUCT_ID_1            0xA501
+#define GEARVR_PRODUCT_ID_2            0xA502
+#define GEARVR_PRODUCT_ID_3            0xA503
+#define GEARVR_PRODUCT_ID_4            0xA504
+#define GEARVR_PRODUCT_ID_5            0xA505
+#define DEXDOCK_PRODUCT_ID             0xA020
+#define HDMI_PRODUCT_ID                        0xA025
+#define MPA_PRODUCT_ID                 0x2122
+/* Samsung UVDM structure */
+#define SEC_UVDM_SHORT_DATA            0x0
+#define SEC_UVDM_LONG_DATA             0x1
+#define SEC_UVDM_ININIATOR             0x0
+#define SEC_UVDM_RESPONDER_ACK 0x1
+#define SEC_UVDM_RESPONDER_NAK 0x2
+#define SEC_UVDM_RESPONDER_BUSY        0x3
+#define SEC_UVDM_UNSTRUCTURED_VDM      0x4
+
+/*For DP Pin Assignment */
+#define DP_PIN_ASSIGNMENT_NODE 0x00000000
+#define DP_PIN_ASSIGNMENT_A    0x00000001      /* ( 1 << 0 ) */
+#define DP_PIN_ASSIGNMENT_B    0x00000002      /* ( 1 << 1 ) */
+#define DP_PIN_ASSIGNMENT_C    0x00000004      /* ( 1 << 2 ) */
+#define DP_PIN_ASSIGNMENT_D    0x00000008      /* ( 1 << 3 ) */
+#define DP_PIN_ASSIGNMENT_E    0x00000010      /* ( 1 << 4 ) */
+#define DP_PIN_ASSIGNMENT_F    0x00000020      /* ( 1 << 5 ) */
+
+/* For DP VDM Modes VDO Port_Capability */
+typedef enum {
+    num_Reserved_Capable        = 0,
+    num_UFP_D_Capable           = 1,
+    num_DFP_D_Capable           = 2,
+    num_DFP_D_and_UFP_D_Capable = 3
+} Num_DP_Port_Capability_Type;
+
+/* For DP VDM Modes VDO Receptacle_Indication */
+typedef enum {
+    num_USB_TYPE_C_PLUG        = 0,
+    num_USB_TYPE_C_Receptacle  = 1
+} Num_DP_Receptacle_Indication_Type;
+
+
+/* For DP_Status_Update Port_Connected */
+typedef enum {
+    num_Adaptor_Disable         = 0,
+    num_Connect_DFP_D           = 1,
+    num_Connect_UFP_D           = 2,
+    num_Connect_DFP_D_and_UFP_D = 3
+} Num_DP_Port_Connected_Type;
+
+/* For DP_Configure Select_Configuration */
+typedef enum {
+    num_Cfg_for_USB             = 0,
+    num_Cfg_UFP_U_as_DFP_D      = 1,
+    num_Cfg_UFP_U_as_UFP_D      = 2,
+    num_Cfg_Reserved            = 3
+} Num_DP_Sel_Configuration_Type;
+
+#if defined(CONFIG_CCIC_NOTIFIER)
+void ccic_event_work(void *data, int dest, int id, int attach, int event);
+extern void select_pdo(int num);
+#endif
+#ifdef CONFIG_CHECK_CTYPE_SIDE
+int usbpd_manager_get_side_check(void);
+#endif
+#if defined(CONFIG_IFCONN_NOTIFIER)
+void ifconn_event_work(void *pd_data, int dest, int id, int event, void *data);
+extern void select_pdo(int num);
+#endif
+#if defined(CONFIG_DUAL_ROLE_USB_INTF)
+extern void role_swap_check(struct work_struct *wk);
+extern int dual_role_is_writeable(struct dual_role_phy_instance *drp,
+                                 enum dual_role_property prop);
+extern int dual_role_get_local_prop(struct dual_role_phy_instance *dual_role,
+                                   enum dual_role_property prop,
+                                   unsigned int *val);
+extern int dual_role_set_prop(struct dual_role_phy_instance *dual_role,
+                             enum dual_role_property prop,
+                             const unsigned int *val);
+extern int dual_role_init(void *_data);
+#endif
+#endif
index 4643f81debd845d674eeb190cb2ff85c33d31dc9..3c2f3c4b6aa8695560d75890be54e31d09e73afa 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef __USBPD_MSG_H__
 #define __USBPD_MSG_H__
 
+/* for header */
+#define USBPD_REV_20   (1)
+#define PD_SID         (0xFF00)
+#define PD_SID_1       (0xFF01)
+
 typedef union {
        u16 word;
        u8  byte[2];
@@ -52,19 +57,6 @@ typedef union {
                unsigned supply_type:2;
        } power_data_obj_sink;
 
-       struct {
-               unsigned max_current:10;        /* 10mA units */
-               unsigned voltage:10;            /* 50mV units */
-               unsigned peak_current:2;
-               unsigned:3;
-               unsigned data_role_swap:1;
-               unsigned usb_comm_capable:1;
-               unsigned externally_powered:1;
-               unsigned usb_suspend_support:1;
-               unsigned dual_role_power:1;
-               unsigned supply_type:2;
-       } power_data_obj_fixed;
-
        struct {
                unsigned max_current:10;        /* 10mA units */
                unsigned min_voltage:10;        /* 50mV units */
@@ -109,6 +101,15 @@ typedef union {
                unsigned vendor_id:16;
        } unstructured_vdm;
 
+       struct {
+               unsigned data:8;
+               unsigned total_number_of_uvdm_set:4;
+               unsigned rsvd:1;
+               unsigned cmd_type:2;
+               unsigned data_type:1;
+               unsigned pid:16;
+       } sec_uvdm_header;
+
        struct {
                unsigned command:5;
                unsigned:1;
@@ -121,33 +122,17 @@ typedef union {
        } structured_vdm;
 
        struct {
-               unsigned usb_vendor_id:16;
-               unsigned:10;
-               unsigned modal_operation:1;
-               unsigned product_type:3;
-               unsigned data_capable_usb_device:1;
-               unsigned data_capable_usb_host:1;
-       } discover_identity_id_header;
+               unsigned USB_Vendor_ID:16;
+               unsigned rsvd:10;
+               unsigned Product_Type:3;
+               unsigned Data_Capable_USB_Device:1;
+               unsigned Data_Capable_USB_Host:1;
+       } id_header_vdo;
 
        struct {
-               unsigned device_version:16;
-               unsigned usb_product_id:16;
-       } discover_identity_product_vdo;
-
-       struct {
-               unsigned svid_1:16;
-               unsigned svid_0:16;
-       } discover_svids_vdo;
-
-       struct {
-               unsigned port_capability:2;
-               unsigned signalling_dp:4;
-               unsigned receptacle_indication:1;
-               unsigned usb_2p0_not_used:1;
-               unsigned dfp_d_pin_assignments:8;
-               unsigned ufp_d_pin_assignments:8;
-               unsigned dp_mode_vdo_reserved:8;
-       } discover_mode_dp_capability;
+               unsigned Device_Version:16;
+               unsigned USB_Product_ID:16;
+       } product_vdo;
 
        struct {
                unsigned port_capability:2;
@@ -169,7 +154,7 @@ typedef union {
                unsigned hpd_state:1;
                unsigned irq_hpd:1;
                unsigned rsvd:23;
-       } dp_status;
+       } displayport_status;
 
        struct{
                unsigned select_configuration:2;
@@ -177,12 +162,209 @@ typedef union {
                unsigned rsvd1:2;
                unsigned ufp_u_pin_assignment:8;
                unsigned rsvd2:16;
-       } dp_configurations;
+       } displayport_configurations;
 
        struct{
                unsigned svid_1:16;
                unsigned svid_0:16;
        } vdm_svid;
 } data_obj_type;
+
+typedef union {
+       u32 object;
+       u16 word[2];
+       u8  byte[4];
+       struct {
+               unsigned vendor_defined:15;
+               unsigned vdm_type:1;
+               unsigned vendor_id:16;
+       };
+} uvdm_header;
+
+typedef union {
+       u32 object;
+       u16 word[2];
+       u8  byte[4];
+
+       struct{
+               unsigned data:8;
+               unsigned total_set_num:4;
+               unsigned direction:1;
+               unsigned cmd_type:2;
+               unsigned data_type:1;
+               unsigned pid:16;
+       };
+} s_uvdm_header;
+       
+typedef union {
+       u32 object;
+       u16 word[2];
+       u8  byte[4];
+
+       struct{
+               unsigned cur_size:8;
+               unsigned total_size:8;
+               unsigned reserved:12;
+               unsigned order_cur_set:4;
+       };
+} s_tx_header;
+
+typedef union {
+       u32 object;
+       u16 word[2];
+       u8  byte[4];
+
+       struct{
+               unsigned checksum:16;
+               unsigned reserved:16;
+       };
+} s_tx_tailer;
+
+typedef union {
+       u32 object;
+       u16 word[2];
+       u8  byte[4];
+
+       struct{
+               unsigned reserved:18;
+               unsigned result_value:2;
+               unsigned rcv_data_size:8;
+               unsigned order_cur_set:4;
+       };
+} s_rx_header;
+
+typedef enum {
+       POWER_TYPE_FIXED = 0,
+       POWER_TYPE_BATTERY,
+       POWER_TYPE_VARIABLE,
+} power_supply_type;
+
+typedef enum {
+       SOP_TYPE_SOP,
+       SOP_TYPE_SOP1,
+       SOP_TYPE_SOP2,
+       SOP_TYPE_SOP1_DEBUG,
+       SOP_TYPE_SOP2_DEBUG
+} sop_type;
+
+enum usbpd_control_msg_type {
+       USBPD_GoodCRC        = 0x1,
+       USBPD_GotoMin        = 0x2,
+       USBPD_Accept         = 0x3,
+       USBPD_Reject         = 0x4,
+       USBPD_Ping           = 0x5,
+       USBPD_PS_RDY         = 0x6,
+       USBPD_Get_Source_Cap = 0x7,
+       USBPD_Get_Sink_Cap   = 0x8,
+       USBPD_DR_Swap        = 0x9,
+       USBPD_PR_Swap        = 0xA,
+       USBPD_VCONN_Swap     = 0xB,
+       USBPD_Wait           = 0xC,
+       USBPD_Soft_Reset     = 0xD,
+       USBPD_UVDM_MSG       = 0xE
+};
+
+enum usbpd_check_msg_pass {
+       NONE_CHECK_MSG_PASS,
+       CHECK_MSG_PASS,
+};
+
+enum usbpd_port_data_role {
+       USBPD_UFP,
+       USBPD_DFP,
+};
+
+enum usbpd_port_power_role {
+       USBPD_SINK,
+       USBPD_SOURCE,
+       USBPD_DRP,
+};
+
+enum usbpd_port_vconn_role {
+       USBPD_VCONN_OFF,
+       USBPD_VCONN_ON,
+};
+
+enum usbpd_port_role {
+       USBPD_Rp        = 0x01,
+       USBPD_Rd        = 0x01 << 1,
+       USBPD_Ra        = 0x01 << 2,
+};
+
+enum usbpd_port_rp_level {
+       USBPD_56k       = 1,
+       USBPD_22k       = 3,
+       USBPD_10k       = 7,
+};
+
+enum {
+       USBPD_CC_OFF,
+       USBPD_CC_ON,
+};
+
+enum usbpd_connect_type {
+       USBPD_UP_SIDE   = 1,
+       USBPD_DOWN_SIDE = 2,
+       USBPD_UNDEFFINED_SIDE   = 3,
+};
+
+enum vdm_command_type{
+       Initiator       = 0,
+       Responder_ACK   = 1,
+       Responder_NAK   = 2,
+       Responder_BUSY  = 3
+};
+
+enum vdm_type{
+       Unstructured_VDM = 0,
+       Structured_VDM = 1
+};
+
+enum vdm_configure_type{
+       USB             = 0,
+       USB_U_AS_DFP_D  = 1,
+       USB_U_AS_UFP_D  = 2
+};
+
+enum vdm_displayport_protocol{
+       UNSPECIFIED     = 0,
+       DP_V_1_3        = 1,
+       GEN_2           = 1 << 1
+};
+
+enum dp_support {
+       USBPD_NOT_DP = 0,
+       USBPD_DP_SUPPORT = 1,
+};
+
+enum vdm_pin_assignment{
+       DE_SELECT_PIN           = 0,
+       PIN_ASSIGNMENT_A        = 1,
+       PIN_ASSIGNMENT_B        = 1 << 1,
+       PIN_ASSIGNMENT_C        = 1 << 2,
+       PIN_ASSIGNMENT_D        = 1 << 3,
+       PIN_ASSIGNMENT_E        = 1 << 4,
+       PIN_ASSIGNMENT_F        = 1 << 5,
+};
+
+enum vdm_command_msg {
+       Discover_Identity               = 1,
+       Discover_SVIDs                  = 2,
+       Discover_Modes                  = 3,
+       Enter_Mode                      = 4,
+       Exit_Mode                       = 5,
+       Attention                       = 6,
+       DisplayPort_Status_Update       = 0x10,
+       DisplayPort_Configure           = 0x11,
+};
+
+enum usbpd_data_msg_type {
+       USBPD_Source_Capabilities       = 0x1,
+       USBPD_Request                   = 0x2,
+       USBPD_BIST                      = 0x3,
+       USBPD_Sink_Capabilities         = 0x4,
+       USBPD_Vendor_Defined            = 0xF,
+};
+
 #endif