diff options
| -rw-r--r-- | drivers/extcon/extcon-sm5502.c | 78 | ||||
| -rw-r--r-- | include/linux/extcon/sm5502.h | 23 |
2 files changed, 96 insertions, 5 deletions
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index a32d40f97ff0..560d7dccec7b 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c | |||
| @@ -228,6 +228,61 @@ static const struct regmap_config sm5502_muic_regmap_config = { | |||
| 228 | .max_register = SM5502_REG_END, | 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 | /* Return cable type of attached or detached accessories */ | 286 | /* Return cable type of attached or detached accessories */ |
| 232 | static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) | 287 | static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) |
| 233 | { | 288 | { |
| @@ -329,7 +384,10 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, | |||
| 329 | static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND; | 384 | static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND; |
| 330 | const char **cable_names = info->edev->supported_cable; | 385 | const char **cable_names = info->edev->supported_cable; |
| 331 | unsigned int cable_type = SM5502_MUIC_ADC_GROUND; | 386 | unsigned int cable_type = SM5502_MUIC_ADC_GROUND; |
| 387 | unsigned int con_sw = DM_DP_SWITCH_OPEN; | ||
| 388 | unsigned int vbus_sw = VBUSIN_SWITCH_OPEN; | ||
| 332 | unsigned int idx = 0; | 389 | unsigned int idx = 0; |
| 390 | int ret; | ||
| 333 | 391 | ||
| 334 | if (!cable_names) | 392 | if (!cable_names) |
| 335 | return 0; | 393 | return 0; |
| @@ -343,15 +401,19 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, | |||
| 343 | 401 | ||
| 344 | switch (cable_type) { | 402 | switch (cable_type) { |
| 345 | case SM5502_MUIC_ADC_OPEN_USB: | 403 | case SM5502_MUIC_ADC_OPEN_USB: |
| 346 | idx = EXTCON_CABLE_USB; | 404 | idx = EXTCON_CABLE_USB; |
| 405 | con_sw = DM_DP_SWITCH_USB; | ||
| 406 | vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB; | ||
| 347 | break; | 407 | break; |
| 348 | case SM5502_MUIC_ADC_OPEN_TA: | 408 | case SM5502_MUIC_ADC_OPEN_TA: |
| 349 | idx = EXTCON_CABLE_TA; | 409 | idx = EXTCON_CABLE_TA; |
| 410 | con_sw = DM_DP_SWITCH_OPEN; | ||
| 411 | vbus_sw = VBUSIN_SWITCH_VBUSOUT; | ||
| 350 | break; | 412 | break; |
| 351 | case SM5502_MUIC_ADC_OPEN_USB_OTG: | 413 | case SM5502_MUIC_ADC_OPEN_USB_OTG: |
| 352 | idx = EXTCON_CABLE_USB_HOST; | 414 | idx = EXTCON_CABLE_USB_HOST; |
| 353 | break; | 415 | con_sw = DM_DP_SWITCH_USB; |
| 354 | case SM5502_MUIC_ADC_GROUND: | 416 | vbus_sw = VBUSIN_SWITCH_OPEN; |
| 355 | break; | 417 | break; |
| 356 | default: | 418 | default: |
| 357 | dev_dbg(info->dev, | 419 | dev_dbg(info->dev, |
| @@ -359,6 +421,12 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, | |||
| 359 | return 0; | 421 | return 0; |
| 360 | }; | 422 | }; |
| 361 | 423 | ||
| 424 | /* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */ | ||
| 425 | ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached); | ||
| 426 | if (ret < 0) | ||
| 427 | return ret; | ||
| 428 | |||
| 429 | /* Change the state of external accessory */ | ||
| 362 | extcon_set_cable_state(info->edev, cable_names[idx], attached); | 430 | extcon_set_cable_state(info->edev, cable_names[idx], attached); |
| 363 | 431 | ||
| 364 | return 0; | 432 | return 0; |
diff --git a/include/linux/extcon/sm5502.h b/include/linux/extcon/sm5502.h index 17bd6550c485..030526bf8d79 100644 --- a/include/linux/extcon/sm5502.h +++ b/include/linux/extcon/sm5502.h | |||
| @@ -223,6 +223,29 @@ enum sm5502_reg { | |||
| 223 | #define SM5502_REG_DEV_TYPE2_TTY_MASK (0x1 << SM5502_REG_DEV_TYPE2_TTY_SHIFT) | 223 | #define SM5502_REG_DEV_TYPE2_TTY_MASK (0x1 << SM5502_REG_DEV_TYPE2_TTY_SHIFT) |
| 224 | #define SM5502_REG_DEV_TYPE2_AV_CABLE_MASK (0x1 << SM5502_REG_DEV_TYPE2_AV_CABLE_SHIFT) | 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 | /* SM5502 Interrupts */ | 249 | /* SM5502 Interrupts */ |
| 227 | enum sm5502_irq { | 250 | enum sm5502_irq { |
| 228 | /* INT1 */ | 251 | /* INT1 */ |
