Branch data Line data Source code
1 : : /*
2 : : * Universal power supply monitor class
3 : : *
4 : : * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
5 : : * Copyright © 2004 Szabolcs Gyurko
6 : : * Copyright © 2003 Ian Molton <spyro@f2s.com>
7 : : *
8 : : * Modified: 2004, Oct Szabolcs Gyurko
9 : : *
10 : : * You may use this code as per GPL version 2
11 : : */
12 : :
13 : : #include <linux/module.h>
14 : : #include <linux/types.h>
15 : : #include <linux/init.h>
16 : : #include <linux/slab.h>
17 : : #include <linux/device.h>
18 : : #include <linux/err.h>
19 : : #include <linux/power_supply.h>
20 : : #include <linux/thermal.h>
21 : : #include "power_supply.h"
22 : :
23 : : /* exported for the APM Power driver, APM emulation */
24 : : struct class *power_supply_class;
25 : : EXPORT_SYMBOL_GPL(power_supply_class);
26 : :
27 : : static struct device_type power_supply_dev_type;
28 : :
29 : 0 : static bool __power_supply_is_supplied_by(struct power_supply *supplier,
30 : : struct power_supply *supply)
31 : : {
32 : : int i;
33 : :
34 [ # # ][ # # ]: 0 : if (!supply->supplied_from && !supplier->supplied_to)
35 : : return false;
36 : :
37 : : /* Support both supplied_to and supplied_from modes */
38 [ # # ]: 0 : if (supply->supplied_from) {
39 [ # # ]: 0 : if (!supplier->name)
40 : : return false;
41 [ # # ]: 0 : for (i = 0; i < supply->num_supplies; i++)
42 [ # # ]: 0 : if (!strcmp(supplier->name, supply->supplied_from[i]))
43 : : return true;
44 : : } else {
45 [ # # ]: 0 : if (!supply->name)
46 : : return false;
47 [ # # ]: 0 : for (i = 0; i < supplier->num_supplicants; i++)
48 [ # # ]: 0 : if (!strcmp(supplier->supplied_to[i], supply->name))
49 : : return true;
50 : : }
51 : :
52 : : return false;
53 : : }
54 : :
55 : 0 : static int __power_supply_changed_work(struct device *dev, void *data)
56 : : {
57 : : struct power_supply *psy = (struct power_supply *)data;
58 : 0 : struct power_supply *pst = dev_get_drvdata(dev);
59 : :
60 [ # # ]: 0 : if (__power_supply_is_supplied_by(psy, pst)) {
61 [ # # ]: 0 : if (pst->external_power_changed)
62 : 0 : pst->external_power_changed(pst);
63 : : }
64 : :
65 : 0 : return 0;
66 : : }
67 : :
68 : 0 : static void power_supply_changed_work(struct work_struct *work)
69 : : {
70 : : unsigned long flags;
71 : 0 : struct power_supply *psy = container_of(work, struct power_supply,
72 : : changed_work);
73 : :
74 : : dev_dbg(psy->dev, "%s\n", __func__);
75 : :
76 : 0 : spin_lock_irqsave(&psy->changed_lock, flags);
77 [ # # ]: 0 : if (psy->changed) {
78 : 0 : psy->changed = false;
79 : : spin_unlock_irqrestore(&psy->changed_lock, flags);
80 : 0 : class_for_each_device(power_supply_class, NULL, psy,
81 : : __power_supply_changed_work);
82 : 0 : power_supply_update_leds(psy);
83 : 0 : kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
84 : 0 : spin_lock_irqsave(&psy->changed_lock, flags);
85 : : }
86 : : /*
87 : : * Dependent power supplies (e.g. battery) may have changed state
88 : : * as a result of this event, so poll again and hold the
89 : : * wakeup_source until all events are processed.
90 : : */
91 [ # # ]: 0 : if (!psy->changed)
92 : 0 : pm_relax(psy->dev);
93 : : spin_unlock_irqrestore(&psy->changed_lock, flags);
94 : 0 : }
95 : :
96 : 0 : void power_supply_changed(struct power_supply *psy)
97 : : {
98 : : unsigned long flags;
99 : :
100 : : dev_dbg(psy->dev, "%s\n", __func__);
101 : :
102 : 0 : spin_lock_irqsave(&psy->changed_lock, flags);
103 : 0 : psy->changed = true;
104 : 0 : pm_stay_awake(psy->dev);
105 : : spin_unlock_irqrestore(&psy->changed_lock, flags);
106 : 0 : schedule_work(&psy->changed_work);
107 : 0 : }
108 : : EXPORT_SYMBOL_GPL(power_supply_changed);
109 : :
110 : : #ifdef CONFIG_OF
111 : : #include <linux/of.h>
112 : :
113 : 0 : static int __power_supply_populate_supplied_from(struct device *dev,
114 : : void *data)
115 : : {
116 : : struct power_supply *psy = (struct power_supply *)data;
117 : 0 : struct power_supply *epsy = dev_get_drvdata(dev);
118 : : struct device_node *np;
119 : : int i = 0;
120 : :
121 : : do {
122 : 0 : np = of_parse_phandle(psy->of_node, "power-supplies", i++);
123 [ # # ]: 0 : if (!np)
124 : 0 : continue;
125 : :
126 [ # # ]: 0 : if (np == epsy->of_node) {
127 : 0 : dev_info(psy->dev, "%s: Found supply : %s\n",
128 : : psy->name, epsy->name);
129 : 0 : psy->supplied_from[i-1] = (char *)epsy->name;
130 : 0 : psy->num_supplies++;
131 : : of_node_put(np);
132 : : break;
133 : : }
134 : : of_node_put(np);
135 [ # # ]: 0 : } while (np);
136 : :
137 : 0 : return 0;
138 : : }
139 : :
140 : : static int power_supply_populate_supplied_from(struct power_supply *psy)
141 : : {
142 : : int error;
143 : :
144 : 0 : error = class_for_each_device(power_supply_class, NULL, psy,
145 : : __power_supply_populate_supplied_from);
146 : :
147 : : dev_dbg(psy->dev, "%s %d\n", __func__, error);
148 : :
149 : : return error;
150 : : }
151 : :
152 : 0 : static int __power_supply_find_supply_from_node(struct device *dev,
153 : : void *data)
154 : : {
155 : : struct device_node *np = (struct device_node *)data;
156 : 0 : struct power_supply *epsy = dev_get_drvdata(dev);
157 : :
158 : : /* return error breaks out of class_for_each_device loop */
159 [ # # ]: 0 : if (epsy->of_node == np)
160 : : return -EINVAL;
161 : :
162 : 0 : return 0;
163 : : }
164 : :
165 : 0 : static int power_supply_find_supply_from_node(struct device_node *supply_node)
166 : : {
167 : : int error;
168 : : struct device *dev;
169 : : struct class_dev_iter iter;
170 : :
171 : : /*
172 : : * Use iterator to see if any other device is registered.
173 : : * This is required since class_for_each_device returns 0
174 : : * if there are no devices registered.
175 : : */
176 : 0 : class_dev_iter_init(&iter, power_supply_class, NULL, NULL);
177 : 0 : dev = class_dev_iter_next(&iter);
178 : :
179 [ # # ]: 0 : if (!dev)
180 : : return -EPROBE_DEFER;
181 : :
182 : : /*
183 : : * We have to treat the return value as inverted, because if
184 : : * we return error on not found, then it won't continue looking.
185 : : * So we trick it by returning error on success to stop looking
186 : : * once the matching device is found.
187 : : */
188 : 0 : error = class_for_each_device(power_supply_class, NULL, supply_node,
189 : : __power_supply_find_supply_from_node);
190 : :
191 [ # # ]: 0 : return error ? 0 : -EPROBE_DEFER;
192 : : }
193 : :
194 : 0 : static int power_supply_check_supplies(struct power_supply *psy)
195 : : {
196 : : struct device_node *np;
197 : : int cnt = 0;
198 : :
199 : : /* If there is already a list honor it */
200 [ # # ][ # # ]: 0 : if (psy->supplied_from && psy->num_supplies > 0)
201 : : return 0;
202 : :
203 : : /* No device node found, nothing to do */
204 [ # # ]: 0 : if (!psy->of_node)
205 : : return 0;
206 : :
207 : : do {
208 : : int ret;
209 : :
210 : 0 : np = of_parse_phandle(psy->of_node, "power-supplies", cnt++);
211 [ # # ]: 0 : if (!np)
212 : 0 : continue;
213 : :
214 : 0 : ret = power_supply_find_supply_from_node(np);
215 [ # # ]: 0 : if (ret) {
216 : : dev_dbg(psy->dev, "Failed to find supply, defer!\n");
217 : : of_node_put(np);
218 : : return -EPROBE_DEFER;
219 : : }
220 : : of_node_put(np);
221 [ # # ]: 0 : } while (np);
222 : :
223 : : /* All supplies found, allocate char ** array for filling */
224 : 0 : psy->supplied_from = devm_kzalloc(psy->dev, sizeof(psy->supplied_from),
225 : : GFP_KERNEL);
226 [ # # ]: 0 : if (!psy->supplied_from) {
227 : 0 : dev_err(psy->dev, "Couldn't allocate memory for supply list\n");
228 : 0 : return -ENOMEM;
229 : : }
230 : :
231 : 0 : *psy->supplied_from = devm_kzalloc(psy->dev, sizeof(char *) * cnt,
232 : : GFP_KERNEL);
233 [ # # ]: 0 : if (!*psy->supplied_from) {
234 : 0 : dev_err(psy->dev, "Couldn't allocate memory for supply list\n");
235 : 0 : return -ENOMEM;
236 : : }
237 : :
238 : 0 : return power_supply_populate_supplied_from(psy);
239 : : }
240 : : #else
241 : : static inline int power_supply_check_supplies(struct power_supply *psy)
242 : : {
243 : : return 0;
244 : : }
245 : : #endif
246 : :
247 : 0 : static int __power_supply_am_i_supplied(struct device *dev, void *data)
248 : : {
249 : 0 : union power_supply_propval ret = {0,};
250 : : struct power_supply *psy = (struct power_supply *)data;
251 : 0 : struct power_supply *epsy = dev_get_drvdata(dev);
252 : :
253 [ # # ]: 0 : if (__power_supply_is_supplied_by(epsy, psy))
254 [ # # ]: 0 : if (!epsy->get_property(epsy, POWER_SUPPLY_PROP_ONLINE, &ret)) {
255 [ # # ]: 0 : if (ret.intval)
256 : 0 : return ret.intval;
257 : : }
258 : :
259 : : return 0;
260 : : }
261 : :
262 : 0 : int power_supply_am_i_supplied(struct power_supply *psy)
263 : : {
264 : : int error;
265 : :
266 : 0 : error = class_for_each_device(power_supply_class, NULL, psy,
267 : : __power_supply_am_i_supplied);
268 : :
269 : : dev_dbg(psy->dev, "%s %d\n", __func__, error);
270 : :
271 : 0 : return error;
272 : : }
273 : : EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
274 : :
275 : 0 : static int __power_supply_is_system_supplied(struct device *dev, void *data)
276 : : {
277 : 0 : union power_supply_propval ret = {0,};
278 : 0 : struct power_supply *psy = dev_get_drvdata(dev);
279 : : unsigned int *count = data;
280 : :
281 : 0 : (*count)++;
282 [ # # ]: 0 : if (psy->type != POWER_SUPPLY_TYPE_BATTERY) {
283 [ # # ]: 0 : if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
284 : : return 0;
285 [ # # ]: 0 : if (ret.intval)
286 : 0 : return ret.intval;
287 : : }
288 : : return 0;
289 : : }
290 : :
291 : 0 : int power_supply_is_system_supplied(void)
292 : : {
293 : : int error;
294 : 0 : unsigned int count = 0;
295 : :
296 : 0 : error = class_for_each_device(power_supply_class, NULL, &count,
297 : : __power_supply_is_system_supplied);
298 : :
299 : : /*
300 : : * If no power class device was found at all, most probably we are
301 : : * running on a desktop system, so assume we are on mains power.
302 : : */
303 [ # # ]: 0 : if (count == 0)
304 : : return 1;
305 : :
306 : 0 : return error;
307 : : }
308 : : EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
309 : :
310 : 0 : int power_supply_set_battery_charged(struct power_supply *psy)
311 : : {
312 [ # # ][ # # ]: 0 : if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) {
313 : 0 : psy->set_charged(psy);
314 : 0 : return 0;
315 : : }
316 : :
317 : : return -EINVAL;
318 : : }
319 : : EXPORT_SYMBOL_GPL(power_supply_set_battery_charged);
320 : :
321 : 0 : static int power_supply_match_device_by_name(struct device *dev, const void *data)
322 : : {
323 : : const char *name = data;
324 : 0 : struct power_supply *psy = dev_get_drvdata(dev);
325 : :
326 : 0 : return strcmp(psy->name, name) == 0;
327 : : }
328 : :
329 : 0 : struct power_supply *power_supply_get_by_name(const char *name)
330 : : {
331 : 0 : struct device *dev = class_find_device(power_supply_class, NULL, name,
332 : : power_supply_match_device_by_name);
333 : :
334 [ # # ]: 0 : return dev ? dev_get_drvdata(dev) : NULL;
335 : : }
336 : : EXPORT_SYMBOL_GPL(power_supply_get_by_name);
337 : :
338 : 0 : int power_supply_powers(struct power_supply *psy, struct device *dev)
339 : : {
340 : 0 : return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers");
341 : : }
342 : : EXPORT_SYMBOL_GPL(power_supply_powers);
343 : :
344 : 0 : static void power_supply_dev_release(struct device *dev)
345 : : {
346 : : pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
347 : 0 : kfree(dev);
348 : 0 : }
349 : :
350 : : #ifdef CONFIG_THERMAL
351 : : static int power_supply_read_temp(struct thermal_zone_device *tzd,
352 : : unsigned long *temp)
353 : : {
354 : : struct power_supply *psy;
355 : : union power_supply_propval val;
356 : : int ret;
357 : :
358 : : WARN_ON(tzd == NULL);
359 : : psy = tzd->devdata;
360 : : ret = psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
361 : :
362 : : /* Convert tenths of degree Celsius to milli degree Celsius. */
363 : : if (!ret)
364 : : *temp = val.intval * 100;
365 : :
366 : : return ret;
367 : : }
368 : :
369 : : static struct thermal_zone_device_ops psy_tzd_ops = {
370 : : .get_temp = power_supply_read_temp,
371 : : };
372 : :
373 : : static int psy_register_thermal(struct power_supply *psy)
374 : : {
375 : : int i;
376 : :
377 : : /* Register battery zone device psy reports temperature */
378 : : for (i = 0; i < psy->num_properties; i++) {
379 : : if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
380 : : psy->tzd = thermal_zone_device_register(psy->name, 0, 0,
381 : : psy, &psy_tzd_ops, NULL, 0, 0);
382 : : if (IS_ERR(psy->tzd))
383 : : return PTR_ERR(psy->tzd);
384 : : break;
385 : : }
386 : : }
387 : : return 0;
388 : : }
389 : :
390 : : static void psy_unregister_thermal(struct power_supply *psy)
391 : : {
392 : : if (IS_ERR_OR_NULL(psy->tzd))
393 : : return;
394 : : thermal_zone_device_unregister(psy->tzd);
395 : : }
396 : :
397 : : /* thermal cooling device callbacks */
398 : : static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
399 : : unsigned long *state)
400 : : {
401 : : struct power_supply *psy;
402 : : union power_supply_propval val;
403 : : int ret;
404 : :
405 : : psy = tcd->devdata;
406 : : ret = psy->get_property(psy,
407 : : POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
408 : : if (!ret)
409 : : *state = val.intval;
410 : :
411 : : return ret;
412 : : }
413 : :
414 : : static int ps_get_cur_chrage_cntl_limit(struct thermal_cooling_device *tcd,
415 : : unsigned long *state)
416 : : {
417 : : struct power_supply *psy;
418 : : union power_supply_propval val;
419 : : int ret;
420 : :
421 : : psy = tcd->devdata;
422 : : ret = psy->get_property(psy,
423 : : POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
424 : : if (!ret)
425 : : *state = val.intval;
426 : :
427 : : return ret;
428 : : }
429 : :
430 : : static int ps_set_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
431 : : unsigned long state)
432 : : {
433 : : struct power_supply *psy;
434 : : union power_supply_propval val;
435 : : int ret;
436 : :
437 : : psy = tcd->devdata;
438 : : val.intval = state;
439 : : ret = psy->set_property(psy,
440 : : POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
441 : :
442 : : return ret;
443 : : }
444 : :
445 : : static struct thermal_cooling_device_ops psy_tcd_ops = {
446 : : .get_max_state = ps_get_max_charge_cntl_limit,
447 : : .get_cur_state = ps_get_cur_chrage_cntl_limit,
448 : : .set_cur_state = ps_set_cur_charge_cntl_limit,
449 : : };
450 : :
451 : : static int psy_register_cooler(struct power_supply *psy)
452 : : {
453 : : int i;
454 : :
455 : : /* Register for cooling device if psy can control charging */
456 : : for (i = 0; i < psy->num_properties; i++) {
457 : : if (psy->properties[i] ==
458 : : POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) {
459 : : psy->tcd = thermal_cooling_device_register(
460 : : (char *)psy->name,
461 : : psy, &psy_tcd_ops);
462 : : if (IS_ERR(psy->tcd))
463 : : return PTR_ERR(psy->tcd);
464 : : break;
465 : : }
466 : : }
467 : : return 0;
468 : : }
469 : :
470 : : static void psy_unregister_cooler(struct power_supply *psy)
471 : : {
472 : : if (IS_ERR_OR_NULL(psy->tcd))
473 : : return;
474 : : thermal_cooling_device_unregister(psy->tcd);
475 : : }
476 : : #else
477 : : static int psy_register_thermal(struct power_supply *psy)
478 : : {
479 : : return 0;
480 : : }
481 : :
482 : : static void psy_unregister_thermal(struct power_supply *psy)
483 : : {
484 : : }
485 : :
486 : : static int psy_register_cooler(struct power_supply *psy)
487 : : {
488 : : return 0;
489 : : }
490 : :
491 : : static void psy_unregister_cooler(struct power_supply *psy)
492 : : {
493 : : }
494 : : #endif
495 : :
496 : 0 : int power_supply_register(struct device *parent, struct power_supply *psy)
497 : : {
498 : : struct device *dev;
499 : : int rc;
500 : :
501 : : dev = kzalloc(sizeof(*dev), GFP_KERNEL);
502 [ # # ]: 0 : if (!dev)
503 : : return -ENOMEM;
504 : :
505 : 0 : device_initialize(dev);
506 : :
507 : 0 : dev->class = power_supply_class;
508 : 0 : dev->type = &power_supply_dev_type;
509 : 0 : dev->parent = parent;
510 : 0 : dev->release = power_supply_dev_release;
511 : 0 : dev_set_drvdata(dev, psy);
512 : 0 : psy->dev = dev;
513 : :
514 : 0 : rc = dev_set_name(dev, "%s", psy->name);
515 [ # # ]: 0 : if (rc)
516 : : goto dev_set_name_failed;
517 : :
518 : 0 : INIT_WORK(&psy->changed_work, power_supply_changed_work);
519 : :
520 : 0 : rc = power_supply_check_supplies(psy);
521 [ # # ]: 0 : if (rc) {
522 : 0 : dev_info(dev, "Not all required supplies found, defer probe\n");
523 : 0 : goto check_supplies_failed;
524 : : }
525 : :
526 : 0 : spin_lock_init(&psy->changed_lock);
527 : 0 : rc = device_init_wakeup(dev, true);
528 [ # # ]: 0 : if (rc)
529 : : goto wakeup_init_failed;
530 : :
531 : 0 : rc = device_add(dev);
532 [ # # ]: 0 : if (rc)
533 : : goto device_add_failed;
534 : :
535 : 0 : spin_lock_init(&psy->changed_lock);
536 : 0 : rc = device_init_wakeup(dev, true);
537 [ # # ]: 0 : if (rc)
538 : : goto wakeup_init_failed;
539 : :
540 : : rc = psy_register_thermal(psy);
541 : : if (rc)
542 : : goto register_thermal_failed;
543 : :
544 : : rc = psy_register_cooler(psy);
545 : : if (rc)
546 : : goto register_cooler_failed;
547 : :
548 : 0 : rc = power_supply_create_triggers(psy);
549 [ # # ]: 0 : if (rc)
550 : : goto create_triggers_failed;
551 : :
552 : 0 : power_supply_changed(psy);
553 : :
554 : 0 : goto success;
555 : :
556 : : create_triggers_failed:
557 : : psy_unregister_cooler(psy);
558 : : register_cooler_failed:
559 : : psy_unregister_thermal(psy);
560 : : register_thermal_failed:
561 : 0 : device_del(dev);
562 : : device_add_failed:
563 : : wakeup_init_failed:
564 : : check_supplies_failed:
565 : : dev_set_name_failed:
566 : 0 : put_device(dev);
567 : : success:
568 : 0 : return rc;
569 : : }
570 : : EXPORT_SYMBOL_GPL(power_supply_register);
571 : :
572 : 0 : void power_supply_unregister(struct power_supply *psy)
573 : : {
574 : 0 : cancel_work_sync(&psy->changed_work);
575 : 0 : sysfs_remove_link(&psy->dev->kobj, "powers");
576 : 0 : power_supply_remove_triggers(psy);
577 : : psy_unregister_cooler(psy);
578 : : psy_unregister_thermal(psy);
579 : 0 : device_init_wakeup(psy->dev, false);
580 : 0 : device_unregister(psy->dev);
581 : 0 : }
582 : : EXPORT_SYMBOL_GPL(power_supply_unregister);
583 : :
584 : 0 : static int __init power_supply_class_init(void)
585 : : {
586 : 0 : power_supply_class = class_create(THIS_MODULE, "power_supply");
587 : :
588 [ # # ]: 0 : if (IS_ERR(power_supply_class))
589 : 0 : return PTR_ERR(power_supply_class);
590 : :
591 : 0 : power_supply_class->dev_uevent = power_supply_uevent;
592 : 0 : power_supply_init_attrs(&power_supply_dev_type);
593 : :
594 : 0 : return 0;
595 : : }
596 : :
597 : 0 : static void __exit power_supply_class_exit(void)
598 : : {
599 : 0 : class_destroy(power_supply_class);
600 : 0 : }
601 : :
602 : : subsys_initcall(power_supply_class_init);
603 : : module_exit(power_supply_class_exit);
604 : :
605 : : MODULE_DESCRIPTION("Universal power supply monitor class");
606 : : MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
607 : : "Szabolcs Gyurko, "
608 : : "Anton Vorontsov <cbou@mail.ru>");
609 : : MODULE_LICENSE("GPL");
|