linux/drivers/usb/typec/class.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * USB Type-C Connector Class
   4 *
   5 * Copyright (C) 2017, Intel Corporation
   6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
   7 */
   8
   9#include <linux/device.h>
  10#include <linux/module.h>
  11#include <linux/mutex.h>
  12#include <linux/property.h>
  13#include <linux/slab.h>
  14
  15#include "bus.h"
  16
  17struct typec_plug {
  18        struct device                   dev;
  19        enum typec_plug_index           index;
  20        struct ida                      mode_ids;
  21};
  22
  23struct typec_cable {
  24        struct device                   dev;
  25        enum typec_plug_type            type;
  26        struct usb_pd_identity          *identity;
  27        unsigned int                    active:1;
  28};
  29
  30struct typec_partner {
  31        struct device                   dev;
  32        unsigned int                    usb_pd:1;
  33        struct usb_pd_identity          *identity;
  34        enum typec_accessory            accessory;
  35        struct ida                      mode_ids;
  36};
  37
  38struct typec_port {
  39        unsigned int                    id;
  40        struct device                   dev;
  41        struct ida                      mode_ids;
  42
  43        int                             prefer_role;
  44        enum typec_data_role            data_role;
  45        enum typec_role                 pwr_role;
  46        enum typec_role                 vconn_role;
  47        enum typec_pwr_opmode           pwr_opmode;
  48        enum typec_port_type            port_type;
  49        struct mutex                    port_type_lock;
  50
  51        enum typec_orientation          orientation;
  52        struct typec_switch             *sw;
  53        struct typec_mux                *mux;
  54
  55        const struct typec_capability   *cap;
  56};
  57
  58#define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
  59#define to_typec_plug(_dev_) container_of(_dev_, struct typec_plug, dev)
  60#define to_typec_cable(_dev_) container_of(_dev_, struct typec_cable, dev)
  61#define to_typec_partner(_dev_) container_of(_dev_, struct typec_partner, dev)
  62
  63static const struct device_type typec_partner_dev_type;
  64static const struct device_type typec_cable_dev_type;
  65static const struct device_type typec_plug_dev_type;
  66
  67#define is_typec_partner(_dev_) (_dev_->type == &typec_partner_dev_type)
  68#define is_typec_cable(_dev_) (_dev_->type == &typec_cable_dev_type)
  69#define is_typec_plug(_dev_) (_dev_->type == &typec_plug_dev_type)
  70
  71static DEFINE_IDA(typec_index_ida);
  72static struct class *typec_class;
  73
  74/* ------------------------------------------------------------------------- */
  75/* Common attributes */
  76
  77static const char * const typec_accessory_modes[] = {
  78        [TYPEC_ACCESSORY_NONE]          = "none",
  79        [TYPEC_ACCESSORY_AUDIO]         = "analog_audio",
  80        [TYPEC_ACCESSORY_DEBUG]         = "debug",
  81};
  82
  83static struct usb_pd_identity *get_pd_identity(struct device *dev)
  84{
  85        if (is_typec_partner(dev)) {
  86                struct typec_partner *partner = to_typec_partner(dev);
  87
  88                return partner->identity;
  89        } else if (is_typec_cable(dev)) {
  90                struct typec_cable *cable = to_typec_cable(dev);
  91
  92                return cable->identity;
  93        }
  94        return NULL;
  95}
  96
  97static ssize_t id_header_show(struct device *dev, struct device_attribute *attr,
  98                              char *buf)
  99{
 100        struct usb_pd_identity *id = get_pd_identity(dev);
 101
 102        return sprintf(buf, "0x%08x\n", id->id_header);
 103}
 104static DEVICE_ATTR_RO(id_header);
 105
 106static ssize_t cert_stat_show(struct device *dev, struct device_attribute *attr,
 107                              char *buf)
 108{
 109        struct usb_pd_identity *id = get_pd_identity(dev);
 110
 111        return sprintf(buf, "0x%08x\n", id->cert_stat);
 112}
 113static DEVICE_ATTR_RO(cert_stat);
 114
 115static ssize_t product_show(struct device *dev, struct device_attribute *attr,
 116                            char *buf)
 117{
 118        struct usb_pd_identity *id = get_pd_identity(dev);
 119
 120        return sprintf(buf, "0x%08x\n", id->product);
 121}
 122static DEVICE_ATTR_RO(product);
 123
 124static struct attribute *usb_pd_id_attrs[] = {
 125        &dev_attr_id_header.attr,
 126        &dev_attr_cert_stat.attr,
 127        &dev_attr_product.attr,
 128        NULL
 129};
 130
 131static const struct attribute_group usb_pd_id_group = {
 132        .name = "identity",
 133        .attrs = usb_pd_id_attrs,
 134};
 135
 136static const struct attribute_group *usb_pd_id_groups[] = {
 137        &usb_pd_id_group,
 138        NULL,
 139};
 140
 141static void typec_report_identity(struct device *dev)
 142{
 143        sysfs_notify(&dev->kobj, "identity", "id_header");
 144        sysfs_notify(&dev->kobj, "identity", "cert_stat");
 145        sysfs_notify(&dev->kobj, "identity", "product");
 146}
 147
 148/* ------------------------------------------------------------------------- */
 149/* Alternate Modes */
 150
 151static int altmode_match(struct device *dev, void *data)
 152{
 153        struct typec_altmode *adev = to_typec_altmode(dev);
 154        struct typec_device_id *id = data;
 155
 156        if (!is_typec_altmode(dev))
 157                return 0;
 158
 159        return ((adev->svid == id->svid) && (adev->mode == id->mode));
 160}
 161
 162static void typec_altmode_set_partner(struct altmode *altmode)
 163{
 164        struct typec_altmode *adev = &altmode->adev;
 165        struct typec_device_id id = { adev->svid, adev->mode, };
 166        struct typec_port *port = typec_altmode2port(adev);
 167        struct altmode *partner;
 168        struct device *dev;
 169
 170        dev = device_find_child(&port->dev, &id, altmode_match);
 171        if (!dev)
 172                return;
 173
 174        /* Bind the port alt mode to the partner/plug alt mode. */
 175        partner = to_altmode(to_typec_altmode(dev));
 176        altmode->partner = partner;
 177
 178        /* Bind the partner/plug alt mode to the port alt mode. */
 179        if (is_typec_plug(adev->dev.parent)) {
 180                struct typec_plug *plug = to_typec_plug(adev->dev.parent);
 181
 182                partner->plug[plug->index] = altmode;
 183        } else {
 184                partner->partner = altmode;
 185        }
 186}
 187
 188static void typec_altmode_put_partner(struct altmode *altmode)
 189{
 190        struct altmode *partner = altmode->partner;
 191        struct typec_altmode *adev;
 192
 193        if (!partner)
 194                return;
 195
 196        adev = &partner->adev;
 197
 198        if (is_typec_plug(adev->dev.parent)) {
 199                struct typec_plug *plug = to_typec_plug(adev->dev.parent);
 200
 201                partner->plug[plug->index] = NULL;
 202        } else {
 203                partner->partner = NULL;
 204        }
 205        put_device(&adev->dev);
 206}
 207
 208static int typec_port_fwnode_match(struct device *dev, const void *fwnode)
 209{
 210        return dev_fwnode(dev) == fwnode;
 211}
 212
 213static int typec_port_name_match(struct device *dev, const void *name)
 214{
 215        return !strcmp((const char *)name, dev_name(dev));
 216}
 217
 218static void *typec_port_match(struct device_connection *con, int ep, void *data)
 219{
 220        struct device *dev;
 221
 222        /*
 223         * FIXME: Check does the fwnode supports the requested SVID. If it does
 224         * we need to return ERR_PTR(-PROBE_DEFER) when there is no device.
 225         */
 226        if (con->fwnode)
 227                return class_find_device(typec_class, NULL, con->fwnode,
 228                                         typec_port_fwnode_match);
 229
 230        dev = class_find_device(typec_class, NULL, con->endpoint[ep],
 231                                typec_port_name_match);
 232
 233        return dev ? dev : ERR_PTR(-EPROBE_DEFER);
 234}
 235
 236struct typec_altmode *
 237typec_altmode_register_notifier(struct device *dev, u16 svid, u8 mode,
 238                                struct notifier_block *nb)
 239{
 240        struct typec_device_id id = { svid, mode, };
 241        struct device *altmode_dev;
 242        struct device *port_dev;
 243        struct altmode *altmode;
 244        int ret;
 245
 246        /* Find the port linked to the caller */
 247        port_dev = device_connection_find_match(dev, NULL, NULL,
 248                                                typec_port_match);
 249        if (IS_ERR_OR_NULL(port_dev))
 250                return port_dev ? ERR_CAST(port_dev) : ERR_PTR(-ENODEV);
 251
 252        /* Find the altmode with matching svid */
 253        altmode_dev = device_find_child(port_dev, &id, altmode_match);
 254
 255        put_device(port_dev);
 256
 257        if (!altmode_dev)
 258                return ERR_PTR(-ENODEV);
 259
 260        altmode = to_altmode(to_typec_altmode(altmode_dev));
 261
 262        /* Register notifier */
 263        ret = blocking_notifier_chain_register(&altmode->nh, nb);
 264        if (ret) {
 265                put_device(altmode_dev);
 266                return ERR_PTR(ret);
 267        }
 268
 269        return &altmode->adev;
 270}
 271EXPORT_SYMBOL_GPL(typec_altmode_register_notifier);
 272
 273void typec_altmode_unregister_notifier(struct typec_altmode *adev,
 274                                       struct notifier_block *nb)
 275{
 276        struct altmode *altmode = to_altmode(adev);
 277
 278        blocking_notifier_chain_unregister(&altmode->nh, nb);
 279        put_device(&adev->dev);
 280}
 281EXPORT_SYMBOL_GPL(typec_altmode_unregister_notifier);
 282
 283/**
 284 * typec_altmode_update_active - Report Enter/Exit mode
 285 * @adev: Handle to the alternate mode
 286 * @active: True when the mode has been entered
 287 *
 288 * If a partner or cable plug executes Enter/Exit Mode command successfully, the
 289 * drivers use this routine to report the updated state of the mode.
 290 */
 291void typec_altmode_update_active(struct typec_altmode *adev, bool active)
 292{
 293        char dir[6];
 294
 295        if (adev->active == active)
 296                return;
 297
 298        if (!is_typec_port(adev->dev.parent) && adev->dev.driver) {
 299                if (!active)
 300                        module_put(adev->dev.driver->owner);
 301                else
 302                        WARN_ON(!try_module_get(adev->dev.driver->owner));
 303        }
 304
 305        adev->active = active;
 306        snprintf(dir, sizeof(dir), "mode%d", adev->mode);
 307        sysfs_notify(&adev->dev.kobj, dir, "active");
 308        sysfs_notify(&adev->dev.kobj, NULL, "active");
 309        kobject_uevent(&adev->dev.kobj, KOBJ_CHANGE);
 310}
 311EXPORT_SYMBOL_GPL(typec_altmode_update_active);
 312
 313/**
 314 * typec_altmode2port - Alternate Mode to USB Type-C port
 315 * @alt: The Alternate Mode
 316 *
 317 * Returns handle to the port that a cable plug or partner with @alt is
 318 * connected to.
 319 */
 320struct typec_port *typec_altmode2port(struct typec_altmode *alt)
 321{
 322        if (is_typec_plug(alt->dev.parent))
 323                return to_typec_port(alt->dev.parent->parent->parent);
 324        if (is_typec_partner(alt->dev.parent))
 325                return to_typec_port(alt->dev.parent->parent);
 326        if (is_typec_port(alt->dev.parent))
 327                return to_typec_port(alt->dev.parent);
 328
 329        return NULL;
 330}
 331EXPORT_SYMBOL_GPL(typec_altmode2port);
 332
 333static ssize_t
 334vdo_show(struct device *dev, struct device_attribute *attr, char *buf)
 335{
 336        struct typec_altmode *alt = to_typec_altmode(dev);
 337
 338        return sprintf(buf, "0x%08x\n", alt->vdo);
 339}
 340static DEVICE_ATTR_RO(vdo);
 341
 342static ssize_t
 343description_show(struct device *dev, struct device_attribute *attr, char *buf)
 344{
 345        struct typec_altmode *alt = to_typec_altmode(dev);
 346
 347        return sprintf(buf, "%s\n", alt->desc ? alt->desc : "");
 348}
 349static DEVICE_ATTR_RO(description);
 350
 351static ssize_t
 352active_show(struct device *dev, struct device_attribute *attr, char *buf)
 353{
 354        struct typec_altmode *alt = to_typec_altmode(dev);
 355
 356        return sprintf(buf, "%s\n", alt->active ? "yes" : "no");
 357}
 358
 359static ssize_t active_store(struct device *dev, struct device_attribute *attr,
 360                            const char *buf, size_t size)
 361{
 362        struct typec_altmode *adev = to_typec_altmode(dev);
 363        struct altmode *altmode = to_altmode(adev);
 364        bool enter;
 365        int ret;
 366
 367        ret = kstrtobool(buf, &enter);
 368        if (ret)
 369                return ret;
 370
 371        if (adev->active == enter)
 372                return size;
 373
 374        if (is_typec_port(adev->dev.parent)) {
 375                typec_altmode_update_active(adev, enter);
 376
 377                /* Make sure that the partner exits the mode before disabling */
 378                if (altmode->partner && !enter && altmode->partner->adev.active)
 379                        typec_altmode_exit(&altmode->partner->adev);
 380        } else if (altmode->partner) {
 381                if (enter && !altmode->partner->adev.active) {
 382                        dev_warn(dev, "port has the mode disabled\n");
 383                        return -EPERM;
 384                }
 385        }
 386
 387        /* Note: If there is no driver, the mode will not be entered */
 388        if (adev->ops && adev->ops->activate) {
 389                ret = adev->ops->activate(adev, enter);
 390                if (ret)
 391                        return ret;
 392        }
 393
 394        return size;
 395}
 396static DEVICE_ATTR_RW(active);
 397
 398static ssize_t
 399supported_roles_show(struct device *dev, struct device_attribute *attr,
 400                     char *buf)
 401{
 402        struct altmode *alt = to_altmode(to_typec_altmode(dev));
 403        ssize_t ret;
 404
 405        switch (alt->roles) {
 406        case TYPEC_PORT_SRC:
 407                ret = sprintf(buf, "source\n");
 408                break;
 409        case TYPEC_PORT_SNK:
 410                ret = sprintf(buf, "sink\n");
 411                break;
 412        case TYPEC_PORT_DRP:
 413        default:
 414                ret = sprintf(buf, "source sink\n");
 415                break;
 416        }
 417        return ret;
 418}
 419static DEVICE_ATTR_RO(supported_roles);
 420
 421static ssize_t
 422mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 423{
 424        struct typec_altmode *adev = to_typec_altmode(dev);
 425
 426        return sprintf(buf, "%u\n", adev->mode);
 427}
 428static DEVICE_ATTR_RO(mode);
 429
 430static ssize_t
 431svid_show(struct device *dev, struct device_attribute *attr, char *buf)
 432{
 433        struct typec_altmode *adev = to_typec_altmode(dev);
 434
 435        return sprintf(buf, "%04x\n", adev->svid);
 436}
 437static DEVICE_ATTR_RO(svid);
 438
 439static struct attribute *typec_altmode_attrs[] = {
 440        &dev_attr_active.attr,
 441        &dev_attr_mode.attr,
 442        &dev_attr_svid.attr,
 443        &dev_attr_vdo.attr,
 444        NULL
 445};
 446ATTRIBUTE_GROUPS(typec_altmode);
 447
 448static int altmode_id_get(struct device *dev)
 449{
 450        struct ida *ids;
 451
 452        if (is_typec_partner(dev))
 453                ids = &to_typec_partner(dev)->mode_ids;
 454        else if (is_typec_plug(dev))
 455                ids = &to_typec_plug(dev)->mode_ids;
 456        else
 457                ids = &to_typec_port(dev)->mode_ids;
 458
 459        return ida_simple_get(ids, 0, 0, GFP_KERNEL);
 460}
 461
 462static void altmode_id_remove(struct device *dev, int id)
 463{
 464        struct ida *ids;
 465
 466        if (is_typec_partner(dev))
 467                ids = &to_typec_partner(dev)->mode_ids;
 468        else if (is_typec_plug(dev))
 469                ids = &to_typec_plug(dev)->mode_ids;
 470        else
 471                ids = &to_typec_port(dev)->mode_ids;
 472
 473        ida_simple_remove(ids, id);
 474}
 475
 476static void typec_altmode_release(struct device *dev)
 477{
 478        struct altmode *alt = to_altmode(to_typec_altmode(dev));
 479
 480        typec_altmode_put_partner(alt);
 481
 482        altmode_id_remove(alt->adev.dev.parent, alt->id);
 483        kfree(alt);
 484}
 485
 486const struct device_type typec_altmode_dev_type = {
 487        .name = "typec_alternate_mode",
 488        .groups = typec_altmode_groups,
 489        .release = typec_altmode_release,
 490};
 491
 492static struct typec_altmode *
 493typec_register_altmode(struct device *parent,
 494                       const struct typec_altmode_desc *desc)
 495{
 496        unsigned int id = altmode_id_get(parent);
 497        bool is_port = is_typec_port(parent);
 498        struct altmode *alt;
 499        int ret;
 500
 501        alt = kzalloc(sizeof(*alt), GFP_KERNEL);
 502        if (!alt)
 503                return ERR_PTR(-ENOMEM);
 504
 505        alt->adev.svid = desc->svid;
 506        alt->adev.mode = desc->mode;
 507        alt->adev.vdo = desc->vdo;
 508        alt->roles = desc->roles;
 509        alt->id = id;
 510
 511        alt->attrs[0] = &dev_attr_vdo.attr;
 512        alt->attrs[1] = &dev_attr_description.attr;
 513        alt->attrs[2] = &dev_attr_active.attr;
 514
 515        if (is_port) {
 516                alt->attrs[3] = &dev_attr_supported_roles.attr;
 517                alt->adev.active = true; /* Enabled by default */
 518        }
 519
 520        sprintf(alt->group_name, "mode%d", desc->mode);
 521        alt->group.name = alt->group_name;
 522        alt->group.attrs = alt->attrs;
 523        alt->groups[0] = &alt->group;
 524
 525        alt->adev.dev.parent = parent;
 526        alt->adev.dev.groups = alt->groups;
 527        alt->adev.dev.type = &typec_altmode_dev_type;
 528        dev_set_name(&alt->adev.dev, "%s.%u", dev_name(parent), id);
 529
 530        /* Link partners and plugs with the ports */
 531        if (is_port)
 532                BLOCKING_INIT_NOTIFIER_HEAD(&alt->nh);
 533        else
 534                typec_altmode_set_partner(alt);
 535
 536        /* The partners are bind to drivers */
 537        if (is_typec_partner(parent))
 538                alt->adev.dev.bus = &typec_bus;
 539
 540        ret = device_register(&alt->adev.dev);
 541        if (ret) {
 542                dev_err(parent, "failed to register alternate mode (%d)\n",
 543                        ret);
 544                put_device(&alt->adev.dev);
 545                return ERR_PTR(ret);
 546        }
 547
 548        return &alt->adev;
 549}
 550
 551/**
 552 * typec_unregister_altmode - Unregister Alternate Mode
 553 * @adev: The alternate mode to be unregistered
 554 *
 555 * Unregister device created with typec_partner_register_altmode(),
 556 * typec_plug_register_altmode() or typec_port_register_altmode().
 557 */
 558void typec_unregister_altmode(struct typec_altmode *adev)
 559{
 560        if (IS_ERR_OR_NULL(adev))
 561                return;
 562        typec_mux_put(to_altmode(adev)->mux);
 563        device_unregister(&adev->dev);
 564}
 565EXPORT_SYMBOL_GPL(typec_unregister_altmode);
 566
 567/* ------------------------------------------------------------------------- */
 568/* Type-C Partners */
 569
 570static ssize_t accessory_mode_show(struct device *dev,
 571                                   struct device_attribute *attr,
 572                                   char *buf)
 573{
 574        struct typec_partner *p = to_typec_partner(dev);
 575
 576        return sprintf(buf, "%s\n", typec_accessory_modes[p->accessory]);
 577}
 578static DEVICE_ATTR_RO(accessory_mode);
 579
 580static ssize_t supports_usb_power_delivery_show(struct device *dev,
 581                                                struct device_attribute *attr,
 582                                                char *buf)
 583{
 584        struct typec_partner *p = to_typec_partner(dev);
 585
 586        return sprintf(buf, "%s\n", p->usb_pd ? "yes" : "no");
 587}
 588static DEVICE_ATTR_RO(supports_usb_power_delivery);
 589
 590static struct attribute *typec_partner_attrs[] = {
 591        &dev_attr_accessory_mode.attr,
 592        &dev_attr_supports_usb_power_delivery.attr,
 593        NULL
 594};
 595ATTRIBUTE_GROUPS(typec_partner);
 596
 597static void typec_partner_release(struct device *dev)
 598{
 599        struct typec_partner *partner = to_typec_partner(dev);
 600
 601        ida_destroy(&partner->mode_ids);
 602        kfree(partner);
 603}
 604
 605static const struct device_type typec_partner_dev_type = {
 606        .name = "typec_partner",
 607        .groups = typec_partner_groups,
 608        .release = typec_partner_release,
 609};
 610
 611/**
 612 * typec_partner_set_identity - Report result from Discover Identity command
 613 * @partner: The partner updated identity values
 614 *
 615 * This routine is used to report that the result of Discover Identity USB power
 616 * delivery command has become available.
 617 */
 618int typec_partner_set_identity(struct typec_partner *partner)
 619{
 620        if (!partner->identity)
 621                return -EINVAL;
 622
 623        typec_report_identity(&partner->dev);
 624        return 0;
 625}
 626EXPORT_SYMBOL_GPL(typec_partner_set_identity);
 627
 628/**
 629 * typec_partner_register_altmode - Register USB Type-C Partner Alternate Mode
 630 * @partner: USB Type-C Partner that supports the alternate mode
 631 * @desc: Description of the alternate mode
 632 *
 633 * This routine is used to register each alternate mode individually that
 634 * @partner has listed in response to Discover SVIDs command. The modes for a
 635 * SVID listed in response to Discover Modes command need to be listed in an
 636 * array in @desc.
 637 *
 638 * Returns handle to the alternate mode on success or NULL on failure.
 639 */
 640struct typec_altmode *
 641typec_partner_register_altmode(struct typec_partner *partner,
 642                               const struct typec_altmode_desc *desc)
 643{
 644        return typec_register_altmode(&partner->dev, desc);
 645}
 646EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
 647
 648/**
 649 * typec_register_partner - Register a USB Type-C Partner
 650 * @port: The USB Type-C Port the partner is connected to
 651 * @desc: Description of the partner
 652 *
 653 * Registers a device for USB Type-C Partner described in @desc.
 654 *
 655 * Returns handle to the partner on success or ERR_PTR on failure.
 656 */
 657struct typec_partner *typec_register_partner(struct typec_port *port,
 658                                             struct typec_partner_desc *desc)
 659{
 660        struct typec_partner *partner;
 661        int ret;
 662
 663        partner = kzalloc(sizeof(*partner), GFP_KERNEL);
 664        if (!partner)
 665                return ERR_PTR(-ENOMEM);
 666
 667        ida_init(&partner->mode_ids);
 668        partner->usb_pd = desc->usb_pd;
 669        partner->accessory = desc->accessory;
 670
 671        if (desc->identity) {
 672                /*
 673                 * Creating directory for the identity only if the driver is
 674                 * able to provide data to it.
 675                 */
 676                partner->dev.groups = usb_pd_id_groups;
 677                partner->identity = desc->identity;
 678        }
 679
 680        partner->dev.class = typec_class;
 681        partner->dev.parent = &port->dev;
 682        partner->dev.type = &typec_partner_dev_type;
 683        dev_set_name(&partner->dev, "%s-partner", dev_name(&port->dev));
 684
 685        ret = device_register(&partner->dev);
 686        if (ret) {
 687                dev_err(&port->dev, "failed to register partner (%d)\n", ret);
 688                put_device(&partner->dev);
 689                return ERR_PTR(ret);
 690        }
 691
 692        return partner;
 693}
 694EXPORT_SYMBOL_GPL(typec_register_partner);
 695
 696/**
 697 * typec_unregister_partner - Unregister a USB Type-C Partner
 698 * @partner: The partner to be unregistered
 699 *
 700 * Unregister device created with typec_register_partner().
 701 */
 702void typec_unregister_partner(struct typec_partner *partner)
 703{
 704        if (!IS_ERR_OR_NULL(partner))
 705                device_unregister(&partner->dev);
 706}
 707EXPORT_SYMBOL_GPL(typec_unregister_partner);
 708
 709/* ------------------------------------------------------------------------- */
 710/* Type-C Cable Plugs */
 711
 712static void typec_plug_release(struct device *dev)
 713{
 714        struct typec_plug *plug = to_typec_plug(dev);
 715
 716        ida_destroy(&plug->mode_ids);
 717        kfree(plug);
 718}
 719
 720static const struct device_type typec_plug_dev_type = {
 721        .name = "typec_plug",
 722        .release = typec_plug_release,
 723};
 724
 725/**
 726 * typec_plug_register_altmode - Register USB Type-C Cable Plug Alternate Mode
 727 * @plug: USB Type-C Cable Plug that supports the alternate mode
 728 * @desc: Description of the alternate mode
 729 *
 730 * This routine is used to register each alternate mode individually that @plug
 731 * has listed in response to Discover SVIDs command. The modes for a SVID that
 732 * the plug lists in response to Discover Modes command need to be listed in an
 733 * array in @desc.
 734 *
 735 * Returns handle to the alternate mode on success or ERR_PTR on failure.
 736 */
 737struct typec_altmode *
 738typec_plug_register_altmode(struct typec_plug *plug,
 739                            const struct typec_altmode_desc *desc)
 740{
 741        return typec_register_altmode(&plug->dev, desc);
 742}
 743EXPORT_SYMBOL_GPL(typec_plug_register_altmode);
 744
 745/**
 746 * typec_register_plug - Register a USB Type-C Cable Plug
 747 * @cable: USB Type-C Cable with the plug
 748 * @desc: Description of the cable plug
 749 *
 750 * Registers a device for USB Type-C Cable Plug described in @desc. A USB Type-C
 751 * Cable Plug represents a plug with electronics in it that can response to USB
 752 * Power Delivery SOP Prime or SOP Double Prime packages.
 753 *
 754 * Returns handle to the cable plug on success or ERR_PTR on failure.
 755 */
 756struct typec_plug *typec_register_plug(struct typec_cable *cable,
 757                                       struct typec_plug_desc *desc)
 758{
 759        struct typec_plug *plug;
 760        char name[8];
 761        int ret;
 762
 763        plug = kzalloc(sizeof(*plug), GFP_KERNEL);
 764        if (!plug)
 765                return ERR_PTR(-ENOMEM);
 766
 767        sprintf(name, "plug%d", desc->index);
 768
 769        ida_init(&plug->mode_ids);
 770        plug->index = desc->index;
 771        plug->dev.class = typec_class;
 772        plug->dev.parent = &cable->dev;
 773        plug->dev.type = &typec_plug_dev_type;
 774        dev_set_name(&plug->dev, "%s-%s", dev_name(cable->dev.parent), name);
 775
 776        ret = device_register(&plug->dev);
 777        if (ret) {
 778                dev_err(&cable->dev, "failed to register plug (%d)\n", ret);
 779                put_device(&plug->dev);
 780                return ERR_PTR(ret);
 781        }
 782
 783        return plug;
 784}
 785EXPORT_SYMBOL_GPL(typec_register_plug);
 786
 787/**
 788 * typec_unregister_plug - Unregister a USB Type-C Cable Plug
 789 * @plug: The cable plug to be unregistered
 790 *
 791 * Unregister device created with typec_register_plug().
 792 */
 793void typec_unregister_plug(struct typec_plug *plug)
 794{
 795        if (!IS_ERR_OR_NULL(plug))
 796                device_unregister(&plug->dev);
 797}
 798EXPORT_SYMBOL_GPL(typec_unregister_plug);
 799
 800/* Type-C Cables */
 801
 802static ssize_t
 803type_show(struct device *dev, struct device_attribute *attr, char *buf)
 804{
 805        struct typec_cable *cable = to_typec_cable(dev);
 806
 807        return sprintf(buf, "%s\n", cable->active ? "active" : "passive");
 808}
 809static DEVICE_ATTR_RO(type);
 810
 811static const char * const typec_plug_types[] = {
 812        [USB_PLUG_NONE]         = "unknown",
 813        [USB_PLUG_TYPE_A]       = "type-a",
 814        [USB_PLUG_TYPE_B]       = "type-b",
 815        [USB_PLUG_TYPE_C]       = "type-c",
 816        [USB_PLUG_CAPTIVE]      = "captive",
 817};
 818
 819static ssize_t plug_type_show(struct device *dev,
 820                              struct device_attribute *attr, char *buf)
 821{
 822        struct typec_cable *cable = to_typec_cable(dev);
 823
 824        return sprintf(buf, "%s\n", typec_plug_types[cable->type]);
 825}
 826static DEVICE_ATTR_RO(plug_type);
 827
 828static struct attribute *typec_cable_attrs[] = {
 829        &dev_attr_type.attr,
 830        &dev_attr_plug_type.attr,
 831        NULL
 832};
 833ATTRIBUTE_GROUPS(typec_cable);
 834
 835static void typec_cable_release(struct device *dev)
 836{
 837        struct typec_cable *cable = to_typec_cable(dev);
 838
 839        kfree(cable);
 840}
 841
 842static const struct device_type typec_cable_dev_type = {
 843        .name = "typec_cable",
 844        .groups = typec_cable_groups,
 845        .release = typec_cable_release,
 846};
 847
 848/**
 849 * typec_cable_set_identity - Report result from Discover Identity command
 850 * @cable: The cable updated identity values
 851 *
 852 * This routine is used to report that the result of Discover Identity USB power
 853 * delivery command has become available.
 854 */
 855int typec_cable_set_identity(struct typec_cable *cable)
 856{
 857        if (!cable->identity)
 858                return -EINVAL;
 859
 860        typec_report_identity(&cable->dev);
 861        return 0;
 862}
 863EXPORT_SYMBOL_GPL(typec_cable_set_identity);
 864
 865/**
 866 * typec_register_cable - Register a USB Type-C Cable
 867 * @port: The USB Type-C Port the cable is connected to
 868 * @desc: Description of the cable
 869 *
 870 * Registers a device for USB Type-C Cable described in @desc. The cable will be
 871 * parent for the optional cable plug devises.
 872 *
 873 * Returns handle to the cable on success or ERR_PTR on failure.
 874 */
 875struct typec_cable *typec_register_cable(struct typec_port *port,
 876                                         struct typec_cable_desc *desc)
 877{
 878        struct typec_cable *cable;
 879        int ret;
 880
 881        cable = kzalloc(sizeof(*cable), GFP_KERNEL);
 882        if (!cable)
 883                return ERR_PTR(-ENOMEM);
 884
 885        cable->type = desc->type;
 886        cable->active = desc->active;
 887
 888        if (desc->identity) {
 889                /*
 890                 * Creating directory for the identity only if the driver is
 891                 * able to provide data to it.
 892                 */
 893                cable->dev.groups = usb_pd_id_groups;
 894                cable->identity = desc->identity;
 895        }
 896
 897        cable->dev.class = typec_class;
 898        cable->dev.parent = &port->dev;
 899        cable->dev.type = &typec_cable_dev_type;
 900        dev_set_name(&cable->dev, "%s-cable", dev_name(&port->dev));
 901
 902        ret = device_register(&cable->dev);
 903        if (ret) {
 904                dev_err(&port->dev, "failed to register cable (%d)\n", ret);
 905                put_device(&cable->dev);
 906                return ERR_PTR(ret);
 907        }
 908
 909        return cable;
 910}
 911EXPORT_SYMBOL_GPL(typec_register_cable);
 912
 913/**
 914 * typec_unregister_cable - Unregister a USB Type-C Cable
 915 * @cable: The cable to be unregistered
 916 *
 917 * Unregister device created with typec_register_cable().
 918 */
 919void typec_unregister_cable(struct typec_cable *cable)
 920{
 921        if (!IS_ERR_OR_NULL(cable))
 922                device_unregister(&cable->dev);
 923}
 924EXPORT_SYMBOL_GPL(typec_unregister_cable);
 925
 926/* ------------------------------------------------------------------------- */
 927/* USB Type-C ports */
 928
 929static const char * const typec_roles[] = {
 930        [TYPEC_SINK]    = "sink",
 931        [TYPEC_SOURCE]  = "source",
 932};
 933
 934static const char * const typec_data_roles[] = {
 935        [TYPEC_DEVICE]  = "device",
 936        [TYPEC_HOST]    = "host",
 937};
 938
 939static const char * const typec_port_power_roles[] = {
 940        [TYPEC_PORT_SRC] = "source",
 941        [TYPEC_PORT_SNK] = "sink",
 942        [TYPEC_PORT_DRP] = "dual",
 943};
 944
 945static const char * const typec_port_data_roles[] = {
 946        [TYPEC_PORT_DFP] = "host",
 947        [TYPEC_PORT_UFP] = "device",
 948        [TYPEC_PORT_DRD] = "dual",
 949};
 950
 951static const char * const typec_port_types_drp[] = {
 952        [TYPEC_PORT_SRC] = "dual [source] sink",
 953        [TYPEC_PORT_SNK] = "dual source [sink]",
 954        [TYPEC_PORT_DRP] = "[dual] source sink",
 955};
 956
 957static ssize_t
 958preferred_role_store(struct device *dev, struct device_attribute *attr,
 959                     const char *buf, size_t size)
 960{
 961        struct typec_port *port = to_typec_port(dev);
 962        int role;
 963        int ret;
 964
 965        if (port->cap->type != TYPEC_PORT_DRP) {
 966                dev_dbg(dev, "Preferred role only supported with DRP ports\n");
 967                return -EOPNOTSUPP;
 968        }
 969
 970        if (!port->cap->try_role) {
 971                dev_dbg(dev, "Setting preferred role not supported\n");
 972                return -EOPNOTSUPP;
 973        }
 974
 975        role = sysfs_match_string(typec_roles, buf);
 976        if (role < 0) {
 977                if (sysfs_streq(buf, "none"))
 978                        role = TYPEC_NO_PREFERRED_ROLE;
 979                else
 980                        return -EINVAL;
 981        }
 982
 983        ret = port->cap->try_role(port->cap, role);
 984        if (ret)
 985                return ret;
 986
 987        port->prefer_role = role;
 988        return size;
 989}
 990
 991static ssize_t
 992preferred_role_show(struct device *dev, struct device_attribute *attr,
 993                    char *buf)
 994{
 995        struct typec_port *port = to_typec_port(dev);
 996
 997        if (port->cap->type != TYPEC_PORT_DRP)
 998                return 0;
 999
1000        if (port->prefer_role < 0)
1001                return 0;
1002
1003        return sprintf(buf, "%s\n", typec_roles[port->prefer_role]);
1004}
1005static DEVICE_ATTR_RW(preferred_role);
1006
1007static ssize_t data_role_store(struct device *dev,
1008                               struct device_attribute *attr,
1009                               const char *buf, size_t size)
1010{
1011        struct typec_port *port = to_typec_port(dev);
1012        int ret;
1013
1014        if (!port->cap->dr_set) {
1015                dev_dbg(dev, "data role swapping not supported\n");
1016                return -EOPNOTSUPP;
1017        }
1018
1019        ret = sysfs_match_string(typec_data_roles, buf);
1020        if (ret < 0)
1021                return ret;
1022
1023        mutex_lock(&port->port_type_lock);
1024        if (port->cap->data != TYPEC_PORT_DRD) {
1025                ret = -EOPNOTSUPP;
1026                goto unlock_and_ret;
1027        }
1028
1029        ret = port->cap->dr_set(port->cap, ret);
1030        if (ret)
1031                goto unlock_and_ret;
1032
1033        ret = size;
1034unlock_and_ret:
1035        mutex_unlock(&port->port_type_lock);
1036        return ret;
1037}
1038
1039static ssize_t data_role_show(struct device *dev,
1040                              struct device_attribute *attr, char *buf)
1041{
1042        struct typec_port *port = to_typec_port(dev);
1043
1044        if (port->cap->data == TYPEC_PORT_DRD)
1045                return sprintf(buf, "%s\n", port->data_role == TYPEC_HOST ?
1046                               "[host] device" : "host [device]");
1047
1048        return sprintf(buf, "[%s]\n", typec_data_roles[port->data_role]);
1049}
1050static DEVICE_ATTR_RW(data_role);
1051
1052static ssize_t power_role_store(struct device *dev,
1053                                struct device_attribute *attr,
1054                                const char *buf, size_t size)
1055{
1056        struct typec_port *port = to_typec_port(dev);
1057        int ret;
1058
1059        if (!port->cap->pd_revision) {
1060                dev_dbg(dev, "USB Power Delivery not supported\n");
1061                return -EOPNOTSUPP;
1062        }
1063
1064        if (!port->cap->pr_set) {
1065                dev_dbg(dev, "power role swapping not supported\n");
1066                return -EOPNOTSUPP;
1067        }
1068
1069        if (port->pwr_opmode != TYPEC_PWR_MODE_PD) {
1070                dev_dbg(dev, "partner unable to swap power role\n");
1071                return -EIO;
1072        }
1073
1074        ret = sysfs_match_string(typec_roles, buf);
1075        if (ret < 0)
1076                return ret;
1077
1078        mutex_lock(&port->port_type_lock);
1079        if (port->port_type != TYPEC_PORT_DRP) {
1080                dev_dbg(dev, "port type fixed at \"%s\"",
1081                             typec_port_power_roles[port->port_type]);
1082                ret = -EOPNOTSUPP;
1083                goto unlock_and_ret;
1084        }
1085
1086        ret = port->cap->pr_set(port->cap, ret);
1087        if (ret)
1088                goto unlock_and_ret;
1089
1090        ret = size;
1091unlock_and_ret:
1092        mutex_unlock(&port->port_type_lock);
1093        return ret;
1094}
1095
1096static ssize_t power_role_show(struct device *dev,
1097                               struct device_attribute *attr, char *buf)
1098{
1099        struct typec_port *port = to_typec_port(dev);
1100
1101        if (port->cap->type == TYPEC_PORT_DRP)
1102                return sprintf(buf, "%s\n", port->pwr_role == TYPEC_SOURCE ?
1103                               "[source] sink" : "source [sink]");
1104
1105        return sprintf(buf, "[%s]\n", typec_roles[port->pwr_role]);
1106}
1107static DEVICE_ATTR_RW(power_role);
1108
1109static ssize_t
1110port_type_store(struct device *dev, struct device_attribute *attr,
1111                        const char *buf, size_t size)
1112{
1113        struct typec_port *port = to_typec_port(dev);
1114        int ret;
1115        enum typec_port_type type;
1116
1117        if (!port->cap->port_type_set || port->cap->type != TYPEC_PORT_DRP) {
1118                dev_dbg(dev, "changing port type not supported\n");
1119                return -EOPNOTSUPP;
1120        }
1121
1122        ret = sysfs_match_string(typec_port_power_roles, buf);
1123        if (ret < 0)
1124                return ret;
1125
1126        type = ret;
1127        mutex_lock(&port->port_type_lock);
1128
1129        if (port->port_type == type) {
1130                ret = size;
1131                goto unlock_and_ret;
1132        }
1133
1134        ret = port->cap->port_type_set(port->cap, type);
1135        if (ret)
1136                goto unlock_and_ret;
1137
1138        port->port_type = type;
1139        ret = size;
1140
1141unlock_and_ret:
1142        mutex_unlock(&port->port_type_lock);
1143        return ret;
1144}
1145
1146static ssize_t
1147port_type_show(struct device *dev, struct device_attribute *attr,
1148                char *buf)
1149{
1150        struct typec_port *port = to_typec_port(dev);
1151
1152        if (port->cap->type == TYPEC_PORT_DRP)
1153                return sprintf(buf, "%s\n",
1154                               typec_port_types_drp[port->port_type]);
1155
1156        return sprintf(buf, "[%s]\n", typec_port_power_roles[port->cap->type]);
1157}
1158static DEVICE_ATTR_RW(port_type);
1159
1160static const char * const typec_pwr_opmodes[] = {
1161        [TYPEC_PWR_MODE_USB]    = "default",
1162        [TYPEC_PWR_MODE_1_5A]   = "1.5A",
1163        [TYPEC_PWR_MODE_3_0A]   = "3.0A",
1164        [TYPEC_PWR_MODE_PD]     = "usb_power_delivery",
1165};
1166
1167static ssize_t power_operation_mode_show(struct device *dev,
1168                                         struct device_attribute *attr,
1169                                         char *buf)
1170{
1171        struct typec_port *port = to_typec_port(dev);
1172
1173        return sprintf(buf, "%s\n", typec_pwr_opmodes[port->pwr_opmode]);
1174}
1175static DEVICE_ATTR_RO(power_operation_mode);
1176
1177static ssize_t vconn_source_store(struct device *dev,
1178                                  struct device_attribute *attr,
1179                                  const char *buf, size_t size)
1180{
1181        struct typec_port *port = to_typec_port(dev);
1182        bool source;
1183        int ret;
1184
1185        if (!port->cap->pd_revision) {
1186                dev_dbg(dev, "VCONN swap depends on USB Power Delivery\n");
1187                return -EOPNOTSUPP;
1188        }
1189
1190        if (!port->cap->vconn_set) {
1191                dev_dbg(dev, "VCONN swapping not supported\n");
1192                return -EOPNOTSUPP;
1193        }
1194
1195        ret = kstrtobool(buf, &source);
1196        if (ret)
1197                return ret;
1198
1199        ret = port->cap->vconn_set(port->cap, (enum typec_role)source);
1200        if (ret)
1201                return ret;
1202
1203        return size;
1204}
1205
1206static ssize_t vconn_source_show(struct device *dev,
1207                                 struct device_attribute *attr, char *buf)
1208{
1209        struct typec_port *port = to_typec_port(dev);
1210
1211        return sprintf(buf, "%s\n",
1212                       port->vconn_role == TYPEC_SOURCE ? "yes" : "no");
1213}
1214static DEVICE_ATTR_RW(vconn_source);
1215
1216static ssize_t supported_accessory_modes_show(struct device *dev,
1217                                              struct device_attribute *attr,
1218                                              char *buf)
1219{
1220        struct typec_port *port = to_typec_port(dev);
1221        ssize_t ret = 0;
1222        int i;
1223
1224        for (i = 0; i < ARRAY_SIZE(port->cap->accessory); i++) {
1225                if (port->cap->accessory[i])
1226                        ret += sprintf(buf + ret, "%s ",
1227                               typec_accessory_modes[port->cap->accessory[i]]);
1228        }
1229
1230        if (!ret)
1231                return sprintf(buf, "none\n");
1232
1233        buf[ret - 1] = '\n';
1234
1235        return ret;
1236}
1237static DEVICE_ATTR_RO(supported_accessory_modes);
1238
1239static ssize_t usb_typec_revision_show(struct device *dev,
1240                                       struct device_attribute *attr,
1241                                       char *buf)
1242{
1243        struct typec_port *port = to_typec_port(dev);
1244        u16 rev = port->cap->revision;
1245
1246        return sprintf(buf, "%d.%d\n", (rev >> 8) & 0xff, (rev >> 4) & 0xf);
1247}
1248static DEVICE_ATTR_RO(usb_typec_revision);
1249
1250static ssize_t usb_power_delivery_revision_show(struct device *dev,
1251                                                struct device_attribute *attr,
1252                                                char *buf)
1253{
1254        struct typec_port *p = to_typec_port(dev);
1255
1256        return sprintf(buf, "%d\n", (p->cap->pd_revision >> 8) & 0xff);
1257}
1258static DEVICE_ATTR_RO(usb_power_delivery_revision);
1259
1260static struct attribute *typec_attrs[] = {
1261        &dev_attr_data_role.attr,
1262        &dev_attr_power_operation_mode.attr,
1263        &dev_attr_power_role.attr,
1264        &dev_attr_preferred_role.attr,
1265        &dev_attr_supported_accessory_modes.attr,
1266        &dev_attr_usb_power_delivery_revision.attr,
1267        &dev_attr_usb_typec_revision.attr,
1268        &dev_attr_vconn_source.attr,
1269        &dev_attr_port_type.attr,
1270        NULL,
1271};
1272ATTRIBUTE_GROUPS(typec);
1273
1274static int typec_uevent(struct device *dev, struct kobj_uevent_env *env)
1275{
1276        int ret;
1277
1278        ret = add_uevent_var(env, "TYPEC_PORT=%s", dev_name(dev));
1279        if (ret)
1280                dev_err(dev, "failed to add uevent TYPEC_PORT\n");
1281
1282        return ret;
1283}
1284
1285static void typec_release(struct device *dev)
1286{
1287        struct typec_port *port = to_typec_port(dev);
1288
1289        ida_simple_remove(&typec_index_ida, port->id);
1290        ida_destroy(&port->mode_ids);
1291        typec_switch_put(port->sw);
1292        typec_mux_put(port->mux);
1293        kfree(port);
1294}
1295
1296const struct device_type typec_port_dev_type = {
1297        .name = "typec_port",
1298        .groups = typec_groups,
1299        .uevent = typec_uevent,
1300        .release = typec_release,
1301};
1302
1303/* --------------------------------------- */
1304/* Driver callbacks to report role updates */
1305
1306/**
1307 * typec_set_data_role - Report data role change
1308 * @port: The USB Type-C Port where the role was changed
1309 * @role: The new data role
1310 *
1311 * This routine is used by the port drivers to report data role changes.
1312 */
1313void typec_set_data_role(struct typec_port *port, enum typec_data_role role)
1314{
1315        if (port->data_role == role)
1316                return;
1317
1318        port->data_role = role;
1319        sysfs_notify(&port->dev.kobj, NULL, "data_role");
1320        kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
1321}
1322EXPORT_SYMBOL_GPL(typec_set_data_role);
1323
1324/**
1325 * typec_set_pwr_role - Report power role change
1326 * @port: The USB Type-C Port where the role was changed
1327 * @role: The new data role
1328 *
1329 * This routine is used by the port drivers to report power role changes.
1330 */
1331void typec_set_pwr_role(struct typec_port *port, enum typec_role role)
1332{
1333        if (port->pwr_role == role)
1334                return;
1335
1336        port->pwr_role = role;
1337        sysfs_notify(&port->dev.kobj, NULL, "power_role");
1338        kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
1339}
1340EXPORT_SYMBOL_GPL(typec_set_pwr_role);
1341
1342/**
1343 * typec_set_vconn_role - Report VCONN source change
1344 * @port: The USB Type-C Port which VCONN role changed
1345 * @role: Source when @port is sourcing VCONN, or Sink when it's not
1346 *
1347 * This routine is used by the port drivers to report if the VCONN source is
1348 * changes.
1349 */
1350void typec_set_vconn_role(struct typec_port *port, enum typec_role role)
1351{
1352        if (port->vconn_role == role)
1353                return;
1354
1355        port->vconn_role = role;
1356        sysfs_notify(&port->dev.kobj, NULL, "vconn_source");
1357        kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
1358}
1359EXPORT_SYMBOL_GPL(typec_set_vconn_role);
1360
1361static int partner_match(struct device *dev, void *data)
1362{
1363        return is_typec_partner(dev);
1364}
1365
1366/**
1367 * typec_set_pwr_opmode - Report changed power operation mode
1368 * @port: The USB Type-C Port where the mode was changed
1369 * @opmode: New power operation mode
1370 *
1371 * This routine is used by the port drivers to report changed power operation
1372 * mode in @port. The modes are USB (default), 1.5A, 3.0A as defined in USB
1373 * Type-C specification, and "USB Power Delivery" when the power levels are
1374 * negotiated with methods defined in USB Power Delivery specification.
1375 */
1376void typec_set_pwr_opmode(struct typec_port *port,
1377                          enum typec_pwr_opmode opmode)
1378{
1379        struct device *partner_dev;
1380
1381        if (port->pwr_opmode == opmode)
1382                return;
1383
1384        port->pwr_opmode = opmode;
1385        sysfs_notify(&port->dev.kobj, NULL, "power_operation_mode");
1386        kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
1387
1388        partner_dev = device_find_child(&port->dev, NULL, partner_match);
1389        if (partner_dev) {
1390                struct typec_partner *partner = to_typec_partner(partner_dev);
1391
1392                if (opmode == TYPEC_PWR_MODE_PD && !partner->usb_pd) {
1393                        partner->usb_pd = 1;
1394                        sysfs_notify(&partner_dev->kobj, NULL,
1395                                     "supports_usb_power_delivery");
1396                }
1397                put_device(partner_dev);
1398        }
1399}
1400EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
1401
1402/**
1403 * typec_find_port_power_role - Get the typec port power capability
1404 * @name: port power capability string
1405 *
1406 * This routine is used to find the typec_port_type by its string name.
1407 *
1408 * Returns typec_port_type if success, otherwise negative error code.
1409 */
1410int typec_find_port_power_role(const char *name)
1411{
1412        return match_string(typec_port_power_roles,
1413                            ARRAY_SIZE(typec_port_power_roles), name);
1414}
1415EXPORT_SYMBOL_GPL(typec_find_port_power_role);
1416
1417/**
1418 * typec_find_power_role - Find the typec one specific power role
1419 * @name: power role string
1420 *
1421 * This routine is used to find the typec_role by its string name.
1422 *
1423 * Returns typec_role if success, otherwise negative error code.
1424 */
1425int typec_find_power_role(const char *name)
1426{
1427        return match_string(typec_roles, ARRAY_SIZE(typec_roles), name);
1428}
1429EXPORT_SYMBOL_GPL(typec_find_power_role);
1430
1431/**
1432 * typec_find_port_data_role - Get the typec port data capability
1433 * @name: port data capability string
1434 *
1435 * This routine is used to find the typec_port_data by its string name.
1436 *
1437 * Returns typec_port_data if success, otherwise negative error code.
1438 */
1439int typec_find_port_data_role(const char *name)
1440{
1441        return match_string(typec_port_data_roles,
1442                            ARRAY_SIZE(typec_port_data_roles), name);
1443}
1444EXPORT_SYMBOL_GPL(typec_find_port_data_role);
1445
1446/* ------------------------------------------ */
1447/* API for Multiplexer/DeMultiplexer Switches */
1448
1449/**
1450 * typec_set_orientation - Set USB Type-C cable plug orientation
1451 * @port: USB Type-C Port
1452 * @orientation: USB Type-C cable plug orientation
1453 *
1454 * Set cable plug orientation for @port.
1455 */
1456int typec_set_orientation(struct typec_port *port,
1457                          enum typec_orientation orientation)
1458{
1459        int ret;
1460
1461        if (port->sw) {
1462                ret = port->sw->set(port->sw, orientation);
1463                if (ret)
1464                        return ret;
1465        }
1466
1467        port->orientation = orientation;
1468
1469        return 0;
1470}
1471EXPORT_SYMBOL_GPL(typec_set_orientation);
1472
1473/**
1474 * typec_get_orientation - Get USB Type-C cable plug orientation
1475 * @port: USB Type-C Port
1476 *
1477 * Get current cable plug orientation for @port.
1478 */
1479enum typec_orientation typec_get_orientation(struct typec_port *port)
1480{
1481        return port->orientation;
1482}
1483EXPORT_SYMBOL_GPL(typec_get_orientation);
1484
1485/**
1486 * typec_set_mode - Set mode of operation for USB Type-C connector
1487 * @port: USB Type-C connector
1488 * @mode: Accessory Mode, USB Operation or Safe State
1489 *
1490 * Configure @port for Accessory Mode @mode. This function will configure the
1491 * muxes needed for @mode.
1492 */
1493int typec_set_mode(struct typec_port *port, int mode)
1494{
1495        return port->mux ? port->mux->set(port->mux, mode) : 0;
1496}
1497EXPORT_SYMBOL_GPL(typec_set_mode);
1498
1499/* --------------------------------------- */
1500
1501/**
1502 * typec_port_register_altmode - Register USB Type-C Port Alternate Mode
1503 * @port: USB Type-C Port that supports the alternate mode
1504 * @desc: Description of the alternate mode
1505 *
1506 * This routine is used to register an alternate mode that @port is capable of
1507 * supporting.
1508 *
1509 * Returns handle to the alternate mode on success or ERR_PTR on failure.
1510 */
1511struct typec_altmode *
1512typec_port_register_altmode(struct typec_port *port,
1513                            const struct typec_altmode_desc *desc)
1514{
1515        struct typec_altmode *adev;
1516        struct typec_mux *mux;
1517
1518        mux = typec_mux_get(&port->dev, desc);
1519        if (IS_ERR(mux))
1520                return ERR_CAST(mux);
1521
1522        adev = typec_register_altmode(&port->dev, desc);
1523        if (IS_ERR(adev))
1524                typec_mux_put(mux);
1525        else
1526                to_altmode(adev)->mux = mux;
1527
1528        return adev;
1529}
1530EXPORT_SYMBOL_GPL(typec_port_register_altmode);
1531
1532/**
1533 * typec_register_port - Register a USB Type-C Port
1534 * @parent: Parent device
1535 * @cap: Description of the port
1536 *
1537 * Registers a device for USB Type-C Port described in @cap.
1538 *
1539 * Returns handle to the port on success or ERR_PTR on failure.
1540 */
1541struct typec_port *typec_register_port(struct device *parent,
1542                                       const struct typec_capability *cap)
1543{
1544        struct typec_port *port;
1545        int ret;
1546        int id;
1547
1548        port = kzalloc(sizeof(*port), GFP_KERNEL);
1549        if (!port)
1550                return ERR_PTR(-ENOMEM);
1551
1552        id = ida_simple_get(&typec_index_ida, 0, 0, GFP_KERNEL);
1553        if (id < 0) {
1554                kfree(port);
1555                return ERR_PTR(id);
1556        }
1557
1558        switch (cap->type) {
1559        case TYPEC_PORT_SRC:
1560                port->pwr_role = TYPEC_SOURCE;
1561                port->vconn_role = TYPEC_SOURCE;
1562                break;
1563        case TYPEC_PORT_SNK:
1564                port->pwr_role = TYPEC_SINK;
1565                port->vconn_role = TYPEC_SINK;
1566                break;
1567        case TYPEC_PORT_DRP:
1568                if (cap->prefer_role != TYPEC_NO_PREFERRED_ROLE)
1569                        port->pwr_role = cap->prefer_role;
1570                else
1571                        port->pwr_role = TYPEC_SINK;
1572                break;
1573        }
1574
1575        switch (cap->data) {
1576        case TYPEC_PORT_DFP:
1577                port->data_role = TYPEC_HOST;
1578                break;
1579        case TYPEC_PORT_UFP:
1580                port->data_role = TYPEC_DEVICE;
1581                break;
1582        case TYPEC_PORT_DRD:
1583                if (cap->prefer_role == TYPEC_SOURCE)
1584                        port->data_role = TYPEC_HOST;
1585                else
1586                        port->data_role = TYPEC_DEVICE;
1587                break;
1588        }
1589
1590        ida_init(&port->mode_ids);
1591        mutex_init(&port->port_type_lock);
1592
1593        port->id = id;
1594        port->cap = cap;
1595        port->port_type = cap->type;
1596        port->prefer_role = cap->prefer_role;
1597
1598        device_initialize(&port->dev);
1599        port->dev.class = typec_class;
1600        port->dev.parent = parent;
1601        port->dev.fwnode = cap->fwnode;
1602        port->dev.type = &typec_port_dev_type;
1603        dev_set_name(&port->dev, "port%d", id);
1604
1605        port->sw = typec_switch_get(&port->dev);
1606        if (IS_ERR(port->sw)) {
1607                put_device(&port->dev);
1608                return ERR_CAST(port->sw);
1609        }
1610
1611        port->mux = typec_mux_get(&port->dev, NULL);
1612        if (IS_ERR(port->mux)) {
1613                put_device(&port->dev);
1614                return ERR_CAST(port->mux);
1615        }
1616
1617        ret = device_add(&port->dev);
1618        if (ret) {
1619                dev_err(parent, "failed to register port (%d)\n", ret);
1620                put_device(&port->dev);
1621                return ERR_PTR(ret);
1622        }
1623
1624        return port;
1625}
1626EXPORT_SYMBOL_GPL(typec_register_port);
1627
1628/**
1629 * typec_unregister_port - Unregister a USB Type-C Port
1630 * @port: The port to be unregistered
1631 *
1632 * Unregister device created with typec_register_port().
1633 */
1634void typec_unregister_port(struct typec_port *port)
1635{
1636        if (!IS_ERR_OR_NULL(port))
1637                device_unregister(&port->dev);
1638}
1639EXPORT_SYMBOL_GPL(typec_unregister_port);
1640
1641static int __init typec_init(void)
1642{
1643        int ret;
1644
1645        ret = bus_register(&typec_bus);
1646        if (ret)
1647                return ret;
1648
1649        ret = class_register(&typec_mux_class);
1650        if (ret)
1651                goto err_unregister_bus;
1652
1653        typec_class = class_create(THIS_MODULE, "typec");
1654        if (IS_ERR(typec_class)) {
1655                ret = PTR_ERR(typec_class);
1656                goto err_unregister_mux_class;
1657        }
1658
1659        return 0;
1660
1661err_unregister_mux_class:
1662        class_unregister(&typec_mux_class);
1663
1664err_unregister_bus:
1665        bus_unregister(&typec_bus);
1666
1667        return ret;
1668}
1669subsys_initcall(typec_init);
1670
1671static void __exit typec_exit(void)
1672{
1673        class_destroy(typec_class);
1674        ida_destroy(&typec_index_ida);
1675        bus_unregister(&typec_bus);
1676        class_unregister(&typec_mux_class);
1677}
1678module_exit(typec_exit);
1679
1680MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
1681MODULE_LICENSE("GPL v2");
1682MODULE_DESCRIPTION("USB Type-C Connector Class");
1683