Skip to content

Commit 27a2195

Browse files
committed
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>
1 parent 25b8006 commit 27a2195

3 files changed

Lines changed: 191 additions & 19 deletions

File tree

drivers/power/supply/power_supply_core.c

Lines changed: 161 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ static int __power_supply_get_supplier_property(struct device *dev, void *_data)
388388
struct psy_get_supplier_prop_data *data = _data;
389389

390390
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))
392392
return 1; /* Success */
393393

394394
return 0; /* Continue iterating */
@@ -832,6 +832,133 @@ void power_supply_put_battery_info(struct power_supply *psy,
832832
}
833833
EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
834834

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+
835962
/**
836963
* power_supply_temp2resist_simple() - find the battery internal resistance
837964
* percent from temperature
@@ -1046,6 +1173,22 @@ bool power_supply_battery_bti_in_range(struct power_supply_battery_info *info,
10461173
}
10471174
EXPORT_SYMBOL_GPL(power_supply_battery_bti_in_range);
10481175

1176+
static bool psy_has_property(const struct power_supply_desc *psy_desc,
1177+
enum power_supply_property psp)
1178+
{
1179+
bool found = false;
1180+
int i;
1181+
1182+
for (i = 0; i < psy_desc->num_properties; i++) {
1183+
if (psy_desc->properties[i] == psp) {
1184+
found = true;
1185+
break;
1186+
}
1187+
}
1188+
1189+
return found;
1190+
}
1191+
10491192
int power_supply_get_property(struct power_supply *psy,
10501193
enum power_supply_property psp,
10511194
union power_supply_propval *val)
@@ -1056,7 +1199,12 @@ int power_supply_get_property(struct power_supply *psy,
10561199
return -ENODEV;
10571200
}
10581201

1059-
return psy->desc->get_property(psy, psp, val);
1202+
if (psy_has_property(psy->desc, psp))
1203+
return psy->desc->get_property(psy, psp, val);
1204+
else if (power_supply_battery_info_has_prop(psy->battery_info, psp))
1205+
return power_supply_battery_info_get_prop(psy->battery_info, psp, val);
1206+
else
1207+
return -EINVAL;
10601208
}
10611209
EXPORT_SYMBOL_GPL(power_supply_get_property);
10621210

@@ -1117,22 +1265,6 @@ void power_supply_unreg_notifier(struct notifier_block *nb)
11171265
}
11181266
EXPORT_SYMBOL_GPL(power_supply_unreg_notifier);
11191267

1120-
static bool psy_has_property(const struct power_supply_desc *psy_desc,
1121-
enum power_supply_property psp)
1122-
{
1123-
bool found = false;
1124-
int i;
1125-
1126-
for (i = 0; i < psy_desc->num_properties; i++) {
1127-
if (psy_desc->properties[i] == psp) {
1128-
found = true;
1129-
break;
1130-
}
1131-
}
1132-
1133-
return found;
1134-
}
1135-
11361268
#ifdef CONFIG_THERMAL
11371269
static int power_supply_read_temp(struct thermal_zone_device *tzd,
11381270
int *temp)
@@ -1255,6 +1387,17 @@ __power_supply_register(struct device *parent,
12551387
goto check_supplies_failed;
12561388
}
12571389

1390+
/*
1391+
* Expose constant battery info, if it is available. While there are
1392+
* some chargers accessing constant battery data, we only want to
1393+
* expose battery data to userspace for battery devices.
1394+
*/
1395+
if (desc->type == POWER_SUPPLY_TYPE_BATTERY) {
1396+
rc = power_supply_get_battery_info(psy, &psy->battery_info);
1397+
if (rc && rc != -ENODEV && rc != -ENOENT)
1398+
goto check_supplies_failed;
1399+
}
1400+
12581401
spin_lock_init(&psy->changed_lock);
12591402
rc = device_add(dev);
12601403
if (rc)

drivers/power/supply/power_supply_sysfs.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,10 @@ static struct power_supply_attr power_supply_attrs[] = {
221221
POWER_SUPPLY_ATTR(MANUFACTURER),
222222
POWER_SUPPLY_ATTR(SERIAL_NUMBER),
223223
};
224+
#define POWER_SUPPLY_ATTR_CNT ARRAY_SIZE(power_supply_attrs)
224225

225226
static struct attribute *
226-
__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
227+
__power_supply_attrs[POWER_SUPPLY_ATTR_CNT + 1];
227228

228229
static struct power_supply_attr *to_ps_attr(struct device_attribute *attr)
229230
{
@@ -380,6 +381,9 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
380381
}
381382
}
382383

384+
if (power_supply_battery_info_has_prop(psy->battery_info, attrno))
385+
return mode;
386+
383387
return 0;
384388
}
385389

@@ -461,6 +465,10 @@ static int add_prop_uevent(const struct device *dev, struct kobj_uevent_env *env
461465
int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
462466
{
463467
const struct power_supply *psy = dev_get_drvdata(dev);
468+
const enum power_supply_property *battery_props =
469+
power_supply_battery_info_properties;
470+
unsigned long psy_drv_properties[POWER_SUPPLY_ATTR_CNT /
471+
sizeof(unsigned long) + 1] = {0};
464472
int ret = 0, j;
465473
char *prop_buf;
466474

@@ -482,12 +490,25 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
482490
goto out;
483491

484492
for (j = 0; j < psy->desc->num_properties; j++) {
493+
set_bit(psy->desc->properties[j], psy_drv_properties);
485494
ret = add_prop_uevent(dev, env, psy->desc->properties[j],
486495
prop_buf);
487496
if (ret)
488497
goto out;
489498
}
490499

500+
for (j = 0; j < power_supply_battery_info_properties_size; j++) {
501+
if (test_bit(battery_props[j], psy_drv_properties))
502+
continue;
503+
if (!power_supply_battery_info_has_prop(psy->battery_info,
504+
battery_props[j]))
505+
continue;
506+
ret = add_prop_uevent(dev, env, battery_props[j],
507+
prop_buf);
508+
if (ret)
509+
goto out;
510+
}
511+
491512
out:
492513
free_page((unsigned long)prop_buf);
493514

include/linux/power_supply.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ struct power_supply {
301301
bool initialized;
302302
bool removing;
303303
atomic_t use_cnt;
304+
struct power_supply_battery_info *battery_info;
304305
#ifdef CONFIG_THERMAL
305306
struct thermal_zone_device *tzd;
306307
struct thermal_cooling_device *tcd;
@@ -791,10 +792,17 @@ devm_power_supply_get_by_phandle(struct device *dev, const char *property)
791792
{ return NULL; }
792793
#endif /* CONFIG_OF */
793794

795+
extern const enum power_supply_property power_supply_battery_info_properties[];
796+
extern const size_t power_supply_battery_info_properties_size;
794797
extern int power_supply_get_battery_info(struct power_supply *psy,
795798
struct power_supply_battery_info **info_out);
796799
extern void power_supply_put_battery_info(struct power_supply *psy,
797800
struct power_supply_battery_info *info);
801+
extern bool power_supply_battery_info_has_prop(struct power_supply_battery_info *info,
802+
enum power_supply_property psp);
803+
extern int power_supply_battery_info_get_prop(struct power_supply_battery_info *info,
804+
enum power_supply_property psp,
805+
union power_supply_propval *val);
798806
extern int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
799807
int table_len, int ocv);
800808
extern struct power_supply_battery_ocv_table *

0 commit comments

Comments
 (0)