summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/regulator/core.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index cc1d1214766..41b6aa640e1 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -88,7 +88,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
static void _notifier_call_chain(struct regulator_dev *rdev,
- unsigned long event, void *data);
+ unsigned long event, void *data, int lock_sublevel);
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV);
@@ -1439,7 +1439,7 @@ static int _regulator_disable(struct regulator_dev *rdev,
trace_regulator_disable_complete(rdev_get_name(rdev));
_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
- NULL);
+ NULL, 0);
}
/* decrease our supplies ref count and disable if required */
@@ -1512,7 +1512,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
}
/* notify other consumers that power has been forced off */
_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
- REGULATOR_EVENT_DISABLE, NULL);
+ REGULATOR_EVENT_DISABLE, NULL, 0);
}
/* decrease our supplies ref count and disable if required */
@@ -1734,7 +1734,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
if (ret == 0)
_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
- NULL);
+ NULL, 0);
trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector);
@@ -2202,19 +2202,23 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
/* notify regulator consumers and downstream regulator consumers.
* Note mutex must be held by caller.
+ * lock_sublevel should always be 0, only used for recursive calls.
*/
static void _notifier_call_chain(struct regulator_dev *rdev,
- unsigned long event, void *data)
+ unsigned long event, void *data, int lock_sublevel)
{
struct regulator_dev *_rdev;
/* call rdev chain first */
blocking_notifier_call_chain(&rdev->notifier, event, NULL);
+ /* increase sublevel before stepping into nested regulators */
+ lock_sublevel++;
+
/* now notify regulator we supply */
list_for_each_entry(_rdev, &rdev->supply_list, slist) {
- mutex_lock(&_rdev->mutex);
- _notifier_call_chain(_rdev, event, data);
+ mutex_lock_nested(&_rdev->mutex, lock_sublevel);
+ _notifier_call_chain(_rdev, event, data, lock_sublevel);
mutex_unlock(&_rdev->mutex);
}
}
@@ -2368,7 +2372,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free);
int regulator_notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
{
- _notifier_call_chain(rdev, event, data);
+ _notifier_call_chain(rdev, event, data, 0);
return NOTIFY_DONE;
}