14
14
#include <linux/platform_data/cros_usbpd_notify.h>
15
15
#include <linux/platform_device.h>
16
16
#include <linux/usb/typec.h>
17
+ #include <linux/usb/typec_altmode.h>
17
18
#include <linux/usb/typec_mux.h>
18
19
#include <linux/usb/role.h>
19
20
@@ -30,6 +31,10 @@ struct cros_typec_port {
30
31
struct typec_switch * ori_sw ;
31
32
struct typec_mux * mux ;
32
33
struct usb_role_switch * role_sw ;
34
+
35
+ /* Variables keeping track of switch state. */
36
+ struct typec_mux_state state ;
37
+ uint8_t mux_flags ;
33
38
};
34
39
35
40
/* Platform-specific data for the Chrome OS EC Type C controller. */
@@ -264,6 +269,23 @@ static int cros_typec_add_partner(struct cros_typec_data *typec, int port_num,
264
269
return ret ;
265
270
}
266
271
272
+ static void cros_typec_remove_partner (struct cros_typec_data * typec ,
273
+ int port_num )
274
+ {
275
+ struct cros_typec_port * port = typec -> ports [port_num ];
276
+
277
+ port -> state .alt = NULL ;
278
+ port -> state .mode = TYPEC_STATE_USB ;
279
+ port -> state .data = NULL ;
280
+
281
+ usb_role_switch_set_role (port -> role_sw , USB_ROLE_NONE );
282
+ typec_switch_set (port -> ori_sw , TYPEC_ORIENTATION_NONE );
283
+ typec_mux_set (port -> mux , & port -> state );
284
+
285
+ typec_unregister_partner (port -> partner );
286
+ port -> partner = NULL ;
287
+ }
288
+
267
289
static void cros_typec_set_port_params_v0 (struct cros_typec_data * typec ,
268
290
int port_num , struct ec_response_usb_pd_control * resp )
269
291
{
@@ -317,16 +339,69 @@ static void cros_typec_set_port_params_v1(struct cros_typec_data *typec,
317
339
} else {
318
340
if (!typec -> ports [port_num ]-> partner )
319
341
return ;
342
+ cros_typec_remove_partner (typec , port_num );
343
+ }
344
+ }
345
+
346
+ static int cros_typec_get_mux_info (struct cros_typec_data * typec , int port_num ,
347
+ struct ec_response_usb_pd_mux_info * resp )
348
+ {
349
+ struct ec_params_usb_pd_mux_info req = {
350
+ .port = port_num ,
351
+ };
352
+
353
+ return cros_typec_ec_command (typec , 0 , EC_CMD_USB_PD_MUX_INFO , & req ,
354
+ sizeof (req ), resp , sizeof (* resp ));
355
+ }
356
+
357
+ static int cros_typec_usb_safe_state (struct cros_typec_port * port )
358
+ {
359
+ port -> state .mode = TYPEC_STATE_SAFE ;
360
+
361
+ return typec_mux_set (port -> mux , & port -> state );
362
+ }
320
363
321
- typec_unregister_partner (typec -> ports [port_num ]-> partner );
322
- typec -> ports [port_num ]-> partner = NULL ;
364
+ int cros_typec_configure_mux (struct cros_typec_data * typec , int port_num ,
365
+ uint8_t mux_flags )
366
+ {
367
+ struct cros_typec_port * port = typec -> ports [port_num ];
368
+ enum typec_orientation orientation ;
369
+ int ret ;
370
+
371
+ if (!port -> partner )
372
+ return 0 ;
373
+
374
+ if (mux_flags & USB_PD_MUX_POLARITY_INVERTED )
375
+ orientation = TYPEC_ORIENTATION_REVERSE ;
376
+ else
377
+ orientation = TYPEC_ORIENTATION_NORMAL ;
378
+
379
+ ret = typec_switch_set (port -> ori_sw , orientation );
380
+ if (ret )
381
+ return ret ;
382
+
383
+ port -> state .alt = NULL ;
384
+ port -> state .mode = TYPEC_STATE_USB ;
385
+
386
+ if (mux_flags & USB_PD_MUX_SAFE_MODE )
387
+ ret = cros_typec_usb_safe_state (port );
388
+ else if (mux_flags & USB_PD_MUX_USB_ENABLED )
389
+ ret = typec_mux_set (port -> mux , & port -> state );
390
+ else {
391
+ dev_info (typec -> dev ,
392
+ "Unsupported mode requested, mux flags: %x\n" ,
393
+ mux_flags );
394
+ ret = - ENOTSUPP ;
323
395
}
396
+
397
+ return ret ;
324
398
}
325
399
326
400
static int cros_typec_port_update (struct cros_typec_data * typec , int port_num )
327
401
{
328
402
struct ec_params_usb_pd_control req ;
329
403
struct ec_response_usb_pd_control_v1 resp ;
404
+ struct ec_response_usb_pd_mux_info mux_resp ;
330
405
int ret ;
331
406
332
407
if (port_num < 0 || port_num >= typec -> num_ports ) {
@@ -357,7 +432,26 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
357
432
cros_typec_set_port_params_v0 (typec , port_num ,
358
433
(struct ec_response_usb_pd_control * ) & resp );
359
434
360
- return 0 ;
435
+ /* Update the switches if they exist, according to requested state */
436
+ ret = cros_typec_get_mux_info (typec , port_num , & mux_resp );
437
+ if (ret < 0 ) {
438
+ dev_warn (typec -> dev ,
439
+ "Failed to get mux info for port: %d, err = %d\n" ,
440
+ port_num , ret );
441
+ return 0 ;
442
+ }
443
+
444
+ /* No change needs to be made, let's exit early. */
445
+ if (typec -> ports [port_num ]-> mux_flags == mux_resp .flags )
446
+ return 0 ;
447
+
448
+ typec -> ports [port_num ]-> mux_flags = mux_resp .flags ;
449
+ ret = cros_typec_configure_mux (typec , port_num , mux_resp .flags );
450
+ if (ret )
451
+ dev_warn (typec -> dev , "Configure muxes failed, err = %d\n" , ret );
452
+
453
+ return usb_role_switch_set_role (typec -> ports [port_num ]-> role_sw ,
454
+ !!(resp .role & PD_CTRL_RESP_ROLE_DATA ));
361
455
}
362
456
363
457
static int cros_typec_get_cmd_version (struct cros_typec_data * typec )
0 commit comments