From 766f8e1cf50da5a4c56f5948e8ae338a69dcbfdc Mon Sep 17 00:00:00 2001 From: Kim Taejeong Date: Fri, 29 Mar 2019 10:54:43 +0900 Subject: [PATCH] [RAMEN9610-13997][COMMON] drivers: usb/usbpd: support role swap Change-Id: I9d6ec02ed07bf81b1104324f2dfd2a0d62c3ed54 Signed-off-by: Kim Taejeong --- arch/arm64/configs/erd9610_defconfig | 3 +- drivers/ccic/s2mu106-usbpd.c | 243 ++++++++++------ drivers/ccic/usbpd.c | 2 + drivers/ccic/usbpd_cc.c | 339 ++++++++++++++++++++-- drivers/ccic/usbpd_manager.c | 2 +- drivers/muic/muic_manager.c | 54 +--- drivers/power/supply/power_supply_sysfs.c | 1 + drivers/power/supply/s2mu106_charger.c | 13 +- drivers/power/supply/s2mu106_pmeter.c | 4 +- drivers/usb/dwc3/otg.c | 52 ---- include/linux/ccic/usbpd-s2mu106.h | 18 +- include/linux/ccic/usbpd_ext.h | 8 + include/linux/power_supply.h | 1 + 13 files changed, 533 insertions(+), 207 deletions(-) mode change 100755 => 100644 arch/arm64/configs/erd9610_defconfig mode change 100755 => 100644 drivers/power/supply/s2mu106_charger.c mode change 100755 => 100644 drivers/power/supply/s2mu106_pmeter.c diff --git a/arch/arm64/configs/erd9610_defconfig b/arch/arm64/configs/erd9610_defconfig old mode 100755 new mode 100644 index c93f1a4b49fd..c537ea6d5b5f --- a/arch/arm64/configs/erd9610_defconfig +++ b/arch/arm64/configs/erd9610_defconfig @@ -437,7 +437,8 @@ CONFIG_USB_NOTIFY_LAYER=y CONFIG_USB_NOTIFIER=y CONFIG_USB_HW_PARAM=y CONFIG_USB_DWC3=y -CONFIG_DUAL_ROLE_USB_INTF=y +#CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_TYPEC=y CONFIG_USB_GADGET=y CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_ACM=y diff --git a/drivers/ccic/s2mu106-usbpd.c b/drivers/ccic/s2mu106-usbpd.c index 08ab1eb4562c..26300009943a 100644 --- a/drivers/ccic/s2mu106-usbpd.c +++ b/drivers/ccic/s2mu106-usbpd.c @@ -78,8 +78,7 @@ 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_assert_drp(void *_data); 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); @@ -90,6 +89,8 @@ 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); +static void s2mu106_usbpd_set_rp_scr_sel(struct s2mu106_usbpd_data *pdic_data, + CCIC_RP_SCR_SEL scr_sel); char *rid_text[] = { "UNDEFINED", @@ -114,15 +115,19 @@ static void s2mu106_usbpd_test_read(struct s2mu106_usbpd_data *usbpd_data) s2mu106_usbpd_read_reg(i2c, 0xe2, &data[5]); s2mu106_usbpd_read_reg(i2c, 0xb3, &data[6]); s2mu106_usbpd_read_reg(i2c, 0xb4, &data[7]); + s2mu106_usbpd_read_reg(i2c, 0xf7, &data[8]); - 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]); + pr_info("%s, 0x1(%x) 0x18(%x) 0x27(%x) 0x28(%x) 0x40(%x) 0xe2(%x) 0xb3(%x) 0xb4(%x) 0xf7(%X)\n", + __func__, data[0], data[1], data[2], data[3], data[4], + data[5], data[6], data[7], data[8]); } void s2mu106_rprd_mode_change(struct s2mu106_usbpd_data *usbpd_data, u8 mode) { u8 data = 0; struct i2c_client *i2c = usbpd_data->i2c; + struct device *dev = &i2c->dev; + struct usbpd_data *pd_data = dev_get_drvdata(dev); pr_info("%s, mode=0x%x\n", __func__, mode); mutex_lock(&usbpd_data->lpm_mutex); @@ -131,14 +136,28 @@ void s2mu106_rprd_mode_change(struct s2mu106_usbpd_data *usbpd_data, u8 mode) switch (mode) { case TYPE_C_ATTACH_DFP: /* SRC */ - s2mu106_set_detach(usbpd_data, mode); + s2mu106_usbpd_set_cc_control(usbpd_data, USBPD_CC_OFF); + usbpd_data->status_reg |= PLUG_DETACH; + s2mu106_usbpd_set_rp_scr_sel(usbpd_data, PLUG_CTRL_RP0); + s2mu106_assert_rp(pd_data); + msleep(50); + s2mu106_usbpd_set_rp_scr_sel(usbpd_data, PLUG_CTRL_RP80); msleep(S2MU106_ROLE_SWAP_TIME_MS); - s2mu106_set_attach(usbpd_data, mode); + s2mu106_assert_drp(pd_data); break; case TYPE_C_ATTACH_UFP: /* SNK */ - s2mu106_set_detach(usbpd_data, mode); + ifconn_event_work(usbpd_data, IFCONN_NOTIFY_MUIC, + IFCONN_NOTIFY_ID_ROLE_SWAP, + IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP, NULL); + s2mu106_usbpd_set_cc_control(usbpd_data, USBPD_CC_OFF); + usbpd_data->status_reg |= PLUG_DETACH; + s2mu106_assert_rp(pd_data); + s2mu106_usbpd_set_rp_scr_sel(usbpd_data, PLUG_CTRL_RP0); + msleep(50); + s2mu106_assert_rd(pd_data); + s2mu106_usbpd_set_rp_scr_sel(usbpd_data, PLUG_CTRL_RP80); msleep(S2MU106_ROLE_SWAP_TIME_MS); - s2mu106_set_attach(usbpd_data, mode); + s2mu106_assert_drp(pd_data); break; case TYPE_C_ATTACH_DRP: /* DRP */ s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data); @@ -150,6 +169,24 @@ skip: mutex_unlock(&usbpd_data->lpm_mutex); } +void usbpd_charger_test_read(struct s2mu106_usbpd_data *usbpd_data) +{ + struct power_supply *psy_charger; + union power_supply_propval val; + int ret = 0; + + psy_charger = power_supply_get_by_name("s2mu106-charger"); + + if (psy_charger) { + ret = psy_charger->desc->set_property(psy_charger, + POWER_SUPPLY_PROP_USBPD_TEST_READ, &val); + } else { + pr_err("%s: Fail to get psy battery\n", __func__); + + return; + } +} + void vbus_turn_on_ctrl(struct s2mu106_usbpd_data *usbpd_data, bool enable) { struct power_supply *psy_otg; @@ -227,9 +264,9 @@ static int s2mu106_usbpd_get_pmeter_volt(struct s2mu106_usbpd_data *pdic_data) union power_supply_propval val; int ret = 0; - if (psy_pm) { + if (psy_pm) ret = psy_pm->desc->get_property(psy_pm, POWER_SUPPLY_PROP_VCHGIN, &val); - } else { + else { pr_err("%s: Fail to get pmeter\n", __func__); return -1; } @@ -245,6 +282,31 @@ static int s2mu106_usbpd_get_pmeter_volt(struct s2mu106_usbpd_data *pdic_data) return 0; } +static int s2mu106_usbpd_get_pmeter_current(struct s2mu106_usbpd_data *pdic_data) +{ + + struct power_supply *psy_pm = pdic_data->psy_pm; + union power_supply_propval val; + int ret = 0; + + if (psy_pm) + psy_pm->desc->get_property(psy_pm, POWER_SUPPLY_PROP_ICHGIN, &val); + else { + pr_err("%s: Fail to get pmeter\n", __func__); + return -1; + } + + if (ret) { + pr_err("%s: fail to set power_suppy pmeter property(%d)\n", + __func__, ret); + return -1; + } + + pdic_data->pm_chgin_i = val.intval; + + return 0; +} + static int s2mu106_usbpd_check_vbus(struct s2mu106_usbpd_data *pdic_data, int volt, CCIC_VBUS_SEL mode) { @@ -344,17 +406,23 @@ static void s2mu106_pr_swap(void *_data, int val) else if (val == USBPD_SOURCE_ON) { #if defined(CONFIG_DUAL_ROLE_USB_INTF) pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_SRC; +#elif defined(CONFIG_TYPEC) + pdic_data->typec_power_role = TYPEC_SOURCE; + typec_set_pwr_role(pdic_data->port, pdic_data->typec_power_role); +#endif ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC, IFCONN_NOTIFY_ID_ROLE_SWAP, 1/* source */, 0); -#endif } else if (val == USBPD_SOURCE_OFF) { ifconn_event_work(pdic_data, IFCONN_NOTIFY_BATTERY, IFCONN_NOTIFY_ID_DETACH, 0, 0); #if defined(CONFIG_DUAL_ROLE_USB_INTF) pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_SNK; +#elif defined(CONFIG_TYPEC) + pdic_data->typec_power_role = TYPEC_SINK; + typec_set_pwr_role(pdic_data->port, pdic_data->typec_power_role); +#endif ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC, IFCONN_NOTIFY_ID_ROLE_SWAP, 0/* sink */, 0); -#endif } } @@ -721,7 +789,6 @@ static bool s2mu106_poll_status(void *_data) u64 status_reg_val = 0; msg_header_type header; int data_obj_num = 0; - int msg_id = 0; ret = s2mu106_usbpd_bulk_read(i2c, S2MU106_REG_INT_STATUS0, S2MU106_MAX_NUM_INT_STATUS, intr); @@ -776,29 +843,24 @@ static bool s2mu106_poll_status(void *_data) if (intr[1] & S2MU106_REG_INT_STATUS1_MSG_DR_SWAP) status_reg_val |= MSG_DR_SWAP; + if (intr[0] & S2MU106_REG_INT_STATUS0_MSG_ACCEPT) + status_reg_val |= MSG_ACCEPT; + /* function that support dp control */ if (intr[4] & S2MU106_REG_INT_STATUS4_MSG_PASS) { if (intr[3] & S2MU106_REG_INT_STATUS3_UNS_CMD_DATA) status_reg_val |= MSG_RID; else { usbpd_protocol_rx(data); + if (data->msg_received == 0) + goto out; + header = data->protocol_rx.msg_header; data_obj_num = header.num_data_objs; - msg_id = header.msg_id; - pr_info("%s, prev msg_id =(%d), received msg_id =(%d)\n", __func__, - data->msg_id, msg_id); - - if (msg_id == data->msg_id) - goto out; - else - data->msg_id = msg_id; if (data_obj_num > 0) s2mu106_usbpd_check_msg(data, &status_reg_val); - 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; @@ -1242,6 +1304,12 @@ static void s2mu106_usbpd_set_rp_scr_sel(struct s2mu106_usbpd_data *pdic_data, u8 data = 0; pr_info("%s: scr_sel : (%d)\n", __func__, scr_sel); switch (scr_sel) { + case PLUG_CTRL_RP0: + s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data); + data &= ~S2MU106_REG_PLUG_CTRL_RP_SEL_MASK; + data |= S2MU106_REG_PLUG_CTRL_RP0; + s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data); + break; case PLUG_CTRL_RP80: s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data); data &= ~S2MU106_REG_PLUG_CTRL_RP_SEL_MASK; @@ -1482,61 +1550,6 @@ static void s2mu106_usbpd_check_rid(struct s2mu106_usbpd_data *pdic_data) } } -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; @@ -1914,6 +1927,9 @@ static void s2mu106_usbpd_otg_attach(struct s2mu106_usbpd_data *pdic_data) pdic_data->is_host = HOST_ON; #if defined(CONFIG_DUAL_ROLE_USB_INTF) pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_SRC; +#elif defined(CONFIG_TYPEC) + pdic_data->typec_power_role = TYPEC_SOURCE; + typec_set_pwr_role(pdic_data->port, pdic_data->typec_power_role); #endif #if defined(CONFIG_IFCONN_NOTIFIER) /* USB */ @@ -2071,8 +2087,19 @@ static void s2mu106_usbpd_prevent_watchdog_reset( 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 { + msleep(22); + s2mu106_usbpd_set_vbus_wakeup(pdic_data, VBUS_WAKEUP_DISABLE); + usleep_range(1000, 1200); + s2mu106_usbpd_set_vbus_wakeup(pdic_data, VBUS_WAKEUP_ENABLE); + usleep_range(1000, 1200); + 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); @@ -2126,6 +2153,10 @@ static void s2mu106_usbpd_detach_init(struct s2mu106_usbpd_data *pdic_data) if (pdic_data->power_role_dual == DUAL_ROLE_PROP_PR_SRC) { vbus_turn_on_ctrl(pdic_data, VBUS_OFF); } +#elif defined(CONFIG_TYPEC) + if (pdic_data->typec_power_role == TYPEC_SOURCE) { + vbus_turn_on_ctrl(pdic_data, VBUS_OFF); + } #endif pdic_data->detach_valid = true; mutex_unlock(&pdic_data->cc_mutex); @@ -2183,6 +2214,11 @@ static void s2mu106_usbpd_notify_detach(struct s2mu106_usbpd_data *pdic_data) pdic_data->is_client = CLIENT_OFF; #if defined(CONFIG_DUAL_ROLE_USB_INTF) pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_NONE; +#elif defined(CONFIG_TYPEC) + pdic_data->typec_power_role = TYPEC_SINK; + typec_set_pwr_role(pdic_data->port, TYPEC_SINK); + pdic_data->typec_data_role = TYPEC_DEVICE; + typec_set_data_role(pdic_data->port, TYPEC_DEVICE); #endif /* USB */ ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB, @@ -2238,6 +2274,9 @@ static void s2mu106_usbpd_check_host(struct s2mu106_usbpd_data *pdic_data, 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; +#elif defined(CONFIG_TYPEC) + pdic_data->typec_power_role = TYPEC_SINK; + typec_set_pwr_role(pdic_data->port, pdic_data->typec_power_role); #endif /* add to turn off external 5V */ vbus_turn_on_ctrl(pdic_data, VBUS_OFF); @@ -2262,6 +2301,9 @@ static void s2mu106_usbpd_check_client(struct s2mu106_usbpd_data *pdic_data, 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; +#elif defined(CONFIG_TYPEC) + pdic_data->typec_power_role = TYPEC_SINK; + typec_set_pwr_role(pdic_data->port, pdic_data->typec_power_role); #endif ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB, IFCONN_NOTIFY_EVENT_DETACH, NULL); @@ -2339,6 +2381,9 @@ static int s2mu106_check_port_detect(struct s2mu106_usbpd_data *pdic_data) pdic_data->is_client = CLIENT_ON; #if defined(CONFIG_DUAL_ROLE_USB_INTF) pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_SNK; +#elif defined(CONFIG_TYPEC) + pdic_data->typec_power_role = TYPEC_SINK; + typec_set_pwr_role(pdic_data->port, pdic_data->typec_power_role); #endif ifconn_event_work(pdic_data, IFCONN_NOTIFY_USB, IFCONN_NOTIFY_ID_USB, @@ -2466,6 +2511,7 @@ static irqreturn_t s2mu106_irq_thread(int irq, void *data) attach_status = s2mu106_get_status(pd_data, PLUG_ATTACH); rid_status = s2mu106_get_status(pd_data, MSG_RID); s2mu106_usbpd_detach_init(pdic_data); + s2mu106_usbpd_notify_detach(pdic_data); if (attach_status) { ret = s2mu106_check_port_detect(pdic_data); if (ret >= 0) { @@ -2476,7 +2522,7 @@ static irqreturn_t s2mu106_irq_thread(int irq, void *data) goto hard_reset; } } - s2mu106_usbpd_notify_detach(pdic_data); +#if 0 mutex_lock(&pdic_data->lpm_mutex); if (!pdic_data->lpm_mode) { if (s2mu106_usbpd_lpm_check(pdic_data) > 0) { @@ -2487,6 +2533,7 @@ static irqreturn_t s2mu106_irq_thread(int irq, void *data) ENABLED_INT_2, ENABLED_INT_3, ENABLED_INT_4, ENABLED_INT_5); } mutex_unlock(&pdic_data->lpm_mutex); +#endif goto out; } @@ -2730,7 +2777,15 @@ static int s2mu106_usbpd_irq_init(struct s2mu106_usbpd_data *_data) static void s2mu106_usbpd_init_configure(struct s2mu106_usbpd_data *_data) { + s2mu106_usbpd_test_read(_data); + s2mu106_usbpd_get_pmeter_volt(_data); + s2mu106_usbpd_get_pmeter_current(_data); + pr_info("%s, chgin(%d), chgin_i(%d)\n", __func__, + _data->pm_chgin, _data->pm_chgin_i); + usbpd_charger_test_read(_data); s2mu106_set_normal_mode(_data); + pr_info("%s, usbpd irq gpio value(%d)\n", __func__, + gpio_get_value(_data->irq_gpio)); msleep(25); _data->detach_valid = true; s2mu106_set_lpm_mode(_data); @@ -2763,6 +2818,10 @@ static void s2mu106_usbpd_pdic_data_init(struct s2mu106_usbpd_data *_data) _data->lpcharge_water = false; #endif _data->check_rid_wa = false; +#if defined(CONFIG_TYPEC) + _data->typec_power_role = TYPEC_SINK; + _data->typec_data_role = TYPEC_DEVICE; +#endif } static int of_s2mu106_dt(struct device *dev, @@ -2782,6 +2841,8 @@ static int of_s2mu106_dt(struct device *dev, _data->irq_gpio); _data->irq_gpio = 0; } + ret = gpio_get_value(_data->irq_gpio); + pr_info("%s, usbpd irq gpio value(%d)\n", __func__, ret); if (of_find_property(np_usbpd, "vconn-en", NULL)) _data->vconn_en = true; else @@ -2839,6 +2900,14 @@ static int s2mu106_usbpd_probe(struct i2c_client *i2c, mutex_init(&pdic_data->cc_mutex); wake_lock_init(&pdic_data->wake_lock, WAKE_LOCK_SUSPEND, "pdic_wake"); +#ifdef CONFIG_PM_S2MU106 + pdic_data->psy_pm = power_supply_get_by_name("s2mu106_pmeter"); + if (!pdic_data->psy_pm) + pr_err("%s: Fail to get pmeter\n", __func__); + s2mu106_usbpd_set_pmeter_mode(pdic_data, PM_TYPE_VCHGIN); + s2mu106_usbpd_set_pmeter_mode(pdic_data, PM_TYPE_ICHGIN); +#endif + s2mu106_usbpd_init_configure(pdic_data); s2mu106_usbpd_pdic_data_init(pdic_data); @@ -2859,11 +2928,6 @@ static int s2mu106_usbpd_probe(struct i2c_client *i2c, usbpd_set_ops(dev, &s2mu106_ops); -#ifdef CONFIG_PM_S2MU106 - pdic_data->psy_pm = power_supply_get_by_name("s2mu106_pmeter"); - if (!pdic_data->psy_pm) - pr_err("%s: Fail to get pmeter\n", __func__); -#endif s2mu106_usbpd_reg_init(pdic_data); pdic_data->pdic_queue = @@ -2886,6 +2950,13 @@ static int s2mu106_usbpd_probe(struct i2c_client *i2c, #endif if (pdic_data->rid == REG_RID_UNDF) pdic_data->rid = REG_RID_MAX; +#if defined(CONFIG_TYPEC) + ret = typec_init(pdic_data); + if (ret < 0) { + pr_err("failed to init typec\n"); + goto err_return; + } +#endif ret = s2mu106_usbpd_irq_init(pdic_data); if (ret) { @@ -2975,6 +3046,8 @@ static int s2mu106_usbpd_remove(struct i2c_client *i2c) devm_dual_role_instance_unregister(_data->dev, _data->dual_role); devm_kfree(_data->dev, _data->desc); +#elif defined(CONFIG_TYPEC) + typec_unregister_port(_data->port); #endif disable_irq_wake(_data->i2c->irq); free_irq(_data->i2c->irq, _data); diff --git a/drivers/ccic/usbpd.c b/drivers/ccic/usbpd.c index 6d38a0867567..26a0a09581a0 100644 --- a/drivers/ccic/usbpd.c +++ b/drivers/ccic/usbpd.c @@ -368,6 +368,8 @@ protocol_state usbpd_protocol_rx_wait_for_phy_message(struct protocol_data *rx) dev_err(pd_data->dev, "[Rx] Got SOFTRESET.\n"); state = PRL_Rx_Layer_Reset_for_Receive; } else { + pr_info("%s, prev msg_id =(%d), received msg_id =(%d)\n", __func__, + rx->stored_message_id, rx->msg_header.msg_id); if (rx->stored_message_id == rx->msg_header.msg_id) { pd_data->id_matched = 0; return state; diff --git a/drivers/ccic/usbpd_cc.c b/drivers/ccic/usbpd_cc.c index 4c472c27a859..ed6f69409230 100644 --- a/drivers/ccic/usbpd_cc.c +++ b/drivers/ccic/usbpd_cc.c @@ -26,15 +26,20 @@ #include #include -#if (defined CONFIG_CCIC_NOTIFIER || defined CONFIG_DUAL_ROLE_USB_INTF \ - || defined CONFIG_IFCONN_NOTIFIER) +#if (defined CONFIG_CCIC_NOTIFIER || defined CONFIG_DUAL_ROLE_USB_INTF) +#include +#elif defined(CONFIG_TYPEC) #include -#endif -#if defined CONFIG_IFCONN_NOTIFIER -#include #endif #include + +#if defined CONFIG_CCIC_S2MU004 +#include +#elif defined CONFIG_CCIC_S2MU106 #include +#elif defined CONFIG_CCIC_S2MU205 +#include +#endif #if defined(CONFIG_CCIC_NOTIFIER) static void ccic_event_notifier(struct work_struct *data) @@ -61,6 +66,7 @@ static void ccic_event_notifier(struct work_struct *data) event_work); break; } + ccic_noti.src = CCIC_NOTIFY_DEV_CCIC; ccic_noti.dest = event_work->dest; ccic_noti.id = event_work->id; @@ -79,9 +85,18 @@ static void ccic_event_notifier(struct work_struct *data) extern void ccic_event_work(void *data, int dest, int id, int attach, int event) { +#if defined CONFIG_CCIC_S2MU004 + struct s2mu004_usbpd_data *usbpd_data = data; +#elif defined CONFIG_CCIC_S2MU106 struct s2mu106_usbpd_data *usbpd_data = data; +#elif defined CONFIG_CCIC_S2MU205 + struct s2mu205_usbpd_data *usbpd_data = data; +#endif struct ccic_state_work *event_work; - +#if defined(CONFIG_TYPEC) + struct typec_partner_desc desc; + enum typec_pwr_opmode mode; +#endif event_work = kmalloc(sizeof(struct ccic_state_work), GFP_ATOMIC); pr_info("usb: %s,event_work(%p)\n", __func__, event_work); @@ -103,12 +118,45 @@ extern void ccic_event_work(void *data, int dest, int id, int attach, int event) dual_role_instance_changed(usbpd_data->dual_role); if (usbpd_data->try_state_change && - (usbpd_data->data_role_dual != IFCONN_NOTIFY_EVENT_DETACH)) { + (usbpd_data->data_role_dual != USB_STATUS_NOTIFY_DETACH)) { /* Role change try and new mode detected */ pr_info("usb: %s, reverse_completion\n", __func__); complete(&usbpd_data->reverse_completion); } } +#elif defined(CONFIG_TYPEC) + if (id == CCIC_NOTIFY_ID_USB) { + if (usbpd_data->typec_try_state_change && + (event != USB_STATUS_NOTIFY_DETACH)) { + // Role change try and new mode detected + pr_info("usb: %s, role_reverse_completion\n", __func__); + complete(&usbpd_data->role_reverse_completion); + } + + if (event == USB_STATUS_NOTIFY_ATTACH_UFP) { + mode = typec_get_pd_support(usbpd_data); + typec_set_pwr_opmode(usbpd_data->port, mode); + desc.usb_pd = mode == TYPEC_PWR_MODE_PD; + desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ + desc.identity = NULL; + usbpd_data->typec_data_role = TYPEC_DEVICE; + typec_set_data_role(usbpd_data->port, TYPEC_DEVICE); + usbpd_data->partner = typec_register_partner(usbpd_data->port, &desc); + } else if (event == USB_STATUS_NOTIFY_ATTACH_DFP) { + mode = typec_get_pd_support(usbpd_data); + typec_set_pwr_opmode(usbpd_data->port, mode); + desc.usb_pd = mode == TYPEC_PWR_MODE_PD; + desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ + desc.identity = NULL; + usbpd_data->typec_data_role = TYPEC_HOST; + typec_set_data_role(usbpd_data->port, TYPEC_HOST); + usbpd_data->partner = typec_register_partner(usbpd_data->port, &desc); + } else { + if (!IS_ERR(usbpd_data->partner)) + typec_unregister_partner(usbpd_data->partner); + usbpd_data->partner = NULL; + } + } #endif if (queue_work(usbpd_data->ccic_wq, &event_work->ccic_work) == 0) { @@ -147,7 +195,10 @@ extern void ifconn_event_work(void *pd_data, int dest, int id, int event, void * { struct s2mu106_usbpd_data *usbpd_data = pd_data; struct ifconn_state_work *event_work; - +#if defined(CONFIG_TYPEC) + struct typec_partner_desc desc; + enum typec_pwr_opmode mode; +#endif event_work = kmalloc(sizeof(struct ifconn_state_work), GFP_ATOMIC); INIT_WORK(&event_work->ifconn_work, ifconn_event_notifier); @@ -173,6 +224,44 @@ extern void ifconn_event_work(void *pd_data, int dest, int id, int event, void * complete(&usbpd_data->reverse_completion); } } +#elif defined(CONFIG_TYPEC) + if (id == IFCONN_NOTIFY_ID_USB) { + if (usbpd_data->typec_try_state_change && + (event != IFCONN_NOTIFY_EVENT_DETACH)) { + // Role change try and new mode detected + pr_info("usb: %s, role_reverse_completion\n", __func__); + complete(&usbpd_data->role_reverse_completion); + } + + if (event == IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP) { + pr_info("usb: %s, line : %d\n", __func__, __LINE__); + mode = typec_get_pd_support(usbpd_data); + typec_set_pwr_opmode(usbpd_data->port, mode); + desc.usb_pd = mode == TYPEC_PWR_MODE_PD; + desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ + desc.identity = NULL; + usbpd_data->typec_data_role = TYPEC_DEVICE; + typec_set_data_role(usbpd_data->port, TYPEC_DEVICE); + usbpd_data->partner = typec_register_partner(usbpd_data->port, &desc); + } else if (event == IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP) { + pr_info("usb: %s, line : %d\n", __func__, __LINE__); + mode = typec_get_pd_support(usbpd_data); + typec_set_pwr_opmode(usbpd_data->port, mode); + desc.usb_pd = mode == TYPEC_PWR_MODE_PD; + desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ + desc.identity = NULL; + usbpd_data->typec_data_role = TYPEC_HOST; + typec_set_data_role(usbpd_data->port, TYPEC_HOST); + usbpd_data->partner = typec_register_partner(usbpd_data->port, &desc); + } else { + pr_info("usb: %s, line : %d\n", __func__, __LINE__); + if (!IS_ERR(usbpd_data->partner)) + typec_unregister_partner(usbpd_data->partner); + usbpd_data->partner = NULL; + } + pr_info("usb: %s, line : %d\n", __func__, __LINE__); + } + pr_info("usb: %s, line : %d\n", __func__, __LINE__); #endif if (queue_work(usbpd_data->ifconn_wq, &event_work->ifconn_work) == 0) { @@ -194,8 +283,16 @@ void role_swap_check(struct work_struct *wk) { struct delayed_work *delay_work = container_of(wk, struct delayed_work, work); +#if defined CONFIG_CCIC_S2MU004 + struct s2mu004_usbpd_data *usbpd_data = + container_of(delay_work, struct s2mu004_usbpd_data, role_swap_work); +#elif defined CONFIG_CCIC_S2MU106 struct s2mu106_usbpd_data *usbpd_data = container_of(delay_work, struct s2mu106_usbpd_data, role_swap_work); +#elif defined CONFIG_CCIC_S2MU205 + struct s2mu205_usbpd_data *usbpd_data = + container_of(delay_work, struct s2mu205_usbpd_data, role_swap_work); +#endif int mode = 0; pr_info("%s: ccic_set_dual_role check again.\n", __func__); @@ -206,7 +303,13 @@ void role_swap_check(struct work_struct *wk) disable_irq(usbpd_data->irq); /* exit from Disabled state and set mode to DRP */ mode = TYPE_C_ATTACH_DRP; +#if defined CONFIG_CCIC_S2MU004 + s2mu004_rprd_mode_change(usbpd_data, mode); +#elif defined CONFIG_CCIC_S2MU106 s2mu106_rprd_mode_change(usbpd_data, mode); +#elif defined CONFIG_CCIC_S2MU205 + s2mu205_rprd_mode_change(usbpd_data, mode); +#endif enable_irq(usbpd_data->irq); } } @@ -215,10 +318,16 @@ static int ccic_set_dual_role(struct dual_role_phy_instance *dual_role, enum dual_role_property prop, const unsigned int *val) { +#if defined CONFIG_CCIC_S2MU004 + struct s2mu004_usbpd_data *usbpd_data = dual_role_get_drvdata(dual_role); +#elif defined CONFIG_CCIC_S2MU106 struct s2mu106_usbpd_data *usbpd_data = dual_role_get_drvdata(dual_role); +#elif defined CONFIG_CCIC_S2MU205 + struct s2mu205_usbpd_data *usbpd_data = dual_role_get_drvdata(dual_role); +#endif struct i2c_client *i2c; - ifconn_notifier_event_t attached_state; + USB_STATUS attached_state; int mode; int timeout = 0; int ret = 0; @@ -234,47 +343,62 @@ static int ccic_set_dual_role(struct dual_role_phy_instance *dual_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) { + if (attached_state != USB_STATUS_NOTIFY_ATTACH_DFP + && attached_state != USB_STATUS_NOTIFY_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 + if (attached_state == USB_STATUS_NOTIFY_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 + if (attached_state == USB_STATUS_NOTIFY_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) { + if (attached_state == USB_STATUS_NOTIFY_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) +#if defined(CONFIG_MUIC_SUPPORT_CCIC_OTG_CTRL) + muic_disable_otg_detect(); +#endif +#if defined(CONFIG_CCIC_NOTIFIER) /* muic */ - ifconn_event_work(usbpd_data, IFCONN_NOTIFY_MUIC, - IFCONN_NOTIFY_ID_ATTACH, IFCONN_NOTIFY_EVENT_DETACH, NULL); + ccic_event_work(usbpd_data, + CCIC_NOTIFY_DEV_MUIC, CCIC_NOTIFY_ID_ATTACH, 0/*attach*/, 0/*rprd*/); #endif /* exit from Disabled state and set mode to UFP */ mode = TYPE_C_ATTACH_UFP; usbpd_data->try_state_change = TYPE_C_ATTACH_UFP; +#if defined CONFIG_CCIC_S2MU004 + s2mu004_rprd_mode_change(usbpd_data, mode); +#elif defined CONFIG_CCIC_S2MU106 s2mu106_rprd_mode_change(usbpd_data, mode); +#elif defined CONFIG_CCIC_S2MU205 + s2mu205_rprd_mode_change(usbpd_data, mode); +#endif } 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; +#if defined CONFIG_CCIC_S2MU004 + s2mu004_rprd_mode_change(usbpd_data, mode); +#elif defined CONFIG_CCIC_S2MU106 s2mu106_rprd_mode_change(usbpd_data, mode); +#elif defined CONFIG_CCIC_S2MU205 + s2mu205_rprd_mode_change(usbpd_data, mode); +#endif } reinit_completion(&usbpd_data->reverse_completion); @@ -289,7 +413,13 @@ static int ccic_set_dual_role(struct dual_role_phy_instance *dual_role, disable_irq(usbpd_data->irq); /* exit from Disabled state and set mode to DRP */ mode = TYPE_C_ATTACH_DRP; +#if defined CONFIG_CCIC_S2MU004 + s2mu004_rprd_mode_change(usbpd_data, mode); +#elif defined CONFIG_CCIC_S2MU106 s2mu106_rprd_mode_change(usbpd_data, mode); +#elif defined CONFIG_CCIC_S2MU205 + s2mu205_rprd_mode_change(usbpd_data, mode); +#endif enable_irq(usbpd_data->irq); ret = -EIO; } else { @@ -316,9 +446,15 @@ int dual_role_get_local_prop(struct dual_role_phy_instance *dual_role, enum dual_role_property prop, unsigned int *val) { +#if defined CONFIG_CCIC_S2MU004 + struct s2mu004_usbpd_data *usbpd_data = dual_role_get_drvdata(dual_role); +#elif defined CONFIG_CCIC_S2MU106 struct s2mu106_usbpd_data *usbpd_data = dual_role_get_drvdata(dual_role); +#elif defined CONFIG_CCIC_S2MU205 + struct s2mu205_usbpd_data *usbpd_data = dual_role_get_drvdata(dual_role); +#endif - ifconn_notifier_event_t attached_state; + USB_STATUS attached_state; int power_role_dual; if (!usbpd_data) { @@ -339,7 +475,7 @@ int dual_role_get_local_prop(struct dual_role_phy_instance *dual_role, return 0; } - if (attached_state == IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP) { + if (attached_state == USB_STATUS_NOTIFY_ATTACH_DFP) { if (prop == DUAL_ROLE_PROP_MODE) *val = DUAL_ROLE_PROP_MODE_DFP; else if (prop == DUAL_ROLE_PROP_PR) @@ -348,7 +484,7 @@ int dual_role_get_local_prop(struct dual_role_phy_instance *dual_role, *val = DUAL_ROLE_PROP_DR_HOST; else return -EINVAL; - } else if (attached_state == IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP) { + } else if (attached_state == USB_STATUS_NOTIFY_ATTACH_UFP) { if (prop == DUAL_ROLE_PROP_MODE) *val = DUAL_ROLE_PROP_MODE_UFP; else if (prop == DUAL_ROLE_PROP_PR) @@ -393,7 +529,13 @@ int dual_role_set_prop(struct dual_role_phy_instance *dual_role, int dual_role_init(void *_data) { +#if defined CONFIG_CCIC_S2MU004 + struct s2mu004_usbpd_data *pdic_data = _data; +#elif defined CONFIG_CCIC_S2MU106 struct s2mu106_usbpd_data *pdic_data = _data; +#elif defined CONFIG_CCIC_S2MU205 + struct s2mu205_usbpd_data *pdic_data = _data; +#endif struct dual_role_phy_desc *desc; struct dual_role_phy_instance *dual_role; @@ -421,4 +563,161 @@ int dual_role_init(void *_data) return 0; } +#elif defined(CONFIG_TYPEC) +void typec_role_swap_check(struct work_struct *wk) +{ + struct delayed_work *delay_work = + container_of(wk, struct delayed_work, work); +#if defined CONFIG_CCIC_S2MU004 + struct s2mu004_usbpd_data *usbpd_data = + container_of(delay_work, struct s2mu004_usbpd_data, typec_role_swap_work); +#elif defined CONFIG_CCIC_S2MU106 + struct s2mu106_usbpd_data *usbpd_data = + container_of(delay_work, struct s2mu106_usbpd_data, typec_role_swap_work); +#elif defined CONFIG_CCIC_S2MU205 + struct s2mu205_usbpd_data *usbpd_data = + container_of(delay_work, struct s2mu205_usbpd_data, typec_role_swap_work); +#endif + + pr_info("%s: ccic_set_dual_role check again.\n", __func__); + usbpd_data->typec_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 */ +#if defined CONFIG_CCIC_S2MU004 + s2mu004_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DRP); +#elif defined CONFIG_CCIC_S2MU106 + s2mu106_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DRP); +#elif defined CONFIG_CCIC_S2MU205 + s2mu205_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DRP); +#endif + enable_irq(usbpd_data->irq); + } +} + +int typec_port_type_set(const struct typec_capability *cap, enum typec_port_type port_type) +{ +#if defined CONFIG_CCIC_S2MU004 + struct s2mu004_usbpd_data *usbpd_data = container_of(cap, struct s2mu004_usbpd_data, typec_cap); +#elif defined CONFIG_CCIC_S2MU106 + struct s2mu106_usbpd_data *usbpd_data = container_of(cap, struct s2mu106_usbpd_data, typec_cap); +#elif defined CONFIG_CCIC_S2MU205 + struct s2mu205_usbpd_data *usbpd_data = container_of(cap, struct s2mu205_usbpd_data, typec_cap); +#endif + + int timeout = 0; + + if (!usbpd_data) { + pr_err("%s : usbpd_data is null\n", __func__); + return -EINVAL; + } + + pr_info("%s : typec_power_role=%d, typec_data_role=%d, port_type=%d\n", + __func__, usbpd_data->typec_power_role, usbpd_data->typec_data_role, port_type); + + switch (port_type) { + case TYPEC_PORT_DFP: + pr_info("%s : try reversing, from UFP(Sink) to DFP(Source)\n", __func__); + usbpd_data->typec_try_state_change = TYPE_C_ATTACH_DFP; +#if defined CONFIG_CCIC_S2MU004 + s2mu004_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DFP); +#elif defined CONFIG_CCIC_S2MU106 + s2mu106_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DFP); +#elif defined CONFIG_CCIC_S2MU205 + s2mu205_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DFP); +#endif + + break; + case TYPEC_PORT_UFP: + pr_info("%s : try reversing, from DFP(Source) to UFP(Sink)\n", __func__); + /* turns off VBUS first */ + vbus_turn_on_ctrl(usbpd_data, 0); +#if defined(CONFIG_CCIC_NOTIFIER) + ccic_event_work(usbpd_data, + CCIC_NOTIFY_DEV_MUIC, CCIC_NOTIFY_ID_ATTACH, + 0/*attach*/, 0/*rprd*/); +#endif + usbpd_data->typec_try_state_change = TYPE_C_ATTACH_UFP; +#if defined CONFIG_CCIC_S2MU004 + s2mu004_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_UFP); +#elif defined CONFIG_CCIC_S2MU106 + s2mu106_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_UFP); +#elif defined CONFIG_CCIC_S2MU205 + s2mu205_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_UFP); +#endif + + break; + case TYPEC_PORT_DRP: + pr_info("%s : set to DRP (No action)\n", __func__); + return 0; + default : + pr_info("%s : invalid typec_role\n", __func__); + return -EINVAL; + } + + if (usbpd_data->typec_try_state_change) { + reinit_completion(&usbpd_data->role_reverse_completion); + timeout = + wait_for_completion_timeout(&usbpd_data->role_reverse_completion, + msecs_to_jiffies + (DUAL_ROLE_SET_MODE_WAIT_MS)); + + if (!timeout) { + 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 */ + usbpd_data->typec_try_state_change = 0; +#if defined CONFIG_CCIC_S2MU004 + s2mu004_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DRP); +#elif defined CONFIG_CCIC_S2MU106 + s2mu106_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DRP); +#elif defined CONFIG_CCIC_S2MU205 + s2mu205_rprd_mode_change(usbpd_data, TYPE_C_ATTACH_DRP); +#endif + + enable_irq(usbpd_data->irq); + return -EIO; + } else { + pr_err("%s: reverse success, one more check\n", __func__); + schedule_delayed_work(&usbpd_data->typec_role_swap_work, msecs_to_jiffies(DUAL_ROLE_SET_MODE_WAIT_MS)); + } + } + + return 0; +} + +int typec_get_pd_support(void *_data) +{ + return TYPEC_PWR_MODE_USB; +} + +int typec_init(void *_data) +{ +#if defined CONFIG_CCIC_S2MU004 + struct s2mu004_usbpd_data *pdic_data = _data; +#elif defined CONFIG_CCIC_S2MU106 + struct s2mu106_usbpd_data *pdic_data = _data; +#elif defined CONFIG_CCIC_S2MU205 + struct s2mu205_usbpd_data *pdic_data = _data; +#endif + + pdic_data->typec_cap.revision = USB_TYPEC_REV_1_2; + pdic_data->typec_cap.pd_revision = 0x300; + pdic_data->typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; + pdic_data->typec_cap.port_type_set = typec_port_type_set; + pdic_data->typec_cap.type = TYPEC_PORT_DRP; + pdic_data->port = typec_register_port(pdic_data->dev, &pdic_data->typec_cap); + if (IS_ERR(pdic_data->port)) { + pr_err("%s : unable to register typec_register_port\n", __func__); + return -1; + } else + pr_err("%s : success typec_register_port port=%pK\n", __func__, pdic_data->port); + + init_completion(&pdic_data->role_reverse_completion); + INIT_DELAYED_WORK(&pdic_data->typec_role_swap_work, typec_role_swap_check); + + return 0; +} #endif diff --git a/drivers/ccic/usbpd_manager.c b/drivers/ccic/usbpd_manager.c index 22a64049475b..a8383c9cdeaf 100644 --- a/drivers/ccic/usbpd_manager.c +++ b/drivers/ccic/usbpd_manager.c @@ -989,7 +989,7 @@ int usbpd_manager_match_request(struct usbpd_data *pd_data) //pr_info("Rx Request Current : %dmA\n", max_min*10); /* Compare Pdo and Rdo */ - if ((src_max_current >= max_min) && (pos == 1)) + if ((src_max_current >= op) && (pos == 1)) return 0; else return -1; diff --git a/drivers/muic/muic_manager.c b/drivers/muic/muic_manager.c index bace72169161..27c0b8c4cead 100644 --- a/drivers/muic/muic_manager.c +++ b/drivers/muic/muic_manager.c @@ -230,7 +230,7 @@ void muic_manager_handle_ccic_detach(struct muic_interface_t *muic_if) ccic->attached_dev = 0; ccic->ccic_evt_rid = 0; ccic->ccic_evt_rprd = 0; - ccic->ccic_evt_roleswap = 0; + //ccic->ccic_evt_roleswap = 0; ccic->ccic_evt_dcdcnt = 0; ccic->ccic_evt_attached = MUIC_CCIC_NOTI_UNDEFINED; @@ -715,39 +715,19 @@ static int muic_manager_handle_ccic_role_swap(struct muic_interface_t *muic_if, { #ifdef CONFIG_IFCONN_NOTIFIER struct ifconn_notifier_template *pnoti = (struct ifconn_notifier_template *)data; -#else - CC_NOTI_TYPEDEF *pnoti = (CC_NOTI_TYPEDEF *)data; -#endif + struct ccic_desc_t *ccic = muic_if->ccic; - - pr_info("%s: src:%d dest:%d sub1:%d\n", __func__, - pnoti->src, pnoti->dest, pnoti->sub1); - - if (pnoti->sub1 == true) { - /* sink -> src */ - ccic->ccic_evt_rprd = 1; - ccic->ccic_evt_roleswap = 1; - ccic->attached_dev = ATTACHED_DEV_OTG_MUIC; - if (muic_if->set_cable_state) - muic_if->set_cable_state(muic_if->muic_data, ccic->attached_dev); - } else { - /* src -> sink */ - muic_manager_handle_ccic_detach(muic_if); - ccic->ccic_evt_attached = MUIC_CCIC_NOTI_ATTACH; - ccic->ccic_evt_rprd = 1; - ccic->ccic_evt_roleswap = 1; - ccic->attached_dev = ATTACHED_DEV_TYPE3_CHARGER_MUIC; - if (muic_if->set_cable_state) - muic_if->set_cable_state(muic_if->muic_data, ccic->attached_dev); - } + pr_info("%s: event:%d\n", __func__, pnoti->event); - return 0; + if (pnoti->event == IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP) + ccic->ccic_evt_roleswap = 1; +#endif + return 0; } static int muic_manager_handle_otg(struct muic_interface_t *muic_if, void *data) { - int ret = MUIC_NORMAL_OTG; struct ccic_desc_t *ccic = muic_if->ccic; #ifdef CONFIG_IFCONN_NOTIFIER struct ifconn_notifier_template *pnoti = (struct ifconn_notifier_template *)data; @@ -761,20 +741,12 @@ static int muic_manager_handle_otg(struct muic_interface_t *muic_if, void *data) #ifndef CONFIG_IFCONN_NOTIFIER if (pnoti->sub1 == true) { #endif - /* OTG Attach */ - if (muic_if->check_usb_killer) { - ret = muic_if->check_usb_killer(muic_if->muic_data); - } - - if (ret == MUIC_NORMAL_OTG) { - MUIC_SEND_NOTI_TO_CCIC_ATTACH(ATTACHED_DEV_OTG_MUIC); - ccic->ccic_evt_rprd = 1; - ccic->attached_dev = ATTACHED_DEV_OTG_MUIC; - if (muic_if->set_cable_state) - muic_if->set_cable_state(muic_if->muic_data, ccic->attached_dev); - muic_manager_switch_path(muic_if, MUIC_PATH_USB_AP); - } else - pr_info("[MUIC] %s USB Killer Detected!!!\n", __func__); + MUIC_SEND_NOTI_TO_CCIC_ATTACH(ATTACHED_DEV_OTG_MUIC); + ccic->ccic_evt_rprd = 1; + ccic->attached_dev = ATTACHED_DEV_OTG_MUIC; + if (muic_if->set_cable_state) + muic_if->set_cable_state(muic_if->muic_data, ccic->attached_dev); + muic_manager_switch_path(muic_if, MUIC_PATH_USB_AP); #ifndef CONFIG_IFCONN_NOTIFIER } #endif diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 23525cd8bf2e..4ffa65fe52ee 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -284,6 +284,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(co_enable), POWER_SUPPLY_ATTR(rr_enable), POWER_SUPPLY_ATTR(usbpd_reset), + POWER_SUPPLY_ATTR(usbpd_test_read), }; static struct attribute * diff --git a/drivers/power/supply/s2mu106_charger.c b/drivers/power/supply/s2mu106_charger.c old mode 100755 new mode 100644 index 39d809f20c5d..c0565ddf5bd5 --- a/drivers/power/supply/s2mu106_charger.c +++ b/drivers/power/supply/s2mu106_charger.c @@ -551,6 +551,7 @@ static int s2mu106_chg_set_property(struct power_supply *psy, int buck_state = ENABLE; union power_supply_propval value; int ret; + u8 data = 0; switch (psp) { case POWER_SUPPLY_PROP_STATUS: @@ -662,12 +663,20 @@ static int s2mu106_chg_set_property(struct power_supply *psy, } break; case POWER_SUPPLY_PROP_FUELGAUGE_RESET: - s2mu106_update_reg(charger->i2c, 0xE3, 0x03 << 6, 0x03 << 6); + s2mu106_read_reg(charger->i2c, 0xE3, &data); + data |= 0x03 << 6; + s2mu106_write_reg(charger->i2c, 0xE3, data); msleep(1000); - s2mu106_update_reg(charger->i2c, 0xE3, 0x00 << 6, 0x03 << 6); + data &= ~(0x03 << 6); + s2mu106_write_reg(charger->i2c, 0xE3, data); msleep(50); pr_info("%s: reset fuelgauge when surge occur!\n", __func__); break; + case POWER_SUPPLY_PROP_USBPD_TEST_READ: + s2mu106_test_read(charger->i2c); + s2mu106_read_reg(charger->i2c, 0xEC, &data); + pr_info("%s, charger 0xEC=(%x)\n", __func__, data); + break; default: return -EINVAL; } diff --git a/drivers/power/supply/s2mu106_pmeter.c b/drivers/power/supply/s2mu106_pmeter.c old mode 100755 new mode 100644 index 7701e3416249..0b1a32d749a7 --- a/drivers/power/supply/s2mu106_pmeter.c +++ b/drivers/power/supply/s2mu106_pmeter.c @@ -226,14 +226,16 @@ static int s2mu106_pm_get_ichgin(struct s2mu106_pmeter_data *pmeter) s2mu106_read_reg(pmeter->i2c, S2MU106_PM_VAL1_ICHGIN, &data1); s2mu106_read_reg(pmeter->i2c, S2MU106_PM_VAL2_ICHGIN, &data2); - + if (data1 < 0 || data2 < 0) return -EINVAL; charge_current = (int)((data1 << 4) | (data2 >> 4)); +#if 0 pr_info ("%s, data1 : 0x%2x, data2 : 0x%2x, current = %d\n", __func__, data1, data2, charge_current); +#endif return charge_current; } diff --git a/drivers/usb/dwc3/otg.c b/drivers/usb/dwc3/otg.c index cfe9da1ed57b..e6077060d0d0 100644 --- a/drivers/usb/dwc3/otg.c +++ b/drivers/usb/dwc3/otg.c @@ -29,26 +29,12 @@ #include #endif -#if defined(CONFIG_TYPEC) -#include -#endif - #include "core.h" #include "otg.h" #include "io.h" /* -------------------------------------------------------------------------- */ -#if defined(CONFIG_TYPEC) -struct intf_typec { - /* struct mutex lock; */ /* device lock */ - struct device *dev; - struct typec_port *port; - struct typec_capability cap; - struct typec_partner *partner; -}; -#endif - int otg_connection; static int dwc3_otg_statemachine(struct otg_fsm *fsm) { @@ -703,11 +689,6 @@ int dwc3_otg_init(struct dwc3 *dwc) struct dwc3_otg *dotg; struct dwc3_ext_otg_ops *ops = NULL; int ret = 0; -#if defined(CONFIG_TYPEC) - struct intf_typec *typec; - struct typec_partner_desc partner; -#endif - dev_info(dwc->dev, "%s\n", __func__); @@ -766,34 +747,6 @@ int dwc3_otg_init(struct dwc3 *dwc) } } -#if defined(CONFIG_TYPEC) - typec = devm_kzalloc(dwc->dev, sizeof(*typec), GFP_KERNEL); - if (!typec) - return -ENOMEM; - - /* mutex_init(&md05->lock); */ - typec->dev = dwc->dev; - - typec->cap.type = TYPEC_PORT_DRP; - typec->cap.revision = USB_TYPEC_REV_1_1; - typec->cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; - - typec->port = typec_register_port(dwc->dev, &typec->cap); - if (!typec->port) - return -ENODEV; - - typec_set_data_role(typec->port, TYPEC_DEVICE); - typec_set_pwr_role(typec->port, TYPEC_SINK); - typec_set_pwr_opmode(typec->port, TYPEC_PWR_MODE_USB); - - dotg->typec = typec; - - typec->partner = typec_register_partner(typec->port, &partner); - if (!dotg->typec->partner) - dev_err(dwc->dev, "failed register partner\n"); -#endif - - wake_lock_init(&dotg->wakelock, WAKE_LOCK_SUSPEND, "dwc3-otg"); ret = sysfs_create_group(&dwc->dev->kobj, &dwc3_otg_attr_group); @@ -814,11 +767,6 @@ void dwc3_otg_exit(struct dwc3 *dwc) if (!dotg->ext_otg_ops) return; -#if defined(CONFIG_TYPEC) - typec_unregister_partner(dotg->typec->partner); - typec_unregister_port(dotg->typec->port); -#endif - dwc3_ext_otg_exit(dotg); sysfs_remove_group(&dwc->dev->kobj, &dwc3_otg_attr_group); diff --git a/include/linux/ccic/usbpd-s2mu106.h b/include/linux/ccic/usbpd-s2mu106.h index 02adc3e4953f..cd28f1c98aa9 100644 --- a/include/linux/ccic/usbpd-s2mu106.h +++ b/include/linux/ccic/usbpd-s2mu106.h @@ -17,6 +17,9 @@ #if defined CONFIG_IFCONN_NOTIFIER #include #endif +#if defined(CONFIG_TYPEC) +#include +#endif #include @@ -39,9 +42,7 @@ #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) @@ -684,6 +685,16 @@ struct s2mu106_usbpd_data { struct completion reverse_completion; int try_state_change; struct delayed_work role_swap_work; +#elif defined(CONFIG_TYPEC) + struct typec_port *port; + struct typec_partner *partner; + struct usb_pd_identity partner_identity; + struct typec_capability typec_cap; + struct completion role_reverse_completion; + int typec_power_role; + int typec_data_role; + int typec_try_state_change; + struct delayed_work typec_role_swap_work; #endif struct notifier_block type3_nb; struct workqueue_struct *pdic_queue; @@ -694,6 +705,7 @@ struct s2mu106_usbpd_data { int pm_cc1; int pm_cc2; int pm_chgin; + int pm_chgin_i; struct power_supply_desc ccic_desc; struct power_supply *psy_pm; struct power_supply *psy_ccic; @@ -709,9 +721,7 @@ 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); diff --git a/include/linux/ccic/usbpd_ext.h b/include/linux/ccic/usbpd_ext.h index b7c0cacf4d66..ac2a78510c2b 100644 --- a/include/linux/ccic/usbpd_ext.h +++ b/include/linux/ccic/usbpd_ext.h @@ -3,6 +3,8 @@ #endif #if defined(CONFIG_DUAL_ROLE_USB_INTF) #include +#elif defined(CONFIG_TYPEC) +#include #endif #ifndef __USBPD_EXT_H__ @@ -115,5 +117,11 @@ 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); +#elif defined(CONFIG_TYPEC) +extern void typec_role_swap_check(struct work_struct *wk); +extern int typec_port_type_set(const struct typec_capability *cap, + enum typec_port_type port_type); +extern int typec_get_pd_support(void *_data); +extern int typec_init(void *_data); #endif #endif diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index e6d70fcff400..eed131d3daaf 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -185,6 +185,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_CO_ENABLE, POWER_SUPPLY_PROP_RR_ENABLE, POWER_SUPPLY_PROP_USBPD_RESET, + POWER_SUPPLY_PROP_USBPD_TEST_READ, }; enum power_supply_type { -- 2.20.1