Loading drivers/usb/pd/policy_engine.c +45 −0 Original line number Diff line number Diff line Loading @@ -377,6 +377,8 @@ struct usbpd { struct list_head svid_handlers; struct list_head instance; u16 ss_lane_svid; }; static LIST_HEAD(_usbpd); /* useful for debugging */ Loading Loading @@ -445,6 +447,47 @@ static inline void start_usb_peripheral(struct usbpd *pd) extcon_set_state_sync(pd->extcon, EXTCON_USB, 1); } /** * This API allows client driver to request for releasing SS lanes. It should * not be called from atomic context. * * @pd - USBPD handler * @hdlr - client's handler * * @returns int - Success - 0, else negative error code */ static int usbpd_release_ss_lane(struct usbpd *pd, struct usbpd_svid_handler *hdlr) { int ret = 0; if (!hdlr || !pd) return -EINVAL; usbpd_dbg(&pd->dev, "hdlr:%pK svid:%d", hdlr, hdlr->svid); /* * If USB SS lanes are already used by one client, and other client is * requesting for same or same client requesting again, return -EBUSY. */ if (pd->ss_lane_svid) { usbpd_dbg(&pd->dev, "-EBUSY: ss_lanes are already used by(%d)", pd->ss_lane_svid); ret = -EBUSY; goto err_exit; } ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); if (ret) { usbpd_err(&pd->dev, "err(%d) for releasing ss lane", ret); goto err_exit; } pd->ss_lane_svid = hdlr->svid; err_exit: return ret; } static int set_power_role(struct usbpd *pd, enum power_role pr) { union power_supply_propval val = {0}; Loading Loading @@ -764,6 +807,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) if (pd->current_dr == DR_NONE) { pd->current_dr = DR_DFP; start_usb_host(pd, true); pd->ss_lane_svid = 0x0; } dual_role_instance_changed(pd->dual_role); Loading Loading @@ -1084,6 +1128,7 @@ int usbpd_register_svid(struct usbpd *pd, struct usbpd_svid_handler *hdlr) usbpd_dbg(&pd->dev, "registered handler for SVID 0x%04x\n", hdlr->svid); list_add_tail(&hdlr->entry, &pd->svid_handlers); hdlr->request_usb_ss_lane = usbpd_release_ss_lane; /* already connected with this SVID discovered? */ if (pd->vdm_state >= DISCOVERED_SVIDS) { Loading include/linux/usb/usbpd.h +5 −1 Original line number Diff line number Diff line /* 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 Loading Loading @@ -46,6 +46,10 @@ struct usbpd_svid_handler { void (*connect)(struct usbpd_svid_handler *hdlr); void (*disconnect)(struct usbpd_svid_handler *hdlr); /* DP driver -> PE driver for requesting USB SS lanes */ int (*request_usb_ss_lane)(struct usbpd *pd, struct usbpd_svid_handler *hdlr); /* Unstructured VDM */ void (*vdm_received)(struct usbpd_svid_handler *hdlr, u32 vdm_hdr, const u32 *vdos, int num_vdos); Loading Loading
drivers/usb/pd/policy_engine.c +45 −0 Original line number Diff line number Diff line Loading @@ -377,6 +377,8 @@ struct usbpd { struct list_head svid_handlers; struct list_head instance; u16 ss_lane_svid; }; static LIST_HEAD(_usbpd); /* useful for debugging */ Loading Loading @@ -445,6 +447,47 @@ static inline void start_usb_peripheral(struct usbpd *pd) extcon_set_state_sync(pd->extcon, EXTCON_USB, 1); } /** * This API allows client driver to request for releasing SS lanes. It should * not be called from atomic context. * * @pd - USBPD handler * @hdlr - client's handler * * @returns int - Success - 0, else negative error code */ static int usbpd_release_ss_lane(struct usbpd *pd, struct usbpd_svid_handler *hdlr) { int ret = 0; if (!hdlr || !pd) return -EINVAL; usbpd_dbg(&pd->dev, "hdlr:%pK svid:%d", hdlr, hdlr->svid); /* * If USB SS lanes are already used by one client, and other client is * requesting for same or same client requesting again, return -EBUSY. */ if (pd->ss_lane_svid) { usbpd_dbg(&pd->dev, "-EBUSY: ss_lanes are already used by(%d)", pd->ss_lane_svid); ret = -EBUSY; goto err_exit; } ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); if (ret) { usbpd_err(&pd->dev, "err(%d) for releasing ss lane", ret); goto err_exit; } pd->ss_lane_svid = hdlr->svid; err_exit: return ret; } static int set_power_role(struct usbpd *pd, enum power_role pr) { union power_supply_propval val = {0}; Loading Loading @@ -764,6 +807,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) if (pd->current_dr == DR_NONE) { pd->current_dr = DR_DFP; start_usb_host(pd, true); pd->ss_lane_svid = 0x0; } dual_role_instance_changed(pd->dual_role); Loading Loading @@ -1084,6 +1128,7 @@ int usbpd_register_svid(struct usbpd *pd, struct usbpd_svid_handler *hdlr) usbpd_dbg(&pd->dev, "registered handler for SVID 0x%04x\n", hdlr->svid); list_add_tail(&hdlr->entry, &pd->svid_handlers); hdlr->request_usb_ss_lane = usbpd_release_ss_lane; /* already connected with this SVID discovered? */ if (pd->vdm_state >= DISCOVERED_SVIDS) { Loading
include/linux/usb/usbpd.h +5 −1 Original line number Diff line number Diff line /* 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 Loading Loading @@ -46,6 +46,10 @@ struct usbpd_svid_handler { void (*connect)(struct usbpd_svid_handler *hdlr); void (*disconnect)(struct usbpd_svid_handler *hdlr); /* DP driver -> PE driver for requesting USB SS lanes */ int (*request_usb_ss_lane)(struct usbpd *pd, struct usbpd_svid_handler *hdlr); /* Unstructured VDM */ void (*vdm_received)(struct usbpd_svid_handler *hdlr, u32 vdm_hdr, const u32 *vdos, int num_vdos); Loading