summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/typec/mux/intel_pmc_mux.c68
1 files changed, 35 insertions, 33 deletions
diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c
index 1a575858a36f..a6426a076d5a 100644
--- a/drivers/usb/typec/mux/intel_pmc_mux.c
+++ b/drivers/usb/typec/mux/intel_pmc_mux.c
@@ -224,9 +224,6 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state)
return pmc_usb_mux_dp_hpd(port, state->data);
}
- if (data->status & DP_STATUS_IRQ_HPD)
- return pmc_usb_mux_dp_hpd(port, state->data);
-
req.usage = PMC_USB_ALT_MODE;
req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
req.mode_type = PMC_USB_MODE_TYPE_DP << PMC_USB_MODE_TYPE_SHIFT;
@@ -345,39 +342,52 @@ static int pmc_usb_mux_safe_state(struct pmc_usb_port *port)
return pmc_usb_command(port, &msg, sizeof(msg));
}
-static int pmc_usb_connect(struct pmc_usb_port *port)
+static int pmc_usb_disconnect(struct pmc_usb_port *port)
{
+ struct typec_displayport_data data = { };
u8 msg[2];
- if (port->iom_status & IOM_PORT_STATUS_CONNECTED)
+ if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED))
return 0;
- msg[0] = PMC_USB_CONNECT;
+ /* Clear DisplayPort HPD if it's still asserted. */
+ if (IOM_PORT_HPD_ASSERTED(port->iom_status))
+ pmc_usb_mux_dp_hpd(port, &data);
+
+ msg[0] = PMC_USB_DISCONNECT;
msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT;
- msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT;
- msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT;
return pmc_usb_command(port, msg, sizeof(msg));
}
-static int pmc_usb_disconnect(struct pmc_usb_port *port)
+static int pmc_usb_connect(struct pmc_usb_port *port, enum usb_role role)
{
- struct typec_displayport_data data = { };
+ u8 ufp = role == USB_ROLE_DEVICE ? 1 : 0;
u8 msg[2];
+ int ret;
- if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED))
- return 0;
+ if (port->orientation == TYPEC_ORIENTATION_NONE)
+ return -EINVAL;
- /* Clear DisplayPort HPD if it's still asserted. */
- if (IOM_PORT_HPD_ASSERTED(port->iom_status))
- pmc_usb_mux_dp_hpd(port, &data);
+ if (port->iom_status & IOM_PORT_STATUS_CONNECTED) {
+ if (port->role == role || port->role == USB_ROLE_NONE)
+ return 0;
- msg[0] = PMC_USB_DISCONNECT;
+ /* Role swap */
+ ret = pmc_usb_disconnect(port);
+ if (ret)
+ return ret;
+ }
+
+ msg[0] = PMC_USB_CONNECT;
msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT;
+ msg[1] |= ufp << PMC_USB_MSG_UFP_SHIFT;
+ msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT;
+ msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT;
return pmc_usb_command(port, msg, sizeof(msg));
}
@@ -395,7 +405,7 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
if (state->mode == TYPEC_STATE_SAFE)
return pmc_usb_mux_safe_state(port);
if (state->mode == TYPEC_STATE_USB)
- return pmc_usb_connect(port);
+ return pmc_usb_connect(port, port->role);
if (state->alt) {
switch (state->alt->svid) {
@@ -410,7 +420,7 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
/* REVISIT: Try with usb3_port set to 0? */
break;
case TYPEC_MODE_USB3:
- return pmc_usb_connect(port);
+ return pmc_usb_connect(port, port->role);
case TYPEC_MODE_USB4:
return pmc_usb_mux_usb4(port, state);
}
@@ -428,32 +438,24 @@ static int pmc_usb_set_orientation(struct typec_switch *sw,
port->orientation = orientation;
- if (port->role) {
- if (orientation == TYPEC_ORIENTATION_NONE)
- return pmc_usb_disconnect(port);
- else
- return pmc_usb_connect(port);
- }
-
return 0;
}
static int pmc_usb_set_role(struct usb_role_switch *sw, enum usb_role role)
{
struct pmc_usb_port *port = usb_role_switch_get_drvdata(sw);
+ int ret;
update_port_status(port);
- port->role = role;
+ if (role == USB_ROLE_NONE)
+ ret = pmc_usb_disconnect(port);
+ else
+ ret = pmc_usb_connect(port, role);
- if (port->orientation) {
- if (role == USB_ROLE_NONE)
- return pmc_usb_disconnect(port);
- else
- return pmc_usb_connect(port);
- }
+ port->role = role;
- return 0;
+ return ret;
}
static int pmc_usb_register_port(struct pmc_usb *pmc, int index,