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);
struct usbpd_data *pd_data = dev_get_drvdata(dev);
pr_info("%s, mode=0x%x\n", __func__, mode);
- mutex_lock(&usbpd_data->lpm_mutex);
+ mutex_lock(&usbpd_data->_mutex);
if (usbpd_data->lpm_mode)
goto skip;
+ pr_info("%s, %d\n", __func__, __LINE__);
switch (mode) {
case TYPE_C_ATTACH_DFP: /* SRC */
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);
+ msleep(20);
+ s2mu106_usbpd_detach_init(usbpd_data);
+ s2mu106_usbpd_notify_detach(usbpd_data);
+ msleep(600);
s2mu106_usbpd_set_rp_scr_sel(usbpd_data, PLUG_CTRL_RP80);
msleep(S2MU106_ROLE_SWAP_TIME_MS);
s2mu106_assert_drp(pd_data);
+ usbpd_data->status_reg |= PLUG_ATTACH;
+ schedule_delayed_work(&usbpd_data->plug_work, 0);
break;
case TYPE_C_ATTACH_UFP: /* SNK */
ifconn_event_work(usbpd_data, IFCONN_NOTIFY_MUIC,
IFCONN_NOTIFY_ID_ROLE_SWAP,
- IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP, NULL);
+ IFCONN_NOTIFY_EVENT_PD_SINK, 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);
+ msleep(20);
+ s2mu106_usbpd_detach_init(usbpd_data);
+ s2mu106_usbpd_notify_detach(usbpd_data);
+ msleep(600);
s2mu106_assert_rd(pd_data);
s2mu106_usbpd_set_rp_scr_sel(usbpd_data, PLUG_CTRL_RP80);
msleep(S2MU106_ROLE_SWAP_TIME_MS);
s2mu106_assert_drp(pd_data);
+ usbpd_data->status_reg |= PLUG_ATTACH;
+ schedule_delayed_work(&usbpd_data->plug_work, 0);
break;
case TYPE_C_ATTACH_DRP: /* DRP */
s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, &data);
break;
};
skip:
- mutex_unlock(&usbpd_data->lpm_mutex);
+ mutex_unlock(&usbpd_data->_mutex);
}
void usbpd_charger_test_read(struct s2mu106_usbpd_data *usbpd_data)
#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_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_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);
+ schedule_delayed_work(&usbpd_data->dr_work, msecs_to_jiffies(0));
}
#endif
struct usbpd_data *data = (struct usbpd_data *) _data;
struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
- if (val == USBPD_SINK_OFF)
+ if (val == USBPD_SINK_OFF) {
+ ifconn_event_work(pdic_data, IFCONN_NOTIFY_MUIC,
+ IFCONN_NOTIFY_ID_ROLE_SWAP,
+ IFCONN_NOTIFY_EVENT_PD_SOURCE, 0);
ifconn_event_work(pdic_data, IFCONN_NOTIFY_BATTERY,
IFCONN_NOTIFY_ID_DETACH, 0, 0);
- else if (val == USBPD_SOURCE_ON) {
+ } 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);
} else if (val == USBPD_SOURCE_OFF) {
ifconn_event_work(pdic_data, IFCONN_NOTIFY_BATTERY,
IFCONN_NOTIFY_ID_DETACH, 0, 0);
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);
+ IFCONN_NOTIFY_ID_ROLE_SWAP,
+ IFCONN_NOTIFY_EVENT_PD_SINK, 0);
}
+#if defined(CONFIG_TYPEC)
+ if (val == USBPD_PR_DONE) {
+ typec_set_pwr_role(pdic_data->port, pdic_data->typec_power_role);
+ if (pdic_data->typec_try_state_change == TYPE_C_PR_SWAP)
+ complete(&pdic_data->role_reverse_completion);
+ }
+#endif
}
static int s2mu106_usbpd_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
struct i2c_client *i2c = pdic_data->i2c;
u8 val;
- u8 cc1_val, cc2_val;
-
+#if 0
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;
+#endif
- if (cc1_val == 2) {
+ if (pdic_data->cc1_val == USBPD_Rd) {
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;
}
}
- if (cc2_val == 2) {
+ if (pdic_data->cc2_val == USBPD_Rd) {
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;
return s2mu106_usbpd_check_vbus(pdic_data, 3500, VBUS_ON);
}
+static void s2mu106_set_pwr_opmode(void *_data, int mode)
+{
+ struct usbpd_data *data = (struct usbpd_data *) _data;
+ struct s2mu106_usbpd_data *pdic_data = data->phy_driver_data;
+
+ typec_set_pwr_opmode(pdic_data->port, mode);
+}
+
#if defined(CONFIG_CHECK_CTYPE_SIDE) || defined(CONFIG_CCIC_SYSFS)
static int s2mu106_get_side_check(void *_data)
{
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)
{
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;
}
switch (vdm_command) {
- case DisplayPort_Status_Update:
- *val |= VDM_DP_STATUS_UPDATE;
- break;
- case DisplayPort_Configure:
- *val |= VDM_DP_CONFIGURE;
- break;
- case Attention:
- *val |= VDM_ATTENTION;
- break;
- case Exit_Mode:
- *val |= VDM_EXIT_MODE;
- break;
- case Enter_Mode:
- *val |= VDM_ENTER_MODE;
- break;
- case Discover_Modes:
- *val |= VDM_ENTER_MODE;
- break;
- case Discover_SVIDs:
- *val |= VDM_DISCOVER_SVID;
- break;
- case Discover_Identity:
- *val |= VDM_DISCOVER_IDENTITY;
- break;
- default:
- break;
+ case DisplayPort_Status_Update:
+ *val |= VDM_DP_STATUS_UPDATE;
+ break;
+ case DisplayPort_Configure:
+ *val |= VDM_DP_CONFIGURE;
+ break;
+ case Attention:
+ *val |= VDM_ATTENTION;
+ break;
+ case Exit_Mode:
+ *val |= VDM_EXIT_MODE;
+ break;
+ case Enter_Mode:
+ *val |= VDM_ENTER_MODE;
+ break;
+ case Discover_Modes:
+ *val |= VDM_ENTER_MODE;
+ break;
+ case Discover_SVIDs:
+ *val |= VDM_DISCOVER_SVID;
+ break;
+ case Discover_Identity:
+ *val |= VDM_DISCOVER_IDENTITY;
+ break;
+ default:
+ break;
}
break;
default:
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;
+ data |= S2MU106_REG_PLUG_CTRL_DRP | S2MU106_REG_PLUG_CTRL_RP80;
s2mu106_usbpd_read_reg(i2c, S2MU106_REG_PD_CTRL, &data_lpm);
data_lpm &= ~S2MU106_REG_LPM_EN;
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);
+ else
+ s2mu106_usbpd_set_mode(pdic_data, PD_NORMAL_MODE);
}
s2mu106_set_irq_enable(pdic_data, ENABLED_INT_0, ENABLED_INT_1,
if (pdic_data->typec_power_role == TYPEC_SOURCE) {
vbus_turn_on_ctrl(pdic_data, VBUS_OFF);
}
+ pd_data->pd_support = 0;
#endif
pdic_data->detach_valid = true;
mutex_unlock(&pdic_data->cc_mutex);
#if defined(CONFIG_DUAL_ROLE_USB_INTF)
pdic_data->power_role_dual = DUAL_ROLE_PROP_PR_NONE;
#elif defined(CONFIG_TYPEC)
+ if (pdic_data->partner) {
+ pr_info("%s, %d\n", __func__, __LINE__);
+ if (!IS_ERR(pdic_data->partner)) {
+ typec_unregister_partner(pdic_data->partner);
+ pdic_data->partner = NULL;
+ }
+ }
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,
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);
cc1_val = val & S2MU106_REG_CTRL_MON_CC1_MASK;
cc2_val = (val & S2MU106_REG_CTRL_MON_CC2_MASK) >> S2MU106_REG_CTRL_MON_CC2_SHIFT;
+ pdic_data->cc1_val = cc1_val;
+ pdic_data->cc2_val = cc2_val;
+
dev_info(dev, "%s, attach cc pin check cc1_val(%x), cc2_val(%x)\n",
__func__, cc1_val, cc2_val);
#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;
+ data |= S2MU106_REG_PLUG_CTRL_DRP | S2MU106_REG_PLUG_CTRL_RP80;
s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_PORT, data);
#endif
return -1;
}
#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;
if (ret)
goto skip_detach;
#endif /* CONFIG_SEC_FACTORY */
-#ifndef CONFIG_SEC_FACTORY
- s2mu106_usbpd_check_reboost(pdic_data);
-#endif
+ s2mu106_usbpd_set_rp_scr_sel(pdic_data, PLUG_CTRL_RP80);
attach_status = s2mu106_get_status(pd_data, PLUG_ATTACH);
rid_status = s2mu106_get_status(pd_data, MSG_RID);
s2mu106_usbpd_detach_init(pdic_data);
return IRQ_HANDLED;
}
+static void s2mu106_usbpd_plug_work(struct work_struct *work)
+{
+ struct s2mu106_usbpd_data *pdic_data =
+ container_of(work, struct s2mu106_usbpd_data, plug_work.work);
+
+ s2mu106_irq_thread(-1, pdic_data);
+}
+
+static void s2mu106_usbpd_dr_work(struct work_struct *work)
+{
+ struct s2mu106_usbpd_data *usbpd_data =
+ container_of(work, struct s2mu106_usbpd_data, dr_work.work);
+ 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_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_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);
+}
+
static int s2mu106_usbpd_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
#ifdef CONFIG_PM_S2MU106
s2mu106_usbpd_set_pmeter_mode(_data, PM_TYPE_VCHGIN);
#endif
- s2mu106_usbpd_write_reg(i2c, S2MU106_REG_PLUG_CTRL_RpRd, S2MU106_RESET_REG_00);
s2mu106_usbpd_set_vconn_manual(_data, true);
}
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);
+ INIT_DELAYED_WORK(&pdic_data->water_dry_handler, S2MU106_PDIC_water_dry_handler);
+ INIT_DELAYED_WORK(&pdic_data->plug_work, s2mu106_usbpd_plug_work);
+ INIT_DELAYED_WORK(&pdic_data->dr_work, s2mu106_usbpd_dr_work);
if (pdic_data->detach_valid) {
mutex_lock(&pdic_data->_mutex);
.get_side_check = s2mu106_get_side_check,
.pr_swap = s2mu106_pr_swap,
.vbus_on_check = s2mu106_vbus_on_check,
+ .set_pwr_opmode = s2mu106_set_pwr_opmode,
};
#if defined CONFIG_PM
pd_data->phy_ops.get_side_check = ops->get_side_check;
pd_data->phy_ops.pr_swap = ops->pr_swap;
pd_data->phy_ops.vbus_on_check = ops->vbus_on_check;
+ pd_data->phy_ops.set_pwr_opmode = ops->set_pwr_opmode;
}
protocol_state usbpd_protocol_rx_layer_reset_for_receive(struct protocol_data *rx)
usbpd_init_policy(pd_data);
usbpd_init_manager(pd_data);
+ pd_data->pd_support = 0;
+
mutex_init(&pd_data->accept_mutex);
pd_data->policy_wqueue =
#include <linux/ccic/usbpd-s2mu205.h>
#endif
+#include <linux/usb_notify.h>
+
#if defined(CONFIG_CCIC_NOTIFIER)
static void ccic_event_notifier(struct work_struct *data)
{
}
}
#elif defined(CONFIG_TYPEC)
- if (id == IFCONN_NOTIFY_ID_USB) {
+ 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);
+ (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);
+ if (usbpd_data->partner == NULL) {
+ 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_pwr_role(usbpd_data->port, usbpd_data->typec_power_role);
+ 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_pwr_role(usbpd_data->port, usbpd_data->typec_power_role);
+ 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__);
} 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;
+ if (event == IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP) {
+ pr_info("usb: %s, line : %d\n", __func__, __LINE__);
+ usbpd_data->typec_data_role = TYPEC_DEVICE;
+ typec_set_data_role(usbpd_data->port, TYPEC_DEVICE);
+ } else if (event == IFCONN_NOTIFY_EVENT_USB_ATTACH_DFP) {
+ usbpd_data->typec_data_role = TYPEC_HOST;
+ typec_set_data_role(usbpd_data->port, TYPEC_HOST);
+ } else
+ pr_info("usb: %s, line : %d\n", __func__, __LINE__);
}
- 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) {
case TYPEC_PORT_DRP:
pr_info("%s : set to DRP (No action)\n", __func__);
return 0;
- default :
+ default:
pr_info("%s : invalid typec_role\n", __func__);
return -EINVAL;
}
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));
- }
+ } else
+ pr_err("%s: reverse success\n", __func__);
+ }
+
+ return 0;
+}
+
+static int typec_pr_set(const struct typec_capability *cap, enum typec_role role)
+{
+#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, role=%d\n",
+ __func__, usbpd_data->typec_power_role, usbpd_data->typec_data_role, role);
+
+ if (role == TYPEC_SINK) {
+ pr_info("%s, try reversing, from Source to Sink\n", __func__);
+ usbpd_data->typec_try_state_change = TYPE_C_PR_SWAP;
+ usbpd_manager_send_pr_swap(usbpd_data->dev);
+ } else if (role == TYPEC_SOURCE) {
+ pr_info("%s, try reversing, from Sink to Source\n", __func__);
+ usbpd_data->typec_try_state_change = TYPE_C_PR_SWAP;
+ usbpd_manager_send_pr_swap(usbpd_data->dev);
+ } else {
+ pr_info("invalid power role\n");
+ return -EIO;
+ }
+
+ 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\n", __func__);
+ disable_irq(usbpd_data->irq);
+ /* exit from Disabled state and set mode to DRP */
+ usbpd_data->typec_try_state_change = 0;
+ return -EIO;
+ } else
+ pr_err("%s: reverse success\n", __func__);
+ }
+
+ return 0;
+}
+
+static int typec_dr_set(const struct typec_capability *cap, enum typec_data_role role)
+{
+#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, role=%d\n",
+ __func__, usbpd_data->typec_power_role, usbpd_data->typec_data_role, role);
+
+ if (role == TYPEC_DEVICE) {
+ pr_info("%s, try reversing, from DFP to UFP\n", __func__);
+ usbpd_data->typec_try_state_change = TYPE_C_DR_SWAP;
+ usbpd_manager_send_dr_swap(usbpd_data->dev);
+ } else if (role == TYPEC_HOST) {
+ pr_info("%s, try reversing, from UFP to DFP\n", __func__);
+ usbpd_data->typec_try_state_change = TYPE_C_DR_SWAP;
+ usbpd_manager_send_dr_swap(usbpd_data->dev);
+ } else {
+ pr_info("invalid power role\n");
+ return -EIO;
+ }
+
+ 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\n", __func__);
+ disable_irq(usbpd_data->irq);
+ /* exit from Disabled state and set mode to DRP */
+ usbpd_data->typec_try_state_change = 0;
+ return -EIO;
+ } else
+ pr_err("%s: reverse success\n", __func__);
}
return 0;
int typec_get_pd_support(void *_data)
{
- return TYPEC_PWR_MODE_USB;
+ struct s2mu106_usbpd_data *pdic_data = _data;
+ struct usbpd_data *pd_data = dev_get_drvdata(pdic_data->dev);
+
+ if (pd_data->pd_support)
+ return TYPEC_PWR_MODE_PD;
+ else
+ return TYPEC_PWR_MODE_USB;
}
int typec_init(void *_data)
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.pr_set = typec_pr_set;
+ pdic_data->typec_cap.dr_set = typec_dr_set;
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);
+ pdic_data->partner = NULL;
if (IS_ERR(pdic_data->port)) {
pr_err("%s : unable to register typec_register_port\n", __func__);
return -1;
usbpd_manager_inform_event(pd_noti.pd_data, MANAGER_SEND_PR_SWAP);
}
+void usbpd_manager_send_dr_swap(struct device *dev)
+{
+ pr_info("%s: call send pr swap msg\n", __func__);
+
+ usbpd_manager_inform_event(pd_noti.pd_data, MANAGER_SEND_DR_SWAP);
+}
+
static void init_source_cap_data(struct usbpd_manager_data *_data)
{
/* struct usbpd_data *pd_data = manager_to_usbpd(_data);
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 = 0;
+ data_obj->power_data_obj.usb_comm_capable = 1;
}
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 = 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 = 3000/10;
usbpd_manager_command_to_policy(pd_data->dev,
MANAGER_REQ_PR_SWAP);
break;
+ case MANAGER_SEND_DR_SWAP:
+ usbpd_manager_command_to_policy(pd_data->dev,
+ MANAGER_REQ_DR_SWAP);
+ break;
default:
pr_info("%s: not matched event(%d)\n", __func__, event);
}
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 = 0;
+ 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
#include <linux/ifconn/ifconn_notifier.h>
#endif
+#include <linux/ccic/usbpd-s2mu106.h>
+
#define CHECK_MSG(pd, msg, ret) do {\
if (pd->phy_ops.get_status(pd, msg))\
return ret;\
/* 1) PD State Inform for AP */
dev_info(pd_data->dev, "%s\n", __func__);
- policy->pd_support = 1;
+ if (pd_data->pd_support == 0) {
+ pd_data->pd_support = 1;
+ pd_data->phy_ops.set_pwr_opmode(pd_data, TYPEC_PWR_MODE_PD);
+ }
/* 2) Wait Message or State */
CHECK_MSG(pd_data, MSG_GET_SRC_CAP, PE_SRC_Give_Source_Cap);
CHECK_MSG(pd_data, MSG_SOFTRESET, PE_SRC_Soft_Reset);
CHECK_MSG(pd_data, MSG_ERROR, PE_SRC_Send_Soft_Reset);
CHECK_MSG(pd_data, MSG_BIST, PE_BIST_Receive_Mode);
+
#if 0
CHECK_MSG(pd_data, VDM_DISCOVER_IDENTITY, PE_UFP_VDM_Get_Identity);
CHECK_MSG(pd_data, VDM_DISCOVER_SVID, PE_UFP_VDM_Get_SVIDs);
#if defined(CONFIG_IFCONN_NOTIFIER)
pd_noti.sink_status.current_pdo_num = pd_noti.sink_status.selected_pdo_num;
#endif
+ /* 2) Notify Plug Attach */
+ usbpd_manager_plug_attach(pd_data->dev);
+
ret = PE_SNK_Ready;
break;
}
/* 1) PD State Inform to AP */
dev_info(pd_data->dev, "%s\n", __func__);
- /* enable pd support for typec role swap */
- policy->pd_support = 1;
-
- /* 2) Notify Plug Attach */
- usbpd_manager_plug_attach(pd_data->dev);
+ if (pd_data->pd_support == 0) {
+ pd_data->pd_support = 1;
+ pd_data->phy_ops.set_pwr_opmode(pd_data, TYPEC_PWR_MODE_PD);
+ }
/* 3) Message Check */
CHECK_MSG(pd_data, MSG_GET_SNK_CAP, PE_SNK_Give_Sink_Cap);
mutex_lock(&pd_data->accept_mutex);
usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
USBPD_Accept, USBPD_DFP, power_role);
-
pd_data->phy_ops.set_data_role(pd_data, USBPD_UFP);
mutex_unlock(&pd_data->accept_mutex);
if (pd_data->phy_ops.get_status(pd_data, MSG_ACCEPT)) {
dev_info(pd_data->dev, "%s, got Accept\n", __func__);
ret = PE_DRS_DFP_UFP_Change_to_UFP;
+ pd_data->phy_ops.set_data_role(pd_data, USBPD_UFP);
break;
}
if (pd_data->phy_ops.get_status(pd_data, MSG_REJECT)) {
mutex_lock(&pd_data->accept_mutex);
usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header,
USBPD_Accept, USBPD_UFP, power_role);
- pd_data->phy_ops.set_data_role(pd_data, USBPD_DFP);
mutex_unlock(&pd_data->accept_mutex);
return PE_DRS_UFP_DFP_Change_to_DFP;
}
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;
+ return ret;
}
policy_state usbpd_policy_prs_src_snk_accept_swap(struct policy_data *policy)
if (pd_data->phy_ops.get_status(pd_data, MSG_PSRDY)) {
dev_info(pd_data->dev, "got PSRDY.\n");
pd_data->counter.swap_hard_reset_counter = 0;
+ pd_data->phy_ops.set_cc_control(pd_data, USBPD_CC_OFF);
/* Self SoftReset for Message ID Clear */
pd_data->phy_ops.soft_reset(pd_data);
- mdelay(15);
+ msleep(20);
+ pd_data->phy_ops.pr_swap(pd_data, USBPD_PR_DONE);
ret = PE_SNK_Startup;
break;
}
ms = usbpd_check_time1(pd_data);
if (pd_data->phy_ops.get_status(pd_data, MSG_ACCEPT)) {
ret = PE_PRS_SNK_SRC_Transition_off;
+ pd_data->phy_ops.set_power_role(pd_data, USBPD_SINK);
break;
}
/* Send Accept Message */
pd_data->phy_ops.get_data_role(pd_data, &data_role);
+
usbpd_send_ctrl_msg(pd_data, &policy->tx_msg_header, USBPD_Accept,
data_role, USBPD_SINK);
+
pd_data->phy_ops.set_power_role(pd_data, USBPD_SINK);
return PE_PRS_SNK_SRC_Transition_off;
while (1) {
if (policy->plug_valid == 0) {
ret = PE_PRS_SNK_SRC_Transition_off;
+ pd_data->phy_ops.set_power_role(pd_data, USBPD_DRP);
break;
}
ms = usbpd_check_time1(pd_data);
/* Self SoftReset for Message ID Clear */
pd_data->phy_ops.soft_reset(pd_data);
+ pd_data->phy_ops.pr_swap(pd_data, USBPD_PR_DONE);
+
return PE_SRC_Startup;
}
Request Identity information from DPM
**********************************************/
- return PE_UFP_VDM_Get_Identity_NAK;
+ return PE_UFP_VDM_Send_Identity;
}
policy_state usbpd_policy_ufp_vdm_send_identity(struct policy_data *policy)
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_msg_header.num_data_objs = 4;
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.command_type = Responder_ACK;
policy->tx_data_obj[0].structured_vdm.command = Discover_Identity;
+ policy->tx_data_obj[1].object = 0xD10004E8;
+ policy->tx_data_obj[2].object = 0x0;
+ policy->tx_data_obj[3].object = 0x68600000;
+
/* TODO: data object should be prepared from device manager */
if (usbpd_send_msg(pd_data, &policy->tx_msg_header,
pr_info("%s: event:%d\n", __func__, pnoti->event);
- if (pnoti->event == IFCONN_NOTIFY_EVENT_USB_ATTACH_UFP)
+ if (pnoti->event == IFCONN_NOTIFY_EVENT_PD_SINK) {
ccic->ccic_evt_roleswap = 1;
+ } else if (pnoti->event == IFCONN_NOTIFY_EVENT_PD_SOURCE) {
+ 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);
+ }
#endif
return 0;
}
#define TA_WATER_CHK_DURATION_MS 5000
/* define timer */
-#define S2MU106_ROLE_SWAP_TIME_MS (1350)
+#define S2MU106_ROLE_SWAP_TIME_MS (500)
#define S2MU106_HARD_RESET_DELAY_MS (300)
#define S2MU106_WAIT_RD_DETACH_DELAY_MS (200)
#define S2MU106_WAIT_ATTACH_DELAY_MS (30)
TYPE_C_ATTACH_DFP = 1, /* Host */
TYPE_C_ATTACH_UFP = 2, /* Device */
TYPE_C_ATTACH_DRP = 3, /* Dual role */
+ TYPE_C_PR_SWAP = 4,
+ TYPE_C_DR_SWAP = 5,
} CCIC_OTP_MODE;
typedef enum {
bool vbus_short_check;
bool vbus_short;
bool vbus_access;
+ int cc1_val;
+ int cc2_val;
#ifndef CONFIG_SEC_FACTORY
bool lpcharge_water;
#endif
struct notifier_block type3_nb;
struct workqueue_struct *pdic_queue;
struct delayed_work plug_work;
+ struct delayed_work dr_work;
struct delayed_work water_detect_handler;
struct delayed_work ta_water_detect_handler;
struct delayed_work water_dry_handler;
#define tVDMWaitModeEntry (50) /* 40~50 ms */
#define tVDMWaitModeExit (50) /* 40~50 ms */
#define tDiscoverIdentity (50) /* 40~50 ms */
-#define tSwapSourceStart (20) /* 20 ms */
+#define tSwapSourceStart (30) /* 30 ms */
#define tTypeCSinkWaitCap (310) /* 310~620 ms */
#define tTypeCSendSourceCap (100) /* 100~200ms */
#define tSrcRecover (880) /* 660~1000ms */
MANAGER_UVDM_RECEIVE_MESSAGE = 17,
MANAGER_START_DISCOVER_IDENTITY = 18,
MANAGER_SEND_PR_SWAP = 19,
+ MANAGER_SEND_DR_SWAP = 20,
} usbpd_manager_event_type;
enum usbpd_msg_status {
void (*pr_swap)(void *, int);
int (*vbus_on_check)(void *);
int (*get_side_check)(void *_data);
+ void (*set_pwr_opmode)(void *_data, int mode);
} usbpd_phy_ops_type;
struct policy_data {
struct timeval time1;
struct timeval time2;
+
+ int pd_support;
};
static inline struct usbpd_data *protocol_rx_to_usbpd(struct protocol_data *rx)
extern void usbpd_manager_acc_handler_cancel(struct device *);
extern void usbpd_manager_acc_detach_handler(struct work_struct *);
extern void usbpd_manager_send_pr_swap(struct device *);
+extern void usbpd_manager_send_dr_swap(struct device *);
extern void usbpd_policy_work(struct work_struct *);
extern void usbpd_protocol_tx(struct usbpd_data *);
extern void usbpd_protocol_rx(struct usbpd_data *);
USBPD_SINK_ON,
USBPD_SOURCE_OFF,
USBPD_SOURCE_ON,
+ USBPD_PR_DONE,
};
enum usbpd_port_role {