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);
}

浙公网安备 33010602011771号