Loading drivers/power/qpnp-smbcharger.c +154 −3 Original line number Diff line number Diff line Loading @@ -123,7 +123,6 @@ struct smbchg_chip { int prechg_safety_time; int bmd_pin_src; int jeita_temp_hard_limit; int sw_esr_pulse_current_ma; int aicl_rerun_period_s; bool use_vfloat_adjustments; bool iterm_disabled; Loading Loading @@ -293,6 +292,7 @@ enum smbchg_wa { SMBCHG_BATT_OV_WA = BIT(3), SMBCHG_CC_ESR_WA = BIT(4), SMBCHG_FLASH_ICL_DISABLE_WA = BIT(5), SMBCHG_RESTART_WA = BIT(6), }; enum print_reason { Loading Loading @@ -326,6 +326,7 @@ enum icl_voters { USER_ICL_VOTER, WEAK_CHARGER_ICL_VOTER, SW_AICL_ICL_VOTER, CHG_SUSPEND_WORKAROUND_ICL_VOTER, NUM_ICL_VOTER, }; Loading Loading @@ -6378,6 +6379,18 @@ static int smbchg_hw_init(struct smbchg_chip *chip) chip->revision[DIG_MAJOR], chip->revision[DIG_MINOR], chip->revision[ANA_MAJOR], chip->revision[ANA_MINOR]); /* Setup 9V HVDCP */ if (!chip->hvdcp_not_supported) { rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_ADAPTER_SEL_MASK, HVDCP_9V); if (rc < 0) { pr_err("Couldn't set hvdcp config in chgpath_chg rc=%d\n", rc); return rc; } } if (chip->aicl_rerun_period_s > 0) { rc = smbchg_set_aicl_rerun_period_s(chip, chip->aicl_rerun_period_s); Loading Loading @@ -7394,7 +7407,8 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) case PMI8994: chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA | SMBCHG_BATT_OV_WA | SMBCHG_CC_ESR_WA; | SMBCHG_CC_ESR_WA | SMBCHG_RESTART_WA; use_pmi8994_tables(chip); chip->schg_version = QPNP_SCHG; break; Loading @@ -7414,7 +7428,8 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) break; case PMI8996: chip->wa_flags |= SMBCHG_CC_ESR_WA | SMBCHG_FLASH_ICL_DISABLE_WA; | SMBCHG_FLASH_ICL_DISABLE_WA | SMBCHG_RESTART_WA; use_pmi8996_tables(chip); chip->schg_version = QPNP_SCHG; break; Loading @@ -7430,6 +7445,50 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) return 0; } static void rerun_hvdcp_det_if_necessary(struct smbchg_chip *chip) { enum power_supply_type usb_supply_type; char *usb_type_name; int rc; if (!(chip->wa_flags & SMBCHG_RESTART_WA)) return; read_usb_type(chip, &usb_type_name, &usb_supply_type); if (usb_supply_type == POWER_SUPPLY_TYPE_USB_DCP && !is_hvdcp_present(chip)) { pr_smb(PR_STATUS, "DCP found rerunning APSD\n"); rc = vote(chip->usb_icl_votable, CHG_SUSPEND_WORKAROUND_ICL_VOTER, true, 300); if (rc < 0) pr_err("Couldn't vote for 300mA for suspend wa, going ahead rc=%d\n", rc); pr_smb(PR_STATUS, "Faking Removal\n"); fake_insertion_removal(chip, false); msleep(500); pr_smb(PR_STATUS, "Faking Insertion\n"); fake_insertion_removal(chip, true); read_usb_type(chip, &usb_type_name, &usb_supply_type); if (usb_supply_type != POWER_SUPPLY_TYPE_USB_DCP) { msleep(500); pr_smb(PR_STATUS, "Fake Removal again as type!=DCP\n"); fake_insertion_removal(chip, false); msleep(500); pr_smb(PR_STATUS, "Fake Insert again as type!=DCP\n"); fake_insertion_removal(chip, true); } rc = vote(chip->usb_icl_votable, CHG_SUSPEND_WORKAROUND_ICL_VOTER, false, 0); if (rc < 0) pr_err("Couldn't vote for 0 for suspend wa, going ahead rc=%d\n", rc); } } static int smbchg_probe(struct spmi_device *spmi) { int rc; Loading Loading @@ -7635,6 +7694,8 @@ static int smbchg_probe(struct spmi_device *spmi) power_supply_set_present(chip->usb_psy, chip->usb_present); } rerun_hvdcp_det_if_necessary(chip); dump_regs(chip); create_debugfs_entries(chip); dev_info(chip->dev, Loading Loading @@ -7672,6 +7733,95 @@ static int smbchg_remove(struct spmi_device *spmi) return 0; } static void smbchg_shutdown(struct spmi_device *spmi) { struct smbchg_chip *chip = dev_get_drvdata(&spmi->dev); int rc; if (!(chip->wa_flags & SMBCHG_RESTART_WA)) return; if (!is_hvdcp_present(chip)) return; pr_smb(PR_MISC, "Disable Parallel\n"); mutex_lock(&chip->parallel.lock); smbchg_parallel_en = 0; smbchg_parallel_usb_disable(chip); mutex_unlock(&chip->parallel.lock); pr_smb(PR_MISC, "Disable all interrupts\n"); disable_irq(chip->aicl_done_irq); disable_irq(chip->batt_cold_irq); disable_irq(chip->batt_cool_irq); disable_irq(chip->batt_hot_irq); disable_irq(chip->batt_missing_irq); disable_irq(chip->batt_warm_irq); disable_irq(chip->chg_error_irq); disable_irq(chip->chg_hot_irq); disable_irq(chip->chg_term_irq); disable_irq(chip->dcin_uv_irq); disable_irq(chip->fastchg_irq); disable_irq(chip->otg_fail_irq); disable_irq(chip->otg_oc_irq); disable_irq(chip->power_ok_irq); disable_irq(chip->recharge_irq); disable_irq(chip->src_detect_irq); disable_irq(chip->taper_irq); disable_irq(chip->usbid_change_irq); disable_irq(chip->usbin_ov_irq); disable_irq(chip->usbin_uv_irq); disable_irq(chip->vbat_low_irq); disable_irq(chip->wdog_timeout_irq); /* switch to 5V HVDCP */ pr_smb(PR_MISC, "Switch to 5V HVDCP\n"); rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_ADAPTER_SEL_MASK, HVDCP_5V); if (rc < 0) { pr_err("Couldn't configure HVDCP 5V rc=%d\n", rc); return; } pr_smb(PR_MISC, "Wait 500mS to lower to 5V\n"); /* wait for HVDCP to lower to 5V */ msleep(500); /* * Check if the same hvdcp session is in progress. src_det should be * high and that we are still in 5V hvdcp */ if (!is_src_detect_high(chip)) { pr_smb(PR_MISC, "src det low after 500mS sleep\n"); return; } /* disable HVDCP */ pr_smb(PR_MISC, "Disable HVDCP\n"); rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_EN_BIT, 0); if (rc < 0) pr_err("Couldn't disable HVDCP rc=%d\n", rc); chip->hvdcp_3_det_ignore_uv = true; /* fake a removal */ pr_smb(PR_MISC, "Faking Removal\n"); rc = fake_insertion_removal(chip, false); if (rc < 0) pr_err("Couldn't fake removal HVDCP Removed rc=%d\n", rc); /* fake an insertion */ pr_smb(PR_MISC, "Faking Insertion\n"); rc = fake_insertion_removal(chip, true); if (rc < 0) pr_err("Couldn't fake insertion rc=%d\n", rc); pr_smb(PR_MISC, "Wait 1S to settle\n"); msleep(1000); chip->hvdcp_3_det_ignore_uv = false; pr_smb(PR_STATUS, "wrote power off configurations\n"); } static const struct dev_pm_ops smbchg_pm_ops = { }; Loading @@ -7686,6 +7836,7 @@ static struct spmi_driver smbchg_driver = { }, .probe = smbchg_probe, .remove = smbchg_remove, .shutdown = smbchg_shutdown, }; static int __init smbchg_init(void) Loading Loading
drivers/power/qpnp-smbcharger.c +154 −3 Original line number Diff line number Diff line Loading @@ -123,7 +123,6 @@ struct smbchg_chip { int prechg_safety_time; int bmd_pin_src; int jeita_temp_hard_limit; int sw_esr_pulse_current_ma; int aicl_rerun_period_s; bool use_vfloat_adjustments; bool iterm_disabled; Loading Loading @@ -293,6 +292,7 @@ enum smbchg_wa { SMBCHG_BATT_OV_WA = BIT(3), SMBCHG_CC_ESR_WA = BIT(4), SMBCHG_FLASH_ICL_DISABLE_WA = BIT(5), SMBCHG_RESTART_WA = BIT(6), }; enum print_reason { Loading Loading @@ -326,6 +326,7 @@ enum icl_voters { USER_ICL_VOTER, WEAK_CHARGER_ICL_VOTER, SW_AICL_ICL_VOTER, CHG_SUSPEND_WORKAROUND_ICL_VOTER, NUM_ICL_VOTER, }; Loading Loading @@ -6378,6 +6379,18 @@ static int smbchg_hw_init(struct smbchg_chip *chip) chip->revision[DIG_MAJOR], chip->revision[DIG_MINOR], chip->revision[ANA_MAJOR], chip->revision[ANA_MINOR]); /* Setup 9V HVDCP */ if (!chip->hvdcp_not_supported) { rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_ADAPTER_SEL_MASK, HVDCP_9V); if (rc < 0) { pr_err("Couldn't set hvdcp config in chgpath_chg rc=%d\n", rc); return rc; } } if (chip->aicl_rerun_period_s > 0) { rc = smbchg_set_aicl_rerun_period_s(chip, chip->aicl_rerun_period_s); Loading Loading @@ -7394,7 +7407,8 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) case PMI8994: chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA | SMBCHG_BATT_OV_WA | SMBCHG_CC_ESR_WA; | SMBCHG_CC_ESR_WA | SMBCHG_RESTART_WA; use_pmi8994_tables(chip); chip->schg_version = QPNP_SCHG; break; Loading @@ -7414,7 +7428,8 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) break; case PMI8996: chip->wa_flags |= SMBCHG_CC_ESR_WA | SMBCHG_FLASH_ICL_DISABLE_WA; | SMBCHG_FLASH_ICL_DISABLE_WA | SMBCHG_RESTART_WA; use_pmi8996_tables(chip); chip->schg_version = QPNP_SCHG; break; Loading @@ -7430,6 +7445,50 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) return 0; } static void rerun_hvdcp_det_if_necessary(struct smbchg_chip *chip) { enum power_supply_type usb_supply_type; char *usb_type_name; int rc; if (!(chip->wa_flags & SMBCHG_RESTART_WA)) return; read_usb_type(chip, &usb_type_name, &usb_supply_type); if (usb_supply_type == POWER_SUPPLY_TYPE_USB_DCP && !is_hvdcp_present(chip)) { pr_smb(PR_STATUS, "DCP found rerunning APSD\n"); rc = vote(chip->usb_icl_votable, CHG_SUSPEND_WORKAROUND_ICL_VOTER, true, 300); if (rc < 0) pr_err("Couldn't vote for 300mA for suspend wa, going ahead rc=%d\n", rc); pr_smb(PR_STATUS, "Faking Removal\n"); fake_insertion_removal(chip, false); msleep(500); pr_smb(PR_STATUS, "Faking Insertion\n"); fake_insertion_removal(chip, true); read_usb_type(chip, &usb_type_name, &usb_supply_type); if (usb_supply_type != POWER_SUPPLY_TYPE_USB_DCP) { msleep(500); pr_smb(PR_STATUS, "Fake Removal again as type!=DCP\n"); fake_insertion_removal(chip, false); msleep(500); pr_smb(PR_STATUS, "Fake Insert again as type!=DCP\n"); fake_insertion_removal(chip, true); } rc = vote(chip->usb_icl_votable, CHG_SUSPEND_WORKAROUND_ICL_VOTER, false, 0); if (rc < 0) pr_err("Couldn't vote for 0 for suspend wa, going ahead rc=%d\n", rc); } } static int smbchg_probe(struct spmi_device *spmi) { int rc; Loading Loading @@ -7635,6 +7694,8 @@ static int smbchg_probe(struct spmi_device *spmi) power_supply_set_present(chip->usb_psy, chip->usb_present); } rerun_hvdcp_det_if_necessary(chip); dump_regs(chip); create_debugfs_entries(chip); dev_info(chip->dev, Loading Loading @@ -7672,6 +7733,95 @@ static int smbchg_remove(struct spmi_device *spmi) return 0; } static void smbchg_shutdown(struct spmi_device *spmi) { struct smbchg_chip *chip = dev_get_drvdata(&spmi->dev); int rc; if (!(chip->wa_flags & SMBCHG_RESTART_WA)) return; if (!is_hvdcp_present(chip)) return; pr_smb(PR_MISC, "Disable Parallel\n"); mutex_lock(&chip->parallel.lock); smbchg_parallel_en = 0; smbchg_parallel_usb_disable(chip); mutex_unlock(&chip->parallel.lock); pr_smb(PR_MISC, "Disable all interrupts\n"); disable_irq(chip->aicl_done_irq); disable_irq(chip->batt_cold_irq); disable_irq(chip->batt_cool_irq); disable_irq(chip->batt_hot_irq); disable_irq(chip->batt_missing_irq); disable_irq(chip->batt_warm_irq); disable_irq(chip->chg_error_irq); disable_irq(chip->chg_hot_irq); disable_irq(chip->chg_term_irq); disable_irq(chip->dcin_uv_irq); disable_irq(chip->fastchg_irq); disable_irq(chip->otg_fail_irq); disable_irq(chip->otg_oc_irq); disable_irq(chip->power_ok_irq); disable_irq(chip->recharge_irq); disable_irq(chip->src_detect_irq); disable_irq(chip->taper_irq); disable_irq(chip->usbid_change_irq); disable_irq(chip->usbin_ov_irq); disable_irq(chip->usbin_uv_irq); disable_irq(chip->vbat_low_irq); disable_irq(chip->wdog_timeout_irq); /* switch to 5V HVDCP */ pr_smb(PR_MISC, "Switch to 5V HVDCP\n"); rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_ADAPTER_SEL_MASK, HVDCP_5V); if (rc < 0) { pr_err("Couldn't configure HVDCP 5V rc=%d\n", rc); return; } pr_smb(PR_MISC, "Wait 500mS to lower to 5V\n"); /* wait for HVDCP to lower to 5V */ msleep(500); /* * Check if the same hvdcp session is in progress. src_det should be * high and that we are still in 5V hvdcp */ if (!is_src_detect_high(chip)) { pr_smb(PR_MISC, "src det low after 500mS sleep\n"); return; } /* disable HVDCP */ pr_smb(PR_MISC, "Disable HVDCP\n"); rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_EN_BIT, 0); if (rc < 0) pr_err("Couldn't disable HVDCP rc=%d\n", rc); chip->hvdcp_3_det_ignore_uv = true; /* fake a removal */ pr_smb(PR_MISC, "Faking Removal\n"); rc = fake_insertion_removal(chip, false); if (rc < 0) pr_err("Couldn't fake removal HVDCP Removed rc=%d\n", rc); /* fake an insertion */ pr_smb(PR_MISC, "Faking Insertion\n"); rc = fake_insertion_removal(chip, true); if (rc < 0) pr_err("Couldn't fake insertion rc=%d\n", rc); pr_smb(PR_MISC, "Wait 1S to settle\n"); msleep(1000); chip->hvdcp_3_det_ignore_uv = false; pr_smb(PR_STATUS, "wrote power off configurations\n"); } static const struct dev_pm_ops smbchg_pm_ops = { }; Loading @@ -7686,6 +7836,7 @@ static struct spmi_driver smbchg_driver = { }, .probe = smbchg_probe, .remove = smbchg_remove, .shutdown = smbchg_shutdown, }; static int __init smbchg_init(void) Loading