S(BIST_RX), \
\
S(ERROR_RECOVERY), \
- S(ERROR_RECOVERY_WAIT_OFF)
+ S(PORT_RESET), \
+ S(PORT_RESET_WAIT_OFF)
#define GENERATE_ENUM(e) e
#define GENERATE_STRING(s) #s
struct mutex swap_lock; /* swap command lock */
bool swap_pending;
+ bool non_pd_role_swap;
struct completion swap_complete;
int swap_status;
if (port->swap_pending) {
port->swap_status = result;
port->swap_pending = false;
+ port->non_pd_role_swap = false;
complete(&port->swap_complete);
}
}
break;
/* SRC states */
case SRC_UNATTACHED:
- tcpm_swap_complete(port, -ENOTCONN);
+ if (!port->non_pd_role_swap)
+ tcpm_swap_complete(port, -ENOTCONN);
tcpm_src_detach(port);
if (tcpm_start_drp_toggling(port)) {
tcpm_set_state(port, DRP_TOGGLING, 0);
/* SNK states */
case SNK_UNATTACHED:
- tcpm_swap_complete(port, -ENOTCONN);
+ if (!port->non_pd_role_swap)
+ tcpm_swap_complete(port, -ENOTCONN);
tcpm_snk_detach(port);
if (tcpm_start_drp_toggling(port)) {
tcpm_set_state(port, DRP_TOGGLING, 0);
break;
case ERROR_RECOVERY:
tcpm_swap_complete(port, -EPROTO);
+ tcpm_set_state(port, PORT_RESET, 0);
+ break;
+ case PORT_RESET:
tcpm_reset_port(port);
-
tcpm_set_cc(port, TYPEC_CC_OPEN);
- tcpm_set_state(port, ERROR_RECOVERY_WAIT_OFF,
+ tcpm_set_state(port, PORT_RESET_WAIT_OFF,
PD_T_ERROR_RECOVERY);
break;
- case ERROR_RECOVERY_WAIT_OFF:
+ case PORT_RESET_WAIT_OFF:
tcpm_set_state(port,
tcpm_default_state(port),
port->vbus_present ? PD_T_PS_SOURCE_OFF : 0);
/* Do nothing, expected */
break;
- case ERROR_RECOVERY_WAIT_OFF:
+ case PORT_RESET_WAIT_OFF:
tcpm_set_state(port, tcpm_default_state(port), 0);
break;
mutex_lock(&port->swap_lock);
mutex_lock(&port->lock);
- if (port->typec_caps.type != TYPEC_PORT_DRP || !port->pd_capable) {
+ if (port->typec_caps.type != TYPEC_PORT_DRP) {
ret = -EINVAL;
goto port_unlock;
}
* Reject data role swap request in this case.
*/
+ if (!port->pd_capable) {
+ /*
+ * If the partner is not PD capable, reset the port to
+ * trigger a role change. This can only work if a preferred
+ * role is configured, and if it matches the requested role.
+ */
+ if (port->try_role == TYPEC_NO_PREFERRED_ROLE ||
+ port->try_role == port->pwr_role) {
+ ret = -EINVAL;
+ goto port_unlock;
+ }
+ port->non_pd_role_swap = true;
+ tcpm_set_state(port, PORT_RESET, 0);
+ } else {
+ tcpm_set_state(port, DR_SWAP_SEND, 0);
+ }
+
port->swap_status = 0;
port->swap_pending = true;
reinit_completion(&port->swap_complete);
- tcpm_set_state(port, DR_SWAP_SEND, 0);
mutex_unlock(&port->lock);
if (!wait_for_completion_timeout(&port->swap_complete,
else
ret = port->swap_status;
+ port->non_pd_role_swap = false;
goto swap_unlock;
port_unlock:
goto port_unlock;
}
- if (!port->pd_capable) {
- /*
- * If the partner is not PD capable, reset the port to
- * trigger a role change. This can only work if a preferred
- * role is configured, and if it matches the requested role.
- */
- if (port->try_role == TYPEC_NO_PREFERRED_ROLE ||
- port->try_role == port->pwr_role) {
- ret = -EINVAL;
- goto port_unlock;
- }
- tcpm_set_state(port, HARD_RESET_SEND, 0);
- ret = 0;
- goto port_unlock;
- }
-
port->swap_status = 0;
port->swap_pending = true;
reinit_completion(&port->swap_complete);
* Some adapters need a clean slate at startup, and won't recover
* otherwise. So do not try to be fancy and force a clean disconnect.
*/
- tcpm_set_state(port, ERROR_RECOVERY, 0);
+ tcpm_set_state(port, PORT_RESET, 0);
}
void tcpm_tcpc_reset(struct tcpm_port *port)