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 accessory detection support

The TUSB320 can detect the following types of accessory:

- Audio Accessory
- Audio Accessory with charge-thru
- Debug Accessory (DFP)
- Debug Accessory (UFP)

Moreover, the typec subsystem can be informed of this through the
typec_set_mode() function. The information will be propagated to any
linked typec muxes. Add the necessary support to the driver.

Note that for the Debug Accessory modes, an educated guess was made that
for the USB data role, DFP implies HOST and UFP implies DEVICE. But this
might want to be made configurable at a later date.

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
18eb81d8 04151575

+70 -24
+70 -24
drivers/extcon/extcon-usbc-tusb320.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/regmap.h> 17 17 #include <linux/usb/typec.h> 18 + #include <linux/usb/typec_altmode.h> 18 19 19 20 #define TUSB320_REG8 0x8 20 21 #define TUSB320_REG8_CURRENT_MODE_ADVERTISE GENMASK(7, 6) ··· 27 26 #define TUSB320_REG8_CURRENT_MODE_DETECT_MED 0x1 28 27 #define TUSB320_REG8_CURRENT_MODE_DETECT_ACC 0x2 29 28 #define TUSB320_REG8_CURRENT_MODE_DETECT_HI 0x3 30 - #define TUSB320_REG8_ACCESSORY_CONNECTED GENMASK(3, 2) 29 + #define TUSB320_REG8_ACCESSORY_CONNECTED GENMASK(3, 1) 31 30 #define TUSB320_REG8_ACCESSORY_CONNECTED_NONE 0x0 32 31 #define TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO 0x4 33 - #define TUSB320_REG8_ACCESSORY_CONNECTED_ACC 0x5 34 - #define TUSB320_REG8_ACCESSORY_CONNECTED_DEBUG 0x6 32 + #define TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG 0x5 33 + #define TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP 0x6 34 + #define TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP 0x7 35 35 #define TUSB320_REG8_ACTIVE_CABLE_DETECTION BIT(0) 36 36 37 37 #define TUSB320_REG9 0x9 38 - #define TUSB320_REG9_ATTACHED_STATE_SHIFT 6 39 - #define TUSB320_REG9_ATTACHED_STATE_MASK 0x3 38 + #define TUSB320_REG9_ATTACHED_STATE GENMASK(7, 6) 40 39 #define TUSB320_REG9_CABLE_DIRECTION BIT(5) 41 40 #define TUSB320_REG9_INTERRUPT_STATUS BIT(4) 42 41 ··· 251 250 { 252 251 int state, polarity; 253 252 254 - state = (reg >> TUSB320_REG9_ATTACHED_STATE_SHIFT) & 255 - TUSB320_REG9_ATTACHED_STATE_MASK; 253 + state = FIELD_GET(TUSB320_REG9_ATTACHED_STATE, reg); 256 254 polarity = !!(reg & TUSB320_REG9_CABLE_DIRECTION); 257 255 258 256 dev_dbg(priv->dev, "attached state: %s, polarity: %d\n", ··· 277 277 { 278 278 struct typec_port *port = priv->port; 279 279 struct device *dev = priv->dev; 280 - u8 mode, role, state; 280 + int typec_mode; 281 + enum typec_role pwr_role; 282 + enum typec_data_role data_role; 283 + u8 state, mode, accessory; 281 284 int ret, reg8; 282 285 bool ori; 283 - 284 - ori = reg9 & TUSB320_REG9_CABLE_DIRECTION; 285 - typec_set_orientation(port, ori ? TYPEC_ORIENTATION_REVERSE : 286 - TYPEC_ORIENTATION_NORMAL); 287 - 288 - state = (reg9 >> TUSB320_REG9_ATTACHED_STATE_SHIFT) & 289 - TUSB320_REG9_ATTACHED_STATE_MASK; 290 - if (state == TUSB320_ATTACHED_STATE_DFP) 291 - role = TYPEC_SOURCE; 292 - else 293 - role = TYPEC_SINK; 294 - 295 - typec_set_vconn_role(port, role); 296 - typec_set_pwr_role(port, role); 297 - typec_set_data_role(port, role == TYPEC_SOURCE ? 298 - TYPEC_HOST : TYPEC_DEVICE); 299 286 300 287 ret = regmap_read(priv->regmap, TUSB320_REG8, &reg8); 301 288 if (ret) { 302 289 dev_err(dev, "error during reg8 i2c read, ret=%d!\n", ret); 303 290 return; 304 291 } 292 + 293 + ori = reg9 & TUSB320_REG9_CABLE_DIRECTION; 294 + typec_set_orientation(port, ori ? TYPEC_ORIENTATION_REVERSE : 295 + TYPEC_ORIENTATION_NORMAL); 296 + 297 + state = FIELD_GET(TUSB320_REG9_ATTACHED_STATE, reg9); 298 + accessory = FIELD_GET(TUSB320_REG8_ACCESSORY_CONNECTED, reg8); 299 + 300 + switch (state) { 301 + case TUSB320_ATTACHED_STATE_DFP: 302 + typec_mode = TYPEC_MODE_USB2; 303 + pwr_role = TYPEC_SOURCE; 304 + data_role = TYPEC_HOST; 305 + break; 306 + case TUSB320_ATTACHED_STATE_UFP: 307 + typec_mode = TYPEC_MODE_USB2; 308 + pwr_role = TYPEC_SINK; 309 + data_role = TYPEC_DEVICE; 310 + break; 311 + case TUSB320_ATTACHED_STATE_ACC: 312 + /* 313 + * Accessory detected. For debug accessories, just make some 314 + * qualified guesses as to the role for lack of a better option. 315 + */ 316 + if (accessory == TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO || 317 + accessory == TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG) { 318 + typec_mode = TYPEC_MODE_AUDIO; 319 + pwr_role = TYPEC_SINK; 320 + data_role = TYPEC_DEVICE; 321 + break; 322 + } else if (accessory == 323 + TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP) { 324 + typec_mode = TYPEC_MODE_DEBUG; 325 + pwr_role = TYPEC_SOURCE; 326 + data_role = TYPEC_HOST; 327 + break; 328 + } else if (accessory == 329 + TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP) { 330 + typec_mode = TYPEC_MODE_DEBUG; 331 + pwr_role = TYPEC_SINK; 332 + data_role = TYPEC_DEVICE; 333 + break; 334 + } 335 + 336 + dev_warn(priv->dev, "unexpected ACCESSORY_CONNECTED state %d\n", 337 + accessory); 338 + 339 + fallthrough; 340 + default: 341 + typec_mode = TYPEC_MODE_USB2; 342 + pwr_role = TYPEC_SINK; 343 + data_role = TYPEC_DEVICE; 344 + break; 345 + } 346 + 347 + typec_set_vconn_role(port, pwr_role); 348 + typec_set_pwr_role(port, pwr_role); 349 + typec_set_data_role(port, data_role); 350 + typec_set_mode(port, typec_mode); 305 351 306 352 mode = FIELD_GET(TUSB320_REG8_CURRENT_MODE_DETECT, reg8); 307 353 if (mode == TUSB320_REG8_CURRENT_MODE_DETECT_DEF)