usb: pd: Ensure VBUS is below 0.8V before turning it on
The Type-C spec requires that VBUS must not be enabled as a source if there is already a voltage > VSafe0V. To address this, add a polling loop that checks PROP_VOLTAGE_NOW to ensure it has fallen below 0.8V before enabling the VBUS regulator. Change-Id: Idd3ebd185d6bbed15b6ac700cb2cf4af428210ee Signed-off-by: Jack Pham <jackp@codeaurora.org>
This commit is contained in:
parent
314869eb56
commit
44e0fb6162
1 changed files with 42 additions and 18 deletions
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2016, Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2016-2017, Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -253,6 +253,9 @@ static void *usbpd_ipc_log;
|
|||
#define ID_HDR_VID 0x05c6 /* qcom */
|
||||
#define PROD_VDO_PID 0x0a00 /* TBD */
|
||||
|
||||
static bool check_vsafe0v = true;
|
||||
module_param(check_vsafe0v, bool, S_IRUSR | S_IWUSR);
|
||||
|
||||
static int min_sink_current = 900;
|
||||
module_param(min_sink_current, int, S_IRUSR | S_IWUSR);
|
||||
|
||||
|
@ -1390,6 +1393,41 @@ static void vconn_swap(struct usbpd *pd)
|
|||
}
|
||||
}
|
||||
|
||||
static int enable_vbus(struct usbpd *pd)
|
||||
{
|
||||
union power_supply_propval val = {0};
|
||||
int count = 100;
|
||||
int ret;
|
||||
|
||||
if (!check_vsafe0v)
|
||||
goto enable_reg;
|
||||
|
||||
/*
|
||||
* Check to make sure there's no lingering charge on
|
||||
* VBUS before enabling it as a source. If so poll here
|
||||
* until it goes below VSafe0V (0.8V) before proceeding.
|
||||
*/
|
||||
while (count--) {
|
||||
ret = power_supply_get_property(pd->usb_psy,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
|
||||
if (ret || val.intval <= 800000)
|
||||
break;
|
||||
usleep_range(20000, 30000);
|
||||
}
|
||||
|
||||
if (count < 99)
|
||||
msleep(100); /* need to wait an additional tCCDebounce */
|
||||
|
||||
enable_reg:
|
||||
ret = regulator_enable(pd->vbus);
|
||||
if (ret)
|
||||
usbpd_err(&pd->dev, "Unable to enable vbus (%d)\n", ret);
|
||||
else
|
||||
pd->vbus_enabled = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void rx_msg_cleanup(struct usbpd *pd)
|
||||
{
|
||||
struct rx_msg *msg, *tmp;
|
||||
|
@ -1541,12 +1579,7 @@ static void usbpd_sm(struct work_struct *w)
|
|||
if (pd->current_pr == PR_SINK) {
|
||||
usbpd_set_state(pd, PE_SNK_STARTUP);
|
||||
} else if (pd->current_pr == PR_SRC) {
|
||||
ret = regulator_enable(pd->vbus);
|
||||
if (ret)
|
||||
usbpd_err(&pd->dev, "Unable to enable vbus\n");
|
||||
else
|
||||
pd->vbus_enabled = true;
|
||||
|
||||
enable_vbus(pd);
|
||||
if (!pd->vconn_enabled &&
|
||||
pd->typec_mode ==
|
||||
POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE) {
|
||||
|
@ -1718,11 +1751,7 @@ static void usbpd_sm(struct work_struct *w)
|
|||
msleep(SRC_RECOVER_TIME);
|
||||
|
||||
pd->vbus_enabled = false;
|
||||
ret = regulator_enable(pd->vbus);
|
||||
if (ret)
|
||||
usbpd_err(&pd->dev, "Unable to enable vbus\n");
|
||||
else
|
||||
pd->vbus_enabled = true;
|
||||
enable_vbus(pd);
|
||||
|
||||
if (pd->vconn_enabled) {
|
||||
ret = regulator_enable(pd->vconn);
|
||||
|
@ -2145,12 +2174,7 @@ static void usbpd_sm(struct work_struct *w)
|
|||
/* fall-through */
|
||||
|
||||
case PE_PRS_SNK_SRC_SOURCE_ON:
|
||||
ret = regulator_enable(pd->vbus);
|
||||
if (ret)
|
||||
usbpd_err(&pd->dev, "Unable to enable vbus\n");
|
||||
else
|
||||
pd->vbus_enabled = true;
|
||||
|
||||
enable_vbus(pd);
|
||||
msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */
|
||||
|
||||
ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
|
||||
|
|
Loading…
Add table
Reference in a new issue