@@ -562,8 +562,9 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient)
562
562
}
563
563
}
564
564
565
- static int ucsi_get_pdos (struct ucsi_connector * con , int is_partner ,
566
- u32 * pdos , int offset , int num_pdos )
565
+ static int ucsi_read_pdos (struct ucsi_connector * con ,
566
+ enum typec_role role , int is_partner ,
567
+ u32 * pdos , int offset , int num_pdos )
567
568
{
568
569
struct ucsi * ucsi = con -> ucsi ;
569
570
u64 command ;
@@ -573,7 +574,7 @@ static int ucsi_get_pdos(struct ucsi_connector *con, int is_partner,
573
574
command |= UCSI_GET_PDOS_PARTNER_PDO (is_partner );
574
575
command |= UCSI_GET_PDOS_PDO_OFFSET (offset );
575
576
command |= UCSI_GET_PDOS_NUM_PDOS (num_pdos - 1 );
576
- command |= UCSI_GET_PDOS_SRC_PDOS ;
577
+ command |= is_source ( role ) ? UCSI_GET_PDOS_SRC_PDOS : 0 ;
577
578
ret = ucsi_send_command (ucsi , command , pdos + offset ,
578
579
num_pdos * sizeof (u32 ));
579
580
if (ret < 0 && ret != - ETIMEDOUT )
@@ -582,30 +583,43 @@ static int ucsi_get_pdos(struct ucsi_connector *con, int is_partner,
582
583
return ret ;
583
584
}
584
585
585
- static int ucsi_get_src_pdos (struct ucsi_connector * con )
586
+ static int ucsi_get_pdos (struct ucsi_connector * con , enum typec_role role ,
587
+ int is_partner , u32 * pdos )
586
588
{
589
+ u8 num_pdos ;
587
590
int ret ;
588
591
589
592
/* UCSI max payload means only getting at most 4 PDOs at a time */
590
- ret = ucsi_get_pdos (con , 1 , con -> src_pdos , 0 , UCSI_MAX_PDOS );
593
+ ret = ucsi_read_pdos (con , role , is_partner , pdos , 0 , UCSI_MAX_PDOS );
591
594
if (ret < 0 )
592
595
return ret ;
593
596
594
- con -> num_pdos = ret / sizeof (u32 ); /* number of bytes to 32-bit PDOs */
595
- if (con -> num_pdos < UCSI_MAX_PDOS )
596
- return 0 ;
597
+ num_pdos = ret / sizeof (u32 ); /* number of bytes to 32-bit PDOs */
598
+ if (num_pdos < UCSI_MAX_PDOS )
599
+ return num_pdos ;
597
600
598
601
/* get the remaining PDOs, if any */
599
- ret = ucsi_get_pdos (con , 1 , con -> src_pdos , UCSI_MAX_PDOS ,
600
- PDO_MAX_OBJECTS - UCSI_MAX_PDOS );
602
+ ret = ucsi_read_pdos (con , role , is_partner , pdos , UCSI_MAX_PDOS ,
603
+ PDO_MAX_OBJECTS - UCSI_MAX_PDOS );
601
604
if (ret < 0 )
602
605
return ret ;
603
606
604
- con -> num_pdos += ret / sizeof (u32 );
607
+ return ret / sizeof (u32 ) + num_pdos ;
608
+ }
609
+
610
+ static int ucsi_get_src_pdos (struct ucsi_connector * con )
611
+ {
612
+ int ret ;
613
+
614
+ ret = ucsi_get_pdos (con , TYPEC_SOURCE , 1 , con -> src_pdos );
615
+ if (ret < 0 )
616
+ return ret ;
617
+
618
+ con -> num_pdos = ret ;
605
619
606
620
ucsi_port_psy_changed (con );
607
621
608
- return 0 ;
622
+ return ret ;
609
623
}
610
624
611
625
static int ucsi_check_altmodes (struct ucsi_connector * con )
@@ -630,6 +644,72 @@ static int ucsi_check_altmodes(struct ucsi_connector *con)
630
644
return ret ;
631
645
}
632
646
647
+ static int ucsi_register_partner_pdos (struct ucsi_connector * con )
648
+ {
649
+ struct usb_power_delivery_desc desc = { con -> ucsi -> cap .pd_version };
650
+ struct usb_power_delivery_capabilities_desc caps ;
651
+ struct usb_power_delivery_capabilities * cap ;
652
+ int ret ;
653
+
654
+ if (con -> partner_pd )
655
+ return 0 ;
656
+
657
+ con -> partner_pd = usb_power_delivery_register (NULL , & desc );
658
+ if (IS_ERR (con -> partner_pd ))
659
+ return PTR_ERR (con -> partner_pd );
660
+
661
+ ret = ucsi_get_pdos (con , TYPEC_SOURCE , 1 , caps .pdo );
662
+ if (ret > 0 ) {
663
+ if (ret < PDO_MAX_OBJECTS )
664
+ caps .pdo [ret ] = 0 ;
665
+
666
+ caps .role = TYPEC_SOURCE ;
667
+ cap = usb_power_delivery_register_capabilities (con -> partner_pd , & caps );
668
+ if (IS_ERR (cap ))
669
+ return PTR_ERR (cap );
670
+
671
+ con -> partner_source_caps = cap ;
672
+
673
+ ret = typec_partner_set_usb_power_delivery (con -> partner , con -> partner_pd );
674
+ if (ret ) {
675
+ usb_power_delivery_unregister_capabilities (con -> partner_source_caps );
676
+ return ret ;
677
+ }
678
+ }
679
+
680
+ ret = ucsi_get_pdos (con , TYPEC_SINK , 1 , caps .pdo );
681
+ if (ret > 0 ) {
682
+ if (ret < PDO_MAX_OBJECTS )
683
+ caps .pdo [ret ] = 0 ;
684
+
685
+ caps .role = TYPEC_SINK ;
686
+
687
+ cap = usb_power_delivery_register_capabilities (con -> partner_pd , & caps );
688
+ if (IS_ERR (cap ))
689
+ return PTR_ERR (cap );
690
+
691
+ con -> partner_sink_caps = cap ;
692
+
693
+ ret = typec_partner_set_usb_power_delivery (con -> partner , con -> partner_pd );
694
+ if (ret ) {
695
+ usb_power_delivery_unregister_capabilities (con -> partner_sink_caps );
696
+ return ret ;
697
+ }
698
+ }
699
+
700
+ return 0 ;
701
+ }
702
+
703
+ static void ucsi_unregister_partner_pdos (struct ucsi_connector * con )
704
+ {
705
+ usb_power_delivery_unregister_capabilities (con -> partner_sink_caps );
706
+ con -> partner_sink_caps = NULL ;
707
+ usb_power_delivery_unregister_capabilities (con -> partner_source_caps );
708
+ con -> partner_source_caps = NULL ;
709
+ usb_power_delivery_unregister (con -> partner_pd );
710
+ con -> partner_pd = NULL ;
711
+ }
712
+
633
713
static void ucsi_pwr_opmode_change (struct ucsi_connector * con )
634
714
{
635
715
switch (UCSI_CONSTAT_PWR_OPMODE (con -> status .flags )) {
@@ -638,6 +718,7 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
638
718
typec_set_pwr_opmode (con -> port , TYPEC_PWR_MODE_PD );
639
719
ucsi_partner_task (con , ucsi_get_src_pdos , 30 , 0 );
640
720
ucsi_partner_task (con , ucsi_check_altmodes , 30 , 0 );
721
+ ucsi_partner_task (con , ucsi_register_partner_pdos , 1 , HZ );
641
722
break ;
642
723
case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5 :
643
724
con -> rdo = 0 ;
@@ -696,6 +777,7 @@ static void ucsi_unregister_partner(struct ucsi_connector *con)
696
777
if (!con -> partner )
697
778
return ;
698
779
780
+ ucsi_unregister_partner_pdos (con );
699
781
ucsi_unregister_altmodes (con , UCSI_RECIPIENT_SOP );
700
782
typec_unregister_partner (con -> partner );
701
783
con -> partner = NULL ;
@@ -800,6 +882,10 @@ static void ucsi_handle_connector_change(struct work_struct *work)
800
882
if (con -> status .flags & UCSI_CONSTAT_CONNECTED ) {
801
883
ucsi_register_partner (con );
802
884
ucsi_partner_task (con , ucsi_check_connection , 1 , HZ );
885
+
886
+ if (UCSI_CONSTAT_PWR_OPMODE (con -> status .flags ) ==
887
+ UCSI_CONSTAT_PWR_OPMODE_PD )
888
+ ucsi_partner_task (con , ucsi_register_partner_pdos , 1 , HZ );
803
889
} else {
804
890
ucsi_unregister_partner (con );
805
891
}
@@ -1036,6 +1122,9 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con)
1036
1122
1037
1123
static int ucsi_register_port (struct ucsi * ucsi , int index )
1038
1124
{
1125
+ struct usb_power_delivery_desc desc = { ucsi -> cap .pd_version };
1126
+ struct usb_power_delivery_capabilities_desc pd_caps ;
1127
+ struct usb_power_delivery_capabilities * pd_cap ;
1039
1128
struct ucsi_connector * con = & ucsi -> connector [index ];
1040
1129
struct typec_capability * cap = & con -> typec_cap ;
1041
1130
enum typec_accessory * accessory = cap -> accessory ;
@@ -1114,6 +1203,41 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
1114
1203
goto out ;
1115
1204
}
1116
1205
1206
+ con -> pd = usb_power_delivery_register (ucsi -> dev , & desc );
1207
+
1208
+ ret = ucsi_get_pdos (con , TYPEC_SOURCE , 0 , pd_caps .pdo );
1209
+ if (ret > 0 ) {
1210
+ if (ret < PDO_MAX_OBJECTS )
1211
+ pd_caps .pdo [ret ] = 0 ;
1212
+
1213
+ pd_caps .role = TYPEC_SOURCE ;
1214
+ pd_cap = usb_power_delivery_register_capabilities (con -> pd , & pd_caps );
1215
+ if (IS_ERR (pd_cap )) {
1216
+ ret = PTR_ERR (pd_cap );
1217
+ goto out ;
1218
+ }
1219
+
1220
+ con -> port_source_caps = pd_cap ;
1221
+ typec_port_set_usb_power_delivery (con -> port , con -> pd );
1222
+ }
1223
+
1224
+ memset (& pd_caps , 0 , sizeof (pd_caps ));
1225
+ ret = ucsi_get_pdos (con , TYPEC_SINK , 0 , pd_caps .pdo );
1226
+ if (ret > 0 ) {
1227
+ if (ret < PDO_MAX_OBJECTS )
1228
+ pd_caps .pdo [ret ] = 0 ;
1229
+
1230
+ pd_caps .role = TYPEC_SINK ;
1231
+ pd_cap = usb_power_delivery_register_capabilities (con -> pd , & pd_caps );
1232
+ if (IS_ERR (pd_cap )) {
1233
+ ret = PTR_ERR (pd_cap );
1234
+ goto out ;
1235
+ }
1236
+
1237
+ con -> port_sink_caps = pd_cap ;
1238
+ typec_port_set_usb_power_delivery (con -> port , con -> pd );
1239
+ }
1240
+
1117
1241
/* Alternate modes */
1118
1242
ret = ucsi_register_altmodes (con , UCSI_RECIPIENT_CON );
1119
1243
if (ret ) {
@@ -1152,8 +1276,8 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
1152
1276
if (con -> status .flags & UCSI_CONSTAT_CONNECTED ) {
1153
1277
typec_set_pwr_role (con -> port ,
1154
1278
!!(con -> status .flags & UCSI_CONSTAT_PWR_DIR ));
1155
- ucsi_pwr_opmode_change (con );
1156
1279
ucsi_register_partner (con );
1280
+ ucsi_pwr_opmode_change (con );
1157
1281
ucsi_port_psy_changed (con );
1158
1282
}
1159
1283
@@ -1259,6 +1383,13 @@ static int ucsi_init(struct ucsi *ucsi)
1259
1383
ucsi_unregister_port_psy (con );
1260
1384
if (con -> wq )
1261
1385
destroy_workqueue (con -> wq );
1386
+
1387
+ usb_power_delivery_unregister_capabilities (con -> port_sink_caps );
1388
+ con -> port_sink_caps = NULL ;
1389
+ usb_power_delivery_unregister_capabilities (con -> port_source_caps );
1390
+ con -> port_source_caps = NULL ;
1391
+ usb_power_delivery_unregister (con -> pd );
1392
+ con -> pd = NULL ;
1262
1393
typec_unregister_port (con -> port );
1263
1394
con -> port = NULL ;
1264
1395
}
@@ -1422,6 +1553,12 @@ void ucsi_unregister(struct ucsi *ucsi)
1422
1553
ucsi_unregister_port_psy (& ucsi -> connector [i ]);
1423
1554
if (ucsi -> connector [i ].wq )
1424
1555
destroy_workqueue (ucsi -> connector [i ].wq );
1556
+ usb_power_delivery_unregister_capabilities (ucsi -> connector [i ].port_sink_caps );
1557
+ ucsi -> connector [i ].port_sink_caps = NULL ;
1558
+ usb_power_delivery_unregister_capabilities (ucsi -> connector [i ].port_source_caps );
1559
+ ucsi -> connector [i ].port_source_caps = NULL ;
1560
+ usb_power_delivery_unregister (ucsi -> connector [i ].pd );
1561
+ ucsi -> connector [i ].pd = NULL ;
1425
1562
typec_unregister_port (ucsi -> connector [i ].port );
1426
1563
}
1427
1564
0 commit comments