1
2
3
4
5
6
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
25
26
27
28
29
30
31#define UCSI_TIMEOUT_MS 5000
32
33
34
35
36
37
38
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
76 struct mutex ppm_lock;
77
78
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
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
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
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
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
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
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
385
386
387
388
389void ucsi_notify(struct ucsi *ucsi)
390{
391 struct ucsi_cci *cci;
392
393
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
450 ret = ucsi_sync(ucsi);
451 if (ret)
452 goto err;
453
454 if (ucsi->ppm->data->cci.reset_complete)
455 break;
456
457
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
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
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
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
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
635 con->port = typec_register_port(ucsi->dev, cap);
636 if (IS_ERR(con->port))
637 return PTR_ERR(con->port);
638
639
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
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
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
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
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
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
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
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
746
747
748
749
750
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
769
770
771 queue_work(system_long_wq, &ucsi->work);
772
773 return ucsi;
774}
775EXPORT_SYMBOL_GPL(ucsi_register_ppm);
776
777
778
779
780
781
782
783void ucsi_unregister_ppm(struct ucsi *ucsi)
784{
785 struct ucsi_control ctrl;
786 int i;
787
788
789 cancel_work_sync(&ucsi->work);
790
791 mutex_lock(&ucsi->ppm_lock);
792
793
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