Loading Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +20 −11 Original line number Diff line number Diff line Loading @@ -99,10 +99,10 @@ First Level Node - FG Gen3 device - qcom,fg-delta-soc-thr Usage: optional Value type: <u32> Definition: Percentage of monotonic SOC increase upon which the delta SOC interrupt will be triggered. If this property is not specified, then the default value will be 1. Possible values are in the range of 0 to 12. Definition: Percentage of SOC increase upon which the delta monotonic & battery SOC interrupts will be triggered. If this property is not specified, then the default value will be 1. Possible values are in the range of 0 to 12. - qcom,fg-recharge-soc-thr Usage: optional Loading Loading @@ -156,12 +156,12 @@ First Level Node - FG Gen3 device - qcom,cycle-counter-en Usage: optional Value type: <bool> Value type: <empty> Definition: Enables the cycle counter feature. - qcom,fg-force-load-profile Usage: optional Value type: <bool> Value type: <empty> Definition: If set, battery profile will be force loaded if the profile loaded earlier by bootloader doesn't match with the profile available in the device tree. Loading Loading @@ -229,13 +229,13 @@ First Level Node - FG Gen3 device Definition: Battery temperature delta interrupt threshold. Possible values are: 2, 4, 6 and 10. Unit is in Kelvin. - qcom,hold-soc-while-full: - qcom,hold-soc-while-full Usage: optional Value type: <bool> Value type: <empty> Definition: A boolean property that when defined holds SOC at 100% when the battery is full. - qcom,ki-coeff-soc-dischg: - qcom,ki-coeff-soc-dischg Usage: optional Value type: <prop-encoded-array> Definition: Array of monotonic SOC threshold values to change the ki Loading @@ -243,7 +243,7 @@ First Level Node - FG Gen3 device This should be defined in the ascending order and in the range of 0-100. Array limit is set to 3. - qcom,ki-coeff-med-dischg: - qcom,ki-coeff-med-dischg Usage: optional Value type: <prop-encoded-array> Definition: Array of ki coefficient values for medium discharge current Loading @@ -254,7 +254,7 @@ First Level Node - FG Gen3 device is specified to make it fully functional. Value has no unit. Allowed range is 0 to 62200 in micro units. - qcom,ki-coeff-hi-dischg: - qcom,ki-coeff-hi-dischg Usage: optional Value type: <prop-encoded-array> Definition: Array of ki coefficient values for high discharge current Loading Loading @@ -311,6 +311,15 @@ First Level Node - FG Gen3 device 148438 (14.84 %) will be used. Lowest possible value is 1954 (0.19 %). - qcom,fg-auto-recharge-soc Usage: optional Value type: <empty> Definition: A boolean property when defined will configure automatic recharge SOC threshold. If not specified, automatic recharge voltage threshold will be configured. This has to be configured in conjunction with the charger side configuration for proper functionality. ========================================================== Second Level Nodes - Peripherals managed by FG Gen3 driver ========================================================== Loading arch/arm/boot/dts/qcom/msm-pm660.dtsi +4 −2 Original line number Diff line number Diff line Loading @@ -518,8 +518,10 @@ reg = <0x4000 0x100>; interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x2 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x3 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x2 IRQ_TYPE_EDGE_RISING>, <0x0 0x40 0x3 IRQ_TYPE_EDGE_RISING>, <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x5 IRQ_TYPE_EDGE_RISING>, Loading arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +4 −2 Original line number Diff line number Diff line Loading @@ -333,8 +333,10 @@ reg = <0x4000 0x100>; interrupts = <0x2 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x2 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x3 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x2 IRQ_TYPE_EDGE_RISING>, <0x2 0x40 0x3 IRQ_TYPE_EDGE_RISING>, <0x2 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x5 IRQ_TYPE_EDGE_RISING>, Loading drivers/power/supply/qcom/fg-core.h +4 −1 Original line number Diff line number Diff line Loading @@ -156,7 +156,8 @@ enum fg_sram_param_id { FG_SRAM_ESR_TIMER_CHG_INIT, FG_SRAM_SYS_TERM_CURR, FG_SRAM_CHG_TERM_CURR, FG_SRAM_DELTA_SOC_THR, FG_SRAM_DELTA_MSOC_THR, FG_SRAM_DELTA_BSOC_THR, FG_SRAM_RECHARGE_SOC_THR, FG_SRAM_RECHARGE_VBATT_THR, FG_SRAM_KI_COEFF_MED_DISCHG, Loading Loading @@ -205,6 +206,7 @@ enum wa_flags { struct fg_dt_props { bool force_load_profile; bool hold_soc_while_full; bool auto_recharge_soc; int cutoff_volt_mv; int empty_volt_mv; int vbatt_low_thr_mv; Loading Loading @@ -345,6 +347,7 @@ struct fg_chip { bool esr_fcc_ctrl_en; bool soc_reporting_ready; bool esr_flt_cold_temp_en; bool bsoc_delta_irq_en; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; Loading drivers/power/supply/qcom/qpnp-fg-gen3.c +165 −42 Original line number Diff line number Diff line Loading @@ -48,8 +48,10 @@ #define KI_COEFF_HI_DISCHG_OFFSET 0 #define KI_COEFF_LOW_DISCHG_WORD 10 #define KI_COEFF_LOW_DISCHG_OFFSET 2 #define DELTA_SOC_THR_WORD 12 #define DELTA_SOC_THR_OFFSET 3 #define DELTA_MSOC_THR_WORD 12 #define DELTA_MSOC_THR_OFFSET 3 #define DELTA_BSOC_THR_WORD 13 #define DELTA_BSOC_THR_OFFSET 2 #define RECHARGE_SOC_THR_WORD 14 #define RECHARGE_SOC_THR_OFFSET 0 #define CHG_TERM_CURR_WORD 14 Loading Loading @@ -113,8 +115,10 @@ #define KI_COEFF_MED_DISCHG_v2_OFFSET 0 #define KI_COEFF_HI_DISCHG_v2_WORD 10 #define KI_COEFF_HI_DISCHG_v2_OFFSET 1 #define DELTA_SOC_THR_v2_WORD 13 #define DELTA_SOC_THR_v2_OFFSET 0 #define DELTA_BSOC_THR_v2_WORD 12 #define DELTA_BSOC_THR_v2_OFFSET 3 #define DELTA_MSOC_THR_v2_WORD 13 #define DELTA_MSOC_THR_v2_OFFSET 0 #define RECHARGE_SOC_THR_v2_WORD 14 #define RECHARGE_SOC_THR_v2_OFFSET 1 #define CHG_TERM_CURR_v2_WORD 15 Loading Loading @@ -143,6 +147,8 @@ static void fg_encode_current(struct fg_sram_param *sp, static void fg_encode_default(struct fg_sram_param *sp, enum fg_sram_param_id id, int val, u8 *buf); static struct fg_irq_info fg_irqs[FG_IRQ_MAX]; #define PARAM(_id, _addr_word, _addr_byte, _len, _num, _den, _offset, \ _enc, _dec) \ [FG_SRAM_##_id] = { \ Loading Loading @@ -188,8 +194,10 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = { 1000000, 122070, 0, fg_encode_current, NULL), PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1, 100000, 390625, 0, fg_encode_current, NULL), PARAM(DELTA_SOC_THR, DELTA_SOC_THR_WORD, DELTA_SOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET, 1, 256, 100, 0, fg_encode_default, NULL), PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD, Loading Loading @@ -248,8 +256,10 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = { 1000000, 122070, 0, fg_encode_current, NULL), PARAM(CHG_TERM_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_CURR_v2_OFFSET, 1, 100000, 390625, 0, fg_encode_current, NULL), PARAM(DELTA_SOC_THR, DELTA_SOC_THR_v2_WORD, DELTA_SOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD, RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default, NULL), Loading Loading @@ -773,6 +783,7 @@ static bool is_debug_batt_id(struct fg_chip *chip) #define FULL_CAPACITY 100 #define FULL_SOC_RAW 255 #define DEBUG_BATT_SOC 67 #define BATT_MISS_SOC 50 #define EMPTY_SOC 0 static int fg_get_prop_capacity(struct fg_chip *chip, int *val) { Loading @@ -783,6 +794,16 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val) return 0; } if (chip->fg_restarting) { *val = chip->last_soc; return 0; } if (chip->battery_missing) { *val = BATT_MISS_SOC; return 0; } if (is_batt_empty(chip)) { *val = EMPTY_SOC; return 0; Loading Loading @@ -1386,6 +1407,36 @@ static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip) return 0; } static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv) { u8 buf; int rc; if (chip->dt.auto_recharge_soc) return 0; /* This configuration is available only for pmicobalt v2.0 and above */ if (chip->wa_flags & PMI8998_V1_REV_WA) return 0; fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n", voltage_mv); fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte, &buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing recharge_vbatt_thr, rc=%d\n", rc); return rc; } return 0; } #define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700 static int fg_charge_full_update(struct fg_chip *chip) { union power_supply_propval prop = {0, }; Loading @@ -1398,6 +1449,16 @@ static int fg_charge_full_update(struct fg_chip *chip) if (!batt_psy_initialized(chip)) return 0; if (!chip->charge_done && chip->bsoc_delta_irq_en) { disable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq); disable_irq_nosync(fg_irqs[BSOC_DELTA_IRQ].irq); chip->bsoc_delta_irq_en = false; } else if (chip->charge_done && !chip->bsoc_delta_irq_en) { enable_irq(fg_irqs[BSOC_DELTA_IRQ].irq); enable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq); chip->bsoc_delta_irq_en = true; } rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &prop); if (rc < 0) { Loading @@ -1423,18 +1484,46 @@ static int fg_charge_full_update(struct fg_chip *chip) return rc; } fg_dbg(chip, FG_STATUS, "msoc: %d health: %d status: %d\n", msoc, chip->health, chip->charge_status); if (chip->charge_done) { if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n", msoc, bsoc, chip->health, chip->charge_status, chip->charge_full); if (chip->charge_done && !chip->charge_full) { if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) { fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n"); chip->charge_full = true; else /* * Lower the recharge voltage so that VBAT_LT_RECHG * signal will not be asserted soon. */ rc = fg_set_recharge_voltage(chip, AUTO_RECHG_VOLT_LOW_LIMIT_MV); if (rc < 0) { pr_err("Error in reducing recharge voltage, rc=%d\n", rc); return rc; } } else { fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n", msoc); } else if ((bsoc >> 8) <= recharge_soc) { } } else if ((bsoc >> 8) <= recharge_soc && chip->charge_full) { fg_dbg(chip, FG_STATUS, "bsoc: %d recharge_soc: %d\n", bsoc >> 8, recharge_soc); chip->charge_full = false; /* * Raise the recharge voltage so that VBAT_LT_RECHG signal * will be asserted soon as battery SOC had dropped below * the recharge SOC threshold. */ rc = fg_set_recharge_voltage(chip, chip->dt.recharge_volt_thr_mv); if (rc < 0) { pr_err("Error in setting recharge voltage, rc=%d\n", rc); return rc; } } else { return 0; } if (!chip->charge_full) Loading Loading @@ -1539,13 +1628,16 @@ static int fg_rconn_config(struct fg_chip *chip) static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc) { u8 buf[4]; u8 buf; int rc; fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, buf); if (!chip->dt.auto_recharge_soc) return 0; fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word, chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, buf, chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf, chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc); Loading @@ -1559,6 +1651,9 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip) { int rc, msoc, recharge_soc, new_recharge_soc = 0; if (!chip->dt.auto_recharge_soc) return 0; recharge_soc = chip->dt.recharge_soc_thr; /* * If the input is present and charging had been terminated, adjust Loading Loading @@ -2062,7 +2157,6 @@ wait: goto wait; } else if (rc <= 0) { pr_err("wait for soc_ready timed out rc=%d\n", rc); goto out; } rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0); Loading Loading @@ -2494,12 +2588,12 @@ static int fg_psy_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CAPACITY: if (chip->fg_restarting) pval->intval = chip->last_soc; else rc = fg_get_prop_capacity(chip, &pval->intval); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: if (chip->battery_missing) pval->intval = 3700000; else rc = fg_get_battery_voltage(chip, &pval->intval); break; case POWER_SUPPLY_PROP_CURRENT_NOW: Loading Loading @@ -2753,15 +2847,27 @@ static int fg_hw_init(struct fg_chip *chip) } if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) { fg_encode(chip->sp, FG_SRAM_DELTA_SOC_THR, fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR, chip->dt.delta_soc_thr, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_DELTA_SOC_THR].addr_word, chip->sp[FG_SRAM_DELTA_SOC_THR].addr_byte, buf, chip->sp[FG_SRAM_DELTA_SOC_THR].len, chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word, chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte, buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing delta_soc_thr, rc=%d\n", rc); pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc); return rc; } fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR, chip->dt.delta_soc_thr, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word, chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte, buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc); return rc; } } Loading @@ -2774,18 +2880,11 @@ static int fg_hw_init(struct fg_chip *chip) } } /* This configuration is available only for pmicobalt v2.0 and above */ if (!(chip->wa_flags & PMI8998_V1_REV_WA) && chip->dt.recharge_volt_thr_mv > 0) { fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, chip->dt.recharge_volt_thr_mv, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte, buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len, FG_IMA_DEFAULT); if (chip->dt.recharge_volt_thr_mv > 0) { rc = fg_set_recharge_voltage(chip, chip->dt.recharge_volt_thr_mv); if (rc < 0) { pr_err("Error in writing recharge_vbatt_thr, rc=%d\n", pr_err("Error in setting recharge_voltage, rc=%d\n", rc); return rc; } Loading Loading @@ -3052,7 +3151,20 @@ static irqreturn_t fg_soc_update_irq_handler(int irq, void *data) return IRQ_HANDLED; } static irqreturn_t fg_delta_soc_irq_handler(int irq, void *data) static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data) { struct fg_chip *chip = data; int rc; fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq); rc = fg_charge_full_update(chip); if (rc < 0) pr_err("Error in charge_full_update, rc=%d\n", rc); return IRQ_HANDLED; } static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) { struct fg_chip *chip = data; int rc; Loading Loading @@ -3126,12 +3238,13 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = { }, [MSOC_DELTA_IRQ] = { .name = "msoc-delta", .handler = fg_delta_soc_irq_handler, .handler = fg_delta_msoc_irq_handler, .wakeable = true, }, [BSOC_DELTA_IRQ] = { .name = "bsoc-delta", .handler = fg_dummy_irq_handler, .handler = fg_delta_bsoc_irq_handler, .wakeable = true, }, [SOC_READY_IRQ] = { .name = "soc-ready", Loading Loading @@ -3489,6 +3602,9 @@ static int fg_parse_dt(struct fg_chip *chip) else chip->dt.recharge_volt_thr_mv = temp; chip->dt.auto_recharge_soc = of_property_read_bool(node, "qcom,fg-auto-recharge-soc"); rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp); if (rc < 0) chip->dt.rsense_sel = SRC_SEL_BATFET_SMB; Loading Loading @@ -3746,6 +3862,13 @@ static int fg_gen3_probe(struct platform_device *pdev) if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ irq disabled until we require it */ if (fg_irqs[BSOC_DELTA_IRQ].irq) { disable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq); disable_irq_nosync(fg_irqs[BSOC_DELTA_IRQ].irq); chip->bsoc_delta_irq_en = false; } rc = fg_debugfs_create(chip); if (rc < 0) { dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n", Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +20 −11 Original line number Diff line number Diff line Loading @@ -99,10 +99,10 @@ First Level Node - FG Gen3 device - qcom,fg-delta-soc-thr Usage: optional Value type: <u32> Definition: Percentage of monotonic SOC increase upon which the delta SOC interrupt will be triggered. If this property is not specified, then the default value will be 1. Possible values are in the range of 0 to 12. Definition: Percentage of SOC increase upon which the delta monotonic & battery SOC interrupts will be triggered. If this property is not specified, then the default value will be 1. Possible values are in the range of 0 to 12. - qcom,fg-recharge-soc-thr Usage: optional Loading Loading @@ -156,12 +156,12 @@ First Level Node - FG Gen3 device - qcom,cycle-counter-en Usage: optional Value type: <bool> Value type: <empty> Definition: Enables the cycle counter feature. - qcom,fg-force-load-profile Usage: optional Value type: <bool> Value type: <empty> Definition: If set, battery profile will be force loaded if the profile loaded earlier by bootloader doesn't match with the profile available in the device tree. Loading Loading @@ -229,13 +229,13 @@ First Level Node - FG Gen3 device Definition: Battery temperature delta interrupt threshold. Possible values are: 2, 4, 6 and 10. Unit is in Kelvin. - qcom,hold-soc-while-full: - qcom,hold-soc-while-full Usage: optional Value type: <bool> Value type: <empty> Definition: A boolean property that when defined holds SOC at 100% when the battery is full. - qcom,ki-coeff-soc-dischg: - qcom,ki-coeff-soc-dischg Usage: optional Value type: <prop-encoded-array> Definition: Array of monotonic SOC threshold values to change the ki Loading @@ -243,7 +243,7 @@ First Level Node - FG Gen3 device This should be defined in the ascending order and in the range of 0-100. Array limit is set to 3. - qcom,ki-coeff-med-dischg: - qcom,ki-coeff-med-dischg Usage: optional Value type: <prop-encoded-array> Definition: Array of ki coefficient values for medium discharge current Loading @@ -254,7 +254,7 @@ First Level Node - FG Gen3 device is specified to make it fully functional. Value has no unit. Allowed range is 0 to 62200 in micro units. - qcom,ki-coeff-hi-dischg: - qcom,ki-coeff-hi-dischg Usage: optional Value type: <prop-encoded-array> Definition: Array of ki coefficient values for high discharge current Loading Loading @@ -311,6 +311,15 @@ First Level Node - FG Gen3 device 148438 (14.84 %) will be used. Lowest possible value is 1954 (0.19 %). - qcom,fg-auto-recharge-soc Usage: optional Value type: <empty> Definition: A boolean property when defined will configure automatic recharge SOC threshold. If not specified, automatic recharge voltage threshold will be configured. This has to be configured in conjunction with the charger side configuration for proper functionality. ========================================================== Second Level Nodes - Peripherals managed by FG Gen3 driver ========================================================== Loading
arch/arm/boot/dts/qcom/msm-pm660.dtsi +4 −2 Original line number Diff line number Diff line Loading @@ -518,8 +518,10 @@ reg = <0x4000 0x100>; interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x2 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x3 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x2 IRQ_TYPE_EDGE_RISING>, <0x0 0x40 0x3 IRQ_TYPE_EDGE_RISING>, <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, <0x0 0x40 0x5 IRQ_TYPE_EDGE_RISING>, Loading
arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +4 −2 Original line number Diff line number Diff line Loading @@ -333,8 +333,10 @@ reg = <0x4000 0x100>; interrupts = <0x2 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x2 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x3 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x2 IRQ_TYPE_EDGE_RISING>, <0x2 0x40 0x3 IRQ_TYPE_EDGE_RISING>, <0x2 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, <0x2 0x40 0x5 IRQ_TYPE_EDGE_RISING>, Loading
drivers/power/supply/qcom/fg-core.h +4 −1 Original line number Diff line number Diff line Loading @@ -156,7 +156,8 @@ enum fg_sram_param_id { FG_SRAM_ESR_TIMER_CHG_INIT, FG_SRAM_SYS_TERM_CURR, FG_SRAM_CHG_TERM_CURR, FG_SRAM_DELTA_SOC_THR, FG_SRAM_DELTA_MSOC_THR, FG_SRAM_DELTA_BSOC_THR, FG_SRAM_RECHARGE_SOC_THR, FG_SRAM_RECHARGE_VBATT_THR, FG_SRAM_KI_COEFF_MED_DISCHG, Loading Loading @@ -205,6 +206,7 @@ enum wa_flags { struct fg_dt_props { bool force_load_profile; bool hold_soc_while_full; bool auto_recharge_soc; int cutoff_volt_mv; int empty_volt_mv; int vbatt_low_thr_mv; Loading Loading @@ -345,6 +347,7 @@ struct fg_chip { bool esr_fcc_ctrl_en; bool soc_reporting_ready; bool esr_flt_cold_temp_en; bool bsoc_delta_irq_en; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; Loading
drivers/power/supply/qcom/qpnp-fg-gen3.c +165 −42 Original line number Diff line number Diff line Loading @@ -48,8 +48,10 @@ #define KI_COEFF_HI_DISCHG_OFFSET 0 #define KI_COEFF_LOW_DISCHG_WORD 10 #define KI_COEFF_LOW_DISCHG_OFFSET 2 #define DELTA_SOC_THR_WORD 12 #define DELTA_SOC_THR_OFFSET 3 #define DELTA_MSOC_THR_WORD 12 #define DELTA_MSOC_THR_OFFSET 3 #define DELTA_BSOC_THR_WORD 13 #define DELTA_BSOC_THR_OFFSET 2 #define RECHARGE_SOC_THR_WORD 14 #define RECHARGE_SOC_THR_OFFSET 0 #define CHG_TERM_CURR_WORD 14 Loading Loading @@ -113,8 +115,10 @@ #define KI_COEFF_MED_DISCHG_v2_OFFSET 0 #define KI_COEFF_HI_DISCHG_v2_WORD 10 #define KI_COEFF_HI_DISCHG_v2_OFFSET 1 #define DELTA_SOC_THR_v2_WORD 13 #define DELTA_SOC_THR_v2_OFFSET 0 #define DELTA_BSOC_THR_v2_WORD 12 #define DELTA_BSOC_THR_v2_OFFSET 3 #define DELTA_MSOC_THR_v2_WORD 13 #define DELTA_MSOC_THR_v2_OFFSET 0 #define RECHARGE_SOC_THR_v2_WORD 14 #define RECHARGE_SOC_THR_v2_OFFSET 1 #define CHG_TERM_CURR_v2_WORD 15 Loading Loading @@ -143,6 +147,8 @@ static void fg_encode_current(struct fg_sram_param *sp, static void fg_encode_default(struct fg_sram_param *sp, enum fg_sram_param_id id, int val, u8 *buf); static struct fg_irq_info fg_irqs[FG_IRQ_MAX]; #define PARAM(_id, _addr_word, _addr_byte, _len, _num, _den, _offset, \ _enc, _dec) \ [FG_SRAM_##_id] = { \ Loading Loading @@ -188,8 +194,10 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = { 1000000, 122070, 0, fg_encode_current, NULL), PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1, 100000, 390625, 0, fg_encode_current, NULL), PARAM(DELTA_SOC_THR, DELTA_SOC_THR_WORD, DELTA_SOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET, 1, 256, 100, 0, fg_encode_default, NULL), PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD, Loading Loading @@ -248,8 +256,10 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = { 1000000, 122070, 0, fg_encode_current, NULL), PARAM(CHG_TERM_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_CURR_v2_OFFSET, 1, 100000, 390625, 0, fg_encode_current, NULL), PARAM(DELTA_SOC_THR, DELTA_SOC_THR_v2_WORD, DELTA_SOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD, RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default, NULL), Loading Loading @@ -773,6 +783,7 @@ static bool is_debug_batt_id(struct fg_chip *chip) #define FULL_CAPACITY 100 #define FULL_SOC_RAW 255 #define DEBUG_BATT_SOC 67 #define BATT_MISS_SOC 50 #define EMPTY_SOC 0 static int fg_get_prop_capacity(struct fg_chip *chip, int *val) { Loading @@ -783,6 +794,16 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val) return 0; } if (chip->fg_restarting) { *val = chip->last_soc; return 0; } if (chip->battery_missing) { *val = BATT_MISS_SOC; return 0; } if (is_batt_empty(chip)) { *val = EMPTY_SOC; return 0; Loading Loading @@ -1386,6 +1407,36 @@ static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip) return 0; } static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv) { u8 buf; int rc; if (chip->dt.auto_recharge_soc) return 0; /* This configuration is available only for pmicobalt v2.0 and above */ if (chip->wa_flags & PMI8998_V1_REV_WA) return 0; fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n", voltage_mv); fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte, &buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing recharge_vbatt_thr, rc=%d\n", rc); return rc; } return 0; } #define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700 static int fg_charge_full_update(struct fg_chip *chip) { union power_supply_propval prop = {0, }; Loading @@ -1398,6 +1449,16 @@ static int fg_charge_full_update(struct fg_chip *chip) if (!batt_psy_initialized(chip)) return 0; if (!chip->charge_done && chip->bsoc_delta_irq_en) { disable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq); disable_irq_nosync(fg_irqs[BSOC_DELTA_IRQ].irq); chip->bsoc_delta_irq_en = false; } else if (chip->charge_done && !chip->bsoc_delta_irq_en) { enable_irq(fg_irqs[BSOC_DELTA_IRQ].irq); enable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq); chip->bsoc_delta_irq_en = true; } rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &prop); if (rc < 0) { Loading @@ -1423,18 +1484,46 @@ static int fg_charge_full_update(struct fg_chip *chip) return rc; } fg_dbg(chip, FG_STATUS, "msoc: %d health: %d status: %d\n", msoc, chip->health, chip->charge_status); if (chip->charge_done) { if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n", msoc, bsoc, chip->health, chip->charge_status, chip->charge_full); if (chip->charge_done && !chip->charge_full) { if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) { fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n"); chip->charge_full = true; else /* * Lower the recharge voltage so that VBAT_LT_RECHG * signal will not be asserted soon. */ rc = fg_set_recharge_voltage(chip, AUTO_RECHG_VOLT_LOW_LIMIT_MV); if (rc < 0) { pr_err("Error in reducing recharge voltage, rc=%d\n", rc); return rc; } } else { fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n", msoc); } else if ((bsoc >> 8) <= recharge_soc) { } } else if ((bsoc >> 8) <= recharge_soc && chip->charge_full) { fg_dbg(chip, FG_STATUS, "bsoc: %d recharge_soc: %d\n", bsoc >> 8, recharge_soc); chip->charge_full = false; /* * Raise the recharge voltage so that VBAT_LT_RECHG signal * will be asserted soon as battery SOC had dropped below * the recharge SOC threshold. */ rc = fg_set_recharge_voltage(chip, chip->dt.recharge_volt_thr_mv); if (rc < 0) { pr_err("Error in setting recharge voltage, rc=%d\n", rc); return rc; } } else { return 0; } if (!chip->charge_full) Loading Loading @@ -1539,13 +1628,16 @@ static int fg_rconn_config(struct fg_chip *chip) static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc) { u8 buf[4]; u8 buf; int rc; fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, buf); if (!chip->dt.auto_recharge_soc) return 0; fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word, chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, buf, chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf, chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc); Loading @@ -1559,6 +1651,9 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip) { int rc, msoc, recharge_soc, new_recharge_soc = 0; if (!chip->dt.auto_recharge_soc) return 0; recharge_soc = chip->dt.recharge_soc_thr; /* * If the input is present and charging had been terminated, adjust Loading Loading @@ -2062,7 +2157,6 @@ wait: goto wait; } else if (rc <= 0) { pr_err("wait for soc_ready timed out rc=%d\n", rc); goto out; } rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0); Loading Loading @@ -2494,12 +2588,12 @@ static int fg_psy_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CAPACITY: if (chip->fg_restarting) pval->intval = chip->last_soc; else rc = fg_get_prop_capacity(chip, &pval->intval); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: if (chip->battery_missing) pval->intval = 3700000; else rc = fg_get_battery_voltage(chip, &pval->intval); break; case POWER_SUPPLY_PROP_CURRENT_NOW: Loading Loading @@ -2753,15 +2847,27 @@ static int fg_hw_init(struct fg_chip *chip) } if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) { fg_encode(chip->sp, FG_SRAM_DELTA_SOC_THR, fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR, chip->dt.delta_soc_thr, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_DELTA_SOC_THR].addr_word, chip->sp[FG_SRAM_DELTA_SOC_THR].addr_byte, buf, chip->sp[FG_SRAM_DELTA_SOC_THR].len, chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word, chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte, buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing delta_soc_thr, rc=%d\n", rc); pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc); return rc; } fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR, chip->dt.delta_soc_thr, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word, chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte, buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc); return rc; } } Loading @@ -2774,18 +2880,11 @@ static int fg_hw_init(struct fg_chip *chip) } } /* This configuration is available only for pmicobalt v2.0 and above */ if (!(chip->wa_flags & PMI8998_V1_REV_WA) && chip->dt.recharge_volt_thr_mv > 0) { fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, chip->dt.recharge_volt_thr_mv, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte, buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len, FG_IMA_DEFAULT); if (chip->dt.recharge_volt_thr_mv > 0) { rc = fg_set_recharge_voltage(chip, chip->dt.recharge_volt_thr_mv); if (rc < 0) { pr_err("Error in writing recharge_vbatt_thr, rc=%d\n", pr_err("Error in setting recharge_voltage, rc=%d\n", rc); return rc; } Loading Loading @@ -3052,7 +3151,20 @@ static irqreturn_t fg_soc_update_irq_handler(int irq, void *data) return IRQ_HANDLED; } static irqreturn_t fg_delta_soc_irq_handler(int irq, void *data) static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data) { struct fg_chip *chip = data; int rc; fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq); rc = fg_charge_full_update(chip); if (rc < 0) pr_err("Error in charge_full_update, rc=%d\n", rc); return IRQ_HANDLED; } static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) { struct fg_chip *chip = data; int rc; Loading Loading @@ -3126,12 +3238,13 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = { }, [MSOC_DELTA_IRQ] = { .name = "msoc-delta", .handler = fg_delta_soc_irq_handler, .handler = fg_delta_msoc_irq_handler, .wakeable = true, }, [BSOC_DELTA_IRQ] = { .name = "bsoc-delta", .handler = fg_dummy_irq_handler, .handler = fg_delta_bsoc_irq_handler, .wakeable = true, }, [SOC_READY_IRQ] = { .name = "soc-ready", Loading Loading @@ -3489,6 +3602,9 @@ static int fg_parse_dt(struct fg_chip *chip) else chip->dt.recharge_volt_thr_mv = temp; chip->dt.auto_recharge_soc = of_property_read_bool(node, "qcom,fg-auto-recharge-soc"); rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp); if (rc < 0) chip->dt.rsense_sel = SRC_SEL_BATFET_SMB; Loading Loading @@ -3746,6 +3862,13 @@ static int fg_gen3_probe(struct platform_device *pdev) if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ irq disabled until we require it */ if (fg_irqs[BSOC_DELTA_IRQ].irq) { disable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq); disable_irq_nosync(fg_irqs[BSOC_DELTA_IRQ].irq); chip->bsoc_delta_irq_en = false; } rc = fg_debugfs_create(chip); if (rc < 0) { dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n", Loading