linux/drivers/usb/typec/ucsi/ucsi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * USB Type-C Connector System Software Interface driver
   4 *
   5 * Copyright (C) 2017, Intel Corporation
   6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
   7 */
   8
   9#include <linux/completion.h>
  10#include <linux/property.h>
  11#include <linux/device.h>
  12#include <linux/module.h>
  13#include <linux/delay.h>
  14#include <linux/slab.h>
  15#include <linux/usb/typec.h>
  16
  17#include "ucsi.h"
  18#include "trace.h"
  19
  20#define to_ucsi_connector(_cap_) container_of(_cap_, struct ucsi_connector, \
  21                                              typec_cap)
  22
  23/*
  24 * UCSI_TIMEOUT_MS - PPM communication timeout
  25 *
  26 * Ideally we could use MIN_TIME_TO_RESPOND_WITH_BUSY (which is defined in UCSI
  27 * specification) here as reference, but unfortunately we can't. It is very
  28 * difficult to estimate the time it takes for the system to process the command
  29 * before it is actually passed to the PPM.
  30 */
  31#define UCSI_TIMEOUT_MS         5000
  32
  33/*
  34 * UCSI_SWAP_TIMEOUT_MS - Timeout for role swap requests
  35 *
  36 * 5 seconds is close to the time it takes for CapsCounter to reach 0, so even
  37 * if the PPM does not generate Connector Change events before that with
  38 * partners that do not support USB Power Delivery, this should still work.
  39 */
  40#define UCSI_SWAP_TIMEOUT_MS    5000
  41
  42enum ucsi_status {
  43        UCSI_IDLE = 0,
  44        UCSI_BUSY,
  45        UCSI_ERROR,
  46};
  47
  48struct ucsi_connector {
  49        int num;
  50
  51        struct ucsi *ucsi;
  52        struct work_struct work;
  53        struct completion complete;
  54
  55        struct typec_port *port;
  56        struct typec_partner *partner;
  57
  58        struct typec_capability typec_cap;
  59
  60        struct ucsi_connector_status status;
  61        struct ucsi_connector_capability cap;
  62};
  63
  64struct ucsi {
  65        struct device *dev;
  66        struct ucsi_ppm *ppm;
  67
  68        enum ucsi_status status;
  69        struct completion complete;
  70        struct ucsi_capability cap;
  71        struct ucsi_connector *connector;
  72
  73        struct work_struct work;
  74
  75        /* PPM Communication lock */
  76        struct mutex ppm_lock;
  77
  78        /* PPM communication flags */
  79        unsigned long flags;
  80#define EVENT_PENDING   0
  81#define COMMAND_PENDING 1
  82#define ACK_PENDING     2
  83};
  84
  85static inline int ucsi_sync(struct ucsi *ucsi)
  86{
  87        if (ucsi->ppm && ucsi->ppm->sync)
  88                return ucsi->ppm->sync(ucsi->ppm);
  89        return 0;
  90}
  91
  92static int ucsi_command(struct ucsi *ucsi, struct ucsi_control *ctrl)
  93{
  94        int ret;
  95
  96        trace_ucsi_command(ctrl);
  97
  98        set_bit(COMMAND_PENDING, &ucsi->flags);
  99
 100        ret = ucsi->ppm->cmd(ucsi->ppm, ctrl);
 101        if (ret)
 102                goto err_clear_flag;
 103
 104        if (!wait_for_completion_timeout(&ucsi->complete,
 105                                         msecs_to_jiffies(UCSI_TIMEOUT_MS))) {
 106                dev_warn(ucsi->dev, "PPM NOT RESPONDING\n");
 107                ret = -ETIMEDOUT;
 108        }
 109
 110err_clear_flag:
 111        clear_bit(COMMAND_PENDING, &ucsi->flags);
 112
 113        return ret;
 114}
 115
 116static int ucsi_ack(struct ucsi *ucsi, u8 ack)
 117{
 118        struct ucsi_control ctrl;
 119        int ret;
 120
 121        trace_ucsi_ack(ack);
 122
 123        set_bit(ACK_PENDING, &ucsi->flags);
 124
 125        UCSI_CMD_ACK(ctrl, ack);
 126        ret = ucsi->ppm->cmd(ucsi->ppm, &ctrl);
 127        if (ret)
 128                goto out_clear_bit;
 129
 130        /* Waiting for ACK with ACK CMD, but not with EVENT for now */
 131        if (ack == UCSI_ACK_EVENT)
 132                goto out_clear_bit;
 133
 134        if (!wait_for_completion_timeout(&ucsi->complete,
 135                                         msecs_to_jiffies(UCSI_TIMEOUT_MS)))
 136                ret = -ETIMEDOUT;
 137
 138out_clear_bit:
 139        clear_bit(ACK_PENDING, &ucsi->flags);
 140
 141        if (ret)
 142                dev_err(ucsi->dev, "%s: failed\n", __func__);
 143
 144        return ret;
 145}
 146
 147static int ucsi_run_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
 148                            void *data, size_t size)
 149{
 150        struct ucsi_control _ctrl;
 151        u8 data_length;
 152        u16 error;
 153        int ret;
 154
 155        ret = ucsi_command(ucsi, ctrl);
 156        if (ret)
 157                goto err;
 158
 159        switch (ucsi->status) {
 160        case UCSI_IDLE:
 161                ret = ucsi_sync(ucsi);
 162                if (ret)
 163                        dev_warn(ucsi->dev, "%s: sync failed\n", __func__);
 164
 165                if (data)
 166                        memcpy(data, ucsi->ppm->data->message_in, size);
 167
 168                data_length = ucsi->ppm->data->cci.data_length;
 169
 170                ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
 171                if (!ret)
 172                        ret = data_length;
 173                break;
 174        case UCSI_BUSY:
 175                /* The caller decides whether to cancel or not */
 176                ret = -EBUSY;
 177                break;
 178        case UCSI_ERROR:
 179                ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
 180                if (ret)
 181                        break;
 182
 183                _ctrl.raw_cmd = 0;
 184                _ctrl.cmd.cmd = UCSI_GET_ERROR_STATUS;
 185                ret = ucsi_command(ucsi, &_ctrl);
 186                if (ret) {
 187                        dev_err(ucsi->dev, "reading error failed!\n");
 188                        break;
 189                }
 190
 191                memcpy(&error, ucsi->ppm->data->message_in, sizeof(error));
 192
 193                /* Something has really gone wrong */
 194                if (WARN_ON(ucsi->status == UCSI_ERROR)) {
 195                        ret = -ENODEV;
 196                        break;
 197                }
 198
 199                ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
 200                if (ret)
 201                        break;
 202
 203                switch (error) {
 204                case UCSI_ERROR_INCOMPATIBLE_PARTNER:
 205                        ret = -EOPNOTSUPP;
 206                        break;
 207                case UCSI_ERROR_CC_COMMUNICATION_ERR:
 208                        ret = -ECOMM;
 209                        break;
 210                case UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL:
 211                        ret = -EPROTO;
 212                        break;
 213                case UCSI_ERROR_DEAD_BATTERY:
 214                        dev_warn(ucsi->dev, "Dead battery condition!\n");
 215                        ret = -EPERM;
 216                        break;
 217                /* The following mean a bug in this driver */
 218                case UCSI_ERROR_INVALID_CON_NUM:
 219                case UCSI_ERROR_UNREGONIZED_CMD:
 220                case UCSI_ERROR_INVALID_CMD_ARGUMENT:
 221                        dev_warn(ucsi->dev,
 222                                 "%s: possible UCSI driver bug - error 0x%x\n",
 223                                 __func__, error);
 224                        ret = -EINVAL;
 225                        break;
 226                default:
 227                        dev_warn(ucsi->dev,
 228                                 "%s: error without status\n", __func__);
 229                        ret = -EIO;
 230                        break;
 231                }
 232                break;
 233        }
 234
 235err:
 236        trace_ucsi_run_command(ctrl, ret);
 237
 238        return ret;
 239}
 240
 241/* -------------------------------------------------------------------------- */
 242
 243static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
 244{
 245        switch (con->status.pwr_op_mode) {
 246        case UCSI_CONSTAT_PWR_OPMODE_PD:
 247                typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_PD);
 248                break;
 249        case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
 250                typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_1_5A);
 251                break;
 252        case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
 253                typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_3_0A);
 254                break;
 255        default:
 256                typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_USB);
 257                break;
 258        }
 259}
 260
 261static int ucsi_register_partner(struct ucsi_connector *con)
 262{
 263        struct typec_partner_desc desc;
 264        struct typec_partner *partner;
 265
 266        if (con->partner)
 267                return 0;
 268
 269        memset(&desc, 0, sizeof(desc));
 270
 271        switch (con->status.partner_type) {
 272        case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
 273                desc.accessory = TYPEC_ACCESSORY_DEBUG;
 274                break;
 275        case UCSI_CONSTAT_PARTNER_TYPE_AUDIO:
 276                desc.accessory = TYPEC_ACCESSORY_AUDIO;
 277                break;
 278        default:
 279                break;
 280        }
 281
 282        desc.usb_pd = con->status.pwr_op_mode == UCSI_CONSTAT_PWR_OPMODE_PD;
 283
 284        partner = typec_register_partner(con->port, &desc);
 285        if (IS_ERR(partner)) {
 286                dev_err(con->ucsi->dev,
 287                        "con%d: failed to register partner (%ld)\n", con->num,
 288                        PTR_ERR(partner));
 289                return PTR_ERR(partner);
 290        }
 291
 292        con->partner = partner;
 293
 294        return 0;
 295}
 296
 297static void ucsi_unregister_partner(struct ucsi_connector *con)
 298{
 299        if (!con->partner)
 300                return;
 301
 302        typec_unregister_partner(con->partner);
 303        con->partner = NULL;
 304}
 305
 306static void ucsi_connector_change(struct work_struct *work)
 307{
 308        struct ucsi_connector *con = container_of(work, struct ucsi_connector,
 309                                                  work);
 310        struct ucsi *ucsi = con->ucsi;
 311        struct ucsi_control ctrl;
 312        int ret;
 313
 314        mutex_lock(&ucsi->ppm_lock);
 315
 316        UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num);
 317        ret = ucsi_run_command(ucsi, &ctrl, &con->status, sizeof(con->status));
 318        if (ret < 0) {
 319                dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
 320                        __func__, ret);
 321                goto out_unlock;
 322        }
 323
 324        if (con->status.change & UCSI_CONSTAT_POWER_OPMODE_CHANGE)
 325                ucsi_pwr_opmode_change(con);
 326
 327        if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) {
 328                typec_set_pwr_role(con->port, con->status.pwr_dir);
 329
 330                /* Complete pending power role swap */
 331                if (!completion_done(&con->complete))
 332                        complete(&con->complete);
 333        }
 334
 335        if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) {
 336                switch (con->status.partner_type) {
 337                case UCSI_CONSTAT_PARTNER_TYPE_UFP:
 338                        typec_set_data_role(con->port, TYPEC_HOST);
 339                        break;
 340                case UCSI_CONSTAT_PARTNER_TYPE_DFP:
 341                        typec_set_data_role(con->port, TYPEC_DEVICE);
 342                        break;
 343                default:
 344                        break;
 345                }
 346
 347                /* Complete pending data role swap */
 348                if (!completion_done(&con->complete))
 349                        complete(&con->complete);
 350        }
 351
 352        if (con->status.change & UCSI_CONSTAT_CONNECT_CHANGE) {
 353                typec_set_pwr_role(con->port, con->status.pwr_dir);
 354
 355                switch (con->status.partner_type) {
 356                case UCSI_CONSTAT_PARTNER_TYPE_UFP:
 357                        typec_set_data_role(con->port, TYPEC_HOST);
 358                        break;
 359                case UCSI_CONSTAT_PARTNER_TYPE_DFP:
 360                        typec_set_data_role(con->port, TYPEC_DEVICE);
 361                        break;
 362                default:
 363                        break;
 364                }
 365
 366                if (con->status.connected)
 367                        ucsi_register_partner(con);
 368                else
 369                        ucsi_unregister_partner(con);
 370        }
 371
 372        ret = ucsi_ack(ucsi, UCSI_ACK_EVENT);
 373        if (ret)
 374                dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret);
 375
 376        trace_ucsi_connector_change(con->num, &con->status);
 377
 378out_unlock:
 379        clear_bit(EVENT_PENDING, &ucsi->flags);
 380        mutex_unlock(&ucsi->ppm_lock);
 381}
 382
 383/**
 384 * ucsi_notify - PPM notification handler
 385 * @ucsi: Source UCSI Interface for the notifications
 386 *
 387 * Handle notifications from PPM of @ucsi.
 388 */
 389void ucsi_notify(struct ucsi *ucsi)
 390{
 391        struct ucsi_cci *cci;
 392
 393        /* There is no requirement to sync here, but no harm either. */
 394        ucsi_sync(ucsi);
 395
 396        cci = &ucsi->ppm->data->cci;
 397
 398        if (cci->error)
 399                ucsi->status = UCSI_ERROR;
 400        else if (cci->busy)
 401                ucsi->status = UCSI_BUSY;
 402        else
 403                ucsi->status = UCSI_IDLE;
 404
 405        if (cci->cmd_complete && test_bit(COMMAND_PENDING, &ucsi->flags)) {
 406                complete(&ucsi->complete);
 407        } else if (cci->ack_complete && test_bit(ACK_PENDING, &ucsi->flags)) {
 408                complete(&ucsi->complete);
 409        } else if (cci->connector_change) {
 410                struct ucsi_connector *con;
 411
 412                con = &ucsi->connector[cci->connector_change - 1];
 413
 414                if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags))
 415                        schedule_work(&con->work);
 416        }
 417
 418        trace_ucsi_notify(ucsi->ppm->data->raw_cci);
 419}
 420EXPORT_SYMBOL_GPL(ucsi_notify);
 421
 422/* -------------------------------------------------------------------------- */
 423
 424static int ucsi_reset_connector(struct ucsi_connector *con, bool hard)
 425{
 426        struct ucsi_control ctrl;
 427
 428        UCSI_CMD_CONNECTOR_RESET(ctrl, con, hard);
 429
 430        return ucsi_run_command(con->ucsi, &ctrl, NULL, 0);
 431}
 432
 433static int ucsi_reset_ppm(struct ucsi *ucsi)
 434{
 435        struct ucsi_control ctrl;
 436        unsigned long tmo;
 437        int ret;
 438
 439        ctrl.raw_cmd = 0;
 440        ctrl.cmd.cmd = UCSI_PPM_RESET;
 441        trace_ucsi_command(&ctrl);
 442        ret = ucsi->ppm->cmd(ucsi->ppm, &ctrl);
 443        if (ret)
 444                goto err;
 445
 446        tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
 447
 448        do {
 449                /* Here sync is critical. */
 450                ret = ucsi_sync(ucsi);
 451                if (ret)
 452                        goto err;
 453
 454                if (ucsi->ppm->data->cci.reset_complete)
 455                        break;
 456
 457                /* If the PPM is still doing something else, reset it again. */
 458                if (ucsi->ppm->data->raw_cci) {
 459                        dev_warn_ratelimited(ucsi->dev,
 460                                "Failed to reset PPM! Trying again..\n");
 461
 462                        trace_ucsi_command(&ctrl);
 463                        ret = ucsi->ppm->cmd(ucsi->ppm, &ctrl);
 464                        if (ret)
 465                                goto err;
 466                }
 467
 468                /* Letting the PPM settle down. */
 469                msleep(20);
 470
 471                ret = -ETIMEDOUT;
 472        } while (time_is_after_jiffies(tmo));
 473
 474err:
 475        trace_ucsi_reset_ppm(&ctrl, ret);
 476
 477        return ret;
 478}
 479
 480static int ucsi_role_cmd(struct ucsi_connector *con, struct ucsi_control *ctrl)
 481{
 482        int ret;
 483
 484        ret = ucsi_run_command(con->ucsi, ctrl, NULL, 0);
 485        if (ret == -ETIMEDOUT) {
 486                struct ucsi_control c;
 487
 488                /* PPM most likely stopped responding. Resetting everything. */
 489                ucsi_reset_ppm(con->ucsi);
 490
 491                UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL);
 492                ucsi_run_command(con->ucsi, &c, NULL, 0);
 493
 494                ucsi_reset_connector(con, true);
 495        }
 496
 497        return ret;
 498}
 499
 500static int
 501ucsi_dr_swap(const struct typec_capability *cap, enum typec_data_role role)
 502{
 503        struct ucsi_connector *con = to_ucsi_connector(cap);
 504        struct ucsi_control ctrl;
 505        int ret = 0;
 506
 507        if (!con->partner)
 508                return -ENOTCONN;
 509
 510        mutex_lock(&con->ucsi->ppm_lock);
 511
 512        if ((con->status.partner_type == UCSI_CONSTAT_PARTNER_TYPE_DFP &&
 513             role == TYPEC_DEVICE) ||
 514            (con->status.partner_type == UCSI_CONSTAT_PARTNER_TYPE_UFP &&
 515             role == TYPEC_HOST))
 516                goto out_unlock;
 517
 518        UCSI_CMD_SET_UOR(ctrl, con, role);
 519        ret = ucsi_role_cmd(con, &ctrl);
 520        if (ret < 0)
 521                goto out_unlock;
 522
 523        mutex_unlock(&con->ucsi->ppm_lock);
 524
 525        if (!wait_for_completion_timeout(&con->complete,
 526                                        msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS)))
 527                return -ETIMEDOUT;
 528
 529        return 0;
 530
 531out_unlock:
 532        mutex_unlock(&con->ucsi->ppm_lock);
 533
 534        return ret;
 535}
 536
 537static int
 538ucsi_pr_swap(const struct typec_capability *cap, enum typec_role role)
 539{
 540        struct ucsi_connector *con = to_ucsi_connector(cap);
 541        struct ucsi_control ctrl;
 542        int ret = 0;
 543
 544        if (!con->partner)
 545                return -ENOTCONN;
 546
 547        mutex_lock(&con->ucsi->ppm_lock);
 548
 549        if (con->status.pwr_dir == role)
 550                goto out_unlock;
 551
 552        UCSI_CMD_SET_PDR(ctrl, con, role);
 553        ret = ucsi_role_cmd(con, &ctrl);
 554        if (ret < 0)
 555                goto out_unlock;
 556
 557        mutex_unlock(&con->ucsi->ppm_lock);
 558
 559        if (!wait_for_completion_timeout(&con->complete,
 560                                        msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS)))
 561                return -ETIMEDOUT;
 562
 563        mutex_lock(&con->ucsi->ppm_lock);
 564
 565        /* Something has gone wrong while swapping the role */
 566        if (con->status.pwr_op_mode != UCSI_CONSTAT_PWR_OPMODE_PD) {
 567                ucsi_reset_connector(con, true);
 568                ret = -EPROTO;
 569        }
 570
 571out_unlock:
 572        mutex_unlock(&con->ucsi->ppm_lock);
 573
 574        return ret;
 575}
 576
 577static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con)
 578{
 579        struct fwnode_handle *fwnode;
 580        int i = 1;
 581
 582        device_for_each_child_node(con->ucsi->dev, fwnode)
 583                if (i++ == con->num)
 584                        return fwnode;
 585        return NULL;
 586}
 587
 588static int ucsi_register_port(struct ucsi *ucsi, int index)
 589{
 590        struct ucsi_connector *con = &ucsi->connector[index];
 591        struct typec_capability *cap = &con->typec_cap;
 592        enum typec_accessory *accessory = cap->accessory;
 593        struct ucsi_control ctrl;
 594        int ret;
 595
 596        INIT_WORK(&con->work, ucsi_connector_change);
 597        init_completion(&con->complete);
 598        con->num = index + 1;
 599        con->ucsi = ucsi;
 600
 601        /* Get connector capability */
 602        UCSI_CMD_GET_CONNECTOR_CAPABILITY(ctrl, con->num);
 603        ret = ucsi_run_command(ucsi, &ctrl, &con->cap, sizeof(con->cap));
 604        if (ret < 0)
 605                return ret;
 606
 607        if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP)
 608                cap->data = TYPEC_PORT_DRD;
 609        else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DFP)
 610                cap->data = TYPEC_PORT_DFP;
 611        else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_UFP)
 612                cap->data = TYPEC_PORT_UFP;
 613
 614        if (con->cap.provider && con->cap.consumer)
 615                cap->type = TYPEC_PORT_DRP;
 616        else if (con->cap.provider)
 617                cap->type = TYPEC_PORT_SRC;
 618        else if (con->cap.consumer)
 619                cap->type = TYPEC_PORT_SNK;
 620
 621        cap->revision = ucsi->cap.typec_version;
 622        cap->pd_revision = ucsi->cap.pd_version;
 623        cap->prefer_role = TYPEC_NO_PREFERRED_ROLE;
 624
 625        if (con->cap.op_mode & UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY)
 626                *accessory++ = TYPEC_ACCESSORY_AUDIO;
 627        if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY)
 628                *accessory = TYPEC_ACCESSORY_DEBUG;
 629
 630        cap->fwnode = ucsi_find_fwnode(con);
 631        cap->dr_set = ucsi_dr_swap;
 632        cap->pr_set = ucsi_pr_swap;
 633
 634        /* Register the connector */
 635        con->port = typec_register_port(ucsi->dev, cap);
 636        if (IS_ERR(con->port))
 637                return PTR_ERR(con->port);
 638
 639        /* Get the status */
 640        UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num);
 641        ret = ucsi_run_command(ucsi, &ctrl, &con->status, sizeof(con->status));
 642        if (ret < 0) {
 643                dev_err(ucsi->dev, "con%d: failed to get status\n", con->num);
 644                return 0;
 645        }
 646
 647        ucsi_pwr_opmode_change(con);
 648        typec_set_pwr_role(con->port, con->status.pwr_dir);
 649
 650        switch (con->status.partner_type) {
 651        case UCSI_CONSTAT_PARTNER_TYPE_UFP:
 652                typec_set_data_role(con->port, TYPEC_HOST);
 653                break;
 654        case UCSI_CONSTAT_PARTNER_TYPE_DFP:
 655                typec_set_data_role(con->port, TYPEC_DEVICE);
 656                break;
 657        default:
 658                break;
 659        }
 660
 661        /* Check if there is already something connected */
 662        if (con->status.connected)
 663                ucsi_register_partner(con);
 664
 665        trace_ucsi_register_port(con->num, &con->status);
 666
 667        return 0;
 668}
 669
 670static void ucsi_init(struct work_struct *work)
 671{
 672        struct ucsi *ucsi = container_of(work, struct ucsi, work);
 673        struct ucsi_connector *con;
 674        struct ucsi_control ctrl;
 675        int ret;
 676        int i;
 677
 678        mutex_lock(&ucsi->ppm_lock);
 679
 680        /* Reset the PPM */
 681        ret = ucsi_reset_ppm(ucsi);
 682        if (ret) {
 683                dev_err(ucsi->dev, "failed to reset PPM!\n");
 684                goto err;
 685        }
 686
 687        /* Enable basic notifications */
 688        UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE |
 689                                        UCSI_ENABLE_NTFY_ERROR);
 690        ret = ucsi_run_command(ucsi, &ctrl, NULL, 0);
 691        if (ret < 0)
 692                goto err_reset;
 693
 694        /* Get PPM capabilities */
 695        UCSI_CMD_GET_CAPABILITY(ctrl);
 696        ret = ucsi_run_command(ucsi, &ctrl, &ucsi->cap, sizeof(ucsi->cap));
 697        if (ret < 0)
 698                goto err_reset;
 699
 700        if (!ucsi->cap.num_connectors) {
 701                ret = -ENODEV;
 702                goto err_reset;
 703        }
 704
 705        /* Allocate the connectors. Released in ucsi_unregister_ppm() */
 706        ucsi->connector = kcalloc(ucsi->cap.num_connectors + 1,
 707                                  sizeof(*ucsi->connector), GFP_KERNEL);
 708        if (!ucsi->connector) {
 709                ret = -ENOMEM;
 710                goto err_reset;
 711        }
 712
 713        /* Register all connectors */
 714        for (i = 0; i < ucsi->cap.num_connectors; i++) {
 715                ret = ucsi_register_port(ucsi, i);
 716                if (ret)
 717                        goto err_unregister;
 718        }
 719
 720        /* Enable all notifications */
 721        UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL);
 722        ret = ucsi_run_command(ucsi, &ctrl, NULL, 0);
 723        if (ret < 0)
 724                goto err_unregister;
 725
 726        mutex_unlock(&ucsi->ppm_lock);
 727
 728        return;
 729
 730err_unregister:
 731        for (con = ucsi->connector; con->port; con++) {
 732                ucsi_unregister_partner(con);
 733                typec_unregister_port(con->port);
 734                con->port = NULL;
 735        }
 736
 737err_reset:
 738        ucsi_reset_ppm(ucsi);
 739err:
 740        mutex_unlock(&ucsi->ppm_lock);
 741        dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
 742}
 743
 744/**
 745 * ucsi_register_ppm - Register UCSI PPM Interface
 746 * @dev: Device interface to the PPM
 747 * @ppm: The PPM interface
 748 *
 749 * Allocates UCSI instance, associates it with @ppm and returns it to the
 750 * caller, and schedules initialization of the interface.
 751 */
 752struct ucsi *ucsi_register_ppm(struct device *dev, struct ucsi_ppm *ppm)
 753{
 754        struct ucsi *ucsi;
 755
 756        ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL);
 757        if (!ucsi)
 758                return ERR_PTR(-ENOMEM);
 759
 760        INIT_WORK(&ucsi->work, ucsi_init);
 761        init_completion(&ucsi->complete);
 762        mutex_init(&ucsi->ppm_lock);
 763
 764        ucsi->dev = dev;
 765        ucsi->ppm = ppm;
 766
 767        /*
 768         * Communication with the PPM takes a lot of time. It is not reasonable
 769         * to initialize the driver here. Using a work for now.
 770         */
 771        queue_work(system_long_wq, &ucsi->work);
 772
 773        return ucsi;
 774}
 775EXPORT_SYMBOL_GPL(ucsi_register_ppm);
 776
 777/**
 778 * ucsi_unregister_ppm - Unregister UCSI PPM Interface
 779 * @ucsi: struct ucsi associated with the PPM
 780 *
 781 * Unregister UCSI PPM that was created with ucsi_register().
 782 */
 783void ucsi_unregister_ppm(struct ucsi *ucsi)
 784{
 785        struct ucsi_control ctrl;
 786        int i;
 787
 788        /* Make sure that we are not in the middle of driver initialization */
 789        cancel_work_sync(&ucsi->work);
 790
 791        mutex_lock(&ucsi->ppm_lock);
 792
 793        /* Disable everything except command complete notification */
 794        UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE)
 795        ucsi_run_command(ucsi, &ctrl, NULL, 0);
 796
 797        mutex_unlock(&ucsi->ppm_lock);
 798
 799        for (i = 0; i < ucsi->cap.num_connectors; i++) {
 800                cancel_work_sync(&ucsi->connector[i].work);
 801                ucsi_unregister_partner(&ucsi->connector[i]);
 802                typec_unregister_port(ucsi->connector[i].port);
 803        }
 804
 805        ucsi_reset_ppm(ucsi);
 806
 807        kfree(ucsi->connector);
 808        kfree(ucsi);
 809}
 810EXPORT_SYMBOL_GPL(ucsi_unregister_ppm);
 811
 812MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
 813MODULE_LICENSE("GPL v2");
 814MODULE_DESCRIPTION("USB Type-C Connector System Software Interface driver");
 815