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