Loading Documentation/devicetree/bindings/usb/qpnp-pdphy.txt +3 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ Optional properties: - vconn-supply: Regulator that enables VCONN source output. This will be supplied on the USB CC line that is not used for communication when Ra resistance is detected. - qcom,vconn-uses-external-source: Indicates whether VCONN supply is sourced from an external regulator. If omitted, then it is assumed it is connected to VBUS. Example: qcom,qpnp-pdphy@1700 { Loading drivers/power/power_supply_sysfs.c +3 −0 Original line number Diff line number Diff line Loading @@ -267,6 +267,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(typec_power_role), POWER_SUPPLY_ATTR(pd_allowed), POWER_SUPPLY_ATTR(pd_active), POWER_SUPPLY_ATTR(pd_in_hard_reset), POWER_SUPPLY_ATTR(pd_current_max), POWER_SUPPLY_ATTR(pd_usb_suspend_supported), POWER_SUPPLY_ATTR(charger_temp), POWER_SUPPLY_ATTR(charger_temp_max), POWER_SUPPLY_ATTR(parallel_disable), Loading drivers/usb/pd/policy_engine.c +291 −107 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ enum usbpd_state { PE_PRS_SRC_SNK_SEND_SWAP, PE_PRS_SRC_SNK_TRANSITION_TO_OFF, PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_VCS_WAIT_FOR_VCONN, }; static const char * const usbpd_state_strings[] = { Loading Loading @@ -94,6 +95,7 @@ static const char * const usbpd_state_strings[] = { "PRS_SRC_SNK_Send_Swap", "PRS_SRC_SNK_Transition_to_off", "PRS_SRC_SNK_Wait_Source_on", "VCS_Wait_for_VCONN", }; enum usbpd_control_msg_type { Loading Loading @@ -170,6 +172,7 @@ static void *usbpd_ipc_log; #define PS_SOURCE_OFF 750 #define SWAP_SOURCE_START_TIME 20 #define VDM_BUSY_TIME 50 #define VCONN_ON_TIME 100 /* tPSHardReset + tSafe0V + tSrcRecover + tSrcTurnOn */ #define SNK_HARD_RESET_RECOVER_TIME (35 + 650 + 1000 + 275) Loading @@ -195,7 +198,7 @@ static void *usbpd_ipc_log; #define PD_RDO_MISMATCH(rdo) ((rdo) >> 26 & 1) #define PD_RDO_USB_COMM(rdo) ((rdo) >> 25 & 1) #define PD_RDO_NO_USB_SUSP(rdo) ((rdo) >> 24 & 1) #define PD_RDO_FIXED_CURR(rdo) ((rdo) >> 19 & 0x3FF) #define PD_RDO_FIXED_CURR(rdo) ((rdo) >> 10 & 0x3FF) #define PD_RDO_FIXED_CURR_MINMAX(rdo) ((rdo) & 0x3FF) #define PD_SRC_PDO_TYPE(pdo) (((pdo) >> 30) & 3) Loading Loading @@ -223,9 +226,10 @@ static void *usbpd_ipc_log; /* VDM header is the first 32-bit object following the 16-bit PD header */ #define VDM_HDR_SVID(hdr) ((hdr) >> 16) #define VDM_HDR_TYPE(hdr) ((hdr) & 0x8000) #define VDM_HDR_CMD_TYPE(hdr) (((hdr) >> 6) & 0x3) #define VDM_HDR_CMD(hdr) ((hdr) & 0x1f) #define VDM_IS_SVDM(hdr) ((hdr) & 0x8000) #define SVDM_HDR_OBJ_POS(hdr) (((hdr) >> 8) & 0x7) #define SVDM_HDR_CMD_TYPE(hdr) (((hdr) >> 6) & 0x3) #define SVDM_HDR_CMD(hdr) ((hdr) & 0x1f) #define SVDM_HDR(svid, ver, obj, cmd_type, cmd) \ (((svid) << 16) | (1 << 15) | ((ver) << 13) \ Loading Loading @@ -253,15 +257,11 @@ static bool ss_dev = true; module_param(ss_dev, bool, S_IRUSR | S_IWUSR); static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */ static const u32 default_snk_caps[] = { 0x2601905A, /* 5V @ 900mA */ 0x0002D096, /* 9V @ 1.5A */ 0x0003C064 }; /* 12V @ 1A */ static const u32 default_snk_caps[] = { 0x2601905A }; /* 5V @ 900mA */ struct vdm_tx { u32 data[7]; int size; struct list_head entry; }; struct usbpd { Loading @@ -269,6 +269,7 @@ struct usbpd { struct workqueue_struct *wq; struct work_struct sm_work; struct hrtimer timer; bool sm_queued; struct extcon_dev *extcon; Loading Loading @@ -307,6 +308,7 @@ struct usbpd { struct regulator *vbus; struct regulator *vconn; bool vconn_enabled; bool vconn_is_external; u8 tx_msgid; u8 rx_msgid; Loading @@ -315,8 +317,9 @@ struct usbpd { enum vdm_state vdm_state; u16 *discovered_svids; int num_svids; struct vdm_tx *vdm_tx; struct vdm_tx *vdm_tx_retry; struct list_head vdm_tx_queue; struct list_head svid_handlers; struct list_head instance; Loading Loading @@ -440,6 +443,12 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos) } pd->requested_voltage = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000; /* Can't sink more than 5V if VCONN is sourced from the VBUS input */ if (pd->vconn_enabled && !pd->vconn_is_external && pd->requested_voltage > 5000000) return -ENOTSUPP; pd->requested_current = curr; pd->requested_pdo = pdo_pos; pd->rdo = PD_RDO_FIXED(pdo_pos, 0, mismatch, 1, 1, curr / 10, Loading Loading @@ -485,6 +494,17 @@ static void pd_send_hard_reset(struct usbpd *pd) pd->hard_reset = true; } static void kick_sm(struct usbpd *pd, int ms) { pm_stay_awake(&pd->dev); pd->sm_queued = true; if (ms) hrtimer_start(&pd->timer, ms_to_ktime(ms), HRTIMER_MODE_REL); else queue_work(pd->wq, &pd->sm_work); } static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) { if (type != HARD_RESET_SIG) { Loading @@ -497,7 +517,7 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) /* Force CC logic to source/sink to keep Rp/Rd unchanged */ set_power_role(pd, pd->current_pr); pd->hard_reset = true; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); } static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, Loading Loading @@ -534,6 +554,10 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, pd->rx_msgid = PD_MSG_HDR_ID(header); /* discard Pings */ if (PD_MSG_HDR_TYPE(header) == MSG_PING && !len) return; /* check header's count field to see if it matches len */ if (PD_MSG_HDR_COUNT(header) != (len / 4)) { usbpd_err(&pd->dev, "header count (%d) mismatch, len=%ld\n", Loading @@ -541,11 +565,18 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, return; } /* block until previous message has been consumed by usbpd_sm */ if (pd->rx_msg_type) flush_work(&pd->sm_work); pd->rx_msg_type = PD_MSG_HDR_TYPE(header); pd->rx_msg_len = PD_MSG_HDR_COUNT(header); memcpy(&pd->rx_payload, buf, len); queue_work(pd->wq, &pd->sm_work); usbpd_dbg(&pd->dev, "received message: type(%d) len(%d)\n", pd->rx_msg_type, pd->rx_msg_len); kick_sm(pd, 0); } static void phy_shutdown(struct usbpd *pd) Loading Loading @@ -587,7 +618,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->in_pr_swap = false; set_power_role(pd, PR_NONE); pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); break; /* Source states */ Loading Loading @@ -634,20 +665,22 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->current_state = PE_SRC_SEND_CAPABILITIES; if (pd->in_pr_swap) { pd->in_pr_swap = false; hrtimer_start(&pd->timer, ms_to_ktime(SWAP_SOURCE_START_TIME), HRTIMER_MODE_REL); kick_sm(pd, SWAP_SOURCE_START_TIME); break; } /* fall-through */ case PE_SRC_SEND_CAPABILITIES: queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); break; case PE_SRC_NEGOTIATE_CAPABILITY: if (PD_RDO_OBJ_POS(pd->rdo) != 1) { if (PD_RDO_OBJ_POS(pd->rdo) != 1 || PD_RDO_FIXED_CURR(pd->rdo) > PD_SRC_PDO_FIXED_MAX_CURR(*default_src_caps) || PD_RDO_FIXED_CURR_MINMAX(pd->rdo) > PD_SRC_PDO_FIXED_MAX_CURR(*default_src_caps)) { /* send Reject */ ret = pd_send_msg(pd, MSG_REJECT, NULL, 0, SOP_MSG); if (ret) { Loading Loading @@ -717,6 +750,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) break; case PE_SRC_TRANSITION_TO_DEFAULT: pd->hard_reset = false; if (pd->vconn_enabled) regulator_disable(pd->vconn); regulator_disable(pd->vbus); Loading Loading @@ -747,7 +782,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SRC_HARD_RESET: case PE_SNK_HARD_RESET: /* hard reset may sleep; handle it in the workqueue */ queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); break; case PE_SRC_SEND_SOFT_RESET: Loading @@ -765,8 +800,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } /* wait for ACCEPT */ hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), HRTIMER_MODE_REL); kick_sm(pd, SENDER_RESPONSE_TIME); break; /* Sink states */ Loading @@ -786,9 +820,11 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } } /* Reset protocol layer */ pd->tx_msgid = 0; pd->rx_msgid = -1; pd->rx_msg_len = 0; pd->rx_msg_type = 0; pd->rx_msgid = -1; if (!pd->in_pr_swap) { if (pd->pd_phy_opened) { Loading Loading @@ -819,11 +855,9 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SNK_WAIT_FOR_CAPABILITIES: if (pd->rx_msg_len && pd->rx_msg_type) queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); else hrtimer_start(&pd->timer, ms_to_ktime(SINK_WAIT_CAP_TIME), HRTIMER_MODE_REL); kick_sm(pd, SINK_WAIT_CAP_TIME); break; case PE_SNK_EVALUATE_CAPABILITY: Loading @@ -841,18 +875,19 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SNK_SELECT_CAPABILITY: ret = pd_send_msg(pd, MSG_REQUEST, &pd->rdo, 1, SOP_MSG); if (ret) if (ret) { usbpd_err(&pd->dev, "Error sending Request\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } /* wait for ACCEPT */ hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), HRTIMER_MODE_REL); kick_sm(pd, SENDER_RESPONSE_TIME); break; case PE_SNK_TRANSITION_SINK: /* wait for PS_RDY */ hrtimer_start(&pd->timer, ms_to_ktime(PS_TRANSITION_TIME), HRTIMER_MODE_REL); kick_sm(pd, PS_TRANSITION_TIME); break; case PE_SNK_READY: Loading @@ -861,6 +896,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) break; case PE_SNK_TRANSITION_TO_DEFAULT: pd->hard_reset = false; if (pd->current_dr != DR_UFP) { extcon_set_cable_state_(pd->extcon, EXTCON_USB_HOST, 0); Loading @@ -877,17 +914,13 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->vconn_enabled = false; } pd->tx_msgid = 0; val.intval = pd->requested_voltage; /* set range back to 5V */ power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &val); pd->current_voltage = pd->requested_voltage; /* max time for hard reset to toggle vbus off/on */ hrtimer_start(&pd->timer, ms_to_ktime(SNK_HARD_RESET_RECOVER_TIME), HRTIMER_MODE_REL); kick_sm(pd, SNK_HARD_RESET_RECOVER_TIME); break; case PE_PRS_SNK_SRC_TRANSITION_TO_OFF: Loading @@ -904,8 +937,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd_phy_update_roles(pd->current_dr, PR_SRC); /* wait for PS_RDY */ hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_OFF), HRTIMER_MODE_REL); kick_sm(pd, PS_SOURCE_OFF); break; default: Loading @@ -929,10 +961,10 @@ int usbpd_register_svid(struct usbpd *pd, struct usbpd_svid_handler *hdlr) /* already connected with this SVID discovered? */ if (pd->vdm_state >= DISCOVERED_SVIDS) { u16 *psvid; int i; for (psvid = pd->discovered_svids; *psvid; psvid++) { if (*psvid == hdlr->svid) { for (i = 0; i < pd->num_svids; i++) { if (pd->discovered_svids[i] == hdlr->svid) { if (hdlr->connect) hdlr->connect(hdlr); break; Loading @@ -954,7 +986,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos) { struct vdm_tx *vdm_tx; if (!pd->in_explicit_contract) if (!pd->in_explicit_contract || pd->vdm_tx) return -EBUSY; vdm_tx = kzalloc(sizeof(*vdm_tx), GFP_KERNEL); Loading @@ -967,8 +999,10 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos) vdm_tx->size = num_vdos + 1; /* include the header */ /* VDM will get sent in PE_SRC/SNK_READY state handling */ list_add_tail(&vdm_tx->entry, &pd->vdm_tx_queue); queue_work(pd->wq, &pd->sm_work); pd->vdm_tx = vdm_tx; /* slight delay before queuing to prioritize handling of incoming VDM */ kick_sm(pd, 5); return 0; } Loading @@ -994,8 +1028,8 @@ static void handle_vdm_rx(struct usbpd *pd) u16 svid = VDM_HDR_SVID(vdm_hdr); u16 *psvid; u8 i, num_vdos = pd->rx_msg_len - 1; /* num objects minus header */ u8 cmd = VDM_HDR_CMD(vdm_hdr); u8 cmd_type = VDM_HDR_CMD_TYPE(vdm_hdr); u8 cmd = SVDM_HDR_CMD(vdm_hdr); u8 cmd_type = SVDM_HDR_CMD_TYPE(vdm_hdr); struct usbpd_svid_handler *handler; usbpd_dbg(&pd->dev, "VDM rx: svid:%x cmd:%x cmd_type:%x vdm_hdr:%x\n", Loading @@ -1005,7 +1039,7 @@ static void handle_vdm_rx(struct usbpd *pd) handler = find_svid_handler(pd, svid); /* Unstructured VDM */ if (!VDM_HDR_TYPE(vdm_hdr)) { if (!VDM_IS_SVDM(vdm_hdr)) { if (handler && handler->vdm_received) handler->vdm_received(handler, vdm_hdr, vdos, num_vdos); return; Loading @@ -1016,7 +1050,19 @@ static void handle_vdm_rx(struct usbpd *pd) switch (cmd_type) { case SVDM_CMD_TYPE_INITIATOR: if (cmd == USBPD_SVDM_DISCOVER_IDENTITY) { /* * if this interrupts a previous exchange, abort the previous * outgoing response */ if (pd->vdm_tx) { usbpd_dbg(&pd->dev, "Discarding previously queued SVDM tx (SVID:0x%04x)\n", VDM_HDR_SVID(pd->vdm_tx->data[0])); kfree(pd->vdm_tx); pd->vdm_tx = NULL; } if (svid == USBPD_SID && cmd == USBPD_SVDM_DISCOVER_IDENTITY) { u32 tx_vdos[3] = { ID_HDR_USB_HOST | ID_HDR_USB_DEVICE | ID_HDR_PRODUCT_PER_MASK | ID_HDR_VID, Loading @@ -1027,9 +1073,9 @@ static void handle_vdm_rx(struct usbpd *pd) usbpd_send_svdm(pd, USBPD_SID, cmd, SVDM_CMD_TYPE_RESP_ACK, 0, tx_vdos, 3); } else { usbpd_send_svdm(pd, USBPD_SID, cmd, SVDM_CMD_TYPE_RESP_NAK, 0, NULL, 0); } else if (cmd != USBPD_SVDM_ATTENTION) { usbpd_send_svdm(pd, svid, cmd, SVDM_CMD_TYPE_RESP_NAK, SVDM_HDR_OBJ_POS(vdm_hdr), NULL, 0); } break; Loading Loading @@ -1061,10 +1107,9 @@ static void handle_vdm_rx(struct usbpd *pd) kfree(pd->vdm_tx_retry); pd->vdm_tx_retry = NULL; kfree(pd->discovered_svids); /* TODO: handle > 12 SVIDs */ pd->discovered_svids = kzalloc((2 * num_vdos + 1) * if (!pd->discovered_svids) { pd->num_svids = 2 * num_vdos; pd->discovered_svids = kcalloc(pd->num_svids, sizeof(u16), GFP_KERNEL); if (!pd->discovered_svids) { Loading @@ -1072,8 +1117,27 @@ static void handle_vdm_rx(struct usbpd *pd) break; } /* convert 32-bit VDOs to list of 16-bit SVIDs */ psvid = pd->discovered_svids; } else { /* handle > 12 SVIDs */ void *ptr; size_t oldsize = pd->num_svids * sizeof(u16); size_t newsize = oldsize + (2 * num_vdos * sizeof(u16)); ptr = krealloc(pd->discovered_svids, newsize, GFP_KERNEL); if (!ptr) { usbpd_err(&pd->dev, "unable to realloc SVIDs\n"); break; } pd->discovered_svids = ptr; psvid = pd->discovered_svids + pd->num_svids; memset(psvid, 0, (2 * num_vdos)); pd->num_svids += 2 * num_vdos; } /* convert 32-bit VDOs to list of 16-bit SVIDs */ for (i = 0; i < num_vdos * 2; i++) { /* * Within each 32-bit VDO, Loading @@ -1097,8 +1161,22 @@ static void handle_vdm_rx(struct usbpd *pd) usbpd_dbg(&pd->dev, "Discovered SVID: 0x%04x\n", svid); *psvid++ = svid; } } /* if SVID supported notify handler */ /* if more than 12 SVIDs, resend the request */ if (num_vdos == 6 && vdos[5] != 0) { usbpd_send_svdm(pd, USBPD_SID, USBPD_SVDM_DISCOVER_SVIDS, SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0); break; } /* now that all SVIDs are discovered, notify handlers */ for (i = 0; i < pd->num_svids; i++) { svid = pd->discovered_svids[i]; if (svid) { handler = find_svid_handler(pd, svid); if (handler && handler->connect) handler->connect(handler); Loading Loading @@ -1148,10 +1226,9 @@ static void handle_vdm_rx(struct usbpd *pd) } /* wait tVDMBusy, then retry */ list_move(&pd->vdm_tx_retry->entry, &pd->vdm_tx_queue); pd->vdm_tx = pd->vdm_tx_retry; pd->vdm_tx_retry = NULL; hrtimer_start(&pd->timer, ms_to_ktime(VDM_BUSY_TIME), HRTIMER_MODE_REL); kick_sm(pd, VDM_BUSY_TIME); break; default: break; Loading @@ -1165,16 +1242,14 @@ static void handle_vdm_tx(struct usbpd *pd) int ret; /* only send one VDM at a time */ if (!list_empty(&pd->vdm_tx_queue)) { struct vdm_tx *vdm_tx = list_first_entry(&pd->vdm_tx_queue, struct vdm_tx, entry); u32 vdm_hdr = vdm_tx->data[0]; if (pd->vdm_tx) { u32 vdm_hdr = pd->vdm_tx->data[0]; ret = pd_send_msg(pd, MSG_VDM, vdm_tx->data, vdm_tx->size, SOP_MSG); ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data, pd->vdm_tx->size, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending VDM command %d\n", VDM_HDR_CMD(vdm_tx->data[0])); SVDM_HDR_CMD(pd->vdm_tx->data[0])); usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_SEND_SOFT_RESET : PE_SNK_SEND_SOFT_RESET); Loading @@ -1183,24 +1258,25 @@ static void handle_vdm_tx(struct usbpd *pd) return; } list_del(&vdm_tx->entry); /* * special case: keep initiated Discover ID/SVIDs * around in case we need to re-try when receiving BUSY */ if (VDM_HDR_TYPE(vdm_hdr) && VDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR && VDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) { if (VDM_IS_SVDM(vdm_hdr) && SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR && SVDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) { if (pd->vdm_tx_retry) { usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", VDM_HDR_CMD(pd->vdm_tx_retry->data[0])); SVDM_HDR_CMD( pd->vdm_tx_retry->data[0])); kfree(pd->vdm_tx_retry); } pd->vdm_tx_retry = vdm_tx; pd->vdm_tx_retry = pd->vdm_tx; } else { kfree(vdm_tx); kfree(pd->vdm_tx); } pd->vdm_tx = NULL; } } Loading @@ -1216,13 +1292,9 @@ static void reset_vdm_state(struct usbpd *pd) pd->vdm_tx_retry = NULL; kfree(pd->discovered_svids); pd->discovered_svids = NULL; while (!list_empty(&pd->vdm_tx_queue)) { struct vdm_tx *vdm_tx = list_first_entry(&pd->vdm_tx_queue, struct vdm_tx, entry); list_del(&vdm_tx->entry); kfree(vdm_tx); } pd->num_svids = 0; kfree(pd->vdm_tx); pd->vdm_tx = NULL; } static void dr_swap(struct usbpd *pd) Loading Loading @@ -1252,6 +1324,34 @@ static void dr_swap(struct usbpd *pd) pd_phy_update_roles(pd->current_dr, pd->current_pr); } static void vconn_swap(struct usbpd *pd) { int ret; if (pd->vconn_enabled) { pd->current_state = PE_VCS_WAIT_FOR_VCONN; kick_sm(pd, VCONN_ON_TIME); } else { ret = regulator_enable(pd->vconn); if (ret) { usbpd_err(&pd->dev, "Unable to enable vconn\n"); return; } pd->vconn_enabled = true; ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending PS_RDY\n"); usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_SEND_SOFT_RESET : PE_SNK_SEND_SOFT_RESET); return; } } } /* Handles current state and determines transitions */ static void usbpd_sm(struct work_struct *w) { Loading @@ -1265,6 +1365,7 @@ static void usbpd_sm(struct work_struct *w) usbpd_state_strings[pd->current_state]); hrtimer_cancel(&pd->timer); pd->sm_queued = false; if (pd->rx_msg_len) data_recvd = pd->rx_msg_type; Loading @@ -1274,7 +1375,7 @@ static void usbpd_sm(struct work_struct *w) /* Disconnect? */ if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) { if (pd->current_state == PE_UNKNOWN) return; goto sm_done; usbpd_info(&pd->dev, "USB PD disconnect\n"); Loading Loading @@ -1328,7 +1429,7 @@ static void usbpd_sm(struct work_struct *w) pd->current_state = PE_UNKNOWN; return; goto sm_done; } /* Hard reset? */ Loading @@ -1339,7 +1440,8 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT); else usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT); pd->hard_reset = false; goto sm_done; } /* Soft reset? */ Loading Loading @@ -1400,8 +1502,7 @@ static void usbpd_sm(struct work_struct *w) break; } hrtimer_start(&pd->timer, ms_to_ktime(SRC_CAP_TIME), HRTIMER_MODE_REL); kick_sm(pd, SRC_CAP_TIME); break; } Loading @@ -1416,14 +1517,16 @@ static void usbpd_sm(struct work_struct *w) /* wait for REQUEST */ pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT; hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), HRTIMER_MODE_REL); kick_sm(pd, SENDER_RESPONSE_TIME); break; case PE_SRC_SEND_CAPABILITIES_WAIT: if (data_recvd == MSG_REQUEST) { pd->rdo = pd->rx_payload[0]; usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY); } else if (data_recvd || ctrl_recvd) { usbpd_err(&pd->dev, "Unexpected message received\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); } else { usbpd_set_state(pd, PE_SRC_HARD_RESET); } Loading @@ -1439,6 +1542,14 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); break; } } else if (ctrl_recvd == MSG_GET_SINK_CAP) { ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES, default_snk_caps, ARRAY_SIZE(default_snk_caps), SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Sink Caps\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); } } else if (data_recvd == MSG_REQUEST) { pd->rdo = pd->rx_payload[0]; usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY); Loading Loading @@ -1470,10 +1581,17 @@ static void usbpd_sm(struct work_struct *w) } pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF; hrtimer_start(&pd->timer, ms_to_ktime(SRC_TRANSITION_TIME), HRTIMER_MODE_REL); kick_sm(pd, SRC_TRANSITION_TIME); break; } else if (ctrl_recvd == MSG_VCONN_SWAP) { ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Accept\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); break; } vconn_swap(pd); } else { if (data_recvd == MSG_VDM) handle_vdm_rx(pd); Loading Loading @@ -1538,6 +1656,9 @@ static void usbpd_sm(struct work_struct *w) else usbpd_set_state(pd, PE_SNK_WAIT_FOR_CAPABILITIES); } else if (pd->rx_msg_type) { usbpd_err(&pd->dev, "Invalid response to sink request\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); } else { /* timed out; go to hard reset */ usbpd_set_state(pd, PE_SNK_HARD_RESET); Loading Loading @@ -1566,9 +1687,9 @@ static void usbpd_sm(struct work_struct *w) break; case PE_SNK_READY: if (data_recvd == MSG_SOURCE_CAPABILITIES) if (data_recvd == MSG_SOURCE_CAPABILITIES) { usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); else if (ctrl_recvd == MSG_GET_SINK_CAP) { } else if (ctrl_recvd == MSG_GET_SINK_CAP) { ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES, default_snk_caps, ARRAY_SIZE(default_snk_caps), SOP_MSG); Loading @@ -1576,6 +1697,15 @@ static void usbpd_sm(struct work_struct *w) usbpd_err(&pd->dev, "Error sending Sink Caps\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); } } else if (ctrl_recvd == MSG_GET_SOURCE_CAP) { ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES, default_src_caps, ARRAY_SIZE(default_src_caps), SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending SRC CAPs\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } } else if (ctrl_recvd == MSG_DR_SWAP) { if (pd->vdm_state == MODE_ENTERED) { usbpd_set_state(pd, PE_SNK_HARD_RESET); Loading Loading @@ -1606,6 +1736,32 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = true; usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF); break; } else if (ctrl_recvd == MSG_VCONN_SWAP) { /* * if VCONN is connected to VBUS, make sure we are * not in high voltage contract, otherwise reject. */ if (!pd->vconn_is_external && (pd->requested_voltage > 5000000)) { ret = pd_send_msg(pd, MSG_REJECT, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Reject\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); } break; } ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Accept\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } vconn_swap(pd); } else { if (data_recvd == MSG_VDM) handle_vdm_rx(pd); Loading @@ -1623,7 +1779,7 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_TYPEC_MODE, &val); if (val.intval == POWER_SUPPLY_TYPEC_NONE) { pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); } } break; Loading Loading @@ -1701,8 +1857,7 @@ static void usbpd_sm(struct work_struct *w) } pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF; hrtimer_start(&pd->timer, ms_to_ktime(SRC_TRANSITION_TIME), HRTIMER_MODE_REL); kick_sm(pd, SRC_TRANSITION_TIME); break; case PE_PRS_SRC_SNK_TRANSITION_TO_OFF: Loading @@ -1727,8 +1882,7 @@ static void usbpd_sm(struct work_struct *w) } pd->current_state = PE_PRS_SRC_SNK_WAIT_SOURCE_ON; hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_ON), HRTIMER_MODE_REL); kick_sm(pd, PS_SOURCE_ON); break; case PE_PRS_SRC_SNK_WAIT_SOURCE_ON: Loading Loading @@ -1778,6 +1932,26 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SRC_STARTUP); break; case PE_VCS_WAIT_FOR_VCONN: if (ctrl_recvd == MSG_PS_RDY) { /* * hopefully redundant check but in case not enabled * avoids unbalanced regulator disable count */ if (pd->vconn_enabled) regulator_disable(pd->vconn); pd->vconn_enabled = false; pd->current_state = pd->current_pr == PR_SRC ? PE_SRC_READY : PE_SNK_READY; } else { /* timed out; go to hard reset */ usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_HARD_RESET : PE_SNK_HARD_RESET); } break; default: usbpd_err(&pd->dev, "Unhandled state %s\n", usbpd_state_strings[pd->current_state]); Loading @@ -1786,6 +1960,10 @@ static void usbpd_sm(struct work_struct *w) /* Rx message should have been consumed now */ pd->rx_msg_type = pd->rx_msg_len = 0; sm_done: if (!pd->sm_queued) pm_relax(&pd->dev); } static inline const char *src_current(enum power_supply_typec_mode typec_mode) Loading Loading @@ -1897,7 +2075,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) switch (typec_mode) { /* Disconnect */ case POWER_SUPPLY_TYPEC_NONE: queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); break; /* Sink states */ Loading @@ -1909,7 +2087,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) if (pd->current_pr != PR_SINK || pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) { pd->current_pr = PR_SINK; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); } break; Loading @@ -1921,7 +2099,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) "" : " (powered)"); if (pd->current_pr != PR_SRC) { pd->current_pr = PR_SRC; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); } break; Loading Loading @@ -2359,6 +2537,10 @@ struct usbpd *usbpd_create(struct device *parent) if (ret) goto free_pd; ret = device_init_wakeup(&pd->dev, true); if (ret) goto free_pd; ret = device_add(&pd->dev); if (ret) goto free_pd; Loading Loading @@ -2414,11 +2596,13 @@ struct usbpd *usbpd_create(struct device *parent) goto unreg_psy; } pd->vconn_is_external = device_property_present(parent, "qcom,vconn-uses-external-source"); pd->current_pr = PR_NONE; pd->current_dr = DR_NONE; list_add_tail(&pd->instance, &_usbpd); INIT_LIST_HEAD(&pd->vdm_tx_queue); INIT_LIST_HEAD(&pd->svid_handlers); /* force read initial power_supply values */ Loading include/linux/power_supply.h +3 −0 Original line number Diff line number Diff line Loading @@ -216,6 +216,9 @@ enum power_supply_property { POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, POWER_SUPPLY_PROP_PD_CURRENT_MAX, POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, POWER_SUPPLY_PROP_PARALLEL_DISABLE, Loading Loading
Documentation/devicetree/bindings/usb/qpnp-pdphy.txt +3 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ Optional properties: - vconn-supply: Regulator that enables VCONN source output. This will be supplied on the USB CC line that is not used for communication when Ra resistance is detected. - qcom,vconn-uses-external-source: Indicates whether VCONN supply is sourced from an external regulator. If omitted, then it is assumed it is connected to VBUS. Example: qcom,qpnp-pdphy@1700 { Loading
drivers/power/power_supply_sysfs.c +3 −0 Original line number Diff line number Diff line Loading @@ -267,6 +267,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(typec_power_role), POWER_SUPPLY_ATTR(pd_allowed), POWER_SUPPLY_ATTR(pd_active), POWER_SUPPLY_ATTR(pd_in_hard_reset), POWER_SUPPLY_ATTR(pd_current_max), POWER_SUPPLY_ATTR(pd_usb_suspend_supported), POWER_SUPPLY_ATTR(charger_temp), POWER_SUPPLY_ATTR(charger_temp_max), POWER_SUPPLY_ATTR(parallel_disable), Loading
drivers/usb/pd/policy_engine.c +291 −107 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ enum usbpd_state { PE_PRS_SRC_SNK_SEND_SWAP, PE_PRS_SRC_SNK_TRANSITION_TO_OFF, PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_VCS_WAIT_FOR_VCONN, }; static const char * const usbpd_state_strings[] = { Loading Loading @@ -94,6 +95,7 @@ static const char * const usbpd_state_strings[] = { "PRS_SRC_SNK_Send_Swap", "PRS_SRC_SNK_Transition_to_off", "PRS_SRC_SNK_Wait_Source_on", "VCS_Wait_for_VCONN", }; enum usbpd_control_msg_type { Loading Loading @@ -170,6 +172,7 @@ static void *usbpd_ipc_log; #define PS_SOURCE_OFF 750 #define SWAP_SOURCE_START_TIME 20 #define VDM_BUSY_TIME 50 #define VCONN_ON_TIME 100 /* tPSHardReset + tSafe0V + tSrcRecover + tSrcTurnOn */ #define SNK_HARD_RESET_RECOVER_TIME (35 + 650 + 1000 + 275) Loading @@ -195,7 +198,7 @@ static void *usbpd_ipc_log; #define PD_RDO_MISMATCH(rdo) ((rdo) >> 26 & 1) #define PD_RDO_USB_COMM(rdo) ((rdo) >> 25 & 1) #define PD_RDO_NO_USB_SUSP(rdo) ((rdo) >> 24 & 1) #define PD_RDO_FIXED_CURR(rdo) ((rdo) >> 19 & 0x3FF) #define PD_RDO_FIXED_CURR(rdo) ((rdo) >> 10 & 0x3FF) #define PD_RDO_FIXED_CURR_MINMAX(rdo) ((rdo) & 0x3FF) #define PD_SRC_PDO_TYPE(pdo) (((pdo) >> 30) & 3) Loading Loading @@ -223,9 +226,10 @@ static void *usbpd_ipc_log; /* VDM header is the first 32-bit object following the 16-bit PD header */ #define VDM_HDR_SVID(hdr) ((hdr) >> 16) #define VDM_HDR_TYPE(hdr) ((hdr) & 0x8000) #define VDM_HDR_CMD_TYPE(hdr) (((hdr) >> 6) & 0x3) #define VDM_HDR_CMD(hdr) ((hdr) & 0x1f) #define VDM_IS_SVDM(hdr) ((hdr) & 0x8000) #define SVDM_HDR_OBJ_POS(hdr) (((hdr) >> 8) & 0x7) #define SVDM_HDR_CMD_TYPE(hdr) (((hdr) >> 6) & 0x3) #define SVDM_HDR_CMD(hdr) ((hdr) & 0x1f) #define SVDM_HDR(svid, ver, obj, cmd_type, cmd) \ (((svid) << 16) | (1 << 15) | ((ver) << 13) \ Loading Loading @@ -253,15 +257,11 @@ static bool ss_dev = true; module_param(ss_dev, bool, S_IRUSR | S_IWUSR); static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */ static const u32 default_snk_caps[] = { 0x2601905A, /* 5V @ 900mA */ 0x0002D096, /* 9V @ 1.5A */ 0x0003C064 }; /* 12V @ 1A */ static const u32 default_snk_caps[] = { 0x2601905A }; /* 5V @ 900mA */ struct vdm_tx { u32 data[7]; int size; struct list_head entry; }; struct usbpd { Loading @@ -269,6 +269,7 @@ struct usbpd { struct workqueue_struct *wq; struct work_struct sm_work; struct hrtimer timer; bool sm_queued; struct extcon_dev *extcon; Loading Loading @@ -307,6 +308,7 @@ struct usbpd { struct regulator *vbus; struct regulator *vconn; bool vconn_enabled; bool vconn_is_external; u8 tx_msgid; u8 rx_msgid; Loading @@ -315,8 +317,9 @@ struct usbpd { enum vdm_state vdm_state; u16 *discovered_svids; int num_svids; struct vdm_tx *vdm_tx; struct vdm_tx *vdm_tx_retry; struct list_head vdm_tx_queue; struct list_head svid_handlers; struct list_head instance; Loading Loading @@ -440,6 +443,12 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos) } pd->requested_voltage = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000; /* Can't sink more than 5V if VCONN is sourced from the VBUS input */ if (pd->vconn_enabled && !pd->vconn_is_external && pd->requested_voltage > 5000000) return -ENOTSUPP; pd->requested_current = curr; pd->requested_pdo = pdo_pos; pd->rdo = PD_RDO_FIXED(pdo_pos, 0, mismatch, 1, 1, curr / 10, Loading Loading @@ -485,6 +494,17 @@ static void pd_send_hard_reset(struct usbpd *pd) pd->hard_reset = true; } static void kick_sm(struct usbpd *pd, int ms) { pm_stay_awake(&pd->dev); pd->sm_queued = true; if (ms) hrtimer_start(&pd->timer, ms_to_ktime(ms), HRTIMER_MODE_REL); else queue_work(pd->wq, &pd->sm_work); } static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) { if (type != HARD_RESET_SIG) { Loading @@ -497,7 +517,7 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) /* Force CC logic to source/sink to keep Rp/Rd unchanged */ set_power_role(pd, pd->current_pr); pd->hard_reset = true; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); } static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, Loading Loading @@ -534,6 +554,10 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, pd->rx_msgid = PD_MSG_HDR_ID(header); /* discard Pings */ if (PD_MSG_HDR_TYPE(header) == MSG_PING && !len) return; /* check header's count field to see if it matches len */ if (PD_MSG_HDR_COUNT(header) != (len / 4)) { usbpd_err(&pd->dev, "header count (%d) mismatch, len=%ld\n", Loading @@ -541,11 +565,18 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, return; } /* block until previous message has been consumed by usbpd_sm */ if (pd->rx_msg_type) flush_work(&pd->sm_work); pd->rx_msg_type = PD_MSG_HDR_TYPE(header); pd->rx_msg_len = PD_MSG_HDR_COUNT(header); memcpy(&pd->rx_payload, buf, len); queue_work(pd->wq, &pd->sm_work); usbpd_dbg(&pd->dev, "received message: type(%d) len(%d)\n", pd->rx_msg_type, pd->rx_msg_len); kick_sm(pd, 0); } static void phy_shutdown(struct usbpd *pd) Loading Loading @@ -587,7 +618,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->in_pr_swap = false; set_power_role(pd, PR_NONE); pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); break; /* Source states */ Loading Loading @@ -634,20 +665,22 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->current_state = PE_SRC_SEND_CAPABILITIES; if (pd->in_pr_swap) { pd->in_pr_swap = false; hrtimer_start(&pd->timer, ms_to_ktime(SWAP_SOURCE_START_TIME), HRTIMER_MODE_REL); kick_sm(pd, SWAP_SOURCE_START_TIME); break; } /* fall-through */ case PE_SRC_SEND_CAPABILITIES: queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); break; case PE_SRC_NEGOTIATE_CAPABILITY: if (PD_RDO_OBJ_POS(pd->rdo) != 1) { if (PD_RDO_OBJ_POS(pd->rdo) != 1 || PD_RDO_FIXED_CURR(pd->rdo) > PD_SRC_PDO_FIXED_MAX_CURR(*default_src_caps) || PD_RDO_FIXED_CURR_MINMAX(pd->rdo) > PD_SRC_PDO_FIXED_MAX_CURR(*default_src_caps)) { /* send Reject */ ret = pd_send_msg(pd, MSG_REJECT, NULL, 0, SOP_MSG); if (ret) { Loading Loading @@ -717,6 +750,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) break; case PE_SRC_TRANSITION_TO_DEFAULT: pd->hard_reset = false; if (pd->vconn_enabled) regulator_disable(pd->vconn); regulator_disable(pd->vbus); Loading Loading @@ -747,7 +782,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SRC_HARD_RESET: case PE_SNK_HARD_RESET: /* hard reset may sleep; handle it in the workqueue */ queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); break; case PE_SRC_SEND_SOFT_RESET: Loading @@ -765,8 +800,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } /* wait for ACCEPT */ hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), HRTIMER_MODE_REL); kick_sm(pd, SENDER_RESPONSE_TIME); break; /* Sink states */ Loading @@ -786,9 +820,11 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) } } /* Reset protocol layer */ pd->tx_msgid = 0; pd->rx_msgid = -1; pd->rx_msg_len = 0; pd->rx_msg_type = 0; pd->rx_msgid = -1; if (!pd->in_pr_swap) { if (pd->pd_phy_opened) { Loading Loading @@ -819,11 +855,9 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SNK_WAIT_FOR_CAPABILITIES: if (pd->rx_msg_len && pd->rx_msg_type) queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); else hrtimer_start(&pd->timer, ms_to_ktime(SINK_WAIT_CAP_TIME), HRTIMER_MODE_REL); kick_sm(pd, SINK_WAIT_CAP_TIME); break; case PE_SNK_EVALUATE_CAPABILITY: Loading @@ -841,18 +875,19 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SNK_SELECT_CAPABILITY: ret = pd_send_msg(pd, MSG_REQUEST, &pd->rdo, 1, SOP_MSG); if (ret) if (ret) { usbpd_err(&pd->dev, "Error sending Request\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } /* wait for ACCEPT */ hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), HRTIMER_MODE_REL); kick_sm(pd, SENDER_RESPONSE_TIME); break; case PE_SNK_TRANSITION_SINK: /* wait for PS_RDY */ hrtimer_start(&pd->timer, ms_to_ktime(PS_TRANSITION_TIME), HRTIMER_MODE_REL); kick_sm(pd, PS_TRANSITION_TIME); break; case PE_SNK_READY: Loading @@ -861,6 +896,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) break; case PE_SNK_TRANSITION_TO_DEFAULT: pd->hard_reset = false; if (pd->current_dr != DR_UFP) { extcon_set_cable_state_(pd->extcon, EXTCON_USB_HOST, 0); Loading @@ -877,17 +914,13 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->vconn_enabled = false; } pd->tx_msgid = 0; val.intval = pd->requested_voltage; /* set range back to 5V */ power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &val); pd->current_voltage = pd->requested_voltage; /* max time for hard reset to toggle vbus off/on */ hrtimer_start(&pd->timer, ms_to_ktime(SNK_HARD_RESET_RECOVER_TIME), HRTIMER_MODE_REL); kick_sm(pd, SNK_HARD_RESET_RECOVER_TIME); break; case PE_PRS_SNK_SRC_TRANSITION_TO_OFF: Loading @@ -904,8 +937,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd_phy_update_roles(pd->current_dr, PR_SRC); /* wait for PS_RDY */ hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_OFF), HRTIMER_MODE_REL); kick_sm(pd, PS_SOURCE_OFF); break; default: Loading @@ -929,10 +961,10 @@ int usbpd_register_svid(struct usbpd *pd, struct usbpd_svid_handler *hdlr) /* already connected with this SVID discovered? */ if (pd->vdm_state >= DISCOVERED_SVIDS) { u16 *psvid; int i; for (psvid = pd->discovered_svids; *psvid; psvid++) { if (*psvid == hdlr->svid) { for (i = 0; i < pd->num_svids; i++) { if (pd->discovered_svids[i] == hdlr->svid) { if (hdlr->connect) hdlr->connect(hdlr); break; Loading @@ -954,7 +986,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos) { struct vdm_tx *vdm_tx; if (!pd->in_explicit_contract) if (!pd->in_explicit_contract || pd->vdm_tx) return -EBUSY; vdm_tx = kzalloc(sizeof(*vdm_tx), GFP_KERNEL); Loading @@ -967,8 +999,10 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos) vdm_tx->size = num_vdos + 1; /* include the header */ /* VDM will get sent in PE_SRC/SNK_READY state handling */ list_add_tail(&vdm_tx->entry, &pd->vdm_tx_queue); queue_work(pd->wq, &pd->sm_work); pd->vdm_tx = vdm_tx; /* slight delay before queuing to prioritize handling of incoming VDM */ kick_sm(pd, 5); return 0; } Loading @@ -994,8 +1028,8 @@ static void handle_vdm_rx(struct usbpd *pd) u16 svid = VDM_HDR_SVID(vdm_hdr); u16 *psvid; u8 i, num_vdos = pd->rx_msg_len - 1; /* num objects minus header */ u8 cmd = VDM_HDR_CMD(vdm_hdr); u8 cmd_type = VDM_HDR_CMD_TYPE(vdm_hdr); u8 cmd = SVDM_HDR_CMD(vdm_hdr); u8 cmd_type = SVDM_HDR_CMD_TYPE(vdm_hdr); struct usbpd_svid_handler *handler; usbpd_dbg(&pd->dev, "VDM rx: svid:%x cmd:%x cmd_type:%x vdm_hdr:%x\n", Loading @@ -1005,7 +1039,7 @@ static void handle_vdm_rx(struct usbpd *pd) handler = find_svid_handler(pd, svid); /* Unstructured VDM */ if (!VDM_HDR_TYPE(vdm_hdr)) { if (!VDM_IS_SVDM(vdm_hdr)) { if (handler && handler->vdm_received) handler->vdm_received(handler, vdm_hdr, vdos, num_vdos); return; Loading @@ -1016,7 +1050,19 @@ static void handle_vdm_rx(struct usbpd *pd) switch (cmd_type) { case SVDM_CMD_TYPE_INITIATOR: if (cmd == USBPD_SVDM_DISCOVER_IDENTITY) { /* * if this interrupts a previous exchange, abort the previous * outgoing response */ if (pd->vdm_tx) { usbpd_dbg(&pd->dev, "Discarding previously queued SVDM tx (SVID:0x%04x)\n", VDM_HDR_SVID(pd->vdm_tx->data[0])); kfree(pd->vdm_tx); pd->vdm_tx = NULL; } if (svid == USBPD_SID && cmd == USBPD_SVDM_DISCOVER_IDENTITY) { u32 tx_vdos[3] = { ID_HDR_USB_HOST | ID_HDR_USB_DEVICE | ID_HDR_PRODUCT_PER_MASK | ID_HDR_VID, Loading @@ -1027,9 +1073,9 @@ static void handle_vdm_rx(struct usbpd *pd) usbpd_send_svdm(pd, USBPD_SID, cmd, SVDM_CMD_TYPE_RESP_ACK, 0, tx_vdos, 3); } else { usbpd_send_svdm(pd, USBPD_SID, cmd, SVDM_CMD_TYPE_RESP_NAK, 0, NULL, 0); } else if (cmd != USBPD_SVDM_ATTENTION) { usbpd_send_svdm(pd, svid, cmd, SVDM_CMD_TYPE_RESP_NAK, SVDM_HDR_OBJ_POS(vdm_hdr), NULL, 0); } break; Loading Loading @@ -1061,10 +1107,9 @@ static void handle_vdm_rx(struct usbpd *pd) kfree(pd->vdm_tx_retry); pd->vdm_tx_retry = NULL; kfree(pd->discovered_svids); /* TODO: handle > 12 SVIDs */ pd->discovered_svids = kzalloc((2 * num_vdos + 1) * if (!pd->discovered_svids) { pd->num_svids = 2 * num_vdos; pd->discovered_svids = kcalloc(pd->num_svids, sizeof(u16), GFP_KERNEL); if (!pd->discovered_svids) { Loading @@ -1072,8 +1117,27 @@ static void handle_vdm_rx(struct usbpd *pd) break; } /* convert 32-bit VDOs to list of 16-bit SVIDs */ psvid = pd->discovered_svids; } else { /* handle > 12 SVIDs */ void *ptr; size_t oldsize = pd->num_svids * sizeof(u16); size_t newsize = oldsize + (2 * num_vdos * sizeof(u16)); ptr = krealloc(pd->discovered_svids, newsize, GFP_KERNEL); if (!ptr) { usbpd_err(&pd->dev, "unable to realloc SVIDs\n"); break; } pd->discovered_svids = ptr; psvid = pd->discovered_svids + pd->num_svids; memset(psvid, 0, (2 * num_vdos)); pd->num_svids += 2 * num_vdos; } /* convert 32-bit VDOs to list of 16-bit SVIDs */ for (i = 0; i < num_vdos * 2; i++) { /* * Within each 32-bit VDO, Loading @@ -1097,8 +1161,22 @@ static void handle_vdm_rx(struct usbpd *pd) usbpd_dbg(&pd->dev, "Discovered SVID: 0x%04x\n", svid); *psvid++ = svid; } } /* if SVID supported notify handler */ /* if more than 12 SVIDs, resend the request */ if (num_vdos == 6 && vdos[5] != 0) { usbpd_send_svdm(pd, USBPD_SID, USBPD_SVDM_DISCOVER_SVIDS, SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0); break; } /* now that all SVIDs are discovered, notify handlers */ for (i = 0; i < pd->num_svids; i++) { svid = pd->discovered_svids[i]; if (svid) { handler = find_svid_handler(pd, svid); if (handler && handler->connect) handler->connect(handler); Loading Loading @@ -1148,10 +1226,9 @@ static void handle_vdm_rx(struct usbpd *pd) } /* wait tVDMBusy, then retry */ list_move(&pd->vdm_tx_retry->entry, &pd->vdm_tx_queue); pd->vdm_tx = pd->vdm_tx_retry; pd->vdm_tx_retry = NULL; hrtimer_start(&pd->timer, ms_to_ktime(VDM_BUSY_TIME), HRTIMER_MODE_REL); kick_sm(pd, VDM_BUSY_TIME); break; default: break; Loading @@ -1165,16 +1242,14 @@ static void handle_vdm_tx(struct usbpd *pd) int ret; /* only send one VDM at a time */ if (!list_empty(&pd->vdm_tx_queue)) { struct vdm_tx *vdm_tx = list_first_entry(&pd->vdm_tx_queue, struct vdm_tx, entry); u32 vdm_hdr = vdm_tx->data[0]; if (pd->vdm_tx) { u32 vdm_hdr = pd->vdm_tx->data[0]; ret = pd_send_msg(pd, MSG_VDM, vdm_tx->data, vdm_tx->size, SOP_MSG); ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data, pd->vdm_tx->size, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending VDM command %d\n", VDM_HDR_CMD(vdm_tx->data[0])); SVDM_HDR_CMD(pd->vdm_tx->data[0])); usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_SEND_SOFT_RESET : PE_SNK_SEND_SOFT_RESET); Loading @@ -1183,24 +1258,25 @@ static void handle_vdm_tx(struct usbpd *pd) return; } list_del(&vdm_tx->entry); /* * special case: keep initiated Discover ID/SVIDs * around in case we need to re-try when receiving BUSY */ if (VDM_HDR_TYPE(vdm_hdr) && VDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR && VDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) { if (VDM_IS_SVDM(vdm_hdr) && SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR && SVDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) { if (pd->vdm_tx_retry) { usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", VDM_HDR_CMD(pd->vdm_tx_retry->data[0])); SVDM_HDR_CMD( pd->vdm_tx_retry->data[0])); kfree(pd->vdm_tx_retry); } pd->vdm_tx_retry = vdm_tx; pd->vdm_tx_retry = pd->vdm_tx; } else { kfree(vdm_tx); kfree(pd->vdm_tx); } pd->vdm_tx = NULL; } } Loading @@ -1216,13 +1292,9 @@ static void reset_vdm_state(struct usbpd *pd) pd->vdm_tx_retry = NULL; kfree(pd->discovered_svids); pd->discovered_svids = NULL; while (!list_empty(&pd->vdm_tx_queue)) { struct vdm_tx *vdm_tx = list_first_entry(&pd->vdm_tx_queue, struct vdm_tx, entry); list_del(&vdm_tx->entry); kfree(vdm_tx); } pd->num_svids = 0; kfree(pd->vdm_tx); pd->vdm_tx = NULL; } static void dr_swap(struct usbpd *pd) Loading Loading @@ -1252,6 +1324,34 @@ static void dr_swap(struct usbpd *pd) pd_phy_update_roles(pd->current_dr, pd->current_pr); } static void vconn_swap(struct usbpd *pd) { int ret; if (pd->vconn_enabled) { pd->current_state = PE_VCS_WAIT_FOR_VCONN; kick_sm(pd, VCONN_ON_TIME); } else { ret = regulator_enable(pd->vconn); if (ret) { usbpd_err(&pd->dev, "Unable to enable vconn\n"); return; } pd->vconn_enabled = true; ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending PS_RDY\n"); usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_SEND_SOFT_RESET : PE_SNK_SEND_SOFT_RESET); return; } } } /* Handles current state and determines transitions */ static void usbpd_sm(struct work_struct *w) { Loading @@ -1265,6 +1365,7 @@ static void usbpd_sm(struct work_struct *w) usbpd_state_strings[pd->current_state]); hrtimer_cancel(&pd->timer); pd->sm_queued = false; if (pd->rx_msg_len) data_recvd = pd->rx_msg_type; Loading @@ -1274,7 +1375,7 @@ static void usbpd_sm(struct work_struct *w) /* Disconnect? */ if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) { if (pd->current_state == PE_UNKNOWN) return; goto sm_done; usbpd_info(&pd->dev, "USB PD disconnect\n"); Loading Loading @@ -1328,7 +1429,7 @@ static void usbpd_sm(struct work_struct *w) pd->current_state = PE_UNKNOWN; return; goto sm_done; } /* Hard reset? */ Loading @@ -1339,7 +1440,8 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT); else usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT); pd->hard_reset = false; goto sm_done; } /* Soft reset? */ Loading Loading @@ -1400,8 +1502,7 @@ static void usbpd_sm(struct work_struct *w) break; } hrtimer_start(&pd->timer, ms_to_ktime(SRC_CAP_TIME), HRTIMER_MODE_REL); kick_sm(pd, SRC_CAP_TIME); break; } Loading @@ -1416,14 +1517,16 @@ static void usbpd_sm(struct work_struct *w) /* wait for REQUEST */ pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT; hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), HRTIMER_MODE_REL); kick_sm(pd, SENDER_RESPONSE_TIME); break; case PE_SRC_SEND_CAPABILITIES_WAIT: if (data_recvd == MSG_REQUEST) { pd->rdo = pd->rx_payload[0]; usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY); } else if (data_recvd || ctrl_recvd) { usbpd_err(&pd->dev, "Unexpected message received\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); } else { usbpd_set_state(pd, PE_SRC_HARD_RESET); } Loading @@ -1439,6 +1542,14 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); break; } } else if (ctrl_recvd == MSG_GET_SINK_CAP) { ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES, default_snk_caps, ARRAY_SIZE(default_snk_caps), SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Sink Caps\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); } } else if (data_recvd == MSG_REQUEST) { pd->rdo = pd->rx_payload[0]; usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY); Loading Loading @@ -1470,10 +1581,17 @@ static void usbpd_sm(struct work_struct *w) } pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF; hrtimer_start(&pd->timer, ms_to_ktime(SRC_TRANSITION_TIME), HRTIMER_MODE_REL); kick_sm(pd, SRC_TRANSITION_TIME); break; } else if (ctrl_recvd == MSG_VCONN_SWAP) { ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Accept\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); break; } vconn_swap(pd); } else { if (data_recvd == MSG_VDM) handle_vdm_rx(pd); Loading Loading @@ -1538,6 +1656,9 @@ static void usbpd_sm(struct work_struct *w) else usbpd_set_state(pd, PE_SNK_WAIT_FOR_CAPABILITIES); } else if (pd->rx_msg_type) { usbpd_err(&pd->dev, "Invalid response to sink request\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); } else { /* timed out; go to hard reset */ usbpd_set_state(pd, PE_SNK_HARD_RESET); Loading Loading @@ -1566,9 +1687,9 @@ static void usbpd_sm(struct work_struct *w) break; case PE_SNK_READY: if (data_recvd == MSG_SOURCE_CAPABILITIES) if (data_recvd == MSG_SOURCE_CAPABILITIES) { usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); else if (ctrl_recvd == MSG_GET_SINK_CAP) { } else if (ctrl_recvd == MSG_GET_SINK_CAP) { ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES, default_snk_caps, ARRAY_SIZE(default_snk_caps), SOP_MSG); Loading @@ -1576,6 +1697,15 @@ static void usbpd_sm(struct work_struct *w) usbpd_err(&pd->dev, "Error sending Sink Caps\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); } } else if (ctrl_recvd == MSG_GET_SOURCE_CAP) { ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES, default_src_caps, ARRAY_SIZE(default_src_caps), SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending SRC CAPs\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } } else if (ctrl_recvd == MSG_DR_SWAP) { if (pd->vdm_state == MODE_ENTERED) { usbpd_set_state(pd, PE_SNK_HARD_RESET); Loading Loading @@ -1606,6 +1736,32 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = true; usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF); break; } else if (ctrl_recvd == MSG_VCONN_SWAP) { /* * if VCONN is connected to VBUS, make sure we are * not in high voltage contract, otherwise reject. */ if (!pd->vconn_is_external && (pd->requested_voltage > 5000000)) { ret = pd_send_msg(pd, MSG_REJECT, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Reject\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); } break; } ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Accept\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } vconn_swap(pd); } else { if (data_recvd == MSG_VDM) handle_vdm_rx(pd); Loading @@ -1623,7 +1779,7 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_TYPEC_MODE, &val); if (val.intval == POWER_SUPPLY_TYPEC_NONE) { pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); } } break; Loading Loading @@ -1701,8 +1857,7 @@ static void usbpd_sm(struct work_struct *w) } pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF; hrtimer_start(&pd->timer, ms_to_ktime(SRC_TRANSITION_TIME), HRTIMER_MODE_REL); kick_sm(pd, SRC_TRANSITION_TIME); break; case PE_PRS_SRC_SNK_TRANSITION_TO_OFF: Loading @@ -1727,8 +1882,7 @@ static void usbpd_sm(struct work_struct *w) } pd->current_state = PE_PRS_SRC_SNK_WAIT_SOURCE_ON; hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_ON), HRTIMER_MODE_REL); kick_sm(pd, PS_SOURCE_ON); break; case PE_PRS_SRC_SNK_WAIT_SOURCE_ON: Loading Loading @@ -1778,6 +1932,26 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SRC_STARTUP); break; case PE_VCS_WAIT_FOR_VCONN: if (ctrl_recvd == MSG_PS_RDY) { /* * hopefully redundant check but in case not enabled * avoids unbalanced regulator disable count */ if (pd->vconn_enabled) regulator_disable(pd->vconn); pd->vconn_enabled = false; pd->current_state = pd->current_pr == PR_SRC ? PE_SRC_READY : PE_SNK_READY; } else { /* timed out; go to hard reset */ usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_HARD_RESET : PE_SNK_HARD_RESET); } break; default: usbpd_err(&pd->dev, "Unhandled state %s\n", usbpd_state_strings[pd->current_state]); Loading @@ -1786,6 +1960,10 @@ static void usbpd_sm(struct work_struct *w) /* Rx message should have been consumed now */ pd->rx_msg_type = pd->rx_msg_len = 0; sm_done: if (!pd->sm_queued) pm_relax(&pd->dev); } static inline const char *src_current(enum power_supply_typec_mode typec_mode) Loading Loading @@ -1897,7 +2075,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) switch (typec_mode) { /* Disconnect */ case POWER_SUPPLY_TYPEC_NONE: queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); break; /* Sink states */ Loading @@ -1909,7 +2087,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) if (pd->current_pr != PR_SINK || pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) { pd->current_pr = PR_SINK; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); } break; Loading @@ -1921,7 +2099,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) "" : " (powered)"); if (pd->current_pr != PR_SRC) { pd->current_pr = PR_SRC; queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0); } break; Loading Loading @@ -2359,6 +2537,10 @@ struct usbpd *usbpd_create(struct device *parent) if (ret) goto free_pd; ret = device_init_wakeup(&pd->dev, true); if (ret) goto free_pd; ret = device_add(&pd->dev); if (ret) goto free_pd; Loading Loading @@ -2414,11 +2596,13 @@ struct usbpd *usbpd_create(struct device *parent) goto unreg_psy; } pd->vconn_is_external = device_property_present(parent, "qcom,vconn-uses-external-source"); pd->current_pr = PR_NONE; pd->current_dr = DR_NONE; list_add_tail(&pd->instance, &_usbpd); INIT_LIST_HEAD(&pd->vdm_tx_queue); INIT_LIST_HEAD(&pd->svid_handlers); /* force read initial power_supply values */ Loading
include/linux/power_supply.h +3 −0 Original line number Diff line number Diff line Loading @@ -216,6 +216,9 @@ enum power_supply_property { POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, POWER_SUPPLY_PROP_PD_CURRENT_MAX, POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, POWER_SUPPLY_PROP_PARALLEL_DISABLE, Loading