Loading Documentation/devicetree/bindings/batterydata/batterydata.txt +8 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,14 @@ Profile data node optional properties: size 5. - qcom,therm-center-offset: Specifies the resistor divide ratio between pull-up resistor and the thermistor for GEN4 FG. - qcom,therm-pull-up: Specifies the thermistor pull-up resistor value in KOhms. - qcom,rslow-normal-coeffs: Array of Rslow coefficients that will be applied when the battery temperature is greater than 0 degree Celsius for GEN4 FG. This should be exactly of size 4. - qcom,rslow-low-coeffs: Array of Rslow coefficients that will be applied when the battery temperature is lower than 0 degree Celsius for GEN4 FG. This should be exactly of size 4. - qcom,soc-based-step-chg: A bool property to indicate if the battery will perform SoC (State of Charge) based step charging. If yes, the low and high thresholds defined in Loading drivers/power/supply/power_supply_sysfs.c +3 −0 Original line number Diff line number Diff line Loading @@ -369,6 +369,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(recharge_soc), POWER_SUPPLY_ATTR(hvdcp_opti_allowed), POWER_SUPPLY_ATTR(smb_en_mode), POWER_SUPPLY_ATTR(esr_actual), POWER_SUPPLY_ATTR(esr_nominal), POWER_SUPPLY_ATTR(soh), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ Loading drivers/power/supply/qcom/fg-core.h +7 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ #define DEBUG_BATT_SOC 67 #define BATT_MISS_SOC 50 #define ESR_SOH_SOC 50 #define EMPTY_SOC 0 enum prof_load_status { Loading Loading @@ -165,6 +166,8 @@ enum fg_sram_param_id { FG_SRAM_VOLTAGE_PRED, FG_SRAM_OCV, FG_SRAM_ESR, FG_SRAM_ESR_MDL, FG_SRAM_ESR_ACT, FG_SRAM_RSLOW, FG_SRAM_ALG_FLAGS, FG_SRAM_CC_SOC, Loading Loading @@ -257,6 +260,7 @@ enum wa_flags { PMI8998_V1_REV_WA = BIT(0), PM660_TSMC_OSC_WA = BIT(1), PM8150B_V1_DMA_WA = BIT(2), PM8150B_V1_RSLOW_COMP_WA = BIT(3), }; enum slope_limit_status { Loading Loading @@ -287,6 +291,9 @@ struct fg_batt_props { int fastchg_curr_ma; int *therm_coeffs; int therm_ctr_offset; int therm_pull_up_kohms; int *rslow_normal_coeffs; int *rslow_low_coeffs; }; struct fg_cyc_ctr_data { Loading drivers/power/supply/qcom/fg-reg.h +6 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,12 @@ #define ADC_RR_BATT_ID_LO_BIAS_LSB(chip) (chip->rradc_base + 0x76) #define ADC_RR_BATT_ID_LO_BIAS_MSB(chip) (chip->rradc_base + 0x77) #define ADC_RR_BATT_THERM_BASE_CFG1(chip) (chip->rradc_base + 0x81) #define BATT_THERM_PULL_UP_30K 1 #define BATT_THERM_PULL_UP_100K 2 #define BATT_THERM_PULL_UP_400K 3 #define BATT_THERM_PULL_UP_MASK GENMASK(1, 0) #define ADC_RR_BATT_TEMP_LSB(chip) (chip->rradc_base + 0x88) #define ADC_RR_BATT_TEMP_MSB(chip) (chip->rradc_base + 0x89) #define GEN4_BATT_TEMP_MSB_MASK GENMASK(1, 0) Loading drivers/power/supply/qcom/qpnp-fg-gen4.c +271 −27 Original line number Diff line number Diff line Loading @@ -33,12 +33,13 @@ #define FG_SRAM_LEN 960 #define PROFILE_LEN 416 #define PROFILE_COMP_LEN 208 #define PROFILE_COMP_LEN 24 #define KI_COEFF_SOC_LEVELS 3 #define KI_COEFF_MAX 15564 #define SLOPE_LIMIT_NUM_COEFFS 4 #define SLOPE_LIMIT_COEFF_MAX 31128 #define BATT_THERM_NUM_COEFFS 5 #define RSLOW_NUM_COEFFS 4 /* SRAM address/offset definitions in ascending order */ #define BATT_THERM_CONFIG_WORD 3 Loading Loading @@ -90,6 +91,10 @@ #define VBATT_LOW_OFFSET 1 #define PROFILE_LOAD_WORD 65 #define PROFILE_LOAD_OFFSET 0 #define RSLOW_COEFF_DISCHG_WORD 78 #define RSLOW_COEFF_LOW_OFFSET 0 #define RSLOW_CONFIG_WORD 241 #define RSLOW_CONFIG_OFFSET 0 #define NOM_CAP_WORD 271 #define NOM_CAP_OFFSET 0 #define RCONN_WORD 275 Loading @@ -102,6 +107,10 @@ #define PROFILE_INTEGRITY_OFFSET 0 #define ESR_WORD 331 #define ESR_OFFSET 0 #define ESR_MDL_WORD 335 #define ESR_MDL_OFFSET 0 #define ESR_ACT_WORD 342 #define ESR_ACT_OFFSET 0 #define RSLOW_WORD 368 #define RSLOW_OFFSET 0 #define OCV_WORD 417 Loading Loading @@ -161,8 +170,12 @@ struct fg_gen4_chip { struct ttf *ttf; char batt_profile[PROFILE_LEN]; int recharge_soc_thr; int esr_actual; int esr_nominal; int soh; bool ki_coeff_dischg_en; bool slope_limit_en; bool rslow_low; }; struct bias_config { Loading Loading @@ -200,6 +213,10 @@ static struct fg_sram_param pm8150_sram_params[] = { fg_decode_voltage_15b), PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default, fg_decode_value_16b), PARAM(ESR_MDL, ESR_MDL_WORD, ESR_MDL_OFFSET, 2, 1000, 244141, 0, fg_encode_default, fg_decode_value_16b), PARAM(ESR_ACT, ESR_ACT_WORD, ESR_ACT_OFFSET, 2, 1000, 244141, 0, fg_encode_default, fg_decode_value_16b), PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL, fg_decode_value_16b), PARAM(CC_SOC, CC_SOC_WORD, CC_SOC_OFFSET, 4, 1, 1, 0, NULL, Loading Loading @@ -761,6 +778,67 @@ static int fg_gen4_store_count(void *data, u16 *buf, int id, int length) /* All worker and helper functions below */ static int fg_parse_dt_property_u32_array(struct device_node *node, const char *prop_name, int *buf, int len) { int rc; rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32)); if (rc < 0) { if (rc == -EINVAL) return 0; else return rc; } else if (rc != len) { pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name, rc); return -EINVAL; } rc = of_property_read_u32_array(node, prop_name, buf, len); if (rc < 0) { pr_err("Error in reading %s, rc=%d\n", prop_name, rc); return rc; } return 0; } static void fg_gen4_update_rslow_coeff(struct fg_dev *fg, int batt_temp) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, i; bool rslow_low = false; u8 buf[RSLOW_NUM_COEFFS]; if (!fg->bp.rslow_normal_coeffs || !fg->bp.rslow_low_coeffs) return; /* Update Rslow low coefficients when Tbatt is < 0 C */ if (batt_temp < 0) rslow_low = true; if (chip->rslow_low == rslow_low) return; for (i = 0; i < RSLOW_NUM_COEFFS; i++) { if (rslow_low) buf[i] = fg->bp.rslow_low_coeffs[i] & 0xFF; else buf[i] = fg->bp.rslow_normal_coeffs[i] & 0xFF; } rc = fg_sram_write(fg, RSLOW_COEFF_DISCHG_WORD, RSLOW_COEFF_LOW_OFFSET, buf, RSLOW_NUM_COEFFS, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Failed to write RLOW_COEFF_DISCHG_WORD rc=%d\n", rc); } else { chip->rslow_low = rslow_low; fg_dbg(fg, FG_STATUS, "Updated Rslow %s coefficients\n", rslow_low ? "low" : "normal"); } } #define KI_COEFF_LOW_DISCHG_DEFAULT 428 #define KI_COEFF_MED_DISCHG_DEFAULT 245 #define KI_COEFF_HI_DISCHG_DEFAULT 123 Loading Loading @@ -921,6 +999,59 @@ static int fg_gen4_get_batt_profile(struct fg_dev *fg) } } if (of_find_property(profile_node, "qcom,therm-pull-up", NULL)) { rc = of_property_read_u32(profile_node, "qcom,therm-pull-up", &fg->bp.therm_pull_up_kohms); if (rc < 0) { pr_err("Couldn't read therm-pull-up, rc:%d\n", rc); fg->bp.therm_pull_up_kohms = -EINVAL; } } if (of_find_property(profile_node, "qcom,rslow-normal-coeffs", NULL) && of_find_property(profile_node, "qcom,rslow-low-coeffs", NULL)) { if (!fg->bp.rslow_normal_coeffs) { fg->bp.rslow_normal_coeffs = devm_kcalloc(fg->dev, RSLOW_NUM_COEFFS, sizeof(u32), GFP_KERNEL); if (!fg->bp.rslow_normal_coeffs) return -ENOMEM; } if (!fg->bp.rslow_low_coeffs) { fg->bp.rslow_low_coeffs = devm_kcalloc(fg->dev, RSLOW_NUM_COEFFS, sizeof(u32), GFP_KERNEL); if (!fg->bp.rslow_low_coeffs) { devm_kfree(fg->dev, fg->bp.rslow_normal_coeffs); fg->bp.rslow_normal_coeffs = NULL; return -ENOMEM; } } rc = fg_parse_dt_property_u32_array(profile_node, "qcom,rslow-normal-coeffs", fg->bp.rslow_normal_coeffs, RSLOW_NUM_COEFFS); if (rc < 0) { devm_kfree(fg->dev, fg->bp.rslow_normal_coeffs); fg->bp.rslow_normal_coeffs = NULL; devm_kfree(fg->dev, fg->bp.rslow_low_coeffs); fg->bp.rslow_low_coeffs = NULL; return rc; } rc = fg_parse_dt_property_u32_array(profile_node, "qcom,rslow-low-coeffs", fg->bp.rslow_low_coeffs, RSLOW_NUM_COEFFS); if (rc < 0) { devm_kfree(fg->dev, fg->bp.rslow_normal_coeffs); fg->bp.rslow_normal_coeffs = NULL; devm_kfree(fg->dev, fg->bp.rslow_low_coeffs); fg->bp.rslow_low_coeffs = NULL; return rc; } } data = of_get_property(profile_node, "qcom,fg-profile-data", &len); if (!data) { pr_err("No profile data available\n"); Loading @@ -940,8 +1071,10 @@ static int fg_gen4_get_batt_profile(struct fg_dev *fg) static int fg_gen4_bp_params_config(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, i; u8 buf, therm_coeffs[BATT_THERM_NUM_COEFFS * 2]; u8 rslow_coeffs[RSLOW_NUM_COEFFS]; if (fg->bp.vbatt_full_mv > 0) { rc = fg_set_constant_chg_voltage(fg, Loading Loading @@ -974,6 +1107,53 @@ static int fg_gen4_bp_params_config(struct fg_dev *fg) } } if (fg->bp.rslow_normal_coeffs && fg->bp.rslow_low_coeffs) { rc = fg_sram_read(fg, RSLOW_COEFF_DISCHG_WORD, RSLOW_COEFF_LOW_OFFSET, rslow_coeffs, RSLOW_NUM_COEFFS, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Failed to read RLOW_COEFF_DISCHG_WORD rc=%d\n", rc); return rc; } /* Read Rslow coefficients back and set the status */ for (i = 0; i < RSLOW_NUM_COEFFS; i++) { buf = fg->bp.rslow_low_coeffs[i] & 0xFF; if (rslow_coeffs[i] == buf) { chip->rslow_low = true; } else { chip->rslow_low = false; break; } } fg_dbg(fg, FG_STATUS, "Rslow_low: %d\n", chip->rslow_low); } if (fg->bp.therm_pull_up_kohms > 0) { switch (fg->bp.therm_pull_up_kohms) { case 30: buf = BATT_THERM_PULL_UP_30K; break; case 100: buf = BATT_THERM_PULL_UP_100K; break; case 400: buf = BATT_THERM_PULL_UP_400K; break; default: return -EINVAL; } rc = fg_masked_write(fg, ADC_RR_BATT_THERM_BASE_CFG1(fg), BATT_THERM_PULL_UP_MASK, buf); if (rc < 0) { pr_err("failed to write to 0x%04X, rc=%d\n", ADC_RR_BATT_THERM_BASE_CFG1(fg), rc); return rc; } } return 0; } Loading Loading @@ -1216,6 +1396,53 @@ static void get_batt_psy_props(struct fg_dev *fg) } } static int fg_gen4_esr_soh_update(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, msoc, esr_uohms; if (!fg->soc_reporting_ready || fg->battery_missing) { chip->esr_actual = -EINVAL; chip->esr_nominal = -EINVAL; return 0; } if (fg->charge_status == POWER_SUPPLY_STATUS_CHARGING) { rc = fg_get_msoc(fg, &msoc); if (rc < 0) { pr_err("Error in getting msoc, rc=%d\n", rc); return rc; } if (msoc == ESR_SOH_SOC) { rc = fg_get_sram_prop(fg, FG_SRAM_ESR_ACT, &esr_uohms); if (rc < 0) { pr_err("Error in getting esr_actual, rc=%d\n", rc); return rc; } chip->esr_actual = esr_uohms; rc = fg_get_sram_prop(fg, FG_SRAM_ESR_MDL, &esr_uohms); if (rc < 0) { pr_err("Error in getting esr_nominal, rc=%d\n", rc); chip->esr_actual = -EINVAL; return rc; } chip->esr_nominal = esr_uohms; fg_dbg(fg, FG_STATUS, "esr_actual: %d esr_nominal: %d\n", chip->esr_actual, chip->esr_nominal); if (fg->batt_psy) power_supply_changed(fg->batt_psy); } } return 0; } static int fg_gen4_update_maint_soc(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); Loading Loading @@ -1599,6 +1826,7 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) if (batt_psy_initialized(fg)) power_supply_changed(fg->batt_psy); fg_gen4_update_rslow_coeff(fg, batt_temp); return IRQ_HANDLED; } Loading Loading @@ -1664,6 +1892,10 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) if (rc < 0) pr_err("Error in charge_full_update, rc=%d\n", rc); rc = fg_gen4_esr_soh_update(fg); if (rc < 0) pr_err("Error in updating ESR for SOH, rc=%d\n", rc); rc = fg_gen4_update_maint_soc(fg); if (rc < 0) pr_err("Error in updating maint_soc, rc=%d\n", rc); Loading Loading @@ -2042,6 +2274,12 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_RESISTANCE: rc = fg_get_battery_resistance(fg, &pval->intval); break; case POWER_SUPPLY_PROP_ESR_ACTUAL: pval->intval = chip->esr_actual; break; case POWER_SUPPLY_PROP_ESR_NOMINAL: pval->intval = chip->esr_nominal; break; case POWER_SUPPLY_PROP_VOLTAGE_OCV: rc = fg_get_sram_prop(fg, FG_SRAM_OCV, &pval->intval); break; Loading Loading @@ -2084,6 +2322,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_SOC_REPORTING_READY: pval->intval = fg->soc_reporting_ready; break; case POWER_SUPPLY_PROP_SOH: pval->intval = chip->soh; break; case POWER_SUPPLY_PROP_DEBUG_BATTERY: pval->intval = is_debug_batt_id(fg); break; Loading Loading @@ -2165,6 +2406,15 @@ static int fg_psy_set_property(struct power_supply *psy, return -EINVAL; } break; case POWER_SUPPLY_PROP_ESR_ACTUAL: chip->esr_actual = pval->intval; break; case POWER_SUPPLY_PROP_ESR_NOMINAL: chip->esr_nominal = pval->intval; break; case POWER_SUPPLY_PROP_SOH: chip->soh = pval->intval; break; default: break; } Loading @@ -2179,6 +2429,9 @@ static int fg_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CC_STEP: case POWER_SUPPLY_PROP_CC_STEP_SEL: case POWER_SUPPLY_PROP_ESR_ACTUAL: case POWER_SUPPLY_PROP_ESR_NOMINAL: case POWER_SUPPLY_PROP_SOH: return 1; default: break; Loading @@ -2196,6 +2449,8 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_RESISTANCE_ID, POWER_SUPPLY_PROP_RESISTANCE, POWER_SUPPLY_PROP_ESR_ACTUAL, POWER_SUPPLY_PROP_ESR_NOMINAL, POWER_SUPPLY_PROP_BATTERY_TYPE, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, Loading @@ -2205,6 +2460,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_SOH, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, Loading Loading @@ -2638,35 +2894,21 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) } } rc = restore_cycle_count(chip->counter); if (fg->wa_flags & PM8150B_V1_RSLOW_COMP_WA) { val = 0; mask = BIT(1); rc = fg_sram_masked_write(fg, RSLOW_CONFIG_WORD, RSLOW_CONFIG_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in restoring cycle_count, rc=%d\n", rc); pr_err("Error in writing RSLOW_CONFIG_WORD, rc=%d\n", rc); return rc; } return 0; } static int fg_parse_dt_property_u32_array(struct device_node *node, const char *prop_name, int *buf, int len) { int rc; rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32)); if (rc < 0) { if (rc == -EINVAL) return 0; else return rc; } else if (rc != len) { pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name, rc); return -EINVAL; } rc = of_property_read_u32_array(node, prop_name, buf, len); rc = restore_cycle_count(chip->counter); if (rc < 0) { pr_err("Error in reading %s, rc=%d\n", prop_name, rc); pr_err("Error in restoring cycle_count, rc=%d\n", rc); return rc; } Loading Loading @@ -2833,8 +3075,10 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) fg->version = GEN4_FG; fg->use_dma = true; fg->sp = pm8150_sram_params; if (fg->pmic_rev_id->rev4 == PM8150B_V1P0_REV4) if (fg->pmic_rev_id->rev4 == PM8150B_V1P0_REV4) { fg->wa_flags |= PM8150B_V1_DMA_WA; fg->wa_flags |= PM8150B_V1_RSLOW_COMP_WA; } break; default: return -EINVAL; Loading Loading
Documentation/devicetree/bindings/batterydata/batterydata.txt +8 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,14 @@ Profile data node optional properties: size 5. - qcom,therm-center-offset: Specifies the resistor divide ratio between pull-up resistor and the thermistor for GEN4 FG. - qcom,therm-pull-up: Specifies the thermistor pull-up resistor value in KOhms. - qcom,rslow-normal-coeffs: Array of Rslow coefficients that will be applied when the battery temperature is greater than 0 degree Celsius for GEN4 FG. This should be exactly of size 4. - qcom,rslow-low-coeffs: Array of Rslow coefficients that will be applied when the battery temperature is lower than 0 degree Celsius for GEN4 FG. This should be exactly of size 4. - qcom,soc-based-step-chg: A bool property to indicate if the battery will perform SoC (State of Charge) based step charging. If yes, the low and high thresholds defined in Loading
drivers/power/supply/power_supply_sysfs.c +3 −0 Original line number Diff line number Diff line Loading @@ -369,6 +369,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(recharge_soc), POWER_SUPPLY_ATTR(hvdcp_opti_allowed), POWER_SUPPLY_ATTR(smb_en_mode), POWER_SUPPLY_ATTR(esr_actual), POWER_SUPPLY_ATTR(esr_nominal), POWER_SUPPLY_ATTR(soh), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ Loading
drivers/power/supply/qcom/fg-core.h +7 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ #define DEBUG_BATT_SOC 67 #define BATT_MISS_SOC 50 #define ESR_SOH_SOC 50 #define EMPTY_SOC 0 enum prof_load_status { Loading Loading @@ -165,6 +166,8 @@ enum fg_sram_param_id { FG_SRAM_VOLTAGE_PRED, FG_SRAM_OCV, FG_SRAM_ESR, FG_SRAM_ESR_MDL, FG_SRAM_ESR_ACT, FG_SRAM_RSLOW, FG_SRAM_ALG_FLAGS, FG_SRAM_CC_SOC, Loading Loading @@ -257,6 +260,7 @@ enum wa_flags { PMI8998_V1_REV_WA = BIT(0), PM660_TSMC_OSC_WA = BIT(1), PM8150B_V1_DMA_WA = BIT(2), PM8150B_V1_RSLOW_COMP_WA = BIT(3), }; enum slope_limit_status { Loading Loading @@ -287,6 +291,9 @@ struct fg_batt_props { int fastchg_curr_ma; int *therm_coeffs; int therm_ctr_offset; int therm_pull_up_kohms; int *rslow_normal_coeffs; int *rslow_low_coeffs; }; struct fg_cyc_ctr_data { Loading
drivers/power/supply/qcom/fg-reg.h +6 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,12 @@ #define ADC_RR_BATT_ID_LO_BIAS_LSB(chip) (chip->rradc_base + 0x76) #define ADC_RR_BATT_ID_LO_BIAS_MSB(chip) (chip->rradc_base + 0x77) #define ADC_RR_BATT_THERM_BASE_CFG1(chip) (chip->rradc_base + 0x81) #define BATT_THERM_PULL_UP_30K 1 #define BATT_THERM_PULL_UP_100K 2 #define BATT_THERM_PULL_UP_400K 3 #define BATT_THERM_PULL_UP_MASK GENMASK(1, 0) #define ADC_RR_BATT_TEMP_LSB(chip) (chip->rradc_base + 0x88) #define ADC_RR_BATT_TEMP_MSB(chip) (chip->rradc_base + 0x89) #define GEN4_BATT_TEMP_MSB_MASK GENMASK(1, 0) Loading
drivers/power/supply/qcom/qpnp-fg-gen4.c +271 −27 Original line number Diff line number Diff line Loading @@ -33,12 +33,13 @@ #define FG_SRAM_LEN 960 #define PROFILE_LEN 416 #define PROFILE_COMP_LEN 208 #define PROFILE_COMP_LEN 24 #define KI_COEFF_SOC_LEVELS 3 #define KI_COEFF_MAX 15564 #define SLOPE_LIMIT_NUM_COEFFS 4 #define SLOPE_LIMIT_COEFF_MAX 31128 #define BATT_THERM_NUM_COEFFS 5 #define RSLOW_NUM_COEFFS 4 /* SRAM address/offset definitions in ascending order */ #define BATT_THERM_CONFIG_WORD 3 Loading Loading @@ -90,6 +91,10 @@ #define VBATT_LOW_OFFSET 1 #define PROFILE_LOAD_WORD 65 #define PROFILE_LOAD_OFFSET 0 #define RSLOW_COEFF_DISCHG_WORD 78 #define RSLOW_COEFF_LOW_OFFSET 0 #define RSLOW_CONFIG_WORD 241 #define RSLOW_CONFIG_OFFSET 0 #define NOM_CAP_WORD 271 #define NOM_CAP_OFFSET 0 #define RCONN_WORD 275 Loading @@ -102,6 +107,10 @@ #define PROFILE_INTEGRITY_OFFSET 0 #define ESR_WORD 331 #define ESR_OFFSET 0 #define ESR_MDL_WORD 335 #define ESR_MDL_OFFSET 0 #define ESR_ACT_WORD 342 #define ESR_ACT_OFFSET 0 #define RSLOW_WORD 368 #define RSLOW_OFFSET 0 #define OCV_WORD 417 Loading Loading @@ -161,8 +170,12 @@ struct fg_gen4_chip { struct ttf *ttf; char batt_profile[PROFILE_LEN]; int recharge_soc_thr; int esr_actual; int esr_nominal; int soh; bool ki_coeff_dischg_en; bool slope_limit_en; bool rslow_low; }; struct bias_config { Loading Loading @@ -200,6 +213,10 @@ static struct fg_sram_param pm8150_sram_params[] = { fg_decode_voltage_15b), PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default, fg_decode_value_16b), PARAM(ESR_MDL, ESR_MDL_WORD, ESR_MDL_OFFSET, 2, 1000, 244141, 0, fg_encode_default, fg_decode_value_16b), PARAM(ESR_ACT, ESR_ACT_WORD, ESR_ACT_OFFSET, 2, 1000, 244141, 0, fg_encode_default, fg_decode_value_16b), PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL, fg_decode_value_16b), PARAM(CC_SOC, CC_SOC_WORD, CC_SOC_OFFSET, 4, 1, 1, 0, NULL, Loading Loading @@ -761,6 +778,67 @@ static int fg_gen4_store_count(void *data, u16 *buf, int id, int length) /* All worker and helper functions below */ static int fg_parse_dt_property_u32_array(struct device_node *node, const char *prop_name, int *buf, int len) { int rc; rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32)); if (rc < 0) { if (rc == -EINVAL) return 0; else return rc; } else if (rc != len) { pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name, rc); return -EINVAL; } rc = of_property_read_u32_array(node, prop_name, buf, len); if (rc < 0) { pr_err("Error in reading %s, rc=%d\n", prop_name, rc); return rc; } return 0; } static void fg_gen4_update_rslow_coeff(struct fg_dev *fg, int batt_temp) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, i; bool rslow_low = false; u8 buf[RSLOW_NUM_COEFFS]; if (!fg->bp.rslow_normal_coeffs || !fg->bp.rslow_low_coeffs) return; /* Update Rslow low coefficients when Tbatt is < 0 C */ if (batt_temp < 0) rslow_low = true; if (chip->rslow_low == rslow_low) return; for (i = 0; i < RSLOW_NUM_COEFFS; i++) { if (rslow_low) buf[i] = fg->bp.rslow_low_coeffs[i] & 0xFF; else buf[i] = fg->bp.rslow_normal_coeffs[i] & 0xFF; } rc = fg_sram_write(fg, RSLOW_COEFF_DISCHG_WORD, RSLOW_COEFF_LOW_OFFSET, buf, RSLOW_NUM_COEFFS, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Failed to write RLOW_COEFF_DISCHG_WORD rc=%d\n", rc); } else { chip->rslow_low = rslow_low; fg_dbg(fg, FG_STATUS, "Updated Rslow %s coefficients\n", rslow_low ? "low" : "normal"); } } #define KI_COEFF_LOW_DISCHG_DEFAULT 428 #define KI_COEFF_MED_DISCHG_DEFAULT 245 #define KI_COEFF_HI_DISCHG_DEFAULT 123 Loading Loading @@ -921,6 +999,59 @@ static int fg_gen4_get_batt_profile(struct fg_dev *fg) } } if (of_find_property(profile_node, "qcom,therm-pull-up", NULL)) { rc = of_property_read_u32(profile_node, "qcom,therm-pull-up", &fg->bp.therm_pull_up_kohms); if (rc < 0) { pr_err("Couldn't read therm-pull-up, rc:%d\n", rc); fg->bp.therm_pull_up_kohms = -EINVAL; } } if (of_find_property(profile_node, "qcom,rslow-normal-coeffs", NULL) && of_find_property(profile_node, "qcom,rslow-low-coeffs", NULL)) { if (!fg->bp.rslow_normal_coeffs) { fg->bp.rslow_normal_coeffs = devm_kcalloc(fg->dev, RSLOW_NUM_COEFFS, sizeof(u32), GFP_KERNEL); if (!fg->bp.rslow_normal_coeffs) return -ENOMEM; } if (!fg->bp.rslow_low_coeffs) { fg->bp.rslow_low_coeffs = devm_kcalloc(fg->dev, RSLOW_NUM_COEFFS, sizeof(u32), GFP_KERNEL); if (!fg->bp.rslow_low_coeffs) { devm_kfree(fg->dev, fg->bp.rslow_normal_coeffs); fg->bp.rslow_normal_coeffs = NULL; return -ENOMEM; } } rc = fg_parse_dt_property_u32_array(profile_node, "qcom,rslow-normal-coeffs", fg->bp.rslow_normal_coeffs, RSLOW_NUM_COEFFS); if (rc < 0) { devm_kfree(fg->dev, fg->bp.rslow_normal_coeffs); fg->bp.rslow_normal_coeffs = NULL; devm_kfree(fg->dev, fg->bp.rslow_low_coeffs); fg->bp.rslow_low_coeffs = NULL; return rc; } rc = fg_parse_dt_property_u32_array(profile_node, "qcom,rslow-low-coeffs", fg->bp.rslow_low_coeffs, RSLOW_NUM_COEFFS); if (rc < 0) { devm_kfree(fg->dev, fg->bp.rslow_normal_coeffs); fg->bp.rslow_normal_coeffs = NULL; devm_kfree(fg->dev, fg->bp.rslow_low_coeffs); fg->bp.rslow_low_coeffs = NULL; return rc; } } data = of_get_property(profile_node, "qcom,fg-profile-data", &len); if (!data) { pr_err("No profile data available\n"); Loading @@ -940,8 +1071,10 @@ static int fg_gen4_get_batt_profile(struct fg_dev *fg) static int fg_gen4_bp_params_config(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, i; u8 buf, therm_coeffs[BATT_THERM_NUM_COEFFS * 2]; u8 rslow_coeffs[RSLOW_NUM_COEFFS]; if (fg->bp.vbatt_full_mv > 0) { rc = fg_set_constant_chg_voltage(fg, Loading Loading @@ -974,6 +1107,53 @@ static int fg_gen4_bp_params_config(struct fg_dev *fg) } } if (fg->bp.rslow_normal_coeffs && fg->bp.rslow_low_coeffs) { rc = fg_sram_read(fg, RSLOW_COEFF_DISCHG_WORD, RSLOW_COEFF_LOW_OFFSET, rslow_coeffs, RSLOW_NUM_COEFFS, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Failed to read RLOW_COEFF_DISCHG_WORD rc=%d\n", rc); return rc; } /* Read Rslow coefficients back and set the status */ for (i = 0; i < RSLOW_NUM_COEFFS; i++) { buf = fg->bp.rslow_low_coeffs[i] & 0xFF; if (rslow_coeffs[i] == buf) { chip->rslow_low = true; } else { chip->rslow_low = false; break; } } fg_dbg(fg, FG_STATUS, "Rslow_low: %d\n", chip->rslow_low); } if (fg->bp.therm_pull_up_kohms > 0) { switch (fg->bp.therm_pull_up_kohms) { case 30: buf = BATT_THERM_PULL_UP_30K; break; case 100: buf = BATT_THERM_PULL_UP_100K; break; case 400: buf = BATT_THERM_PULL_UP_400K; break; default: return -EINVAL; } rc = fg_masked_write(fg, ADC_RR_BATT_THERM_BASE_CFG1(fg), BATT_THERM_PULL_UP_MASK, buf); if (rc < 0) { pr_err("failed to write to 0x%04X, rc=%d\n", ADC_RR_BATT_THERM_BASE_CFG1(fg), rc); return rc; } } return 0; } Loading Loading @@ -1216,6 +1396,53 @@ static void get_batt_psy_props(struct fg_dev *fg) } } static int fg_gen4_esr_soh_update(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, msoc, esr_uohms; if (!fg->soc_reporting_ready || fg->battery_missing) { chip->esr_actual = -EINVAL; chip->esr_nominal = -EINVAL; return 0; } if (fg->charge_status == POWER_SUPPLY_STATUS_CHARGING) { rc = fg_get_msoc(fg, &msoc); if (rc < 0) { pr_err("Error in getting msoc, rc=%d\n", rc); return rc; } if (msoc == ESR_SOH_SOC) { rc = fg_get_sram_prop(fg, FG_SRAM_ESR_ACT, &esr_uohms); if (rc < 0) { pr_err("Error in getting esr_actual, rc=%d\n", rc); return rc; } chip->esr_actual = esr_uohms; rc = fg_get_sram_prop(fg, FG_SRAM_ESR_MDL, &esr_uohms); if (rc < 0) { pr_err("Error in getting esr_nominal, rc=%d\n", rc); chip->esr_actual = -EINVAL; return rc; } chip->esr_nominal = esr_uohms; fg_dbg(fg, FG_STATUS, "esr_actual: %d esr_nominal: %d\n", chip->esr_actual, chip->esr_nominal); if (fg->batt_psy) power_supply_changed(fg->batt_psy); } } return 0; } static int fg_gen4_update_maint_soc(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); Loading Loading @@ -1599,6 +1826,7 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) if (batt_psy_initialized(fg)) power_supply_changed(fg->batt_psy); fg_gen4_update_rslow_coeff(fg, batt_temp); return IRQ_HANDLED; } Loading Loading @@ -1664,6 +1892,10 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) if (rc < 0) pr_err("Error in charge_full_update, rc=%d\n", rc); rc = fg_gen4_esr_soh_update(fg); if (rc < 0) pr_err("Error in updating ESR for SOH, rc=%d\n", rc); rc = fg_gen4_update_maint_soc(fg); if (rc < 0) pr_err("Error in updating maint_soc, rc=%d\n", rc); Loading Loading @@ -2042,6 +2274,12 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_RESISTANCE: rc = fg_get_battery_resistance(fg, &pval->intval); break; case POWER_SUPPLY_PROP_ESR_ACTUAL: pval->intval = chip->esr_actual; break; case POWER_SUPPLY_PROP_ESR_NOMINAL: pval->intval = chip->esr_nominal; break; case POWER_SUPPLY_PROP_VOLTAGE_OCV: rc = fg_get_sram_prop(fg, FG_SRAM_OCV, &pval->intval); break; Loading Loading @@ -2084,6 +2322,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_SOC_REPORTING_READY: pval->intval = fg->soc_reporting_ready; break; case POWER_SUPPLY_PROP_SOH: pval->intval = chip->soh; break; case POWER_SUPPLY_PROP_DEBUG_BATTERY: pval->intval = is_debug_batt_id(fg); break; Loading Loading @@ -2165,6 +2406,15 @@ static int fg_psy_set_property(struct power_supply *psy, return -EINVAL; } break; case POWER_SUPPLY_PROP_ESR_ACTUAL: chip->esr_actual = pval->intval; break; case POWER_SUPPLY_PROP_ESR_NOMINAL: chip->esr_nominal = pval->intval; break; case POWER_SUPPLY_PROP_SOH: chip->soh = pval->intval; break; default: break; } Loading @@ -2179,6 +2429,9 @@ static int fg_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CC_STEP: case POWER_SUPPLY_PROP_CC_STEP_SEL: case POWER_SUPPLY_PROP_ESR_ACTUAL: case POWER_SUPPLY_PROP_ESR_NOMINAL: case POWER_SUPPLY_PROP_SOH: return 1; default: break; Loading @@ -2196,6 +2449,8 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_RESISTANCE_ID, POWER_SUPPLY_PROP_RESISTANCE, POWER_SUPPLY_PROP_ESR_ACTUAL, POWER_SUPPLY_PROP_ESR_NOMINAL, POWER_SUPPLY_PROP_BATTERY_TYPE, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, Loading @@ -2205,6 +2460,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_SOH, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, Loading Loading @@ -2638,35 +2894,21 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) } } rc = restore_cycle_count(chip->counter); if (fg->wa_flags & PM8150B_V1_RSLOW_COMP_WA) { val = 0; mask = BIT(1); rc = fg_sram_masked_write(fg, RSLOW_CONFIG_WORD, RSLOW_CONFIG_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in restoring cycle_count, rc=%d\n", rc); pr_err("Error in writing RSLOW_CONFIG_WORD, rc=%d\n", rc); return rc; } return 0; } static int fg_parse_dt_property_u32_array(struct device_node *node, const char *prop_name, int *buf, int len) { int rc; rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32)); if (rc < 0) { if (rc == -EINVAL) return 0; else return rc; } else if (rc != len) { pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name, rc); return -EINVAL; } rc = of_property_read_u32_array(node, prop_name, buf, len); rc = restore_cycle_count(chip->counter); if (rc < 0) { pr_err("Error in reading %s, rc=%d\n", prop_name, rc); pr_err("Error in restoring cycle_count, rc=%d\n", rc); return rc; } Loading Loading @@ -2833,8 +3075,10 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) fg->version = GEN4_FG; fg->use_dma = true; fg->sp = pm8150_sram_params; if (fg->pmic_rev_id->rev4 == PM8150B_V1P0_REV4) if (fg->pmic_rev_id->rev4 == PM8150B_V1P0_REV4) { fg->wa_flags |= PM8150B_V1_DMA_WA; fg->wa_flags |= PM8150B_V1_RSLOW_COMP_WA; } break; default: return -EINVAL; Loading