summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/power/supply/power_supply_core.c11
-rw-r--r--include/linux/power_supply.h1
2 files changed, 10 insertions, 2 deletions
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index a74d8ca383a1..9e05ae0430a9 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/err.h>
@@ -138,8 +139,13 @@ static void power_supply_deferred_register_work(struct work_struct *work)
struct power_supply *psy = container_of(work, struct power_supply,
deferred_register_work.work);
- if (psy->dev.parent)
- mutex_lock(&psy->dev.parent->mutex);
+ if (psy->dev.parent) {
+ while (!mutex_trylock(&psy->dev.parent->mutex)) {
+ if (psy->removing)
+ return;
+ msleep(10);
+ }
+ }
power_supply_changed(psy);
@@ -944,6 +950,7 @@ EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws);
void power_supply_unregister(struct power_supply *psy)
{
WARN_ON(atomic_dec_return(&psy->use_cnt));
+ psy->removing = true;
cancel_work_sync(&psy->changed_work);
cancel_delayed_work_sync(&psy->deferred_register_work);
sysfs_remove_link(&psy->dev.kobj, "powers");
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 3965503315ef..ad97baf7b8de 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -249,6 +249,7 @@ struct power_supply {
spinlock_t changed_lock;
bool changed;
bool initialized;
+ bool removing;
atomic_t use_cnt;
#ifdef CONFIG_THERMAL
struct thermal_zone_device *tzd;