1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2020 Google LLC 4 * 5 * This driver provides the ability to view and manage Type C ports through the 6 * Chrome OS EC. 7 */ 8 9 #include <linux/acpi.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/platform_data/cros_ec_commands.h> 13 #include <linux/platform_data/cros_ec_proto.h> 14 #include <linux/platform_data/cros_usbpd_notify.h> 15 #include <linux/platform_device.h> 16 #include <linux/usb/typec.h> 17 18 #define DRV_NAME "cros-ec-typec" 19 20 /* Per port data. */ 21 struct cros_typec_port { 22 struct typec_port *port; 23 /* Initial capabilities for the port. */ 24 struct typec_capability caps; 25 struct typec_partner *partner; 26 /* Port partner PD identity info. */ 27 struct usb_pd_identity p_identity; 28 }; 29 30 /* Platform-specific data for the Chrome OS EC Type C controller. */ 31 struct cros_typec_data { 32 struct device *dev; 33 struct cros_ec_device *ec; 34 int num_ports; 35 unsigned int cmd_ver; 36 /* Array of ports, indexed by port number. */ 37 struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS]; 38 struct notifier_block nb; 39 }; 40 41 static int cros_typec_parse_port_props(struct typec_capability *cap, 42 struct fwnode_handle *fwnode, 43 struct device *dev) 44 { 45 const char *buf; 46 int ret; 47 48 memset(cap, 0, sizeof(*cap)); 49 ret = fwnode_property_read_string(fwnode, "power-role", &buf); 50 if (ret) { 51 dev_err(dev, "power-role not found: %d\n", ret); 52 return ret; 53 } 54 55 ret = typec_find_port_power_role(buf); 56 if (ret < 0) 57 return ret; 58 cap->type = ret; 59 60 ret = fwnode_property_read_string(fwnode, "data-role", &buf); 61 if (ret) { 62 dev_err(dev, "data-role not found: %d\n", ret); 63 return ret; 64 } 65 66 ret = typec_find_port_data_role(buf); 67 if (ret < 0) 68 return ret; 69 cap->data = ret; 70 71 ret = fwnode_property_read_string(fwnode, "try-power-role", &buf); 72 if (ret) { 73 dev_err(dev, "try-power-role not found: %d\n", ret); 74 return ret; 75 } 76 77 ret = typec_find_power_role(buf); 78 if (ret < 0) 79 return ret; 80 cap->prefer_role = ret; 81 82 cap->fwnode = fwnode; 83 84 return 0; 85 } 86 87 static void cros_unregister_ports(struct cros_typec_data *typec) 88 { 89 int i; 90 91 for (i = 0; i < typec->num_ports; i++) { 92 if (!typec->ports[i]) 93 continue; 94 typec_unregister_port(typec->ports[i]->port); 95 } 96 } 97 98 static int cros_typec_init_ports(struct cros_typec_data *typec) 99 { 100 struct device *dev = typec->dev; 101 struct typec_capability *cap; 102 struct fwnode_handle *fwnode; 103 struct cros_typec_port *cros_port; 104 const char *port_prop; 105 int ret; 106 int nports; 107 u32 port_num = 0; 108 109 nports = device_get_child_node_count(dev); 110 if (nports == 0) { 111 dev_err(dev, "No port entries found.\n"); 112 return -ENODEV; 113 } 114 115 if (nports > typec->num_ports) { 116 dev_err(dev, "More ports listed than can be supported.\n"); 117 return -EINVAL; 118 } 119 120 /* DT uses "reg" to specify port number. */ 121 port_prop = dev->of_node ? "reg" : "port-number"; 122 device_for_each_child_node(dev, fwnode) { 123 if (fwnode_property_read_u32(fwnode, port_prop, &port_num)) { 124 ret = -EINVAL; 125 dev_err(dev, "No port-number for port, aborting.\n"); 126 goto unregister_ports; 127 } 128 129 if (port_num >= typec->num_ports) { 130 dev_err(dev, "Invalid port number.\n"); 131 ret = -EINVAL; 132 goto unregister_ports; 133 } 134 135 dev_dbg(dev, "Registering port %d\n", port_num); 136 137 cros_port = devm_kzalloc(dev, sizeof(*cros_port), GFP_KERNEL); 138 if (!cros_port) { 139 ret = -ENOMEM; 140 goto unregister_ports; 141 } 142 143 typec->ports[port_num] = cros_port; 144 cap = &cros_port->caps; 145 146 ret = cros_typec_parse_port_props(cap, fwnode, dev); 147 if (ret < 0) 148 goto unregister_ports; 149 150 cros_port->port = typec_register_port(dev, cap); 151 if (IS_ERR(cros_port->port)) { 152 dev_err(dev, "Failed to register port %d\n", port_num); 153 ret = PTR_ERR(cros_port->port); 154 goto unregister_ports; 155 } 156 } 157 158 return 0; 159 160 unregister_ports: 161 cros_unregister_ports(typec); 162 return ret; 163 } 164 165 static int cros_typec_ec_command(struct cros_typec_data *typec, 166 unsigned int version, 167 unsigned int command, 168 void *outdata, 169 unsigned int outsize, 170 void *indata, 171 unsigned int insize) 172 { 173 struct cros_ec_command *msg; 174 int ret; 175 176 msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); 177 if (!msg) 178 return -ENOMEM; 179 180 msg->version = version; 181 msg->command = command; 182 msg->outsize = outsize; 183 msg->insize = insize; 184 185 if (outsize) 186 memcpy(msg->data, outdata, outsize); 187 188 ret = cros_ec_cmd_xfer_status(typec->ec, msg); 189 if (ret >= 0 && insize) 190 memcpy(indata, msg->data, insize); 191 192 kfree(msg); 193 return ret; 194 } 195 196 static int cros_typec_add_partner(struct cros_typec_data *typec, int port_num, 197 bool pd_en) 198 { 199 struct cros_typec_port *port = typec->ports[port_num]; 200 struct typec_partner_desc p_desc = { 201 .usb_pd = pd_en, 202 }; 203 int ret = 0; 204 205 /* 206 * Fill an initial PD identity, which will then be updated with info 207 * from the EC. 208 */ 209 p_desc.identity = &port->p_identity; 210 211 port->partner = typec_register_partner(port->port, &p_desc); 212 if (IS_ERR(port->partner)) { 213 ret = PTR_ERR(port->partner); 214 port->partner = NULL; 215 } 216 217 return ret; 218 } 219 220 static void cros_typec_set_port_params_v0(struct cros_typec_data *typec, 221 int port_num, struct ec_response_usb_pd_control *resp) 222 { 223 struct typec_port *port = typec->ports[port_num]->port; 224 enum typec_orientation polarity; 225 226 if (!resp->enabled) 227 polarity = TYPEC_ORIENTATION_NONE; 228 else if (!resp->polarity) 229 polarity = TYPEC_ORIENTATION_NORMAL; 230 else 231 polarity = TYPEC_ORIENTATION_REVERSE; 232 233 typec_set_pwr_role(port, resp->role ? TYPEC_SOURCE : TYPEC_SINK); 234 typec_set_orientation(port, polarity); 235 } 236 237 static void cros_typec_set_port_params_v1(struct cros_typec_data *typec, 238 int port_num, struct ec_response_usb_pd_control_v1 *resp) 239 { 240 struct typec_port *port = typec->ports[port_num]->port; 241 enum typec_orientation polarity; 242 bool pd_en; 243 int ret; 244 245 if (!(resp->enabled & PD_CTRL_RESP_ENABLED_CONNECTED)) 246 polarity = TYPEC_ORIENTATION_NONE; 247 else if (!resp->polarity) 248 polarity = TYPEC_ORIENTATION_NORMAL; 249 else 250 polarity = TYPEC_ORIENTATION_REVERSE; 251 typec_set_orientation(port, polarity); 252 typec_set_data_role(port, resp->role & PD_CTRL_RESP_ROLE_DATA ? 253 TYPEC_HOST : TYPEC_DEVICE); 254 typec_set_pwr_role(port, resp->role & PD_CTRL_RESP_ROLE_POWER ? 255 TYPEC_SOURCE : TYPEC_SINK); 256 typec_set_vconn_role(port, resp->role & PD_CTRL_RESP_ROLE_VCONN ? 257 TYPEC_SOURCE : TYPEC_SINK); 258 259 /* Register/remove partners when a connect/disconnect occurs. */ 260 if (resp->enabled & PD_CTRL_RESP_ENABLED_CONNECTED) { 261 if (typec->ports[port_num]->partner) 262 return; 263 264 pd_en = resp->enabled & PD_CTRL_RESP_ENABLED_PD_CAPABLE; 265 ret = cros_typec_add_partner(typec, port_num, pd_en); 266 if (ret) 267 dev_warn(typec->dev, 268 "Failed to register partner on port: %d\n", 269 port_num); 270 } else { 271 if (!typec->ports[port_num]->partner) 272 return; 273 274 typec_unregister_partner(typec->ports[port_num]->partner); 275 typec->ports[port_num]->partner = NULL; 276 } 277 } 278 279 static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) 280 { 281 struct ec_params_usb_pd_control req; 282 struct ec_response_usb_pd_control_v1 resp; 283 int ret; 284 285 if (port_num < 0 || port_num >= typec->num_ports) { 286 dev_err(typec->dev, "cannot get status for invalid port %d\n", 287 port_num); 288 return -EINVAL; 289 } 290 291 req.port = port_num; 292 req.role = USB_PD_CTRL_ROLE_NO_CHANGE; 293 req.mux = USB_PD_CTRL_MUX_NO_CHANGE; 294 req.swap = USB_PD_CTRL_SWAP_NONE; 295 296 ret = cros_typec_ec_command(typec, typec->cmd_ver, 297 EC_CMD_USB_PD_CONTROL, &req, sizeof(req), 298 &resp, sizeof(resp)); 299 if (ret < 0) 300 return ret; 301 302 dev_dbg(typec->dev, "Enabled %d: 0x%hhx\n", port_num, resp.enabled); 303 dev_dbg(typec->dev, "Role %d: 0x%hhx\n", port_num, resp.role); 304 dev_dbg(typec->dev, "Polarity %d: 0x%hhx\n", port_num, resp.polarity); 305 dev_dbg(typec->dev, "State %d: %s\n", port_num, resp.state); 306 307 if (typec->cmd_ver == 1) 308 cros_typec_set_port_params_v1(typec, port_num, &resp); 309 else 310 cros_typec_set_port_params_v0(typec, port_num, 311 (struct ec_response_usb_pd_control *) &resp); 312 313 return 0; 314 } 315 316 static int cros_typec_get_cmd_version(struct cros_typec_data *typec) 317 { 318 struct ec_params_get_cmd_versions_v1 req_v1; 319 struct ec_response_get_cmd_versions resp; 320 int ret; 321 322 /* We're interested in the PD control command version. */ 323 req_v1.cmd = EC_CMD_USB_PD_CONTROL; 324 ret = cros_typec_ec_command(typec, 1, EC_CMD_GET_CMD_VERSIONS, 325 &req_v1, sizeof(req_v1), &resp, 326 sizeof(resp)); 327 if (ret < 0) 328 return ret; 329 330 if (resp.version_mask & EC_VER_MASK(1)) 331 typec->cmd_ver = 1; 332 else 333 typec->cmd_ver = 0; 334 335 dev_dbg(typec->dev, "PD Control has version mask 0x%hhx\n", 336 typec->cmd_ver); 337 338 return 0; 339 } 340 341 static int cros_ec_typec_event(struct notifier_block *nb, 342 unsigned long host_event, void *_notify) 343 { 344 struct cros_typec_data *typec = container_of(nb, struct cros_typec_data, 345 nb); 346 int ret, i; 347 348 for (i = 0; i < typec->num_ports; i++) { 349 ret = cros_typec_port_update(typec, i); 350 if (ret < 0) 351 dev_warn(typec->dev, "Update failed for port: %d\n", i); 352 } 353 354 return NOTIFY_OK; 355 } 356 357 #ifdef CONFIG_ACPI 358 static const struct acpi_device_id cros_typec_acpi_id[] = { 359 { "GOOG0014", 0 }, 360 {} 361 }; 362 MODULE_DEVICE_TABLE(acpi, cros_typec_acpi_id); 363 #endif 364 365 #ifdef CONFIG_OF 366 static const struct of_device_id cros_typec_of_match[] = { 367 { .compatible = "google,cros-ec-typec", }, 368 {} 369 }; 370 MODULE_DEVICE_TABLE(of, cros_typec_of_match); 371 #endif 372 373 static int cros_typec_probe(struct platform_device *pdev) 374 { 375 struct device *dev = &pdev->dev; 376 struct cros_typec_data *typec; 377 struct ec_response_usb_pd_ports resp; 378 int ret, i; 379 380 typec = devm_kzalloc(dev, sizeof(*typec), GFP_KERNEL); 381 if (!typec) 382 return -ENOMEM; 383 384 typec->dev = dev; 385 typec->ec = dev_get_drvdata(pdev->dev.parent); 386 platform_set_drvdata(pdev, typec); 387 388 ret = cros_typec_get_cmd_version(typec); 389 if (ret < 0) { 390 dev_err(dev, "failed to get PD command version info\n"); 391 return ret; 392 } 393 394 ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, 395 &resp, sizeof(resp)); 396 if (ret < 0) 397 return ret; 398 399 typec->num_ports = resp.num_ports; 400 if (typec->num_ports > EC_USB_PD_MAX_PORTS) { 401 dev_warn(typec->dev, 402 "Too many ports reported: %d, limiting to max: %d\n", 403 typec->num_ports, EC_USB_PD_MAX_PORTS); 404 typec->num_ports = EC_USB_PD_MAX_PORTS; 405 } 406 407 ret = cros_typec_init_ports(typec); 408 if (ret < 0) 409 return ret; 410 411 for (i = 0; i < typec->num_ports; i++) { 412 ret = cros_typec_port_update(typec, i); 413 if (ret < 0) 414 goto unregister_ports; 415 } 416 417 typec->nb.notifier_call = cros_ec_typec_event; 418 ret = cros_usbpd_register_notify(&typec->nb); 419 if (ret < 0) 420 goto unregister_ports; 421 422 return 0; 423 424 unregister_ports: 425 cros_unregister_ports(typec); 426 return ret; 427 } 428 429 static struct platform_driver cros_typec_driver = { 430 .driver = { 431 .name = DRV_NAME, 432 .acpi_match_table = ACPI_PTR(cros_typec_acpi_id), 433 .of_match_table = of_match_ptr(cros_typec_of_match), 434 }, 435 .probe = cros_typec_probe, 436 }; 437 438 module_platform_driver(cros_typec_driver); 439 440 MODULE_AUTHOR("Prashant Malani <pmalani@chromium.org>"); 441 MODULE_DESCRIPTION("Chrome OS EC Type C control"); 442 MODULE_LICENSE("GPL"); 443