Loading drivers/usb/dwc3/dwc3-msm.c +94 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include <linux/extcon.h> #include <linux/reset.h> #include <linux/usb/dwc3-msm.h> #include <linux/usb/role.h> #include "core.h" #include "gadget.h" Loading Loading @@ -362,6 +363,12 @@ static const char * const gsi_op_strings[] = { "FREE_TRBS", "SET_CLR_BLOCK_DBL", "CHECK_FOR_SUSP", "EP_DISABLE" }; static const char * const usb_role_strings[] = { "NONE", "HOST", "DEVICE" }; struct dwc3_msm; struct extcon_nb { Loading Loading @@ -471,6 +478,8 @@ struct dwc3_msm { u64 dummy_gsi_db; dma_addr_t dummy_gsi_db_dma; struct usb_role_switch *role_switch; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ Loading Loading @@ -3551,6 +3560,79 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc) return 0; } static inline const char *usb_role_string(enum usb_role role) { if (role < ARRAY_SIZE(usb_role_strings)) return usb_role_strings[role]; return "Invalid"; } static enum usb_role dwc3_msm_usb_get_role(struct device *dev) { struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); enum usb_role role; if (mdwc->vbus_active) role = USB_ROLE_DEVICE; else if (mdwc->id_state == DWC3_ID_GROUND) role = USB_ROLE_HOST; else role = USB_ROLE_NONE; dbg_log_string("get_role:%s\n", usb_role_string(role)); return role; } static int dwc3_msm_usb_set_role(struct device *dev, enum usb_role role) { struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); enum usb_role cur_role = USB_ROLE_NONE; cur_role = dwc3_msm_usb_get_role(dev); switch (role) { case USB_ROLE_HOST: mdwc->vbus_active = false; mdwc->id_state = DWC3_ID_GROUND; break; case USB_ROLE_DEVICE: mdwc->vbus_active = true; mdwc->id_state = DWC3_ID_FLOAT; break; case USB_ROLE_NONE: mdwc->vbus_active = false; mdwc->id_state = DWC3_ID_FLOAT; break; } dbg_log_string("cur_role:%s new_role:%s\n", usb_role_string(cur_role), usb_role_string(role)); /* * For boot up without USB cable connected case, don't check * previous role value to allow resetting USB controller and * PHYs. */ if (mdwc->drd_state != DRD_STATE_UNDEFINED && cur_role == role) { dbg_log_string("no USB role change"); return 0; } dwc3_ext_event_notify(mdwc); return 0; } static struct usb_role_switch_desc role_desc = { .set = dwc3_msm_usb_set_role, .get = dwc3_msm_usb_get_role, .allow_userspace_control = true, }; static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { Loading Loading @@ -4112,7 +4194,17 @@ static int dwc3_msm_probe(struct platform_device *pdev) } else { queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); } } else { } if (of_property_read_bool(node, "usb-role-switch")) { role_desc.fwnode = dev_fwnode(&pdev->dev); mdwc->role_switch = usb_role_switch_register(mdwc->dev, &role_desc); if (IS_ERR(mdwc->role_switch)) return PTR_ERR(mdwc->role_switch); } if (!mdwc->role_switch && !mdwc->extcon) { switch (dwc->dr_mode) { case USB_DR_MODE_OTG: if (of_property_read_bool(node, Loading Loading @@ -4168,6 +4260,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); int i, ret_pm; usb_role_switch_unregister(mdwc->role_switch); device_remove_file(&pdev->dev, &dev_attr_mode); device_remove_file(&pdev->dev, &dev_attr_speed); device_remove_file(&pdev->dev, &dev_attr_bus_vote); Loading drivers/usb/typec/ucsi/ucsi.c +32 −0 Original line number Diff line number Diff line Loading @@ -473,15 +473,19 @@ static void ucsi_unregister_partner(struct ucsi_connector *con) static void ucsi_partner_change(struct ucsi_connector *con) { int ret; struct ucsi *ucsi = con->ucsi; enum usb_role u_role = USB_ROLE_NONE; if (!con->partner) return; switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: u_role = USB_ROLE_HOST; typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: u_role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: Loading @@ -492,6 +496,11 @@ static void ucsi_partner_change(struct ucsi_connector *con) if (!completion_done(&con->complete)) complete(&con->complete); ret = usb_role_switch_set_role(ucsi->usb_role_sw, u_role); if (ret) dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n", __func__, u_role, ret); /* Can't rely on Partner Flags field. Always checking the alt modes. */ ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); if (ret) Loading @@ -510,6 +519,7 @@ static void ucsi_handle_connector_change(struct work_struct *work) enum typec_role role; u64 command; int ret; enum usb_role u_role = USB_ROLE_NONE; mutex_lock(&con->lock); Loading Loading @@ -540,9 +550,11 @@ static void ucsi_handle_connector_change(struct work_struct *work) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: u_role = USB_ROLE_HOST; typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: u_role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: Loading @@ -553,6 +565,11 @@ static void ucsi_handle_connector_change(struct work_struct *work) ucsi_register_partner(con); else ucsi_unregister_partner(con); ret = usb_role_switch_set_role(ucsi->usb_role_sw, u_role); if (ret) dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n", __func__, u_role, ret); } if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) { Loading Loading @@ -776,6 +793,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) enum typec_accessory *accessory = cap->accessory; u64 command; int ret; enum usb_role role = USB_ROLE_NONE; INIT_WORK(&con->work, ucsi_handle_connector_change); init_completion(&con->complete); Loading Loading @@ -840,9 +858,11 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: role = USB_ROLE_HOST; typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: Loading @@ -857,6 +877,11 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ucsi_register_partner(con); } ret = usb_role_switch_set_role(ucsi->usb_role_sw, role); if (ret) dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n", __func__, role, ret); if (con->partner) { ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); if (ret) Loading Loading @@ -920,6 +945,13 @@ int ucsi_init(struct ucsi *ucsi) goto err_reset; } ucsi->usb_role_sw = fwnode_usb_role_switch_get(dev_fwnode(ucsi->dev)); if (IS_ERR_OR_NULL(ucsi->usb_role_sw)) { dev_err(ucsi->dev, "%s(): Unable to find usb role switch\n", __func__); ucsi->usb_role_sw = NULL; } /* Register all connectors */ for (i = 0; i < ucsi->cap.num_connectors; i++) { ret = ucsi_register_port(ucsi, i); Loading drivers/usb/typec/ucsi/ucsi.h +3 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ #include <linux/device.h> #include <linux/types.h> #include <linux/usb/typec.h> #include <linux/usb/role.h> /* -------------------------------------------------------------------------- */ Loading Loading @@ -277,6 +278,8 @@ struct ucsi { #define EVENT_PENDING 0 #define COMMAND_PENDING 1 #define ACK_PENDING 2 struct usb_role_switch *usb_role_sw; }; #define UCSI_MAX_SVID 5 Loading Loading
drivers/usb/dwc3/dwc3-msm.c +94 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include <linux/extcon.h> #include <linux/reset.h> #include <linux/usb/dwc3-msm.h> #include <linux/usb/role.h> #include "core.h" #include "gadget.h" Loading Loading @@ -362,6 +363,12 @@ static const char * const gsi_op_strings[] = { "FREE_TRBS", "SET_CLR_BLOCK_DBL", "CHECK_FOR_SUSP", "EP_DISABLE" }; static const char * const usb_role_strings[] = { "NONE", "HOST", "DEVICE" }; struct dwc3_msm; struct extcon_nb { Loading Loading @@ -471,6 +478,8 @@ struct dwc3_msm { u64 dummy_gsi_db; dma_addr_t dummy_gsi_db_dma; struct usb_role_switch *role_switch; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ Loading Loading @@ -3551,6 +3560,79 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc) return 0; } static inline const char *usb_role_string(enum usb_role role) { if (role < ARRAY_SIZE(usb_role_strings)) return usb_role_strings[role]; return "Invalid"; } static enum usb_role dwc3_msm_usb_get_role(struct device *dev) { struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); enum usb_role role; if (mdwc->vbus_active) role = USB_ROLE_DEVICE; else if (mdwc->id_state == DWC3_ID_GROUND) role = USB_ROLE_HOST; else role = USB_ROLE_NONE; dbg_log_string("get_role:%s\n", usb_role_string(role)); return role; } static int dwc3_msm_usb_set_role(struct device *dev, enum usb_role role) { struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); enum usb_role cur_role = USB_ROLE_NONE; cur_role = dwc3_msm_usb_get_role(dev); switch (role) { case USB_ROLE_HOST: mdwc->vbus_active = false; mdwc->id_state = DWC3_ID_GROUND; break; case USB_ROLE_DEVICE: mdwc->vbus_active = true; mdwc->id_state = DWC3_ID_FLOAT; break; case USB_ROLE_NONE: mdwc->vbus_active = false; mdwc->id_state = DWC3_ID_FLOAT; break; } dbg_log_string("cur_role:%s new_role:%s\n", usb_role_string(cur_role), usb_role_string(role)); /* * For boot up without USB cable connected case, don't check * previous role value to allow resetting USB controller and * PHYs. */ if (mdwc->drd_state != DRD_STATE_UNDEFINED && cur_role == role) { dbg_log_string("no USB role change"); return 0; } dwc3_ext_event_notify(mdwc); return 0; } static struct usb_role_switch_desc role_desc = { .set = dwc3_msm_usb_set_role, .get = dwc3_msm_usb_get_role, .allow_userspace_control = true, }; static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { Loading Loading @@ -4112,7 +4194,17 @@ static int dwc3_msm_probe(struct platform_device *pdev) } else { queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); } } else { } if (of_property_read_bool(node, "usb-role-switch")) { role_desc.fwnode = dev_fwnode(&pdev->dev); mdwc->role_switch = usb_role_switch_register(mdwc->dev, &role_desc); if (IS_ERR(mdwc->role_switch)) return PTR_ERR(mdwc->role_switch); } if (!mdwc->role_switch && !mdwc->extcon) { switch (dwc->dr_mode) { case USB_DR_MODE_OTG: if (of_property_read_bool(node, Loading Loading @@ -4168,6 +4260,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); int i, ret_pm; usb_role_switch_unregister(mdwc->role_switch); device_remove_file(&pdev->dev, &dev_attr_mode); device_remove_file(&pdev->dev, &dev_attr_speed); device_remove_file(&pdev->dev, &dev_attr_bus_vote); Loading
drivers/usb/typec/ucsi/ucsi.c +32 −0 Original line number Diff line number Diff line Loading @@ -473,15 +473,19 @@ static void ucsi_unregister_partner(struct ucsi_connector *con) static void ucsi_partner_change(struct ucsi_connector *con) { int ret; struct ucsi *ucsi = con->ucsi; enum usb_role u_role = USB_ROLE_NONE; if (!con->partner) return; switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: u_role = USB_ROLE_HOST; typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: u_role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: Loading @@ -492,6 +496,11 @@ static void ucsi_partner_change(struct ucsi_connector *con) if (!completion_done(&con->complete)) complete(&con->complete); ret = usb_role_switch_set_role(ucsi->usb_role_sw, u_role); if (ret) dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n", __func__, u_role, ret); /* Can't rely on Partner Flags field. Always checking the alt modes. */ ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); if (ret) Loading @@ -510,6 +519,7 @@ static void ucsi_handle_connector_change(struct work_struct *work) enum typec_role role; u64 command; int ret; enum usb_role u_role = USB_ROLE_NONE; mutex_lock(&con->lock); Loading Loading @@ -540,9 +550,11 @@ static void ucsi_handle_connector_change(struct work_struct *work) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: u_role = USB_ROLE_HOST; typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: u_role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: Loading @@ -553,6 +565,11 @@ static void ucsi_handle_connector_change(struct work_struct *work) ucsi_register_partner(con); else ucsi_unregister_partner(con); ret = usb_role_switch_set_role(ucsi->usb_role_sw, u_role); if (ret) dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n", __func__, u_role, ret); } if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) { Loading Loading @@ -776,6 +793,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) enum typec_accessory *accessory = cap->accessory; u64 command; int ret; enum usb_role role = USB_ROLE_NONE; INIT_WORK(&con->work, ucsi_handle_connector_change); init_completion(&con->complete); Loading Loading @@ -840,9 +858,11 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: role = USB_ROLE_HOST; typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: Loading @@ -857,6 +877,11 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ucsi_register_partner(con); } ret = usb_role_switch_set_role(ucsi->usb_role_sw, role); if (ret) dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n", __func__, role, ret); if (con->partner) { ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); if (ret) Loading Loading @@ -920,6 +945,13 @@ int ucsi_init(struct ucsi *ucsi) goto err_reset; } ucsi->usb_role_sw = fwnode_usb_role_switch_get(dev_fwnode(ucsi->dev)); if (IS_ERR_OR_NULL(ucsi->usb_role_sw)) { dev_err(ucsi->dev, "%s(): Unable to find usb role switch\n", __func__); ucsi->usb_role_sw = NULL; } /* Register all connectors */ for (i = 0; i < ucsi->cap.num_connectors; i++) { ret = ucsi_register_port(ucsi, i); Loading
drivers/usb/typec/ucsi/ucsi.h +3 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ #include <linux/device.h> #include <linux/types.h> #include <linux/usb/typec.h> #include <linux/usb/role.h> /* -------------------------------------------------------------------------- */ Loading Loading @@ -277,6 +278,8 @@ struct ucsi { #define EVENT_PENDING 0 #define COMMAND_PENDING 1 #define ACK_PENDING 2 struct usb_role_switch *usb_role_sw; }; #define UCSI_MAX_SVID 5 Loading