}
/**
+ * regulator_lock_nested - lock a single regulator
+ * @rdev: regulator source
+ * @subclass: mutex subclass used for lockdep
+ *
+ * This function can be called many times by one task on
+ * a single regulator and its mutex will be locked only
+ * once. If a task, which is calling this function is other
+ * than the one, which initially locked the mutex, it will
+ * wait on mutex.
+ */
+static void regulator_lock_nested(struct regulator_dev *rdev,
+ unsigned int subclass)
+{
+ if (!mutex_trylock(&rdev->mutex)) {
+ if (rdev->mutex_owner == current) {
+ rdev->ref_cnt++;
+ return;
+ }
+ mutex_lock_nested(&rdev->mutex, subclass);
+ }
+
+ rdev->ref_cnt = 1;
+ rdev->mutex_owner = current;
+}
+
+static inline void regulator_lock(struct regulator_dev *rdev)
+{
+ regulator_lock_nested(rdev, 0);
+}
+
+/**
+ * regulator_unlock - unlock a single regulator
+ * @rdev: regulator_source
+ *
+ * This function unlocks the mutex when the
+ * reference counter reaches 0.
+ */
+static void regulator_unlock(struct regulator_dev *rdev)
+{
+ if (rdev->ref_cnt != 0) {
+ rdev->ref_cnt--;
+
+ if (!rdev->ref_cnt) {
+ rdev->mutex_owner = NULL;
+ mutex_unlock(&rdev->mutex);
+ }
+ }
+}
+
+/**
* regulator_lock_supply - lock a regulator and its supplies
* @rdev: regulator source
*/
int i;
for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++)
- mutex_lock_nested(&rdev->mutex, i);
+ regulator_lock_nested(rdev, i);
}
/**
struct regulator *supply;
while (1) {
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
supply = rdev->supply;
if (!rdev->supply)
struct regulator_dev *rdev = dev_get_drvdata(dev);
ssize_t ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev));
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
struct regulator_dev *rdev = dev_get_drvdata(dev);
ssize_t ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
ret = regulator_print_state(buf, _regulator_is_enabled(rdev));
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
struct regulator *regulator;
int uA = 0;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
list_for_each_entry(regulator, &rdev->consumer_list, list)
uA += regulator->uA_load;
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return sprintf(buf, "%d\n", uA);
}
static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL);
if (regulator == NULL)
return NULL;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
regulator->rdev = rdev;
list_add(®ulator->list, &rdev->consumer_list);
_regulator_is_enabled(rdev))
regulator->always_on = true;
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return regulator;
overflow_err:
list_del(®ulator->list);
kfree(regulator);
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return NULL;
}
/* remove any sysfs entries */
if (regulator->dev)
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
list_del(®ulator->list);
rdev->open_count--;
rdev->exclusive = 0;
put_device(&rdev->dev);
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
kfree_const(regulator->supply_name);
kfree(regulator);
disable_work.work);
int count, i, ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
BUG_ON(!rdev->deferred_disables);
rdev_err(rdev, "Deferred disable failed: %d\n", ret);
}
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
if (rdev->supply) {
for (i = 0; i < count; i++) {
if (!ms)
return regulator_disable(regulator);
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
rdev->deferred_disables++;
mod_delayed_work(system_power_efficient_wq, &rdev->disable_work,
msecs_to_jiffies(ms));
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return 0;
}
if (selector >= rdev->desc->n_voltages)
return -EINVAL;
if (lock)
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
ret = ops->list_voltage(rdev, selector);
if (lock)
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
} else if (rdev->is_switch && rdev->supply) {
ret = _regulator_list_voltage(rdev->supply->rdev,
selector, lock);
struct regulator_voltage *voltage = ®ulator->voltage[PM_SUSPEND_ON];
int ret, min_uV, max_uV;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
if (!rdev->desc->ops->set_voltage &&
!rdev->desc->ops->set_voltage_sel) {
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
out:
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_sync_voltage);
struct regulator_dev *rdev = regulator->rdev;
int ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
/* sanity check */
if (!rdev->desc->ops->set_current_limit) {
ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA);
out:
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_current_limit);
{
int ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
/* sanity check */
if (!rdev->desc->ops->get_current_limit) {
ret = rdev->desc->ops->get_current_limit(rdev);
out:
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
int ret;
int regulator_curr_mode;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
/* sanity check */
if (!rdev->desc->ops->set_mode) {
ret = rdev->desc->ops->set_mode(rdev, mode);
out:
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_mode);
{
int ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
/* sanity check */
if (!rdev->desc->ops->get_mode) {
ret = rdev->desc->ops->get_mode(rdev);
out:
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
{
int ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
/* sanity check */
if (!rdev->desc->ops->get_error_flags) {
ret = rdev->desc->ops->get_error_flags(rdev, flags);
out:
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
struct regulator_dev *rdev = regulator->rdev;
int ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
regulator->uA_load = uA_load;
ret = drms_uA_update(rdev);
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_BYPASS))
return 0;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
if (enable && !regulator->bypass) {
rdev->bypass_count++;
if (ret == 0)
regulator->bypass = enable;
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
suspend_state_t *state = data;
int ret;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
ret = suspend_set_state(rdev, *state);
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
if (rstate == NULL)
return 0;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
if (rdev->desc->ops->resume_early &&
(rstate->enabled == ENABLE_IN_SUSPEND ||
rstate->enabled == DISABLE_IN_SUSPEND))
ret = rdev->desc->ops->resume_early(rdev);
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return ret;
}
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS))
return 0;
- mutex_lock(&rdev->mutex);
+ regulator_lock(rdev);
if (rdev->use_count)
goto unlock;
}
unlock:
- mutex_unlock(&rdev->mutex);
+ regulator_unlock(rdev);
return 0;
}