Skip to content

Commit ab229c2

Browse files
apanditTzung-Bi Shih
authored andcommitted
platform/chrome: cros_ec_typec: Add role swap ops
Add the pr_set and dr_set typec_operations to registered typec ports. This enables sysfs to control power and data role when the port is capable of doing so. Signed-off-by: Abhishek Pandit-Subedi <[email protected]> Co-developed-by: Radu Vele <[email protected]> Signed-off-by: Radu Vele <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Tzung-Bi Shih <[email protected]>
1 parent 5af89b6 commit ab229c2

File tree

1 file changed

+84
-1
lines changed

1 file changed

+84
-1
lines changed

drivers/platform/chrome/cros_ec_typec.c

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+
61142
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,
63146
};
64147

65148
static int cros_typec_parse_port_props(struct typec_capability *cap,

0 commit comments

Comments
 (0)