diff options
-rw-r--r-- | drivers/power/power_supply_core.c | 47 | ||||
-rw-r--r-- | include/linux/power_supply.h | 16 |
2 files changed, 62 insertions, 1 deletions
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index a21e36ed8d41..583dece8845b 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
@@ -314,7 +314,9 @@ EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); | |||
314 | 314 | ||
315 | int power_supply_set_battery_charged(struct power_supply *psy) | 315 | int power_supply_set_battery_charged(struct power_supply *psy) |
316 | { | 316 | { |
317 | if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) { | 317 | if (atomic_read(&psy->use_cnt) >= 0 && |
318 | psy->type == POWER_SUPPLY_TYPE_BATTERY && | ||
319 | psy->set_charged) { | ||
318 | psy->set_charged(psy); | 320 | psy->set_charged(psy); |
319 | return 0; | 321 | return 0; |
320 | } | 322 | } |
@@ -366,6 +368,47 @@ struct power_supply *power_supply_get_by_phandle(struct device_node *np, | |||
366 | EXPORT_SYMBOL_GPL(power_supply_get_by_phandle); | 368 | EXPORT_SYMBOL_GPL(power_supply_get_by_phandle); |
367 | #endif /* CONFIG_OF */ | 369 | #endif /* CONFIG_OF */ |
368 | 370 | ||
371 | int power_supply_get_property(struct power_supply *psy, | ||
372 | enum power_supply_property psp, | ||
373 | union power_supply_propval *val) | ||
374 | { | ||
375 | if (atomic_read(&psy->use_cnt) <= 0) | ||
376 | return -ENODEV; | ||
377 | |||
378 | return psy->get_property(psy, psp, val); | ||
379 | } | ||
380 | EXPORT_SYMBOL_GPL(power_supply_get_property); | ||
381 | |||
382 | int power_supply_set_property(struct power_supply *psy, | ||
383 | enum power_supply_property psp, | ||
384 | const union power_supply_propval *val) | ||
385 | { | ||
386 | if (atomic_read(&psy->use_cnt) <= 0 || !psy->set_property) | ||
387 | return -ENODEV; | ||
388 | |||
389 | return psy->set_property(psy, psp, val); | ||
390 | } | ||
391 | EXPORT_SYMBOL_GPL(power_supply_set_property); | ||
392 | |||
393 | int power_supply_property_is_writeable(struct power_supply *psy, | ||
394 | enum power_supply_property psp) | ||
395 | { | ||
396 | if (atomic_read(&psy->use_cnt) <= 0 || !psy->property_is_writeable) | ||
397 | return -ENODEV; | ||
398 | |||
399 | return psy->property_is_writeable(psy, psp); | ||
400 | } | ||
401 | EXPORT_SYMBOL_GPL(power_supply_property_is_writeable); | ||
402 | |||
403 | void power_supply_external_power_changed(struct power_supply *psy) | ||
404 | { | ||
405 | if (atomic_read(&psy->use_cnt) <= 0 || !psy->external_power_changed) | ||
406 | return; | ||
407 | |||
408 | psy->external_power_changed(psy); | ||
409 | } | ||
410 | EXPORT_SYMBOL_GPL(power_supply_external_power_changed); | ||
411 | |||
369 | int power_supply_powers(struct power_supply *psy, struct device *dev) | 412 | int power_supply_powers(struct power_supply *psy, struct device *dev) |
370 | { | 413 | { |
371 | return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers"); | 414 | return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers"); |
@@ -555,6 +598,7 @@ static int __power_supply_register(struct device *parent, | |||
555 | dev->release = power_supply_dev_release; | 598 | dev->release = power_supply_dev_release; |
556 | dev_set_drvdata(dev, psy); | 599 | dev_set_drvdata(dev, psy); |
557 | psy->dev = dev; | 600 | psy->dev = dev; |
601 | atomic_inc(&psy->use_cnt); | ||
558 | if (cfg) { | 602 | if (cfg) { |
559 | psy->drv_data = cfg->drv_data; | 603 | psy->drv_data = cfg->drv_data; |
560 | psy->of_node = cfg->of_node; | 604 | psy->of_node = cfg->of_node; |
@@ -676,6 +720,7 @@ EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws); | |||
676 | 720 | ||
677 | void power_supply_unregister(struct power_supply *psy) | 721 | void power_supply_unregister(struct power_supply *psy) |
678 | { | 722 | { |
723 | WARN_ON(atomic_dec_return(&psy->use_cnt)); | ||
679 | cancel_work_sync(&psy->changed_work); | 724 | cancel_work_sync(&psy->changed_work); |
680 | sysfs_remove_link(&psy->dev->kobj, "powers"); | 725 | sysfs_remove_link(&psy->dev->kobj, "powers"); |
681 | power_supply_remove_triggers(psy); | 726 | power_supply_remove_triggers(psy); |
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 0d7c95f634a5..7ae60346465f 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h | |||
@@ -199,6 +199,12 @@ struct power_supply { | |||
199 | size_t num_supplies; | 199 | size_t num_supplies; |
200 | struct device_node *of_node; | 200 | struct device_node *of_node; |
201 | 201 | ||
202 | /* | ||
203 | * Functions for drivers implementing power supply class. | ||
204 | * These shouldn't be called directly by other drivers for accessing | ||
205 | * this power supply. Instead use power_supply_*() functions (for | ||
206 | * example power_supply_get_property()). | ||
207 | */ | ||
202 | int (*get_property)(struct power_supply *psy, | 208 | int (*get_property)(struct power_supply *psy, |
203 | enum power_supply_property psp, | 209 | enum power_supply_property psp, |
204 | union power_supply_propval *val); | 210 | union power_supply_propval *val); |
@@ -227,6 +233,7 @@ struct power_supply { | |||
227 | struct work_struct changed_work; | 233 | struct work_struct changed_work; |
228 | spinlock_t changed_lock; | 234 | spinlock_t changed_lock; |
229 | bool changed; | 235 | bool changed; |
236 | atomic_t use_cnt; | ||
230 | #ifdef CONFIG_THERMAL | 237 | #ifdef CONFIG_THERMAL |
231 | struct thermal_zone_device *tzd; | 238 | struct thermal_zone_device *tzd; |
232 | struct thermal_cooling_device *tcd; | 239 | struct thermal_cooling_device *tcd; |
@@ -287,6 +294,15 @@ extern int power_supply_is_system_supplied(void); | |||
287 | static inline int power_supply_is_system_supplied(void) { return -ENOSYS; } | 294 | static inline int power_supply_is_system_supplied(void) { return -ENOSYS; } |
288 | #endif | 295 | #endif |
289 | 296 | ||
297 | extern int power_supply_get_property(struct power_supply *psy, | ||
298 | enum power_supply_property psp, | ||
299 | union power_supply_propval *val); | ||
300 | extern int power_supply_set_property(struct power_supply *psy, | ||
301 | enum power_supply_property psp, | ||
302 | const union power_supply_propval *val); | ||
303 | extern int power_supply_property_is_writeable(struct power_supply *psy, | ||
304 | enum power_supply_property psp); | ||
305 | extern void power_supply_external_power_changed(struct power_supply *psy); | ||
290 | extern int power_supply_register(struct device *parent, | 306 | extern int power_supply_register(struct device *parent, |
291 | struct power_supply *psy, | 307 | struct power_supply *psy, |
292 | const struct power_supply_config *cfg); | 308 | const struct power_supply_config *cfg); |