@@ -58,8 +58,91 @@ static int cros_typec_enter_usb_mode(struct typec_port *tc_port, enum usb_mode m
58
58
& req , sizeof (req ), NULL , 0 );
59
59
}
60
60
61
+ static int cros_typec_perform_role_swap (struct typec_port * tc_port , int target_role , u8 swap_type )
62
+ {
63
+ struct cros_typec_port * port = typec_get_drvdata (tc_port );
64
+ struct cros_typec_data * data = port -> typec_data ;
65
+ struct ec_response_usb_pd_control_v2 resp ;
66
+ struct ec_params_usb_pd_control req ;
67
+ int role , ret ;
68
+
69
+ /* Must be at least v1 to support role swap. */
70
+ if (!data -> pd_ctrl_ver )
71
+ return - EOPNOTSUPP ;
72
+
73
+ /* First query the state */
74
+ req .port = port -> port_num ;
75
+ req .role = USB_PD_CTRL_ROLE_NO_CHANGE ;
76
+ req .mux = USB_PD_CTRL_MUX_NO_CHANGE ;
77
+ req .swap = USB_PD_CTRL_SWAP_NONE ;
78
+
79
+ ret = cros_ec_cmd (data -> ec , data -> pd_ctrl_ver , EC_CMD_USB_PD_CONTROL ,
80
+ & req , sizeof (req ), & resp , sizeof (resp ));
81
+ if (ret < 0 )
82
+ return ret ;
83
+
84
+ switch (swap_type ) {
85
+ case USB_PD_CTRL_SWAP_DATA :
86
+ role = (resp .role & PD_CTRL_RESP_ROLE_DATA ) ? TYPEC_HOST :
87
+ TYPEC_DEVICE ;
88
+ break ;
89
+ case USB_PD_CTRL_SWAP_POWER :
90
+ role = (resp .role & PD_CTRL_RESP_ROLE_POWER ) ? TYPEC_SOURCE :
91
+ TYPEC_SINK ;
92
+ break ;
93
+ default :
94
+ dev_warn (data -> dev , "Unsupported role swap type %d\n" , swap_type );
95
+ return - EOPNOTSUPP ;
96
+ }
97
+
98
+ if (role == target_role )
99
+ return 0 ;
100
+
101
+ req .swap = swap_type ;
102
+ ret = cros_ec_cmd (data -> ec , data -> pd_ctrl_ver , EC_CMD_USB_PD_CONTROL ,
103
+ & req , sizeof (req ), & resp , sizeof (resp ));
104
+ if (ret < 0 )
105
+ return ret ;
106
+
107
+ switch (swap_type ) {
108
+ case USB_PD_CTRL_SWAP_DATA :
109
+ role = resp .role & PD_CTRL_RESP_ROLE_DATA ? TYPEC_HOST : TYPEC_DEVICE ;
110
+ if (role != target_role ) {
111
+ dev_err (data -> dev , "Data role swap failed despite EC returning success\n" );
112
+ return - EIO ;
113
+ }
114
+ typec_set_data_role (tc_port , target_role );
115
+ break ;
116
+ case USB_PD_CTRL_SWAP_POWER :
117
+ role = resp .role & PD_CTRL_RESP_ROLE_POWER ? TYPEC_SOURCE : TYPEC_SINK ;
118
+ if (role != target_role ) {
119
+ dev_err (data -> dev , "Power role swap failed despite EC returning success\n" );
120
+ return - EIO ;
121
+ }
122
+ typec_set_pwr_role (tc_port , target_role );
123
+ break ;
124
+ default :
125
+ /* Should never execute */
126
+ break ;
127
+ }
128
+
129
+ return 0 ;
130
+ }
131
+
132
+ static int cros_typec_dr_swap (struct typec_port * port , enum typec_data_role role )
133
+ {
134
+ return cros_typec_perform_role_swap (port , role , USB_PD_CTRL_SWAP_DATA );
135
+ }
136
+
137
+ static int cros_typec_pr_swap (struct typec_port * port , enum typec_role role )
138
+ {
139
+ return cros_typec_perform_role_swap (port , role , USB_PD_CTRL_SWAP_POWER );
140
+ }
141
+
61
142
static const struct typec_operations cros_typec_usb_mode_ops = {
62
- .enter_usb_mode = cros_typec_enter_usb_mode
143
+ .enter_usb_mode = cros_typec_enter_usb_mode ,
144
+ .dr_set = cros_typec_dr_swap ,
145
+ .pr_set = cros_typec_pr_swap ,
63
146
};
64
147
65
148
static int cros_typec_parse_port_props (struct typec_capability * cap ,
0 commit comments