Loading drivers/of/of_batterydata.c +130 −0 Original line number Diff line number Diff line Loading @@ -468,6 +468,136 @@ struct device_node *of_batterydata_get_best_aged_profile( return best_node; } int of_batterydata_get_aged_profile_count( const struct device_node *batterydata_node, int batt_id_kohm, int *count) { struct device_node *node; int id_range_pct, i = 0, rc = 0, limit = 0, delta = 0; bool in_range = false; u32 batt_id; /* read battery id range percentage for best profile */ rc = of_property_read_u32(batterydata_node, "qcom,batt-id-range-pct", &id_range_pct); if (rc) { if (rc == -EINVAL) { id_range_pct = 0; } else { pr_err("failed to read battery id range\n"); return -ENXIO; } } for_each_available_child_of_node(batterydata_node, node) { if (!of_find_property(node, "qcom,batt-age-level", NULL)) continue; if (!of_find_property(node, "qcom,soh-range", NULL)) continue; rc = of_property_read_u32(node, "qcom,batt-id-kohm", &batt_id); if (rc) continue; delta = abs(batt_id_kohm - batt_id); limit = (batt_id_kohm * id_range_pct) / 100; in_range = (delta <= limit); if (!in_range) { pr_debug("not in range batt_id: %d\n", batt_id); continue; } i++; } if (i <= 1) { pr_err("Less number of profiles to support SOH\n"); return -EINVAL; } *count = i; return 0; } int of_batterydata_read_soh_aged_profiles( const struct device_node *batterydata_node, int batt_id_kohm, struct soh_range *soh_data) { struct device_node *node; u32 val, temp[2], i = 0; int rc, batt_id, id_range_pct, limit = 0, delta = 0; bool in_range = false; if (!batterydata_node || !soh_data) return -ENODEV; /* read battery id range percentage for best profile */ rc = of_property_read_u32(batterydata_node, "qcom,batt-id-range-pct", &id_range_pct); if (rc) { if (rc == -EINVAL) { id_range_pct = 0; } else { pr_err("failed to read battery id range\n"); return -ENXIO; } } for_each_available_child_of_node(batterydata_node, node) { rc = of_property_read_u32(node, "qcom,batt-age-level", &val); if (rc) continue; rc = of_property_read_u32(node, "qcom,batt-id-kohm", &batt_id); if (rc) continue; delta = abs(batt_id_kohm - batt_id); limit = (batt_id_kohm * id_range_pct) / 100; in_range = (delta <= limit); if (!in_range) { pr_debug("not in range batt_id: %d\n", batt_id); continue; } if (!of_find_property(node, "qcom,soh-range", NULL)) continue; rc = of_property_count_elems_of_size(node, "qcom,soh-range", sizeof(u32)); if (rc != 2) { pr_err("Incorrect element size for qcom,soh-range, rc=%d\n", rc); return -EINVAL; } rc = of_property_read_u32_array(node, "qcom,soh-range", temp, 2); if (rc < 0) { pr_err("Error in reading qcom,soh-range, rc=%d\n", rc); return rc; } if (temp[0] > 100 || temp[1] > 100 || (temp[0] > temp[1])) { pr_err("Incorrect SOH range [%d %d]\n", temp[0], temp[1]); return -ERANGE; } pr_debug("batt_age_level: %d soh: [%d %d]\n", val, temp[0], temp[1]); soh_data[i].batt_age_level = val; soh_data[i].soh_min = temp[0]; soh_data[i].soh_max = temp[1]; i++; } return 0; } int of_batterydata_read_data(struct device_node *batterydata_container_node, struct bms_battery_data *batt_data, int batt_id_uv) Loading include/linux/batterydata-lib.h +16 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved. * Copyright (c) 2012-2015, 2017, 2019 The Linux Foundation. * All rights reserved. */ #ifndef __BMS_BATTERYDATA_H Loading Loading @@ -137,6 +138,20 @@ struct bms_battery_data { const char *battery_type; }; /** * struct soh_range - * @batt_age_level: Battery age level (e.g. 0, 1 etc.,) * @soh_min: Minimum SOH (state of health) level that this battery * profile can support. * @soh_max: Maximum SOH (state of health) level that this battery * profile can support. */ struct soh_range { int batt_age_level; int soh_min; int soh_max; }; #define is_between(left, right, value) \ (((left) >= (right) && (left) >= (value) \ && (value) >= (right)) \ Loading include/linux/of_batterydata.h +39 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,33 @@ struct device_node *of_batterydata_get_best_profile( struct device_node *of_batterydata_get_best_aged_profile( const struct device_node *batterydata_container_node, int batt_id_kohm, int batt_age_level, int *avail_age_level); /** * of_batterydata_get_aged_profile_count() - Gets the number of aged profiles * @batterydata_node: pointer to the battery-data container device * node containing the profile nodes. * @batt_id_kohm: Battery ID in KOhms for which we want to find the profile. * @count: Number of aged profiles available to support SOH based profile * loading. * * This routine returns zero if valid number of aged profiles are available. */ int of_batterydata_get_aged_profile_count( const struct device_node *batterydata_node, int batt_id_kohm, int *count); /** * of_batterydata_read_soh_aged_profiles() - Reads the data from aged profiles * @batterydata_node: pointer to the battery-data container device * node containing the profile nodes. * @batt_id_kohm: Battery ID in KOhms for which we want to find the profile. * @soh_data: SOH data from the profile if it is found to be valid. * * This routine returns zero if SOH data of aged profiles is valid. */ int of_batterydata_read_soh_aged_profiles( const struct device_node *batterydata_node, int batt_id_kohm, struct soh_range *soh_data); #else static inline int of_batterydata_read_data(struct device_node *container_node, struct bms_battery_data *batt_data, Loading @@ -75,4 +102,16 @@ static inline struct device_node *of_batterydata_get_best_aged_profile( { return NULL; } static inline int of_batterydata_get_aged_profile_count( const struct device_node *batterydata_node, int batt_id_kohm, int *count) { return -EINVAL; } static inline int of_batterydata_read_soh_aged_profiles( const struct device_node *batterydata_node, int batt_id_kohm, struct soh_range *soh_data) { return -EINVAL; } #endif /* CONFIG_OF_BATTERYDATA */ Loading
drivers/of/of_batterydata.c +130 −0 Original line number Diff line number Diff line Loading @@ -468,6 +468,136 @@ struct device_node *of_batterydata_get_best_aged_profile( return best_node; } int of_batterydata_get_aged_profile_count( const struct device_node *batterydata_node, int batt_id_kohm, int *count) { struct device_node *node; int id_range_pct, i = 0, rc = 0, limit = 0, delta = 0; bool in_range = false; u32 batt_id; /* read battery id range percentage for best profile */ rc = of_property_read_u32(batterydata_node, "qcom,batt-id-range-pct", &id_range_pct); if (rc) { if (rc == -EINVAL) { id_range_pct = 0; } else { pr_err("failed to read battery id range\n"); return -ENXIO; } } for_each_available_child_of_node(batterydata_node, node) { if (!of_find_property(node, "qcom,batt-age-level", NULL)) continue; if (!of_find_property(node, "qcom,soh-range", NULL)) continue; rc = of_property_read_u32(node, "qcom,batt-id-kohm", &batt_id); if (rc) continue; delta = abs(batt_id_kohm - batt_id); limit = (batt_id_kohm * id_range_pct) / 100; in_range = (delta <= limit); if (!in_range) { pr_debug("not in range batt_id: %d\n", batt_id); continue; } i++; } if (i <= 1) { pr_err("Less number of profiles to support SOH\n"); return -EINVAL; } *count = i; return 0; } int of_batterydata_read_soh_aged_profiles( const struct device_node *batterydata_node, int batt_id_kohm, struct soh_range *soh_data) { struct device_node *node; u32 val, temp[2], i = 0; int rc, batt_id, id_range_pct, limit = 0, delta = 0; bool in_range = false; if (!batterydata_node || !soh_data) return -ENODEV; /* read battery id range percentage for best profile */ rc = of_property_read_u32(batterydata_node, "qcom,batt-id-range-pct", &id_range_pct); if (rc) { if (rc == -EINVAL) { id_range_pct = 0; } else { pr_err("failed to read battery id range\n"); return -ENXIO; } } for_each_available_child_of_node(batterydata_node, node) { rc = of_property_read_u32(node, "qcom,batt-age-level", &val); if (rc) continue; rc = of_property_read_u32(node, "qcom,batt-id-kohm", &batt_id); if (rc) continue; delta = abs(batt_id_kohm - batt_id); limit = (batt_id_kohm * id_range_pct) / 100; in_range = (delta <= limit); if (!in_range) { pr_debug("not in range batt_id: %d\n", batt_id); continue; } if (!of_find_property(node, "qcom,soh-range", NULL)) continue; rc = of_property_count_elems_of_size(node, "qcom,soh-range", sizeof(u32)); if (rc != 2) { pr_err("Incorrect element size for qcom,soh-range, rc=%d\n", rc); return -EINVAL; } rc = of_property_read_u32_array(node, "qcom,soh-range", temp, 2); if (rc < 0) { pr_err("Error in reading qcom,soh-range, rc=%d\n", rc); return rc; } if (temp[0] > 100 || temp[1] > 100 || (temp[0] > temp[1])) { pr_err("Incorrect SOH range [%d %d]\n", temp[0], temp[1]); return -ERANGE; } pr_debug("batt_age_level: %d soh: [%d %d]\n", val, temp[0], temp[1]); soh_data[i].batt_age_level = val; soh_data[i].soh_min = temp[0]; soh_data[i].soh_max = temp[1]; i++; } return 0; } int of_batterydata_read_data(struct device_node *batterydata_container_node, struct bms_battery_data *batt_data, int batt_id_uv) Loading
include/linux/batterydata-lib.h +16 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved. * Copyright (c) 2012-2015, 2017, 2019 The Linux Foundation. * All rights reserved. */ #ifndef __BMS_BATTERYDATA_H Loading Loading @@ -137,6 +138,20 @@ struct bms_battery_data { const char *battery_type; }; /** * struct soh_range - * @batt_age_level: Battery age level (e.g. 0, 1 etc.,) * @soh_min: Minimum SOH (state of health) level that this battery * profile can support. * @soh_max: Maximum SOH (state of health) level that this battery * profile can support. */ struct soh_range { int batt_age_level; int soh_min; int soh_max; }; #define is_between(left, right, value) \ (((left) >= (right) && (left) >= (value) \ && (value) >= (right)) \ Loading
include/linux/of_batterydata.h +39 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,33 @@ struct device_node *of_batterydata_get_best_profile( struct device_node *of_batterydata_get_best_aged_profile( const struct device_node *batterydata_container_node, int batt_id_kohm, int batt_age_level, int *avail_age_level); /** * of_batterydata_get_aged_profile_count() - Gets the number of aged profiles * @batterydata_node: pointer to the battery-data container device * node containing the profile nodes. * @batt_id_kohm: Battery ID in KOhms for which we want to find the profile. * @count: Number of aged profiles available to support SOH based profile * loading. * * This routine returns zero if valid number of aged profiles are available. */ int of_batterydata_get_aged_profile_count( const struct device_node *batterydata_node, int batt_id_kohm, int *count); /** * of_batterydata_read_soh_aged_profiles() - Reads the data from aged profiles * @batterydata_node: pointer to the battery-data container device * node containing the profile nodes. * @batt_id_kohm: Battery ID in KOhms for which we want to find the profile. * @soh_data: SOH data from the profile if it is found to be valid. * * This routine returns zero if SOH data of aged profiles is valid. */ int of_batterydata_read_soh_aged_profiles( const struct device_node *batterydata_node, int batt_id_kohm, struct soh_range *soh_data); #else static inline int of_batterydata_read_data(struct device_node *container_node, struct bms_battery_data *batt_data, Loading @@ -75,4 +102,16 @@ static inline struct device_node *of_batterydata_get_best_aged_profile( { return NULL; } static inline int of_batterydata_get_aged_profile_count( const struct device_node *batterydata_node, int batt_id_kohm, int *count) { return -EINVAL; } static inline int of_batterydata_read_soh_aged_profiles( const struct device_node *batterydata_node, int batt_id_kohm, struct soh_range *soh_data) { return -EINVAL; } #endif /* CONFIG_OF_BATTERYDATA */