typec CC脚检测中断
[TYPEC_ATTACH_DETACH_IRQ] = { .name = "typec-attach-detach", .handler = smblite_typec_attach_detach_irq_handler, .wake = true, },
irqreturn_t smblite_typec_attach_detach_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; u8 stat; bool attached = false; int rc; /* IRQ not expected to be executed for uUSB, return */ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) return IRQ_HANDLED; smblite_lib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); rc = smblite_lib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat); if (rc < 0) { smblite_lib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n", rc); return IRQ_HANDLED; } attached = !!(stat & TYPEC_ATTACH_DETACH_STATE_BIT); if (attached) { rc = smblite_lib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblite_lib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n", rc); return IRQ_HANDLED; } if (smblite_lib_get_prop_dfp_mode(chg) == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { chg->sink_src_mode = AUDIO_ACCESS_MODE; typec_ra_ra_insertion(chg); } else if (stat & SNK_SRC_MODE_BIT) { chg->sink_src_mode = SRC_MODE; typec_sink_insertion(chg); //mode的切换 } else { chg->sink_src_mode = SINK_MODE; typec_src_insertion(chg);//mode的切换 } rc = typec_partner_register(chg); if (rc < 0) smblite_lib_err(chg, "Couldn't to register partner rc =%d\n", rc); } else { switch (chg->sink_src_mode) { case SRC_MODE: typec_sink_removal(chg); break; case SINK_MODE: case AUDIO_ACCESS_MODE: typec_src_removal(chg); break; case UNATTACHED_MODE: default: typec_mode_unattached(chg); break; } if (!chg->pr_swap_in_progress) chg->sink_src_mode = UNATTACHED_MODE; /* * Restore DRP mode on type-C cable disconnect if role * swap is not in progress, to ensure forced sink or src * mode configuration is reset properly. */ if (chg->typec_port && !chg->pr_swap_in_progress) { /* * Schedule the work to differentiate actual removal * of cable and detach interrupt during role swap, * unregister the partner only during actual cable * removal. */ cancel_delayed_work(&chg->pr_swap_detach_work); vote(chg->awake_votable, DETACH_DETECT_VOTER, true, 0); schedule_delayed_work(&chg->pr_swap_detach_work, msecs_to_jiffies(TYPEC_DETACH_DETECT_DELAY_MS)); smblite_lib_force_dr_mode(chg, TYPEC_PORT_DRP); /* * To handle cable removal during role * swap failure. */ chg->typec_role_swap_failed = false; } } rc = smblite_lib_masked_write(chg, USB_CMD_PULLDOWN_REG, EN_PULLDOWN_USB_IN_BIT, attached ? 0 : EN_PULLDOWN_USB_IN_BIT); if (rc < 0) smblite_lib_err(chg, "Couldn't configure pulldown on USB_IN rc=%d\n", rc); power_supply_changed(chg->usb_psy); return IRQ_HANDLED; }
- typec的otg功能,是当otg线插上时CC pin会被到下拉GND,触发typec-attach-detach然后就会切换成host mode,识别设备:
static void smblite_lib_notify_usb_host(struct smb_charger *chg, bool enable) { int rc = 0; /* LDO mode doesn't support OTG */ if (chg->ldo_mode) return; if (enable) { smblite_lib_dbg(chg, PR_OTG, "enabling VBUS in OTG mode\n"); rc = smblite_lib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT, OTG_EN_BIT); //typec打开otg功能,给设备供电 if (rc < 0) { smblite_lib_err(chg, "Couldn't enable VBUS in OTG mode rc=%d\n", rc); return; } rc = smblite_lib_masked_write(chg, DCDC_BST_VREG_SEL, VBOOST_MASK, VBOOST_5P00V); if (rc < 0) { smblite_lib_err(chg, "Couldn't write BST_VREG_SEL rc=%d\n", rc); return; } smblite_lib_notify_extcon_props(chg, EXTCON_USB_HOST); } else { smblite_lib_dbg(chg, PR_OTG, "disabling VBUS in OTG mode\n"); rc = smblite_lib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT, 0); if (rc < 0) { smblite_lib_err(chg, "Couldn't disable VBUS in OTG mode rc=%d\n", rc); return; } } extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);//切换host模式 chg->otg_present = enable; }
当插入typec线CCpin会被上拉到vbus时,切换成device模式:
static void smblite_lib_notify_device_mode(struct smb_charger *chg, bool enable) { if (enable) smblite_lib_notify_extcon_props(chg, EXTCON_USB); extcon_set_state_sync(chg->extcon, EXTCON_USB, enable); }