Loading Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +15 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,19 @@ First Level Node - FG Gen4 device - #thermal-sensor-cells: Should be 0. See thermal.txt for the description. - nvmem-names: Usage: optional Value type: <string> Definition: Nvmem device name for SDAM to store parameters like cycle counters and learned capacity. It must be defined as "fg_sdam". - nvmem: Usage: optional Value type: <phandle> Definition: Phandle of the nvmem device name to access SDAM to store parameters. - qcom,fg-cutoff-voltage Usage: optional Value type: <u32> Loading Loading @@ -487,6 +500,8 @@ pm8150b_fg: qpnp,fg { #address-cells = <1>; #size-cells = <1>; qcom,pmic-revid = <&pm8150b_revid>; nvmem-names = "fg_sdam"; nvmem = <&pm8150_sdam_2>; #thermal-sensor-cells = <0>; status = "okay"; Loading arch/arm64/boot/dts/qcom/kona-pmic-overlay.dtsi +5 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,11 @@ pinctrl-1 = <&qnovo_fet_ctrl_state2>; }; &pm8150b_fg { nvmem-names = "fg_sdam"; nvmem = <&pm8150_sdam_2>; }; &pm8150b_charger { dpdm-supply = <&usb2_phy0>; smb5_vconn: qcom,smb5-vconn { Loading drivers/power/supply/qcom/qpnp-fg-gen4.c +272 −111 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ #include <linux/alarmtimer.h> #include <linux/irq.h> #include <linux/ktime.h> #include <linux/nvmem-consumer.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_batterydata.h> Loading @@ -27,6 +28,12 @@ #define FG_MEM_IF_PM8150B 0x0D #define FG_ADC_RR_PM8150B 0x13 #define SDAM_COOKIE_OFFSET 0x80 #define SDAM_CYCLE_COUNT_OFFSET 0x81 #define SDAM_CAP_LEARN_OFFSET 0x91 #define SDAM_COOKIE 0xA5 #define SDAM_FG_PARAM_LENGTH 20 #define FG_SRAM_LEN 972 #define PROFILE_LEN 416 #define PROFILE_COMP_LEN 24 Loading Loading @@ -231,6 +238,7 @@ struct fg_gen4_chip { struct cycle_counter *counter; struct cap_learning *cl; struct ttf *ttf; struct nvmem_device *fg_nvmem; struct votable *delta_esr_irq_en_votable; struct votable *pl_disable_votable; struct votable *cp_disable_votable; Loading Loading @@ -589,17 +597,25 @@ static int fg_gen4_get_learned_capacity(void *data, int64_t *learned_cap_uah) struct fg_gen4_chip *chip = data; struct fg_dev *fg; int rc, act_cap_mah; u8 buf[2]; if (!chip) return -ENODEV; fg = &chip->fg; if (chip->fg_nvmem) rc = nvmem_device_read(chip->fg_nvmem, SDAM_CAP_LEARN_OFFSET, 2, buf); else rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); if (rc < 0) { pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc); pr_err("Error in getting learned capacity, rc=%d\n", rc); return rc; } if (chip->fg_nvmem) *learned_cap_uah = (buf[0] | buf[1] << 8) * 1000; else *learned_cap_uah = act_cap_mah * 1000; fg_dbg(fg, FG_CAP_LEARN, "learned_cap_uah:%lld\n", *learned_cap_uah); Loading Loading @@ -951,6 +967,7 @@ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) struct fg_gen4_chip *chip = data; struct fg_dev *fg; int rc = 0, act_cap_mah, full_soc; u8 buf[2]; if (!chip) return -ENODEV; Loading @@ -970,12 +987,20 @@ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) rc = fg_get_battery_current(fg, val); break; case TTF_FCC: rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); if (chip->fg_nvmem) rc = nvmem_device_read(chip->fg_nvmem, SDAM_CAP_LEARN_OFFSET, 2, buf); else rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); if (rc < 0) { pr_err("Failed to get ACT_BATT_CAP rc=%d\n", rc); break; } if (chip->fg_nvmem) act_cap_mah = buf[0] | buf[1] << 8; rc = fg_get_sram_prop(fg, FG_SRAM_FULL_SOC, &full_soc); if (rc < 0) { pr_err("Failed to get FULL_SOC rc=%d\n", rc); Loading Loading @@ -1024,6 +1049,7 @@ static int fg_gen4_store_learned_capacity(void *data, int64_t learned_cap_uah) struct fg_dev *fg; int16_t cc_mah; int rc; u8 cookie = SDAM_COOKIE; if (!chip) return -ENODEV; Loading @@ -1041,6 +1067,23 @@ static int fg_gen4_store_learned_capacity(void *data, int64_t learned_cap_uah) return rc; } if (chip->fg_nvmem) { rc = nvmem_device_write(chip->fg_nvmem, SDAM_CAP_LEARN_OFFSET, 2, (u8 *)&cc_mah); if (rc < 0) { pr_err("Error in writing learned capacity to SDAM, rc=%d\n", rc); return rc; } rc = nvmem_device_write(chip->fg_nvmem, SDAM_COOKIE_OFFSET, 1, &cookie); if (rc < 0) { pr_err("Error in writing cookie to SDAM, rc=%d\n", rc); return rc; } } fg_dbg(fg, FG_CAP_LEARN, "learned capacity %llduah/%dmah stored\n", chip->cl->learned_cap_uah, cc_mah); return 0; Loading Loading @@ -1106,6 +1149,10 @@ static int fg_gen4_restore_count(void *data, u16 *buf, int length) return -EINVAL; for (id = 0; id < length; id++) { if (chip->fg_nvmem) rc = nvmem_device_read(chip->fg_nvmem, SDAM_CYCLE_COUNT_OFFSET + (id * 2), 2, tmp); else rc = fg_sram_read(&chip->fg, CYCLE_COUNT_WORD + id, CYCLE_COUNT_OFFSET, (u8 *)tmp, 2, FG_IMA_DEFAULT); Loading @@ -1130,8 +1177,13 @@ static int fg_gen4_store_count(void *data, u16 *buf, int id, int length) id > BUCKET_COUNT - 1 || ((id * 2) + length) > BUCKET_COUNT * 2) return -EINVAL; rc = fg_sram_write(&chip->fg, CYCLE_COUNT_WORD + id, CYCLE_COUNT_OFFSET, (u8 *)buf, length, FG_IMA_DEFAULT); if (chip->fg_nvmem) rc = nvmem_device_write(chip->fg_nvmem, SDAM_CYCLE_COUNT_OFFSET + (id * 2), length, (u8 *)buf); else rc = fg_sram_write(&chip->fg, CYCLE_COUNT_WORD + id, CYCLE_COUNT_OFFSET, (u8 *)buf, length, FG_IMA_DEFAULT); if (rc < 0) pr_err("failed to write bucket %d rc=%d\n", id, rc); Loading Loading @@ -1995,6 +2047,84 @@ static int qpnp_fg_gen4_load_profile(struct fg_gen4_chip *chip) return 0; } static bool is_sdam_cookie_set(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc; u8 cookie; rc = nvmem_device_read(chip->fg_nvmem, SDAM_COOKIE_OFFSET, 1, &cookie); if (rc < 0) { pr_err("Error in reading SDAM_COOKIE rc=%d\n", rc); return false; } fg_dbg(fg, FG_STATUS, "cookie: %x\n", cookie); return (cookie == SDAM_COOKIE); } static void fg_gen4_clear_sdam(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; u8 buf[SDAM_FG_PARAM_LENGTH] = { 0 }; int rc; /* * Clear all bytes of SDAM used to store FG parameters when it is first * profile load so that the junk values would not be used. */ rc = nvmem_device_write(chip->fg_nvmem, SDAM_CYCLE_COUNT_OFFSET, SDAM_FG_PARAM_LENGTH, buf); if (rc < 0) pr_err("Error in clearing SDAM rc=%d\n", rc); else fg_dbg(fg, FG_STATUS, "Cleared SDAM\n"); } static void fg_gen4_post_profile_load(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc, act_cap_mah; u8 buf[16]; /* If SDAM cookie is not set, read back from SRAM and load it in SDAM */ if (chip->fg_nvmem && !is_sdam_cookie_set(chip)) { fg_gen4_clear_sdam(chip); rc = fg_sram_read(&chip->fg, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET, buf, 16, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading cycle counters from SRAM rc=%d\n", rc); } else { rc = nvmem_device_write(chip->fg_nvmem, SDAM_CYCLE_COUNT_OFFSET, 16, (u8 *)buf); if (rc < 0) pr_err("Error in writing cycle counters to SDAM rc=%d\n", rc); } rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); if (rc < 0) { pr_err("Error in getting learned capacity, rc=%d\n", rc); } else { rc = nvmem_device_write(chip->fg_nvmem, SDAM_CAP_LEARN_OFFSET, 2, (u8 *)&act_cap_mah); if (rc < 0) pr_err("Error in writing learned capacity to SDAM, rc=%d\n", rc); } } /* Restore the cycle counters so that it would be valid at this point */ rc = restore_cycle_count(chip->counter); if (rc < 0) pr_err("Error in restoring cycle_count, rc=%d\n", rc); } static void profile_load_work(struct work_struct *work) { struct fg_dev *fg = container_of(work, Loading Loading @@ -2028,8 +2158,11 @@ static void profile_load_work(struct work_struct *work) if (!is_profile_load_required(chip)) goto done; if (!chip->dt.multi_profile_load) if (!chip->dt.multi_profile_load) { clear_cycle_count(chip->counter); if (chip->fg_nvmem && !is_sdam_cookie_set(chip)) fg_gen4_clear_sdam(chip); } fg_dbg(fg, FG_STATUS, "profile loading started\n"); Loading @@ -2054,9 +2187,8 @@ static void profile_load_work(struct work_struct *work) pr_err("Error in reading %04x[%d] rc=%d\n", NOM_CAP_WORD, NOM_CAP_OFFSET, rc); } else { rc = fg_sram_write(fg, fg->sp[FG_SRAM_ACT_BATT_CAP].addr_word, fg->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, buf, fg->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT); nom_cap_uah = (buf[0] | buf[1] << 8) * 1000; rc = fg_gen4_store_learned_capacity(chip, nom_cap_uah); if (rc < 0) pr_err("Error in writing to ACT_BATT_CAP rc=%d\n", rc); } Loading @@ -2068,6 +2200,8 @@ static void profile_load_work(struct work_struct *work) chip->first_profile_load = true; } fg_gen4_post_profile_load(chip); rc = fg_gen4_bp_params_config(fg); if (rc < 0) pr_err("Error in configuring battery profile params, rc:%d\n", Loading Loading @@ -4520,12 +4654,6 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) if (rc < 0) return rc; rc = restore_cycle_count(chip->counter); if (rc < 0) { pr_err("Error in restoring cycle_count, rc=%d\n", rc); return rc; } chip->batt_age_level = chip->last_batt_age_level = -EINVAL; if (chip->dt.multi_profile_load) { rc = fg_sram_read(fg, BATT_AGE_LEVEL_WORD, Loading Loading @@ -4766,15 +4894,30 @@ static void fg_gen4_parse_batt_temp_dt(struct fg_gen4_chip *chip) rc = of_property_read_u32(node, "qcom,fg-batt-therm-freq", &temp); if (temp > 0 && temp <= 255) chip->dt.batt_therm_freq = temp; } static int fg_gen4_parse_nvmem_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc; if (of_find_property(fg->dev->of_node, "nvmem", NULL)) { chip->fg_nvmem = devm_nvmem_device_get(fg->dev, "fg_sdam"); if (IS_ERR_OR_NULL(chip->fg_nvmem)) { rc = PTR_ERR(chip->fg_nvmem); if (rc != -EPROBE_DEFER) { dev_err(fg->dev, "Couldn't get nvmem device, rc=%d\n", rc); return -ENODEV; } chip->fg_nvmem = NULL; return rc; } } return 0; } #define DEFAULT_CUTOFF_VOLT_MV 3100 #define DEFAULT_EMPTY_VOLT_MV 2812 #define DEFAULT_SYS_MIN_VOLT_MV 2800 #define DEFAULT_SYS_TERM_CURR_MA -125 #define DEFAULT_CUTOFF_CURR_MA 200 #define DEFAULT_DELTA_SOC_THR 5 /* 0.5 % */ #define DEFAULT_CL_START_SOC 15 #define DEFAULT_CL_MIN_TEMP_DECIDEGC 150 #define DEFAULT_CL_MAX_TEMP_DECIDEGC 500 Loading @@ -4783,22 +4926,54 @@ static void fg_gen4_parse_batt_temp_dt(struct fg_gen4_chip *chip) #define DEFAULT_CL_MIN_LIM_DECIPERC 0 #define DEFAULT_CL_MAX_LIM_DECIPERC 0 #define DEFAULT_CL_DELTA_BATT_SOC 10 #define DEFAULT_ESR_PULSE_THRESH_MA 47 #define DEFAULT_ESR_MEAS_CURR_MA 120 static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) static void fg_gen4_parse_cl_params_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; struct device_node *child, *revid_node, *node = fg->dev->of_node; u32 base, temp; u8 subtype; int rc; struct device_node *node = fg->dev->of_node; if (!node) { dev_err(fg->dev, "device tree node missing\n"); return -ENXIO; chip->cl->dt.max_start_soc = DEFAULT_CL_START_SOC; of_property_read_u32(node, "qcom,cl-start-capacity", &chip->cl->dt.max_start_soc); chip->cl->dt.min_delta_batt_soc = DEFAULT_CL_DELTA_BATT_SOC; /* read from DT property and update, if value exists */ of_property_read_u32(node, "qcom,cl-min-delta-batt-soc", &chip->cl->dt.min_delta_batt_soc); chip->cl->dt.cl_wt_enable = of_property_read_bool(node, "qcom,cl-wt-enable"); chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC; of_property_read_u32(node, "qcom,cl-min-temp", &chip->cl->dt.min_temp); chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC; of_property_read_u32(node, "qcom,cl-max-temp", &chip->cl->dt.max_temp); chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC; of_property_read_u32(node, "qcom,cl-max-increment", &chip->cl->dt.max_cap_inc); chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC; of_property_read_u32(node, "qcom,cl-max-decrement", &chip->cl->dt.max_cap_dec); chip->cl->dt.min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC; of_property_read_u32(node, "qcom,cl-min-limit", &chip->cl->dt.min_cap_limit); chip->cl->dt.max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC; of_property_read_u32(node, "qcom,cl-max-limit", &chip->cl->dt.max_cap_limit); of_property_read_u32(node, "qcom,cl-skew", &chip->cl->dt.skew_decipct); } static int fg_gen4_parse_revid_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; struct device_node *revid_node, *node = fg->dev->of_node; revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0); if (!revid_node) { pr_err("Missing qcom,pmic-revid property - driver failed\n"); Loading Loading @@ -4838,6 +5013,17 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) return -EINVAL; } return 0; } static int fg_gen4_parse_child_nodes_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; struct device_node *child, *node = fg->dev->of_node; u32 base; u8 subtype; int rc; if (of_get_available_child_count(node) == 0) { dev_err(fg->dev, "No child nodes specified!\n"); return -ENXIO; Loading Loading @@ -4878,36 +5064,62 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) } } /* Read all the optional properties below */ rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp); return 0; } #define DEFAULT_CUTOFF_VOLT_MV 3100 #define DEFAULT_EMPTY_VOLT_MV 2812 #define DEFAULT_SYS_MIN_VOLT_MV 2800 #define DEFAULT_SYS_TERM_CURR_MA -125 #define DEFAULT_CUTOFF_CURR_MA 200 #define DEFAULT_DELTA_SOC_THR 5 /* 0.5 % */ #define DEFAULT_ESR_PULSE_THRESH_MA 47 #define DEFAULT_ESR_MEAS_CURR_MA 120 static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; struct device_node *node = fg->dev->of_node; u32 temp; int rc; if (!node) { dev_err(fg->dev, "device tree node missing\n"); return -ENXIO; } rc = fg_gen4_parse_revid_dt(chip); if (rc < 0) chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV; else chip->dt.cutoff_volt_mv = temp; return rc; rc = of_property_read_u32(node, "qcom,fg-cutoff-current", &temp); rc = fg_gen4_parse_nvmem_dt(chip); if (rc < 0) chip->dt.cutoff_curr_ma = DEFAULT_CUTOFF_CURR_MA; else chip->dt.cutoff_curr_ma = temp; return rc; rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp); rc = fg_gen4_parse_child_nodes_dt(chip); if (rc < 0) return rc; /* Read all the optional properties below */ chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV; of_property_read_u32(node, "qcom,fg-cutoff-voltage", &chip->dt.cutoff_volt_mv); chip->dt.cutoff_curr_ma = DEFAULT_CUTOFF_CURR_MA; of_property_read_u32(node, "qcom,fg-cutoff-current", &chip->dt.cutoff_curr_ma); chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV; else chip->dt.empty_volt_mv = temp; of_property_read_u32(node, "qcom,fg-empty-voltage", &chip->dt.empty_volt_mv); rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp); if (rc < 0) chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA; else chip->dt.sys_term_curr_ma = temp; of_property_read_u32(node, "qcom,fg-sys-term-current", &chip->dt.sys_term_curr_ma); rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp); if (rc < 0) chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR; else chip->dt.delta_soc_thr = temp; of_property_read_u32(node, "qcom,fg-delta-soc-thr", &chip->dt.delta_soc_thr); chip->dt.esr_timer_chg_fast[TIMER_RETRY] = -EINVAL; chip->dt.esr_timer_chg_fast[TIMER_MAX] = -EINVAL; Loading Loading @@ -4942,58 +5154,7 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) chip->dt.force_load_profile = of_property_read_bool(node, "qcom,fg-force-load-profile"); rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp); if (rc < 0) chip->cl->dt.max_start_soc = DEFAULT_CL_START_SOC; else chip->cl->dt.max_start_soc = temp; chip->cl->dt.min_delta_batt_soc = DEFAULT_CL_DELTA_BATT_SOC; /* read from DT property and update, if value exists */ of_property_read_u32(node, "qcom,cl-min-delta-batt-soc", &chip->cl->dt.min_delta_batt_soc); chip->cl->dt.cl_wt_enable = of_property_read_bool(node, "qcom,cl-wt-enable"); rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp); if (rc < 0) chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC; else chip->cl->dt.min_temp = temp; rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp); if (rc < 0) chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC; else chip->cl->dt.max_temp = temp; rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp); if (rc < 0) chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC; else chip->cl->dt.max_cap_inc = temp; rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp); if (rc < 0) chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC; else chip->cl->dt.max_cap_dec = temp; rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp); if (rc < 0) chip->cl->dt.min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC; else chip->cl->dt.min_cap_limit = temp; rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp); if (rc < 0) chip->cl->dt.max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC; else chip->cl->dt.max_cap_limit = temp; of_property_read_u32(node, "qcom,cl-skew", &chip->cl->dt.skew_decipct); fg_gen4_parse_cl_params_dt(chip); fg_gen4_parse_batt_temp_dt(chip); chip->dt.hold_soc_while_full = of_property_read_bool(node, Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +15 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,19 @@ First Level Node - FG Gen4 device - #thermal-sensor-cells: Should be 0. See thermal.txt for the description. - nvmem-names: Usage: optional Value type: <string> Definition: Nvmem device name for SDAM to store parameters like cycle counters and learned capacity. It must be defined as "fg_sdam". - nvmem: Usage: optional Value type: <phandle> Definition: Phandle of the nvmem device name to access SDAM to store parameters. - qcom,fg-cutoff-voltage Usage: optional Value type: <u32> Loading Loading @@ -487,6 +500,8 @@ pm8150b_fg: qpnp,fg { #address-cells = <1>; #size-cells = <1>; qcom,pmic-revid = <&pm8150b_revid>; nvmem-names = "fg_sdam"; nvmem = <&pm8150_sdam_2>; #thermal-sensor-cells = <0>; status = "okay"; Loading
arch/arm64/boot/dts/qcom/kona-pmic-overlay.dtsi +5 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,11 @@ pinctrl-1 = <&qnovo_fet_ctrl_state2>; }; &pm8150b_fg { nvmem-names = "fg_sdam"; nvmem = <&pm8150_sdam_2>; }; &pm8150b_charger { dpdm-supply = <&usb2_phy0>; smb5_vconn: qcom,smb5-vconn { Loading
drivers/power/supply/qcom/qpnp-fg-gen4.c +272 −111 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ #include <linux/alarmtimer.h> #include <linux/irq.h> #include <linux/ktime.h> #include <linux/nvmem-consumer.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_batterydata.h> Loading @@ -27,6 +28,12 @@ #define FG_MEM_IF_PM8150B 0x0D #define FG_ADC_RR_PM8150B 0x13 #define SDAM_COOKIE_OFFSET 0x80 #define SDAM_CYCLE_COUNT_OFFSET 0x81 #define SDAM_CAP_LEARN_OFFSET 0x91 #define SDAM_COOKIE 0xA5 #define SDAM_FG_PARAM_LENGTH 20 #define FG_SRAM_LEN 972 #define PROFILE_LEN 416 #define PROFILE_COMP_LEN 24 Loading Loading @@ -231,6 +238,7 @@ struct fg_gen4_chip { struct cycle_counter *counter; struct cap_learning *cl; struct ttf *ttf; struct nvmem_device *fg_nvmem; struct votable *delta_esr_irq_en_votable; struct votable *pl_disable_votable; struct votable *cp_disable_votable; Loading Loading @@ -589,17 +597,25 @@ static int fg_gen4_get_learned_capacity(void *data, int64_t *learned_cap_uah) struct fg_gen4_chip *chip = data; struct fg_dev *fg; int rc, act_cap_mah; u8 buf[2]; if (!chip) return -ENODEV; fg = &chip->fg; if (chip->fg_nvmem) rc = nvmem_device_read(chip->fg_nvmem, SDAM_CAP_LEARN_OFFSET, 2, buf); else rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); if (rc < 0) { pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc); pr_err("Error in getting learned capacity, rc=%d\n", rc); return rc; } if (chip->fg_nvmem) *learned_cap_uah = (buf[0] | buf[1] << 8) * 1000; else *learned_cap_uah = act_cap_mah * 1000; fg_dbg(fg, FG_CAP_LEARN, "learned_cap_uah:%lld\n", *learned_cap_uah); Loading Loading @@ -951,6 +967,7 @@ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) struct fg_gen4_chip *chip = data; struct fg_dev *fg; int rc = 0, act_cap_mah, full_soc; u8 buf[2]; if (!chip) return -ENODEV; Loading @@ -970,12 +987,20 @@ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) rc = fg_get_battery_current(fg, val); break; case TTF_FCC: rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); if (chip->fg_nvmem) rc = nvmem_device_read(chip->fg_nvmem, SDAM_CAP_LEARN_OFFSET, 2, buf); else rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); if (rc < 0) { pr_err("Failed to get ACT_BATT_CAP rc=%d\n", rc); break; } if (chip->fg_nvmem) act_cap_mah = buf[0] | buf[1] << 8; rc = fg_get_sram_prop(fg, FG_SRAM_FULL_SOC, &full_soc); if (rc < 0) { pr_err("Failed to get FULL_SOC rc=%d\n", rc); Loading Loading @@ -1024,6 +1049,7 @@ static int fg_gen4_store_learned_capacity(void *data, int64_t learned_cap_uah) struct fg_dev *fg; int16_t cc_mah; int rc; u8 cookie = SDAM_COOKIE; if (!chip) return -ENODEV; Loading @@ -1041,6 +1067,23 @@ static int fg_gen4_store_learned_capacity(void *data, int64_t learned_cap_uah) return rc; } if (chip->fg_nvmem) { rc = nvmem_device_write(chip->fg_nvmem, SDAM_CAP_LEARN_OFFSET, 2, (u8 *)&cc_mah); if (rc < 0) { pr_err("Error in writing learned capacity to SDAM, rc=%d\n", rc); return rc; } rc = nvmem_device_write(chip->fg_nvmem, SDAM_COOKIE_OFFSET, 1, &cookie); if (rc < 0) { pr_err("Error in writing cookie to SDAM, rc=%d\n", rc); return rc; } } fg_dbg(fg, FG_CAP_LEARN, "learned capacity %llduah/%dmah stored\n", chip->cl->learned_cap_uah, cc_mah); return 0; Loading Loading @@ -1106,6 +1149,10 @@ static int fg_gen4_restore_count(void *data, u16 *buf, int length) return -EINVAL; for (id = 0; id < length; id++) { if (chip->fg_nvmem) rc = nvmem_device_read(chip->fg_nvmem, SDAM_CYCLE_COUNT_OFFSET + (id * 2), 2, tmp); else rc = fg_sram_read(&chip->fg, CYCLE_COUNT_WORD + id, CYCLE_COUNT_OFFSET, (u8 *)tmp, 2, FG_IMA_DEFAULT); Loading @@ -1130,8 +1177,13 @@ static int fg_gen4_store_count(void *data, u16 *buf, int id, int length) id > BUCKET_COUNT - 1 || ((id * 2) + length) > BUCKET_COUNT * 2) return -EINVAL; rc = fg_sram_write(&chip->fg, CYCLE_COUNT_WORD + id, CYCLE_COUNT_OFFSET, (u8 *)buf, length, FG_IMA_DEFAULT); if (chip->fg_nvmem) rc = nvmem_device_write(chip->fg_nvmem, SDAM_CYCLE_COUNT_OFFSET + (id * 2), length, (u8 *)buf); else rc = fg_sram_write(&chip->fg, CYCLE_COUNT_WORD + id, CYCLE_COUNT_OFFSET, (u8 *)buf, length, FG_IMA_DEFAULT); if (rc < 0) pr_err("failed to write bucket %d rc=%d\n", id, rc); Loading Loading @@ -1995,6 +2047,84 @@ static int qpnp_fg_gen4_load_profile(struct fg_gen4_chip *chip) return 0; } static bool is_sdam_cookie_set(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc; u8 cookie; rc = nvmem_device_read(chip->fg_nvmem, SDAM_COOKIE_OFFSET, 1, &cookie); if (rc < 0) { pr_err("Error in reading SDAM_COOKIE rc=%d\n", rc); return false; } fg_dbg(fg, FG_STATUS, "cookie: %x\n", cookie); return (cookie == SDAM_COOKIE); } static void fg_gen4_clear_sdam(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; u8 buf[SDAM_FG_PARAM_LENGTH] = { 0 }; int rc; /* * Clear all bytes of SDAM used to store FG parameters when it is first * profile load so that the junk values would not be used. */ rc = nvmem_device_write(chip->fg_nvmem, SDAM_CYCLE_COUNT_OFFSET, SDAM_FG_PARAM_LENGTH, buf); if (rc < 0) pr_err("Error in clearing SDAM rc=%d\n", rc); else fg_dbg(fg, FG_STATUS, "Cleared SDAM\n"); } static void fg_gen4_post_profile_load(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc, act_cap_mah; u8 buf[16]; /* If SDAM cookie is not set, read back from SRAM and load it in SDAM */ if (chip->fg_nvmem && !is_sdam_cookie_set(chip)) { fg_gen4_clear_sdam(chip); rc = fg_sram_read(&chip->fg, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET, buf, 16, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading cycle counters from SRAM rc=%d\n", rc); } else { rc = nvmem_device_write(chip->fg_nvmem, SDAM_CYCLE_COUNT_OFFSET, 16, (u8 *)buf); if (rc < 0) pr_err("Error in writing cycle counters to SDAM rc=%d\n", rc); } rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); if (rc < 0) { pr_err("Error in getting learned capacity, rc=%d\n", rc); } else { rc = nvmem_device_write(chip->fg_nvmem, SDAM_CAP_LEARN_OFFSET, 2, (u8 *)&act_cap_mah); if (rc < 0) pr_err("Error in writing learned capacity to SDAM, rc=%d\n", rc); } } /* Restore the cycle counters so that it would be valid at this point */ rc = restore_cycle_count(chip->counter); if (rc < 0) pr_err("Error in restoring cycle_count, rc=%d\n", rc); } static void profile_load_work(struct work_struct *work) { struct fg_dev *fg = container_of(work, Loading Loading @@ -2028,8 +2158,11 @@ static void profile_load_work(struct work_struct *work) if (!is_profile_load_required(chip)) goto done; if (!chip->dt.multi_profile_load) if (!chip->dt.multi_profile_load) { clear_cycle_count(chip->counter); if (chip->fg_nvmem && !is_sdam_cookie_set(chip)) fg_gen4_clear_sdam(chip); } fg_dbg(fg, FG_STATUS, "profile loading started\n"); Loading @@ -2054,9 +2187,8 @@ static void profile_load_work(struct work_struct *work) pr_err("Error in reading %04x[%d] rc=%d\n", NOM_CAP_WORD, NOM_CAP_OFFSET, rc); } else { rc = fg_sram_write(fg, fg->sp[FG_SRAM_ACT_BATT_CAP].addr_word, fg->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, buf, fg->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT); nom_cap_uah = (buf[0] | buf[1] << 8) * 1000; rc = fg_gen4_store_learned_capacity(chip, nom_cap_uah); if (rc < 0) pr_err("Error in writing to ACT_BATT_CAP rc=%d\n", rc); } Loading @@ -2068,6 +2200,8 @@ static void profile_load_work(struct work_struct *work) chip->first_profile_load = true; } fg_gen4_post_profile_load(chip); rc = fg_gen4_bp_params_config(fg); if (rc < 0) pr_err("Error in configuring battery profile params, rc:%d\n", Loading Loading @@ -4520,12 +4654,6 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) if (rc < 0) return rc; rc = restore_cycle_count(chip->counter); if (rc < 0) { pr_err("Error in restoring cycle_count, rc=%d\n", rc); return rc; } chip->batt_age_level = chip->last_batt_age_level = -EINVAL; if (chip->dt.multi_profile_load) { rc = fg_sram_read(fg, BATT_AGE_LEVEL_WORD, Loading Loading @@ -4766,15 +4894,30 @@ static void fg_gen4_parse_batt_temp_dt(struct fg_gen4_chip *chip) rc = of_property_read_u32(node, "qcom,fg-batt-therm-freq", &temp); if (temp > 0 && temp <= 255) chip->dt.batt_therm_freq = temp; } static int fg_gen4_parse_nvmem_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc; if (of_find_property(fg->dev->of_node, "nvmem", NULL)) { chip->fg_nvmem = devm_nvmem_device_get(fg->dev, "fg_sdam"); if (IS_ERR_OR_NULL(chip->fg_nvmem)) { rc = PTR_ERR(chip->fg_nvmem); if (rc != -EPROBE_DEFER) { dev_err(fg->dev, "Couldn't get nvmem device, rc=%d\n", rc); return -ENODEV; } chip->fg_nvmem = NULL; return rc; } } return 0; } #define DEFAULT_CUTOFF_VOLT_MV 3100 #define DEFAULT_EMPTY_VOLT_MV 2812 #define DEFAULT_SYS_MIN_VOLT_MV 2800 #define DEFAULT_SYS_TERM_CURR_MA -125 #define DEFAULT_CUTOFF_CURR_MA 200 #define DEFAULT_DELTA_SOC_THR 5 /* 0.5 % */ #define DEFAULT_CL_START_SOC 15 #define DEFAULT_CL_MIN_TEMP_DECIDEGC 150 #define DEFAULT_CL_MAX_TEMP_DECIDEGC 500 Loading @@ -4783,22 +4926,54 @@ static void fg_gen4_parse_batt_temp_dt(struct fg_gen4_chip *chip) #define DEFAULT_CL_MIN_LIM_DECIPERC 0 #define DEFAULT_CL_MAX_LIM_DECIPERC 0 #define DEFAULT_CL_DELTA_BATT_SOC 10 #define DEFAULT_ESR_PULSE_THRESH_MA 47 #define DEFAULT_ESR_MEAS_CURR_MA 120 static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) static void fg_gen4_parse_cl_params_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; struct device_node *child, *revid_node, *node = fg->dev->of_node; u32 base, temp; u8 subtype; int rc; struct device_node *node = fg->dev->of_node; if (!node) { dev_err(fg->dev, "device tree node missing\n"); return -ENXIO; chip->cl->dt.max_start_soc = DEFAULT_CL_START_SOC; of_property_read_u32(node, "qcom,cl-start-capacity", &chip->cl->dt.max_start_soc); chip->cl->dt.min_delta_batt_soc = DEFAULT_CL_DELTA_BATT_SOC; /* read from DT property and update, if value exists */ of_property_read_u32(node, "qcom,cl-min-delta-batt-soc", &chip->cl->dt.min_delta_batt_soc); chip->cl->dt.cl_wt_enable = of_property_read_bool(node, "qcom,cl-wt-enable"); chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC; of_property_read_u32(node, "qcom,cl-min-temp", &chip->cl->dt.min_temp); chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC; of_property_read_u32(node, "qcom,cl-max-temp", &chip->cl->dt.max_temp); chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC; of_property_read_u32(node, "qcom,cl-max-increment", &chip->cl->dt.max_cap_inc); chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC; of_property_read_u32(node, "qcom,cl-max-decrement", &chip->cl->dt.max_cap_dec); chip->cl->dt.min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC; of_property_read_u32(node, "qcom,cl-min-limit", &chip->cl->dt.min_cap_limit); chip->cl->dt.max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC; of_property_read_u32(node, "qcom,cl-max-limit", &chip->cl->dt.max_cap_limit); of_property_read_u32(node, "qcom,cl-skew", &chip->cl->dt.skew_decipct); } static int fg_gen4_parse_revid_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; struct device_node *revid_node, *node = fg->dev->of_node; revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0); if (!revid_node) { pr_err("Missing qcom,pmic-revid property - driver failed\n"); Loading Loading @@ -4838,6 +5013,17 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) return -EINVAL; } return 0; } static int fg_gen4_parse_child_nodes_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; struct device_node *child, *node = fg->dev->of_node; u32 base; u8 subtype; int rc; if (of_get_available_child_count(node) == 0) { dev_err(fg->dev, "No child nodes specified!\n"); return -ENXIO; Loading Loading @@ -4878,36 +5064,62 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) } } /* Read all the optional properties below */ rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp); return 0; } #define DEFAULT_CUTOFF_VOLT_MV 3100 #define DEFAULT_EMPTY_VOLT_MV 2812 #define DEFAULT_SYS_MIN_VOLT_MV 2800 #define DEFAULT_SYS_TERM_CURR_MA -125 #define DEFAULT_CUTOFF_CURR_MA 200 #define DEFAULT_DELTA_SOC_THR 5 /* 0.5 % */ #define DEFAULT_ESR_PULSE_THRESH_MA 47 #define DEFAULT_ESR_MEAS_CURR_MA 120 static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; struct device_node *node = fg->dev->of_node; u32 temp; int rc; if (!node) { dev_err(fg->dev, "device tree node missing\n"); return -ENXIO; } rc = fg_gen4_parse_revid_dt(chip); if (rc < 0) chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV; else chip->dt.cutoff_volt_mv = temp; return rc; rc = of_property_read_u32(node, "qcom,fg-cutoff-current", &temp); rc = fg_gen4_parse_nvmem_dt(chip); if (rc < 0) chip->dt.cutoff_curr_ma = DEFAULT_CUTOFF_CURR_MA; else chip->dt.cutoff_curr_ma = temp; return rc; rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp); rc = fg_gen4_parse_child_nodes_dt(chip); if (rc < 0) return rc; /* Read all the optional properties below */ chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV; of_property_read_u32(node, "qcom,fg-cutoff-voltage", &chip->dt.cutoff_volt_mv); chip->dt.cutoff_curr_ma = DEFAULT_CUTOFF_CURR_MA; of_property_read_u32(node, "qcom,fg-cutoff-current", &chip->dt.cutoff_curr_ma); chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV; else chip->dt.empty_volt_mv = temp; of_property_read_u32(node, "qcom,fg-empty-voltage", &chip->dt.empty_volt_mv); rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp); if (rc < 0) chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA; else chip->dt.sys_term_curr_ma = temp; of_property_read_u32(node, "qcom,fg-sys-term-current", &chip->dt.sys_term_curr_ma); rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp); if (rc < 0) chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR; else chip->dt.delta_soc_thr = temp; of_property_read_u32(node, "qcom,fg-delta-soc-thr", &chip->dt.delta_soc_thr); chip->dt.esr_timer_chg_fast[TIMER_RETRY] = -EINVAL; chip->dt.esr_timer_chg_fast[TIMER_MAX] = -EINVAL; Loading Loading @@ -4942,58 +5154,7 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) chip->dt.force_load_profile = of_property_read_bool(node, "qcom,fg-force-load-profile"); rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp); if (rc < 0) chip->cl->dt.max_start_soc = DEFAULT_CL_START_SOC; else chip->cl->dt.max_start_soc = temp; chip->cl->dt.min_delta_batt_soc = DEFAULT_CL_DELTA_BATT_SOC; /* read from DT property and update, if value exists */ of_property_read_u32(node, "qcom,cl-min-delta-batt-soc", &chip->cl->dt.min_delta_batt_soc); chip->cl->dt.cl_wt_enable = of_property_read_bool(node, "qcom,cl-wt-enable"); rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp); if (rc < 0) chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC; else chip->cl->dt.min_temp = temp; rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp); if (rc < 0) chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC; else chip->cl->dt.max_temp = temp; rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp); if (rc < 0) chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC; else chip->cl->dt.max_cap_inc = temp; rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp); if (rc < 0) chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC; else chip->cl->dt.max_cap_dec = temp; rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp); if (rc < 0) chip->cl->dt.min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC; else chip->cl->dt.min_cap_limit = temp; rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp); if (rc < 0) chip->cl->dt.max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC; else chip->cl->dt.max_cap_limit = temp; of_property_read_u32(node, "qcom,cl-skew", &chip->cl->dt.skew_decipct); fg_gen4_parse_cl_params_dt(chip); fg_gen4_parse_batt_temp_dt(chip); chip->dt.hold_soc_while_full = of_property_read_bool(node, Loading