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
|
* 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
|
* 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 ID_HDR_VID 0x05c6 /* qcom */
|
||||||
#define PROD_VDO_PID 0x0a00 /* TBD */
|
#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;
|
static int min_sink_current = 900;
|
||||||
module_param(min_sink_current, int, S_IRUSR | S_IWUSR);
|
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)
|
static inline void rx_msg_cleanup(struct usbpd *pd)
|
||||||
{
|
{
|
||||||
struct rx_msg *msg, *tmp;
|
struct rx_msg *msg, *tmp;
|
||||||
|
@ -1541,12 +1579,7 @@ static void usbpd_sm(struct work_struct *w)
|
||||||
if (pd->current_pr == PR_SINK) {
|
if (pd->current_pr == PR_SINK) {
|
||||||
usbpd_set_state(pd, PE_SNK_STARTUP);
|
usbpd_set_state(pd, PE_SNK_STARTUP);
|
||||||
} else if (pd->current_pr == PR_SRC) {
|
} else if (pd->current_pr == PR_SRC) {
|
||||||
ret = regulator_enable(pd->vbus);
|
enable_vbus(pd);
|
||||||
if (ret)
|
|
||||||
usbpd_err(&pd->dev, "Unable to enable vbus\n");
|
|
||||||
else
|
|
||||||
pd->vbus_enabled = true;
|
|
||||||
|
|
||||||
if (!pd->vconn_enabled &&
|
if (!pd->vconn_enabled &&
|
||||||
pd->typec_mode ==
|
pd->typec_mode ==
|
||||||
POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE) {
|
POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE) {
|
||||||
|
@ -1718,11 +1751,7 @@ static void usbpd_sm(struct work_struct *w)
|
||||||
msleep(SRC_RECOVER_TIME);
|
msleep(SRC_RECOVER_TIME);
|
||||||
|
|
||||||
pd->vbus_enabled = false;
|
pd->vbus_enabled = false;
|
||||||
ret = regulator_enable(pd->vbus);
|
enable_vbus(pd);
|
||||||
if (ret)
|
|
||||||
usbpd_err(&pd->dev, "Unable to enable vbus\n");
|
|
||||||
else
|
|
||||||
pd->vbus_enabled = true;
|
|
||||||
|
|
||||||
if (pd->vconn_enabled) {
|
if (pd->vconn_enabled) {
|
||||||
ret = regulator_enable(pd->vconn);
|
ret = regulator_enable(pd->vconn);
|
||||||
|
@ -2145,12 +2174,7 @@ static void usbpd_sm(struct work_struct *w)
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
|
||||||
case PE_PRS_SNK_SRC_SOURCE_ON:
|
case PE_PRS_SNK_SRC_SOURCE_ON:
|
||||||
ret = regulator_enable(pd->vbus);
|
enable_vbus(pd);
|
||||||
if (ret)
|
|
||||||
usbpd_err(&pd->dev, "Unable to enable vbus\n");
|
|
||||||
else
|
|
||||||
pd->vbus_enabled = true;
|
|
||||||
|
|
||||||
msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */
|
msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */
|
||||||
|
|
||||||
ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
|
ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
|
||||||
|
|
Loading…
Add table
Reference in a new issue