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

Configure Feed

Select the types of activity you want to include in your feed.

extcon: usbc-tusb320: add usb_role_switch support

The connector child node of the TUSB320 device might be linked with a
dual-role capable USB controller. Add driver support for detecting a
usb_role_switch and setting its state in the typec interrupt handler.
This follows similar practice in other drivers in the typec subsystem,
which this extcon driver can opt-in to.

Signed-off-by: Alvin Šipraga <alsi@bang-olufsen.dk>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>

authored by

Alvin Šipraga and committed by
Chanwoo Choi
df101446 18eb81d8

+21
+21
drivers/extcon/extcon-usbc-tusb320.c
··· 16 16 #include <linux/regmap.h> 17 17 #include <linux/usb/typec.h> 18 18 #include <linux/usb/typec_altmode.h> 19 + #include <linux/usb/role.h> 19 20 20 21 #define TUSB320_REG8 0x8 21 22 #define TUSB320_REG8_CURRENT_MODE_ADVERTISE GENMASK(7, 6) ··· 81 80 enum typec_port_type port_type; 82 81 enum typec_pwr_opmode pwr_opmode; 83 82 struct fwnode_handle *connector_fwnode; 83 + struct usb_role_switch *role_sw; 84 84 }; 85 85 86 86 static const char * const tusb_attached_states[] = { ··· 280 278 struct typec_port *port = priv->port; 281 279 struct device *dev = priv->dev; 282 280 int typec_mode; 281 + enum usb_role usb_role; 283 282 enum typec_role pwr_role; 284 283 enum typec_data_role data_role; 285 284 u8 state, mode, accessory; ··· 303 300 switch (state) { 304 301 case TUSB320_ATTACHED_STATE_DFP: 305 302 typec_mode = TYPEC_MODE_USB2; 303 + usb_role = USB_ROLE_HOST; 306 304 pwr_role = TYPEC_SOURCE; 307 305 data_role = TYPEC_HOST; 308 306 break; 309 307 case TUSB320_ATTACHED_STATE_UFP: 310 308 typec_mode = TYPEC_MODE_USB2; 309 + usb_role = USB_ROLE_DEVICE; 311 310 pwr_role = TYPEC_SINK; 312 311 data_role = TYPEC_DEVICE; 313 312 break; ··· 321 316 if (accessory == TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO || 322 317 accessory == TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG) { 323 318 typec_mode = TYPEC_MODE_AUDIO; 319 + usb_role = USB_ROLE_NONE; 324 320 pwr_role = TYPEC_SINK; 325 321 data_role = TYPEC_DEVICE; 326 322 break; ··· 329 323 TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP) { 330 324 typec_mode = TYPEC_MODE_DEBUG; 331 325 pwr_role = TYPEC_SOURCE; 326 + usb_role = USB_ROLE_HOST; 332 327 data_role = TYPEC_HOST; 333 328 break; 334 329 } else if (accessory == 335 330 TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP) { 336 331 typec_mode = TYPEC_MODE_DEBUG; 337 332 pwr_role = TYPEC_SINK; 333 + usb_role = USB_ROLE_DEVICE; 338 334 data_role = TYPEC_DEVICE; 339 335 break; 340 336 } ··· 347 339 fallthrough; 348 340 default: 349 341 typec_mode = TYPEC_MODE_USB2; 342 + usb_role = USB_ROLE_NONE; 350 343 pwr_role = TYPEC_SINK; 351 344 data_role = TYPEC_DEVICE; 352 345 break; ··· 357 348 typec_set_pwr_role(port, pwr_role); 358 349 typec_set_data_role(port, data_role); 359 350 typec_set_mode(port, typec_mode); 351 + usb_role_switch_set_role(priv->role_sw, usb_role); 360 352 361 353 mode = FIELD_GET(TUSB320_REG8_CURRENT_MODE_DETECT, reg8); 362 354 if (mode == TUSB320_REG8_CURRENT_MODE_DETECT_DEF) ··· 482 472 goto err_put; 483 473 } 484 474 475 + /* Find any optional USB role switch that needs reporting to */ 476 + priv->role_sw = fwnode_usb_role_switch_get(connector); 477 + if (IS_ERR(priv->role_sw)) { 478 + ret = PTR_ERR(priv->role_sw); 479 + goto err_unreg; 480 + } 481 + 485 482 priv->connector_fwnode = connector; 486 483 487 484 return 0; 485 + 486 + err_unreg: 487 + typec_unregister_port(priv->port); 488 488 489 489 err_put: 490 490 fwnode_handle_put(connector); ··· 504 484 505 485 static void tusb320_typec_remove(struct tusb320_priv *priv) 506 486 { 487 + usb_role_switch_put(priv->role_sw); 507 488 typec_unregister_port(priv->port); 508 489 fwnode_handle_put(priv->connector_fwnode); 509 490 }