Loading Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +7 −0 Original line number Diff line number Diff line Loading @@ -419,6 +419,13 @@ First Level Node - FG Gen4 device multiple battery profiles to be specified for a battery for proper functionality. - qcom,soc-hi-res Usage: optional Value type: <empty> Definition: A boolean property that when specified shows high resolution of monotonic SOC under CAPACITY_RAW property during charging in the scale of 0-10000. ========================================================== Second Level Nodes - Peripherals managed by FG Gen4 driver ========================================================== Loading drivers/power/supply/qcom/qpnp-fg-gen4.c +94 −24 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ #define pr_fmt(fmt) "FG: %s: " fmt, __func__ #include <linux/alarmtimer.h> #include <linux/irq.h> #include <linux/ktime.h> #include <linux/of.h> #include <linux/of_platform.h> Loading Loading @@ -188,6 +189,7 @@ struct fg_dt_props { bool five_pin_battery; bool multi_profile_load; bool esr_calib_dischg; bool soc_hi_res; int cutoff_volt_mv; int empty_volt_mv; int cutoff_curr_ma; Loading Loading @@ -236,7 +238,7 @@ struct fg_gen4_chip { struct work_struct esr_calib_work; struct alarm esr_fast_cal_timer; struct delayed_work pl_enable_work; struct delayed_work pl_current_en_work; struct work_struct pl_current_en_work; struct completion mem_attn; char batt_profile[PROFILE_LEN]; enum slope_limit_status slope_limit_sts; Loading Loading @@ -851,6 +853,35 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) return 0; } static int fg_gen4_get_prop_capacity_raw(struct fg_gen4_chip *chip, int *val) { struct fg_dev *fg = &chip->fg; int rc; if (!chip->dt.soc_hi_res) { rc = fg_get_msoc_raw(fg, val); return rc; } if (!is_input_present(fg)) { rc = fg_gen4_get_prop_capacity(fg, val); if (!rc) *val = *val * 100; return rc; } rc = fg_get_sram_prop(&chip->fg, FG_SRAM_MONOTONIC_SOC, val); if (rc < 0) { pr_err("Error in getting MONOTONIC_SOC, rc=%d\n", rc); return rc; } /* Show it in centi-percentage */ *val = (*val * 10000) / 0xFFFF; return 0; } static inline void get_esr_meas_current(int curr_ma, u8 *val) { switch (curr_ma) { Loading @@ -874,6 +905,43 @@ static inline void get_esr_meas_current(int curr_ma, u8 *val) *val <<= ESR_PULL_DOWN_IVAL_SHIFT; } static int fg_gen4_get_power(struct fg_gen4_chip *chip, int *val, bool average) { struct fg_dev *fg = &chip->fg; int rc, v_min, v_pred, esr_uohms, rslow_uohms; s64 power; rc = fg_get_sram_prop(fg, FG_SRAM_VOLTAGE_PRED, &v_pred); if (rc < 0) return rc; v_min = chip->dt.cutoff_volt_mv * 1000; power = (s64)v_min * (v_pred - v_min); rc = fg_get_sram_prop(fg, FG_SRAM_ESR, &esr_uohms); if (rc < 0) { pr_err("failed to get ESR, rc=%d\n", rc); return rc; } rc = fg_get_sram_prop(fg, FG_SRAM_RSLOW, &rslow_uohms); if (rc < 0) { pr_err("failed to get Rslow, rc=%d\n", rc); return rc; } if (average) power = div_s64(power, esr_uohms + rslow_uohms); else power = div_s64(power, esr_uohms); pr_debug("V_min: %d V_pred: %d ESR: %d Rslow: %d power: %lld\n", v_min, v_pred, esr_uohms, rslow_uohms, power); *val = power; return 0; } /* ALG callback functions below */ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) Loading Loading @@ -3221,31 +3289,16 @@ static void pl_current_en_work(struct work_struct *work) { struct fg_gen4_chip *chip = container_of(work, struct fg_gen4_chip, pl_current_en_work.work); pl_current_en_work); struct fg_dev *fg = &chip->fg; bool input_present = is_input_present(fg), en; en = fg->charge_done ? false : input_present; /* * If mem_attn_irq is disabled and parallel summing current * configuration needs to be modified, then enable mem_attn_irq and * wait for 1 second before doing it. */ if (get_effective_result(chip->parallel_current_en_votable) != en && !get_effective_result(chip->mem_attn_irq_en_votable)) { vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, true, 0); schedule_delayed_work(&chip->pl_current_en_work, msecs_to_jiffies(1000)); return; } if (!get_effective_result(chip->mem_attn_irq_en_votable)) if (get_effective_result(chip->parallel_current_en_votable) == en) return; vote(chip->parallel_current_en_votable, FG_PARALLEL_EN_VOTER, en, 0); vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); } static void pl_enable_work(struct work_struct *work) Loading Loading @@ -3339,9 +3392,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); if (is_parallel_charger_available(fg) && !delayed_work_pending(&chip->pl_current_en_work)) schedule_delayed_work(&chip->pl_current_en_work, 0); if (is_parallel_charger_available(fg)) { cancel_work_sync(&chip->pl_current_en_work); schedule_work(&chip->pl_current_en_work); } ttf_update(chip->ttf, input_present); fg->prev_charge_status = fg->charge_status; Loading Loading @@ -3556,7 +3610,7 @@ static int fg_psy_get_property(struct power_supply *psy, rc = fg_gen4_get_prop_capacity(fg, &pval->intval); break; case POWER_SUPPLY_PROP_CAPACITY_RAW: rc = fg_get_msoc_raw(fg, &pval->intval); rc = fg_gen4_get_prop_capacity_raw(chip, &pval->intval); break; case POWER_SUPPLY_PROP_CC_SOC: rc = fg_get_sram_prop(&chip->fg, FG_SRAM_CC_SOC, &val); Loading Loading @@ -3668,6 +3722,12 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: pval->intval = chip->batt_age_level; break; case POWER_SUPPLY_PROP_POWER_NOW: rc = fg_gen4_get_power(chip, &pval->intval, false); break; case POWER_SUPPLY_PROP_POWER_AVG: rc = fg_gen4_get_power(chip, &pval->intval, true); break; default: pr_err("unsupported property %d\n", psp); rc = -EINVAL; Loading Loading @@ -3815,6 +3875,8 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CC_STEP, POWER_SUPPLY_PROP_CC_STEP_SEL, POWER_SUPPLY_PROP_BATT_AGE_LEVEL, POWER_SUPPLY_PROP_POWER_NOW, POWER_SUPPLY_PROP_POWER_AVG, }; static const struct power_supply_desc fg_psy_desc = { Loading Loading @@ -3923,6 +3985,8 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data, int rc; u8 val, mask; vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, true, 0); /* Wait for MEM_ATTN interrupt */ rc = fg_wait_for_mem_attn(chip); if (rc < 0) Loading @@ -3935,6 +3999,7 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data, pr_err("Error in writing to 0x%04x, rc=%d\n", BATT_INFO_FG_CNV_CHAR_CFG(fg), rc); vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); fg_dbg(fg, FG_STATUS, "Parallel current summing: %d\n", enable); return rc; Loading Loading @@ -4956,6 +5021,7 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) "qcom,five-pin-battery"); chip->dt.multi_profile_load = of_property_read_bool(node, "qcom,multi-profile-load"); chip->dt.soc_hi_res = of_property_read_bool(node, "qcom,soc-hi-res"); return 0; } Loading @@ -4968,7 +5034,7 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip) cancel_work_sync(&fg->status_change_work); cancel_delayed_work_sync(&fg->profile_load_work); cancel_delayed_work_sync(&fg->sram_dump_work); cancel_delayed_work_sync(&chip->pl_current_en_work); cancel_work_sync(&chip->pl_current_en_work); power_supply_unreg_notifier(&fg->nb); debugfs_remove_recursive(fg->dfs_root); Loading Loading @@ -5031,7 +5097,7 @@ static int fg_gen4_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); INIT_DELAYED_WORK(&chip->pl_current_en_work, pl_current_en_work); INIT_WORK(&chip->pl_current_en_work, pl_current_en_work); fg->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb, fg); Loading Loading @@ -5145,6 +5211,10 @@ static int fg_gen4_probe(struct platform_device *pdev) goto exit; } if (fg->irqs[MEM_ATTN_IRQ].irq) irq_set_status_flags(fg->irqs[MEM_ATTN_IRQ].irq, IRQ_DISABLE_UNLAZY); /* Keep SOC_UPDATE irq disabled until we require it */ if (fg->irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg->irqs[SOC_UPDATE_IRQ].irq); Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +7 −0 Original line number Diff line number Diff line Loading @@ -419,6 +419,13 @@ First Level Node - FG Gen4 device multiple battery profiles to be specified for a battery for proper functionality. - qcom,soc-hi-res Usage: optional Value type: <empty> Definition: A boolean property that when specified shows high resolution of monotonic SOC under CAPACITY_RAW property during charging in the scale of 0-10000. ========================================================== Second Level Nodes - Peripherals managed by FG Gen4 driver ========================================================== Loading
drivers/power/supply/qcom/qpnp-fg-gen4.c +94 −24 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ #define pr_fmt(fmt) "FG: %s: " fmt, __func__ #include <linux/alarmtimer.h> #include <linux/irq.h> #include <linux/ktime.h> #include <linux/of.h> #include <linux/of_platform.h> Loading Loading @@ -188,6 +189,7 @@ struct fg_dt_props { bool five_pin_battery; bool multi_profile_load; bool esr_calib_dischg; bool soc_hi_res; int cutoff_volt_mv; int empty_volt_mv; int cutoff_curr_ma; Loading Loading @@ -236,7 +238,7 @@ struct fg_gen4_chip { struct work_struct esr_calib_work; struct alarm esr_fast_cal_timer; struct delayed_work pl_enable_work; struct delayed_work pl_current_en_work; struct work_struct pl_current_en_work; struct completion mem_attn; char batt_profile[PROFILE_LEN]; enum slope_limit_status slope_limit_sts; Loading Loading @@ -851,6 +853,35 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) return 0; } static int fg_gen4_get_prop_capacity_raw(struct fg_gen4_chip *chip, int *val) { struct fg_dev *fg = &chip->fg; int rc; if (!chip->dt.soc_hi_res) { rc = fg_get_msoc_raw(fg, val); return rc; } if (!is_input_present(fg)) { rc = fg_gen4_get_prop_capacity(fg, val); if (!rc) *val = *val * 100; return rc; } rc = fg_get_sram_prop(&chip->fg, FG_SRAM_MONOTONIC_SOC, val); if (rc < 0) { pr_err("Error in getting MONOTONIC_SOC, rc=%d\n", rc); return rc; } /* Show it in centi-percentage */ *val = (*val * 10000) / 0xFFFF; return 0; } static inline void get_esr_meas_current(int curr_ma, u8 *val) { switch (curr_ma) { Loading @@ -874,6 +905,43 @@ static inline void get_esr_meas_current(int curr_ma, u8 *val) *val <<= ESR_PULL_DOWN_IVAL_SHIFT; } static int fg_gen4_get_power(struct fg_gen4_chip *chip, int *val, bool average) { struct fg_dev *fg = &chip->fg; int rc, v_min, v_pred, esr_uohms, rslow_uohms; s64 power; rc = fg_get_sram_prop(fg, FG_SRAM_VOLTAGE_PRED, &v_pred); if (rc < 0) return rc; v_min = chip->dt.cutoff_volt_mv * 1000; power = (s64)v_min * (v_pred - v_min); rc = fg_get_sram_prop(fg, FG_SRAM_ESR, &esr_uohms); if (rc < 0) { pr_err("failed to get ESR, rc=%d\n", rc); return rc; } rc = fg_get_sram_prop(fg, FG_SRAM_RSLOW, &rslow_uohms); if (rc < 0) { pr_err("failed to get Rslow, rc=%d\n", rc); return rc; } if (average) power = div_s64(power, esr_uohms + rslow_uohms); else power = div_s64(power, esr_uohms); pr_debug("V_min: %d V_pred: %d ESR: %d Rslow: %d power: %lld\n", v_min, v_pred, esr_uohms, rslow_uohms, power); *val = power; return 0; } /* ALG callback functions below */ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) Loading Loading @@ -3221,31 +3289,16 @@ static void pl_current_en_work(struct work_struct *work) { struct fg_gen4_chip *chip = container_of(work, struct fg_gen4_chip, pl_current_en_work.work); pl_current_en_work); struct fg_dev *fg = &chip->fg; bool input_present = is_input_present(fg), en; en = fg->charge_done ? false : input_present; /* * If mem_attn_irq is disabled and parallel summing current * configuration needs to be modified, then enable mem_attn_irq and * wait for 1 second before doing it. */ if (get_effective_result(chip->parallel_current_en_votable) != en && !get_effective_result(chip->mem_attn_irq_en_votable)) { vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, true, 0); schedule_delayed_work(&chip->pl_current_en_work, msecs_to_jiffies(1000)); return; } if (!get_effective_result(chip->mem_attn_irq_en_votable)) if (get_effective_result(chip->parallel_current_en_votable) == en) return; vote(chip->parallel_current_en_votable, FG_PARALLEL_EN_VOTER, en, 0); vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); } static void pl_enable_work(struct work_struct *work) Loading Loading @@ -3339,9 +3392,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); if (is_parallel_charger_available(fg) && !delayed_work_pending(&chip->pl_current_en_work)) schedule_delayed_work(&chip->pl_current_en_work, 0); if (is_parallel_charger_available(fg)) { cancel_work_sync(&chip->pl_current_en_work); schedule_work(&chip->pl_current_en_work); } ttf_update(chip->ttf, input_present); fg->prev_charge_status = fg->charge_status; Loading Loading @@ -3556,7 +3610,7 @@ static int fg_psy_get_property(struct power_supply *psy, rc = fg_gen4_get_prop_capacity(fg, &pval->intval); break; case POWER_SUPPLY_PROP_CAPACITY_RAW: rc = fg_get_msoc_raw(fg, &pval->intval); rc = fg_gen4_get_prop_capacity_raw(chip, &pval->intval); break; case POWER_SUPPLY_PROP_CC_SOC: rc = fg_get_sram_prop(&chip->fg, FG_SRAM_CC_SOC, &val); Loading Loading @@ -3668,6 +3722,12 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: pval->intval = chip->batt_age_level; break; case POWER_SUPPLY_PROP_POWER_NOW: rc = fg_gen4_get_power(chip, &pval->intval, false); break; case POWER_SUPPLY_PROP_POWER_AVG: rc = fg_gen4_get_power(chip, &pval->intval, true); break; default: pr_err("unsupported property %d\n", psp); rc = -EINVAL; Loading Loading @@ -3815,6 +3875,8 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CC_STEP, POWER_SUPPLY_PROP_CC_STEP_SEL, POWER_SUPPLY_PROP_BATT_AGE_LEVEL, POWER_SUPPLY_PROP_POWER_NOW, POWER_SUPPLY_PROP_POWER_AVG, }; static const struct power_supply_desc fg_psy_desc = { Loading Loading @@ -3923,6 +3985,8 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data, int rc; u8 val, mask; vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, true, 0); /* Wait for MEM_ATTN interrupt */ rc = fg_wait_for_mem_attn(chip); if (rc < 0) Loading @@ -3935,6 +3999,7 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data, pr_err("Error in writing to 0x%04x, rc=%d\n", BATT_INFO_FG_CNV_CHAR_CFG(fg), rc); vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); fg_dbg(fg, FG_STATUS, "Parallel current summing: %d\n", enable); return rc; Loading Loading @@ -4956,6 +5021,7 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) "qcom,five-pin-battery"); chip->dt.multi_profile_load = of_property_read_bool(node, "qcom,multi-profile-load"); chip->dt.soc_hi_res = of_property_read_bool(node, "qcom,soc-hi-res"); return 0; } Loading @@ -4968,7 +5034,7 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip) cancel_work_sync(&fg->status_change_work); cancel_delayed_work_sync(&fg->profile_load_work); cancel_delayed_work_sync(&fg->sram_dump_work); cancel_delayed_work_sync(&chip->pl_current_en_work); cancel_work_sync(&chip->pl_current_en_work); power_supply_unreg_notifier(&fg->nb); debugfs_remove_recursive(fg->dfs_root); Loading Loading @@ -5031,7 +5097,7 @@ static int fg_gen4_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); INIT_DELAYED_WORK(&chip->pl_current_en_work, pl_current_en_work); INIT_WORK(&chip->pl_current_en_work, pl_current_en_work); fg->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb, fg); Loading Loading @@ -5145,6 +5211,10 @@ static int fg_gen4_probe(struct platform_device *pdev) goto exit; } if (fg->irqs[MEM_ATTN_IRQ].irq) irq_set_status_flags(fg->irqs[MEM_ATTN_IRQ].irq, IRQ_DISABLE_UNLAZY); /* Keep SOC_UPDATE irq disabled until we require it */ if (fg->irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg->irqs[SOC_UPDATE_IRQ].irq); Loading