@@ -191,6 +191,64 @@ int ucsi_resume(struct ucsi *ucsi)
191191EXPORT_SYMBOL_GPL (ucsi_resume );
192192/* -------------------------------------------------------------------------- */
193193
194+ struct ucsi_work {
195+ struct delayed_work work ;
196+ unsigned long delay ;
197+ unsigned int count ;
198+ struct ucsi_connector * con ;
199+ int (* cb )(struct ucsi_connector * );
200+ };
201+
202+ static void ucsi_poll_worker (struct work_struct * work )
203+ {
204+ struct ucsi_work * uwork = container_of (work , struct ucsi_work , work .work );
205+ struct ucsi_connector * con = uwork -> con ;
206+ int ret ;
207+
208+ mutex_lock (& con -> lock );
209+
210+ if (!con -> partner ) {
211+ mutex_unlock (& con -> lock );
212+ kfree (uwork );
213+ return ;
214+ }
215+
216+ ret = uwork -> cb (con );
217+
218+ if (uwork -> count -- && (ret == - EBUSY || ret == - ETIMEDOUT ))
219+ queue_delayed_work (con -> wq , & uwork -> work , uwork -> delay );
220+ else
221+ kfree (uwork );
222+
223+ mutex_unlock (& con -> lock );
224+ }
225+
226+ static int ucsi_partner_task (struct ucsi_connector * con ,
227+ int (* cb )(struct ucsi_connector * ),
228+ int retries , unsigned long delay )
229+ {
230+ struct ucsi_work * uwork ;
231+
232+ if (!con -> partner )
233+ return 0 ;
234+
235+ uwork = kzalloc (sizeof (* uwork ), GFP_KERNEL );
236+ if (!uwork )
237+ return - ENOMEM ;
238+
239+ INIT_DELAYED_WORK (& uwork -> work , ucsi_poll_worker );
240+ uwork -> count = retries ;
241+ uwork -> delay = delay ;
242+ uwork -> con = con ;
243+ uwork -> cb = cb ;
244+
245+ queue_delayed_work (con -> wq , & uwork -> work , delay );
246+
247+ return 0 ;
248+ }
249+
250+ /* -------------------------------------------------------------------------- */
251+
194252void ucsi_altmode_update_active (struct ucsi_connector * con )
195253{
196254 const struct typec_altmode * altmode = NULL ;
@@ -543,6 +601,25 @@ static void ucsi_get_src_pdos(struct ucsi_connector *con, int is_partner)
543601 con -> num_pdos += ret / sizeof (u32 );
544602}
545603
604+ static int ucsi_check_altmodes (struct ucsi_connector * con )
605+ {
606+ int ret ;
607+
608+ ret = ucsi_register_altmodes (con , UCSI_RECIPIENT_SOP );
609+ if (ret && ret != - ETIMEDOUT )
610+ dev_err (con -> ucsi -> dev ,
611+ "con%d: failed to register partner alt modes (%d)\n" ,
612+ con -> num , ret );
613+
614+ /* Ignoring the errors in this case. */
615+ if (con -> partner_altmode [0 ]) {
616+ ucsi_altmode_update_active (con );
617+ return 0 ;
618+ }
619+
620+ return ret ;
621+ }
622+
546623static void ucsi_pwr_opmode_change (struct ucsi_connector * con )
547624{
548625 switch (UCSI_CONSTAT_PWR_OPMODE (con -> status .flags )) {
@@ -650,14 +727,7 @@ static void ucsi_partner_change(struct ucsi_connector *con)
650727 dev_err (con -> ucsi -> dev , "con:%d: failed to set usb role:%d\n" ,
651728 con -> num , u_role );
652729
653- /* Can't rely on Partner Flags field. Always checking the alt modes. */
654- ret = ucsi_register_altmodes (con , UCSI_RECIPIENT_SOP );
655- if (ret )
656- dev_err (con -> ucsi -> dev ,
657- "con%d: failed to register partner alternate modes\n" ,
658- con -> num );
659- else
660- ucsi_altmode_update_active (con );
730+ ucsi_partner_task (con , ucsi_check_altmodes , 30 , 0 );
661731}
662732
663733static void ucsi_handle_connector_change (struct work_struct * work )
@@ -1045,8 +1115,18 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
10451115 enum typec_accessory * accessory = cap -> accessory ;
10461116 enum usb_role u_role = USB_ROLE_NONE ;
10471117 u64 command ;
1118+ char * name ;
10481119 int ret ;
10491120
1121+ name = kasprintf (GFP_KERNEL , "%s-con%d" , dev_name (ucsi -> dev ), con -> num );
1122+ if (!name )
1123+ return - ENOMEM ;
1124+
1125+ con -> wq = create_singlethread_workqueue (name );
1126+ kfree (name );
1127+ if (!con -> wq )
1128+ return - ENOMEM ;
1129+
10501130 INIT_WORK (& con -> work , ucsi_handle_connector_change );
10511131 init_completion (& con -> complete );
10521132 mutex_init (& con -> lock );
@@ -1164,24 +1244,21 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
11641244 ret = 0 ;
11651245 }
11661246
1167- if (con -> partner ) {
1168- ret = ucsi_register_altmodes (con , UCSI_RECIPIENT_SOP );
1169- if (ret ) {
1170- dev_err (ucsi -> dev ,
1171- "con%d: failed to register alternate modes\n" ,
1172- con -> num );
1173- ret = 0 ;
1174- } else {
1175- ucsi_altmode_update_active (con );
1176- }
1177- }
1247+ if (con -> partner )
1248+ ucsi_check_altmodes (con );
11781249
11791250 trace_ucsi_register_port (con -> num , & con -> status );
11801251
11811252out :
11821253 fwnode_handle_put (cap -> fwnode );
11831254out_unlock :
11841255 mutex_unlock (& con -> lock );
1256+
1257+ if (ret && con -> wq ) {
1258+ destroy_workqueue (con -> wq );
1259+ con -> wq = NULL ;
1260+ }
1261+
11851262 return ret ;
11861263}
11871264
@@ -1252,6 +1329,8 @@ static int ucsi_init(struct ucsi *ucsi)
12521329 ucsi_unregister_partner (con );
12531330 ucsi_unregister_altmodes (con , UCSI_RECIPIENT_CON );
12541331 ucsi_unregister_port_psy (con );
1332+ if (con -> wq )
1333+ destroy_workqueue (con -> wq );
12551334 typec_unregister_port (con -> port );
12561335 con -> port = NULL ;
12571336 }
@@ -1374,6 +1453,8 @@ void ucsi_unregister(struct ucsi *ucsi)
13741453 ucsi_unregister_altmodes (& ucsi -> connector [i ],
13751454 UCSI_RECIPIENT_CON );
13761455 ucsi_unregister_port_psy (& ucsi -> connector [i ]);
1456+ if (ucsi -> connector [i ].wq )
1457+ destroy_workqueue (ucsi -> connector [i ].wq );
13771458 typec_unregister_port (ucsi -> connector [i ].port );
13781459 }
13791460
0 commit comments