aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/power/power_supply_core.c47
-rw-r--r--include/linux/power_supply.h16
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
315int power_supply_set_battery_charged(struct power_supply *psy) 315int 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,
366EXPORT_SYMBOL_GPL(power_supply_get_by_phandle); 368EXPORT_SYMBOL_GPL(power_supply_get_by_phandle);
367#endif /* CONFIG_OF */ 369#endif /* CONFIG_OF */
368 370
371int 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}
380EXPORT_SYMBOL_GPL(power_supply_get_property);
381
382int 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}
391EXPORT_SYMBOL_GPL(power_supply_set_property);
392
393int 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}
401EXPORT_SYMBOL_GPL(power_supply_property_is_writeable);
402
403void 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}
410EXPORT_SYMBOL_GPL(power_supply_external_power_changed);
411
369int power_supply_powers(struct power_supply *psy, struct device *dev) 412int 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
677void power_supply_unregister(struct power_supply *psy) 721void 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);
287static inline int power_supply_is_system_supplied(void) { return -ENOSYS; } 294static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
288#endif 295#endif
289 296
297extern int power_supply_get_property(struct power_supply *psy,
298 enum power_supply_property psp,
299 union power_supply_propval *val);
300extern int power_supply_set_property(struct power_supply *psy,
301 enum power_supply_property psp,
302 const union power_supply_propval *val);
303extern int power_supply_property_is_writeable(struct power_supply *psy,
304 enum power_supply_property psp);
305extern void power_supply_external_power_changed(struct power_supply *psy);
290extern int power_supply_register(struct device *parent, 306extern 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);