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