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

usb: typec: ucsi: Preliminary support for alternate modes

With UCSI the alternate modes, just like everything else
related to USB Type-C connectors, are handled in firmware.
The operating system can see the status and is allowed to
request certain things, for example entering and exiting the
modes, but the support for alternate modes is very limited
in UCSI. The feature is also optional, which means that even
when the platform supports alternate modes, the operating
system may not be even made aware of them.

UCSI does not support direct VDM reading or writing.
Instead, alternate modes can be entered and exited using a
single custom command which takes also an optional SVID
specific configuration value as parameter. That means every
supported alternate mode has to be handled separately in
UCSI driver.

This commit does not include support for any specific
alternate mode. The discovered alternate modes are now
registered, but binding a driver to an alternate mode will
not be possible until support for that alternate mode is
added to the UCSI driver.

Tested-by: Ajay Gupta <ajayg@nvidia.com>
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Heikki Krogerus and committed by
Greg Kroah-Hartman
ad74b864 5c9ae5a8

+428 -92
+12
drivers/usb/typec/ucsi/trace.c
··· 60 60 61 61 return ""; 62 62 } 63 + 64 + static const char * const ucsi_recipient_strs[] = { 65 + [UCSI_RECIPIENT_CON] = "port", 66 + [UCSI_RECIPIENT_SOP] = "partner", 67 + [UCSI_RECIPIENT_SOP_P] = "plug (prime)", 68 + [UCSI_RECIPIENT_SOP_PP] = "plug (double prime)", 69 + }; 70 + 71 + const char *ucsi_recipient_str(u8 recipient) 72 + { 73 + return ucsi_recipient_strs[recipient]; 74 + }
+26
drivers/usb/typec/ucsi/trace.h
··· 7 7 #define __UCSI_TRACE_H 8 8 9 9 #include <linux/tracepoint.h> 10 + #include <linux/usb/typec_altmode.h> 10 11 11 12 const char *ucsi_cmd_str(u64 raw_cmd); 12 13 const char *ucsi_ack_str(u8 ack); ··· 133 132 DEFINE_EVENT(ucsi_log_connector_status, ucsi_register_port, 134 133 TP_PROTO(int port, struct ucsi_connector_status *status), 135 134 TP_ARGS(port, status) 135 + ); 136 + 137 + DECLARE_EVENT_CLASS(ucsi_log_register_altmode, 138 + TP_PROTO(u8 recipient, struct typec_altmode *alt), 139 + TP_ARGS(recipient, alt), 140 + TP_STRUCT__entry( 141 + __field(u8, recipient) 142 + __field(u16, svid) 143 + __field(u8, mode) 144 + __field(u32, vdo) 145 + ), 146 + TP_fast_assign( 147 + __entry->recipient = recipient; 148 + __entry->svid = alt->svid; 149 + __entry->mode = alt->mode; 150 + __entry->vdo = alt->vdo; 151 + ), 152 + TP_printk("%s alt mode: svid %04x, mode %d vdo %x", 153 + ucsi_recipient_str(__entry->recipient), __entry->svid, 154 + __entry->mode, __entry->vdo) 155 + ); 156 + 157 + DEFINE_EVENT(ucsi_log_register_altmode, ucsi_register_altmode, 158 + TP_PROTO(u8 recipient, struct typec_altmode *alt), 159 + TP_ARGS(recipient, alt) 136 160 ); 137 161 138 162 #endif /* __UCSI_TRACE_H */
+293 -92
drivers/usb/typec/ucsi/ucsi.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/delay.h> 14 14 #include <linux/slab.h> 15 - #include <linux/usb/typec.h> 15 + #include <linux/usb/typec_altmode.h> 16 16 17 17 #include "ucsi.h" 18 18 #include "trace.h" ··· 38 38 * partners that do not support USB Power Delivery, this should still work. 39 39 */ 40 40 #define UCSI_SWAP_TIMEOUT_MS 5000 41 - 42 - enum ucsi_status { 43 - UCSI_IDLE = 0, 44 - UCSI_BUSY, 45 - UCSI_ERROR, 46 - }; 47 - 48 - struct 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 - 64 - struct 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 41 85 42 static inline int ucsi_sync(struct ucsi *ucsi) 86 43 { ··· 195 238 return ret; 196 239 } 197 240 241 + int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl, 242 + void *retval, size_t size) 243 + { 244 + int ret; 245 + 246 + mutex_lock(&ucsi->ppm_lock); 247 + ret = ucsi_run_command(ucsi, ctrl, retval, size); 248 + mutex_unlock(&ucsi->ppm_lock); 249 + 250 + return ret; 251 + } 252 + 198 253 /* -------------------------------------------------------------------------- */ 254 + 255 + void ucsi_altmode_update_active(struct ucsi_connector *con) 256 + { 257 + const struct typec_altmode *altmode = NULL; 258 + struct ucsi_control ctrl; 259 + int ret; 260 + u8 cur; 261 + int i; 262 + 263 + UCSI_CMD_GET_CURRENT_CAM(ctrl, con->num); 264 + ret = ucsi_run_command(con->ucsi, &ctrl, &cur, sizeof(cur)); 265 + if (ret < 0) { 266 + if (con->ucsi->ppm->data->version > 0x0100) { 267 + dev_err(con->ucsi->dev, 268 + "GET_CURRENT_CAM command failed\n"); 269 + return; 270 + } 271 + cur = 0xff; 272 + } 273 + 274 + if (cur < UCSI_MAX_ALTMODES) 275 + altmode = typec_altmode_get_partner(con->port_altmode[cur]); 276 + 277 + for (i = 0; con->partner_altmode[i]; i++) 278 + typec_altmode_update_active(con->partner_altmode[i], 279 + con->partner_altmode[i] == altmode); 280 + } 281 + 282 + static u8 ucsi_altmode_next_mode(struct typec_altmode **alt, u16 svid) 283 + { 284 + u8 mode = 1; 285 + int i; 286 + 287 + for (i = 0; alt[i]; i++) 288 + if (alt[i]->svid == svid) 289 + mode++; 290 + 291 + return mode; 292 + } 293 + 294 + static int ucsi_next_altmode(struct typec_altmode **alt) 295 + { 296 + int i = 0; 297 + 298 + for (i = 0; i < UCSI_MAX_ALTMODES; i++) 299 + if (!alt[i]) 300 + return i; 301 + 302 + return -ENOENT; 303 + } 304 + 305 + static int ucsi_register_altmode(struct ucsi_connector *con, 306 + struct typec_altmode_desc *desc, 307 + u8 recipient) 308 + { 309 + struct typec_altmode *alt; 310 + int ret; 311 + int i; 312 + 313 + switch (recipient) { 314 + case UCSI_RECIPIENT_CON: 315 + i = ucsi_next_altmode(con->port_altmode); 316 + if (i < 0) { 317 + ret = i; 318 + goto err; 319 + } 320 + 321 + desc->mode = ucsi_altmode_next_mode(con->port_altmode, 322 + desc->svid); 323 + 324 + alt = typec_port_register_altmode(con->port, desc); 325 + if (IS_ERR(alt)) { 326 + ret = PTR_ERR(alt); 327 + goto err; 328 + } 329 + 330 + con->port_altmode[i] = alt; 331 + break; 332 + case UCSI_RECIPIENT_SOP: 333 + i = ucsi_next_altmode(con->partner_altmode); 334 + if (i < 0) { 335 + ret = i; 336 + goto err; 337 + } 338 + 339 + desc->mode = ucsi_altmode_next_mode(con->partner_altmode, 340 + desc->svid); 341 + 342 + alt = typec_partner_register_altmode(con->partner, desc); 343 + if (IS_ERR(alt)) { 344 + ret = PTR_ERR(alt); 345 + goto err; 346 + } 347 + 348 + con->partner_altmode[i] = alt; 349 + break; 350 + default: 351 + return -EINVAL; 352 + } 353 + 354 + trace_ucsi_register_altmode(recipient, alt); 355 + 356 + return 0; 357 + 358 + err: 359 + dev_err(con->ucsi->dev, "failed to registers svid 0x%04x mode %d\n", 360 + desc->svid, desc->mode); 361 + 362 + return ret; 363 + } 364 + 365 + static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient) 366 + { 367 + int max_altmodes = UCSI_MAX_ALTMODES; 368 + struct typec_altmode_desc desc; 369 + struct ucsi_altmode alt[2]; 370 + struct ucsi_control ctrl; 371 + int num = 1; 372 + int ret; 373 + int len; 374 + int j; 375 + int i; 376 + 377 + if (!(con->ucsi->cap.features & UCSI_CAP_ALT_MODE_DETAILS)) 378 + return 0; 379 + 380 + if (recipient == UCSI_RECIPIENT_SOP && con->partner_altmode[0]) 381 + return 0; 382 + 383 + if (recipient == UCSI_RECIPIENT_CON) 384 + max_altmodes = con->ucsi->cap.num_alt_modes; 385 + 386 + for (i = 0; i < max_altmodes;) { 387 + memset(alt, 0, sizeof(alt)); 388 + UCSI_CMD_GET_ALTERNATE_MODES(ctrl, recipient, con->num, i, 1); 389 + len = ucsi_run_command(con->ucsi, &ctrl, alt, sizeof(alt)); 390 + if (len <= 0) 391 + return len; 392 + 393 + /* 394 + * This code is requesting one alt mode at a time, but some PPMs 395 + * may still return two. If that happens both alt modes need be 396 + * registered and the offset for the next alt mode has to be 397 + * incremented. 398 + */ 399 + num = len / sizeof(alt[0]); 400 + i += num; 401 + 402 + for (j = 0; j < num; j++) { 403 + if (!alt[j].svid) 404 + return 0; 405 + 406 + memset(&desc, 0, sizeof(desc)); 407 + desc.vdo = alt[j].mid; 408 + desc.svid = alt[j].svid; 409 + desc.roles = TYPEC_PORT_DRD; 410 + 411 + ret = ucsi_register_altmode(con, &desc, recipient); 412 + if (ret) 413 + return ret; 414 + } 415 + } 416 + 417 + return 0; 418 + } 419 + 420 + static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient) 421 + { 422 + struct typec_altmode **adev; 423 + int i = 0; 424 + 425 + switch (recipient) { 426 + case UCSI_RECIPIENT_CON: 427 + adev = con->port_altmode; 428 + break; 429 + case UCSI_RECIPIENT_SOP: 430 + adev = con->partner_altmode; 431 + break; 432 + default: 433 + return; 434 + } 435 + 436 + while (adev[i]) { 437 + typec_unregister_altmode(adev[i]); 438 + adev[i++] = NULL; 439 + } 440 + } 199 441 200 442 static void ucsi_pwr_opmode_change(struct ucsi_connector *con) 201 443 { ··· 455 299 if (!con->partner) 456 300 return; 457 301 302 + ucsi_unregister_altmodes(con, UCSI_RECIPIENT_SOP); 458 303 typec_unregister_partner(con->partner); 459 304 con->partner = NULL; 305 + } 306 + 307 + static void ucsi_partner_change(struct ucsi_connector *con) 308 + { 309 + int ret; 310 + 311 + if (!con->partner) 312 + return; 313 + 314 + switch (con->status.partner_type) { 315 + case UCSI_CONSTAT_PARTNER_TYPE_UFP: 316 + typec_set_data_role(con->port, TYPEC_HOST); 317 + break; 318 + case UCSI_CONSTAT_PARTNER_TYPE_DFP: 319 + typec_set_data_role(con->port, TYPEC_DEVICE); 320 + break; 321 + default: 322 + break; 323 + } 324 + 325 + /* Complete pending data role swap */ 326 + if (!completion_done(&con->complete)) 327 + complete(&con->complete); 328 + 329 + /* Can't rely on Partner Flags field. Always checking the alt modes. */ 330 + ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); 331 + if (ret) 332 + dev_err(con->ucsi->dev, 333 + "con%d: failed to register partner alternate modes\n", 334 + con->num); 335 + else 336 + ucsi_altmode_update_active(con); 460 337 } 461 338 462 339 static void ucsi_connector_change(struct work_struct *work) ··· 500 311 struct ucsi_control ctrl; 501 312 int ret; 502 313 503 - mutex_lock(&ucsi->ppm_lock); 314 + mutex_lock(&con->lock); 504 315 505 316 UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); 506 - ret = ucsi_run_command(ucsi, &ctrl, &con->status, sizeof(con->status)); 317 + ret = ucsi_send_command(ucsi, &ctrl, &con->status, sizeof(con->status)); 507 318 if (ret < 0) { 508 319 dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n", 509 320 __func__, ret); ··· 517 328 typec_set_pwr_role(con->port, con->status.pwr_dir); 518 329 519 330 /* Complete pending power role swap */ 520 - if (!completion_done(&con->complete)) 521 - complete(&con->complete); 522 - } 523 - 524 - if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) { 525 - switch (con->status.partner_type) { 526 - case UCSI_CONSTAT_PARTNER_TYPE_UFP: 527 - typec_set_data_role(con->port, TYPEC_HOST); 528 - break; 529 - case UCSI_CONSTAT_PARTNER_TYPE_DFP: 530 - typec_set_data_role(con->port, TYPEC_DEVICE); 531 - break; 532 - default: 533 - break; 534 - } 535 - 536 - /* Complete pending data role swap */ 537 331 if (!completion_done(&con->complete)) 538 332 complete(&con->complete); 539 333 } ··· 541 369 ucsi_unregister_partner(con); 542 370 } 543 371 372 + if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) { 373 + /* 374 + * We don't need to know the currently supported alt modes here. 375 + * Running GET_CAM_SUPPORTED command just to make sure the PPM 376 + * does not get stuck in case it assumes we do so. 377 + */ 378 + UCSI_CMD_GET_CAM_SUPPORTED(ctrl, con->num); 379 + ucsi_run_command(con->ucsi, &ctrl, NULL, 0); 380 + } 381 + 382 + if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) 383 + ucsi_partner_change(con); 384 + 544 385 ret = ucsi_ack(ucsi, UCSI_ACK_EVENT); 545 386 if (ret) 546 387 dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret); ··· 562 377 563 378 out_unlock: 564 379 clear_bit(EVENT_PENDING, &ucsi->flags); 565 - mutex_unlock(&ucsi->ppm_lock); 380 + mutex_unlock(&con->lock); 566 381 } 567 382 568 383 /** ··· 612 427 613 428 UCSI_CMD_CONNECTOR_RESET(ctrl, con, hard); 614 429 615 - return ucsi_run_command(con->ucsi, &ctrl, NULL, 0); 430 + return ucsi_send_command(con->ucsi, &ctrl, NULL, 0); 616 431 } 617 432 618 433 static int ucsi_reset_ppm(struct ucsi *ucsi) ··· 666 481 { 667 482 int ret; 668 483 669 - ret = ucsi_run_command(con->ucsi, ctrl, NULL, 0); 484 + ret = ucsi_send_command(con->ucsi, ctrl, NULL, 0); 670 485 if (ret == -ETIMEDOUT) { 671 486 struct ucsi_control c; 672 487 673 488 /* PPM most likely stopped responding. Resetting everything. */ 489 + mutex_lock(&con->ucsi->ppm_lock); 674 490 ucsi_reset_ppm(con->ucsi); 491 + mutex_unlock(&con->ucsi->ppm_lock); 675 492 676 493 UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL); 677 - ucsi_run_command(con->ucsi, &c, NULL, 0); 494 + ucsi_send_command(con->ucsi, &c, NULL, 0); 678 495 679 496 ucsi_reset_connector(con, true); 680 497 } ··· 691 504 struct ucsi_control ctrl; 692 505 int ret = 0; 693 506 694 - if (!con->partner) 695 - return -ENOTCONN; 507 + mutex_lock(&con->lock); 696 508 697 - mutex_lock(&con->ucsi->ppm_lock); 509 + if (!con->partner) { 510 + ret = -ENOTCONN; 511 + goto out_unlock; 512 + } 698 513 699 514 if ((con->status.partner_type == UCSI_CONSTAT_PARTNER_TYPE_DFP && 700 515 role == TYPEC_DEVICE) || ··· 709 520 if (ret < 0) 710 521 goto out_unlock; 711 522 712 - mutex_unlock(&con->ucsi->ppm_lock); 713 - 714 523 if (!wait_for_completion_timeout(&con->complete, 715 524 msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) 716 - return -ETIMEDOUT; 717 - 718 - return 0; 525 + ret = -ETIMEDOUT; 719 526 720 527 out_unlock: 721 - mutex_unlock(&con->ucsi->ppm_lock); 528 + mutex_unlock(&con->lock); 722 529 723 - return ret; 530 + return ret < 0 ? ret : 0; 724 531 } 725 532 726 533 static int ··· 726 541 struct ucsi_control ctrl; 727 542 int ret = 0; 728 543 729 - if (!con->partner) 730 - return -ENOTCONN; 544 + mutex_lock(&con->lock); 731 545 732 - mutex_lock(&con->ucsi->ppm_lock); 546 + if (!con->partner) { 547 + ret = -ENOTCONN; 548 + goto out_unlock; 549 + } 733 550 734 551 if (con->status.pwr_dir == role) 735 552 goto out_unlock; ··· 741 554 if (ret < 0) 742 555 goto out_unlock; 743 556 744 - mutex_unlock(&con->ucsi->ppm_lock); 745 - 746 557 if (!wait_for_completion_timeout(&con->complete, 747 - msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) 748 - return -ETIMEDOUT; 749 - 750 - mutex_lock(&con->ucsi->ppm_lock); 558 + msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) { 559 + ret = -ETIMEDOUT; 560 + goto out_unlock; 561 + } 751 562 752 563 /* Something has gone wrong while swapping the role */ 753 564 if (con->status.pwr_op_mode != UCSI_CONSTAT_PWR_OPMODE_PD) { ··· 754 569 } 755 570 756 571 out_unlock: 757 - mutex_unlock(&con->ucsi->ppm_lock); 572 + mutex_unlock(&con->lock); 758 573 759 574 return ret; 760 575 } ··· 780 595 781 596 INIT_WORK(&con->work, ucsi_connector_change); 782 597 init_completion(&con->complete); 598 + mutex_init(&con->lock); 783 599 con->num = index + 1; 784 600 con->ucsi = ucsi; 785 601 ··· 822 636 if (IS_ERR(con->port)) 823 637 return PTR_ERR(con->port); 824 638 639 + /* Alternate modes */ 640 + ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON); 641 + if (ret) 642 + dev_err(ucsi->dev, "con%d: failed to register alt modes\n", 643 + con->num); 644 + 825 645 /* Get the status */ 826 646 UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); 827 647 ret = ucsi_run_command(ucsi, &ctrl, &con->status, sizeof(con->status)); ··· 853 661 /* Check if there is already something connected */ 854 662 if (con->status.connected) 855 663 ucsi_register_partner(con); 664 + 665 + if (con->partner) { 666 + ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); 667 + if (ret) 668 + dev_err(ucsi->dev, 669 + "con%d: failed to register alternate modes\n", 670 + con->num); 671 + else 672 + ucsi_altmode_update_active(con); 673 + } 856 674 857 675 trace_ucsi_register_port(con->num, &con->status); 858 676 ··· 932 730 err_unregister: 933 731 for (con = ucsi->connector; con->port; con++) { 934 732 ucsi_unregister_partner(con); 733 + ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON); 935 734 typec_unregister_port(con->port); 936 735 con->port = NULL; 937 736 } ··· 991 788 /* Make sure that we are not in the middle of driver initialization */ 992 789 cancel_work_sync(&ucsi->work); 993 790 994 - mutex_lock(&ucsi->ppm_lock); 995 - 996 791 /* Disable everything except command complete notification */ 997 792 UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE) 998 - ucsi_run_command(ucsi, &ctrl, NULL, 0); 999 - 1000 - mutex_unlock(&ucsi->ppm_lock); 793 + ucsi_send_command(ucsi, &ctrl, NULL, 0); 1001 794 1002 795 for (i = 0; i < ucsi->cap.num_connectors; i++) { 1003 796 cancel_work_sync(&ucsi->connector[i].work); 1004 797 ucsi_unregister_partner(&ucsi->connector[i]); 798 + ucsi_unregister_altmodes(&ucsi->connector[i], 799 + UCSI_RECIPIENT_CON); 1005 800 typec_unregister_port(ucsi->connector[i].port); 1006 801 } 1007 802
+97
drivers/usb/typec/ucsi/ucsi.h
··· 6 6 #include <linux/bitops.h> 7 7 #include <linux/device.h> 8 8 #include <linux/types.h> 9 + #include <linux/usb/typec.h> 9 10 10 11 /* -------------------------------------------------------------------------- */ 11 12 ··· 61 60 u16:6; /* reserved */ 62 61 } __packed; 63 62 63 + /* Get Alternate Modes Command structure */ 64 + struct ucsi_altmode_cmd { 65 + u8 cmd; 66 + u8 length; 67 + u8 recipient; 68 + #define UCSI_RECIPIENT_CON 0 69 + #define UCSI_RECIPIENT_SOP 1 70 + #define UCSI_RECIPIENT_SOP_P 2 71 + #define UCSI_RECIPIENT_SOP_PP 3 72 + u8 con_num; 73 + u8 offset; 74 + u8 num_altmodes; 75 + } __packed; 76 + 64 77 struct ucsi_control { 65 78 union { 66 79 u64 raw_cmd; ··· 82 67 struct ucsi_uor_cmd uor; 83 68 struct ucsi_ack_cmd ack; 84 69 struct ucsi_con_rst con_rst; 70 + struct ucsi_altmode_cmd alt; 85 71 }; 86 72 }; 87 73 ··· 126 110 { \ 127 111 __UCSI_CMD(_ctrl_, UCSI_GET_CONNECTOR_CAPABILITY) \ 128 112 (_ctrl_).cmd.data = _con_; \ 113 + } 114 + 115 + /* Helper for preparing ucsi_control for GET_ALTERNATE_MODES command. */ 116 + #define UCSI_CMD_GET_ALTERNATE_MODES(_ctrl_, _r_, _con_num_, _o_, _num_)\ 117 + { \ 118 + __UCSI_CMD((_ctrl_), UCSI_GET_ALTERNATE_MODES) \ 119 + _ctrl_.alt.recipient = (_r_); \ 120 + _ctrl_.alt.con_num = (_con_num_); \ 121 + _ctrl_.alt.offset = (_o_); \ 122 + _ctrl_.alt.num_altmodes = (_num_) - 1; \ 123 + } 124 + 125 + /* Helper for preparing ucsi_control for GET_CAM_SUPPORTED command. */ 126 + #define UCSI_CMD_GET_CAM_SUPPORTED(_ctrl_, _con_) \ 127 + { \ 128 + __UCSI_CMD((_ctrl_), UCSI_GET_CAM_SUPPORTED) \ 129 + _ctrl_.cmd.data = (_con_); \ 130 + } 131 + 132 + /* Helper for preparing ucsi_control for GET_CAM_SUPPORTED command. */ 133 + #define UCSI_CMD_GET_CURRENT_CAM(_ctrl_, _con_) \ 134 + { \ 135 + __UCSI_CMD((_ctrl_), UCSI_GET_CURRENT_CAM) \ 136 + _ctrl_.cmd.data = (_con_); \ 129 137 } 130 138 131 139 /* Helper for preparing ucsi_control for GET_CONNECTOR_STATUS command. */ ··· 373 333 struct ucsi *ucsi_register_ppm(struct device *dev, struct ucsi_ppm *ppm); 374 334 void ucsi_unregister_ppm(struct ucsi *ucsi); 375 335 void ucsi_notify(struct ucsi *ucsi); 336 + 337 + /* -------------------------------------------------------------------------- */ 338 + 339 + enum ucsi_status { 340 + UCSI_IDLE = 0, 341 + UCSI_BUSY, 342 + UCSI_ERROR, 343 + }; 344 + 345 + struct ucsi { 346 + struct device *dev; 347 + struct ucsi_ppm *ppm; 348 + 349 + enum ucsi_status status; 350 + struct completion complete; 351 + struct ucsi_capability cap; 352 + struct ucsi_connector *connector; 353 + 354 + struct work_struct work; 355 + 356 + /* PPM Communication lock */ 357 + struct mutex ppm_lock; 358 + 359 + /* PPM communication flags */ 360 + unsigned long flags; 361 + #define EVENT_PENDING 0 362 + #define COMMAND_PENDING 1 363 + #define ACK_PENDING 2 364 + }; 365 + 366 + #define UCSI_MAX_SVID 5 367 + #define UCSI_MAX_ALTMODES (UCSI_MAX_SVID * 6) 368 + 369 + struct ucsi_connector { 370 + int num; 371 + 372 + struct ucsi *ucsi; 373 + struct mutex lock; /* port lock */ 374 + struct work_struct work; 375 + struct completion complete; 376 + 377 + struct typec_port *port; 378 + struct typec_partner *partner; 379 + 380 + struct typec_altmode *port_altmode[UCSI_MAX_ALTMODES]; 381 + struct typec_altmode *partner_altmode[UCSI_MAX_ALTMODES]; 382 + 383 + struct typec_capability typec_cap; 384 + 385 + struct ucsi_connector_status status; 386 + struct ucsi_connector_capability cap; 387 + }; 388 + 389 + int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl, 390 + void *retval, size_t size); 391 + 392 + void ucsi_altmode_update_active(struct ucsi_connector *con); 376 393 377 394 #endif /* __DRIVER_USB_TYPEC_UCSI_H */