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

Configure Feed

Select the types of activity you want to include in your feed.

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