Loading Documentation/devicetree/bindings/batterydata/batterydata.txt +2 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,8 @@ Profile data node optional properties: JEITA conditions (cool/warm). Element 0 - FV value for soft cool. Element 1 - FV value for soft warm. - qcom,batt-age-level: Battery age level. This is used only when multiple profile loading is supported. Profile data node required subnodes: - qcom,fcc-temp-lut : An 1-dimensional lookup table node that encodes temperature to fcc lookup. The units for this lookup Loading drivers/of/of_batterydata.c +78 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -398,6 +398,83 @@ struct device_node *of_batterydata_get_best_profile( return best_node; } 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) { struct batt_ids batt_ids; struct device_node *node, *best_node = NULL; const char *battery_type = NULL; int delta = 0, best_id_kohm = 0, id_range_pct, i = 0, rc = 0, limit = 0; u32 val; bool in_range = false; /* read battery id range percentage for best profile */ rc = of_property_read_u32(batterydata_container_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 ERR_PTR(-ENXIO); } } /* * Find the battery data with a battery id resistor closest to this one */ for_each_available_child_of_node(batterydata_container_node, node) { val = 0; of_property_read_u32(node, "qcom,batt-age-level", &val); rc = of_batterydata_read_batt_id_kohm(node, "qcom,batt-id-kohm", &batt_ids); if (rc) continue; for (i = 0; i < batt_ids.num; i++) { delta = abs(batt_ids.kohm[i] - batt_id_kohm); limit = (batt_ids.kohm[i] * id_range_pct) / 100; in_range = (delta <= limit); /* * Check if the battery aging level matches and the * limits are in range before selecting the best node. */ if ((batt_age_level == val || !best_node) && in_range) { best_node = node; best_id_kohm = batt_ids.kohm[i]; *avail_age_level = val; break; } } } if (best_node == NULL) { pr_err("No battery data found\n"); return best_node; } /* check that profile id is in range of the measured batt_id */ if (abs(best_id_kohm - batt_id_kohm) > ((best_id_kohm * id_range_pct) / 100)) { pr_err("out of range: profile id %d batt id %d pct %d", best_id_kohm, batt_id_kohm, id_range_pct); return NULL; } rc = of_property_read_string(best_node, "qcom,battery-type", &battery_type); if (!rc) pr_info("%s age level %d found\n", battery_type, *avail_age_level); else pr_info("%s age level %d found\n", best_node->name, *avail_age_level); return best_node; } int of_batterydata_read_data(struct device_node *batterydata_container_node, struct bms_battery_data *batt_data, int batt_id_uv) Loading drivers/power/supply/power_supply_sysfs.c +1 −0 Original line number Diff line number Diff line Loading @@ -390,6 +390,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(fg_reset), POWER_SUPPLY_ATTR(qc_opti_disable), POWER_SUPPLY_ATTR(cc_soc), POWER_SUPPLY_ATTR(batt_age_level), /* Charge pump properties */ POWER_SUPPLY_ATTR(cp_status1), POWER_SUPPLY_ATTR(cp_status2), Loading include/linux/of_batterydata.h +23 −2 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, 2016-2017 The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -48,6 +48,21 @@ int of_batterydata_read_data(struct device_node *container_node, struct device_node *of_batterydata_get_best_profile( struct device_node *batterydata_container_node, int batt_id_kohm, const char *batt_type); /** * of_batterydata_get_best_aged_profile() - Find best aged battery profile * @batterydata_container_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. * @batt_age_level: Battery age level. * @avail_age_level: Available battery age level. * * This routine returns a device_node pointer to the closest match battery data * from device tree based on the battery id reading and age level. */ 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); #else static inline int of_batterydata_read_data(struct device_node *container_node, struct bms_battery_data *batt_data, Loading @@ -59,6 +74,12 @@ static inline struct device_node *of_batterydata_get_best_profile( struct device_node *batterydata_container_node, int batt_id_kohm, const char *batt_type) { return -ENXIO; return NULL; } static inline struct device_node *of_batterydata_get_best_aged_profile( const struct device_node *batterydata_container_node, int batt_id_kohm, u32 batt_age_level) { return NULL; } #endif /* CONFIG_OF_QPNP */ include/linux/power_supply.h +1 −0 Original line number Diff line number Diff line Loading @@ -321,6 +321,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_FG_RESET, POWER_SUPPLY_PROP_QC_OPTI_DISABLE, POWER_SUPPLY_PROP_CC_SOC, POWER_SUPPLY_PROP_BATT_AGE_LEVEL, /* Charge pump properties */ POWER_SUPPLY_PROP_CP_STATUS1, POWER_SUPPLY_PROP_CP_STATUS2, Loading Loading
Documentation/devicetree/bindings/batterydata/batterydata.txt +2 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,8 @@ Profile data node optional properties: JEITA conditions (cool/warm). Element 0 - FV value for soft cool. Element 1 - FV value for soft warm. - qcom,batt-age-level: Battery age level. This is used only when multiple profile loading is supported. Profile data node required subnodes: - qcom,fcc-temp-lut : An 1-dimensional lookup table node that encodes temperature to fcc lookup. The units for this lookup Loading
drivers/of/of_batterydata.c +78 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -398,6 +398,83 @@ struct device_node *of_batterydata_get_best_profile( return best_node; } 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) { struct batt_ids batt_ids; struct device_node *node, *best_node = NULL; const char *battery_type = NULL; int delta = 0, best_id_kohm = 0, id_range_pct, i = 0, rc = 0, limit = 0; u32 val; bool in_range = false; /* read battery id range percentage for best profile */ rc = of_property_read_u32(batterydata_container_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 ERR_PTR(-ENXIO); } } /* * Find the battery data with a battery id resistor closest to this one */ for_each_available_child_of_node(batterydata_container_node, node) { val = 0; of_property_read_u32(node, "qcom,batt-age-level", &val); rc = of_batterydata_read_batt_id_kohm(node, "qcom,batt-id-kohm", &batt_ids); if (rc) continue; for (i = 0; i < batt_ids.num; i++) { delta = abs(batt_ids.kohm[i] - batt_id_kohm); limit = (batt_ids.kohm[i] * id_range_pct) / 100; in_range = (delta <= limit); /* * Check if the battery aging level matches and the * limits are in range before selecting the best node. */ if ((batt_age_level == val || !best_node) && in_range) { best_node = node; best_id_kohm = batt_ids.kohm[i]; *avail_age_level = val; break; } } } if (best_node == NULL) { pr_err("No battery data found\n"); return best_node; } /* check that profile id is in range of the measured batt_id */ if (abs(best_id_kohm - batt_id_kohm) > ((best_id_kohm * id_range_pct) / 100)) { pr_err("out of range: profile id %d batt id %d pct %d", best_id_kohm, batt_id_kohm, id_range_pct); return NULL; } rc = of_property_read_string(best_node, "qcom,battery-type", &battery_type); if (!rc) pr_info("%s age level %d found\n", battery_type, *avail_age_level); else pr_info("%s age level %d found\n", best_node->name, *avail_age_level); return best_node; } int of_batterydata_read_data(struct device_node *batterydata_container_node, struct bms_battery_data *batt_data, int batt_id_uv) Loading
drivers/power/supply/power_supply_sysfs.c +1 −0 Original line number Diff line number Diff line Loading @@ -390,6 +390,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(fg_reset), POWER_SUPPLY_ATTR(qc_opti_disable), POWER_SUPPLY_ATTR(cc_soc), POWER_SUPPLY_ATTR(batt_age_level), /* Charge pump properties */ POWER_SUPPLY_ATTR(cp_status1), POWER_SUPPLY_ATTR(cp_status2), Loading
include/linux/of_batterydata.h +23 −2 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, 2016-2017 The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -48,6 +48,21 @@ int of_batterydata_read_data(struct device_node *container_node, struct device_node *of_batterydata_get_best_profile( struct device_node *batterydata_container_node, int batt_id_kohm, const char *batt_type); /** * of_batterydata_get_best_aged_profile() - Find best aged battery profile * @batterydata_container_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. * @batt_age_level: Battery age level. * @avail_age_level: Available battery age level. * * This routine returns a device_node pointer to the closest match battery data * from device tree based on the battery id reading and age level. */ 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); #else static inline int of_batterydata_read_data(struct device_node *container_node, struct bms_battery_data *batt_data, Loading @@ -59,6 +74,12 @@ static inline struct device_node *of_batterydata_get_best_profile( struct device_node *batterydata_container_node, int batt_id_kohm, const char *batt_type) { return -ENXIO; return NULL; } static inline struct device_node *of_batterydata_get_best_aged_profile( const struct device_node *batterydata_container_node, int batt_id_kohm, u32 batt_age_level) { return NULL; } #endif /* CONFIG_OF_QPNP */
include/linux/power_supply.h +1 −0 Original line number Diff line number Diff line Loading @@ -321,6 +321,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_FG_RESET, POWER_SUPPLY_PROP_QC_OPTI_DISABLE, POWER_SUPPLY_PROP_CC_SOC, POWER_SUPPLY_PROP_BATT_AGE_LEVEL, /* Charge pump properties */ POWER_SUPPLY_PROP_CP_STATUS1, POWER_SUPPLY_PROP_CP_STATUS2, Loading