Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power: supply: core: auto-exposure of simple-battery data

Automatically expose data from the simple-battery firmware
node for all battery drivers.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Matti Vaittinen <mazziesaccount@gmail.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>

+191 -19
+161 -18
drivers/power/supply/power_supply_core.c
··· 388 388 struct psy_get_supplier_prop_data *data = _data; 389 389 390 390 if (__power_supply_is_supplied_by(epsy, data->psy)) 391 - if (!epsy->desc->get_property(epsy, data->psp, data->val)) 391 + if (!power_supply_get_property(epsy, data->psp, data->val)) 392 392 return 1; /* Success */ 393 393 394 394 return 0; /* Continue iterating */ ··· 832 832 } 833 833 EXPORT_SYMBOL_GPL(power_supply_put_battery_info); 834 834 835 + const enum power_supply_property power_supply_battery_info_properties[] = { 836 + POWER_SUPPLY_PROP_TECHNOLOGY, 837 + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 838 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 839 + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 840 + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 841 + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, 842 + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 843 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 844 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 845 + POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN, 846 + POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX, 847 + POWER_SUPPLY_PROP_TEMP_ALERT_MIN, 848 + POWER_SUPPLY_PROP_TEMP_ALERT_MAX, 849 + POWER_SUPPLY_PROP_TEMP_MIN, 850 + POWER_SUPPLY_PROP_TEMP_MAX, 851 + }; 852 + EXPORT_SYMBOL_GPL(power_supply_battery_info_properties); 853 + 854 + const size_t power_supply_battery_info_properties_size = ARRAY_SIZE(power_supply_battery_info_properties); 855 + EXPORT_SYMBOL_GPL(power_supply_battery_info_properties_size); 856 + 857 + bool power_supply_battery_info_has_prop(struct power_supply_battery_info *info, 858 + enum power_supply_property psp) 859 + { 860 + if (!info) 861 + return false; 862 + 863 + switch (psp) { 864 + case POWER_SUPPLY_PROP_TECHNOLOGY: 865 + return info->technology != POWER_SUPPLY_TECHNOLOGY_UNKNOWN; 866 + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: 867 + return info->energy_full_design_uwh >= 0; 868 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 869 + return info->charge_full_design_uah >= 0; 870 + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 871 + return info->voltage_min_design_uv >= 0; 872 + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 873 + return info->voltage_max_design_uv >= 0; 874 + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 875 + return info->precharge_current_ua >= 0; 876 + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 877 + return info->charge_term_current_ua >= 0; 878 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 879 + return info->constant_charge_current_max_ua >= 0; 880 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 881 + return info->constant_charge_voltage_max_uv >= 0; 882 + case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN: 883 + return info->temp_ambient_alert_min > INT_MIN; 884 + case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX: 885 + return info->temp_ambient_alert_max < INT_MAX; 886 + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 887 + return info->temp_alert_min > INT_MIN; 888 + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 889 + return info->temp_alert_max < INT_MAX; 890 + case POWER_SUPPLY_PROP_TEMP_MIN: 891 + return info->temp_min > INT_MIN; 892 + case POWER_SUPPLY_PROP_TEMP_MAX: 893 + return info->temp_max < INT_MAX; 894 + default: 895 + return false; 896 + } 897 + } 898 + EXPORT_SYMBOL_GPL(power_supply_battery_info_has_prop); 899 + 900 + int power_supply_battery_info_get_prop(struct power_supply_battery_info *info, 901 + enum power_supply_property psp, 902 + union power_supply_propval *val) 903 + { 904 + if (!info) 905 + return -EINVAL; 906 + 907 + if (!power_supply_battery_info_has_prop(info, psp)) 908 + return -EINVAL; 909 + 910 + switch (psp) { 911 + case POWER_SUPPLY_PROP_TECHNOLOGY: 912 + val->intval = info->technology; 913 + return 0; 914 + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: 915 + val->intval = info->energy_full_design_uwh; 916 + return 0; 917 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 918 + val->intval = info->charge_full_design_uah; 919 + return 0; 920 + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 921 + val->intval = info->voltage_min_design_uv; 922 + return 0; 923 + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 924 + val->intval = info->voltage_max_design_uv; 925 + return 0; 926 + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 927 + val->intval = info->precharge_current_ua; 928 + return 0; 929 + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 930 + val->intval = info->charge_term_current_ua; 931 + return 0; 932 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 933 + val->intval = info->constant_charge_current_max_ua; 934 + return 0; 935 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 936 + val->intval = info->constant_charge_voltage_max_uv; 937 + return 0; 938 + case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN: 939 + val->intval = info->temp_ambient_alert_min; 940 + return 0; 941 + case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX: 942 + val->intval = info->temp_ambient_alert_max; 943 + return 0; 944 + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 945 + val->intval = info->temp_alert_min; 946 + return 0; 947 + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 948 + val->intval = info->temp_alert_max; 949 + return 0; 950 + case POWER_SUPPLY_PROP_TEMP_MIN: 951 + val->intval = info->temp_min; 952 + return 0; 953 + case POWER_SUPPLY_PROP_TEMP_MAX: 954 + val->intval = info->temp_max; 955 + return 0; 956 + default: 957 + return -EINVAL; 958 + } 959 + } 960 + EXPORT_SYMBOL_GPL(power_supply_battery_info_get_prop); 961 + 835 962 /** 836 963 * power_supply_temp2resist_simple() - find the battery internal resistance 837 964 * percent from temperature ··· 1173 1046 } 1174 1047 EXPORT_SYMBOL_GPL(power_supply_battery_bti_in_range); 1175 1048 1049 + static bool psy_has_property(const struct power_supply_desc *psy_desc, 1050 + enum power_supply_property psp) 1051 + { 1052 + bool found = false; 1053 + int i; 1054 + 1055 + for (i = 0; i < psy_desc->num_properties; i++) { 1056 + if (psy_desc->properties[i] == psp) { 1057 + found = true; 1058 + break; 1059 + } 1060 + } 1061 + 1062 + return found; 1063 + } 1064 + 1176 1065 int power_supply_get_property(struct power_supply *psy, 1177 1066 enum power_supply_property psp, 1178 1067 union power_supply_propval *val) ··· 1199 1056 return -ENODEV; 1200 1057 } 1201 1058 1202 - return psy->desc->get_property(psy, psp, val); 1059 + if (psy_has_property(psy->desc, psp)) 1060 + return psy->desc->get_property(psy, psp, val); 1061 + else if (power_supply_battery_info_has_prop(psy->battery_info, psp)) 1062 + return power_supply_battery_info_get_prop(psy->battery_info, psp, val); 1063 + else 1064 + return -EINVAL; 1203 1065 } 1204 1066 EXPORT_SYMBOL_GPL(power_supply_get_property); 1205 1067 ··· 1264 1116 atomic_notifier_chain_unregister(&power_supply_notifier, nb); 1265 1117 } 1266 1118 EXPORT_SYMBOL_GPL(power_supply_unreg_notifier); 1267 - 1268 - static bool psy_has_property(const struct power_supply_desc *psy_desc, 1269 - enum power_supply_property psp) 1270 - { 1271 - bool found = false; 1272 - int i; 1273 - 1274 - for (i = 0; i < psy_desc->num_properties; i++) { 1275 - if (psy_desc->properties[i] == psp) { 1276 - found = true; 1277 - break; 1278 - } 1279 - } 1280 - 1281 - return found; 1282 - } 1283 1119 1284 1120 #ifdef CONFIG_THERMAL 1285 1121 static int power_supply_read_temp(struct thermal_zone_device *tzd, ··· 1385 1253 if (rc) { 1386 1254 dev_dbg(dev, "Not all required supplies found, defer probe\n"); 1387 1255 goto check_supplies_failed; 1256 + } 1257 + 1258 + /* 1259 + * Expose constant battery info, if it is available. While there are 1260 + * some chargers accessing constant battery data, we only want to 1261 + * expose battery data to userspace for battery devices. 1262 + */ 1263 + if (desc->type == POWER_SUPPLY_TYPE_BATTERY) { 1264 + rc = power_supply_get_battery_info(psy, &psy->battery_info); 1265 + if (rc && rc != -ENODEV && rc != -ENOENT) 1266 + goto check_supplies_failed; 1388 1267 } 1389 1268 1390 1269 spin_lock_init(&psy->changed_lock);
+22 -1
drivers/power/supply/power_supply_sysfs.c
··· 221 221 POWER_SUPPLY_ATTR(MANUFACTURER), 222 222 POWER_SUPPLY_ATTR(SERIAL_NUMBER), 223 223 }; 224 + #define POWER_SUPPLY_ATTR_CNT ARRAY_SIZE(power_supply_attrs) 224 225 225 226 static struct attribute * 226 - __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1]; 227 + __power_supply_attrs[POWER_SUPPLY_ATTR_CNT + 1]; 227 228 228 229 static struct power_supply_attr *to_ps_attr(struct device_attribute *attr) 229 230 { ··· 381 380 } 382 381 } 383 382 383 + if (power_supply_battery_info_has_prop(psy->battery_info, attrno)) 384 + return mode; 385 + 384 386 return 0; 385 387 } 386 388 ··· 465 461 int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env) 466 462 { 467 463 const struct power_supply *psy = dev_get_drvdata(dev); 464 + const enum power_supply_property *battery_props = 465 + power_supply_battery_info_properties; 466 + unsigned long psy_drv_properties[POWER_SUPPLY_ATTR_CNT / 467 + sizeof(unsigned long) + 1] = {0}; 468 468 int ret = 0, j; 469 469 char *prop_buf; 470 470 ··· 490 482 goto out; 491 483 492 484 for (j = 0; j < psy->desc->num_properties; j++) { 485 + set_bit(psy->desc->properties[j], psy_drv_properties); 493 486 ret = add_prop_uevent(dev, env, psy->desc->properties[j], 494 487 prop_buf); 488 + if (ret) 489 + goto out; 490 + } 491 + 492 + for (j = 0; j < power_supply_battery_info_properties_size; j++) { 493 + if (test_bit(battery_props[j], psy_drv_properties)) 494 + continue; 495 + if (!power_supply_battery_info_has_prop(psy->battery_info, 496 + battery_props[j])) 497 + continue; 498 + ret = add_prop_uevent(dev, env, battery_props[j], 499 + prop_buf); 495 500 if (ret) 496 501 goto out; 497 502 }
+8
include/linux/power_supply.h
··· 301 301 bool initialized; 302 302 bool removing; 303 303 atomic_t use_cnt; 304 + struct power_supply_battery_info *battery_info; 304 305 #ifdef CONFIG_THERMAL 305 306 struct thermal_zone_device *tzd; 306 307 struct thermal_cooling_device *tcd; ··· 792 791 { return NULL; } 793 792 #endif /* CONFIG_OF */ 794 793 794 + extern const enum power_supply_property power_supply_battery_info_properties[]; 795 + extern const size_t power_supply_battery_info_properties_size; 795 796 extern int power_supply_get_battery_info(struct power_supply *psy, 796 797 struct power_supply_battery_info **info_out); 797 798 extern void power_supply_put_battery_info(struct power_supply *psy, 798 799 struct power_supply_battery_info *info); 800 + extern bool power_supply_battery_info_has_prop(struct power_supply_battery_info *info, 801 + enum power_supply_property psp); 802 + extern int power_supply_battery_info_get_prop(struct power_supply_battery_info *info, 803 + enum power_supply_property psp, 804 + union power_supply_propval *val); 799 805 extern int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table, 800 806 int table_len, int ocv); 801 807 extern struct power_supply_battery_ocv_table *