Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.13-rc1 1368 lines 35 kB view raw
1/* 2 * USB Type-C Connector Class 3 * 4 * Copyright (C) 2017, Intel Corporation 5 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/device.h> 13#include <linux/module.h> 14#include <linux/mutex.h> 15#include <linux/slab.h> 16#include <linux/usb/typec.h> 17 18struct typec_mode { 19 int index; 20 u32 vdo; 21 char *desc; 22 enum typec_port_type roles; 23 24 struct typec_altmode *alt_mode; 25 26 unsigned int active:1; 27 28 char group_name[6]; 29 struct attribute_group group; 30 struct attribute *attrs[5]; 31 struct device_attribute vdo_attr; 32 struct device_attribute desc_attr; 33 struct device_attribute active_attr; 34 struct device_attribute roles_attr; 35}; 36 37struct typec_altmode { 38 struct device dev; 39 u16 svid; 40 int n_modes; 41 struct typec_mode modes[ALTMODE_MAX_MODES]; 42 const struct attribute_group *mode_groups[ALTMODE_MAX_MODES]; 43}; 44 45struct typec_plug { 46 struct device dev; 47 enum typec_plug_index index; 48}; 49 50struct typec_cable { 51 struct device dev; 52 enum typec_plug_type type; 53 struct usb_pd_identity *identity; 54 unsigned int active:1; 55}; 56 57struct typec_partner { 58 struct device dev; 59 unsigned int usb_pd:1; 60 struct usb_pd_identity *identity; 61 enum typec_accessory accessory; 62}; 63 64struct typec_port { 65 unsigned int id; 66 struct device dev; 67 68 int prefer_role; 69 enum typec_data_role data_role; 70 enum typec_role pwr_role; 71 enum typec_role vconn_role; 72 enum typec_pwr_opmode pwr_opmode; 73 enum typec_port_type port_type; 74 struct mutex port_type_lock; 75 76 const struct typec_capability *cap; 77}; 78 79#define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev) 80#define to_typec_plug(_dev_) container_of(_dev_, struct typec_plug, dev) 81#define to_typec_cable(_dev_) container_of(_dev_, struct typec_cable, dev) 82#define to_typec_partner(_dev_) container_of(_dev_, struct typec_partner, dev) 83#define to_altmode(_dev_) container_of(_dev_, struct typec_altmode, dev) 84 85static const struct device_type typec_partner_dev_type; 86static const struct device_type typec_cable_dev_type; 87static const struct device_type typec_plug_dev_type; 88static const struct device_type typec_port_dev_type; 89 90#define is_typec_partner(_dev_) (_dev_->type == &typec_partner_dev_type) 91#define is_typec_cable(_dev_) (_dev_->type == &typec_cable_dev_type) 92#define is_typec_plug(_dev_) (_dev_->type == &typec_plug_dev_type) 93#define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type) 94 95static DEFINE_IDA(typec_index_ida); 96static struct class *typec_class; 97 98/* Common attributes */ 99 100static const char * const typec_accessory_modes[] = { 101 [TYPEC_ACCESSORY_NONE] = "none", 102 [TYPEC_ACCESSORY_AUDIO] = "analog_audio", 103 [TYPEC_ACCESSORY_DEBUG] = "debug", 104}; 105 106static struct usb_pd_identity *get_pd_identity(struct device *dev) 107{ 108 if (is_typec_partner(dev)) { 109 struct typec_partner *partner = to_typec_partner(dev); 110 111 return partner->identity; 112 } else if (is_typec_cable(dev)) { 113 struct typec_cable *cable = to_typec_cable(dev); 114 115 return cable->identity; 116 } 117 return NULL; 118} 119 120static ssize_t id_header_show(struct device *dev, struct device_attribute *attr, 121 char *buf) 122{ 123 struct usb_pd_identity *id = get_pd_identity(dev); 124 125 return sprintf(buf, "0x%08x\n", id->id_header); 126} 127static DEVICE_ATTR_RO(id_header); 128 129static ssize_t cert_stat_show(struct device *dev, struct device_attribute *attr, 130 char *buf) 131{ 132 struct usb_pd_identity *id = get_pd_identity(dev); 133 134 return sprintf(buf, "0x%08x\n", id->cert_stat); 135} 136static DEVICE_ATTR_RO(cert_stat); 137 138static ssize_t product_show(struct device *dev, struct device_attribute *attr, 139 char *buf) 140{ 141 struct usb_pd_identity *id = get_pd_identity(dev); 142 143 return sprintf(buf, "0x%08x\n", id->product); 144} 145static DEVICE_ATTR_RO(product); 146 147static struct attribute *usb_pd_id_attrs[] = { 148 &dev_attr_id_header.attr, 149 &dev_attr_cert_stat.attr, 150 &dev_attr_product.attr, 151 NULL 152}; 153 154static const struct attribute_group usb_pd_id_group = { 155 .name = "identity", 156 .attrs = usb_pd_id_attrs, 157}; 158 159static const struct attribute_group *usb_pd_id_groups[] = { 160 &usb_pd_id_group, 161 NULL, 162}; 163 164static void typec_report_identity(struct device *dev) 165{ 166 sysfs_notify(&dev->kobj, "identity", "id_header"); 167 sysfs_notify(&dev->kobj, "identity", "cert_stat"); 168 sysfs_notify(&dev->kobj, "identity", "product"); 169} 170 171/* ------------------------------------------------------------------------- */ 172/* Alternate Modes */ 173 174/** 175 * typec_altmode_update_active - Report Enter/Exit mode 176 * @alt: Handle to the alternate mode 177 * @mode: Mode index 178 * @active: True when the mode has been entered 179 * 180 * If a partner or cable plug executes Enter/Exit Mode command successfully, the 181 * drivers use this routine to report the updated state of the mode. 182 */ 183void typec_altmode_update_active(struct typec_altmode *alt, int mode, 184 bool active) 185{ 186 struct typec_mode *m = &alt->modes[mode]; 187 char dir[6]; 188 189 if (m->active == active) 190 return; 191 192 m->active = active; 193 snprintf(dir, sizeof(dir), "mode%d", mode); 194 sysfs_notify(&alt->dev.kobj, dir, "active"); 195 kobject_uevent(&alt->dev.kobj, KOBJ_CHANGE); 196} 197EXPORT_SYMBOL_GPL(typec_altmode_update_active); 198 199/** 200 * typec_altmode2port - Alternate Mode to USB Type-C port 201 * @alt: The Alternate Mode 202 * 203 * Returns handle to the port that a cable plug or partner with @alt is 204 * connected to. 205 */ 206struct typec_port *typec_altmode2port(struct typec_altmode *alt) 207{ 208 if (is_typec_plug(alt->dev.parent)) 209 return to_typec_port(alt->dev.parent->parent->parent); 210 if (is_typec_partner(alt->dev.parent)) 211 return to_typec_port(alt->dev.parent->parent); 212 if (is_typec_port(alt->dev.parent)) 213 return to_typec_port(alt->dev.parent); 214 215 return NULL; 216} 217EXPORT_SYMBOL_GPL(typec_altmode2port); 218 219static ssize_t 220typec_altmode_vdo_show(struct device *dev, struct device_attribute *attr, 221 char *buf) 222{ 223 struct typec_mode *mode = container_of(attr, struct typec_mode, 224 vdo_attr); 225 226 return sprintf(buf, "0x%08x\n", mode->vdo); 227} 228 229static ssize_t 230typec_altmode_desc_show(struct device *dev, struct device_attribute *attr, 231 char *buf) 232{ 233 struct typec_mode *mode = container_of(attr, struct typec_mode, 234 desc_attr); 235 236 return sprintf(buf, "%s\n", mode->desc ? mode->desc : ""); 237} 238 239static ssize_t 240typec_altmode_active_show(struct device *dev, struct device_attribute *attr, 241 char *buf) 242{ 243 struct typec_mode *mode = container_of(attr, struct typec_mode, 244 active_attr); 245 246 return sprintf(buf, "%s\n", mode->active ? "yes" : "no"); 247} 248 249static ssize_t 250typec_altmode_active_store(struct device *dev, struct device_attribute *attr, 251 const char *buf, size_t size) 252{ 253 struct typec_mode *mode = container_of(attr, struct typec_mode, 254 active_attr); 255 struct typec_port *port = typec_altmode2port(mode->alt_mode); 256 bool activate; 257 int ret; 258 259 if (!port->cap->activate_mode) 260 return -EOPNOTSUPP; 261 262 ret = kstrtobool(buf, &activate); 263 if (ret) 264 return ret; 265 266 ret = port->cap->activate_mode(port->cap, mode->index, activate); 267 if (ret) 268 return ret; 269 270 return size; 271} 272 273static ssize_t 274typec_altmode_roles_show(struct device *dev, struct device_attribute *attr, 275 char *buf) 276{ 277 struct typec_mode *mode = container_of(attr, struct typec_mode, 278 roles_attr); 279 ssize_t ret; 280 281 switch (mode->roles) { 282 case TYPEC_PORT_DFP: 283 ret = sprintf(buf, "source\n"); 284 break; 285 case TYPEC_PORT_UFP: 286 ret = sprintf(buf, "sink\n"); 287 break; 288 case TYPEC_PORT_DRP: 289 default: 290 ret = sprintf(buf, "source sink\n"); 291 break; 292 } 293 return ret; 294} 295 296static void typec_init_modes(struct typec_altmode *alt, 297 const struct typec_mode_desc *desc, bool is_port) 298{ 299 int i; 300 301 for (i = 0; i < alt->n_modes; i++, desc++) { 302 struct typec_mode *mode = &alt->modes[i]; 303 304 /* Not considering the human readable description critical */ 305 mode->desc = kstrdup(desc->desc, GFP_KERNEL); 306 if (desc->desc && !mode->desc) 307 dev_err(&alt->dev, "failed to copy mode%d desc\n", i); 308 309 mode->alt_mode = alt; 310 mode->vdo = desc->vdo; 311 mode->roles = desc->roles; 312 mode->index = desc->index; 313 sprintf(mode->group_name, "mode%d", desc->index); 314 315 sysfs_attr_init(&mode->vdo_attr.attr); 316 mode->vdo_attr.attr.name = "vdo"; 317 mode->vdo_attr.attr.mode = 0444; 318 mode->vdo_attr.show = typec_altmode_vdo_show; 319 320 sysfs_attr_init(&mode->desc_attr.attr); 321 mode->desc_attr.attr.name = "description"; 322 mode->desc_attr.attr.mode = 0444; 323 mode->desc_attr.show = typec_altmode_desc_show; 324 325 sysfs_attr_init(&mode->active_attr.attr); 326 mode->active_attr.attr.name = "active"; 327 mode->active_attr.attr.mode = 0644; 328 mode->active_attr.show = typec_altmode_active_show; 329 mode->active_attr.store = typec_altmode_active_store; 330 331 mode->attrs[0] = &mode->vdo_attr.attr; 332 mode->attrs[1] = &mode->desc_attr.attr; 333 mode->attrs[2] = &mode->active_attr.attr; 334 335 /* With ports, list the roles that the mode is supported with */ 336 if (is_port) { 337 sysfs_attr_init(&mode->roles_attr.attr); 338 mode->roles_attr.attr.name = "supported_roles"; 339 mode->roles_attr.attr.mode = 0444; 340 mode->roles_attr.show = typec_altmode_roles_show; 341 342 mode->attrs[3] = &mode->roles_attr.attr; 343 } 344 345 mode->group.attrs = mode->attrs; 346 mode->group.name = mode->group_name; 347 348 alt->mode_groups[i] = &mode->group; 349 } 350} 351 352static ssize_t svid_show(struct device *dev, struct device_attribute *attr, 353 char *buf) 354{ 355 struct typec_altmode *alt = to_altmode(dev); 356 357 return sprintf(buf, "%04x\n", alt->svid); 358} 359static DEVICE_ATTR_RO(svid); 360 361static struct attribute *typec_altmode_attrs[] = { 362 &dev_attr_svid.attr, 363 NULL 364}; 365ATTRIBUTE_GROUPS(typec_altmode); 366 367static void typec_altmode_release(struct device *dev) 368{ 369 struct typec_altmode *alt = to_altmode(dev); 370 int i; 371 372 for (i = 0; i < alt->n_modes; i++) 373 kfree(alt->modes[i].desc); 374 kfree(alt); 375} 376 377static const struct device_type typec_altmode_dev_type = { 378 .name = "typec_alternate_mode", 379 .groups = typec_altmode_groups, 380 .release = typec_altmode_release, 381}; 382 383static struct typec_altmode * 384typec_register_altmode(struct device *parent, 385 const struct typec_altmode_desc *desc) 386{ 387 struct typec_altmode *alt; 388 int ret; 389 390 alt = kzalloc(sizeof(*alt), GFP_KERNEL); 391 if (!alt) 392 return NULL; 393 394 alt->svid = desc->svid; 395 alt->n_modes = desc->n_modes; 396 typec_init_modes(alt, desc->modes, is_typec_port(parent)); 397 398 alt->dev.parent = parent; 399 alt->dev.groups = alt->mode_groups; 400 alt->dev.type = &typec_altmode_dev_type; 401 dev_set_name(&alt->dev, "svid-%04x", alt->svid); 402 403 ret = device_register(&alt->dev); 404 if (ret) { 405 dev_err(parent, "failed to register alternate mode (%d)\n", 406 ret); 407 put_device(&alt->dev); 408 return NULL; 409 } 410 411 return alt; 412} 413 414/** 415 * typec_unregister_altmode - Unregister Alternate Mode 416 * @alt: The alternate mode to be unregistered 417 * 418 * Unregister device created with typec_partner_register_altmode(), 419 * typec_plug_register_altmode() or typec_port_register_altmode(). 420 */ 421void typec_unregister_altmode(struct typec_altmode *alt) 422{ 423 if (alt) 424 device_unregister(&alt->dev); 425} 426EXPORT_SYMBOL_GPL(typec_unregister_altmode); 427 428/* ------------------------------------------------------------------------- */ 429/* Type-C Partners */ 430 431static ssize_t accessory_mode_show(struct device *dev, 432 struct device_attribute *attr, 433 char *buf) 434{ 435 struct typec_partner *p = to_typec_partner(dev); 436 437 return sprintf(buf, "%s\n", typec_accessory_modes[p->accessory]); 438} 439static DEVICE_ATTR_RO(accessory_mode); 440 441static ssize_t supports_usb_power_delivery_show(struct device *dev, 442 struct device_attribute *attr, 443 char *buf) 444{ 445 struct typec_partner *p = to_typec_partner(dev); 446 447 return sprintf(buf, "%s\n", p->usb_pd ? "yes" : "no"); 448} 449static DEVICE_ATTR_RO(supports_usb_power_delivery); 450 451static struct attribute *typec_partner_attrs[] = { 452 &dev_attr_accessory_mode.attr, 453 &dev_attr_supports_usb_power_delivery.attr, 454 NULL 455}; 456ATTRIBUTE_GROUPS(typec_partner); 457 458static void typec_partner_release(struct device *dev) 459{ 460 struct typec_partner *partner = to_typec_partner(dev); 461 462 kfree(partner); 463} 464 465static const struct device_type typec_partner_dev_type = { 466 .name = "typec_partner", 467 .groups = typec_partner_groups, 468 .release = typec_partner_release, 469}; 470 471/** 472 * typec_partner_set_identity - Report result from Discover Identity command 473 * @partner: The partner updated identity values 474 * 475 * This routine is used to report that the result of Discover Identity USB power 476 * delivery command has become available. 477 */ 478int typec_partner_set_identity(struct typec_partner *partner) 479{ 480 if (!partner->identity) 481 return -EINVAL; 482 483 typec_report_identity(&partner->dev); 484 return 0; 485} 486EXPORT_SYMBOL_GPL(typec_partner_set_identity); 487 488/** 489 * typec_partner_register_altmode - Register USB Type-C Partner Alternate Mode 490 * @partner: USB Type-C Partner that supports the alternate mode 491 * @desc: Description of the alternate mode 492 * 493 * This routine is used to register each alternate mode individually that 494 * @partner has listed in response to Discover SVIDs command. The modes for a 495 * SVID listed in response to Discover Modes command need to be listed in an 496 * array in @desc. 497 * 498 * Returns handle to the alternate mode on success or NULL on failure. 499 */ 500struct typec_altmode * 501typec_partner_register_altmode(struct typec_partner *partner, 502 const struct typec_altmode_desc *desc) 503{ 504 return typec_register_altmode(&partner->dev, desc); 505} 506EXPORT_SYMBOL_GPL(typec_partner_register_altmode); 507 508/** 509 * typec_register_partner - Register a USB Type-C Partner 510 * @port: The USB Type-C Port the partner is connected to 511 * @desc: Description of the partner 512 * 513 * Registers a device for USB Type-C Partner described in @desc. 514 * 515 * Returns handle to the partner on success or NULL on failure. 516 */ 517struct typec_partner *typec_register_partner(struct typec_port *port, 518 struct typec_partner_desc *desc) 519{ 520 struct typec_partner *partner; 521 int ret; 522 523 partner = kzalloc(sizeof(*partner), GFP_KERNEL); 524 if (!partner) 525 return NULL; 526 527 partner->usb_pd = desc->usb_pd; 528 partner->accessory = desc->accessory; 529 530 if (desc->identity) { 531 /* 532 * Creating directory for the identity only if the driver is 533 * able to provide data to it. 534 */ 535 partner->dev.groups = usb_pd_id_groups; 536 partner->identity = desc->identity; 537 } 538 539 partner->dev.class = typec_class; 540 partner->dev.parent = &port->dev; 541 partner->dev.type = &typec_partner_dev_type; 542 dev_set_name(&partner->dev, "%s-partner", dev_name(&port->dev)); 543 544 ret = device_register(&partner->dev); 545 if (ret) { 546 dev_err(&port->dev, "failed to register partner (%d)\n", ret); 547 put_device(&partner->dev); 548 return NULL; 549 } 550 551 return partner; 552} 553EXPORT_SYMBOL_GPL(typec_register_partner); 554 555/** 556 * typec_unregister_partner - Unregister a USB Type-C Partner 557 * @partner: The partner to be unregistered 558 * 559 * Unregister device created with typec_register_partner(). 560 */ 561void typec_unregister_partner(struct typec_partner *partner) 562{ 563 if (partner) 564 device_unregister(&partner->dev); 565} 566EXPORT_SYMBOL_GPL(typec_unregister_partner); 567 568/* ------------------------------------------------------------------------- */ 569/* Type-C Cable Plugs */ 570 571static void typec_plug_release(struct device *dev) 572{ 573 struct typec_plug *plug = to_typec_plug(dev); 574 575 kfree(plug); 576} 577 578static const struct device_type typec_plug_dev_type = { 579 .name = "typec_plug", 580 .release = typec_plug_release, 581}; 582 583/** 584 * typec_plug_register_altmode - Register USB Type-C Cable Plug Alternate Mode 585 * @plug: USB Type-C Cable Plug that supports the alternate mode 586 * @desc: Description of the alternate mode 587 * 588 * This routine is used to register each alternate mode individually that @plug 589 * has listed in response to Discover SVIDs command. The modes for a SVID that 590 * the plug lists in response to Discover Modes command need to be listed in an 591 * array in @desc. 592 * 593 * Returns handle to the alternate mode on success or NULL on failure. 594 */ 595struct typec_altmode * 596typec_plug_register_altmode(struct typec_plug *plug, 597 const struct typec_altmode_desc *desc) 598{ 599 return typec_register_altmode(&plug->dev, desc); 600} 601EXPORT_SYMBOL_GPL(typec_plug_register_altmode); 602 603/** 604 * typec_register_plug - Register a USB Type-C Cable Plug 605 * @cable: USB Type-C Cable with the plug 606 * @desc: Description of the cable plug 607 * 608 * Registers a device for USB Type-C Cable Plug described in @desc. A USB Type-C 609 * Cable Plug represents a plug with electronics in it that can response to USB 610 * Power Delivery SOP Prime or SOP Double Prime packages. 611 * 612 * Returns handle to the cable plug on success or NULL on failure. 613 */ 614struct typec_plug *typec_register_plug(struct typec_cable *cable, 615 struct typec_plug_desc *desc) 616{ 617 struct typec_plug *plug; 618 char name[8]; 619 int ret; 620 621 plug = kzalloc(sizeof(*plug), GFP_KERNEL); 622 if (!plug) 623 return NULL; 624 625 sprintf(name, "plug%d", desc->index); 626 627 plug->index = desc->index; 628 plug->dev.class = typec_class; 629 plug->dev.parent = &cable->dev; 630 plug->dev.type = &typec_plug_dev_type; 631 dev_set_name(&plug->dev, "%s-%s", dev_name(cable->dev.parent), name); 632 633 ret = device_register(&plug->dev); 634 if (ret) { 635 dev_err(&cable->dev, "failed to register plug (%d)\n", ret); 636 put_device(&plug->dev); 637 return NULL; 638 } 639 640 return plug; 641} 642EXPORT_SYMBOL_GPL(typec_register_plug); 643 644/** 645 * typec_unregister_plug - Unregister a USB Type-C Cable Plug 646 * @plug: The cable plug to be unregistered 647 * 648 * Unregister device created with typec_register_plug(). 649 */ 650void typec_unregister_plug(struct typec_plug *plug) 651{ 652 if (plug) 653 device_unregister(&plug->dev); 654} 655EXPORT_SYMBOL_GPL(typec_unregister_plug); 656 657/* Type-C Cables */ 658 659static ssize_t 660type_show(struct device *dev, struct device_attribute *attr, char *buf) 661{ 662 struct typec_cable *cable = to_typec_cable(dev); 663 664 return sprintf(buf, "%s\n", cable->active ? "active" : "passive"); 665} 666static DEVICE_ATTR_RO(type); 667 668static const char * const typec_plug_types[] = { 669 [USB_PLUG_NONE] = "unknown", 670 [USB_PLUG_TYPE_A] = "type-a", 671 [USB_PLUG_TYPE_B] = "type-b", 672 [USB_PLUG_TYPE_C] = "type-c", 673 [USB_PLUG_CAPTIVE] = "captive", 674}; 675 676static ssize_t plug_type_show(struct device *dev, 677 struct device_attribute *attr, char *buf) 678{ 679 struct typec_cable *cable = to_typec_cable(dev); 680 681 return sprintf(buf, "%s\n", typec_plug_types[cable->type]); 682} 683static DEVICE_ATTR_RO(plug_type); 684 685static struct attribute *typec_cable_attrs[] = { 686 &dev_attr_type.attr, 687 &dev_attr_plug_type.attr, 688 NULL 689}; 690ATTRIBUTE_GROUPS(typec_cable); 691 692static void typec_cable_release(struct device *dev) 693{ 694 struct typec_cable *cable = to_typec_cable(dev); 695 696 kfree(cable); 697} 698 699static const struct device_type typec_cable_dev_type = { 700 .name = "typec_cable", 701 .groups = typec_cable_groups, 702 .release = typec_cable_release, 703}; 704 705/** 706 * typec_cable_set_identity - Report result from Discover Identity command 707 * @cable: The cable updated identity values 708 * 709 * This routine is used to report that the result of Discover Identity USB power 710 * delivery command has become available. 711 */ 712int typec_cable_set_identity(struct typec_cable *cable) 713{ 714 if (!cable->identity) 715 return -EINVAL; 716 717 typec_report_identity(&cable->dev); 718 return 0; 719} 720EXPORT_SYMBOL_GPL(typec_cable_set_identity); 721 722/** 723 * typec_register_cable - Register a USB Type-C Cable 724 * @port: The USB Type-C Port the cable is connected to 725 * @desc: Description of the cable 726 * 727 * Registers a device for USB Type-C Cable described in @desc. The cable will be 728 * parent for the optional cable plug devises. 729 * 730 * Returns handle to the cable on success or NULL on failure. 731 */ 732struct typec_cable *typec_register_cable(struct typec_port *port, 733 struct typec_cable_desc *desc) 734{ 735 struct typec_cable *cable; 736 int ret; 737 738 cable = kzalloc(sizeof(*cable), GFP_KERNEL); 739 if (!cable) 740 return NULL; 741 742 cable->type = desc->type; 743 cable->active = desc->active; 744 745 if (desc->identity) { 746 /* 747 * Creating directory for the identity only if the driver is 748 * able to provide data to it. 749 */ 750 cable->dev.groups = usb_pd_id_groups; 751 cable->identity = desc->identity; 752 } 753 754 cable->dev.class = typec_class; 755 cable->dev.parent = &port->dev; 756 cable->dev.type = &typec_cable_dev_type; 757 dev_set_name(&cable->dev, "%s-cable", dev_name(&port->dev)); 758 759 ret = device_register(&cable->dev); 760 if (ret) { 761 dev_err(&port->dev, "failed to register cable (%d)\n", ret); 762 put_device(&cable->dev); 763 return NULL; 764 } 765 766 return cable; 767} 768EXPORT_SYMBOL_GPL(typec_register_cable); 769 770/** 771 * typec_unregister_cable - Unregister a USB Type-C Cable 772 * @cable: The cable to be unregistered 773 * 774 * Unregister device created with typec_register_cable(). 775 */ 776void typec_unregister_cable(struct typec_cable *cable) 777{ 778 if (cable) 779 device_unregister(&cable->dev); 780} 781EXPORT_SYMBOL_GPL(typec_unregister_cable); 782 783/* ------------------------------------------------------------------------- */ 784/* USB Type-C ports */ 785 786static const char * const typec_roles[] = { 787 [TYPEC_SINK] = "sink", 788 [TYPEC_SOURCE] = "source", 789}; 790 791static const char * const typec_data_roles[] = { 792 [TYPEC_DEVICE] = "device", 793 [TYPEC_HOST] = "host", 794}; 795 796static const char * const typec_port_types[] = { 797 [TYPEC_PORT_DFP] = "source", 798 [TYPEC_PORT_UFP] = "sink", 799 [TYPEC_PORT_DRP] = "dual", 800}; 801 802static const char * const typec_port_types_drp[] = { 803 [TYPEC_PORT_DFP] = "dual [source] sink", 804 [TYPEC_PORT_UFP] = "dual source [sink]", 805 [TYPEC_PORT_DRP] = "[dual] source sink", 806}; 807 808static ssize_t 809preferred_role_store(struct device *dev, struct device_attribute *attr, 810 const char *buf, size_t size) 811{ 812 struct typec_port *port = to_typec_port(dev); 813 int role; 814 int ret; 815 816 if (port->cap->type != TYPEC_PORT_DRP) { 817 dev_dbg(dev, "Preferred role only supported with DRP ports\n"); 818 return -EOPNOTSUPP; 819 } 820 821 if (!port->cap->try_role) { 822 dev_dbg(dev, "Setting preferred role not supported\n"); 823 return -EOPNOTSUPP; 824 } 825 826 role = sysfs_match_string(typec_roles, buf); 827 if (role < 0) { 828 if (sysfs_streq(buf, "none")) 829 role = TYPEC_NO_PREFERRED_ROLE; 830 else 831 return -EINVAL; 832 } 833 834 ret = port->cap->try_role(port->cap, role); 835 if (ret) 836 return ret; 837 838 port->prefer_role = role; 839 return size; 840} 841 842static ssize_t 843preferred_role_show(struct device *dev, struct device_attribute *attr, 844 char *buf) 845{ 846 struct typec_port *port = to_typec_port(dev); 847 848 if (port->cap->type != TYPEC_PORT_DRP) 849 return 0; 850 851 if (port->prefer_role < 0) 852 return 0; 853 854 return sprintf(buf, "%s\n", typec_roles[port->prefer_role]); 855} 856static DEVICE_ATTR_RW(preferred_role); 857 858static ssize_t data_role_store(struct device *dev, 859 struct device_attribute *attr, 860 const char *buf, size_t size) 861{ 862 struct typec_port *port = to_typec_port(dev); 863 int ret; 864 865 if (!port->cap->dr_set) { 866 dev_dbg(dev, "data role swapping not supported\n"); 867 return -EOPNOTSUPP; 868 } 869 870 ret = sysfs_match_string(typec_data_roles, buf); 871 if (ret < 0) 872 return ret; 873 874 mutex_lock(&port->port_type_lock); 875 if (port->port_type != TYPEC_PORT_DRP) { 876 dev_dbg(dev, "port type fixed at \"%s\"", 877 typec_port_types[port->port_type]); 878 ret = -EOPNOTSUPP; 879 goto unlock_and_ret; 880 } 881 882 ret = port->cap->dr_set(port->cap, ret); 883 if (ret) 884 goto unlock_and_ret; 885 886 ret = size; 887unlock_and_ret: 888 mutex_unlock(&port->port_type_lock); 889 return ret; 890} 891 892static ssize_t data_role_show(struct device *dev, 893 struct device_attribute *attr, char *buf) 894{ 895 struct typec_port *port = to_typec_port(dev); 896 897 if (port->cap->type == TYPEC_PORT_DRP) 898 return sprintf(buf, "%s\n", port->data_role == TYPEC_HOST ? 899 "[host] device" : "host [device]"); 900 901 return sprintf(buf, "[%s]\n", typec_data_roles[port->data_role]); 902} 903static DEVICE_ATTR_RW(data_role); 904 905static ssize_t power_role_store(struct device *dev, 906 struct device_attribute *attr, 907 const char *buf, size_t size) 908{ 909 struct typec_port *port = to_typec_port(dev); 910 int ret; 911 912 if (!port->cap->pd_revision) { 913 dev_dbg(dev, "USB Power Delivery not supported\n"); 914 return -EOPNOTSUPP; 915 } 916 917 if (!port->cap->pr_set) { 918 dev_dbg(dev, "power role swapping not supported\n"); 919 return -EOPNOTSUPP; 920 } 921 922 if (port->pwr_opmode != TYPEC_PWR_MODE_PD) { 923 dev_dbg(dev, "partner unable to swap power role\n"); 924 return -EIO; 925 } 926 927 ret = sysfs_match_string(typec_roles, buf); 928 if (ret < 0) 929 return ret; 930 931 mutex_lock(&port->port_type_lock); 932 if (port->port_type != TYPEC_PORT_DRP) { 933 dev_dbg(dev, "port type fixed at \"%s\"", 934 typec_port_types[port->port_type]); 935 ret = -EOPNOTSUPP; 936 goto unlock_and_ret; 937 } 938 939 ret = port->cap->pr_set(port->cap, ret); 940 if (ret) 941 goto unlock_and_ret; 942 943 ret = size; 944unlock_and_ret: 945 mutex_unlock(&port->port_type_lock); 946 return ret; 947} 948 949static ssize_t power_role_show(struct device *dev, 950 struct device_attribute *attr, char *buf) 951{ 952 struct typec_port *port = to_typec_port(dev); 953 954 if (port->cap->type == TYPEC_PORT_DRP) 955 return sprintf(buf, "%s\n", port->pwr_role == TYPEC_SOURCE ? 956 "[source] sink" : "source [sink]"); 957 958 return sprintf(buf, "[%s]\n", typec_roles[port->pwr_role]); 959} 960static DEVICE_ATTR_RW(power_role); 961 962static ssize_t 963port_type_store(struct device *dev, struct device_attribute *attr, 964 const char *buf, size_t size) 965{ 966 struct typec_port *port = to_typec_port(dev); 967 int ret; 968 enum typec_port_type type; 969 970 if (!port->cap->port_type_set || port->cap->type != TYPEC_PORT_DRP) { 971 dev_dbg(dev, "changing port type not supported\n"); 972 return -EOPNOTSUPP; 973 } 974 975 ret = sysfs_match_string(typec_port_types, buf); 976 if (ret < 0) 977 return ret; 978 979 type = ret; 980 mutex_lock(&port->port_type_lock); 981 982 if (port->port_type == type) { 983 ret = size; 984 goto unlock_and_ret; 985 } 986 987 ret = port->cap->port_type_set(port->cap, type); 988 if (ret) 989 goto unlock_and_ret; 990 991 port->port_type = type; 992 ret = size; 993 994unlock_and_ret: 995 mutex_unlock(&port->port_type_lock); 996 return ret; 997} 998 999static ssize_t 1000port_type_show(struct device *dev, struct device_attribute *attr, 1001 char *buf) 1002{ 1003 struct typec_port *port = to_typec_port(dev); 1004 1005 if (port->cap->type == TYPEC_PORT_DRP) 1006 return sprintf(buf, "%s\n", 1007 typec_port_types_drp[port->port_type]); 1008 1009 return sprintf(buf, "[%s]\n", typec_port_types[port->cap->type]); 1010} 1011static DEVICE_ATTR_RW(port_type); 1012 1013static const char * const typec_pwr_opmodes[] = { 1014 [TYPEC_PWR_MODE_USB] = "default", 1015 [TYPEC_PWR_MODE_1_5A] = "1.5A", 1016 [TYPEC_PWR_MODE_3_0A] = "3.0A", 1017 [TYPEC_PWR_MODE_PD] = "usb_power_delivery", 1018}; 1019 1020static ssize_t power_operation_mode_show(struct device *dev, 1021 struct device_attribute *attr, 1022 char *buf) 1023{ 1024 struct typec_port *port = to_typec_port(dev); 1025 1026 return sprintf(buf, "%s\n", typec_pwr_opmodes[port->pwr_opmode]); 1027} 1028static DEVICE_ATTR_RO(power_operation_mode); 1029 1030static ssize_t vconn_source_store(struct device *dev, 1031 struct device_attribute *attr, 1032 const char *buf, size_t size) 1033{ 1034 struct typec_port *port = to_typec_port(dev); 1035 bool source; 1036 int ret; 1037 1038 if (!port->cap->pd_revision) { 1039 dev_dbg(dev, "VCONN swap depends on USB Power Delivery\n"); 1040 return -EOPNOTSUPP; 1041 } 1042 1043 if (!port->cap->vconn_set) { 1044 dev_dbg(dev, "VCONN swapping not supported\n"); 1045 return -EOPNOTSUPP; 1046 } 1047 1048 ret = kstrtobool(buf, &source); 1049 if (ret) 1050 return ret; 1051 1052 ret = port->cap->vconn_set(port->cap, (enum typec_role)source); 1053 if (ret) 1054 return ret; 1055 1056 return size; 1057} 1058 1059static ssize_t vconn_source_show(struct device *dev, 1060 struct device_attribute *attr, char *buf) 1061{ 1062 struct typec_port *port = to_typec_port(dev); 1063 1064 return sprintf(buf, "%s\n", 1065 port->vconn_role == TYPEC_SOURCE ? "yes" : "no"); 1066} 1067static DEVICE_ATTR_RW(vconn_source); 1068 1069static ssize_t supported_accessory_modes_show(struct device *dev, 1070 struct device_attribute *attr, 1071 char *buf) 1072{ 1073 struct typec_port *port = to_typec_port(dev); 1074 ssize_t ret = 0; 1075 int i; 1076 1077 for (i = 0; i < ARRAY_SIZE(port->cap->accessory); i++) { 1078 if (port->cap->accessory[i]) 1079 ret += sprintf(buf + ret, "%s ", 1080 typec_accessory_modes[port->cap->accessory[i]]); 1081 } 1082 1083 if (!ret) 1084 return sprintf(buf, "none\n"); 1085 1086 buf[ret - 1] = '\n'; 1087 1088 return ret; 1089} 1090static DEVICE_ATTR_RO(supported_accessory_modes); 1091 1092static ssize_t usb_typec_revision_show(struct device *dev, 1093 struct device_attribute *attr, 1094 char *buf) 1095{ 1096 struct typec_port *port = to_typec_port(dev); 1097 u16 rev = port->cap->revision; 1098 1099 return sprintf(buf, "%d.%d\n", (rev >> 8) & 0xff, (rev >> 4) & 0xf); 1100} 1101static DEVICE_ATTR_RO(usb_typec_revision); 1102 1103static ssize_t usb_power_delivery_revision_show(struct device *dev, 1104 struct device_attribute *attr, 1105 char *buf) 1106{ 1107 struct typec_port *p = to_typec_port(dev); 1108 1109 return sprintf(buf, "%d\n", (p->cap->pd_revision >> 8) & 0xff); 1110} 1111static DEVICE_ATTR_RO(usb_power_delivery_revision); 1112 1113static struct attribute *typec_attrs[] = { 1114 &dev_attr_data_role.attr, 1115 &dev_attr_power_operation_mode.attr, 1116 &dev_attr_power_role.attr, 1117 &dev_attr_preferred_role.attr, 1118 &dev_attr_supported_accessory_modes.attr, 1119 &dev_attr_usb_power_delivery_revision.attr, 1120 &dev_attr_usb_typec_revision.attr, 1121 &dev_attr_vconn_source.attr, 1122 &dev_attr_port_type.attr, 1123 NULL, 1124}; 1125ATTRIBUTE_GROUPS(typec); 1126 1127static int typec_uevent(struct device *dev, struct kobj_uevent_env *env) 1128{ 1129 int ret; 1130 1131 ret = add_uevent_var(env, "TYPEC_PORT=%s", dev_name(dev)); 1132 if (ret) 1133 dev_err(dev, "failed to add uevent TYPEC_PORT\n"); 1134 1135 return ret; 1136} 1137 1138static void typec_release(struct device *dev) 1139{ 1140 struct typec_port *port = to_typec_port(dev); 1141 1142 ida_simple_remove(&typec_index_ida, port->id); 1143 kfree(port); 1144} 1145 1146static const struct device_type typec_port_dev_type = { 1147 .name = "typec_port", 1148 .groups = typec_groups, 1149 .uevent = typec_uevent, 1150 .release = typec_release, 1151}; 1152 1153/* --------------------------------------- */ 1154/* Driver callbacks to report role updates */ 1155 1156/** 1157 * typec_set_data_role - Report data role change 1158 * @port: The USB Type-C Port where the role was changed 1159 * @role: The new data role 1160 * 1161 * This routine is used by the port drivers to report data role changes. 1162 */ 1163void typec_set_data_role(struct typec_port *port, enum typec_data_role role) 1164{ 1165 if (port->data_role == role) 1166 return; 1167 1168 port->data_role = role; 1169 sysfs_notify(&port->dev.kobj, NULL, "data_role"); 1170 kobject_uevent(&port->dev.kobj, KOBJ_CHANGE); 1171} 1172EXPORT_SYMBOL_GPL(typec_set_data_role); 1173 1174/** 1175 * typec_set_pwr_role - Report power role change 1176 * @port: The USB Type-C Port where the role was changed 1177 * @role: The new data role 1178 * 1179 * This routine is used by the port drivers to report power role changes. 1180 */ 1181void typec_set_pwr_role(struct typec_port *port, enum typec_role role) 1182{ 1183 if (port->pwr_role == role) 1184 return; 1185 1186 port->pwr_role = role; 1187 sysfs_notify(&port->dev.kobj, NULL, "power_role"); 1188 kobject_uevent(&port->dev.kobj, KOBJ_CHANGE); 1189} 1190EXPORT_SYMBOL_GPL(typec_set_pwr_role); 1191 1192/** 1193 * typec_set_pwr_role - Report VCONN source change 1194 * @port: The USB Type-C Port which VCONN role changed 1195 * @role: Source when @port is sourcing VCONN, or Sink when it's not 1196 * 1197 * This routine is used by the port drivers to report if the VCONN source is 1198 * changes. 1199 */ 1200void typec_set_vconn_role(struct typec_port *port, enum typec_role role) 1201{ 1202 if (port->vconn_role == role) 1203 return; 1204 1205 port->vconn_role = role; 1206 sysfs_notify(&port->dev.kobj, NULL, "vconn_source"); 1207 kobject_uevent(&port->dev.kobj, KOBJ_CHANGE); 1208} 1209EXPORT_SYMBOL_GPL(typec_set_vconn_role); 1210 1211static int partner_match(struct device *dev, void *data) 1212{ 1213 return is_typec_partner(dev); 1214} 1215 1216/** 1217 * typec_set_pwr_opmode - Report changed power operation mode 1218 * @port: The USB Type-C Port where the mode was changed 1219 * @opmode: New power operation mode 1220 * 1221 * This routine is used by the port drivers to report changed power operation 1222 * mode in @port. The modes are USB (default), 1.5A, 3.0A as defined in USB 1223 * Type-C specification, and "USB Power Delivery" when the power levels are 1224 * negotiated with methods defined in USB Power Delivery specification. 1225 */ 1226void typec_set_pwr_opmode(struct typec_port *port, 1227 enum typec_pwr_opmode opmode) 1228{ 1229 struct device *partner_dev; 1230 1231 if (port->pwr_opmode == opmode) 1232 return; 1233 1234 port->pwr_opmode = opmode; 1235 sysfs_notify(&port->dev.kobj, NULL, "power_operation_mode"); 1236 kobject_uevent(&port->dev.kobj, KOBJ_CHANGE); 1237 1238 partner_dev = device_find_child(&port->dev, NULL, partner_match); 1239 if (partner_dev) { 1240 struct typec_partner *partner = to_typec_partner(partner_dev); 1241 1242 if (opmode == TYPEC_PWR_MODE_PD && !partner->usb_pd) { 1243 partner->usb_pd = 1; 1244 sysfs_notify(&partner_dev->kobj, NULL, 1245 "supports_usb_power_delivery"); 1246 } 1247 put_device(partner_dev); 1248 } 1249} 1250EXPORT_SYMBOL_GPL(typec_set_pwr_opmode); 1251 1252/* --------------------------------------- */ 1253 1254/** 1255 * typec_port_register_altmode - Register USB Type-C Port Alternate Mode 1256 * @port: USB Type-C Port that supports the alternate mode 1257 * @desc: Description of the alternate mode 1258 * 1259 * This routine is used to register an alternate mode that @port is capable of 1260 * supporting. 1261 * 1262 * Returns handle to the alternate mode on success or NULL on failure. 1263 */ 1264struct typec_altmode * 1265typec_port_register_altmode(struct typec_port *port, 1266 const struct typec_altmode_desc *desc) 1267{ 1268 return typec_register_altmode(&port->dev, desc); 1269} 1270EXPORT_SYMBOL_GPL(typec_port_register_altmode); 1271 1272/** 1273 * typec_register_port - Register a USB Type-C Port 1274 * @parent: Parent device 1275 * @cap: Description of the port 1276 * 1277 * Registers a device for USB Type-C Port described in @cap. 1278 * 1279 * Returns handle to the port on success or NULL on failure. 1280 */ 1281struct typec_port *typec_register_port(struct device *parent, 1282 const struct typec_capability *cap) 1283{ 1284 struct typec_port *port; 1285 int role; 1286 int ret; 1287 int id; 1288 1289 port = kzalloc(sizeof(*port), GFP_KERNEL); 1290 if (!port) 1291 return NULL; 1292 1293 id = ida_simple_get(&typec_index_ida, 0, 0, GFP_KERNEL); 1294 if (id < 0) { 1295 kfree(port); 1296 return NULL; 1297 } 1298 1299 if (cap->type == TYPEC_PORT_DFP) 1300 role = TYPEC_SOURCE; 1301 else if (cap->type == TYPEC_PORT_UFP) 1302 role = TYPEC_SINK; 1303 else 1304 role = cap->prefer_role; 1305 1306 if (role == TYPEC_SOURCE) { 1307 port->data_role = TYPEC_HOST; 1308 port->pwr_role = TYPEC_SOURCE; 1309 port->vconn_role = TYPEC_SOURCE; 1310 } else { 1311 port->data_role = TYPEC_DEVICE; 1312 port->pwr_role = TYPEC_SINK; 1313 port->vconn_role = TYPEC_SINK; 1314 } 1315 1316 port->id = id; 1317 port->cap = cap; 1318 port->port_type = cap->type; 1319 mutex_init(&port->port_type_lock); 1320 port->prefer_role = cap->prefer_role; 1321 1322 port->dev.class = typec_class; 1323 port->dev.parent = parent; 1324 port->dev.fwnode = cap->fwnode; 1325 port->dev.type = &typec_port_dev_type; 1326 dev_set_name(&port->dev, "port%d", id); 1327 1328 ret = device_register(&port->dev); 1329 if (ret) { 1330 dev_err(parent, "failed to register port (%d)\n", ret); 1331 put_device(&port->dev); 1332 return NULL; 1333 } 1334 1335 return port; 1336} 1337EXPORT_SYMBOL_GPL(typec_register_port); 1338 1339/** 1340 * typec_unregister_port - Unregister a USB Type-C Port 1341 * @port: The port to be unregistered 1342 * 1343 * Unregister device created with typec_register_port(). 1344 */ 1345void typec_unregister_port(struct typec_port *port) 1346{ 1347 if (port) 1348 device_unregister(&port->dev); 1349} 1350EXPORT_SYMBOL_GPL(typec_unregister_port); 1351 1352static int __init typec_init(void) 1353{ 1354 typec_class = class_create(THIS_MODULE, "typec"); 1355 return PTR_ERR_OR_ZERO(typec_class); 1356} 1357subsys_initcall(typec_init); 1358 1359static void __exit typec_exit(void) 1360{ 1361 class_destroy(typec_class); 1362 ida_destroy(&typec_index_ida); 1363} 1364module_exit(typec_exit); 1365 1366MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>"); 1367MODULE_LICENSE("GPL v2"); 1368MODULE_DESCRIPTION("USB Type-C Connector Class");