Loading drivers/power/supply/qcom/smb5-lib.c +98 −2 Original line number Diff line number Diff line Loading @@ -3551,6 +3551,7 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, return -EINVAL; } chg->power_role = val->intval; return rc; } Loading Loading @@ -4104,15 +4105,86 @@ int smblib_set_prop_usb_voltage_max_limit(struct smb_charger *chg, return 0; } static void smblib_typec_irq_config(struct smb_charger *chg, bool en) { if (en == chg->typec_irq_en) return; if (en) { enable_irq( chg->irq_info[TYPEC_ATTACH_DETACH_IRQ].irq); enable_irq( chg->irq_info[TYPEC_CC_STATE_CHANGE_IRQ].irq); enable_irq( chg->irq_info[TYPEC_OR_RID_DETECTION_CHANGE_IRQ].irq); } else { disable_irq_nosync( chg->irq_info[TYPEC_ATTACH_DETACH_IRQ].irq); disable_irq_nosync( chg->irq_info[TYPEC_CC_STATE_CHANGE_IRQ].irq); disable_irq_nosync( chg->irq_info[TYPEC_OR_RID_DETECTION_CHANGE_IRQ].irq); } chg->typec_irq_en = en; } #define PR_LOCK_TIMEOUT_MS 1000 int smblib_set_prop_typec_power_role(struct smb_charger *chg, const union power_supply_propval *val) { int rc = 0; u8 power_role; enum power_supply_typec_mode typec_mode; bool snk_attached = false, src_attached = false, is_pr_lock = false; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) return 0; smblib_dbg(chg, PR_MISC, "power role change: %d --> %d!", chg->power_role, val->intval); if (chg->power_role == val->intval) { smblib_dbg(chg, PR_MISC, "power role already in %d, ignore!", chg->power_role); return 0; } typec_mode = smblib_get_prop_typec_mode(chg); if (typec_mode >= POWER_SUPPLY_TYPEC_SINK && typec_mode <= POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) snk_attached = true; else if (typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEFAULT && typec_mode <= POWER_SUPPLY_TYPEC_SOURCE_HIGH) src_attached = true; /* * If current power role is in DRP, and type-c is already in the * mode (source or sink) that's being requested, it means this is * a power role locking request from USBPD driver. Disable type-c * related interrupts for locking power role to avoid the redundant * notifications. */ if ((chg->power_role == POWER_SUPPLY_TYPEC_PR_DUAL) && ((src_attached && val->intval == POWER_SUPPLY_TYPEC_PR_SINK) || (snk_attached && val->intval == POWER_SUPPLY_TYPEC_PR_SOURCE))) is_pr_lock = true; smblib_dbg(chg, PR_MISC, "snk_attached = %d, src_attached = %d, is_pr_lock = %d\n", snk_attached, src_attached, is_pr_lock); cancel_delayed_work_sync(&chg->pr_lock_clear_work); if (!chg->pr_lock_in_progress && is_pr_lock) { smblib_dbg(chg, PR_MISC, "disable type-c interrupts for power role locking\n"); smblib_typec_irq_config(chg, false); schedule_delayed_work(&chg->pr_lock_clear_work, msecs_to_jiffies(PR_LOCK_TIMEOUT_MS)); } else if (chg->pr_lock_in_progress && !is_pr_lock) { smblib_dbg(chg, PR_MISC, "restore type-c interrupts after exit power role locking\n"); smblib_typec_irq_config(chg, true); } chg->pr_lock_in_progress = is_pr_lock; switch (val->intval) { case POWER_SUPPLY_TYPEC_PR_NONE: power_role = TYPEC_DISABLE_CMD_BIT; Loading Loading @@ -4140,6 +4212,7 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, return rc; } chg->power_role = val->intval; return rc; } Loading Loading @@ -5459,8 +5532,10 @@ static void typec_src_insertion(struct smb_charger *chg) int rc = 0; u8 stat; if (chg->pr_swap_in_progress) if (chg->pr_swap_in_progress) { vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); return; } rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat); if (rc < 0) { Loading Loading @@ -6185,13 +6260,19 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", rc); return rc; } /* enable DRP */ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, TYPEC_POWER_ROLE_CMD_MASK, 0); if (rc < 0) if (rc < 0) { smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); return rc; } chg->power_role = POWER_SUPPLY_TYPEC_PR_DUAL; smblib_dbg(chg, PR_MISC, "restore power role: %d\n", chg->power_role); } return 0; Loading @@ -6200,6 +6281,18 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, /*************** * Work Queues * ***************/ static void smblib_pr_lock_clear_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, pr_lock_clear_work.work); if (chg->pr_lock_in_progress) { smblib_dbg(chg, PR_MISC, "restore type-c interrupts\n"); smblib_typec_irq_config(chg, true); chg->pr_lock_in_progress = false; } } static void smblib_pr_swap_detach_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, Loading Loading @@ -7094,6 +7187,8 @@ int smblib_init(struct smb_charger *chg) smblib_dual_role_check_work); INIT_DELAYED_WORK(&chg->pr_swap_detach_work, smblib_pr_swap_detach_work); INIT_DELAYED_WORK(&chg->pr_lock_clear_work, smblib_pr_lock_clear_work); if (chg->wa_flags & CHG_TERMINATION_WA) { INIT_WORK(&chg->chg_termination_work, Loading Loading @@ -7130,6 +7225,7 @@ int smblib_init(struct smb_charger *chg) chg->cp_reason = POWER_SUPPLY_CP_NONE; chg->thermal_status = TEMP_BELOW_RANGE; chg->dr_mode = DUAL_ROLE_PROP_MODE_NONE; chg->typec_irq_en = true; switch (chg->mode) { case PARALLEL_MASTER: Loading drivers/power/supply/qcom/smb5-lib.h +4 −0 Original line number Diff line number Diff line Loading @@ -457,6 +457,7 @@ struct smb_charger { struct delayed_work usbov_dbc_work; struct delayed_work role_reversal_check; struct delayed_work pr_swap_detach_work; struct delayed_work pr_lock_clear_work; struct alarm lpd_recheck_timer; struct alarm moisture_protection_alarm; Loading @@ -473,10 +474,12 @@ struct smb_charger { int voltage_max_uv; int pd_active; bool pd_hard_reset; bool pr_lock_in_progress; bool pr_swap_in_progress; bool early_usb_attach; bool ok_to_pd; bool typec_legacy; bool typec_irq_en; /* cached status */ bool system_suspend_supported; Loading Loading @@ -511,6 +514,7 @@ struct smb_charger { int hw_max_icl_ua; int auto_recharge_soc; enum sink_src_mode sink_src_mode; enum power_supply_typec_power_role power_role; enum jeita_cfg_stat jeita_configured; int charger_temp_max; int smb_temp_max; Loading Loading
drivers/power/supply/qcom/smb5-lib.c +98 −2 Original line number Diff line number Diff line Loading @@ -3551,6 +3551,7 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, return -EINVAL; } chg->power_role = val->intval; return rc; } Loading Loading @@ -4104,15 +4105,86 @@ int smblib_set_prop_usb_voltage_max_limit(struct smb_charger *chg, return 0; } static void smblib_typec_irq_config(struct smb_charger *chg, bool en) { if (en == chg->typec_irq_en) return; if (en) { enable_irq( chg->irq_info[TYPEC_ATTACH_DETACH_IRQ].irq); enable_irq( chg->irq_info[TYPEC_CC_STATE_CHANGE_IRQ].irq); enable_irq( chg->irq_info[TYPEC_OR_RID_DETECTION_CHANGE_IRQ].irq); } else { disable_irq_nosync( chg->irq_info[TYPEC_ATTACH_DETACH_IRQ].irq); disable_irq_nosync( chg->irq_info[TYPEC_CC_STATE_CHANGE_IRQ].irq); disable_irq_nosync( chg->irq_info[TYPEC_OR_RID_DETECTION_CHANGE_IRQ].irq); } chg->typec_irq_en = en; } #define PR_LOCK_TIMEOUT_MS 1000 int smblib_set_prop_typec_power_role(struct smb_charger *chg, const union power_supply_propval *val) { int rc = 0; u8 power_role; enum power_supply_typec_mode typec_mode; bool snk_attached = false, src_attached = false, is_pr_lock = false; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) return 0; smblib_dbg(chg, PR_MISC, "power role change: %d --> %d!", chg->power_role, val->intval); if (chg->power_role == val->intval) { smblib_dbg(chg, PR_MISC, "power role already in %d, ignore!", chg->power_role); return 0; } typec_mode = smblib_get_prop_typec_mode(chg); if (typec_mode >= POWER_SUPPLY_TYPEC_SINK && typec_mode <= POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) snk_attached = true; else if (typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEFAULT && typec_mode <= POWER_SUPPLY_TYPEC_SOURCE_HIGH) src_attached = true; /* * If current power role is in DRP, and type-c is already in the * mode (source or sink) that's being requested, it means this is * a power role locking request from USBPD driver. Disable type-c * related interrupts for locking power role to avoid the redundant * notifications. */ if ((chg->power_role == POWER_SUPPLY_TYPEC_PR_DUAL) && ((src_attached && val->intval == POWER_SUPPLY_TYPEC_PR_SINK) || (snk_attached && val->intval == POWER_SUPPLY_TYPEC_PR_SOURCE))) is_pr_lock = true; smblib_dbg(chg, PR_MISC, "snk_attached = %d, src_attached = %d, is_pr_lock = %d\n", snk_attached, src_attached, is_pr_lock); cancel_delayed_work_sync(&chg->pr_lock_clear_work); if (!chg->pr_lock_in_progress && is_pr_lock) { smblib_dbg(chg, PR_MISC, "disable type-c interrupts for power role locking\n"); smblib_typec_irq_config(chg, false); schedule_delayed_work(&chg->pr_lock_clear_work, msecs_to_jiffies(PR_LOCK_TIMEOUT_MS)); } else if (chg->pr_lock_in_progress && !is_pr_lock) { smblib_dbg(chg, PR_MISC, "restore type-c interrupts after exit power role locking\n"); smblib_typec_irq_config(chg, true); } chg->pr_lock_in_progress = is_pr_lock; switch (val->intval) { case POWER_SUPPLY_TYPEC_PR_NONE: power_role = TYPEC_DISABLE_CMD_BIT; Loading Loading @@ -4140,6 +4212,7 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, return rc; } chg->power_role = val->intval; return rc; } Loading Loading @@ -5459,8 +5532,10 @@ static void typec_src_insertion(struct smb_charger *chg) int rc = 0; u8 stat; if (chg->pr_swap_in_progress) if (chg->pr_swap_in_progress) { vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); return; } rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat); if (rc < 0) { Loading Loading @@ -6185,13 +6260,19 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", rc); return rc; } /* enable DRP */ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, TYPEC_POWER_ROLE_CMD_MASK, 0); if (rc < 0) if (rc < 0) { smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); return rc; } chg->power_role = POWER_SUPPLY_TYPEC_PR_DUAL; smblib_dbg(chg, PR_MISC, "restore power role: %d\n", chg->power_role); } return 0; Loading @@ -6200,6 +6281,18 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, /*************** * Work Queues * ***************/ static void smblib_pr_lock_clear_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, pr_lock_clear_work.work); if (chg->pr_lock_in_progress) { smblib_dbg(chg, PR_MISC, "restore type-c interrupts\n"); smblib_typec_irq_config(chg, true); chg->pr_lock_in_progress = false; } } static void smblib_pr_swap_detach_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, Loading Loading @@ -7094,6 +7187,8 @@ int smblib_init(struct smb_charger *chg) smblib_dual_role_check_work); INIT_DELAYED_WORK(&chg->pr_swap_detach_work, smblib_pr_swap_detach_work); INIT_DELAYED_WORK(&chg->pr_lock_clear_work, smblib_pr_lock_clear_work); if (chg->wa_flags & CHG_TERMINATION_WA) { INIT_WORK(&chg->chg_termination_work, Loading Loading @@ -7130,6 +7225,7 @@ int smblib_init(struct smb_charger *chg) chg->cp_reason = POWER_SUPPLY_CP_NONE; chg->thermal_status = TEMP_BELOW_RANGE; chg->dr_mode = DUAL_ROLE_PROP_MODE_NONE; chg->typec_irq_en = true; switch (chg->mode) { case PARALLEL_MASTER: Loading
drivers/power/supply/qcom/smb5-lib.h +4 −0 Original line number Diff line number Diff line Loading @@ -457,6 +457,7 @@ struct smb_charger { struct delayed_work usbov_dbc_work; struct delayed_work role_reversal_check; struct delayed_work pr_swap_detach_work; struct delayed_work pr_lock_clear_work; struct alarm lpd_recheck_timer; struct alarm moisture_protection_alarm; Loading @@ -473,10 +474,12 @@ struct smb_charger { int voltage_max_uv; int pd_active; bool pd_hard_reset; bool pr_lock_in_progress; bool pr_swap_in_progress; bool early_usb_attach; bool ok_to_pd; bool typec_legacy; bool typec_irq_en; /* cached status */ bool system_suspend_supported; Loading Loading @@ -511,6 +514,7 @@ struct smb_charger { int hw_max_icl_ua; int auto_recharge_soc; enum sink_src_mode sink_src_mode; enum power_supply_typec_power_role power_role; enum jeita_cfg_stat jeita_configured; int charger_temp_max; int smb_temp_max; Loading