@@ -58,8 +58,91 @@ static int cros_typec_enter_usb_mode(struct typec_port *tc_port, enum usb_mode m
5858 & req , sizeof (req ), NULL , 0 );
5959}
6060
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+
61142static 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 ,
63146};
64147
65148static int cros_typec_parse_port_props (struct typec_capability * cap ,
0 commit comments