Loading drivers/power/supply/qcom/qg-core.h +7 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. */ #ifndef __QG_CORE_H__ Loading Loading @@ -125,6 +125,7 @@ struct qpnp_qg { /* status variable */ u32 *debug_mask; u32 qg_version; bool qg_device_open; bool profile_loaded; bool battery_missing; Loading Loading @@ -167,6 +168,7 @@ struct qpnp_qg { u32 s2_state_mask; u32 soc_fvss_entry; u32 vbat_fvss_entry; u32 max_fifo_length; ktime_t last_user_update_time; ktime_t last_fifo_update_time; unsigned long last_maint_soc_update_time; Loading Loading @@ -254,5 +256,9 @@ enum qg_wa_flags { QG_PON_OCV_WA = BIT(3), }; enum qg_version { QG_PMIC5, QG_LITE, }; #endif /* __QG_CORE_H__ */ drivers/power/supply/qcom/qg-reg.h +1 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #define ESR_MEAS_DONE_BIT BIT(4) #define QG_STATUS2_REG 0x09 #define BATTERY_MISSING_BIT BIT(3) #define GOOD_OCV_BIT BIT(1) #define QG_STATUS3_REG 0x0A Loading drivers/power/supply/qcom/qpnp-qg.c +92 −33 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_batterydata.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/power_supply.h> #include <linux/regmap.h> Loading Loading @@ -98,14 +99,25 @@ static int qg_load_battery_profile(struct qpnp_qg *chip); static bool is_battery_present(struct qpnp_qg *chip) { bool present = true; u8 reg = 0; int rc; if (chip->qg_version == QG_LITE) { rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, ®, 1); if (rc < 0) pr_err("Failed to read battery presence, rc=%d\n", rc); else present = !(reg & BATTERY_MISSING_BIT); } else { rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, ®, 1); if (rc < 0) pr_err("Failed to read battery presence, rc=%d\n", rc); else present = !!(reg & BATTERY_PRESENT_BIT); } return !!(reg & BATTERY_PRESENT_BIT); return present; } #define DEBUG_BATT_ID_LOW 6000 Loading Loading @@ -175,7 +187,7 @@ static int qg_update_fifo_length(struct qpnp_qg *chip, u8 length) int rc; u8 s3_entry_fifo_length = 0; if (!length || length > 8) { if (!length || length > chip->max_fifo_length) { pr_err("Invalid FIFO length %d\n", length); return -EINVAL; } Loading Loading @@ -683,7 +695,7 @@ static int qg_vbat_low_wa(struct qpnp_qg *chip) int rc, i, temp = 0; u32 vbat_low_uv = 0; if ((chip->wa_flags & QG_VBAT_LOW_WA) && chip->vbat_low) { if (chip->wa_flags & QG_VBAT_LOW_WA) { rc = qg_get_battery_temp(chip, &temp); if (rc < 0) { pr_err("Failed to read batt_temp rc=%d\n", rc); Loading @@ -693,19 +705,19 @@ static int qg_vbat_low_wa(struct qpnp_qg *chip) vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ? chip->dt.vbatt_low_cold_mv : chip->dt.vbatt_low_mv); vbat_low_uv += VBAT_LOW_HYST_UV; /* * PMI632 1.0 does not generate a falling VBAT_LOW IRQ. * To exit from VBAT_LOW config, check if any of the FIFO * averages is > vbat_low threshold and reconfigure the * FIFO length to normal. */ for (i = 0; i < chip->kdata.fifo_length; i++) { if (chip->kdata.fifo[i].v > vbat_low_uv) { if ((chip->kdata.fifo[i].v > (vbat_low_uv + VBAT_LOW_HYST_UV)) && chip->vbat_low) { chip->vbat_low = false; pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n", chip->kdata.fifo[i].v, vbat_low_uv, chip->dt.s2_fifo_length); pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV\n", chip->kdata.fifo[i].v, vbat_low_uv); break; } else if ((chip->kdata.fifo[i].v < vbat_low_uv) && !chip->vbat_low) { chip->vbat_low = true; pr_info("Enter VBAT_LOW vbat_avg=%duV vbat_low=%duV\n", chip->kdata.fifo[i].v, vbat_low_uv); break; } } Loading Loading @@ -757,6 +769,9 @@ static int qg_vbat_thresholds_config(struct qpnp_qg *chip) vbat_mv, temp); config_vbat_low: if (chip->qg_version == QG_LITE) return 0; vbat_mv = (temp < chip->dt.cold_temp_threshold) ? chip->dt.vbatt_low_cold_mv : chip->dt.vbatt_low_mv; Loading Loading @@ -3327,6 +3342,11 @@ static int qg_set_wa_flags(struct qpnp_qg *chip) case PM7250B_SUBTYPE: qg_esr_mod_count = 10; break; case PM2250_SUBTYPE: chip->wa_flags |= QG_CLK_ADJUST_WA | QG_RECHARGE_SOC_WA | QG_VBAT_LOW_WA; break; default: pr_err("Unsupported PMIC subtype %d\n", chip->pmic_rev_id->pmic_subtype); Loading Loading @@ -3379,6 +3399,9 @@ static int qg_hw_init(struct qpnp_qg *chip) int rc, temp; u8 reg; /* read STATUS2 register to clear its last state */ qg_read(chip, chip->qg_base + QG_STATUS2_REG, ®, 1); /* read the QG perph_subtype */ rc = qg_read(chip, chip->qg_base + PERPH_SUBTYPE_REG, &chip->qg_subtype, 1); Loading Loading @@ -3453,7 +3476,8 @@ static int qg_hw_init(struct qpnp_qg *chip) } chip->last_fifo_update_time = ktime_get_boottime(); if (chip->dt.ocv_timer_expiry_min != -EINVAL) { if (chip->dt.ocv_timer_expiry_min != -EINVAL && chip->qg_version != QG_LITE) { if (chip->dt.ocv_timer_expiry_min < 2) chip->dt.ocv_timer_expiry_min = 2; else if (chip->dt.ocv_timer_expiry_min > 30) Loading Loading @@ -3488,8 +3512,10 @@ static int qg_hw_init(struct qpnp_qg *chip) if (chip->dt.s3_entry_fifo_length != -EINVAL) { if (chip->dt.s3_entry_fifo_length < 1) chip->dt.s3_entry_fifo_length = 1; else if (chip->dt.s3_entry_fifo_length > 8) chip->dt.s3_entry_fifo_length = 8; else if (chip->dt.s3_entry_fifo_length > chip->max_fifo_length) chip->dt.s3_entry_fifo_length = chip->max_fifo_length; reg = chip->dt.s3_entry_fifo_length - 1; rc = qg_masked_write(chip, Loading Loading @@ -3569,12 +3595,14 @@ static int qg_hw_init(struct qpnp_qg *chip) return rc; } if (chip->qg_version != QG_LITE) { /* disable S5 */ rc = qg_masked_write(chip, chip->qg_base + QG_S5_OCV_VALIDATE_MEAS_CTL1_REG, ALLOW_S5_BIT, 0); if (rc < 0) pr_err("Failed to disable S5 rc=%d\n", rc); } /* change PON OCV time to 512ms */ rc = qg_masked_write(chip, chip->qg_base + Loading Loading @@ -3624,7 +3652,6 @@ static int qg_soh_batt_profile_init(struct qpnp_qg *chip) static int qg_post_init(struct qpnp_qg *chip) { u8 status = 0; int rc = 0; /* disable all IRQs if profile is not loaded */ Loading @@ -3641,9 +3668,6 @@ static int qg_post_init(struct qpnp_qg *chip) if (!chip->dt.esr_disable) qg_retrieve_esr_params(chip); /* read STATUS2 register to clear its last state */ qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1); /*soh based multi profile init */ rc = qg_soh_batt_profile_init(chip); if (rc < 0) { Loading Loading @@ -3856,6 +3880,13 @@ static int qg_parse_s2_dt(struct qpnp_qg *chip) else chip->dt.s2_fifo_length = temp; if (chip->dt.s2_fifo_length > chip->max_fifo_length) { pr_err("Invalid S2 fifo-length=%d max_length=%d\n", chip->dt.s2_fifo_length, chip->max_fifo_length); return -EINVAL; } rc = of_property_read_u32(node, "qcom,s2-vbat-low-fifo-length", &temp); if (rc < 0) chip->dt.s2_vbat_low_fifo_length = DEFAULT_S2_VBAT_LOW_LENGTH; Loading Loading @@ -3890,6 +3921,13 @@ static int qg_parse_s2_dt(struct qpnp_qg *chip) else chip->dt.sleep_s2_fifo_length = temp; if (chip->dt.s2_fifo_length > chip->max_fifo_length) { pr_err("Invalid S2 sleep-fifo-length=%d max_length=%d\n", chip->dt.sleep_s2_fifo_length, chip->max_fifo_length); return -EINVAL; } rc = of_property_read_u32(node, "qcom,sleep-s2-acc-length", &temp); if (rc < 0) Loading Loading @@ -3918,6 +3956,13 @@ static int qg_parse_s2_dt(struct qpnp_qg *chip) DEFAULT_FAST_CHG_S2_FIFO_LENGTH; else chip->dt.fast_chg_s2_fifo_length = temp; if (chip->dt.fast_chg_s2_fifo_length > chip->max_fifo_length) { pr_err("Invalid S2 fast-fifo-length=%d max_length=%d\n", chip->dt.fast_chg_s2_fifo_length, chip->max_fifo_length); return -EINVAL; } } return 0; Loading Loading @@ -4598,6 +4643,17 @@ static int qpnp_qg_probe(struct platform_device *pdev) chip->esr_nominal = -EINVAL; chip->batt_age_level = -EINVAL; chip->qg_version = (u8)of_device_get_match_data(&pdev->dev); switch (chip->qg_version) { case QG_LITE: chip->max_fifo_length = 5; break; default: chip->max_fifo_length = 8; break; } qg_create_debugfs(chip); rc = qg_alg_init(chip); Loading Loading @@ -4737,8 +4793,10 @@ static int qpnp_qg_probe(struct platform_device *pdev) } qg_get_battery_capacity(chip, &soc); pr_info("QG initialized! battery_profile=%s SOC=%d QG_subtype=%d\n", qg_get_battery_type(chip), soc, chip->qg_subtype); pr_info("QG initialized! battery_profile=%s SOC=%d QG_subtype=%d QG_version=%s\n", qg_get_battery_type(chip), soc, chip->qg_subtype, (chip->qg_version == QG_LITE) ? "QG_LITE" : "QG_PMIC5"); return rc; Loading Loading @@ -4793,7 +4851,8 @@ static void qpnp_qg_shutdown(struct platform_device *pdev) } static const struct of_device_id match_table[] = { { .compatible = "qcom,qpnp-qg", }, { .compatible = "qcom,qpnp-qg", .data = (void *)QG_PMIC5, }, { .compatible = "qcom,qpnp-qg-lite", .data = (void *)QG_LITE, }, { }, }; Loading Loading
drivers/power/supply/qcom/qg-core.h +7 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. */ #ifndef __QG_CORE_H__ Loading Loading @@ -125,6 +125,7 @@ struct qpnp_qg { /* status variable */ u32 *debug_mask; u32 qg_version; bool qg_device_open; bool profile_loaded; bool battery_missing; Loading Loading @@ -167,6 +168,7 @@ struct qpnp_qg { u32 s2_state_mask; u32 soc_fvss_entry; u32 vbat_fvss_entry; u32 max_fifo_length; ktime_t last_user_update_time; ktime_t last_fifo_update_time; unsigned long last_maint_soc_update_time; Loading Loading @@ -254,5 +256,9 @@ enum qg_wa_flags { QG_PON_OCV_WA = BIT(3), }; enum qg_version { QG_PMIC5, QG_LITE, }; #endif /* __QG_CORE_H__ */
drivers/power/supply/qcom/qg-reg.h +1 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #define ESR_MEAS_DONE_BIT BIT(4) #define QG_STATUS2_REG 0x09 #define BATTERY_MISSING_BIT BIT(3) #define GOOD_OCV_BIT BIT(1) #define QG_STATUS3_REG 0x0A Loading
drivers/power/supply/qcom/qpnp-qg.c +92 −33 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_batterydata.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/power_supply.h> #include <linux/regmap.h> Loading Loading @@ -98,14 +99,25 @@ static int qg_load_battery_profile(struct qpnp_qg *chip); static bool is_battery_present(struct qpnp_qg *chip) { bool present = true; u8 reg = 0; int rc; if (chip->qg_version == QG_LITE) { rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, ®, 1); if (rc < 0) pr_err("Failed to read battery presence, rc=%d\n", rc); else present = !(reg & BATTERY_MISSING_BIT); } else { rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, ®, 1); if (rc < 0) pr_err("Failed to read battery presence, rc=%d\n", rc); else present = !!(reg & BATTERY_PRESENT_BIT); } return !!(reg & BATTERY_PRESENT_BIT); return present; } #define DEBUG_BATT_ID_LOW 6000 Loading Loading @@ -175,7 +187,7 @@ static int qg_update_fifo_length(struct qpnp_qg *chip, u8 length) int rc; u8 s3_entry_fifo_length = 0; if (!length || length > 8) { if (!length || length > chip->max_fifo_length) { pr_err("Invalid FIFO length %d\n", length); return -EINVAL; } Loading Loading @@ -683,7 +695,7 @@ static int qg_vbat_low_wa(struct qpnp_qg *chip) int rc, i, temp = 0; u32 vbat_low_uv = 0; if ((chip->wa_flags & QG_VBAT_LOW_WA) && chip->vbat_low) { if (chip->wa_flags & QG_VBAT_LOW_WA) { rc = qg_get_battery_temp(chip, &temp); if (rc < 0) { pr_err("Failed to read batt_temp rc=%d\n", rc); Loading @@ -693,19 +705,19 @@ static int qg_vbat_low_wa(struct qpnp_qg *chip) vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ? chip->dt.vbatt_low_cold_mv : chip->dt.vbatt_low_mv); vbat_low_uv += VBAT_LOW_HYST_UV; /* * PMI632 1.0 does not generate a falling VBAT_LOW IRQ. * To exit from VBAT_LOW config, check if any of the FIFO * averages is > vbat_low threshold and reconfigure the * FIFO length to normal. */ for (i = 0; i < chip->kdata.fifo_length; i++) { if (chip->kdata.fifo[i].v > vbat_low_uv) { if ((chip->kdata.fifo[i].v > (vbat_low_uv + VBAT_LOW_HYST_UV)) && chip->vbat_low) { chip->vbat_low = false; pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n", chip->kdata.fifo[i].v, vbat_low_uv, chip->dt.s2_fifo_length); pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV\n", chip->kdata.fifo[i].v, vbat_low_uv); break; } else if ((chip->kdata.fifo[i].v < vbat_low_uv) && !chip->vbat_low) { chip->vbat_low = true; pr_info("Enter VBAT_LOW vbat_avg=%duV vbat_low=%duV\n", chip->kdata.fifo[i].v, vbat_low_uv); break; } } Loading Loading @@ -757,6 +769,9 @@ static int qg_vbat_thresholds_config(struct qpnp_qg *chip) vbat_mv, temp); config_vbat_low: if (chip->qg_version == QG_LITE) return 0; vbat_mv = (temp < chip->dt.cold_temp_threshold) ? chip->dt.vbatt_low_cold_mv : chip->dt.vbatt_low_mv; Loading Loading @@ -3327,6 +3342,11 @@ static int qg_set_wa_flags(struct qpnp_qg *chip) case PM7250B_SUBTYPE: qg_esr_mod_count = 10; break; case PM2250_SUBTYPE: chip->wa_flags |= QG_CLK_ADJUST_WA | QG_RECHARGE_SOC_WA | QG_VBAT_LOW_WA; break; default: pr_err("Unsupported PMIC subtype %d\n", chip->pmic_rev_id->pmic_subtype); Loading Loading @@ -3379,6 +3399,9 @@ static int qg_hw_init(struct qpnp_qg *chip) int rc, temp; u8 reg; /* read STATUS2 register to clear its last state */ qg_read(chip, chip->qg_base + QG_STATUS2_REG, ®, 1); /* read the QG perph_subtype */ rc = qg_read(chip, chip->qg_base + PERPH_SUBTYPE_REG, &chip->qg_subtype, 1); Loading Loading @@ -3453,7 +3476,8 @@ static int qg_hw_init(struct qpnp_qg *chip) } chip->last_fifo_update_time = ktime_get_boottime(); if (chip->dt.ocv_timer_expiry_min != -EINVAL) { if (chip->dt.ocv_timer_expiry_min != -EINVAL && chip->qg_version != QG_LITE) { if (chip->dt.ocv_timer_expiry_min < 2) chip->dt.ocv_timer_expiry_min = 2; else if (chip->dt.ocv_timer_expiry_min > 30) Loading Loading @@ -3488,8 +3512,10 @@ static int qg_hw_init(struct qpnp_qg *chip) if (chip->dt.s3_entry_fifo_length != -EINVAL) { if (chip->dt.s3_entry_fifo_length < 1) chip->dt.s3_entry_fifo_length = 1; else if (chip->dt.s3_entry_fifo_length > 8) chip->dt.s3_entry_fifo_length = 8; else if (chip->dt.s3_entry_fifo_length > chip->max_fifo_length) chip->dt.s3_entry_fifo_length = chip->max_fifo_length; reg = chip->dt.s3_entry_fifo_length - 1; rc = qg_masked_write(chip, Loading Loading @@ -3569,12 +3595,14 @@ static int qg_hw_init(struct qpnp_qg *chip) return rc; } if (chip->qg_version != QG_LITE) { /* disable S5 */ rc = qg_masked_write(chip, chip->qg_base + QG_S5_OCV_VALIDATE_MEAS_CTL1_REG, ALLOW_S5_BIT, 0); if (rc < 0) pr_err("Failed to disable S5 rc=%d\n", rc); } /* change PON OCV time to 512ms */ rc = qg_masked_write(chip, chip->qg_base + Loading Loading @@ -3624,7 +3652,6 @@ static int qg_soh_batt_profile_init(struct qpnp_qg *chip) static int qg_post_init(struct qpnp_qg *chip) { u8 status = 0; int rc = 0; /* disable all IRQs if profile is not loaded */ Loading @@ -3641,9 +3668,6 @@ static int qg_post_init(struct qpnp_qg *chip) if (!chip->dt.esr_disable) qg_retrieve_esr_params(chip); /* read STATUS2 register to clear its last state */ qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1); /*soh based multi profile init */ rc = qg_soh_batt_profile_init(chip); if (rc < 0) { Loading Loading @@ -3856,6 +3880,13 @@ static int qg_parse_s2_dt(struct qpnp_qg *chip) else chip->dt.s2_fifo_length = temp; if (chip->dt.s2_fifo_length > chip->max_fifo_length) { pr_err("Invalid S2 fifo-length=%d max_length=%d\n", chip->dt.s2_fifo_length, chip->max_fifo_length); return -EINVAL; } rc = of_property_read_u32(node, "qcom,s2-vbat-low-fifo-length", &temp); if (rc < 0) chip->dt.s2_vbat_low_fifo_length = DEFAULT_S2_VBAT_LOW_LENGTH; Loading Loading @@ -3890,6 +3921,13 @@ static int qg_parse_s2_dt(struct qpnp_qg *chip) else chip->dt.sleep_s2_fifo_length = temp; if (chip->dt.s2_fifo_length > chip->max_fifo_length) { pr_err("Invalid S2 sleep-fifo-length=%d max_length=%d\n", chip->dt.sleep_s2_fifo_length, chip->max_fifo_length); return -EINVAL; } rc = of_property_read_u32(node, "qcom,sleep-s2-acc-length", &temp); if (rc < 0) Loading Loading @@ -3918,6 +3956,13 @@ static int qg_parse_s2_dt(struct qpnp_qg *chip) DEFAULT_FAST_CHG_S2_FIFO_LENGTH; else chip->dt.fast_chg_s2_fifo_length = temp; if (chip->dt.fast_chg_s2_fifo_length > chip->max_fifo_length) { pr_err("Invalid S2 fast-fifo-length=%d max_length=%d\n", chip->dt.fast_chg_s2_fifo_length, chip->max_fifo_length); return -EINVAL; } } return 0; Loading Loading @@ -4598,6 +4643,17 @@ static int qpnp_qg_probe(struct platform_device *pdev) chip->esr_nominal = -EINVAL; chip->batt_age_level = -EINVAL; chip->qg_version = (u8)of_device_get_match_data(&pdev->dev); switch (chip->qg_version) { case QG_LITE: chip->max_fifo_length = 5; break; default: chip->max_fifo_length = 8; break; } qg_create_debugfs(chip); rc = qg_alg_init(chip); Loading Loading @@ -4737,8 +4793,10 @@ static int qpnp_qg_probe(struct platform_device *pdev) } qg_get_battery_capacity(chip, &soc); pr_info("QG initialized! battery_profile=%s SOC=%d QG_subtype=%d\n", qg_get_battery_type(chip), soc, chip->qg_subtype); pr_info("QG initialized! battery_profile=%s SOC=%d QG_subtype=%d QG_version=%s\n", qg_get_battery_type(chip), soc, chip->qg_subtype, (chip->qg_version == QG_LITE) ? "QG_LITE" : "QG_PMIC5"); return rc; Loading Loading @@ -4793,7 +4851,8 @@ static void qpnp_qg_shutdown(struct platform_device *pdev) } static const struct of_device_id match_table[] = { { .compatible = "qcom,qpnp-qg", }, { .compatible = "qcom,qpnp-qg", .data = (void *)QG_PMIC5, }, { .compatible = "qcom,qpnp-qg-lite", .data = (void *)QG_LITE, }, { }, }; Loading