From 7ae4a1711ecb0fbd69578348a63e9592c611dda3 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 19 Oct 2016 12:54:58 -0700 Subject: usb: pd: Start state machine when PE_START is true Support the new POWER_SUPPLY_PROP_PE_START property which indicates when the policy engine state machine can begin. This helps to simplify the psy_changed() routine as we can now rely on this property to indicate that PROP_TYPEC_MODE and PROP_TYPE are already settled. The state machine work can now simply begin when seeing a change in TYPEC_MODE. This replaces the previous use of PROP_PD_ALLOWED which prior to commit 18da08334eb3 ("usb: pd: Handle PD_ALLOWED within state machine") was intended to be a marker to start up the policy engine but now simply indicates whether or not to start PD comms. We can now move reading of this property to usbpd_set_state() as it is now only needed locally in the SNK_STARTUP handling. Change-Id: Ia0b9e5b011ae72e1afcaf5109b8253d124afc021 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 177 +++++++++++++++++++++-------------------- 1 file changed, 90 insertions(+), 87 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 26c91e0ce163..c81a56c7be49 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -299,7 +299,6 @@ struct usbpd { enum power_supply_typec_mode typec_mode; enum power_supply_type psy_type; bool vbus_present; - bool pd_allowed; enum data_role current_dr; enum power_role current_pr; @@ -828,7 +827,15 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } } - if (!pd->pd_allowed) + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ALLOWED, &val); + if (ret) { + usbpd_err(&pd->dev, "Unable to read USB PROP_PD_ALLOWED: %d\n", + ret); + break; + } + + if (!val.intval) break; /* Reset protocol layer */ @@ -2036,41 +2043,41 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) struct usbpd *pd = container_of(nb, struct usbpd, psy_nb); union power_supply_propval val; enum power_supply_typec_mode typec_mode; - bool do_work = false; int ret; if (ptr != pd->usb_psy || evt != PSY_EVENT_PROP_CHANGED) return 0; ret = power_supply_get_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ALLOWED, &val); + POWER_SUPPLY_PROP_TYPEC_MODE, &val); if (ret) { - usbpd_err(&pd->dev, "Unable to read USB PROP_PD_ALLOWED: %d\n", - ret); + usbpd_err(&pd->dev, "Unable to read USB TYPEC_MODE: %d\n", ret); return ret; } - if (pd->pd_allowed != val.intval) - do_work = true; - pd->pd_allowed = val.intval; + typec_mode = val.intval; ret = power_supply_get_property(pd->usb_psy, - POWER_SUPPLY_PROP_PRESENT, &val); + POWER_SUPPLY_PROP_PE_START, &val); if (ret) { - usbpd_err(&pd->dev, "Unable to read USB PRESENT: %d\n", ret); + usbpd_err(&pd->dev, "Unable to read USB PROP_PE_START: %d\n", + ret); return ret; } - pd->vbus_present = val.intval; + /* Don't proceed if PE_START=0 as other props may still change */ + if (!val.intval && !pd->pd_connected && + typec_mode != POWER_SUPPLY_TYPEC_NONE) + return 0; ret = power_supply_get_property(pd->usb_psy, - POWER_SUPPLY_PROP_TYPEC_MODE, &val); + POWER_SUPPLY_PROP_PRESENT, &val); if (ret) { - usbpd_err(&pd->dev, "Unable to read USB TYPEC_MODE: %d\n", ret); + usbpd_err(&pd->dev, "Unable to read USB PRESENT: %d\n", ret); return ret; } - typec_mode = val.intval; + pd->vbus_present = val.intval; ret = power_supply_get_property(pd->usb_psy, POWER_SUPPLY_PROP_TYPE, &val); @@ -2079,91 +2086,87 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) return ret; } - if (pd->psy_type != val.intval) - do_work = true; pd->psy_type = val.intval; + if (pd->typec_mode == typec_mode) + return 0; + + pd->typec_mode = typec_mode; + usbpd_dbg(&pd->dev, "typec mode:%d present:%d type:%d orientation:%d\n", typec_mode, pd->vbus_present, pd->psy_type, usbpd_get_plug_orientation(pd)); - if (pd->typec_mode != typec_mode) { - pd->typec_mode = typec_mode; - do_work = true; - - switch (typec_mode) { - /* Disconnect */ - case POWER_SUPPLY_TYPEC_NONE: - if (pd->in_pr_swap) { - usbpd_dbg(&pd->dev, "Ignoring disconnect due to PR swap\n"); - do_work = false; - } + switch (typec_mode) { + /* Disconnect */ + case POWER_SUPPLY_TYPEC_NONE: + if (pd->in_pr_swap) { + usbpd_dbg(&pd->dev, "Ignoring disconnect due to PR swap\n"); + return 0; + } - /* - * Workaround for PMIC HW bug. - * - * During hard reset when VBUS goes to 0 the CC logic - * will report this as a disconnection. In those cases - * it can be ignored, however the downside is that - * pd->hard_reset can be momentarily true even when a - * non-PD capable source is attached, and can't be - * distinguished from a physical disconnect. In that - * case, allow for the common case of disconnecting - * from an SDP. - * - * The less common case is a PD-capable SDP which will - * result in a hard reset getting treated like a - * disconnect. We can live with this until the HW bug - * is fixed: in which disconnection won't be reported - * on VBUS loss alone unless pullup is also removed - * from CC. - */ - if (pd->psy_type != POWER_SUPPLY_TYPE_USB && - pd->current_state == - PE_SNK_TRANSITION_TO_DEFAULT) { - usbpd_dbg(&pd->dev, "Ignoring disconnect due to hard reset\n"); - do_work = false; - } + /* + * Workaround for PMIC HW bug. + * + * During hard reset when VBUS goes to 0 the CC logic + * will report this as a disconnection. In those cases + * it can be ignored, however the downside is that + * pd->hard_reset can be momentarily true even when a + * non-PD capable source is attached, and can't be + * distinguished from a physical disconnect. In that + * case, allow for the common case of disconnecting + * from an SDP. + * + * The less common case is a PD-capable SDP which will + * result in a hard reset getting treated like a + * disconnect. We can live with this until the HW bug + * is fixed: in which disconnection won't be reported + * on VBUS loss alone unless pullup is also removed + * from CC. + */ + if (pd->psy_type != POWER_SUPPLY_TYPE_USB && + pd->current_state == + PE_SNK_TRANSITION_TO_DEFAULT) { + usbpd_dbg(&pd->dev, "Ignoring disconnect due to hard reset\n"); + return 0; + } - break; + break; - /* Sink states */ - case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: - case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: - case POWER_SUPPLY_TYPEC_SOURCE_HIGH: - usbpd_info(&pd->dev, "Type-C Source (%s) connected\n", - src_current(typec_mode)); - pd->current_pr = PR_SINK; - pd->in_pr_swap = false; - break; + /* Sink states */ + case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: + case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: + case POWER_SUPPLY_TYPEC_SOURCE_HIGH: + usbpd_info(&pd->dev, "Type-C Source (%s) connected\n", + src_current(typec_mode)); + pd->current_pr = PR_SINK; + pd->in_pr_swap = false; + break; - /* Source states */ - case POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE: - case POWER_SUPPLY_TYPEC_SINK: - usbpd_info(&pd->dev, "Type-C Sink%s connected\n", - typec_mode == POWER_SUPPLY_TYPEC_SINK ? - "" : " (powered)"); - pd->current_pr = PR_SRC; - pd->in_pr_swap = false; - break; + /* Source states */ + case POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE: + case POWER_SUPPLY_TYPEC_SINK: + usbpd_info(&pd->dev, "Type-C Sink%s connected\n", + typec_mode == POWER_SUPPLY_TYPEC_SINK ? + "" : " (powered)"); + pd->current_pr = PR_SRC; + pd->in_pr_swap = false; + break; - case POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY: - usbpd_info(&pd->dev, "Type-C Debug Accessory connected\n"); - break; - case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: - usbpd_info(&pd->dev, "Type-C Analog Audio Adapter connected\n"); - break; - default: - usbpd_warn(&pd->dev, "Unsupported typec mode:%d\n", - typec_mode); - break; - } + case POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY: + usbpd_info(&pd->dev, "Type-C Debug Accessory connected\n"); + break; + case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: + usbpd_info(&pd->dev, "Type-C Analog Audio Adapter connected\n"); + break; + default: + usbpd_warn(&pd->dev, "Unsupported typec mode:%d\n", + typec_mode); + break; } - /* only queue state machine if CC state or PD_ALLOWED changes */ - if (do_work) - kick_sm(pd, 0); - + /* queue state machine due to CC state change */ + kick_sm(pd, 0); return 0; } -- cgit v1.2.3