diff options
Diffstat (limited to 'drivers/power/power_supply_core.c')
-rw-r--r-- | drivers/power/power_supply_core.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 1c517c34e4be..082d3c2714e9 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -67,23 +67,40 @@ static int __power_supply_changed_work(struct device *dev, void *data) static void power_supply_changed_work(struct work_struct *work) { + unsigned long flags; struct power_supply *psy = container_of(work, struct power_supply, changed_work); dev_dbg(psy->dev, "%s\n", __func__); - class_for_each_device(power_supply_class, NULL, psy, - __power_supply_changed_work); + spin_lock_irqsave(&psy->changed_lock, flags); + if (psy->changed) { + psy->changed = false; + spin_unlock_irqrestore(&psy->changed_lock, flags); - power_supply_update_leds(psy); + class_for_each_device(power_supply_class, NULL, psy, + __power_supply_changed_work); - kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); + power_supply_update_leds(psy); + + kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); + spin_lock_irqsave(&psy->changed_lock, flags); + } + if (!psy->changed) + pm_relax(psy->dev); + spin_unlock_irqrestore(&psy->changed_lock, flags); } void power_supply_changed(struct power_supply *psy) { + unsigned long flags; + dev_dbg(psy->dev, "%s\n", __func__); + spin_lock_irqsave(&psy->changed_lock, flags); + psy->changed = true; + pm_stay_awake(psy->dev); + spin_unlock_irqrestore(&psy->changed_lock, flags); schedule_work(&psy->changed_work); } EXPORT_SYMBOL_GPL(power_supply_changed); @@ -504,6 +521,11 @@ int power_supply_register(struct device *parent, struct power_supply *psy) if (rc) goto device_add_failed; + spin_lock_init(&psy->changed_lock); + rc = device_init_wakeup(dev, true); + if (rc) + goto wakeup_init_failed; + rc = psy_register_thermal(psy); if (rc) goto register_thermal_failed; @@ -525,6 +547,7 @@ create_triggers_failed: register_cooler_failed: psy_unregister_thermal(psy); register_thermal_failed: +wakeup_init_failed: device_del(dev); kobject_set_name_failed: device_add_failed: |