Loading drivers/power/supply/qcom/qpnp-smb2.c +16 −1 Original line number Diff line number Diff line Loading @@ -1305,7 +1305,22 @@ static int smb2_init_hw(struct smb2 *chip) smblib_get_charge_param(chg, &chg->param.dc_icl, &chip->dt.dc_icl_ua); chg->otg_cl_ua = chip->dt.otg_cl_ua; /* set a slower soft start setting for OTG */ rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG2_REG, ENG_SSUPPLY_IVREF_OTG_SS_MASK, OTG_SS_SLOW); if (rc < 0) { pr_err("Couldn't set otg soft start rc=%d\n", rc); return rc; } /* set OTG current limit */ rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chip->dt.otg_cl_ua); if (rc < 0) { pr_err("Couldn't set otg current limit rc=%d\n", rc); return rc; } chg->dcp_icl_ua = chip->dt.usb_icl_ua; chg->boost_threshold_ua = chip->dt.boost_threshold_ua; Loading drivers/power/supply/qcom/smb-lib.c +234 −156 Original line number Diff line number Diff line Loading @@ -762,20 +762,6 @@ out: return rc; } #define MICRO_250MA 250000 static int smblib_otg_cl_config(struct smb_charger *chg, int otg_cl_ua) { int rc = 0; rc = smblib_set_charge_param(chg, &chg->param.otg_cl, otg_cl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set otg current limit rc=%d\n", rc); return rc; } return rc; } static int smblib_dc_icl_vote_callback(struct votable *votable, void *data, int icl_ua, const char *client) { Loading Loading @@ -955,22 +941,33 @@ static int smblib_apsd_disable_vote_callback(struct votable *votable, * VCONN REGULATOR * * *****************/ #define MAX_OTG_SS_TRIES 2 static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); u8 otg_stat, stat4; int rc = 0; int rc = 0, i; if (!chg->external_vconn) { /* * Hardware based OTG soft start should complete within 1ms, so * wait for 2ms in the worst case. */ for (i = 0; i < MAX_OTG_SS_TRIES; ++i) { usleep_range(1000, 1100); rc = smblib_read(chg, OTG_STATUS_REG, &otg_stat); if (rc < 0) { smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc); smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc); return rc; } if ((otg_stat & OTG_STATE_MASK) != OTG_STATE_ENABLED) { smblib_err(chg, "Couldn't enable VCONN; OTG is not ready otg_stat=0x%02x\n", otg_stat); if (otg_stat & BOOST_SOFTSTART_DONE_BIT) break; } if (!(otg_stat & BOOST_SOFTSTART_DONE_BIT)) { smblib_err(chg, "Couldn't enable VCONN; OTG soft start failed\n"); return -EAGAIN; } } Loading @@ -985,6 +982,7 @@ static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev) return rc; } smblib_dbg(chg, PR_OTG, "enabling VCONN\n"); stat4 = stat4 & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT; rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT, Loading @@ -1002,7 +1000,7 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); if (chg->vconn_en) goto unlock; Loading @@ -1011,7 +1009,7 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev) chg->vconn_en = true; unlock: mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return rc; } Loading @@ -1020,6 +1018,7 @@ static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; smblib_dbg(chg, PR_OTG, "disabling VCONN\n"); rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, VCONN_EN_VALUE_BIT, 0); if (rc < 0) Loading @@ -1033,7 +1032,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); if (!chg->vconn_en) goto unlock; Loading @@ -1042,7 +1041,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev) chg->vconn_en = false; unlock: mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return rc; } Loading @@ -1051,9 +1050,9 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int ret; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); ret = chg->vconn_en; mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return ret; } Loading @@ -1061,14 +1060,12 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) * OTG REGULATOR * *****************/ #define MAX_SOFTSTART_TRIES 2 static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); u8 stat; int rc = 0; int tries = MAX_SOFTSTART_TRIES; int rc; smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n"); rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, ENG_BUCKBOOST_HALT1_8_MODE_BIT, ENG_BUCKBOOST_HALT1_8_MODE_BIT); Loading @@ -1078,34 +1075,13 @@ static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) return rc; } smblib_dbg(chg, PR_OTG, "enabling OTG\n"); rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT); if (rc < 0) { smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc); return rc; } /* waiting for boost readiness, usually ~1ms, 2ms in worst case */ do { usleep_range(1000, 1100); rc = smblib_read(chg, OTG_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read OTG_STATUS_REG rc=%d\n", rc); return rc; } if (stat & BOOST_SOFTSTART_DONE_BIT) { smblib_otg_cl_config(chg, chg->otg_cl_ua); break; } } while (--tries); if (tries == 0) { smblib_err(chg, "Timeout waiting for boost softstart rc=%d\n", rc); return -ETIMEDOUT; } return rc; } Loading @@ -1114,7 +1090,7 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); if (chg->otg_en) goto unlock; Loading @@ -1123,7 +1099,7 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev) chg->otg_en = true; unlock: mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return rc; } Loading @@ -1131,32 +1107,23 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); int rc; u8 stat; if (!chg->external_vconn) { rc = smblib_read(chg, RID_CC_CONTROL_7_0_REG, &stat); if (rc < 0) smblib_err(chg, "Couldn't read RID_CC_CONTROL_7_0 rc=%d\n", rc); /* check if VCONN is enabled on either CC pin */ if (stat & VCONN_EN_CC_MASK) { smblib_dbg(chg, PR_MISC, "Killing VCONN before disabling OTG\n"); if (!chg->external_vconn && chg->vconn_en) { smblib_dbg(chg, PR_OTG, "Killing VCONN before disabling OTG\n"); rc = _smblib_vconn_regulator_disable(rdev); if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); } smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); } smblib_dbg(chg, PR_OTG, "disabling OTG\n"); rc = smblib_write(chg, CMD_OTG_REG, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc); return rc; } smblib_otg_cl_config(chg, MICRO_250MA); smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n"); rc = smblib_write(chg, CMD_OTG_REG, 0); rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0); if (rc < 0) { Loading @@ -1172,7 +1139,7 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); if (!chg->otg_en) goto unlock; Loading @@ -1181,7 +1148,7 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev) chg->otg_en = false; unlock: mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return rc; } Loading @@ -1190,9 +1157,9 @@ int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int ret; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); ret = chg->otg_en; mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return ret; } Loading Loading @@ -2490,50 +2457,9 @@ irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data) return IRQ_HANDLED; } if (!(stat & OTG_OVERCURRENT_RT_STS_BIT)) return IRQ_HANDLED; if (stat & OTG_OVERCURRENT_RT_STS_BIT) schedule_work(&chg->otg_oc_work); smblib_err(chg, "over-current detected on VBUS\n"); if (!chg->vbus_vreg || !chg->vbus_vreg->rdev) return IRQ_HANDLED; mutex_lock(&chg->otg_overcurrent_lock); if (!chg->external_vconn && chg->vconn_en) { rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); } rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc); /* * VBUS must be disabled after OC to be ready for the next insertion. * If the maximum number of attempts have been reached then don't try * to re-enable. */ if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) { smblib_err(chg, "OTG failed to enable after %d attempts\n", chg->otg_attempts - 1); goto unlock; } /* allow the attached device to discharge */ msleep(250); rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc); if (!chg->external_vconn && chg->vconn_en) { rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc); } unlock: mutex_unlock(&chg->otg_overcurrent_lock); return IRQ_HANDLED; } Loading Loading @@ -3117,41 +3043,6 @@ irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg) return IRQ_HANDLED; } static void smblib_handle_vconn_overcurrent(struct smb_charger *chg) { int rc; smblib_err(chg, "over-current detected on VCONN\n"); if (!chg->vconn_vreg || !chg->vconn_vreg->rdev) return; mutex_lock(&chg->otg_overcurrent_lock); rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); /* * VCONN must be disabled after OC to be ready for the next insertion. * If the maximum number of attempts have been reached then don't try * to re-enable. */ if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) { smblib_err(chg, "VCONN failed to enable after %d attempts\n", chg->vconn_attempts - 1); goto unlock; } /* allow the attached device to discharge */ msleep(250); rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc); unlock: mutex_unlock(&chg->otg_overcurrent_lock); } irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) { struct smb_irq_data *irq_data = data; Loading Loading @@ -3191,7 +3082,7 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) irq_data->name); if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT) smblib_handle_vconn_overcurrent(chg); schedule_work(&chg->vconn_oc_work); power_supply_changed(chg->usb_psy); smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4); Loading Loading @@ -3385,6 +3276,190 @@ rerun: schedule_work(&chg->rdstd_cc2_detach_work); } static void smblib_otg_oc_exit(struct smb_charger *chg, bool success) { int rc; chg->otg_attempts = 0; if (!success) { smblib_err(chg, "OTG soft start failed\n"); chg->otg_en = false; } smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n"); rc = smblib_masked_write(chg, OTG_CFG_REG, QUICKSTART_OTG_FASTROLESWAP_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc); if (!chg->external_vconn && chg->vconn_en) { chg->vconn_attempts = 0; if (success) { rc = _smblib_vconn_regulator_enable( chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc); } else { chg->vconn_en = false; } } } #define MAX_OC_FALLING_TRIES 10 static void smblib_otg_oc_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, otg_oc_work); int rc, i; u8 stat; if (!chg->vbus_vreg || !chg->vbus_vreg->rdev) return; smblib_err(chg, "over-current detected on VBUS\n"); mutex_lock(&chg->otg_oc_lock); if (!chg->otg_en) goto unlock; smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n"); smblib_masked_write(chg, OTG_CFG_REG, QUICKSTART_OTG_FASTROLESWAP_BIT, QUICKSTART_OTG_FASTROLESWAP_BIT); /* * If 500ms has passed and another over-current interrupt has not * triggered then it is likely that the software based soft start was * successful and the VBUS < 1V restriction should be re-enabled. */ schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500)); rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc); goto unlock; } if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) { cancel_delayed_work_sync(&chg->otg_ss_done_work); smblib_err(chg, "OTG failed to enable after %d attempts\n", chg->otg_attempts - 1); smblib_otg_oc_exit(chg, false); goto unlock; } /* * The real time status should go low within 10ms. Poll every 1-2ms to * minimize the delay when re-enabling OTG. */ for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) { usleep_range(1000, 2000); rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat); if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT)) break; } if (i >= MAX_OC_FALLING_TRIES) { cancel_delayed_work_sync(&chg->otg_ss_done_work); smblib_err(chg, "OTG OC did not fall after %dms\n", 2 * MAX_OC_FALLING_TRIES); smblib_otg_oc_exit(chg, false); goto unlock; } smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1); rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc); goto unlock; } unlock: mutex_unlock(&chg->otg_oc_lock); } static void smblib_vconn_oc_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, vconn_oc_work); int rc, i; u8 stat; smblib_err(chg, "over-current detected on VCONN\n"); if (!chg->vconn_vreg || !chg->vconn_vreg->rdev) return; mutex_lock(&chg->otg_oc_lock); rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); goto unlock; } if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) { smblib_err(chg, "VCONN failed to enable after %d attempts\n", chg->otg_attempts - 1); chg->vconn_en = false; chg->vconn_attempts = 0; goto unlock; } /* * The real time status should go low within 10ms. Poll every 1-2ms to * minimize the delay when re-enabling OTG. */ for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) { usleep_range(1000, 2000); rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT)) break; } if (i >= MAX_OC_FALLING_TRIES) { smblib_err(chg, "VCONN OC did not fall after %dms\n", 2 * MAX_OC_FALLING_TRIES); chg->vconn_en = false; chg->vconn_attempts = 0; goto unlock; } smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1); if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) { smblib_err(chg, "VCONN failed to enable after %d attempts\n", chg->vconn_attempts - 1); chg->vconn_en = false; goto unlock; } rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc); goto unlock; } unlock: mutex_unlock(&chg->otg_oc_lock); } static void smblib_otg_ss_done_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, otg_ss_done_work.work); int rc; bool success = false; u8 stat; mutex_lock(&chg->otg_oc_lock); rc = smblib_read(chg, OTG_STATUS_REG, &stat); if (rc < 0) smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc); else if (stat & BOOST_SOFTSTART_DONE_BIT) success = true; smblib_otg_oc_exit(chg, success); mutex_unlock(&chg->otg_oc_lock); } static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; Loading Loading @@ -3564,12 +3639,15 @@ int smblib_init(struct smb_charger *chg) int rc = 0; mutex_init(&chg->write_lock); mutex_init(&chg->otg_overcurrent_lock); mutex_init(&chg->otg_oc_lock); INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work); INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work); INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work); INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work); chg->fake_capacity = -EINVAL; switch (chg->mode) { Loading drivers/power/supply/qcom/smb-lib.h +5 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ enum print_reason { PR_REGISTER = BIT(1), PR_MISC = BIT(2), PR_PARALLEL = BIT(3), PR_OTG = BIT(4), }; #define DEFAULT_VOTER "DEFAULT_VOTER" Loading Loading @@ -161,7 +162,7 @@ struct smb_charger { /* locks */ struct mutex write_lock; struct mutex ps_change_lock; struct mutex otg_overcurrent_lock; struct mutex otg_oc_lock; /* power supplies */ struct power_supply *batt_psy; Loading Loading @@ -207,6 +208,9 @@ struct smb_charger { struct delayed_work ps_change_timeout_work; struct delayed_work step_soc_req_work; struct delayed_work clear_hdc_work; struct work_struct otg_oc_work; struct work_struct vconn_oc_work; struct delayed_work otg_ss_done_work; /* cached status */ int voltage_min_uv; Loading @@ -217,7 +221,6 @@ struct smb_charger { int system_temp_level; int thermal_levels; int *thermal_mitigation; int otg_cl_ua; int dcp_icl_ua; int fake_capacity; bool step_chg_enabled; Loading drivers/power/supply/qcom/smb-reg.h +7 −1 Original line number Diff line number Diff line Loading @@ -366,7 +366,9 @@ enum { #define OTG_CURRENT_LIMIT_MASK GENMASK(2, 0) #define OTG_CFG_REG (OTG_BASE + 0x53) #define OTG_RESERVED_MASK GENMASK(7, 4) #define OTG_RESERVED_MASK GENMASK(7, 6) #define DIS_OTG_ON_TLIM_BIT BIT(5) #define QUICKSTART_OTG_FASTROLESWAP_BIT BIT(4) #define INCREASE_DFP_TIME_BIT BIT(3) #define ENABLE_OTG_IN_DEBUG_MODE_BIT BIT(2) #define OTG_EN_SRC_CFG_BIT BIT(1) Loading Loading @@ -793,6 +795,10 @@ enum { ZIN_ICL_HV_MAX_MV = 11000, }; #define DC_ENG_SSUPPLY_CFG2_REG (DCIN_BASE + 0xC1) #define ENG_SSUPPLY_IVREF_OTG_SS_MASK GENMASK(2, 0) #define OTG_SS_SLOW 0x3 #define DC_ENG_SSUPPLY_CFG3_REG (DCIN_BASE + 0xC2) #define ENG_SSUPPLY_HI_CAP_BIT BIT(6) #define ENG_SSUPPLY_HI_RES_BIT BIT(5) Loading Loading
drivers/power/supply/qcom/qpnp-smb2.c +16 −1 Original line number Diff line number Diff line Loading @@ -1305,7 +1305,22 @@ static int smb2_init_hw(struct smb2 *chip) smblib_get_charge_param(chg, &chg->param.dc_icl, &chip->dt.dc_icl_ua); chg->otg_cl_ua = chip->dt.otg_cl_ua; /* set a slower soft start setting for OTG */ rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG2_REG, ENG_SSUPPLY_IVREF_OTG_SS_MASK, OTG_SS_SLOW); if (rc < 0) { pr_err("Couldn't set otg soft start rc=%d\n", rc); return rc; } /* set OTG current limit */ rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chip->dt.otg_cl_ua); if (rc < 0) { pr_err("Couldn't set otg current limit rc=%d\n", rc); return rc; } chg->dcp_icl_ua = chip->dt.usb_icl_ua; chg->boost_threshold_ua = chip->dt.boost_threshold_ua; Loading
drivers/power/supply/qcom/smb-lib.c +234 −156 Original line number Diff line number Diff line Loading @@ -762,20 +762,6 @@ out: return rc; } #define MICRO_250MA 250000 static int smblib_otg_cl_config(struct smb_charger *chg, int otg_cl_ua) { int rc = 0; rc = smblib_set_charge_param(chg, &chg->param.otg_cl, otg_cl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set otg current limit rc=%d\n", rc); return rc; } return rc; } static int smblib_dc_icl_vote_callback(struct votable *votable, void *data, int icl_ua, const char *client) { Loading Loading @@ -955,22 +941,33 @@ static int smblib_apsd_disable_vote_callback(struct votable *votable, * VCONN REGULATOR * * *****************/ #define MAX_OTG_SS_TRIES 2 static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); u8 otg_stat, stat4; int rc = 0; int rc = 0, i; if (!chg->external_vconn) { /* * Hardware based OTG soft start should complete within 1ms, so * wait for 2ms in the worst case. */ for (i = 0; i < MAX_OTG_SS_TRIES; ++i) { usleep_range(1000, 1100); rc = smblib_read(chg, OTG_STATUS_REG, &otg_stat); if (rc < 0) { smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc); smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc); return rc; } if ((otg_stat & OTG_STATE_MASK) != OTG_STATE_ENABLED) { smblib_err(chg, "Couldn't enable VCONN; OTG is not ready otg_stat=0x%02x\n", otg_stat); if (otg_stat & BOOST_SOFTSTART_DONE_BIT) break; } if (!(otg_stat & BOOST_SOFTSTART_DONE_BIT)) { smblib_err(chg, "Couldn't enable VCONN; OTG soft start failed\n"); return -EAGAIN; } } Loading @@ -985,6 +982,7 @@ static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev) return rc; } smblib_dbg(chg, PR_OTG, "enabling VCONN\n"); stat4 = stat4 & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT; rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT, Loading @@ -1002,7 +1000,7 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); if (chg->vconn_en) goto unlock; Loading @@ -1011,7 +1009,7 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev) chg->vconn_en = true; unlock: mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return rc; } Loading @@ -1020,6 +1018,7 @@ static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; smblib_dbg(chg, PR_OTG, "disabling VCONN\n"); rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, VCONN_EN_VALUE_BIT, 0); if (rc < 0) Loading @@ -1033,7 +1032,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); if (!chg->vconn_en) goto unlock; Loading @@ -1042,7 +1041,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev) chg->vconn_en = false; unlock: mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return rc; } Loading @@ -1051,9 +1050,9 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int ret; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); ret = chg->vconn_en; mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return ret; } Loading @@ -1061,14 +1060,12 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) * OTG REGULATOR * *****************/ #define MAX_SOFTSTART_TRIES 2 static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); u8 stat; int rc = 0; int tries = MAX_SOFTSTART_TRIES; int rc; smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n"); rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, ENG_BUCKBOOST_HALT1_8_MODE_BIT, ENG_BUCKBOOST_HALT1_8_MODE_BIT); Loading @@ -1078,34 +1075,13 @@ static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) return rc; } smblib_dbg(chg, PR_OTG, "enabling OTG\n"); rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT); if (rc < 0) { smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc); return rc; } /* waiting for boost readiness, usually ~1ms, 2ms in worst case */ do { usleep_range(1000, 1100); rc = smblib_read(chg, OTG_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read OTG_STATUS_REG rc=%d\n", rc); return rc; } if (stat & BOOST_SOFTSTART_DONE_BIT) { smblib_otg_cl_config(chg, chg->otg_cl_ua); break; } } while (--tries); if (tries == 0) { smblib_err(chg, "Timeout waiting for boost softstart rc=%d\n", rc); return -ETIMEDOUT; } return rc; } Loading @@ -1114,7 +1090,7 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); if (chg->otg_en) goto unlock; Loading @@ -1123,7 +1099,7 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev) chg->otg_en = true; unlock: mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return rc; } Loading @@ -1131,32 +1107,23 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); int rc; u8 stat; if (!chg->external_vconn) { rc = smblib_read(chg, RID_CC_CONTROL_7_0_REG, &stat); if (rc < 0) smblib_err(chg, "Couldn't read RID_CC_CONTROL_7_0 rc=%d\n", rc); /* check if VCONN is enabled on either CC pin */ if (stat & VCONN_EN_CC_MASK) { smblib_dbg(chg, PR_MISC, "Killing VCONN before disabling OTG\n"); if (!chg->external_vconn && chg->vconn_en) { smblib_dbg(chg, PR_OTG, "Killing VCONN before disabling OTG\n"); rc = _smblib_vconn_regulator_disable(rdev); if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); } smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); } smblib_dbg(chg, PR_OTG, "disabling OTG\n"); rc = smblib_write(chg, CMD_OTG_REG, 0); if (rc < 0) { smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc); return rc; } smblib_otg_cl_config(chg, MICRO_250MA); smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n"); rc = smblib_write(chg, CMD_OTG_REG, 0); rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0); if (rc < 0) { Loading @@ -1172,7 +1139,7 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); if (!chg->otg_en) goto unlock; Loading @@ -1181,7 +1148,7 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev) chg->otg_en = false; unlock: mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return rc; } Loading @@ -1190,9 +1157,9 @@ int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev) struct smb_charger *chg = rdev_get_drvdata(rdev); int ret; mutex_lock(&chg->otg_overcurrent_lock); mutex_lock(&chg->otg_oc_lock); ret = chg->otg_en; mutex_unlock(&chg->otg_overcurrent_lock); mutex_unlock(&chg->otg_oc_lock); return ret; } Loading Loading @@ -2490,50 +2457,9 @@ irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data) return IRQ_HANDLED; } if (!(stat & OTG_OVERCURRENT_RT_STS_BIT)) return IRQ_HANDLED; if (stat & OTG_OVERCURRENT_RT_STS_BIT) schedule_work(&chg->otg_oc_work); smblib_err(chg, "over-current detected on VBUS\n"); if (!chg->vbus_vreg || !chg->vbus_vreg->rdev) return IRQ_HANDLED; mutex_lock(&chg->otg_overcurrent_lock); if (!chg->external_vconn && chg->vconn_en) { rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); } rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc); /* * VBUS must be disabled after OC to be ready for the next insertion. * If the maximum number of attempts have been reached then don't try * to re-enable. */ if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) { smblib_err(chg, "OTG failed to enable after %d attempts\n", chg->otg_attempts - 1); goto unlock; } /* allow the attached device to discharge */ msleep(250); rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc); if (!chg->external_vconn && chg->vconn_en) { rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc); } unlock: mutex_unlock(&chg->otg_overcurrent_lock); return IRQ_HANDLED; } Loading Loading @@ -3117,41 +3043,6 @@ irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg) return IRQ_HANDLED; } static void smblib_handle_vconn_overcurrent(struct smb_charger *chg) { int rc; smblib_err(chg, "over-current detected on VCONN\n"); if (!chg->vconn_vreg || !chg->vconn_vreg->rdev) return; mutex_lock(&chg->otg_overcurrent_lock); rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); /* * VCONN must be disabled after OC to be ready for the next insertion. * If the maximum number of attempts have been reached then don't try * to re-enable. */ if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) { smblib_err(chg, "VCONN failed to enable after %d attempts\n", chg->vconn_attempts - 1); goto unlock; } /* allow the attached device to discharge */ msleep(250); rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc); unlock: mutex_unlock(&chg->otg_overcurrent_lock); } irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) { struct smb_irq_data *irq_data = data; Loading Loading @@ -3191,7 +3082,7 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) irq_data->name); if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT) smblib_handle_vconn_overcurrent(chg); schedule_work(&chg->vconn_oc_work); power_supply_changed(chg->usb_psy); smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4); Loading Loading @@ -3385,6 +3276,190 @@ rerun: schedule_work(&chg->rdstd_cc2_detach_work); } static void smblib_otg_oc_exit(struct smb_charger *chg, bool success) { int rc; chg->otg_attempts = 0; if (!success) { smblib_err(chg, "OTG soft start failed\n"); chg->otg_en = false; } smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n"); rc = smblib_masked_write(chg, OTG_CFG_REG, QUICKSTART_OTG_FASTROLESWAP_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc); if (!chg->external_vconn && chg->vconn_en) { chg->vconn_attempts = 0; if (success) { rc = _smblib_vconn_regulator_enable( chg->vconn_vreg->rdev); if (rc < 0) smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc); } else { chg->vconn_en = false; } } } #define MAX_OC_FALLING_TRIES 10 static void smblib_otg_oc_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, otg_oc_work); int rc, i; u8 stat; if (!chg->vbus_vreg || !chg->vbus_vreg->rdev) return; smblib_err(chg, "over-current detected on VBUS\n"); mutex_lock(&chg->otg_oc_lock); if (!chg->otg_en) goto unlock; smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n"); smblib_masked_write(chg, OTG_CFG_REG, QUICKSTART_OTG_FASTROLESWAP_BIT, QUICKSTART_OTG_FASTROLESWAP_BIT); /* * If 500ms has passed and another over-current interrupt has not * triggered then it is likely that the software based soft start was * successful and the VBUS < 1V restriction should be re-enabled. */ schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500)); rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc); goto unlock; } if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) { cancel_delayed_work_sync(&chg->otg_ss_done_work); smblib_err(chg, "OTG failed to enable after %d attempts\n", chg->otg_attempts - 1); smblib_otg_oc_exit(chg, false); goto unlock; } /* * The real time status should go low within 10ms. Poll every 1-2ms to * minimize the delay when re-enabling OTG. */ for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) { usleep_range(1000, 2000); rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat); if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT)) break; } if (i >= MAX_OC_FALLING_TRIES) { cancel_delayed_work_sync(&chg->otg_ss_done_work); smblib_err(chg, "OTG OC did not fall after %dms\n", 2 * MAX_OC_FALLING_TRIES); smblib_otg_oc_exit(chg, false); goto unlock; } smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1); rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc); goto unlock; } unlock: mutex_unlock(&chg->otg_oc_lock); } static void smblib_vconn_oc_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, vconn_oc_work); int rc, i; u8 stat; smblib_err(chg, "over-current detected on VCONN\n"); if (!chg->vconn_vreg || !chg->vconn_vreg->rdev) return; mutex_lock(&chg->otg_oc_lock); rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); goto unlock; } if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) { smblib_err(chg, "VCONN failed to enable after %d attempts\n", chg->otg_attempts - 1); chg->vconn_en = false; chg->vconn_attempts = 0; goto unlock; } /* * The real time status should go low within 10ms. Poll every 1-2ms to * minimize the delay when re-enabling OTG. */ for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) { usleep_range(1000, 2000); rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat); if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT)) break; } if (i >= MAX_OC_FALLING_TRIES) { smblib_err(chg, "VCONN OC did not fall after %dms\n", 2 * MAX_OC_FALLING_TRIES); chg->vconn_en = false; chg->vconn_attempts = 0; goto unlock; } smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1); if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) { smblib_err(chg, "VCONN failed to enable after %d attempts\n", chg->vconn_attempts - 1); chg->vconn_en = false; goto unlock; } rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc); goto unlock; } unlock: mutex_unlock(&chg->otg_oc_lock); } static void smblib_otg_ss_done_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, otg_ss_done_work.work); int rc; bool success = false; u8 stat; mutex_lock(&chg->otg_oc_lock); rc = smblib_read(chg, OTG_STATUS_REG, &stat); if (rc < 0) smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc); else if (stat & BOOST_SOFTSTART_DONE_BIT) success = true; smblib_otg_oc_exit(chg, success); mutex_unlock(&chg->otg_oc_lock); } static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; Loading Loading @@ -3564,12 +3639,15 @@ int smblib_init(struct smb_charger *chg) int rc = 0; mutex_init(&chg->write_lock); mutex_init(&chg->otg_overcurrent_lock); mutex_init(&chg->otg_oc_lock); INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work); INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work); INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work); INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work); chg->fake_capacity = -EINVAL; switch (chg->mode) { Loading
drivers/power/supply/qcom/smb-lib.h +5 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ enum print_reason { PR_REGISTER = BIT(1), PR_MISC = BIT(2), PR_PARALLEL = BIT(3), PR_OTG = BIT(4), }; #define DEFAULT_VOTER "DEFAULT_VOTER" Loading Loading @@ -161,7 +162,7 @@ struct smb_charger { /* locks */ struct mutex write_lock; struct mutex ps_change_lock; struct mutex otg_overcurrent_lock; struct mutex otg_oc_lock; /* power supplies */ struct power_supply *batt_psy; Loading Loading @@ -207,6 +208,9 @@ struct smb_charger { struct delayed_work ps_change_timeout_work; struct delayed_work step_soc_req_work; struct delayed_work clear_hdc_work; struct work_struct otg_oc_work; struct work_struct vconn_oc_work; struct delayed_work otg_ss_done_work; /* cached status */ int voltage_min_uv; Loading @@ -217,7 +221,6 @@ struct smb_charger { int system_temp_level; int thermal_levels; int *thermal_mitigation; int otg_cl_ua; int dcp_icl_ua; int fake_capacity; bool step_chg_enabled; Loading
drivers/power/supply/qcom/smb-reg.h +7 −1 Original line number Diff line number Diff line Loading @@ -366,7 +366,9 @@ enum { #define OTG_CURRENT_LIMIT_MASK GENMASK(2, 0) #define OTG_CFG_REG (OTG_BASE + 0x53) #define OTG_RESERVED_MASK GENMASK(7, 4) #define OTG_RESERVED_MASK GENMASK(7, 6) #define DIS_OTG_ON_TLIM_BIT BIT(5) #define QUICKSTART_OTG_FASTROLESWAP_BIT BIT(4) #define INCREASE_DFP_TIME_BIT BIT(3) #define ENABLE_OTG_IN_DEBUG_MODE_BIT BIT(2) #define OTG_EN_SRC_CFG_BIT BIT(1) Loading Loading @@ -793,6 +795,10 @@ enum { ZIN_ICL_HV_MAX_MV = 11000, }; #define DC_ENG_SSUPPLY_CFG2_REG (DCIN_BASE + 0xC1) #define ENG_SSUPPLY_IVREF_OTG_SS_MASK GENMASK(2, 0) #define OTG_SS_SLOW 0x3 #define DC_ENG_SSUPPLY_CFG3_REG (DCIN_BASE + 0xC2) #define ENG_SSUPPLY_HI_CAP_BIT BIT(6) #define ENG_SSUPPLY_HI_RES_BIT BIT(5) Loading