OSDN Git Service

usb: typec: tcpm: set correct data role for non-DRD
authorLi Jun <jun.li@nxp.com>
Fri, 14 Feb 2020 07:53:48 +0000 (15:53 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Feb 2020 16:38:15 +0000 (08:38 -0800)
Since the typec port data role is separated from power role,
so check the port data capability when setting data role.

Signed-off-by: Li Jun <jun.li@nxp.com>
Reviewed-by: Heikki 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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/tcpm/tcpm.c

index f3087ef..78077c2 100644 (file)
@@ -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 (data == TYPEC_HOST)
-               usb_role = USB_ROLE_HOST;
-       else
-               usb_role = USB_ROLE_DEVICE;
+       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;
        }