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

extcon: sm5502: Change internal hardware switch according to cable type

This patch changes internal hardware DP_CON/DM_CON switch according to
cable type. The SM5502 MUIC device can set hardware switch as following:
- OPEN (not connected state) / USB / UART / AUDIO
Also, this patch set VBUSIN switch according to cable type.

Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>

+96 -5
+73 -5
drivers/extcon/extcon-sm5502.c
··· 228 228 .max_register = SM5502_REG_END, 229 229 }; 230 230 231 + /* Change DM_CON/DP_CON/VBUSIN switch according to cable type */ 232 + static int sm5502_muic_set_path(struct sm5502_muic_info *info, 233 + unsigned int con_sw, unsigned int vbus_sw, 234 + bool attached) 235 + { 236 + int ret; 237 + 238 + if (!attached) { 239 + con_sw = DM_DP_SWITCH_OPEN; 240 + vbus_sw = VBUSIN_SWITCH_OPEN; 241 + } 242 + 243 + switch (con_sw) { 244 + case DM_DP_SWITCH_OPEN: 245 + case DM_DP_SWITCH_USB: 246 + case DM_DP_SWITCH_AUDIO: 247 + case DM_DP_SWITCH_UART: 248 + ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1, 249 + SM5502_REG_MANUAL_SW1_DP_MASK | 250 + SM5502_REG_MANUAL_SW1_DM_MASK, 251 + con_sw); 252 + if (ret < 0) { 253 + dev_err(info->dev, 254 + "cannot update DM_CON/DP_CON switch\n"); 255 + return ret; 256 + } 257 + break; 258 + default: 259 + dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n", 260 + con_sw); 261 + return -EINVAL; 262 + }; 263 + 264 + switch (vbus_sw) { 265 + case VBUSIN_SWITCH_OPEN: 266 + case VBUSIN_SWITCH_VBUSOUT: 267 + case VBUSIN_SWITCH_MIC: 268 + case VBUSIN_SWITCH_VBUSOUT_WITH_USB: 269 + ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1, 270 + SM5502_REG_MANUAL_SW1_VBUSIN_MASK, 271 + vbus_sw); 272 + if (ret < 0) { 273 + dev_err(info->dev, 274 + "cannot update VBUSIN switch\n"); 275 + return ret; 276 + } 277 + break; 278 + default: 279 + dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw); 280 + return -EINVAL; 281 + }; 282 + 283 + return 0; 284 + } 285 + 231 286 /* Return cable type of attached or detached accessories */ 232 287 static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) 233 288 { ··· 384 329 static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND; 385 330 const char **cable_names = info->edev->supported_cable; 386 331 unsigned int cable_type = SM5502_MUIC_ADC_GROUND; 332 + unsigned int con_sw = DM_DP_SWITCH_OPEN; 333 + unsigned int vbus_sw = VBUSIN_SWITCH_OPEN; 387 334 unsigned int idx = 0; 335 + int ret; 388 336 389 337 if (!cable_names) 390 338 return 0; ··· 401 343 402 344 switch (cable_type) { 403 345 case SM5502_MUIC_ADC_OPEN_USB: 404 - idx = EXTCON_CABLE_USB; 346 + idx = EXTCON_CABLE_USB; 347 + con_sw = DM_DP_SWITCH_USB; 348 + vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB; 405 349 break; 406 350 case SM5502_MUIC_ADC_OPEN_TA: 407 - idx = EXTCON_CABLE_TA; 351 + idx = EXTCON_CABLE_TA; 352 + con_sw = DM_DP_SWITCH_OPEN; 353 + vbus_sw = VBUSIN_SWITCH_VBUSOUT; 408 354 break; 409 355 case SM5502_MUIC_ADC_OPEN_USB_OTG: 410 - idx = EXTCON_CABLE_USB_HOST; 411 - break; 412 - case SM5502_MUIC_ADC_GROUND: 356 + idx = EXTCON_CABLE_USB_HOST; 357 + con_sw = DM_DP_SWITCH_USB; 358 + vbus_sw = VBUSIN_SWITCH_OPEN; 413 359 break; 414 360 default: 415 361 dev_dbg(info->dev, ··· 421 359 return 0; 422 360 }; 423 361 362 + /* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */ 363 + ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached); 364 + if (ret < 0) 365 + return ret; 366 + 367 + /* Change the state of external accessory */ 424 368 extcon_set_cable_state(info->edev, cable_names[idx], attached); 425 369 426 370 return 0;
+23
include/linux/extcon/sm5502.h
··· 223 223 #define SM5502_REG_DEV_TYPE2_TTY_MASK (0x1 << SM5502_REG_DEV_TYPE2_TTY_SHIFT) 224 224 #define SM5502_REG_DEV_TYPE2_AV_CABLE_MASK (0x1 << SM5502_REG_DEV_TYPE2_AV_CABLE_SHIFT) 225 225 226 + #define SM5502_REG_MANUAL_SW1_VBUSIN_SHIFT 0 227 + #define SM5502_REG_MANUAL_SW1_DP_SHIFT 2 228 + #define SM5502_REG_MANUAL_SW1_DM_SHIFT 5 229 + #define SM5502_REG_MANUAL_SW1_VBUSIN_MASK (0x3 << SM5502_REG_MANUAL_SW1_VBUSIN_SHIFT) 230 + #define SM5502_REG_MANUAL_SW1_DP_MASK (0x7 << SM5502_REG_MANUAL_SW1_DP_SHIFT) 231 + #define SM5502_REG_MANUAL_SW1_DM_MASK (0x7 << SM5502_REG_MANUAL_SW1_DM_SHIFT) 232 + #define VBUSIN_SWITCH_OPEN 0x0 233 + #define VBUSIN_SWITCH_VBUSOUT 0x1 234 + #define VBUSIN_SWITCH_MIC 0x2 235 + #define VBUSIN_SWITCH_VBUSOUT_WITH_USB 0x3 236 + #define DM_DP_CON_SWITCH_OPEN 0x0 237 + #define DM_DP_CON_SWITCH_USB 0x1 238 + #define DM_DP_CON_SWITCH_AUDIO 0x2 239 + #define DM_DP_CON_SWITCH_UART 0x3 240 + #define DM_DP_SWITCH_OPEN ((DM_DP_CON_SWITCH_OPEN <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \ 241 + | (DM_DP_CON_SWITCH_OPEN <<SM5502_REG_MANUAL_SW1_DM_SHIFT)) 242 + #define DM_DP_SWITCH_USB ((DM_DP_CON_SWITCH_USB <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \ 243 + | (DM_DP_CON_SWITCH_USB <<SM5502_REG_MANUAL_SW1_DM_SHIFT)) 244 + #define DM_DP_SWITCH_AUDIO ((DM_DP_CON_SWITCH_AUDIO <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \ 245 + | (DM_DP_CON_SWITCH_AUDIO <<SM5502_REG_MANUAL_SW1_DM_SHIFT)) 246 + #define DM_DP_SWITCH_UART ((DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \ 247 + | (DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DM_SHIFT)) 248 + 226 249 /* SM5502 Interrupts */ 227 250 enum sm5502_irq { 228 251 /* INT1 */