GNU Linux-libre 4.19.314-gnu1
[releases.git] / drivers / power / supply / power_supply_sysfs.c
1 /*
2  *  Sysfs interface for the universal power supply monitor class
3  *
4  *  Copyright © 2007  David Woodhouse <dwmw2@infradead.org>
5  *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
6  *  Copyright © 2004  Szabolcs Gyurko
7  *  Copyright © 2003  Ian Molton <spyro@f2s.com>
8  *
9  *  Modified: 2004, Oct     Szabolcs Gyurko
10  *
11  *  You may use this code as per GPL version 2
12  */
13
14 #include <linux/ctype.h>
15 #include <linux/device.h>
16 #include <linux/power_supply.h>
17 #include <linux/slab.h>
18 #include <linux/stat.h>
19
20 #include "power_supply.h"
21
22 /*
23  * This is because the name "current" breaks the device attr macro.
24  * The "current" word resolves to "(get_current())" so instead of
25  * "current" "(get_current())" appears in the sysfs.
26  *
27  * The source of this definition is the device.h which calls __ATTR
28  * macro in sysfs.h which calls the __stringify macro.
29  *
30  * Only modification that the name is not tried to be resolved
31  * (as a macro let's say).
32  */
33
34 #define POWER_SUPPLY_ATTR(_name)                                        \
35 {                                                                       \
36         .attr = { .name = #_name },                                     \
37         .show = power_supply_show_property,                             \
38         .store = power_supply_store_property,                           \
39 }
40
41 static struct device_attribute power_supply_attrs[];
42
43 static const char * const power_supply_type_text[] = {
44         "Unknown", "Battery", "UPS", "Mains", "USB",
45         "USB_DCP", "USB_CDP", "USB_ACA", "USB_C",
46         "USB_PD", "USB_PD_DRP", "BrickID"
47 };
48
49 static const char * const power_supply_usb_type_text[] = {
50         "Unknown", "SDP", "DCP", "CDP", "ACA", "C",
51         "PD", "PD_DRP", "PD_PPS", "BrickID"
52 };
53
54 static const char * const power_supply_status_text[] = {
55         "Unknown", "Charging", "Discharging", "Not charging", "Full"
56 };
57
58 static const char * const power_supply_charge_type_text[] = {
59         "Unknown", "N/A", "Trickle", "Fast"
60 };
61
62 static const char * const power_supply_health_text[] = {
63         "Unknown", "Good", "Overheat", "Dead", "Over voltage",
64         "Unspecified failure", "Cold", "Watchdog timer expire",
65         "Safety timer expire"
66 };
67
68 static const char * const power_supply_technology_text[] = {
69         "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
70         "LiMn"
71 };
72
73 static const char * const power_supply_capacity_level_text[] = {
74         "Unknown", "Critical", "Low", "Normal", "High", "Full"
75 };
76
77 static const char * const power_supply_scope_text[] = {
78         "Unknown", "System", "Device"
79 };
80
81 static ssize_t power_supply_show_usb_type(struct device *dev,
82                                           enum power_supply_usb_type *usb_types,
83                                           ssize_t num_usb_types,
84                                           union power_supply_propval *value,
85                                           char *buf)
86 {
87         enum power_supply_usb_type usb_type;
88         ssize_t count = 0;
89         bool match = false;
90         int i;
91
92         for (i = 0; i < num_usb_types; ++i) {
93                 usb_type = usb_types[i];
94
95                 if (value->intval == usb_type) {
96                         count += sprintf(buf + count, "[%s] ",
97                                          power_supply_usb_type_text[usb_type]);
98                         match = true;
99                 } else {
100                         count += sprintf(buf + count, "%s ",
101                                          power_supply_usb_type_text[usb_type]);
102                 }
103         }
104
105         if (!match) {
106                 dev_warn(dev, "driver reporting unsupported connected type\n");
107                 return -EINVAL;
108         }
109
110         if (count)
111                 buf[count - 1] = '\n';
112
113         return count;
114 }
115
116 static ssize_t power_supply_show_property(struct device *dev,
117                                           struct device_attribute *attr,
118                                           char *buf) {
119         ssize_t ret;
120         struct power_supply *psy = dev_get_drvdata(dev);
121         enum power_supply_property psp = attr - power_supply_attrs;
122         union power_supply_propval value;
123
124         if (psp == POWER_SUPPLY_PROP_TYPE) {
125                 value.intval = psy->desc->type;
126         } else {
127                 ret = power_supply_get_property(psy, psp, &value);
128
129                 if (ret < 0) {
130                         if (ret == -ENODATA)
131                                 dev_dbg_ratelimited(dev,
132                                         "driver has no data for `%s' property\n",
133                                         attr->attr.name);
134                         else if (ret != -ENODEV && ret != -EAGAIN)
135                                 dev_err_ratelimited(dev,
136                                         "driver failed to report `%s' property: %zd\n",
137                                         attr->attr.name, ret);
138                         return ret;
139                 }
140         }
141
142         switch (psp) {
143         case POWER_SUPPLY_PROP_STATUS:
144                 ret = sprintf(buf, "%s\n",
145                               power_supply_status_text[value.intval]);
146                 break;
147         case POWER_SUPPLY_PROP_CHARGE_TYPE:
148                 ret = sprintf(buf, "%s\n",
149                               power_supply_charge_type_text[value.intval]);
150                 break;
151         case POWER_SUPPLY_PROP_HEALTH:
152                 ret = sprintf(buf, "%s\n",
153                               power_supply_health_text[value.intval]);
154                 break;
155         case POWER_SUPPLY_PROP_TECHNOLOGY:
156                 ret = sprintf(buf, "%s\n",
157                               power_supply_technology_text[value.intval]);
158                 break;
159         case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
160                 ret = sprintf(buf, "%s\n",
161                               power_supply_capacity_level_text[value.intval]);
162                 break;
163         case POWER_SUPPLY_PROP_TYPE:
164                 ret = sprintf(buf, "%s\n",
165                               power_supply_type_text[value.intval]);
166                 break;
167         case POWER_SUPPLY_PROP_USB_TYPE:
168                 ret = power_supply_show_usb_type(dev, psy->desc->usb_types,
169                                                  psy->desc->num_usb_types,
170                                                  &value, buf);
171                 break;
172         case POWER_SUPPLY_PROP_SCOPE:
173                 ret = sprintf(buf, "%s\n",
174                               power_supply_scope_text[value.intval]);
175                 break;
176         case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
177                 ret = sprintf(buf, "%s\n", value.strval);
178                 break;
179         default:
180                 ret = sprintf(buf, "%d\n", value.intval);
181         }
182
183         return ret;
184 }
185
186 static ssize_t power_supply_store_property(struct device *dev,
187                                            struct device_attribute *attr,
188                                            const char *buf, size_t count) {
189         ssize_t ret;
190         struct power_supply *psy = dev_get_drvdata(dev);
191         enum power_supply_property psp = attr - power_supply_attrs;
192         union power_supply_propval value;
193
194         switch (psp) {
195         case POWER_SUPPLY_PROP_STATUS:
196                 ret = sysfs_match_string(power_supply_status_text, buf);
197                 break;
198         case POWER_SUPPLY_PROP_CHARGE_TYPE:
199                 ret = sysfs_match_string(power_supply_charge_type_text, buf);
200                 break;
201         case POWER_SUPPLY_PROP_HEALTH:
202                 ret = sysfs_match_string(power_supply_health_text, buf);
203                 break;
204         case POWER_SUPPLY_PROP_TECHNOLOGY:
205                 ret = sysfs_match_string(power_supply_technology_text, buf);
206                 break;
207         case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
208                 ret = sysfs_match_string(power_supply_capacity_level_text, buf);
209                 break;
210         case POWER_SUPPLY_PROP_SCOPE:
211                 ret = sysfs_match_string(power_supply_scope_text, buf);
212                 break;
213         default:
214                 ret = -EINVAL;
215         }
216
217         /*
218          * If no match was found, then check to see if it is an integer.
219          * Integer values are valid for enums in addition to the text value.
220          */
221         if (ret < 0) {
222                 long long_val;
223
224                 ret = kstrtol(buf, 10, &long_val);
225                 if (ret < 0)
226                         return ret;
227
228                 ret = long_val;
229         }
230
231         value.intval = ret;
232
233         ret = power_supply_set_property(psy, psp, &value);
234         if (ret < 0)
235                 return ret;
236
237         return count;
238 }
239
240 /* Must be in the same order as POWER_SUPPLY_PROP_* */
241 static struct device_attribute power_supply_attrs[] = {
242         /* Properties of type `int' */
243         POWER_SUPPLY_ATTR(status),
244         POWER_SUPPLY_ATTR(charge_type),
245         POWER_SUPPLY_ATTR(health),
246         POWER_SUPPLY_ATTR(present),
247         POWER_SUPPLY_ATTR(online),
248         POWER_SUPPLY_ATTR(authentic),
249         POWER_SUPPLY_ATTR(technology),
250         POWER_SUPPLY_ATTR(cycle_count),
251         POWER_SUPPLY_ATTR(voltage_max),
252         POWER_SUPPLY_ATTR(voltage_min),
253         POWER_SUPPLY_ATTR(voltage_max_design),
254         POWER_SUPPLY_ATTR(voltage_min_design),
255         POWER_SUPPLY_ATTR(voltage_now),
256         POWER_SUPPLY_ATTR(voltage_avg),
257         POWER_SUPPLY_ATTR(voltage_ocv),
258         POWER_SUPPLY_ATTR(voltage_boot),
259         POWER_SUPPLY_ATTR(current_max),
260         POWER_SUPPLY_ATTR(current_now),
261         POWER_SUPPLY_ATTR(current_avg),
262         POWER_SUPPLY_ATTR(current_boot),
263         POWER_SUPPLY_ATTR(power_now),
264         POWER_SUPPLY_ATTR(power_avg),
265         POWER_SUPPLY_ATTR(charge_full_design),
266         POWER_SUPPLY_ATTR(charge_empty_design),
267         POWER_SUPPLY_ATTR(charge_full),
268         POWER_SUPPLY_ATTR(charge_empty),
269         POWER_SUPPLY_ATTR(charge_now),
270         POWER_SUPPLY_ATTR(charge_avg),
271         POWER_SUPPLY_ATTR(charge_counter),
272         POWER_SUPPLY_ATTR(constant_charge_current),
273         POWER_SUPPLY_ATTR(constant_charge_current_max),
274         POWER_SUPPLY_ATTR(constant_charge_voltage),
275         POWER_SUPPLY_ATTR(constant_charge_voltage_max),
276         POWER_SUPPLY_ATTR(charge_control_limit),
277         POWER_SUPPLY_ATTR(charge_control_limit_max),
278         POWER_SUPPLY_ATTR(input_current_limit),
279         POWER_SUPPLY_ATTR(energy_full_design),
280         POWER_SUPPLY_ATTR(energy_empty_design),
281         POWER_SUPPLY_ATTR(energy_full),
282         POWER_SUPPLY_ATTR(energy_empty),
283         POWER_SUPPLY_ATTR(energy_now),
284         POWER_SUPPLY_ATTR(energy_avg),
285         POWER_SUPPLY_ATTR(capacity),
286         POWER_SUPPLY_ATTR(capacity_alert_min),
287         POWER_SUPPLY_ATTR(capacity_alert_max),
288         POWER_SUPPLY_ATTR(capacity_level),
289         POWER_SUPPLY_ATTR(temp),
290         POWER_SUPPLY_ATTR(temp_max),
291         POWER_SUPPLY_ATTR(temp_min),
292         POWER_SUPPLY_ATTR(temp_alert_min),
293         POWER_SUPPLY_ATTR(temp_alert_max),
294         POWER_SUPPLY_ATTR(temp_ambient),
295         POWER_SUPPLY_ATTR(temp_ambient_alert_min),
296         POWER_SUPPLY_ATTR(temp_ambient_alert_max),
297         POWER_SUPPLY_ATTR(time_to_empty_now),
298         POWER_SUPPLY_ATTR(time_to_empty_avg),
299         POWER_SUPPLY_ATTR(time_to_full_now),
300         POWER_SUPPLY_ATTR(time_to_full_avg),
301         POWER_SUPPLY_ATTR(type),
302         POWER_SUPPLY_ATTR(usb_type),
303         POWER_SUPPLY_ATTR(scope),
304         POWER_SUPPLY_ATTR(precharge_current),
305         POWER_SUPPLY_ATTR(charge_term_current),
306         POWER_SUPPLY_ATTR(calibrate),
307         /* Properties of type `const char *' */
308         POWER_SUPPLY_ATTR(model_name),
309         POWER_SUPPLY_ATTR(manufacturer),
310         POWER_SUPPLY_ATTR(serial_number),
311 };
312
313 static struct attribute *
314 __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
315
316 static umode_t power_supply_attr_is_visible(struct kobject *kobj,
317                                            struct attribute *attr,
318                                            int attrno)
319 {
320         struct device *dev = container_of(kobj, struct device, kobj);
321         struct power_supply *psy = dev_get_drvdata(dev);
322         umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
323         int i;
324
325         if (attrno == POWER_SUPPLY_PROP_TYPE)
326                 return mode;
327
328         for (i = 0; i < psy->desc->num_properties; i++) {
329                 int property = psy->desc->properties[i];
330
331                 if (property == attrno) {
332                         if (psy->desc->property_is_writeable &&
333                             psy->desc->property_is_writeable(psy, property) > 0)
334                                 mode |= S_IWUSR;
335
336                         return mode;
337                 }
338         }
339
340         return 0;
341 }
342
343 static struct attribute_group power_supply_attr_group = {
344         .attrs = __power_supply_attrs,
345         .is_visible = power_supply_attr_is_visible,
346 };
347
348 static const struct attribute_group *power_supply_attr_groups[] = {
349         &power_supply_attr_group,
350         NULL,
351 };
352
353 void power_supply_init_attrs(struct device_type *dev_type)
354 {
355         int i;
356
357         dev_type->groups = power_supply_attr_groups;
358
359         for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
360                 __power_supply_attrs[i] = &power_supply_attrs[i].attr;
361 }
362
363 static char *kstruprdup(const char *str, gfp_t gfp)
364 {
365         char *ret, *ustr;
366
367         ustr = ret = kmalloc(strlen(str) + 1, gfp);
368
369         if (!ret)
370                 return NULL;
371
372         while (*str)
373                 *ustr++ = toupper(*str++);
374
375         *ustr = 0;
376
377         return ret;
378 }
379
380 int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
381 {
382         struct power_supply *psy = dev_get_drvdata(dev);
383         int ret = 0, j;
384         char *prop_buf;
385         char *attrname;
386
387         if (!psy || !psy->desc) {
388                 dev_dbg(dev, "No power supply yet\n");
389                 return ret;
390         }
391
392         ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name);
393         if (ret)
394                 return ret;
395
396         prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
397         if (!prop_buf)
398                 return -ENOMEM;
399
400         for (j = 0; j < psy->desc->num_properties; j++) {
401                 struct device_attribute *attr;
402                 char *line;
403
404                 attr = &power_supply_attrs[psy->desc->properties[j]];
405
406                 ret = power_supply_show_property(dev, attr, prop_buf);
407                 if (ret == -ENODEV || ret == -ENODATA) {
408                         /* When a battery is absent, we expect -ENODEV. Don't abort;
409                            send the uevent with at least the the PRESENT=0 property */
410                         ret = 0;
411                         continue;
412                 }
413
414                 if (ret < 0)
415                         goto out;
416
417                 line = strchr(prop_buf, '\n');
418                 if (line)
419                         *line = 0;
420
421                 attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
422                 if (!attrname) {
423                         ret = -ENOMEM;
424                         goto out;
425                 }
426
427                 ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
428                 kfree(attrname);
429                 if (ret)
430                         goto out;
431         }
432
433 out:
434         free_page((unsigned long)prop_buf);
435
436         return ret;
437 }