summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHemant Kumar <hemantk@codeaurora.org>2017-07-20 13:51:49 -0700
committerJack Pham <jackp@codeaurora.org>2018-01-17 17:55:15 -0800
commitf83e315016ed98567696797b7cb2168a61950a32 (patch)
tree435225cad01898fd98a0b860a2075c20b50aeb75
parentb3b1b7012ce3bdd728f867114e08053b8b7b4fe7 (diff)
usb: pd: Support revision 3.0 in sink-only mode
commit 07040df2790e ("usb: pd: policy_engine: Handle spec revision properly") changed the spec revision handling to be 2.0 mode unless a programmable power supply is seen. Extend this via a module parameter to allow PD 3.0 in sink-only mode regardless of PPS when a 3.0 source is connected. Since the revision of the source is first encountered when receiving the Source Capabilities message, this information is lost by the time pd_eval_src_caps() is called. So bring back the handling in phy_msg_received() removed in commit 07040df2790e ("usb: pd: policy_engine: Handle spec revision properly"). Change-Id: I0485224aeadcffbfaecd0c7942c6dbcd9ddd3813 Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
-rw-r--r--drivers/usb/pd/policy_engine.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 77a1627ac5f2..f2383b62a68b 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -38,6 +38,10 @@ static bool disable_usb_pd;
module_param(disable_usb_pd, bool, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(disable_usb_pd, "Disable USB PD for USB3.1 compliance testing");
+static bool rev3_sink_only;
+module_param(rev3_sink_only, bool, 0644);
+MODULE_PARM_DESC(rev3_sink_only, "Enable power delivery rev3.0 sink only mode");
+
enum usbpd_state {
PE_UNKNOWN,
PE_ERROR_RECOVERY,
@@ -670,7 +674,7 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua)
static int pd_eval_src_caps(struct usbpd *pd)
{
- int obj_cnt;
+ int i;
union power_supply_propval val;
u32 first_pdo = pd->received_pdos[0];
@@ -687,11 +691,20 @@ static int pd_eval_src_caps(struct usbpd *pd)
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val);
- for (obj_cnt = 1; obj_cnt < PD_MAX_DATA_OBJ; obj_cnt++) {
- if ((PD_SRC_PDO_TYPE(pd->received_pdos[obj_cnt]) ==
+ if (pd->spec_rev == USBPD_REV_30 && !rev3_sink_only) {
+ bool pps_found = false;
+
+ /* downgrade to 2.0 if no PPS */
+ for (i = 1; i < PD_MAX_DATA_OBJ; i++) {
+ if ((PD_SRC_PDO_TYPE(pd->received_pdos[i]) ==
PD_SRC_PDO_TYPE_AUGMENTED) &&
- !PD_APDO_PPS(pd->received_pdos[obj_cnt]))
- pd->spec_rev = USBPD_REV_30;
+ !PD_APDO_PPS(pd->received_pdos[i])) {
+ pps_found = true;
+ break;
+ }
+ }
+ if (!pps_found)
+ pd->spec_rev = USBPD_REV_20;
}
/* Select the first PDO (vSafe5V) immediately. */
@@ -1034,6 +1047,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
+ /* support only PD 2.0 as a source */
+ pd->spec_rev = USBPD_REV_20;
pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
@@ -1204,6 +1219,11 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
if (!val.intval || disable_usb_pd)
break;
+ /*
+ * support up to PD 3.0 as a sink; if source is 2.0
+ * phy_msg_received() will handle the downgrade.
+ */
+ pd->spec_rev = USBPD_REV_30;
pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
@@ -1909,6 +1929,8 @@ static void usbpd_sm(struct work_struct *w)
/* set due to dual_role class "mode" change */
if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
val.intval = pd->forced_pr;
+ else if (rev3_sink_only)
+ val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
else
/* Set CC back to DRP toggle */
val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
@@ -3910,8 +3932,6 @@ struct usbpd *usbpd_create(struct device *parent)
pd->dual_role->drv_data = pd;
}
- /* default support as PD 2.0 source or sink */
- pd->spec_rev = USBPD_REV_20;
pd->current_pr = PR_NONE;
pd->current_dr = DR_NONE;
list_add_tail(&pd->instance, &_usbpd);