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.15-rc1 648 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 = (struct power_supply *)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 if (psy->changed) { 82 psy->changed = false; 83 spin_unlock_irqrestore(&psy->changed_lock, flags); 84 class_for_each_device(power_supply_class, NULL, psy, 85 __power_supply_changed_work); 86 power_supply_update_leds(psy); 87 atomic_notifier_call_chain(&power_supply_notifier, 88 PSY_EVENT_PROP_CHANGED, psy); 89 kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); 90 spin_lock_irqsave(&psy->changed_lock, flags); 91 } 92 /* 93 * Dependent power supplies (e.g. battery) may have changed state 94 * as a result of this event, so poll again and hold the 95 * wakeup_source until all events are processed. 96 */ 97 if (!psy->changed) 98 pm_relax(psy->dev); 99 spin_unlock_irqrestore(&psy->changed_lock, flags); 100} 101 102void power_supply_changed(struct power_supply *psy) 103{ 104 unsigned long flags; 105 106 dev_dbg(psy->dev, "%s\n", __func__); 107 108 spin_lock_irqsave(&psy->changed_lock, flags); 109 psy->changed = true; 110 pm_stay_awake(psy->dev); 111 spin_unlock_irqrestore(&psy->changed_lock, flags); 112 schedule_work(&psy->changed_work); 113} 114EXPORT_SYMBOL_GPL(power_supply_changed); 115 116#ifdef CONFIG_OF 117#include <linux/of.h> 118 119static int __power_supply_populate_supplied_from(struct device *dev, 120 void *data) 121{ 122 struct power_supply *psy = (struct power_supply *)data; 123 struct power_supply *epsy = dev_get_drvdata(dev); 124 struct device_node *np; 125 int i = 0; 126 127 do { 128 np = of_parse_phandle(psy->of_node, "power-supplies", i++); 129 if (!np) 130 continue; 131 132 if (np == epsy->of_node) { 133 dev_info(psy->dev, "%s: Found supply : %s\n", 134 psy->name, epsy->name); 135 psy->supplied_from[i-1] = (char *)epsy->name; 136 psy->num_supplies++; 137 of_node_put(np); 138 break; 139 } 140 of_node_put(np); 141 } while (np); 142 143 return 0; 144} 145 146static int power_supply_populate_supplied_from(struct power_supply *psy) 147{ 148 int error; 149 150 error = class_for_each_device(power_supply_class, NULL, psy, 151 __power_supply_populate_supplied_from); 152 153 dev_dbg(psy->dev, "%s %d\n", __func__, error); 154 155 return error; 156} 157 158static int __power_supply_find_supply_from_node(struct device *dev, 159 void *data) 160{ 161 struct device_node *np = (struct device_node *)data; 162 struct power_supply *epsy = dev_get_drvdata(dev); 163 164 /* return error breaks out of class_for_each_device loop */ 165 if (epsy->of_node == np) 166 return -EINVAL; 167 168 return 0; 169} 170 171static int power_supply_find_supply_from_node(struct device_node *supply_node) 172{ 173 int error; 174 struct device *dev; 175 struct class_dev_iter iter; 176 177 /* 178 * Use iterator to see if any other device is registered. 179 * This is required since class_for_each_device returns 0 180 * if there are no devices registered. 181 */ 182 class_dev_iter_init(&iter, power_supply_class, NULL, NULL); 183 dev = class_dev_iter_next(&iter); 184 185 if (!dev) 186 return -EPROBE_DEFER; 187 188 /* 189 * We have to treat the return value as inverted, because if 190 * we return error on not found, then it won't continue looking. 191 * So we trick it by returning error on success to stop looking 192 * once the matching device is found. 193 */ 194 error = class_for_each_device(power_supply_class, NULL, supply_node, 195 __power_supply_find_supply_from_node); 196 197 return error ? 0 : -EPROBE_DEFER; 198} 199 200static int power_supply_check_supplies(struct power_supply *psy) 201{ 202 struct device_node *np; 203 int cnt = 0; 204 205 /* If there is already a list honor it */ 206 if (psy->supplied_from && psy->num_supplies > 0) 207 return 0; 208 209 /* No device node found, nothing to do */ 210 if (!psy->of_node) 211 return 0; 212 213 do { 214 int ret; 215 216 np = of_parse_phandle(psy->of_node, "power-supplies", cnt++); 217 if (!np) 218 continue; 219 220 ret = power_supply_find_supply_from_node(np); 221 if (ret) { 222 dev_dbg(psy->dev, "Failed to find supply, defer!\n"); 223 of_node_put(np); 224 return -EPROBE_DEFER; 225 } 226 of_node_put(np); 227 } while (np); 228 229 /* All supplies found, allocate char ** array for filling */ 230 psy->supplied_from = devm_kzalloc(psy->dev, sizeof(psy->supplied_from), 231 GFP_KERNEL); 232 if (!psy->supplied_from) { 233 dev_err(psy->dev, "Couldn't allocate memory for supply list\n"); 234 return -ENOMEM; 235 } 236 237 *psy->supplied_from = devm_kzalloc(psy->dev, sizeof(char *) * cnt, 238 GFP_KERNEL); 239 if (!*psy->supplied_from) { 240 dev_err(psy->dev, "Couldn't allocate memory for supply list\n"); 241 return -ENOMEM; 242 } 243 244 return power_supply_populate_supplied_from(psy); 245} 246#else 247static inline int power_supply_check_supplies(struct power_supply *psy) 248{ 249 return 0; 250} 251#endif 252 253static int __power_supply_am_i_supplied(struct device *dev, void *data) 254{ 255 union power_supply_propval ret = {0,}; 256 struct power_supply *psy = (struct power_supply *)data; 257 struct power_supply *epsy = dev_get_drvdata(dev); 258 259 if (__power_supply_is_supplied_by(epsy, psy)) 260 if (!epsy->get_property(epsy, POWER_SUPPLY_PROP_ONLINE, &ret)) { 261 if (ret.intval) 262 return ret.intval; 263 } 264 265 return 0; 266} 267 268int power_supply_am_i_supplied(struct power_supply *psy) 269{ 270 int error; 271 272 error = class_for_each_device(power_supply_class, NULL, psy, 273 __power_supply_am_i_supplied); 274 275 dev_dbg(psy->dev, "%s %d\n", __func__, error); 276 277 return error; 278} 279EXPORT_SYMBOL_GPL(power_supply_am_i_supplied); 280 281static int __power_supply_is_system_supplied(struct device *dev, void *data) 282{ 283 union power_supply_propval ret = {0,}; 284 struct power_supply *psy = dev_get_drvdata(dev); 285 unsigned int *count = data; 286 287 (*count)++; 288 if (psy->type != POWER_SUPPLY_TYPE_BATTERY) { 289 if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret)) 290 return 0; 291 if (ret.intval) 292 return ret.intval; 293 } 294 return 0; 295} 296 297int power_supply_is_system_supplied(void) 298{ 299 int error; 300 unsigned int count = 0; 301 302 error = class_for_each_device(power_supply_class, NULL, &count, 303 __power_supply_is_system_supplied); 304 305 /* 306 * If no power class device was found at all, most probably we are 307 * running on a desktop system, so assume we are on mains power. 308 */ 309 if (count == 0) 310 return 1; 311 312 return error; 313} 314EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); 315 316int power_supply_set_battery_charged(struct power_supply *psy) 317{ 318 if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) { 319 psy->set_charged(psy); 320 return 0; 321 } 322 323 return -EINVAL; 324} 325EXPORT_SYMBOL_GPL(power_supply_set_battery_charged); 326 327static int power_supply_match_device_by_name(struct device *dev, const void *data) 328{ 329 const char *name = data; 330 struct power_supply *psy = dev_get_drvdata(dev); 331 332 return strcmp(psy->name, name) == 0; 333} 334 335struct power_supply *power_supply_get_by_name(const char *name) 336{ 337 struct device *dev = class_find_device(power_supply_class, NULL, name, 338 power_supply_match_device_by_name); 339 340 return dev ? dev_get_drvdata(dev) : NULL; 341} 342EXPORT_SYMBOL_GPL(power_supply_get_by_name); 343 344#ifdef CONFIG_OF 345static int power_supply_match_device_node(struct device *dev, const void *data) 346{ 347 return dev->parent && dev->parent->of_node == data; 348} 349 350struct power_supply *power_supply_get_by_phandle(struct device_node *np, 351 const char *property) 352{ 353 struct device_node *power_supply_np; 354 struct device *dev; 355 356 power_supply_np = of_parse_phandle(np, property, 0); 357 if (!power_supply_np) 358 return ERR_PTR(-ENODEV); 359 360 dev = class_find_device(power_supply_class, NULL, power_supply_np, 361 power_supply_match_device_node); 362 363 of_node_put(power_supply_np); 364 365 return dev ? dev_get_drvdata(dev) : NULL; 366} 367EXPORT_SYMBOL_GPL(power_supply_get_by_phandle); 368#endif /* CONFIG_OF */ 369 370int power_supply_powers(struct power_supply *psy, struct device *dev) 371{ 372 return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers"); 373} 374EXPORT_SYMBOL_GPL(power_supply_powers); 375 376static void power_supply_dev_release(struct device *dev) 377{ 378 pr_debug("device: '%s': %s\n", dev_name(dev), __func__); 379 kfree(dev); 380} 381 382int power_supply_reg_notifier(struct notifier_block *nb) 383{ 384 return atomic_notifier_chain_register(&power_supply_notifier, nb); 385} 386EXPORT_SYMBOL_GPL(power_supply_reg_notifier); 387 388void power_supply_unreg_notifier(struct notifier_block *nb) 389{ 390 atomic_notifier_chain_unregister(&power_supply_notifier, nb); 391} 392EXPORT_SYMBOL_GPL(power_supply_unreg_notifier); 393 394#ifdef CONFIG_THERMAL 395static int power_supply_read_temp(struct thermal_zone_device *tzd, 396 unsigned long *temp) 397{ 398 struct power_supply *psy; 399 union power_supply_propval val; 400 int ret; 401 402 WARN_ON(tzd == NULL); 403 psy = tzd->devdata; 404 ret = psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val); 405 406 /* Convert tenths of degree Celsius to milli degree Celsius. */ 407 if (!ret) 408 *temp = val.intval * 100; 409 410 return ret; 411} 412 413static struct thermal_zone_device_ops psy_tzd_ops = { 414 .get_temp = power_supply_read_temp, 415}; 416 417static int psy_register_thermal(struct power_supply *psy) 418{ 419 int i; 420 421 /* Register battery zone device psy reports temperature */ 422 for (i = 0; i < psy->num_properties; i++) { 423 if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) { 424 psy->tzd = thermal_zone_device_register(psy->name, 0, 0, 425 psy, &psy_tzd_ops, NULL, 0, 0); 426 if (IS_ERR(psy->tzd)) 427 return PTR_ERR(psy->tzd); 428 break; 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 if (IS_ERR(psy->tcd)) 507 return PTR_ERR(psy->tcd); 508 break; 509 } 510 } 511 return 0; 512} 513 514static void psy_unregister_cooler(struct power_supply *psy) 515{ 516 if (IS_ERR_OR_NULL(psy->tcd)) 517 return; 518 thermal_cooling_device_unregister(psy->tcd); 519} 520#else 521static int psy_register_thermal(struct power_supply *psy) 522{ 523 return 0; 524} 525 526static void psy_unregister_thermal(struct power_supply *psy) 527{ 528} 529 530static int psy_register_cooler(struct power_supply *psy) 531{ 532 return 0; 533} 534 535static void psy_unregister_cooler(struct power_supply *psy) 536{ 537} 538#endif 539 540int power_supply_register(struct device *parent, struct power_supply *psy) 541{ 542 struct device *dev; 543 int rc; 544 545 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 546 if (!dev) 547 return -ENOMEM; 548 549 device_initialize(dev); 550 551 dev->class = power_supply_class; 552 dev->type = &power_supply_dev_type; 553 dev->parent = parent; 554 dev->release = power_supply_dev_release; 555 dev_set_drvdata(dev, psy); 556 psy->dev = dev; 557 558 rc = dev_set_name(dev, "%s", psy->name); 559 if (rc) 560 goto dev_set_name_failed; 561 562 INIT_WORK(&psy->changed_work, power_supply_changed_work); 563 564 rc = power_supply_check_supplies(psy); 565 if (rc) { 566 dev_info(dev, "Not all required supplies found, defer probe\n"); 567 goto check_supplies_failed; 568 } 569 570 spin_lock_init(&psy->changed_lock); 571 rc = device_init_wakeup(dev, true); 572 if (rc) 573 goto wakeup_init_failed; 574 575 rc = device_add(dev); 576 if (rc) 577 goto device_add_failed; 578 579 rc = psy_register_thermal(psy); 580 if (rc) 581 goto register_thermal_failed; 582 583 rc = psy_register_cooler(psy); 584 if (rc) 585 goto register_cooler_failed; 586 587 rc = power_supply_create_triggers(psy); 588 if (rc) 589 goto create_triggers_failed; 590 591 power_supply_changed(psy); 592 593 goto success; 594 595create_triggers_failed: 596 psy_unregister_cooler(psy); 597register_cooler_failed: 598 psy_unregister_thermal(psy); 599register_thermal_failed: 600 device_del(dev); 601device_add_failed: 602wakeup_init_failed: 603check_supplies_failed: 604dev_set_name_failed: 605 put_device(dev); 606success: 607 return rc; 608} 609EXPORT_SYMBOL_GPL(power_supply_register); 610 611void power_supply_unregister(struct power_supply *psy) 612{ 613 cancel_work_sync(&psy->changed_work); 614 sysfs_remove_link(&psy->dev->kobj, "powers"); 615 power_supply_remove_triggers(psy); 616 psy_unregister_cooler(psy); 617 psy_unregister_thermal(psy); 618 device_init_wakeup(psy->dev, false); 619 device_unregister(psy->dev); 620} 621EXPORT_SYMBOL_GPL(power_supply_unregister); 622 623static int __init power_supply_class_init(void) 624{ 625 power_supply_class = class_create(THIS_MODULE, "power_supply"); 626 627 if (IS_ERR(power_supply_class)) 628 return PTR_ERR(power_supply_class); 629 630 power_supply_class->dev_uevent = power_supply_uevent; 631 power_supply_init_attrs(&power_supply_dev_type); 632 633 return 0; 634} 635 636static void __exit power_supply_class_exit(void) 637{ 638 class_destroy(power_supply_class); 639} 640 641subsys_initcall(power_supply_class_init); 642module_exit(power_supply_class_exit); 643 644MODULE_DESCRIPTION("Universal power supply monitor class"); 645MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, " 646 "Szabolcs Gyurko, " 647 "Anton Vorontsov <cbou@mail.ru>"); 648MODULE_LICENSE("GPL");