Loading Documentation/devicetree/bindings/power/qpnp-fg.txt +30 −1 Original line number Diff line number Diff line Loading @@ -220,7 +220,36 @@ Parent node optional properties: - qcom,fg-slope-limit-high-temp-dischg: Same as "qcom,fg-slope-limit-high-temp-chg" except this is when the battery is discharging. - qcom,fg-dischg-voltage-gain-ctrl: A boolean property to specify if the voltage gain needs to be modified during discharging based on monotonic soc. - qcom,fg-dischg-voltage-gain-soc: Array of monotonic SOC threshold values to change the voltage gain settings during discharge. This should be defined in the ascending order and in the range of 0-100. Array limit is set to 3. If qcom,fg-dischg-voltage-gain-ctrl is set, then this property should be specified to apply the gain settings. - qcom,fg-dischg-med-voltage-gain: Array of voltage gain values that needs to be applied to medC voltage gain when the monotonic SOC goes below the SOC threshold specified under qcom,fg-dischg-voltage-gain-soc. Array limit is set to 3. If qcom,fg-dischg-voltage-gain-ctrl is set, then this property should be specified to apply the gain setting. - qcom,fg-dischg-high-voltage-gain: Array of voltage gain values that needs to be applied to highC voltage gain when the monotonic SOC goes below the SOC threshold specified under qcom,fg-dischg-voltage-gain-soc. Array limit is set to 3. If qcom,fg-dischg-voltage-gain-ctrl is set, then this property should be specified to apply the gain setting. qcom,fg-soc node required properties: - reg : offset and length of the PMIC peripheral register map. Loading drivers/power/qpnp-fg.c +185 −0 Original line number Diff line number Diff line Loading @@ -403,6 +403,14 @@ enum slope_limit_status { SLOPE_LIMIT_MAX, }; #define VOLT_GAIN_MAX 3 struct dischg_gain_soc { bool enable; u32 soc[VOLT_GAIN_MAX]; u32 medc_gain[VOLT_GAIN_MAX]; u32 highc_gain[VOLT_GAIN_MAX]; }; #define THERMAL_COEFF_N_BYTES 6 struct fg_chip { struct device *dev; Loading Loading @@ -532,6 +540,10 @@ struct fg_chip { enum slope_limit_status slope_limit_sts; u32 slope_limit_temp; u32 slope_limit_coeffs[SLOPE_LIMIT_MAX]; /* Discharge soc gain */ struct work_struct dischg_gain_work; struct fg_wakeup_source dischg_gain_wakeup_source; struct dischg_gain_soc dischg_gain; }; /* FG_MEMIF DEBUGFS structures */ Loading Loading @@ -3541,6 +3553,11 @@ static void status_change_work(struct work_struct *work) msecs_to_jiffies(0)); } if (chip->dischg_gain.enable) { fg_stay_awake(&chip->dischg_gain_wakeup_source); schedule_work(&chip->dischg_gain_work); } get_current_time(¤t_time); /* * When charging status changes, update SRAM parameters if it Loading Loading @@ -4115,6 +4132,11 @@ static irqreturn_t fg_soc_irq_handler(int irq, void *_chip) if (fg_debug_mask & FG_IRQS) pr_info("triggered 0x%x\n", soc_rt_sts); if (chip->dischg_gain.enable) { fg_stay_awake(&chip->dischg_gain_wakeup_source); schedule_work(&chip->dischg_gain_work); } if (chip->soc_slope_limiter_en) { fg_stay_awake(&chip->slope_limit_wakeup_source); schedule_work(&chip->slope_limiter_work); Loading Loading @@ -4766,6 +4788,58 @@ static void esr_extract_config_work(struct work_struct *work) fg_relax(&chip->esr_extract_wakeup_source); } #define KI_COEFF_MEDC_REG 0x400 #define KI_COEFF_MEDC_OFFSET 0 #define KI_COEFF_HIGHC_REG 0x404 #define KI_COEFF_HIGHC_OFFSET 0 #define DEFAULT_MEDC_VOLTAGE_GAIN 3 #define DEFAULT_HIGHC_VOLTAGE_GAIN 2 static void discharge_gain_work(struct work_struct *work) { struct fg_chip *chip = container_of(work, struct fg_chip, dischg_gain_work); u8 buf[2]; int capacity, rc, i; int64_t medc_val = DEFAULT_MEDC_VOLTAGE_GAIN; int64_t highc_val = DEFAULT_HIGHC_VOLTAGE_GAIN; capacity = get_prop_capacity(chip); if (chip->status == POWER_SUPPLY_STATUS_DISCHARGING) { for (i = VOLT_GAIN_MAX - 1; i >= 0; i--) { if (capacity <= chip->dischg_gain.soc[i]) { medc_val = chip->dischg_gain.medc_gain[i]; highc_val = chip->dischg_gain.highc_gain[i]; } } } if (fg_debug_mask & FG_STATUS) pr_info("Capacity: %d, medc_gain: %lld highc_gain: %lld\n", capacity, medc_val, highc_val); medc_val *= MICRO_UNIT; half_float_to_buffer(medc_val, buf); rc = fg_mem_write(chip, buf, KI_COEFF_MEDC_REG, 2, KI_COEFF_MEDC_OFFSET, 0); if (rc) pr_err("Couldn't write to ki_coeff_medc_reg, rc=%d\n", rc); else if (fg_debug_mask & FG_STATUS) pr_info("Value [%x %x] written to ki_coeff_medc\n", buf[0], buf[1]); highc_val *= MICRO_UNIT; half_float_to_buffer(highc_val, buf); rc = fg_mem_write(chip, buf, KI_COEFF_HIGHC_REG, 2, KI_COEFF_HIGHC_OFFSET, 0); if (rc) pr_err("Couldn't write to ki_coeff_highc_reg, rc=%d\n", rc); else if (fg_debug_mask & FG_STATUS) pr_info("Value [%x %x] written to ki_coeff_highc\n", buf[0], buf[1]); fg_relax(&chip->dischg_gain_wakeup_source); } #define LOW_LATENCY BIT(6) #define BATT_PROFILE_OFFSET 0x4C0 #define PROFILE_INTEGRITY_REG 0x53C Loading Loading @@ -5578,6 +5652,99 @@ do { \ } \ } while (0) static int fg_dischg_gain_dt_init(struct fg_chip *chip) { struct device_node *node = chip->spmi->dev.of_node; struct property *prop; int i, rc = 0; size_t size; prop = of_find_property(node, "qcom,fg-dischg-voltage-gain-soc", NULL); if (!prop) { pr_err("qcom-fg-dischg-voltage-gain-soc not specified\n"); goto out; } size = prop->length / sizeof(u32); if (size != VOLT_GAIN_MAX) { pr_err("Voltage gain SOC specified is of incorrect size\n"); goto out; } rc = of_property_read_u32_array(node, "qcom,fg-dischg-voltage-gain-soc", chip->dischg_gain.soc, size); if (rc < 0) { pr_err("Reading qcom-fg-dischg-voltage-gain-soc failed, rc=%d\n", rc); goto out; } for (i = 0; i < VOLT_GAIN_MAX; i++) { if (chip->dischg_gain.soc[i] < 0 || chip->dischg_gain.soc[i] > 100) { pr_err("Incorrect dischg-voltage-gain-soc\n"); goto out; } } prop = of_find_property(node, "qcom,fg-dischg-med-voltage-gain", NULL); if (!prop) { pr_err("qcom-fg-dischg-med-voltage-gain not specified\n"); goto out; } size = prop->length / sizeof(u32); if (size != VOLT_GAIN_MAX) { pr_err("med-voltage-gain specified is of incorrect size\n"); goto out; } rc = of_property_read_u32_array(node, "qcom,fg-dischg-med-voltage-gain", chip->dischg_gain.medc_gain, size); if (rc < 0) { pr_err("Reading qcom-fg-dischg-med-voltage-gain failed, rc=%d\n", rc); goto out; } prop = of_find_property(node, "qcom,fg-dischg-high-voltage-gain", NULL); if (!prop) { pr_err("qcom-fg-dischg-high-voltage-gain not specified\n"); goto out; } size = prop->length / sizeof(u32); if (size != VOLT_GAIN_MAX) { pr_err("high-voltage-gain specified is of incorrect size\n"); goto out; } rc = of_property_read_u32_array(node, "qcom,fg-dischg-high-voltage-gain", chip->dischg_gain.highc_gain, size); if (rc < 0) { pr_err("Reading qcom-fg-dischg-high-voltage-gain failed, rc=%d\n", rc); goto out; } if (fg_debug_mask & FG_STATUS) { for (i = 0; i < VOLT_GAIN_MAX; i++) pr_info("SOC:%d MedC_Gain:%d HighC_Gain: %d\n", chip->dischg_gain.soc[i], chip->dischg_gain.medc_gain[i], chip->dischg_gain.highc_gain[i]); } return 0; out: chip->dischg_gain.enable = false; return rc; } #define DEFAULT_EVALUATION_CURRENT_MA 1000 static int fg_of_init(struct fg_chip *chip) { Loading Loading @@ -5754,6 +5921,17 @@ static int fg_of_init(struct fg_chip *chip) OF_READ_PROPERTY(chip->rconn_mohm, "fg-rconn-mohm", rc, 0); chip->dischg_gain.enable = of_property_read_bool(node, "qcom,fg-dischg-voltage-gain-ctrl"); if (chip->dischg_gain.enable) { rc = fg_dischg_gain_dt_init(chip); if (rc) { pr_err("Error in reading dischg_gain parameters, rc=%d\n", rc); rc = 0; } } return rc; } Loading Loading @@ -5955,6 +6133,7 @@ static void fg_cleanup(struct fg_chip *chip) cancel_work_sync(&chip->charge_full_work); cancel_work_sync(&chip->esr_extract_config_work); cancel_work_sync(&chip->slope_limiter_work); cancel_work_sync(&chip->dischg_gain_work); power_supply_unregister(&chip->bms_psy); mutex_destroy(&chip->rslow_comp.lock); mutex_destroy(&chip->rw_lock); Loading @@ -5971,6 +6150,7 @@ static void fg_cleanup(struct fg_chip *chip) wakeup_source_trash(&chip->capacity_learning_wakeup_source.source); wakeup_source_trash(&chip->esr_extract_wakeup_source.source); wakeup_source_trash(&chip->slope_limit_wakeup_source.source); wakeup_source_trash(&chip->dischg_gain_wakeup_source.source); } static int fg_remove(struct spmi_device *spmi) Loading Loading @@ -6949,6 +7129,8 @@ static int fg_probe(struct spmi_device *spmi) "qpnp_fg_esr_extract"); wakeup_source_init(&chip->slope_limit_wakeup_source.source, "qpnp_fg_slope_limit"); wakeup_source_init(&chip->dischg_gain_wakeup_source.source, "qpnp_fg_dischg_gain"); mutex_init(&chip->rw_lock); mutex_init(&chip->cyc_ctr.lock); mutex_init(&chip->learning_data.learning_lock); Loading @@ -6974,6 +7156,7 @@ static int fg_probe(struct spmi_device *spmi) INIT_WORK(&chip->bcl_hi_power_work, bcl_hi_power_work); INIT_WORK(&chip->esr_extract_config_work, esr_extract_config_work); INIT_WORK(&chip->slope_limiter_work, slope_limiter_work); INIT_WORK(&chip->dischg_gain_work, discharge_gain_work); alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME, fg_cap_learning_alarm_cb); init_completion(&chip->sram_access_granted); Loading Loading @@ -7144,6 +7327,7 @@ cancel_work: cancel_work_sync(&chip->bcl_hi_power_work); cancel_work_sync(&chip->esr_extract_config_work); cancel_work_sync(&chip->slope_limiter_work); cancel_work_sync(&chip->dischg_gain_work); of_init_fail: mutex_destroy(&chip->rslow_comp.lock); mutex_destroy(&chip->rw_lock); Loading @@ -7160,6 +7344,7 @@ of_init_fail: wakeup_source_trash(&chip->capacity_learning_wakeup_source.source); wakeup_source_trash(&chip->esr_extract_wakeup_source.source); wakeup_source_trash(&chip->slope_limit_wakeup_source.source); wakeup_source_trash(&chip->dischg_gain_wakeup_source.source); return rc; } Loading Loading
Documentation/devicetree/bindings/power/qpnp-fg.txt +30 −1 Original line number Diff line number Diff line Loading @@ -220,7 +220,36 @@ Parent node optional properties: - qcom,fg-slope-limit-high-temp-dischg: Same as "qcom,fg-slope-limit-high-temp-chg" except this is when the battery is discharging. - qcom,fg-dischg-voltage-gain-ctrl: A boolean property to specify if the voltage gain needs to be modified during discharging based on monotonic soc. - qcom,fg-dischg-voltage-gain-soc: Array of monotonic SOC threshold values to change the voltage gain settings during discharge. This should be defined in the ascending order and in the range of 0-100. Array limit is set to 3. If qcom,fg-dischg-voltage-gain-ctrl is set, then this property should be specified to apply the gain settings. - qcom,fg-dischg-med-voltage-gain: Array of voltage gain values that needs to be applied to medC voltage gain when the monotonic SOC goes below the SOC threshold specified under qcom,fg-dischg-voltage-gain-soc. Array limit is set to 3. If qcom,fg-dischg-voltage-gain-ctrl is set, then this property should be specified to apply the gain setting. - qcom,fg-dischg-high-voltage-gain: Array of voltage gain values that needs to be applied to highC voltage gain when the monotonic SOC goes below the SOC threshold specified under qcom,fg-dischg-voltage-gain-soc. Array limit is set to 3. If qcom,fg-dischg-voltage-gain-ctrl is set, then this property should be specified to apply the gain setting. qcom,fg-soc node required properties: - reg : offset and length of the PMIC peripheral register map. Loading
drivers/power/qpnp-fg.c +185 −0 Original line number Diff line number Diff line Loading @@ -403,6 +403,14 @@ enum slope_limit_status { SLOPE_LIMIT_MAX, }; #define VOLT_GAIN_MAX 3 struct dischg_gain_soc { bool enable; u32 soc[VOLT_GAIN_MAX]; u32 medc_gain[VOLT_GAIN_MAX]; u32 highc_gain[VOLT_GAIN_MAX]; }; #define THERMAL_COEFF_N_BYTES 6 struct fg_chip { struct device *dev; Loading Loading @@ -532,6 +540,10 @@ struct fg_chip { enum slope_limit_status slope_limit_sts; u32 slope_limit_temp; u32 slope_limit_coeffs[SLOPE_LIMIT_MAX]; /* Discharge soc gain */ struct work_struct dischg_gain_work; struct fg_wakeup_source dischg_gain_wakeup_source; struct dischg_gain_soc dischg_gain; }; /* FG_MEMIF DEBUGFS structures */ Loading Loading @@ -3541,6 +3553,11 @@ static void status_change_work(struct work_struct *work) msecs_to_jiffies(0)); } if (chip->dischg_gain.enable) { fg_stay_awake(&chip->dischg_gain_wakeup_source); schedule_work(&chip->dischg_gain_work); } get_current_time(¤t_time); /* * When charging status changes, update SRAM parameters if it Loading Loading @@ -4115,6 +4132,11 @@ static irqreturn_t fg_soc_irq_handler(int irq, void *_chip) if (fg_debug_mask & FG_IRQS) pr_info("triggered 0x%x\n", soc_rt_sts); if (chip->dischg_gain.enable) { fg_stay_awake(&chip->dischg_gain_wakeup_source); schedule_work(&chip->dischg_gain_work); } if (chip->soc_slope_limiter_en) { fg_stay_awake(&chip->slope_limit_wakeup_source); schedule_work(&chip->slope_limiter_work); Loading Loading @@ -4766,6 +4788,58 @@ static void esr_extract_config_work(struct work_struct *work) fg_relax(&chip->esr_extract_wakeup_source); } #define KI_COEFF_MEDC_REG 0x400 #define KI_COEFF_MEDC_OFFSET 0 #define KI_COEFF_HIGHC_REG 0x404 #define KI_COEFF_HIGHC_OFFSET 0 #define DEFAULT_MEDC_VOLTAGE_GAIN 3 #define DEFAULT_HIGHC_VOLTAGE_GAIN 2 static void discharge_gain_work(struct work_struct *work) { struct fg_chip *chip = container_of(work, struct fg_chip, dischg_gain_work); u8 buf[2]; int capacity, rc, i; int64_t medc_val = DEFAULT_MEDC_VOLTAGE_GAIN; int64_t highc_val = DEFAULT_HIGHC_VOLTAGE_GAIN; capacity = get_prop_capacity(chip); if (chip->status == POWER_SUPPLY_STATUS_DISCHARGING) { for (i = VOLT_GAIN_MAX - 1; i >= 0; i--) { if (capacity <= chip->dischg_gain.soc[i]) { medc_val = chip->dischg_gain.medc_gain[i]; highc_val = chip->dischg_gain.highc_gain[i]; } } } if (fg_debug_mask & FG_STATUS) pr_info("Capacity: %d, medc_gain: %lld highc_gain: %lld\n", capacity, medc_val, highc_val); medc_val *= MICRO_UNIT; half_float_to_buffer(medc_val, buf); rc = fg_mem_write(chip, buf, KI_COEFF_MEDC_REG, 2, KI_COEFF_MEDC_OFFSET, 0); if (rc) pr_err("Couldn't write to ki_coeff_medc_reg, rc=%d\n", rc); else if (fg_debug_mask & FG_STATUS) pr_info("Value [%x %x] written to ki_coeff_medc\n", buf[0], buf[1]); highc_val *= MICRO_UNIT; half_float_to_buffer(highc_val, buf); rc = fg_mem_write(chip, buf, KI_COEFF_HIGHC_REG, 2, KI_COEFF_HIGHC_OFFSET, 0); if (rc) pr_err("Couldn't write to ki_coeff_highc_reg, rc=%d\n", rc); else if (fg_debug_mask & FG_STATUS) pr_info("Value [%x %x] written to ki_coeff_highc\n", buf[0], buf[1]); fg_relax(&chip->dischg_gain_wakeup_source); } #define LOW_LATENCY BIT(6) #define BATT_PROFILE_OFFSET 0x4C0 #define PROFILE_INTEGRITY_REG 0x53C Loading Loading @@ -5578,6 +5652,99 @@ do { \ } \ } while (0) static int fg_dischg_gain_dt_init(struct fg_chip *chip) { struct device_node *node = chip->spmi->dev.of_node; struct property *prop; int i, rc = 0; size_t size; prop = of_find_property(node, "qcom,fg-dischg-voltage-gain-soc", NULL); if (!prop) { pr_err("qcom-fg-dischg-voltage-gain-soc not specified\n"); goto out; } size = prop->length / sizeof(u32); if (size != VOLT_GAIN_MAX) { pr_err("Voltage gain SOC specified is of incorrect size\n"); goto out; } rc = of_property_read_u32_array(node, "qcom,fg-dischg-voltage-gain-soc", chip->dischg_gain.soc, size); if (rc < 0) { pr_err("Reading qcom-fg-dischg-voltage-gain-soc failed, rc=%d\n", rc); goto out; } for (i = 0; i < VOLT_GAIN_MAX; i++) { if (chip->dischg_gain.soc[i] < 0 || chip->dischg_gain.soc[i] > 100) { pr_err("Incorrect dischg-voltage-gain-soc\n"); goto out; } } prop = of_find_property(node, "qcom,fg-dischg-med-voltage-gain", NULL); if (!prop) { pr_err("qcom-fg-dischg-med-voltage-gain not specified\n"); goto out; } size = prop->length / sizeof(u32); if (size != VOLT_GAIN_MAX) { pr_err("med-voltage-gain specified is of incorrect size\n"); goto out; } rc = of_property_read_u32_array(node, "qcom,fg-dischg-med-voltage-gain", chip->dischg_gain.medc_gain, size); if (rc < 0) { pr_err("Reading qcom-fg-dischg-med-voltage-gain failed, rc=%d\n", rc); goto out; } prop = of_find_property(node, "qcom,fg-dischg-high-voltage-gain", NULL); if (!prop) { pr_err("qcom-fg-dischg-high-voltage-gain not specified\n"); goto out; } size = prop->length / sizeof(u32); if (size != VOLT_GAIN_MAX) { pr_err("high-voltage-gain specified is of incorrect size\n"); goto out; } rc = of_property_read_u32_array(node, "qcom,fg-dischg-high-voltage-gain", chip->dischg_gain.highc_gain, size); if (rc < 0) { pr_err("Reading qcom-fg-dischg-high-voltage-gain failed, rc=%d\n", rc); goto out; } if (fg_debug_mask & FG_STATUS) { for (i = 0; i < VOLT_GAIN_MAX; i++) pr_info("SOC:%d MedC_Gain:%d HighC_Gain: %d\n", chip->dischg_gain.soc[i], chip->dischg_gain.medc_gain[i], chip->dischg_gain.highc_gain[i]); } return 0; out: chip->dischg_gain.enable = false; return rc; } #define DEFAULT_EVALUATION_CURRENT_MA 1000 static int fg_of_init(struct fg_chip *chip) { Loading Loading @@ -5754,6 +5921,17 @@ static int fg_of_init(struct fg_chip *chip) OF_READ_PROPERTY(chip->rconn_mohm, "fg-rconn-mohm", rc, 0); chip->dischg_gain.enable = of_property_read_bool(node, "qcom,fg-dischg-voltage-gain-ctrl"); if (chip->dischg_gain.enable) { rc = fg_dischg_gain_dt_init(chip); if (rc) { pr_err("Error in reading dischg_gain parameters, rc=%d\n", rc); rc = 0; } } return rc; } Loading Loading @@ -5955,6 +6133,7 @@ static void fg_cleanup(struct fg_chip *chip) cancel_work_sync(&chip->charge_full_work); cancel_work_sync(&chip->esr_extract_config_work); cancel_work_sync(&chip->slope_limiter_work); cancel_work_sync(&chip->dischg_gain_work); power_supply_unregister(&chip->bms_psy); mutex_destroy(&chip->rslow_comp.lock); mutex_destroy(&chip->rw_lock); Loading @@ -5971,6 +6150,7 @@ static void fg_cleanup(struct fg_chip *chip) wakeup_source_trash(&chip->capacity_learning_wakeup_source.source); wakeup_source_trash(&chip->esr_extract_wakeup_source.source); wakeup_source_trash(&chip->slope_limit_wakeup_source.source); wakeup_source_trash(&chip->dischg_gain_wakeup_source.source); } static int fg_remove(struct spmi_device *spmi) Loading Loading @@ -6949,6 +7129,8 @@ static int fg_probe(struct spmi_device *spmi) "qpnp_fg_esr_extract"); wakeup_source_init(&chip->slope_limit_wakeup_source.source, "qpnp_fg_slope_limit"); wakeup_source_init(&chip->dischg_gain_wakeup_source.source, "qpnp_fg_dischg_gain"); mutex_init(&chip->rw_lock); mutex_init(&chip->cyc_ctr.lock); mutex_init(&chip->learning_data.learning_lock); Loading @@ -6974,6 +7156,7 @@ static int fg_probe(struct spmi_device *spmi) INIT_WORK(&chip->bcl_hi_power_work, bcl_hi_power_work); INIT_WORK(&chip->esr_extract_config_work, esr_extract_config_work); INIT_WORK(&chip->slope_limiter_work, slope_limiter_work); INIT_WORK(&chip->dischg_gain_work, discharge_gain_work); alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME, fg_cap_learning_alarm_cb); init_completion(&chip->sram_access_granted); Loading Loading @@ -7144,6 +7327,7 @@ cancel_work: cancel_work_sync(&chip->bcl_hi_power_work); cancel_work_sync(&chip->esr_extract_config_work); cancel_work_sync(&chip->slope_limiter_work); cancel_work_sync(&chip->dischg_gain_work); of_init_fail: mutex_destroy(&chip->rslow_comp.lock); mutex_destroy(&chip->rw_lock); Loading @@ -7160,6 +7344,7 @@ of_init_fail: wakeup_source_trash(&chip->capacity_learning_wakeup_source.source); wakeup_source_trash(&chip->esr_extract_wakeup_source.source); wakeup_source_trash(&chip->slope_limit_wakeup_source.source); wakeup_source_trash(&chip->dischg_gain_wakeup_source.source); return rc; } Loading