Loading Documentation/devicetree/bindings/power/qpnp-smbcharger.txt +6 −0 Original line number Diff line number Diff line Loading @@ -209,6 +209,9 @@ Optional Properties: the line from the battery connectors through vph_power. This is used to calculate maximum available current of the battery. - qcom,vled-max-uv: The maximum input voltage of the flash leds. This is used to calculate maximum available current of the battery. - qcom,autoadjust-vfloat A boolean property that when set, makes the driver automatically readjust vfloat using the fuel gauge ADC readings to make charging more Loading @@ -223,6 +226,9 @@ Optional Properties: AICL deglitch configuration dynamically. This needs to be set if the DCIN supply is going to be less than or equal to 5V. - qcom,ibat-ocp-threshold-ua Maximum current before the battery will trigger overcurrent protection. Use the recommended battery pack value minus some margin. - qcom,soft-vfloat-comp-disabled Set this property when the battery is powered via external source and could go above the float voltage. Loading drivers/power/qpnp-smbcharger.c +67 −20 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <linux/rtc.h> #include <linux/qpnp/qpnp-adc.h> #include <linux/batterydata-lib.h> #include <linux/msm_bcl.h> /* Mask/Bit helpers */ #define _SMB_MASK(BITS, POS) \ Loading Loading @@ -135,6 +136,7 @@ struct smbchg_chip { /* flash current prediction */ int rpara_uohm; int rslow_uohm; int vled_max_uv; /* vfloat adjustment */ int max_vbat_sample; Loading Loading @@ -2288,14 +2290,20 @@ out: return rc; } static int smbchg_ibat_ocp_threshold_ua = 4500000; module_param(smbchg_ibat_ocp_threshold_ua, int, 0644); #define UCONV 1000000LL #define VIN_FLASH_UV 5500000LL #define FLASH_V_THRESHOLD 3000000LL #define MCONV 1000LL #define FLASH_V_THRESHOLD 3000000 #define FLASH_VDIP_MARGIN 100000 #define VPH_FLASH_VDIP (FLASH_V_THRESHOLD + FLASH_VDIP_MARGIN) #define BUCK_EFFICIENCY 800LL static int smbchg_calc_max_flash_current(struct smbchg_chip *chip) { int ocv_uv, ibat_ua, esr_uohm, rbatt_uohm, rc; int64_t ibat_flash_ua, total_flash_ua, total_flash_power_fw; int ocv_uv, esr_uohm, rbatt_uohm, ibat_now, rc; int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw; int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv; rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv); if (rc) { Loading @@ -2303,30 +2311,59 @@ static int smbchg_calc_max_flash_current(struct smbchg_chip *chip) return 0; } rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_CURRENT_NOW, &ibat_ua); rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_RESISTANCE, &esr_uohm); if (rc) { pr_smb(PR_STATUS, "bms psy does not support current_now\n"); pr_smb(PR_STATUS, "bms psy does not support resistance\n"); return 0; } rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_RESISTANCE, &esr_uohm); rc = msm_bcl_read(BCL_PARAM_CURRENT, &ibat_now); if (rc) { pr_smb(PR_STATUS, "bms psy does not support resistance\n"); pr_smb(PR_STATUS, "BCL current read failed: %d\n", rc); return 0; } rbatt_uohm = esr_uohm + chip->rpara_uohm + chip->rslow_uohm; ibat_flash_ua = (div_s64((ocv_uv - FLASH_V_THRESHOLD) * UCONV, rbatt_uohm)) - ibat_ua; total_flash_power_fw = FLASH_V_THRESHOLD * ibat_flash_ua * BUCK_EFFICIENCY; total_flash_ua = div64_s64(total_flash_power_fw, VIN_FLASH_UV * 1000LL); /* * Calculate the maximum current that can pulled out of the battery * before the battery voltage dips below a safe threshold. */ ibat_safe_ua = div_s64((ocv_uv - VPH_FLASH_VDIP) * UCONV, rbatt_uohm); if (ibat_safe_ua <= smbchg_ibat_ocp_threshold_ua) { /* * If the calculated current is below the OCP threshold, then * use it as the possible flash current. */ ibat_flash_ua = ibat_safe_ua - ibat_now; vph_flash_uv = VPH_FLASH_VDIP; } else { /* * If the calculated current is above the OCP threshold, then * use the ocp threshold instead. * * Any higher current will be tripping the battery OCP. */ ibat_flash_ua = smbchg_ibat_ocp_threshold_ua - ibat_now; vph_flash_uv = ocv_uv - div64_s64((int64_t)rbatt_uohm * smbchg_ibat_ocp_threshold_ua, UCONV); } /* Calculate the input voltage of the flash module. */ vin_flash_uv = max((chip->vled_max_uv + 500000LL), (vph_flash_uv * 1200 / 1000)); /* Calculate the available power for the flash module. */ avail_flash_power_fw = BUCK_EFFICIENCY * vph_flash_uv * ibat_flash_ua; /* * Calculate the available amount of current the flash module can draw * before collapsing the battery. (available power/ flash input voltage) */ avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV); pr_smb(PR_MISC, "ibat_flash=%lld\n, ocv=%d, ibat=%d, rbatt=%d t_flash=%lld\n", ibat_flash_ua, ocv_uv, ibat_ua, rbatt_uohm, total_flash_ua); return (int)total_flash_ua; "avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d\n", avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm); return (int)avail_flash_ua; } #define FCC_CMP_CFG 0xF3 Loading Loading @@ -4749,9 +4786,10 @@ err: return rc; } #define DEFAULT_VLED_MAX_UV 3500000 static int smb_parse_dt(struct smbchg_chip *chip) { int rc = 0; int rc = 0, ocp_thresh = -EINVAL; struct device_node *node = chip->dev->of_node; const char *dc_psy_type, *bpd; Loading @@ -4761,12 +4799,21 @@ static int smb_parse_dt(struct smbchg_chip *chip) } /* read optional u32 properties */ OF_PROP_READ(chip, ocp_thresh, "ibat-ocp-threshold-ua", rc, 1); if (ocp_thresh >= 0) smbchg_ibat_ocp_threshold_ua = ocp_thresh; OF_PROP_READ(chip, chip->iterm_ma, "iterm-ma", rc, 1); OF_PROP_READ(chip, chip->target_fastchg_current_ma, "fastchg-current-ma", rc, 1); OF_PROP_READ(chip, chip->vfloat_mv, "float-voltage-mv", rc, 1); OF_PROP_READ(chip, chip->safety_time, "charging-timeout-mins", rc, 1); OF_PROP_READ(chip, chip->vled_max_uv, "vled-max-uv", rc, 1); if (chip->vled_max_uv < 0) chip->vled_max_uv = DEFAULT_VLED_MAX_UV; OF_PROP_READ(chip, chip->rpara_uohm, "rparasitic-uohm", rc, 1); if (chip->rpara_uohm < 0) chip->rpara_uohm = 0; OF_PROP_READ(chip, chip->prechg_safety_time, "precharging-timeout-mins", rc, 1); OF_PROP_READ(chip, chip->fastchg_current_comp, "fastchg-current-comp", Loading Loading @@ -4874,7 +4921,7 @@ static int smb_parse_dt(struct smbchg_chip *chip) if (rc) chip->bms_psy_name = NULL; /* read the bms power supply name */ /* read the battery power supply name */ rc = of_property_read_string(node, "qcom,battery-psy-name", &chip->battery_psy_name); if (rc) Loading Loading
Documentation/devicetree/bindings/power/qpnp-smbcharger.txt +6 −0 Original line number Diff line number Diff line Loading @@ -209,6 +209,9 @@ Optional Properties: the line from the battery connectors through vph_power. This is used to calculate maximum available current of the battery. - qcom,vled-max-uv: The maximum input voltage of the flash leds. This is used to calculate maximum available current of the battery. - qcom,autoadjust-vfloat A boolean property that when set, makes the driver automatically readjust vfloat using the fuel gauge ADC readings to make charging more Loading @@ -223,6 +226,9 @@ Optional Properties: AICL deglitch configuration dynamically. This needs to be set if the DCIN supply is going to be less than or equal to 5V. - qcom,ibat-ocp-threshold-ua Maximum current before the battery will trigger overcurrent protection. Use the recommended battery pack value minus some margin. - qcom,soft-vfloat-comp-disabled Set this property when the battery is powered via external source and could go above the float voltage. Loading
drivers/power/qpnp-smbcharger.c +67 −20 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <linux/rtc.h> #include <linux/qpnp/qpnp-adc.h> #include <linux/batterydata-lib.h> #include <linux/msm_bcl.h> /* Mask/Bit helpers */ #define _SMB_MASK(BITS, POS) \ Loading Loading @@ -135,6 +136,7 @@ struct smbchg_chip { /* flash current prediction */ int rpara_uohm; int rslow_uohm; int vled_max_uv; /* vfloat adjustment */ int max_vbat_sample; Loading Loading @@ -2288,14 +2290,20 @@ out: return rc; } static int smbchg_ibat_ocp_threshold_ua = 4500000; module_param(smbchg_ibat_ocp_threshold_ua, int, 0644); #define UCONV 1000000LL #define VIN_FLASH_UV 5500000LL #define FLASH_V_THRESHOLD 3000000LL #define MCONV 1000LL #define FLASH_V_THRESHOLD 3000000 #define FLASH_VDIP_MARGIN 100000 #define VPH_FLASH_VDIP (FLASH_V_THRESHOLD + FLASH_VDIP_MARGIN) #define BUCK_EFFICIENCY 800LL static int smbchg_calc_max_flash_current(struct smbchg_chip *chip) { int ocv_uv, ibat_ua, esr_uohm, rbatt_uohm, rc; int64_t ibat_flash_ua, total_flash_ua, total_flash_power_fw; int ocv_uv, esr_uohm, rbatt_uohm, ibat_now, rc; int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw; int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv; rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv); if (rc) { Loading @@ -2303,30 +2311,59 @@ static int smbchg_calc_max_flash_current(struct smbchg_chip *chip) return 0; } rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_CURRENT_NOW, &ibat_ua); rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_RESISTANCE, &esr_uohm); if (rc) { pr_smb(PR_STATUS, "bms psy does not support current_now\n"); pr_smb(PR_STATUS, "bms psy does not support resistance\n"); return 0; } rc = get_property_from_fg(chip, POWER_SUPPLY_PROP_RESISTANCE, &esr_uohm); rc = msm_bcl_read(BCL_PARAM_CURRENT, &ibat_now); if (rc) { pr_smb(PR_STATUS, "bms psy does not support resistance\n"); pr_smb(PR_STATUS, "BCL current read failed: %d\n", rc); return 0; } rbatt_uohm = esr_uohm + chip->rpara_uohm + chip->rslow_uohm; ibat_flash_ua = (div_s64((ocv_uv - FLASH_V_THRESHOLD) * UCONV, rbatt_uohm)) - ibat_ua; total_flash_power_fw = FLASH_V_THRESHOLD * ibat_flash_ua * BUCK_EFFICIENCY; total_flash_ua = div64_s64(total_flash_power_fw, VIN_FLASH_UV * 1000LL); /* * Calculate the maximum current that can pulled out of the battery * before the battery voltage dips below a safe threshold. */ ibat_safe_ua = div_s64((ocv_uv - VPH_FLASH_VDIP) * UCONV, rbatt_uohm); if (ibat_safe_ua <= smbchg_ibat_ocp_threshold_ua) { /* * If the calculated current is below the OCP threshold, then * use it as the possible flash current. */ ibat_flash_ua = ibat_safe_ua - ibat_now; vph_flash_uv = VPH_FLASH_VDIP; } else { /* * If the calculated current is above the OCP threshold, then * use the ocp threshold instead. * * Any higher current will be tripping the battery OCP. */ ibat_flash_ua = smbchg_ibat_ocp_threshold_ua - ibat_now; vph_flash_uv = ocv_uv - div64_s64((int64_t)rbatt_uohm * smbchg_ibat_ocp_threshold_ua, UCONV); } /* Calculate the input voltage of the flash module. */ vin_flash_uv = max((chip->vled_max_uv + 500000LL), (vph_flash_uv * 1200 / 1000)); /* Calculate the available power for the flash module. */ avail_flash_power_fw = BUCK_EFFICIENCY * vph_flash_uv * ibat_flash_ua; /* * Calculate the available amount of current the flash module can draw * before collapsing the battery. (available power/ flash input voltage) */ avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV); pr_smb(PR_MISC, "ibat_flash=%lld\n, ocv=%d, ibat=%d, rbatt=%d t_flash=%lld\n", ibat_flash_ua, ocv_uv, ibat_ua, rbatt_uohm, total_flash_ua); return (int)total_flash_ua; "avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d\n", avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm); return (int)avail_flash_ua; } #define FCC_CMP_CFG 0xF3 Loading Loading @@ -4749,9 +4786,10 @@ err: return rc; } #define DEFAULT_VLED_MAX_UV 3500000 static int smb_parse_dt(struct smbchg_chip *chip) { int rc = 0; int rc = 0, ocp_thresh = -EINVAL; struct device_node *node = chip->dev->of_node; const char *dc_psy_type, *bpd; Loading @@ -4761,12 +4799,21 @@ static int smb_parse_dt(struct smbchg_chip *chip) } /* read optional u32 properties */ OF_PROP_READ(chip, ocp_thresh, "ibat-ocp-threshold-ua", rc, 1); if (ocp_thresh >= 0) smbchg_ibat_ocp_threshold_ua = ocp_thresh; OF_PROP_READ(chip, chip->iterm_ma, "iterm-ma", rc, 1); OF_PROP_READ(chip, chip->target_fastchg_current_ma, "fastchg-current-ma", rc, 1); OF_PROP_READ(chip, chip->vfloat_mv, "float-voltage-mv", rc, 1); OF_PROP_READ(chip, chip->safety_time, "charging-timeout-mins", rc, 1); OF_PROP_READ(chip, chip->vled_max_uv, "vled-max-uv", rc, 1); if (chip->vled_max_uv < 0) chip->vled_max_uv = DEFAULT_VLED_MAX_UV; OF_PROP_READ(chip, chip->rpara_uohm, "rparasitic-uohm", rc, 1); if (chip->rpara_uohm < 0) chip->rpara_uohm = 0; OF_PROP_READ(chip, chip->prechg_safety_time, "precharging-timeout-mins", rc, 1); OF_PROP_READ(chip, chip->fastchg_current_comp, "fastchg-current-comp", Loading Loading @@ -4874,7 +4921,7 @@ static int smb_parse_dt(struct smbchg_chip *chip) if (rc) chip->bms_psy_name = NULL; /* read the bms power supply name */ /* read the battery power supply name */ rc = of_property_read_string(node, "qcom,battery-psy-name", &chip->battery_psy_name); if (rc) Loading