Commit 6ecc632d authored by Li Jun's avatar Li Jun Committed by Greg Kroah-Hartman
Browse files

usb: typec: tcpm: set correct data role for non-DRD



Since the typec port data role is separated from power role,
so check the port data capability when setting data role.

Signed-off-by: default avatarLi Jun <jun.li@nxp.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/1581666828-2063-1-git-send-email-jun.li@nxp.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 21d78d86
Loading
Loading
Loading
Loading
+42 −11
Original line number Diff line number Diff line
@@ -373,6 +373,14 @@ struct pd_rx_event {
	((port)->try_src_count == 0 && (port)->try_role == TYPEC_SOURCE && \
	(port)->port_type == TYPEC_PORT_DRP)

#define tcpm_data_role_for_source(port) \
	((port)->typec_caps.data == TYPEC_PORT_UFP ? \
	TYPEC_DEVICE : TYPEC_HOST)

#define tcpm_data_role_for_sink(port) \
	((port)->typec_caps.data == TYPEC_PORT_DFP ? \
	TYPEC_HOST : TYPEC_DEVICE)

static enum tcpm_state tcpm_default_state(struct tcpm_port *port)
{
	if (port->port_type == TYPEC_PORT_DRP) {
@@ -788,10 +796,30 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
	else
		orientation = TYPEC_ORIENTATION_REVERSE;

	if (port->typec_caps.data == TYPEC_PORT_DRD) {
		if (data == TYPEC_HOST)
			usb_role = USB_ROLE_HOST;
		else
			usb_role = USB_ROLE_DEVICE;
	} else if (port->typec_caps.data == TYPEC_PORT_DFP) {
		if (data == TYPEC_HOST) {
			if (role == TYPEC_SOURCE)
				usb_role = USB_ROLE_HOST;
			else
				usb_role = USB_ROLE_NONE;
		} else {
			return -ENOTSUPP;
		}
	} else {
		if (data == TYPEC_DEVICE) {
			if (role == TYPEC_SINK)
				usb_role = USB_ROLE_DEVICE;
			else
				usb_role = USB_ROLE_NONE;
		} else {
			return -ENOTSUPP;
		}
	}

	ret = tcpm_mux_set(port, TYPEC_STATE_USB, usb_role, orientation);
	if (ret < 0)
@@ -1817,7 +1845,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
		tcpm_set_state(port, SOFT_RESET, 0);
		break;
	case PD_CTRL_DR_SWAP:
		if (port->port_type != TYPEC_PORT_DRP) {
		if (port->typec_caps.data != TYPEC_PORT_DRD) {
			tcpm_queue_message(port, PD_MSG_CTRL_REJECT);
			break;
		}
@@ -2618,7 +2646,8 @@ static int tcpm_src_attach(struct tcpm_port *port)
	if (ret < 0)
		return ret;

	ret = tcpm_set_roles(port, true, TYPEC_SOURCE, TYPEC_HOST);
	ret = tcpm_set_roles(port, true, TYPEC_SOURCE,
			     tcpm_data_role_for_source(port));
	if (ret < 0)
		return ret;

@@ -2740,7 +2769,8 @@ static int tcpm_snk_attach(struct tcpm_port *port)
	if (ret < 0)
		return ret;

	ret = tcpm_set_roles(port, true, TYPEC_SINK, TYPEC_DEVICE);
	ret = tcpm_set_roles(port, true, TYPEC_SINK,
			     tcpm_data_role_for_sink(port));
	if (ret < 0)
		return ret;

@@ -2766,7 +2796,8 @@ static int tcpm_acc_attach(struct tcpm_port *port)
	if (port->attached)
		return 0;

	ret = tcpm_set_roles(port, true, TYPEC_SOURCE, TYPEC_HOST);
	ret = tcpm_set_roles(port, true, TYPEC_SOURCE,
			     tcpm_data_role_for_source(port));
	if (ret < 0)
		return ret;

@@ -3293,7 +3324,7 @@ static void run_state_machine(struct tcpm_port *port)
		tcpm_set_vconn(port, true);
		tcpm_set_vbus(port, false);
		tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE,
			       TYPEC_HOST);
			       tcpm_data_role_for_source(port));
		tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
		break;
	case SRC_HARD_RESET_VBUS_ON:
@@ -3308,7 +3339,7 @@ static void run_state_machine(struct tcpm_port *port)
		if (port->pd_capable)
			tcpm_set_charge(port, false);
		tcpm_set_roles(port, port->self_powered, TYPEC_SINK,
			       TYPEC_DEVICE);
			       tcpm_data_role_for_sink(port));
		/*
		 * VBUS may or may not toggle, depending on the adapter.
		 * If it doesn't toggle, transition to SNK_HARD_RESET_SINK_ON
@@ -3969,7 +4000,7 @@ static int tcpm_dr_set(struct typec_port *p, enum typec_data_role data)
	mutex_lock(&port->swap_lock);
	mutex_lock(&port->lock);

	if (port->port_type != TYPEC_PORT_DRP) {
	if (port->typec_caps.data != TYPEC_PORT_DRD) {
		ret = -EINVAL;
		goto port_unlock;
	}