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:
Jack Pham 2017-01-25 18:27:44 -08:00
parent 314869eb56
commit 44e0fb6162

View file

@ -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);