diff options
Diffstat (limited to 'drivers/power/power_supply_core.c')
-rw-r--r-- | drivers/power/power_supply_core.c | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 970f7335d3a..b0ab88bfe47 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -41,23 +41,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) + wake_unlock(&psy->work_wake_lock); + 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; + wake_lock(&psy->work_wake_lock); + spin_unlock_irqrestore(&psy->changed_lock, flags); schedule_work(&psy->changed_work); } EXPORT_SYMBOL_GPL(power_supply_changed); @@ -180,6 +197,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy) goto device_add_failed; INIT_WORK(&psy->changed_work, power_supply_changed_work); + spin_lock_init(&psy->changed_lock); + wake_lock_init(&psy->work_wake_lock, WAKE_LOCK_SUSPEND, "power-supply"); rc = power_supply_create_triggers(psy); if (rc) @@ -190,6 +209,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy) goto success; create_triggers_failed: + wake_lock_destroy(&psy->work_wake_lock); device_del(dev); kobject_set_name_failed: device_add_failed: @@ -203,6 +223,7 @@ void power_supply_unregister(struct power_supply *psy) { cancel_work_sync(&psy->changed_work); power_supply_remove_triggers(psy); + wake_lock_destroy(&psy->work_wake_lock); device_unregister(psy->dev); } EXPORT_SYMBOL_GPL(power_supply_unregister); |