From ea08eeccae9297f7aabd2ef7f0c2517ac4549acc Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:18:26 +0000
Subject: [PATCH] write in 30M
---
kernel/drivers/regulator/core.c | 2504 +++++++++++++++++++++++++++++++++++++++++------------------
1 files changed, 1,726 insertions(+), 778 deletions(-)
diff --git a/kernel/drivers/regulator/core.c b/kernel/drivers/regulator/core.c
index b86d2d5..7105e1b 100644
--- a/kernel/drivers/regulator/core.c
+++ b/kernel/drivers/regulator/core.c
@@ -1,17 +1,11 @@
-/*
- * core.c -- Voltage/Current Regulator framework.
- *
- * Copyright 2007, 2008 Wolfson Microelectronics PLC.
- * Copyright 2008 SlimLogic Ltd.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// core.c -- Voltage/Current Regulator framework.
+//
+// Copyright 2007, 2008 Wolfson Microelectronics PLC.
+// Copyright 2008 SlimLogic Ltd.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -23,14 +17,12 @@
#include <linux/mutex.h>
#include <linux/suspend.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/regmap.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/consumer.h>
+#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/module.h>
@@ -52,12 +44,14 @@
#define rdev_dbg(rdev, fmt, ...) \
pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+static DEFINE_WW_CLASS(regulator_ww_class);
+static DEFINE_MUTEX(regulator_nesting_mutex);
static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_map_list);
static LIST_HEAD(regulator_ena_gpio_list);
static LIST_HEAD(regulator_supply_alias_list);
+static LIST_HEAD(regulator_coupler_list);
static LIST_HEAD(regulator_debug_list);
-static LIST_HEAD(regulator_early_min_volt_list);
static bool has_full_constraints;
static struct dentry *debugfs_root;
@@ -84,7 +78,6 @@
struct gpio_desc *gpiod;
u32 enable_count; /* a number of enabled shared GPIO */
u32 request_count; /* a number of requested shared GPIO */
- unsigned int ena_gpio_invert:1;
};
/*
@@ -106,20 +99,22 @@
};
static int _regulator_is_enabled(struct regulator_dev *rdev);
-static int _regulator_disable(struct regulator_dev *rdev);
-static int _regulator_get_voltage(struct regulator_dev *rdev);
+static int _regulator_disable(struct regulator *regulator);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
static int _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data);
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV);
+static int regulator_balance_voltage(struct regulator_dev *rdev,
+ suspend_state_t state);
static struct regulator *create_regulator(struct regulator_dev *rdev,
struct device *dev,
const char *supply_name);
+static void destroy_regulator(struct regulator *regulator);
static void _regulator_put(struct regulator *regulator);
-static const char *rdev_get_name(struct regulator_dev *rdev)
+const char *rdev_get_name(struct regulator_dev *rdev)
{
if (rdev->constraints && rdev->constraints->name)
return rdev->constraints->name;
@@ -147,18 +142,10 @@
return false;
}
-static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
-{
- if (rdev && rdev->supply)
- return rdev->supply->rdev;
-
- return NULL;
-}
-
/**
* regulator_lock_nested - lock a single regulator
* @rdev: regulator source
- * @subclass: mutex subclass used for lockdep
+ * @ww_ctx: w/w mutex acquire context
*
* This function can be called many times by one task on
* a single regulator and its mutex will be locked only
@@ -166,24 +153,52 @@
* 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)
+static inline int regulator_lock_nested(struct regulator_dev *rdev,
+ struct ww_acquire_ctx *ww_ctx)
{
- if (!mutex_trylock(&rdev->mutex)) {
- if (rdev->mutex_owner == current) {
+ bool lock = false;
+ int ret = 0;
+
+ mutex_lock(®ulator_nesting_mutex);
+
+ if (ww_ctx || !ww_mutex_trylock(&rdev->mutex)) {
+ if (rdev->mutex_owner == current)
rdev->ref_cnt++;
- return;
+ else
+ lock = true;
+
+ if (lock) {
+ mutex_unlock(®ulator_nesting_mutex);
+ ret = ww_mutex_lock(&rdev->mutex, ww_ctx);
+ mutex_lock(®ulator_nesting_mutex);
}
- mutex_lock_nested(&rdev->mutex, subclass);
+ } else {
+ lock = true;
}
- rdev->ref_cnt = 1;
- rdev->mutex_owner = current;
+ if (lock && ret != -EDEADLK) {
+ rdev->ref_cnt++;
+ rdev->mutex_owner = current;
+ }
+
+ mutex_unlock(®ulator_nesting_mutex);
+
+ return ret;
}
-static inline void regulator_lock(struct regulator_dev *rdev)
+/**
+ * regulator_lock - lock a single regulator
+ * @rdev: regulator source
+ *
+ * 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(struct regulator_dev *rdev)
{
- regulator_lock_nested(rdev, 0);
+ regulator_lock_nested(rdev, NULL);
}
/**
@@ -195,45 +210,233 @@
*/
static void regulator_unlock(struct regulator_dev *rdev)
{
- if (rdev->ref_cnt != 0) {
- rdev->ref_cnt--;
+ mutex_lock(®ulator_nesting_mutex);
- if (!rdev->ref_cnt) {
- rdev->mutex_owner = NULL;
- mutex_unlock(&rdev->mutex);
+ if (--rdev->ref_cnt == 0) {
+ rdev->mutex_owner = NULL;
+ ww_mutex_unlock(&rdev->mutex);
+ }
+
+ WARN_ON_ONCE(rdev->ref_cnt < 0);
+
+ mutex_unlock(®ulator_nesting_mutex);
+}
+
+/**
+ * regulator_lock_two - lock two regulators
+ * @rdev1: first regulator
+ * @rdev2: second regulator
+ * @ww_ctx: w/w mutex acquire context
+ *
+ * Locks both rdevs using the regulator_ww_class.
+ */
+static void regulator_lock_two(struct regulator_dev *rdev1,
+ struct regulator_dev *rdev2,
+ struct ww_acquire_ctx *ww_ctx)
+{
+ struct regulator_dev *tmp;
+ int ret;
+
+ ww_acquire_init(ww_ctx, ®ulator_ww_class);
+
+ /* Try to just grab both of them */
+ ret = regulator_lock_nested(rdev1, ww_ctx);
+ WARN_ON(ret);
+ ret = regulator_lock_nested(rdev2, ww_ctx);
+ if (ret != -EDEADLOCK) {
+ WARN_ON(ret);
+ goto exit;
+ }
+
+ while (true) {
+ /*
+ * Start of loop: rdev1 was locked and rdev2 was contended.
+ * Need to unlock rdev1, slowly lock rdev2, then try rdev1
+ * again.
+ */
+ regulator_unlock(rdev1);
+
+ ww_mutex_lock_slow(&rdev2->mutex, ww_ctx);
+ rdev2->ref_cnt++;
+ rdev2->mutex_owner = current;
+ ret = regulator_lock_nested(rdev1, ww_ctx);
+
+ if (ret == -EDEADLOCK) {
+ /* More contention; swap which needs to be slow */
+ tmp = rdev1;
+ rdev1 = rdev2;
+ rdev2 = tmp;
+ } else {
+ WARN_ON(ret);
+ break;
}
}
+
+exit:
+ ww_acquire_done(ww_ctx);
}
/**
- * regulator_lock_supply - lock a regulator and its supplies
- * @rdev: regulator source
+ * regulator_unlock_two - unlock two regulators
+ * @rdev1: first regulator
+ * @rdev2: second regulator
+ * @ww_ctx: w/w mutex acquire context
+ *
+ * The inverse of regulator_lock_two().
*/
-static void regulator_lock_supply(struct regulator_dev *rdev)
+
+static void regulator_unlock_two(struct regulator_dev *rdev1,
+ struct regulator_dev *rdev2,
+ struct ww_acquire_ctx *ww_ctx)
{
+ regulator_unlock(rdev2);
+ regulator_unlock(rdev1);
+ ww_acquire_fini(ww_ctx);
+}
+
+static bool regulator_supply_is_couple(struct regulator_dev *rdev)
+{
+ struct regulator_dev *c_rdev;
int i;
- for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++)
- regulator_lock_nested(rdev, i);
+ for (i = 1; i < rdev->coupling_desc.n_coupled; i++) {
+ c_rdev = rdev->coupling_desc.coupled_rdevs[i];
+
+ if (rdev->supply->rdev == c_rdev)
+ return true;
+ }
+
+ return false;
+}
+
+static void regulator_unlock_recursive(struct regulator_dev *rdev,
+ unsigned int n_coupled)
+{
+ struct regulator_dev *c_rdev, *supply_rdev;
+ int i, supply_n_coupled;
+
+ for (i = n_coupled; i > 0; i--) {
+ c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1];
+
+ if (!c_rdev)
+ continue;
+
+ if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {
+ supply_rdev = c_rdev->supply->rdev;
+ supply_n_coupled = supply_rdev->coupling_desc.n_coupled;
+
+ regulator_unlock_recursive(supply_rdev,
+ supply_n_coupled);
+ }
+
+ regulator_unlock(c_rdev);
+ }
+}
+
+static int regulator_lock_recursive(struct regulator_dev *rdev,
+ struct regulator_dev **new_contended_rdev,
+ struct regulator_dev **old_contended_rdev,
+ struct ww_acquire_ctx *ww_ctx)
+{
+ struct regulator_dev *c_rdev;
+ int i, err;
+
+ for (i = 0; i < rdev->coupling_desc.n_coupled; i++) {
+ c_rdev = rdev->coupling_desc.coupled_rdevs[i];
+
+ if (!c_rdev)
+ continue;
+
+ if (c_rdev != *old_contended_rdev) {
+ err = regulator_lock_nested(c_rdev, ww_ctx);
+ if (err) {
+ if (err == -EDEADLK) {
+ *new_contended_rdev = c_rdev;
+ goto err_unlock;
+ }
+
+ /* shouldn't happen */
+ WARN_ON_ONCE(err != -EALREADY);
+ }
+ } else {
+ *old_contended_rdev = NULL;
+ }
+
+ if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {
+ err = regulator_lock_recursive(c_rdev->supply->rdev,
+ new_contended_rdev,
+ old_contended_rdev,
+ ww_ctx);
+ if (err) {
+ regulator_unlock(c_rdev);
+ goto err_unlock;
+ }
+ }
+ }
+
+ return 0;
+
+err_unlock:
+ regulator_unlock_recursive(rdev, i);
+
+ return err;
}
/**
- * regulator_unlock_supply - unlock a regulator and its supplies
- * @rdev: regulator source
+ * regulator_unlock_dependent - unlock regulator's suppliers and coupled
+ * regulators
+ * @rdev: regulator source
+ * @ww_ctx: w/w mutex acquire context
+ *
+ * Unlock all regulators related with rdev by coupling or supplying.
*/
-static void regulator_unlock_supply(struct regulator_dev *rdev)
+static void regulator_unlock_dependent(struct regulator_dev *rdev,
+ struct ww_acquire_ctx *ww_ctx)
{
- struct regulator *supply;
+ regulator_unlock_recursive(rdev, rdev->coupling_desc.n_coupled);
+ ww_acquire_fini(ww_ctx);
+}
- while (1) {
- regulator_unlock(rdev);
- supply = rdev->supply;
+/**
+ * regulator_lock_dependent - lock regulator's suppliers and coupled regulators
+ * @rdev: regulator source
+ * @ww_ctx: w/w mutex acquire context
+ *
+ * This function as a wrapper on regulator_lock_recursive(), which locks
+ * all regulators related with rdev by coupling or supplying.
+ */
+static void regulator_lock_dependent(struct regulator_dev *rdev,
+ struct ww_acquire_ctx *ww_ctx)
+{
+ struct regulator_dev *new_contended_rdev = NULL;
+ struct regulator_dev *old_contended_rdev = NULL;
+ int err;
- if (!rdev->supply)
- return;
+ mutex_lock(®ulator_list_mutex);
- rdev = supply->rdev;
- }
+ ww_acquire_init(ww_ctx, ®ulator_ww_class);
+
+ do {
+ if (new_contended_rdev) {
+ ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx);
+ old_contended_rdev = new_contended_rdev;
+ old_contended_rdev->ref_cnt++;
+ old_contended_rdev->mutex_owner = current;
+ }
+
+ err = regulator_lock_recursive(rdev,
+ &new_contended_rdev,
+ &old_contended_rdev,
+ ww_ctx);
+
+ if (old_contended_rdev)
+ regulator_unlock(old_contended_rdev);
+
+ } while (err == -EDEADLK);
+
+ ww_acquire_done(ww_ctx);
+
+ mutex_unlock(®ulator_list_mutex);
}
/**
@@ -259,12 +462,16 @@
if (!regnode) {
regnode = of_get_child_regulator(child, prop_name);
if (regnode)
- return regnode;
+ goto err_node_put;
} else {
- return regnode;
+ goto err_node_put;
}
}
return NULL;
+
+err_node_put:
+ of_node_put(child);
+ return regnode;
}
/**
@@ -279,11 +486,11 @@
static struct device_node *of_get_regulator(struct device *dev, const char *supply)
{
struct device_node *regnode = NULL;
- char prop_name[256];
+ char prop_name[64]; /* 64 is max size of property name */
dev_dbg(dev, "Looking up %s-supply from device tree\n", supply);
- snprintf(prop_name, sizeof(prop_name), "%s-supply", supply);
+ snprintf(prop_name, 64, "%s-supply", supply);
regnode = of_parse_phandle(dev->of_node, prop_name, 0);
if (!regnode) {
@@ -299,8 +506,8 @@
}
/* Platform voltage constraint check */
-static int regulator_check_voltage(struct regulator_dev *rdev,
- int *min_uV, int *max_uV)
+int regulator_check_voltage(struct regulator_dev *rdev,
+ int *min_uV, int *max_uV)
{
BUG_ON(*min_uV > *max_uV);
@@ -332,9 +539,9 @@
/* Make sure we select a voltage that suits the needs of all
* regulator consumers
*/
-static int regulator_check_consumers(struct regulator_dev *rdev,
- int *min_uV, int *max_uV,
- suspend_state_t state)
+int regulator_check_consumers(struct regulator_dev *rdev,
+ int *min_uV, int *max_uV,
+ suspend_state_t state)
{
struct regulator *regulator;
struct regulator_voltage *voltage;
@@ -438,17 +645,43 @@
}
}
+static const struct regulator_state *
+regulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t state)
+{
+ const struct regulator_state *rstate;
+
+ rstate = regulator_get_suspend_state(rdev, state);
+ if (rstate == NULL)
+ return NULL;
+
+ /* If we have no suspend mode configuration don't set anything;
+ * only warn if the driver implements set_suspend_voltage or
+ * set_suspend_mode callback.
+ */
+ if (rstate->enabled != ENABLE_IN_SUSPEND &&
+ rstate->enabled != DISABLE_IN_SUSPEND) {
+ if (rdev->desc->ops->set_suspend_voltage ||
+ rdev->desc->ops->set_suspend_mode)
+ rdev_warn(rdev, "No configuration\n");
+ return NULL;
+ }
+
+ return rstate;
+}
+
static ssize_t regulator_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- ssize_t ret;
+ int uV;
regulator_lock(rdev);
- ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev));
+ uV = regulator_get_voltage_rdev(rdev);
regulator_unlock(rdev);
- return ret;
+ if (uV < 0)
+ return uV;
+ return sprintf(buf, "%d\n", uV);
}
static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
@@ -470,19 +703,24 @@
}
static DEVICE_ATTR_RO(name);
-static ssize_t regulator_print_opmode(char *buf, int mode)
+static const char *regulator_opmode_to_str(int mode)
{
switch (mode) {
case REGULATOR_MODE_FAST:
- return sprintf(buf, "fast\n");
+ return "fast";
case REGULATOR_MODE_NORMAL:
- return sprintf(buf, "normal\n");
+ return "normal";
case REGULATOR_MODE_IDLE:
- return sprintf(buf, "idle\n");
+ return "idle";
case REGULATOR_MODE_STANDBY:
- return sprintf(buf, "standby\n");
+ return "standby";
}
- return sprintf(buf, "unknown\n");
+ return "unknown";
+}
+
+static ssize_t regulator_print_opmode(char *buf, int mode)
+{
+ return sprintf(buf, "%s\n", regulator_opmode_to_str(mode));
}
static ssize_t regulator_opmode_show(struct device *dev,
@@ -621,8 +859,10 @@
int uA = 0;
regulator_lock(rdev);
- list_for_each_entry(regulator, &rdev->consumer_list, list)
- uA += regulator->uA_load;
+ list_for_each_entry(regulator, &rdev->consumer_list, list) {
+ if (regulator->enable_count)
+ uA += regulator->uA_load;
+ }
regulator_unlock(rdev);
return sprintf(buf, "%d\n", uA);
}
@@ -775,16 +1015,16 @@
{
struct regulator *sibling;
int current_uA = 0, output_uV, input_uV, err;
- unsigned int regulator_curr_mode, mode;
-
- lockdep_assert_held_once(&rdev->mutex);
+ unsigned int mode;
/*
* first check to see if we can set modes at all, otherwise just
* tell the consumer everything is OK.
*/
- if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
+ if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) {
+ rdev_dbg(rdev, "DRMS operation not allowed\n");
return 0;
+ }
if (!rdev->desc->ops->get_optimum_mode &&
!rdev->desc->ops->set_load)
@@ -795,8 +1035,10 @@
return -EINVAL;
/* calc total requested load */
- list_for_each_entry(sibling, &rdev->consumer_list, list)
- current_uA += sibling->uA_load;
+ list_for_each_entry(sibling, &rdev->consumer_list, list) {
+ if (sibling->enable_count)
+ current_uA += sibling->uA_load;
+ }
current_uA += rdev->constraints->system_load;
@@ -804,10 +1046,11 @@
/* set the optimum mode for our new total regulator load */
err = rdev->desc->ops->set_load(rdev, current_uA);
if (err < 0)
- rdev_err(rdev, "failed to set load %d\n", current_uA);
+ rdev_err(rdev, "failed to set load %d: %pe\n",
+ current_uA, ERR_PTR(err));
} else {
/* get output voltage */
- output_uV = _regulator_get_voltage(rdev);
+ output_uV = regulator_get_voltage_rdev(rdev);
if (output_uV <= 0) {
rdev_err(rdev, "invalid output voltage found\n");
return -EINVAL;
@@ -816,7 +1059,7 @@
/* get input voltage */
input_uV = 0;
if (rdev->supply)
- input_uV = regulator_get_voltage(rdev->supply);
+ input_uV = regulator_get_voltage_rdev(rdev->supply->rdev);
if (input_uV <= 0)
input_uV = rdev->constraints->input_uV;
if (input_uV <= 0) {
@@ -831,48 +1074,24 @@
/* check the new mode is allowed */
err = regulator_mode_constrain(rdev, &mode);
if (err < 0) {
- rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
- current_uA, input_uV, output_uV);
+ rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV: %pe\n",
+ current_uA, input_uV, output_uV, ERR_PTR(err));
return err;
- }
- /* return if the same mode is requested */
- if (rdev->desc->ops->get_mode) {
- regulator_curr_mode = rdev->desc->ops->get_mode(rdev);
- if (regulator_curr_mode == mode)
- return 0;
- } else {
- return 0;
}
err = rdev->desc->ops->set_mode(rdev, mode);
if (err < 0)
- rdev_err(rdev, "failed to set optimum mode %x\n", mode);
+ rdev_err(rdev, "failed to set optimum mode %x: %pe\n",
+ mode, ERR_PTR(err));
}
return err;
}
-static int suspend_set_state(struct regulator_dev *rdev,
- suspend_state_t state)
+static int __suspend_set_state(struct regulator_dev *rdev,
+ const struct regulator_state *rstate)
{
int ret = 0;
- struct regulator_state *rstate;
-
- rstate = regulator_get_suspend_state(rdev, state);
- if (rstate == NULL)
- return 0;
-
- /* If we have no suspend mode configration don't set anything;
- * only warn if the driver implements set_suspend_voltage or
- * set_suspend_mode callback.
- */
- if (rstate->enabled != ENABLE_IN_SUSPEND &&
- rstate->enabled != DISABLE_IN_SUSPEND) {
- if (rdev->desc->ops->set_suspend_voltage ||
- rdev->desc->ops->set_suspend_mode)
- rdev_warn(rdev, "No configuration\n");
- return 0;
- }
if (rstate->enabled == ENABLE_IN_SUSPEND &&
rdev->desc->ops->set_suspend_enable)
@@ -884,14 +1103,14 @@
ret = 0;
if (ret < 0) {
- rdev_err(rdev, "failed to enabled/disable\n");
+ rdev_err(rdev, "failed to enabled/disable: %pe\n", ERR_PTR(ret));
return ret;
}
if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) {
ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV);
if (ret < 0) {
- rdev_err(rdev, "failed to set voltage\n");
+ rdev_err(rdev, "failed to set voltage: %pe\n", ERR_PTR(ret));
return ret;
}
}
@@ -899,7 +1118,7 @@
if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) {
ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode);
if (ret < 0) {
- rdev_err(rdev, "failed to set mode\n");
+ rdev_err(rdev, "failed to set mode: %pe\n", ERR_PTR(ret));
return ret;
}
}
@@ -907,7 +1126,20 @@
return ret;
}
-static void print_constraints(struct regulator_dev *rdev)
+static int suspend_set_initial_state(struct regulator_dev *rdev)
+{
+ const struct regulator_state *rstate;
+
+ rstate = regulator_get_suspend_state_check(rdev,
+ rdev->constraints->initial_state);
+ if (!rstate)
+ return 0;
+
+ return __suspend_set_state(rdev, rstate);
+}
+
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
+static void print_constraints_debug(struct regulator_dev *rdev)
{
struct regulation_constraints *constraints = rdev->constraints;
char buf[160] = "";
@@ -928,7 +1160,7 @@
if (!constraints->min_uV ||
constraints->min_uV != constraints->max_uV) {
- ret = _regulator_get_voltage(rdev);
+ ret = regulator_get_voltage_rdev(rdev);
if (ret > 0)
count += scnprintf(buf + count, len - count,
"at %d mV ", ret / 1000);
@@ -964,12 +1196,27 @@
if (constraints->valid_modes_mask & REGULATOR_MODE_IDLE)
count += scnprintf(buf + count, len - count, "idle ");
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
- count += scnprintf(buf + count, len - count, "standby");
+ count += scnprintf(buf + count, len - count, "standby ");
if (!count)
- scnprintf(buf, len, "no parameters");
+ count = scnprintf(buf, len, "no parameters");
+ else
+ --count;
+
+ count += scnprintf(buf + count, len - count, ", %s",
+ _regulator_is_enabled(rdev) ? "enabled" : "disabled");
rdev_dbg(rdev, "%s\n", buf);
+}
+#else /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */
+static inline void print_constraints_debug(struct regulator_dev *rdev) {}
+#endif /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */
+
+static void print_constraints(struct regulator_dev *rdev)
+{
+ struct regulation_constraints *constraints = rdev->constraints;
+
+ print_constraints_debug(rdev);
if ((constraints->min_uV != constraints->max_uV) &&
!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE))
@@ -987,23 +1234,23 @@
if (rdev->constraints->apply_uV &&
rdev->constraints->min_uV && rdev->constraints->max_uV) {
int target_min, target_max;
- int current_uV = _regulator_get_voltage(rdev);
+ int current_uV = regulator_get_voltage_rdev(rdev);
if (current_uV == -ENOTRECOVERABLE) {
- /* This regulator can't be read and must be initted */
+ /* This regulator can't be read and must be initialized */
rdev_info(rdev, "Setting %d-%duV\n",
rdev->constraints->min_uV,
rdev->constraints->max_uV);
_regulator_do_set_voltage(rdev,
rdev->constraints->min_uV,
rdev->constraints->max_uV);
- current_uV = _regulator_get_voltage(rdev);
+ current_uV = regulator_get_voltage_rdev(rdev);
}
if (current_uV < 0) {
rdev_err(rdev,
- "failed to get the current voltage(%d)\n",
- current_uV);
+ "failed to get the current voltage: %pe\n",
+ ERR_PTR(current_uV));
return current_uV;
}
@@ -1032,8 +1279,8 @@
rdev, target_min, target_max);
if (ret < 0) {
rdev_err(rdev,
- "failed to apply %d-%duV constraint(%d)\n",
- target_min, target_max, ret);
+ "failed to apply %d-%duV constraint: %pe\n",
+ target_min, target_max, ERR_PTR(ret));
return ret;
}
}
@@ -1068,6 +1315,10 @@
rdev_err(rdev, "invalid voltage constraints\n");
return -EINVAL;
}
+
+ /* no need to loop voltages if range is continuous */
+ if (rdev->desc->continuous_voltage_range)
+ return 0;
/* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
for (i = 0; i < count; i++) {
@@ -1167,16 +1418,16 @@
ret = ops->set_input_current_limit(rdev,
rdev->constraints->ilim_uA);
if (ret < 0) {
- rdev_err(rdev, "failed to set input limit\n");
+ rdev_err(rdev, "failed to set input limit: %pe\n", ERR_PTR(ret));
return ret;
}
}
/* do we need to setup our suspend state */
if (rdev->constraints->initial_state) {
- ret = suspend_set_state(rdev, rdev->constraints->initial_state);
+ ret = suspend_set_initial_state(rdev);
if (ret < 0) {
- rdev_err(rdev, "failed to set suspend state\n");
+ rdev_err(rdev, "failed to set suspend state: %pe\n", ERR_PTR(ret));
return ret;
}
}
@@ -1189,16 +1440,22 @@
ret = ops->set_mode(rdev, rdev->constraints->initial_mode);
if (ret < 0) {
- rdev_err(rdev, "failed to set initial mode: %d\n", ret);
+ rdev_err(rdev, "failed to set initial mode: %pe\n", ERR_PTR(ret));
return ret;
}
+ } else if (rdev->constraints->system_load) {
+ /*
+ * We'll only apply the initial system load if an
+ * initial mode wasn't specified.
+ */
+ drms_uA_update(rdev);
}
if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable)
&& ops->set_ramp_delay) {
ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
if (ret < 0) {
- rdev_err(rdev, "failed to set ramp_delay\n");
+ rdev_err(rdev, "failed to set ramp_delay: %pe\n", ERR_PTR(ret));
return ret;
}
}
@@ -1206,7 +1463,7 @@
if (rdev->constraints->pull_down && ops->set_pull_down) {
ret = ops->set_pull_down(rdev);
if (ret < 0) {
- rdev_err(rdev, "failed to set pull down\n");
+ rdev_err(rdev, "failed to set pull down: %pe\n", ERR_PTR(ret));
return ret;
}
}
@@ -1214,7 +1471,7 @@
if (rdev->constraints->soft_start && ops->set_soft_start) {
ret = ops->set_soft_start(rdev);
if (ret < 0) {
- rdev_err(rdev, "failed to set soft start\n");
+ rdev_err(rdev, "failed to set soft start: %pe\n", ERR_PTR(ret));
return ret;
}
}
@@ -1223,7 +1480,8 @@
&& ops->set_over_current_protection) {
ret = ops->set_over_current_protection(rdev);
if (ret < 0) {
- rdev_err(rdev, "failed to set over current protection\n");
+ rdev_err(rdev, "failed to set over current protection: %pe\n",
+ ERR_PTR(ret));
return ret;
}
}
@@ -1234,7 +1492,7 @@
ret = ops->set_active_discharge(rdev, ad_state);
if (ret < 0) {
- rdev_err(rdev, "failed to set active discharge\n");
+ rdev_err(rdev, "failed to set active discharge: %pe\n", ERR_PTR(ret));
return ret;
}
}
@@ -1249,7 +1507,13 @@
if (rdev->supply_name && !rdev->supply)
return -EPROBE_DEFER;
- if (rdev->supply && !_regulator_is_enabled(rdev->supply->rdev)) {
+ /* If supplying regulator has already been enabled,
+ * it's not intended to have use_count increment
+ * when rdev is only boot-on.
+ */
+ if (rdev->supply &&
+ (rdev->constraints->always_on ||
+ !regulator_is_enabled(rdev->supply))) {
ret = regulator_enable(rdev->supply);
if (ret < 0) {
_regulator_put(rdev->supply);
@@ -1258,13 +1522,10 @@
}
}
- /* The regulator may on if it's not switchable or left on */
- if (!_regulator_is_enabled(rdev)) {
- ret = _regulator_do_enable(rdev);
- if (ret < 0 && ret != -EINVAL) {
- rdev_err(rdev, "failed to enable\n");
- return ret;
- }
+ ret = _regulator_do_enable(rdev);
+ if (ret < 0 && ret != -EINVAL) {
+ rdev_err(rdev, "failed to enable: %pe\n", ERR_PTR(ret));
+ return ret;
}
if (rdev->constraints->always_on)
@@ -1277,8 +1538,8 @@
/**
* set_supply - set regulator supply regulator
- * @rdev: regulator name
- * @supply_rdev: supply regulator name
+ * @rdev: regulator (locked)
+ * @supply_rdev: supply regulator (locked))
*
* Called by platform initialisation code to set the supply regulator for this
* regulator. This ensures that a regulators supply will also be enabled by the
@@ -1296,6 +1557,7 @@
rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY");
if (rdev->supply == NULL) {
+ module_put(supply_rdev->owner);
err = -ENOMEM;
return err;
}
@@ -1447,61 +1709,67 @@
const char *supply_name)
{
struct regulator *regulator;
- char buf[REG_STR_SIZE];
- int err, size;
+ int err = 0;
+
+ lockdep_assert_held_once(&rdev->mutex.base);
+
+ if (dev) {
+ char buf[REG_STR_SIZE];
+ int size;
+
+ size = snprintf(buf, REG_STR_SIZE, "%s-%s",
+ dev->kobj.name, supply_name);
+ if (size >= REG_STR_SIZE)
+ return NULL;
+
+ supply_name = kstrdup(buf, GFP_KERNEL);
+ if (supply_name == NULL)
+ return NULL;
+ } else {
+ supply_name = kstrdup_const(supply_name, GFP_KERNEL);
+ if (supply_name == NULL)
+ return NULL;
+ }
regulator = kzalloc(sizeof(*regulator), GFP_KERNEL);
- if (regulator == NULL)
+ if (regulator == NULL) {
+ kfree_const(supply_name);
return NULL;
+ }
- regulator_lock(rdev);
regulator->rdev = rdev;
+ regulator->supply_name = supply_name;
+
list_add(®ulator->list, &rdev->consumer_list);
if (dev) {
regulator->dev = dev;
/* Add a link to the device sysfs entry */
- size = snprintf(buf, REG_STR_SIZE, "%s-%s",
- dev->kobj.name, supply_name);
- if (size >= REG_STR_SIZE)
- goto overflow_err;
-
- regulator->supply_name = kstrdup(buf, GFP_KERNEL);
- if (regulator->supply_name == NULL)
- goto overflow_err;
-
- if (device_is_registered(dev)) {
- err = sysfs_create_link_nowarn(&rdev->dev.kobj,
- &dev->kobj, buf);
- if (err) {
- rdev_dbg(rdev,
- "could not add device link %s err %d\n",
- dev->kobj.name, err);
- /* non-fatal */
- }
+ err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj,
+ supply_name);
+ if (err) {
+ rdev_dbg(rdev, "could not add device link %s: %pe\n",
+ dev->kobj.name, ERR_PTR(err));
+ /* non-fatal */
}
- } else {
- regulator->supply_name = kstrdup_const(supply_name, GFP_KERNEL);
- if (regulator->supply_name == NULL)
- goto overflow_err;
}
- regulator->debugfs = debugfs_create_dir(regulator->supply_name,
- rdev->debugfs);
- if (!regulator->debugfs) {
+ if (err != -EEXIST)
+ regulator->debugfs = debugfs_create_dir(supply_name, rdev->debugfs);
+ else
+ regulator->debugfs = ERR_PTR(err);
+ if (IS_ERR(regulator->debugfs))
rdev_dbg(rdev, "Failed to create debugfs directory\n");
- } else {
- debugfs_create_u32("uA_load", 0444, regulator->debugfs,
- ®ulator->uA_load);
- debugfs_create_u32("min_uV", 0444, regulator->debugfs,
- ®ulator->voltage[PM_SUSPEND_ON].min_uV);
- debugfs_create_u32("max_uV", 0444, regulator->debugfs,
- ®ulator->voltage[PM_SUSPEND_ON].max_uV);
- debugfs_create_file("constraint_flags", 0444,
- regulator->debugfs, regulator,
- &constraint_flags_fops);
- }
+
+ debugfs_create_u32("uA_load", 0444, regulator->debugfs,
+ ®ulator->uA_load);
+ debugfs_create_u32("min_uV", 0444, regulator->debugfs,
+ ®ulator->voltage[PM_SUSPEND_ON].min_uV);
+ debugfs_create_u32("max_uV", 0444, regulator->debugfs,
+ ®ulator->voltage[PM_SUSPEND_ON].max_uV);
+ debugfs_create_file("constraint_flags", 0444, regulator->debugfs,
+ regulator, &constraint_flags_fops);
/*
* Check now if the regulator is an always on regulator - if
@@ -1512,22 +1780,16 @@
_regulator_is_enabled(rdev))
regulator->always_on = true;
- regulator_unlock(rdev);
return regulator;
-overflow_err:
- list_del(®ulator->list);
- kfree(regulator);
- regulator_unlock(rdev);
- return NULL;
}
static int _regulator_get_enable_time(struct regulator_dev *rdev)
{
if (rdev->constraints && rdev->constraints->enable_time)
return rdev->constraints->enable_time;
- if (!rdev->desc->ops->enable_time)
- return rdev->desc->enable_time;
- return rdev->desc->ops->enable_time(rdev);
+ if (rdev->desc->ops->enable_time)
+ return rdev->desc->ops->enable_time(rdev);
+ return rdev->desc->enable_time;
}
static struct regulator_supply_alias *regulator_find_supply_alias(
@@ -1599,6 +1861,7 @@
node = of_get_regulator(dev, supply);
if (node) {
r = of_find_regulator_by_node(node);
+ of_node_put(node);
if (r)
return r;
@@ -1643,9 +1906,10 @@
{
struct regulator_dev *r;
struct device *dev = rdev->dev.parent;
+ struct ww_acquire_ctx ww_ctx;
int ret = 0;
- /* No supply to resovle? */
+ /* No supply to resolve? */
if (!rdev->supply_name)
return 0;
@@ -1709,23 +1973,23 @@
* between rdev->supply null check and setting rdev->supply in
* set_supply() from concurrent tasks.
*/
- regulator_lock(rdev);
+ regulator_lock_two(rdev, r, &ww_ctx);
/* Supply just resolved by a concurrent task? */
if (rdev->supply) {
- regulator_unlock(rdev);
+ regulator_unlock_two(rdev, r, &ww_ctx);
put_device(&r->dev);
goto out;
}
ret = set_supply(rdev, r);
if (ret < 0) {
- regulator_unlock(rdev);
+ regulator_unlock_two(rdev, r, &ww_ctx);
put_device(&r->dev);
goto out;
}
- regulator_unlock(rdev);
+ regulator_unlock_two(rdev, r, &ww_ctx);
/*
* In set_machine_constraints() we may have turned this regulator on
@@ -1751,7 +2015,7 @@
{
struct regulator_dev *rdev;
struct regulator *regulator;
- const char *devname = dev ? dev_name(dev) : "deviceless";
+ struct device_link *link;
int ret;
if (get_type >= MAX_GET_TYPE) {
@@ -1788,9 +2052,7 @@
* enabled, even if it isn't hooked up, and just
* provide a dummy.
*/
- dev_warn(dev,
- "%s supply %s not found, using dummy regulator\n",
- devname, id);
+ dev_warn(dev, "supply %s not found, using dummy regulator\n", id);
rdev = dummy_regulator_rdev;
get_device(&rdev->dev);
break;
@@ -1798,7 +2060,7 @@
case EXCLUSIVE_GET:
dev_warn(dev,
"dummy supplies not allowed for exclusive requests\n");
- /* fall through */
+ fallthrough;
default:
return ERR_PTR(-ENODEV);
@@ -1817,6 +2079,16 @@
return regulator;
}
+ mutex_lock(®ulator_list_mutex);
+ ret = (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled);
+ mutex_unlock(®ulator_list_mutex);
+
+ if (ret != 0) {
+ regulator = ERR_PTR(-EPROBE_DEFER);
+ put_device(&rdev->dev);
+ return regulator;
+ }
+
ret = regulator_resolve_supply(rdev);
if (ret < 0) {
regulator = ERR_PTR(ret);
@@ -1830,7 +2102,9 @@
return regulator;
}
+ regulator_lock(rdev);
regulator = create_regulator(rdev, dev, id);
+ regulator_unlock(rdev);
if (regulator == NULL) {
regulator = ERR_PTR(-ENOMEM);
module_put(rdev->owner);
@@ -1843,13 +2117,18 @@
rdev->exclusive = 1;
ret = _regulator_is_enabled(rdev);
- if (ret > 0)
+ if (ret > 0) {
rdev->use_count = 1;
- else
+ regulator->enable_count = 1;
+ } else {
rdev->use_count = 0;
+ regulator->enable_count = 0;
+ }
}
- device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS);
+ link = device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS);
+ if (!IS_ERR_OR_NULL(link))
+ regulator->device_link = true;
return regulator;
}
@@ -1926,29 +2205,14 @@
}
EXPORT_SYMBOL_GPL(regulator_get_optional);
-/* regulator_list_mutex lock held by regulator_put() */
-static void _regulator_put(struct regulator *regulator)
+static void destroy_regulator(struct regulator *regulator)
{
- struct regulator_dev *rdev;
-
- if (IS_ERR_OR_NULL(regulator))
- return;
-
- lockdep_assert_held_once(®ulator_list_mutex);
-
- rdev = regulator->rdev;
+ struct regulator_dev *rdev = regulator->rdev;
debugfs_remove_recursive(regulator->debugfs);
if (regulator->dev) {
- int count = 0;
- struct regulator *r;
-
- list_for_each_entry(r, &rdev->consumer_list, list)
- if (r->dev == regulator->dev)
- count++;
-
- if (count == 1)
+ if (regulator->device_link)
device_link_remove(regulator->dev, &rdev->dev);
/* remove any sysfs entries */
@@ -1964,6 +2228,24 @@
kfree_const(regulator->supply_name);
kfree(regulator);
+}
+
+/* regulator_list_mutex lock held by regulator_put() */
+static void _regulator_put(struct regulator *regulator)
+{
+ struct regulator_dev *rdev;
+
+ if (IS_ERR_OR_NULL(regulator))
+ return;
+
+ lockdep_assert_held_once(®ulator_list_mutex);
+
+ /* Docs say you must disable before calling regulator_put() */
+ WARN_ON(regulator->enable_count);
+
+ rdev = regulator->rdev;
+
+ destroy_regulator(regulator);
module_put(rdev->owner);
put_device(&rdev->dev);
@@ -2118,45 +2400,39 @@
static int regulator_ena_gpio_request(struct regulator_dev *rdev,
const struct regulator_config *config)
{
- struct regulator_enable_gpio *pin;
+ struct regulator_enable_gpio *pin, *new_pin;
struct gpio_desc *gpiod;
- int ret;
- if (config->ena_gpiod)
- gpiod = config->ena_gpiod;
- else
- gpiod = gpio_to_desc(config->ena_gpio);
+ gpiod = config->ena_gpiod;
+ new_pin = kzalloc(sizeof(*new_pin), GFP_KERNEL);
+
+ mutex_lock(®ulator_list_mutex);
list_for_each_entry(pin, ®ulator_ena_gpio_list, list) {
if (pin->gpiod == gpiod) {
- rdev_dbg(rdev, "GPIO %d is already used\n",
- config->ena_gpio);
+ rdev_dbg(rdev, "GPIO is already used\n");
goto update_ena_gpio_to_rdev;
}
}
- if (!config->ena_gpiod) {
- ret = gpio_request_one(config->ena_gpio,
- GPIOF_DIR_OUT | config->ena_gpio_flags,
- rdev_get_name(rdev));
- if (ret)
- return ret;
- }
-
- pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
- if (pin == NULL) {
- if (!config->ena_gpiod)
- gpio_free(config->ena_gpio);
+ if (new_pin == NULL) {
+ mutex_unlock(®ulator_list_mutex);
return -ENOMEM;
}
+ pin = new_pin;
+ new_pin = NULL;
+
pin->gpiod = gpiod;
- pin->ena_gpio_invert = config->ena_gpio_invert;
list_add(&pin->list, ®ulator_ena_gpio_list);
update_ena_gpio_to_rdev:
pin->request_count++;
rdev->ena_pin = pin;
+
+ mutex_unlock(®ulator_list_mutex);
+ kfree(new_pin);
+
return 0;
}
@@ -2169,19 +2445,19 @@
/* Free the GPIO only in case of no use */
list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) {
- if (pin->gpiod == rdev->ena_pin->gpiod) {
- if (pin->request_count <= 1) {
- pin->request_count = 0;
- gpiod_put(pin->gpiod);
- list_del(&pin->list);
- kfree(pin);
- rdev->ena_pin = NULL;
- return;
- } else {
- pin->request_count--;
- }
- }
+ if (pin != rdev->ena_pin)
+ continue;
+
+ if (--pin->request_count)
+ break;
+
+ gpiod_put(pin->gpiod);
+ list_del(&pin->list);
+ kfree(pin);
+ break;
}
+
+ rdev->ena_pin = NULL;
}
/**
@@ -2202,8 +2478,7 @@
if (enable) {
/* Enable GPIO at initial use */
if (pin->enable_count == 0)
- gpiod_set_value_cansleep(pin->gpiod,
- !pin->ena_gpio_invert);
+ gpiod_set_value_cansleep(pin->gpiod, 1);
pin->enable_count++;
} else {
@@ -2214,8 +2489,7 @@
/* Disable GPIO if not used */
if (pin->enable_count <= 1) {
- gpiod_set_value_cansleep(pin->gpiod,
- pin->ena_gpio_invert);
+ gpiod_set_value_cansleep(pin->gpiod, 0);
pin->enable_count = 0;
}
}
@@ -2229,7 +2503,7 @@
*
* Delay for the requested amount of time as per the guidelines in:
*
- * Documentation/timers/timers-howto.txt
+ * Documentation/timers/timers-howto.rst
*
* The assumption here is that regulators will never be enabled in
* atomic context and therefore sleeping functions can be used.
@@ -2262,6 +2536,37 @@
udelay(us);
}
+/**
+ * _regulator_check_status_enabled
+ *
+ * A helper function to check if the regulator status can be interpreted
+ * as 'regulator is enabled'.
+ * @rdev: the regulator device to check
+ *
+ * Return:
+ * * 1 - if status shows regulator is in enabled state
+ * * 0 - if not enabled state
+ * * Error Value - as received from ops->get_status()
+ */
+static inline int _regulator_check_status_enabled(struct regulator_dev *rdev)
+{
+ int ret = rdev->desc->ops->get_status(rdev);
+
+ if (ret < 0) {
+ rdev_info(rdev, "get_status returned error: %d\n", ret);
+ return ret;
+ }
+
+ switch (ret) {
+ case REGULATOR_STATUS_OFF:
+ case REGULATOR_STATUS_ERROR:
+ case REGULATOR_STATUS_UNDEFINED:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
static int _regulator_do_enable(struct regulator_dev *rdev)
{
int ret, delay;
@@ -2271,7 +2576,7 @@
if (ret >= 0) {
delay = ret;
} else {
- rdev_warn(rdev, "enable_time() failed: %d\n", ret);
+ rdev_warn(rdev, "enable_time() failed: %pe\n", ERR_PTR(ret));
delay = 0;
}
@@ -2292,7 +2597,7 @@
* timer wrapping.
* in case of multiple timer wrapping, either it can be
* detected by out-of-range remaining, or it cannot be
- * detected and we gets a panelty of
+ * detected and we get a penalty of
* _regulator_enable_delay().
*/
remaining = intended - start_jiffy;
@@ -2322,47 +2627,151 @@
* together. */
trace_regulator_enable_delay(rdev_get_name(rdev));
- _regulator_enable_delay(delay);
+ /* If poll_enabled_time is set, poll upto the delay calculated
+ * above, delaying poll_enabled_time uS to check if the regulator
+ * actually got enabled.
+ * If the regulator isn't enabled after enable_delay has
+ * expired, return -ETIMEDOUT.
+ */
+ if (rdev->desc->poll_enabled_time) {
+ int time_remaining = delay;
+
+ while (time_remaining > 0) {
+ _regulator_enable_delay(rdev->desc->poll_enabled_time);
+
+ if (rdev->desc->ops->get_status) {
+ ret = _regulator_check_status_enabled(rdev);
+ if (ret < 0)
+ return ret;
+ else if (ret)
+ break;
+ } else if (rdev->desc->ops->is_enabled(rdev))
+ break;
+
+ time_remaining -= rdev->desc->poll_enabled_time;
+ }
+
+ if (time_remaining <= 0) {
+ rdev_err(rdev, "Enabled check timed out\n");
+ return -ETIMEDOUT;
+ }
+ } else {
+ _regulator_enable_delay(delay);
+ }
trace_regulator_enable_complete(rdev_get_name(rdev));
return 0;
}
-/* locks held by regulator_enable() */
-static int _regulator_enable(struct regulator_dev *rdev)
+/**
+ * _regulator_handle_consumer_enable - handle that a consumer enabled
+ * @regulator: regulator source
+ *
+ * Some things on a regulator consumer (like the contribution towards total
+ * load on the regulator) only have an effect when the consumer wants the
+ * regulator enabled. Explained in example with two consumers of the same
+ * regulator:
+ * consumer A: set_load(100); => total load = 0
+ * consumer A: regulator_enable(); => total load = 100
+ * consumer B: set_load(1000); => total load = 100
+ * consumer B: regulator_enable(); => total load = 1100
+ * consumer A: regulator_disable(); => total_load = 1000
+ *
+ * This function (together with _regulator_handle_consumer_disable) is
+ * responsible for keeping track of the refcount for a given regulator consumer
+ * and applying / unapplying these things.
+ *
+ * Returns 0 upon no error; -error upon error.
+ */
+static int _regulator_handle_consumer_enable(struct regulator *regulator)
{
int ret;
+ struct regulator_dev *rdev = regulator->rdev;
- lockdep_assert_held_once(&rdev->mutex);
+ lockdep_assert_held_once(&rdev->mutex.base);
- /* check voltage and requested load before enabling */
- if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
- drms_uA_update(rdev);
+ regulator->enable_count++;
+ if (regulator->uA_load && regulator->enable_count == 1) {
+ ret = drms_uA_update(rdev);
+ if (ret)
+ regulator->enable_count--;
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * _regulator_handle_consumer_disable - handle that a consumer disabled
+ * @regulator: regulator source
+ *
+ * The opposite of _regulator_handle_consumer_enable().
+ *
+ * Returns 0 upon no error; -error upon error.
+ */
+static int _regulator_handle_consumer_disable(struct regulator *regulator)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+
+ lockdep_assert_held_once(&rdev->mutex.base);
+
+ if (!regulator->enable_count) {
+ rdev_err(rdev, "Underflow of regulator enable count\n");
+ return -EINVAL;
+ }
+
+ regulator->enable_count--;
+ if (regulator->uA_load && regulator->enable_count == 0)
+ return drms_uA_update(rdev);
+
+ return 0;
+}
+
+/* locks held by regulator_enable() */
+static int _regulator_enable(struct regulator *regulator)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+ int ret;
+
+ lockdep_assert_held_once(&rdev->mutex.base);
+
+ if (rdev->use_count == 0 && rdev->supply) {
+ ret = _regulator_enable(rdev->supply);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* balance only if there are regulators coupled */
+ if (rdev->coupling_desc.n_coupled > 1) {
+ ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+ if (ret < 0)
+ goto err_disable_supply;
+ }
+
+ ret = _regulator_handle_consumer_enable(regulator);
+ if (ret < 0)
+ goto err_disable_supply;
if (rdev->use_count == 0) {
/* The regulator may on if it's not switchable or left on */
ret = _regulator_is_enabled(rdev);
if (ret == -EINVAL || ret == 0) {
if (!regulator_ops_is_valid(rdev,
- REGULATOR_CHANGE_STATUS))
- return -EPERM;
+ REGULATOR_CHANGE_STATUS)) {
+ ret = -EPERM;
+ goto err_consumer_disable;
+ }
ret = _regulator_do_enable(rdev);
if (ret < 0)
- return ret;
+ goto err_consumer_disable;
- if (IS_ENABLED(CONFIG_CPU_RV1126)) {
- ret = _regulator_get_voltage(rdev);
- _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE,
- &ret);
- } else {
- _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE,
- NULL);
- }
+ _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE,
+ NULL);
} else if (ret < 0) {
- rdev_err(rdev, "is_enabled() failed: %d\n", ret);
- return ret;
+ rdev_err(rdev, "is_enabled() failed: %pe\n", ERR_PTR(ret));
+ goto err_consumer_disable;
}
/* Fallthrough on positive return values - already enabled */
}
@@ -2370,6 +2779,15 @@
rdev->use_count++;
return 0;
+
+err_consumer_disable:
+ _regulator_handle_consumer_disable(regulator);
+
+err_disable_supply:
+ if (rdev->use_count == 0 && rdev->supply)
+ _regulator_disable(rdev->supply);
+
+ return ret;
}
/**
@@ -2386,23 +2804,12 @@
int regulator_enable(struct regulator *regulator)
{
struct regulator_dev *rdev = regulator->rdev;
- int ret = 0;
+ struct ww_acquire_ctx ww_ctx;
+ int ret;
- if (regulator->always_on)
- return 0;
-
- if (rdev->supply) {
- ret = regulator_enable(rdev->supply);
- if (ret != 0)
- return ret;
- }
-
- mutex_lock(&rdev->mutex);
- ret = _regulator_enable(rdev);
- mutex_unlock(&rdev->mutex);
-
- if (ret != 0 && rdev->supply)
- regulator_disable(rdev->supply);
+ regulator_lock_dependent(rdev, &ww_ctx);
+ ret = _regulator_enable(regulator);
+ regulator_unlock_dependent(rdev, &ww_ctx);
return ret;
}
@@ -2440,11 +2847,12 @@
}
/* locks held by regulator_disable() */
-static int _regulator_disable(struct regulator_dev *rdev)
+static int _regulator_disable(struct regulator *regulator)
{
+ struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
- lockdep_assert_held_once(&rdev->mutex);
+ lockdep_assert_held_once(&rdev->mutex.base);
if (WARN(rdev->use_count <= 0,
"unbalanced disables for %s\n", rdev_get_name(rdev)))
@@ -2464,7 +2872,7 @@
ret = _regulator_do_disable(rdev);
if (ret < 0) {
- rdev_err(rdev, "failed to disable\n");
+ rdev_err(rdev, "failed to disable: %pe\n", ERR_PTR(ret));
_notifier_call_chain(rdev,
REGULATOR_EVENT_ABORT_DISABLE,
NULL);
@@ -2476,11 +2884,17 @@
rdev->use_count = 0;
} else if (rdev->use_count > 1) {
- if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
- drms_uA_update(rdev);
-
rdev->use_count--;
}
+
+ if (ret == 0)
+ ret = _regulator_handle_consumer_disable(regulator);
+
+ if (ret == 0 && rdev->coupling_desc.n_coupled > 1)
+ ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+
+ if (ret == 0 && rdev->use_count == 0 && rdev->supply)
+ ret = _regulator_disable(rdev->supply);
return ret;
}
@@ -2500,17 +2914,12 @@
int regulator_disable(struct regulator *regulator)
{
struct regulator_dev *rdev = regulator->rdev;
- int ret = 0;
+ struct ww_acquire_ctx ww_ctx;
+ int ret;
- if (regulator->always_on)
- return 0;
-
- mutex_lock(&rdev->mutex);
- ret = _regulator_disable(rdev);
- mutex_unlock(&rdev->mutex);
-
- if (ret == 0 && rdev->supply)
- regulator_disable(rdev->supply);
+ regulator_lock_dependent(rdev, &ww_ctx);
+ ret = _regulator_disable(regulator);
+ regulator_unlock_dependent(rdev, &ww_ctx);
return ret;
}
@@ -2521,7 +2930,7 @@
{
int ret = 0;
- lockdep_assert_held_once(&rdev->mutex);
+ lockdep_assert_held_once(&rdev->mutex.base);
ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
REGULATOR_EVENT_PRE_DISABLE, NULL);
@@ -2530,7 +2939,7 @@
ret = _regulator_do_disable(rdev);
if (ret < 0) {
- rdev_err(rdev, "failed to force disable\n");
+ rdev_err(rdev, "failed to force disable: %pe\n", ERR_PTR(ret));
_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
REGULATOR_EVENT_ABORT_DISABLE, NULL);
return ret;
@@ -2554,16 +2963,25 @@
int regulator_force_disable(struct regulator *regulator)
{
struct regulator_dev *rdev = regulator->rdev;
+ struct ww_acquire_ctx ww_ctx;
int ret;
- mutex_lock(&rdev->mutex);
- regulator->uA_load = 0;
- ret = _regulator_force_disable(regulator->rdev);
- mutex_unlock(&rdev->mutex);
+ regulator_lock_dependent(rdev, &ww_ctx);
- if (rdev->supply)
- while (rdev->open_count--)
- regulator_disable(rdev->supply);
+ ret = _regulator_force_disable(regulator->rdev);
+
+ if (rdev->coupling_desc.n_coupled > 1)
+ regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+
+ if (regulator->uA_load) {
+ regulator->uA_load = 0;
+ ret = drms_uA_update(rdev);
+ }
+
+ if (rdev->use_count != 0 && rdev->supply)
+ _regulator_disable(rdev->supply);
+
+ regulator_unlock_dependent(rdev, &ww_ctx);
return ret;
}
@@ -2573,14 +2991,12 @@
{
struct regulator_dev *rdev = container_of(work, struct regulator_dev,
disable_work.work);
+ struct ww_acquire_ctx ww_ctx;
int count, i, ret;
+ struct regulator *regulator;
+ int total_count = 0;
- regulator_lock(rdev);
-
- BUG_ON(!rdev->deferred_disables);
-
- count = rdev->deferred_disables;
- rdev->deferred_disables = 0;
+ regulator_lock_dependent(rdev, &ww_ctx);
/*
* Workqueue functions queue the new work instance while the previous
@@ -2590,29 +3006,34 @@
*/
cancel_delayed_work(&rdev->disable_work);
- for (i = 0; i < count; i++) {
- ret = _regulator_disable(rdev);
- if (ret != 0)
- rdev_err(rdev, "Deferred disable failed: %d\n", ret);
- }
+ list_for_each_entry(regulator, &rdev->consumer_list, list) {
+ count = regulator->deferred_disables;
- regulator_unlock(rdev);
+ if (!count)
+ continue;
- if (rdev->supply) {
+ total_count += count;
+ regulator->deferred_disables = 0;
+
for (i = 0; i < count; i++) {
- ret = regulator_disable(rdev->supply);
- if (ret != 0) {
- rdev_err(rdev,
- "Supply disable failed: %d\n", ret);
- }
+ ret = _regulator_disable(regulator);
+ if (ret != 0)
+ rdev_err(rdev, "Deferred disable failed: %pe\n",
+ ERR_PTR(ret));
}
}
+ WARN_ON(!total_count);
+
+ if (rdev->coupling_desc.n_coupled > 1)
+ regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+
+ regulator_unlock_dependent(rdev, &ww_ctx);
}
/**
* regulator_disable_deferred - disable regulator output with delay
* @regulator: regulator source
- * @ms: miliseconds until the regulator is disabled
+ * @ms: milliseconds until the regulator is disabled
*
* Execute regulator_disable() on the regulator after a delay. This
* is intended for use with devices that require some time to quiesce.
@@ -2625,14 +3046,11 @@
{
struct regulator_dev *rdev = regulator->rdev;
- if (regulator->always_on)
- return 0;
-
if (!ms)
return regulator_disable(regulator);
regulator_lock(rdev);
- rdev->deferred_disables++;
+ regulator->deferred_disables++;
mod_delayed_work(system_power_efficient_wq, &rdev->disable_work,
msecs_to_jiffies(ms));
regulator_unlock(rdev);
@@ -2707,9 +3125,9 @@
if (regulator->always_on)
return 1;
- mutex_lock(®ulator->rdev->mutex);
+ regulator_lock(regulator->rdev);
ret = _regulator_is_enabled(regulator->rdev);
- mutex_unlock(®ulator->rdev->mutex);
+ regulator_unlock(regulator->rdev);
return ret;
}
@@ -2794,7 +3212,7 @@
*vsel_reg = rdev->desc->vsel_reg;
*vsel_mask = rdev->desc->vsel_mask;
- return 0;
+ return 0;
}
EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register);
@@ -2846,7 +3264,7 @@
* @min_uV: Minimum required voltage in uV.
* @max_uV: Maximum required voltage in uV.
*
- * Returns a boolean or a negative error code.
+ * Returns a boolean.
*/
int regulator_is_supported_voltage(struct regulator *regulator,
int min_uV, int max_uV)
@@ -2870,7 +3288,7 @@
ret = regulator_count_voltages(regulator);
if (ret < 0)
- return ret;
+ return 0;
voltages = ret;
for (i = 0; i < voltages; i++) {
@@ -2898,6 +3316,11 @@
if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
+ if (desc->ops->list_voltage ==
+ regulator_list_voltage_pickable_linear_range)
+ return regulator_map_voltage_pickable_linear_range(rdev,
+ min_uV, max_uV);
+
return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
}
@@ -2908,7 +3331,7 @@
struct pre_voltage_change_data data;
int ret;
- data.old_uV = _regulator_get_voltage(rdev);
+ data.old_uV = regulator_get_voltage_rdev(rdev);
data.min_uV = min_uV;
data.max_uV = max_uV;
ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE,
@@ -2932,7 +3355,7 @@
struct pre_voltage_change_data data;
int ret;
- data.old_uV = _regulator_get_voltage(rdev);
+ data.old_uV = regulator_get_voltage_rdev(rdev);
data.min_uV = uV;
data.max_uV = uV;
ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE,
@@ -2947,6 +3370,66 @@
_notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE,
(void *)data.old_uV);
+ return ret;
+}
+
+static int _regulator_set_voltage_sel_step(struct regulator_dev *rdev,
+ int uV, int new_selector)
+{
+ const struct regulator_ops *ops = rdev->desc->ops;
+ int diff, old_sel, curr_sel, ret;
+
+ /* Stepping is only needed if the regulator is enabled. */
+ if (!_regulator_is_enabled(rdev))
+ goto final_set;
+
+ if (!ops->get_voltage_sel)
+ return -EINVAL;
+
+ old_sel = ops->get_voltage_sel(rdev);
+ if (old_sel < 0)
+ return old_sel;
+
+ diff = new_selector - old_sel;
+ if (diff == 0)
+ return 0; /* No change needed. */
+
+ if (diff > 0) {
+ /* Stepping up. */
+ for (curr_sel = old_sel + rdev->desc->vsel_step;
+ curr_sel < new_selector;
+ curr_sel += rdev->desc->vsel_step) {
+ /*
+ * Call the callback directly instead of using
+ * _regulator_call_set_voltage_sel() as we don't
+ * want to notify anyone yet. Same in the branch
+ * below.
+ */
+ ret = ops->set_voltage_sel(rdev, curr_sel);
+ if (ret)
+ goto try_revert;
+ }
+ } else {
+ /* Stepping down. */
+ for (curr_sel = old_sel - rdev->desc->vsel_step;
+ curr_sel > new_selector;
+ curr_sel -= rdev->desc->vsel_step) {
+ ret = ops->set_voltage_sel(rdev, curr_sel);
+ if (ret)
+ goto try_revert;
+ }
+ }
+
+final_set:
+ /* The final selector will trigger the notifiers. */
+ return _regulator_call_set_voltage_sel(rdev, uV, new_selector);
+
+try_revert:
+ /*
+ * At least try to return to the previous voltage if setting a new
+ * one failed.
+ */
+ (void)ops->set_voltage_sel(rdev, old_sel);
return ret;
}
@@ -2985,7 +3468,7 @@
unsigned int selector;
int old_selector = -1;
const struct regulator_ops *ops = rdev->desc->ops;
- int old_uV = _regulator_get_voltage(rdev);
+ int old_uV = regulator_get_voltage_rdev(rdev);
trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
@@ -3012,7 +3495,7 @@
best_val = ops->list_voltage(rdev,
selector);
else
- best_val = _regulator_get_voltage(rdev);
+ best_val = regulator_get_voltage_rdev(rdev);
}
} else if (ops->set_voltage_sel) {
@@ -3023,6 +3506,9 @@
selector = ret;
if (old_selector == selector)
ret = 0;
+ else if (rdev->desc->vsel_step)
+ ret = _regulator_set_voltage_sel_step(
+ rdev, best_val, selector);
else
ret = _regulator_call_set_voltage_sel(
rdev, best_val, selector);
@@ -3058,7 +3544,7 @@
}
if (delay < 0) {
- rdev_warn(rdev, "failed to get delay: %d\n", delay);
+ rdev_warn(rdev, "failed to get delay: %pe\n", ERR_PTR(delay));
delay = 0;
}
@@ -3118,8 +3604,6 @@
int ret = 0;
int old_min_uV, old_max_uV;
int current_uV;
- int best_supply_uV = 0;
- int supply_change_uV = 0;
/* If we're setting the same range as last time the change
* should be a noop (some cpufreq implementations use the same
@@ -3133,7 +3617,7 @@
* changing the voltage.
*/
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
- current_uV = _regulator_get_voltage(rdev);
+ current_uV = regulator_get_voltage_rdev(rdev);
if (min_uV <= current_uV && current_uV <= max_uV) {
voltage->min_uV = min_uV;
voltage->max_uV = max_uV;
@@ -3159,9 +3643,23 @@
voltage->min_uV = min_uV;
voltage->max_uV = max_uV;
- ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
- if (ret < 0)
- goto out2;
+ /* for not coupled regulators this will just set the voltage */
+ ret = regulator_balance_voltage(rdev, state);
+ if (ret < 0) {
+ voltage->min_uV = old_min_uV;
+ voltage->max_uV = old_max_uV;
+ }
+
+out:
+ return ret;
+}
+
+int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
+ int max_uV, suspend_state_t state)
+{
+ int best_supply_uV = 0;
+ int supply_change_uV = 0;
+ int ret;
if (rdev->supply &&
regulator_ops_is_valid(rdev->supply->rdev,
@@ -3174,21 +3672,21 @@
selector = regulator_map_voltage(rdev, min_uV, max_uV);
if (selector < 0) {
ret = selector;
- goto out2;
+ goto out;
}
best_supply_uV = _regulator_list_voltage(rdev, selector, 0);
if (best_supply_uV < 0) {
ret = best_supply_uV;
- goto out2;
+ goto out;
}
best_supply_uV += rdev->desc->min_dropout_uV;
- current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
+ current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev);
if (current_supply_uV < 0) {
ret = current_supply_uV;
- goto out2;
+ goto out;
}
supply_change_uV = best_supply_uV - current_supply_uV;
@@ -3198,9 +3696,9 @@
ret = regulator_set_voltage_unlocked(rdev->supply,
best_supply_uV, INT_MAX, state);
if (ret) {
- dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n",
- ret);
- goto out2;
+ dev_err(&rdev->dev, "Failed to increase supply voltage: %pe\n",
+ ERR_PTR(ret));
+ goto out;
}
}
@@ -3210,25 +3708,303 @@
ret = _regulator_do_set_suspend_voltage(rdev, min_uV,
max_uV, state);
if (ret < 0)
- goto out2;
+ goto out;
if (supply_change_uV < 0) {
ret = regulator_set_voltage_unlocked(rdev->supply,
best_supply_uV, INT_MAX, state);
if (ret)
- dev_warn(&rdev->dev, "Failed to decrease supply voltage: %d\n",
- ret);
+ dev_warn(&rdev->dev, "Failed to decrease supply voltage: %pe\n",
+ ERR_PTR(ret));
/* No need to fail here */
ret = 0;
}
out:
return ret;
-out2:
- voltage->min_uV = old_min_uV;
- voltage->max_uV = old_max_uV;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_rdev);
+static int regulator_limit_voltage_step(struct regulator_dev *rdev,
+ int *current_uV, int *min_uV)
+{
+ struct regulation_constraints *constraints = rdev->constraints;
+
+ /* Limit voltage change only if necessary */
+ if (!constraints->max_uV_step || !_regulator_is_enabled(rdev))
+ return 1;
+
+ if (*current_uV < 0) {
+ *current_uV = regulator_get_voltage_rdev(rdev);
+
+ if (*current_uV < 0)
+ return *current_uV;
+ }
+
+ if (abs(*current_uV - *min_uV) <= constraints->max_uV_step)
+ return 1;
+
+ /* Clamp target voltage within the given step */
+ if (*current_uV < *min_uV)
+ *min_uV = min(*current_uV + constraints->max_uV_step,
+ *min_uV);
+ else
+ *min_uV = max(*current_uV - constraints->max_uV_step,
+ *min_uV);
+
+ return 0;
+}
+
+static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
+ int *current_uV,
+ int *min_uV, int *max_uV,
+ suspend_state_t state,
+ int n_coupled)
+{
+ struct coupling_desc *c_desc = &rdev->coupling_desc;
+ struct regulator_dev **c_rdevs = c_desc->coupled_rdevs;
+ struct regulation_constraints *constraints = rdev->constraints;
+ int desired_min_uV = 0, desired_max_uV = INT_MAX;
+ int max_current_uV = 0, min_current_uV = INT_MAX;
+ int highest_min_uV = 0, target_uV, possible_uV;
+ int i, ret, max_spread;
+ bool done;
+
+ *current_uV = -1;
+
+ /*
+ * If there are no coupled regulators, simply set the voltage
+ * demanded by consumers.
+ */
+ if (n_coupled == 1) {
+ /*
+ * If consumers don't provide any demands, set voltage
+ * to min_uV
+ */
+ desired_min_uV = constraints->min_uV;
+ desired_max_uV = constraints->max_uV;
+
+ ret = regulator_check_consumers(rdev,
+ &desired_min_uV,
+ &desired_max_uV, state);
+ if (ret < 0)
+ return ret;
+
+ possible_uV = desired_min_uV;
+ done = true;
+
+ goto finish;
+ }
+
+ /* Find highest min desired voltage */
+ for (i = 0; i < n_coupled; i++) {
+ int tmp_min = 0;
+ int tmp_max = INT_MAX;
+
+ lockdep_assert_held_once(&c_rdevs[i]->mutex.base);
+
+ ret = regulator_check_consumers(c_rdevs[i],
+ &tmp_min,
+ &tmp_max, state);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max);
+ if (ret < 0)
+ return ret;
+
+ highest_min_uV = max(highest_min_uV, tmp_min);
+
+ if (i == 0) {
+ desired_min_uV = tmp_min;
+ desired_max_uV = tmp_max;
+ }
+ }
+
+ max_spread = constraints->max_spread[0];
+
+ /*
+ * Let target_uV be equal to the desired one if possible.
+ * If not, set it to minimum voltage, allowed by other coupled
+ * regulators.
+ */
+ target_uV = max(desired_min_uV, highest_min_uV - max_spread);
+
+ /*
+ * Find min and max voltages, which currently aren't violating
+ * max_spread.
+ */
+ for (i = 1; i < n_coupled; i++) {
+ int tmp_act;
+
+ if (!_regulator_is_enabled(c_rdevs[i]))
+ continue;
+
+ tmp_act = regulator_get_voltage_rdev(c_rdevs[i]);
+ if (tmp_act < 0)
+ return tmp_act;
+
+ min_current_uV = min(tmp_act, min_current_uV);
+ max_current_uV = max(tmp_act, max_current_uV);
+ }
+
+ /* There aren't any other regulators enabled */
+ if (max_current_uV == 0) {
+ possible_uV = target_uV;
+ } else {
+ /*
+ * Correct target voltage, so as it currently isn't
+ * violating max_spread
+ */
+ possible_uV = max(target_uV, max_current_uV - max_spread);
+ possible_uV = min(possible_uV, min_current_uV + max_spread);
+ }
+
+ if (possible_uV > desired_max_uV)
+ return -EINVAL;
+
+ done = (possible_uV == target_uV);
+ desired_min_uV = possible_uV;
+
+finish:
+ /* Apply max_uV_step constraint if necessary */
+ if (state == PM_SUSPEND_ON) {
+ ret = regulator_limit_voltage_step(rdev, current_uV,
+ &desired_min_uV);
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0)
+ done = false;
+ }
+
+ /* Set current_uV if wasn't done earlier in the code and if necessary */
+ if (n_coupled > 1 && *current_uV == -1) {
+
+ if (_regulator_is_enabled(rdev)) {
+ ret = regulator_get_voltage_rdev(rdev);
+ if (ret < 0)
+ return ret;
+
+ *current_uV = ret;
+ } else {
+ *current_uV = desired_min_uV;
+ }
+ }
+
+ *min_uV = desired_min_uV;
+ *max_uV = desired_max_uV;
+
+ return done;
+}
+
+int regulator_do_balance_voltage(struct regulator_dev *rdev,
+ suspend_state_t state, bool skip_coupled)
+{
+ struct regulator_dev **c_rdevs;
+ struct regulator_dev *best_rdev;
+ struct coupling_desc *c_desc = &rdev->coupling_desc;
+ int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev;
+ unsigned int delta, best_delta;
+ unsigned long c_rdev_done = 0;
+ bool best_c_rdev_done;
+
+ c_rdevs = c_desc->coupled_rdevs;
+ n_coupled = skip_coupled ? 1 : c_desc->n_coupled;
+
+ /*
+ * Find the best possible voltage change on each loop. Leave the loop
+ * if there isn't any possible change.
+ */
+ do {
+ best_c_rdev_done = false;
+ best_delta = 0;
+ best_min_uV = 0;
+ best_max_uV = 0;
+ best_c_rdev = 0;
+ best_rdev = NULL;
+
+ /*
+ * Find highest difference between optimal voltage
+ * and current voltage.
+ */
+ for (i = 0; i < n_coupled; i++) {
+ /*
+ * optimal_uV is the best voltage that can be set for
+ * i-th regulator at the moment without violating
+ * max_spread constraint in order to balance
+ * the coupled voltages.
+ */
+ int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0;
+
+ if (test_bit(i, &c_rdev_done))
+ continue;
+
+ ret = regulator_get_optimal_voltage(c_rdevs[i],
+ ¤t_uV,
+ &optimal_uV,
+ &optimal_max_uV,
+ state, n_coupled);
+ if (ret < 0)
+ goto out;
+
+ delta = abs(optimal_uV - current_uV);
+
+ if (delta && best_delta <= delta) {
+ best_c_rdev_done = ret;
+ best_delta = delta;
+ best_rdev = c_rdevs[i];
+ best_min_uV = optimal_uV;
+ best_max_uV = optimal_max_uV;
+ best_c_rdev = i;
+ }
+ }
+
+ /* Nothing to change, return successfully */
+ if (!best_rdev) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = regulator_set_voltage_rdev(best_rdev, best_min_uV,
+ best_max_uV, state);
+
+ if (ret < 0)
+ goto out;
+
+ if (best_c_rdev_done)
+ set_bit(best_c_rdev, &c_rdev_done);
+
+ } while (n_coupled > 1);
+
+out:
return ret;
+}
+
+static int regulator_balance_voltage(struct regulator_dev *rdev,
+ suspend_state_t state)
+{
+ struct coupling_desc *c_desc = &rdev->coupling_desc;
+ struct regulator_coupler *coupler = c_desc->coupler;
+ bool skip_coupled = false;
+
+ /*
+ * If system is in a state other than PM_SUSPEND_ON, don't check
+ * other coupled regulators.
+ */
+ if (state != PM_SUSPEND_ON)
+ skip_coupled = true;
+
+ if (c_desc->n_resolved < c_desc->n_coupled) {
+ rdev_err(rdev, "Not all coupled regulators registered\n");
+ return -EPERM;
+ }
+
+ /* Invoke custom balancer for customized couplers */
+ if (coupler && coupler->balance_voltage)
+ return coupler->balance_voltage(coupler, rdev, state);
+
+ return regulator_do_balance_voltage(rdev, state, skip_coupled);
}
/**
@@ -3251,14 +4027,15 @@
*/
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
{
- int ret = 0;
+ struct ww_acquire_ctx ww_ctx;
+ int ret;
- regulator_lock_supply(regulator->rdev);
+ regulator_lock_dependent(regulator->rdev, &ww_ctx);
ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV,
PM_SUSPEND_ON);
- regulator_unlock_supply(regulator->rdev);
+ regulator_unlock_dependent(regulator->rdev, &ww_ctx);
return ret;
}
@@ -3330,18 +4107,19 @@
int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV,
int max_uV, suspend_state_t state)
{
- int ret = 0;
+ struct ww_acquire_ctx ww_ctx;
+ int ret;
/* PM_SUSPEND_ON is handled by regulator_set_voltage() */
if (regulator_check_states(state) || state == PM_SUSPEND_ON)
return -EINVAL;
- regulator_lock_supply(regulator->rdev);
+ regulator_lock_dependent(regulator->rdev, &ww_ctx);
ret = _regulator_set_suspend_voltage(regulator, min_uV,
max_uV, state);
- regulator_unlock_supply(regulator->rdev);
+ regulator_unlock_dependent(regulator->rdev, &ww_ctx);
return ret;
}
@@ -3477,7 +4255,7 @@
}
EXPORT_SYMBOL_GPL(regulator_sync_voltage);
-static int _regulator_get_voltage(struct regulator_dev *rdev)
+int regulator_get_voltage_rdev(struct regulator_dev *rdev)
{
int sel, ret;
bool bypassed;
@@ -3494,7 +4272,7 @@
return -EPROBE_DEFER;
}
- return _regulator_get_voltage(rdev->supply->rdev);
+ return regulator_get_voltage_rdev(rdev->supply->rdev);
}
}
@@ -3510,7 +4288,7 @@
} else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) {
ret = rdev->desc->fixed_uV;
} else if (rdev->supply) {
- ret = _regulator_get_voltage(rdev->supply->rdev);
+ ret = regulator_get_voltage_rdev(rdev->supply->rdev);
} else if (rdev->supply_name) {
return -EPROBE_DEFER;
} else {
@@ -3521,6 +4299,7 @@
return ret;
return ret - rdev->constraints->uV_offset;
}
+EXPORT_SYMBOL_GPL(regulator_get_voltage_rdev);
/**
* regulator_get_voltage - get regulator output voltage
@@ -3533,13 +4312,12 @@
*/
int regulator_get_voltage(struct regulator *regulator)
{
+ struct ww_acquire_ctx ww_ctx;
int ret;
- regulator_lock_supply(regulator->rdev);
-
- ret = _regulator_get_voltage(regulator->rdev);
-
- regulator_unlock_supply(regulator->rdev);
+ regulator_lock_dependent(regulator->rdev, &ww_ctx);
+ ret = regulator_get_voltage_rdev(regulator->rdev);
+ regulator_unlock_dependent(regulator->rdev, &ww_ctx);
return ret;
}
@@ -3587,21 +4365,23 @@
}
EXPORT_SYMBOL_GPL(regulator_set_current_limit);
+static int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev)
+{
+ /* sanity check */
+ if (!rdev->desc->ops->get_current_limit)
+ return -EINVAL;
+
+ return rdev->desc->ops->get_current_limit(rdev);
+}
+
static int _regulator_get_current_limit(struct regulator_dev *rdev)
{
int ret;
regulator_lock(rdev);
-
- /* sanity check */
- if (!rdev->desc->ops->get_current_limit) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = rdev->desc->ops->get_current_limit(rdev);
-out:
+ ret = _regulator_get_current_limit_unlocked(rdev);
regulator_unlock(rdev);
+
return ret;
}
@@ -3666,21 +4446,23 @@
}
EXPORT_SYMBOL_GPL(regulator_set_mode);
+static unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev)
+{
+ /* sanity check */
+ if (!rdev->desc->ops->get_mode)
+ return -EINVAL;
+
+ return rdev->desc->ops->get_mode(rdev);
+}
+
static unsigned int _regulator_get_mode(struct regulator_dev *rdev)
{
int ret;
regulator_lock(rdev);
-
- /* sanity check */
- if (!rdev->desc->ops->get_mode) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = rdev->desc->ops->get_mode(rdev);
-out:
+ ret = _regulator_get_mode_unlocked(rdev);
regulator_unlock(rdev);
+
return ret;
}
@@ -3753,16 +4535,30 @@
* DRMS will sum the total requested load on the regulator and change
* to the most efficient operating mode if platform constraints allow.
*
+ * NOTE: when a regulator consumer requests to have a regulator
+ * disabled then any load that consumer requested no longer counts
+ * toward the total requested load. If the regulator is re-enabled
+ * then the previously requested load will start counting again.
+ *
+ * If a regulator is an always-on regulator then an individual consumer's
+ * load will still be removed if that consumer is fully disabled.
+ *
* On error a negative errno is returned.
*/
int regulator_set_load(struct regulator *regulator, int uA_load)
{
struct regulator_dev *rdev = regulator->rdev;
- int ret;
+ int old_uA_load;
+ int ret = 0;
regulator_lock(rdev);
+ old_uA_load = regulator->uA_load;
regulator->uA_load = uA_load;
- ret = drms_uA_update(rdev);
+ if (regulator->enable_count && old_uA_load != uA_load) {
+ ret = drms_uA_update(rdev);
+ if (ret < 0)
+ regulator->uA_load = old_uA_load;
+ }
regulator_unlock(rdev);
return ret;
@@ -3783,6 +4579,7 @@
int regulator_allow_bypass(struct regulator *regulator, bool enable)
{
struct regulator_dev *rdev = regulator->rdev;
+ const char *name = rdev_get_name(rdev);
int ret = 0;
if (!rdev->desc->ops->set_bypass)
@@ -3797,18 +4594,26 @@
rdev->bypass_count++;
if (rdev->bypass_count == rdev->open_count) {
+ trace_regulator_bypass_enable(name);
+
ret = rdev->desc->ops->set_bypass(rdev, enable);
if (ret != 0)
rdev->bypass_count--;
+ else
+ trace_regulator_bypass_enable_complete(name);
}
} else if (!enable && regulator->bypass) {
rdev->bypass_count--;
if (rdev->bypass_count != rdev->open_count) {
+ trace_regulator_bypass_disable(name);
+
ret = rdev->desc->ops->set_bypass(rdev, enable);
if (ret != 0)
rdev->bypass_count++;
+ else
+ trace_regulator_bypass_disable_complete(name);
}
}
@@ -3889,8 +4694,6 @@
consumers[i].supply);
if (IS_ERR(consumers[i].consumer)) {
ret = PTR_ERR(consumers[i].consumer);
- dev_err(dev, "Failed to get supply '%s': %d\n",
- consumers[i].supply, ret);
consumers[i].consumer = NULL;
goto err;
}
@@ -3899,6 +4702,13 @@
return 0;
err:
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get supply '%s': %pe\n",
+ consumers[i].supply, ERR_PTR(ret));
+ else
+ dev_dbg(dev, "Failed to get supply '%s', deferring\n",
+ consumers[i].supply);
+
while (--i >= 0)
regulator_put(consumers[i].consumer);
@@ -3933,11 +4743,8 @@
int ret = 0;
for (i = 0; i < num_consumers; i++) {
- if (consumers[i].consumer->always_on)
- consumers[i].ret = 0;
- else
- async_schedule_domain(regulator_bulk_enable_async,
- &consumers[i], &async_domain);
+ async_schedule_domain(regulator_bulk_enable_async,
+ &consumers[i], &async_domain);
}
async_synchronize_full_domain(&async_domain);
@@ -3955,8 +4762,8 @@
err:
for (i = 0; i < num_consumers; i++) {
if (consumers[i].ret < 0)
- pr_err("Failed to enable %s: %d\n", consumers[i].supply,
- consumers[i].ret);
+ pr_err("Failed to enable %s: %pe\n", consumers[i].supply,
+ ERR_PTR(consumers[i].ret));
else
regulator_disable(consumers[i].consumer);
}
@@ -3992,12 +4799,12 @@
return 0;
err:
- pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
+ pr_err("Failed to disable %s: %pe\n", consumers[i].supply, ERR_PTR(ret));
for (++i; i < num_consumers; ++i) {
r = regulator_enable(consumers[i].consumer);
if (r != 0)
- pr_err("Failed to re-enable %s: %d\n",
- consumers[i].supply, r);
+ pr_err("Failed to re-enable %s: %pe\n",
+ consumers[i].supply, ERR_PTR(r));
}
return ret;
@@ -4065,14 +4872,11 @@
* @data: callback-specific data.
*
* Called by regulator drivers to notify clients a regulator event has
- * occurred. We also notify regulator clients downstream.
- * Note lock must be held by caller.
+ * occurred.
*/
int regulator_notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
{
- lockdep_assert_held_once(&rdev->mutex);
-
_notifier_call_chain(rdev, event, data);
return NOTIFY_DONE;
@@ -4173,10 +4977,6 @@
if (attr == &dev_attr_bypass.attr)
return ops->get_bypass ? mode : 0;
- /* some attributes are type-specific */
- if (attr == &dev_attr_requested_microamps.attr)
- return rdev->desc->type == REGULATOR_CURRENT ? mode : 0;
-
/* constraints need specific supporting methods */
if (attr == &dev_attr_min_microvolts.attr ||
attr == &dev_attr_max_microvolts.attr)
@@ -4214,16 +5014,31 @@
NULL
};
+#ifdef CONFIG_DEBUG_FS
+static void rdev_deinit_debugfs(struct regulator_dev *rdev);
+#else
+static inline void rdev_deinit_debugfs(struct regulator_dev *rdev)
+{
+}
+#endif
+
static void regulator_dev_release(struct device *dev)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
+ rdev_deinit_debugfs(rdev);
kfree(rdev->constraints);
of_node_put(rdev->dev.of_node);
kfree(rdev);
}
#ifdef CONFIG_DEBUG_FS
+
+#define MAX_DEBUG_BUF_LEN 50
+#define REGULATOR_ALLOW_WRITE_DEBUGFS
+
+#ifdef REGULATOR_ALLOW_WRITE_DEBUGFS
+
static int reg_debug_enable_set(void *data, u64 val)
{
struct regulator *regulator = data;
@@ -4244,17 +5059,6 @@
return ret;
}
-static int reg_debug_enable_get(void *data, u64 *val)
-{
- struct regulator *regulator = data;
-
- *val = regulator_is_enabled(regulator);
-
- return 0;
-}
-DEFINE_DEBUGFS_ATTRIBUTE(reg_enable_fops, reg_debug_enable_get,
- reg_debug_enable_set, "%llu\n");
-
static int reg_debug_force_disable_set(void *data, u64 val)
{
struct regulator *regulator = data;
@@ -4269,10 +5073,7 @@
return ret;
}
-DEFINE_DEBUGFS_ATTRIBUTE(reg_force_disable_fops, reg_debug_enable_get,
- reg_debug_force_disable_set, "%llu\n");
-#define MAX_DEBUG_BUF_LEN 50
static ssize_t reg_debug_voltage_write(struct file *file,
const char __user *ubuf,
@@ -4325,6 +5126,57 @@
return count;
}
+static int reg_debug_mode_set(void *data, u64 val)
+{
+ struct regulator *regulator = data;
+ unsigned int mode = val;
+ int ret;
+
+ ret = regulator_set_mode(regulator, mode);
+ if (ret)
+ rdev_err(regulator->rdev, "set mode=%u failed, ret=%d\n",
+ mode, ret);
+
+ return ret;
+}
+
+static int reg_debug_set_load(void *data, u64 val)
+{
+ struct regulator *regulator = data;
+ int load = val;
+ int ret;
+
+ ret = regulator_set_load(regulator, load);
+ if (ret)
+ rdev_err(regulator->rdev, "set load=%d failed, ret=%d\n",
+ load, ret);
+
+ return ret;
+}
+
+#else
+#define reg_debug_enable_set NULL
+#define reg_debug_force_disable_set NULL
+#define reg_debug_voltage_write NULL
+#define reg_debug_mode_set NULL
+#define reg_debug_set_load NULL
+#endif
+
+static int reg_debug_enable_get(void *data, u64 *val)
+{
+ struct regulator *regulator = data;
+
+ *val = regulator_is_enabled(regulator);
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(reg_enable_fops, reg_debug_enable_get,
+ reg_debug_enable_set, "%llu\n");
+
+
+DEFINE_DEBUGFS_ATTRIBUTE(reg_force_disable_fops, reg_debug_enable_get,
+ reg_debug_force_disable_set, "%llu\n");
+
static ssize_t reg_debug_voltage_read(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
@@ -4352,20 +5204,6 @@
.read = reg_debug_voltage_read,
};
-static int reg_debug_mode_set(void *data, u64 val)
-{
- struct regulator *regulator = data;
- unsigned int mode = val;
- int ret;
-
- ret = regulator_set_mode(regulator, mode);
- if (ret)
- rdev_err(regulator->rdev, "set mode=%u failed, ret=%d\n",
- mode, ret);
-
- return ret;
-}
-
static int reg_debug_mode_get(void *data, u64 *val)
{
struct regulator *regulator = data;
@@ -4384,19 +5222,6 @@
DEFINE_DEBUGFS_ATTRIBUTE(reg_mode_fops, reg_debug_mode_get, reg_debug_mode_set,
"%llu\n");
-static int reg_debug_set_load(void *data, u64 val)
-{
- struct regulator *regulator = data;
- int load = val;
- int ret;
-
- ret = regulator_set_load(regulator, load);
- if (ret)
- rdev_err(regulator->rdev, "set load=%d failed, ret=%d\n",
- load, ret);
-
- return ret;
-}
DEFINE_DEBUGFS_ATTRIBUTE(reg_set_load_fops, reg_debug_mode_get,
reg_debug_set_load, "%llu\n");
@@ -4445,9 +5270,6 @@
{
struct regulator_limit_volt *reg_debug, *n;
- if (IS_ERR_OR_NULL(rdev))
- return;
-
debugfs_remove_recursive(rdev->debugfs);
list_for_each_entry_safe(reg_debug, n, ®ulator_debug_list, list) {
@@ -4478,10 +5300,8 @@
}
rdev->debugfs = debugfs_create_dir(rname, debugfs_root);
- if (!rdev->debugfs) {
- rdev_warn(rdev, "Failed to create debugfs directory\n");
- return;
- }
+ if (IS_ERR(rdev->debugfs))
+ rdev_dbg(rdev, "Failed to create debugfs directory\n");
debugfs_create_u32("use_count", 0444, rdev->debugfs,
&rdev->use_count);
@@ -4509,14 +5329,20 @@
ops = rdev->desc->ops;
- debugfs_create_file("enable", 0644, rdev->debugfs, regulator,
+ mode = 0444;
+#ifdef REGULATOR_ALLOW_WRITE_DEBUGFS
+ mode |= 0200;
+#endif
+ debugfs_create_file("enable", mode, rdev->debugfs, regulator,
®_enable_fops);
mode = 0;
if (ops->is_enabled)
mode |= 0444;
+#ifdef REGULATOR_ALLOW_WRITE_DEBUGFS
if (ops->disable)
mode |= 0200;
+#endif
if (mode)
debugfs_create_file("force_disable", mode, rdev->debugfs,
regulator, ®_force_disable_fops);
@@ -4524,8 +5350,10 @@
mode = 0;
if (ops->get_voltage || ops->get_voltage_sel)
mode |= 0444;
+#ifdef REGULATOR_ALLOW_WRITE_DEBUGFS
if (ops->set_voltage || ops->set_voltage_sel)
mode |= 0200;
+#endif
if (mode)
debugfs_create_file("voltage", mode, rdev->debugfs, regulator,
®_voltage_fops);
@@ -4533,8 +5361,10 @@
mode = 0;
if (ops->get_mode)
mode |= 0444;
+#ifdef REGULATOR_ALLOW_WRITE_DEBUGFS
if (ops->set_mode)
mode |= 0200;
+#endif
if (mode)
debugfs_create_file("mode", mode, rdev->debugfs, regulator,
®_mode_fops);
@@ -4542,53 +5372,20 @@
mode = 0;
if (ops->get_mode)
mode |= 0444;
+#ifdef REGULATOR_ALLOW_WRITE_DEBUGFS
if (ops->set_load || (ops->get_optimum_mode && ops->set_mode))
mode |= 0200;
+#endif
if (mode)
debugfs_create_file("load", mode, rdev->debugfs, regulator,
®_set_load_fops);
}
#else
-static inline void rdev_deinit_debugfs(struct regulator_dev *rdev)
-{
-}
-
static inline void rdev_init_debugfs(struct regulator_dev *rdev)
{
}
#endif
-
-static void rdev_init_early_min_volt(struct regulator_dev *rdev)
-{
- struct device_node *np = rdev->dev.of_node;
- struct regulator_limit_volt *reg_early;
- u32 pval;
-
- /*
- * Minimum voltage during system startup, make sure we select a
- * voltage that suits the needs of all regulator consumers
- */
- if (of_property_read_u32(np, "regulator-early-min-microvolt", &pval))
- return;
-
- reg_early = kzalloc(sizeof(*reg_early), GFP_KERNEL);
- if (reg_early == NULL)
- return;
-
- reg_early->reg = regulator_get(NULL, rdev_get_name(rdev));
- if (IS_ERR(reg_early->reg)) {
- rdev_err(rdev, "regulator get failed, ret=%ld\n",
- PTR_ERR(reg_early->reg));
- return;
- }
-
- reg_early->reg->voltage[PM_SUSPEND_ON].min_uV = pval;
- reg_early->reg->voltage[PM_SUSPEND_ON].max_uV =
- rdev->constraints->max_uV;
-
- list_add(®_early->list, ®ulator_early_min_volt_list);
-}
static int regulator_register_resolve_supply(struct device *dev, void *data)
{
@@ -4600,8 +5397,60 @@
return 0;
}
-static int regulator_fill_coupling_array(struct regulator_dev *rdev)
+int regulator_coupler_register(struct regulator_coupler *coupler)
{
+ mutex_lock(®ulator_list_mutex);
+ list_add_tail(&coupler->list, ®ulator_coupler_list);
+ mutex_unlock(®ulator_list_mutex);
+
+ return 0;
+}
+
+static struct regulator_coupler *
+regulator_find_coupler(struct regulator_dev *rdev)
+{
+ struct regulator_coupler *coupler;
+ int err;
+
+ /*
+ * Note that regulators are appended to the list and the generic
+ * coupler is registered first, hence it will be attached at last
+ * if nobody cared.
+ */
+ list_for_each_entry_reverse(coupler, ®ulator_coupler_list, list) {
+ err = coupler->attach_regulator(coupler, rdev);
+ if (!err) {
+ if (!coupler->balance_voltage &&
+ rdev->coupling_desc.n_coupled > 2)
+ goto err_unsupported;
+
+ return coupler;
+ }
+
+ if (err < 0)
+ return ERR_PTR(err);
+
+ if (err == 1)
+ continue;
+
+ break;
+ }
+
+ return ERR_PTR(-EINVAL);
+
+err_unsupported:
+ if (coupler->detach_regulator)
+ coupler->detach_regulator(coupler, rdev);
+
+ rdev_err(rdev,
+ "Voltage balancing for multiple regulator couples is unimplemented\n");
+
+ return ERR_PTR(-EPERM);
+}
+
+static void regulator_resolve_coupling(struct regulator_dev *rdev)
+{
+ struct regulator_coupler *coupler = rdev->coupling_desc.coupler;
struct coupling_desc *c_desc = &rdev->coupling_desc;
int n_coupled = c_desc->n_coupled;
struct regulator_dev *c_rdev;
@@ -4614,45 +5463,86 @@
c_rdev = of_parse_coupled_regulator(rdev, i - 1);
- if (c_rdev) {
- c_desc->coupled_rdevs[i] = c_rdev;
- c_desc->n_resolved++;
+ if (!c_rdev)
+ continue;
+
+ if (c_rdev->coupling_desc.coupler != coupler) {
+ rdev_err(rdev, "coupler mismatch with %s\n",
+ rdev_get_name(c_rdev));
+ return;
}
+
+ c_desc->coupled_rdevs[i] = c_rdev;
+ c_desc->n_resolved++;
+
+ regulator_resolve_coupling(c_rdev);
+ }
+}
+
+static void regulator_remove_coupling(struct regulator_dev *rdev)
+{
+ struct regulator_coupler *coupler = rdev->coupling_desc.coupler;
+ struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc;
+ struct regulator_dev *__c_rdev, *c_rdev;
+ unsigned int __n_coupled, n_coupled;
+ int i, k;
+ int err;
+
+ n_coupled = c_desc->n_coupled;
+
+ for (i = 1; i < n_coupled; i++) {
+ c_rdev = c_desc->coupled_rdevs[i];
+
+ if (!c_rdev)
+ continue;
+
+ regulator_lock(c_rdev);
+
+ __c_desc = &c_rdev->coupling_desc;
+ __n_coupled = __c_desc->n_coupled;
+
+ for (k = 1; k < __n_coupled; k++) {
+ __c_rdev = __c_desc->coupled_rdevs[k];
+
+ if (__c_rdev == rdev) {
+ __c_desc->coupled_rdevs[k] = NULL;
+ __c_desc->n_resolved--;
+ break;
+ }
+ }
+
+ regulator_unlock(c_rdev);
+
+ c_desc->coupled_rdevs[i] = NULL;
+ c_desc->n_resolved--;
}
- if (rdev->coupling_desc.n_resolved < n_coupled)
- return -1;
- else
- return 0;
+ if (coupler && coupler->detach_regulator) {
+ err = coupler->detach_regulator(coupler, rdev);
+ if (err)
+ rdev_err(rdev, "failed to detach from coupler: %pe\n",
+ ERR_PTR(err));
+ }
+
+ kfree(rdev->coupling_desc.coupled_rdevs);
+ rdev->coupling_desc.coupled_rdevs = NULL;
}
-static int regulator_register_fill_coupling_array(struct device *dev,
- void *data)
+static int regulator_init_coupling(struct regulator_dev *rdev)
{
- struct regulator_dev *rdev = dev_to_rdev(dev);
-
- if (!IS_ENABLED(CONFIG_OF))
- return 0;
-
- if (regulator_fill_coupling_array(rdev))
- rdev_dbg(rdev, "unable to resolve coupling\n");
-
- return 0;
-}
-
-static int regulator_resolve_coupling(struct regulator_dev *rdev)
-{
- int n_phandles;
+ struct regulator_dev **coupled;
+ int err, n_phandles;
if (!IS_ENABLED(CONFIG_OF))
n_phandles = 0;
else
n_phandles = of_get_n_coupled(rdev);
- if (n_phandles + 1 > MAX_COUPLED) {
- rdev_err(rdev, "too many regulators coupled\n");
- return -EPERM;
- }
+ coupled = kcalloc(n_phandles + 1, sizeof(*coupled), GFP_KERNEL);
+ if (!coupled)
+ return -ENOMEM;
+
+ rdev->coupling_desc.coupled_rdevs = coupled;
/*
* Every regulator should always have coupling descriptor filled with
@@ -4666,29 +5556,43 @@
if (n_phandles == 0)
return 0;
- /* regulator, which can't change its voltage, can't be coupled */
- if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
- rdev_err(rdev, "voltage operation not allowed\n");
- return -EPERM;
- }
-
- if (rdev->constraints->max_spread <= 0) {
- rdev_err(rdev, "wrong max_spread value\n");
- return -EPERM;
- }
-
if (!of_check_coupling_data(rdev))
return -EPERM;
- /*
- * After everything has been checked, try to fill rdevs array
- * with pointers to regulators parsed from device tree. If some
- * regulators are not registered yet, retry in late init call
- */
- regulator_fill_coupling_array(rdev);
+ mutex_lock(®ulator_list_mutex);
+ rdev->coupling_desc.coupler = regulator_find_coupler(rdev);
+ mutex_unlock(®ulator_list_mutex);
+
+ if (IS_ERR(rdev->coupling_desc.coupler)) {
+ err = PTR_ERR(rdev->coupling_desc.coupler);
+ rdev_err(rdev, "failed to get coupler: %pe\n", ERR_PTR(err));
+ return err;
+ }
return 0;
}
+
+static int generic_coupler_attach(struct regulator_coupler *coupler,
+ struct regulator_dev *rdev)
+{
+ if (rdev->coupling_desc.n_coupled > 2) {
+ rdev_err(rdev,
+ "Voltage balancing for multiple regulator couples is unimplemented\n");
+ return -EPERM;
+ }
+
+ if (!rdev->constraints->always_on) {
+ rdev_err(rdev,
+ "Coupling of a non always-on regulator is unimplemented\n");
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static struct regulator_coupler generic_regulator_coupler = {
+ .attach_regulator = generic_coupler_attach,
+};
/**
* regulator_register - register regulator
@@ -4707,21 +5611,33 @@
struct regulator_config *config = NULL;
static atomic_t regulator_no = ATOMIC_INIT(-1);
struct regulator_dev *rdev;
+ bool dangling_cfg_gpiod = false;
+ bool dangling_of_gpiod = false;
struct device *dev;
int ret, i;
- if (regulator_desc == NULL || cfg == NULL)
+ if (cfg == NULL)
return ERR_PTR(-EINVAL);
+ if (cfg->ena_gpiod)
+ dangling_cfg_gpiod = true;
+ if (regulator_desc == NULL) {
+ ret = -EINVAL;
+ goto rinse;
+ }
dev = cfg->dev;
WARN_ON(!dev);
- if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
- return ERR_PTR(-EINVAL);
+ if (regulator_desc->name == NULL || regulator_desc->ops == NULL) {
+ ret = -EINVAL;
+ goto rinse;
+ }
if (regulator_desc->type != REGULATOR_VOLTAGE &&
- regulator_desc->type != REGULATOR_CURRENT)
- return ERR_PTR(-EINVAL);
+ regulator_desc->type != REGULATOR_CURRENT) {
+ ret = -EINVAL;
+ goto rinse;
+ }
/* Only one of each should be implemented */
WARN_ON(regulator_desc->ops->get_voltage &&
@@ -4732,16 +5648,21 @@
/* If we're using selectors we must implement list_voltage. */
if (regulator_desc->ops->get_voltage_sel &&
!regulator_desc->ops->list_voltage) {
- return ERR_PTR(-EINVAL);
+ ret = -EINVAL;
+ goto rinse;
}
if (regulator_desc->ops->set_voltage_sel &&
!regulator_desc->ops->list_voltage) {
- return ERR_PTR(-EINVAL);
+ ret = -EINVAL;
+ goto rinse;
}
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
- if (rdev == NULL)
- return ERR_PTR(-ENOMEM);
+ if (rdev == NULL) {
+ ret = -ENOMEM;
+ goto rinse;
+ }
+ device_initialize(&rdev->dev);
/*
* Duplicate the config so the driver could override it after
@@ -4749,18 +5670,39 @@
*/
config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL);
if (config == NULL) {
- kfree(rdev);
- return ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
+ goto clean;
}
init_data = regulator_of_get_init_data(dev, regulator_desc, config,
&rdev->dev.of_node);
+
+ /*
+ * Sometimes not all resources are probed already so we need to take
+ * that into account. This happens most the time if the ena_gpiod comes
+ * from a gpio extender or something else.
+ */
+ if (PTR_ERR(init_data) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto clean;
+ }
+
+ /*
+ * We need to keep track of any GPIO descriptor coming from the
+ * device tree until we have handled it over to the core. If the
+ * config that was passed in to this function DOES NOT contain
+ * a descriptor, and the config after this call DOES contain
+ * a descriptor, we definitely got one from parsing the device
+ * tree.
+ */
+ if (!cfg->ena_gpiod && config->ena_gpiod)
+ dangling_of_gpiod = true;
if (!init_data) {
init_data = config->init_data;
rdev->dev.of_node = of_node_get(config->of_node);
}
- mutex_init(&rdev->mutex);
+ ww_mutex_init(&rdev->mutex, ®ulator_ww_class);
rdev->reg_data = config->driver_data;
rdev->owner = regulator_desc->owner;
rdev->desc = regulator_desc;
@@ -4782,17 +5724,16 @@
goto clean;
}
- if (config->ena_gpiod ||
- ((config->ena_gpio || config->ena_gpio_initialized) &&
- gpio_is_valid(config->ena_gpio))) {
- mutex_lock(®ulator_list_mutex);
+ if (config->ena_gpiod) {
ret = regulator_ena_gpio_request(rdev, config);
- mutex_unlock(®ulator_list_mutex);
if (ret != 0) {
- rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
- config->ena_gpio, ret);
+ rdev_err(rdev, "Failed to request enable GPIO: %pe\n",
+ ERR_PTR(ret));
goto clean;
}
+ /* The regulator core took over the GPIO descriptor */
+ dangling_cfg_gpiod = false;
+ dangling_of_gpiod = false;
}
/* register with sysfs */
@@ -4800,6 +5741,7 @@
rdev->dev.parent = dev;
dev_set_name(&rdev->dev, "regulator.%lu",
(unsigned long) atomic_inc_return(®ulator_no));
+ dev_set_drvdata(&rdev->dev, rdev);
/* set regulator constraints */
if (init_data)
@@ -4836,11 +5778,8 @@
if (ret < 0)
goto wash;
- mutex_lock(®ulator_list_mutex);
- ret = regulator_resolve_coupling(rdev);
- mutex_unlock(®ulator_list_mutex);
-
- if (ret != 0)
+ ret = regulator_init_coupling(rdev);
+ if (ret < 0)
goto wash;
/* add consumers devices */
@@ -4862,29 +5801,16 @@
!rdev->desc->fixed_uV)
rdev->is_switch = true;
- dev_set_drvdata(&rdev->dev, rdev);
- ret = device_register(&rdev->dev);
- if (ret != 0) {
- put_device(&rdev->dev);
+ ret = device_add(&rdev->dev);
+ if (ret != 0)
goto unset_supplies;
- }
-
- /* Add a link to the device sysfs entry */
- if (rdev->supply && rdev->supply->dev) {
- ret = sysfs_create_link_nowarn(&rdev->supply->dev->kobj,
- &rdev->dev.kobj,
- rdev->supply->supply_name);
- if (ret) {
- rdev_dbg(rdev, "could not add device link %s err %d\n",
- rdev->dev.kobj.name, ret);
- /* non-fatal */
- }
- }
rdev_init_debugfs(rdev);
- rdev_init_early_min_volt(rdev);
- rdev->proxy_consumer = regulator_proxy_consumer_register(dev,
- config->of_node);
+
+ /* try to resolve regulators coupling since a new one was registered */
+ mutex_lock(®ulator_list_mutex);
+ regulator_resolve_coupling(rdev);
+ mutex_unlock(®ulator_list_mutex);
/* try to resolve regulators supply since a new one was registered */
class_for_each_device(®ulator_class, NULL, NULL,
@@ -4895,15 +5821,26 @@
unset_supplies:
mutex_lock(®ulator_list_mutex);
unset_regulator_supplies(rdev);
+ regulator_remove_coupling(rdev);
mutex_unlock(®ulator_list_mutex);
wash:
- kfree(rdev->constraints);
+ regulator_put(rdev->supply);
+ kfree(rdev->coupling_desc.coupled_rdevs);
mutex_lock(®ulator_list_mutex);
regulator_ena_gpio_free(rdev);
mutex_unlock(®ulator_list_mutex);
+ put_device(&rdev->dev);
+ rdev = NULL;
clean:
+ if (dangling_of_gpiod)
+ gpiod_put(config->ena_gpiod);
+ if (rdev && rdev->dev.of_node)
+ of_node_put(rdev->dev.of_node);
kfree(rdev);
kfree(config);
+rinse:
+ if (dangling_cfg_gpiod)
+ gpiod_put(cfg->ena_gpiod);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(regulator_register);
@@ -4924,89 +5861,42 @@
regulator_disable(rdev->supply);
regulator_put(rdev->supply);
}
- rdev_deinit_debugfs(rdev);
- regulator_proxy_consumer_unregister(rdev->proxy_consumer);
- mutex_lock(®ulator_list_mutex);
+
flush_work(&rdev->disable_work.work);
+
+ mutex_lock(®ulator_list_mutex);
+
WARN_ON(rdev->open_count);
+ regulator_remove_coupling(rdev);
unset_regulator_supplies(rdev);
list_del(&rdev->list);
regulator_ena_gpio_free(rdev);
- mutex_unlock(®ulator_list_mutex);
device_unregister(&rdev->dev);
+
+ mutex_unlock(®ulator_list_mutex);
}
EXPORT_SYMBOL_GPL(regulator_unregister);
-static int regulator_sync_supply(struct device *dev, void *data)
-{
- struct regulator_dev *rdev = dev_to_rdev(dev);
-
- if (rdev->dev.parent != data)
- return 0;
-
- if (!rdev->proxy_consumer)
- return 0;
-
- dev_dbg(data, "Removing regulator proxy consumer requests\n");
- regulator_proxy_consumer_unregister(rdev->proxy_consumer);
- rdev->proxy_consumer = NULL;
-
- return 0;
-}
-
-void regulator_sync_state(struct device *dev)
-{
- class_for_each_device(®ulator_class, NULL, dev,
- regulator_sync_supply);
-}
-EXPORT_SYMBOL_GPL(regulator_sync_state);
-
#ifdef CONFIG_SUSPEND
-static int _regulator_suspend(struct device *dev, void *data)
-{
- struct regulator_dev *rdev = dev_to_rdev(dev);
- suspend_state_t *state = data;
- int ret;
-
- regulator_lock(rdev);
- ret = suspend_set_state(rdev, *state);
- regulator_unlock(rdev);
-
- return ret;
-}
-
/**
* regulator_suspend - prepare regulators for system wide suspend
- * @state: system suspend state
+ * @dev: ``&struct device`` pointer that is passed to _regulator_suspend()
*
* Configure each regulator with it's suspend operating parameters for state.
*/
static int regulator_suspend(struct device *dev)
{
- suspend_state_t state = pm_suspend_target_state;
-
- return class_for_each_device(®ulator_class, NULL, &state,
- _regulator_suspend);
-}
-
-static int _regulator_resume(struct device *dev, void *data)
-{
- int ret = 0;
struct regulator_dev *rdev = dev_to_rdev(dev);
- suspend_state_t *state = data;
- struct regulator_state *rstate;
+ suspend_state_t state = pm_suspend_target_state;
+ int ret;
+ const struct regulator_state *rstate;
- rstate = regulator_get_suspend_state(rdev, *state);
- if (rstate == NULL)
+ rstate = regulator_get_suspend_state_check(rdev, state);
+ if (!rstate)
return 0;
regulator_lock(rdev);
-
- if (rdev->desc->ops->resume &&
- (rstate->enabled == ENABLE_IN_SUSPEND ||
- rstate->enabled == DISABLE_IN_SUSPEND))
- ret = rdev->desc->ops->resume(rdev);
-
+ ret = __suspend_set_state(rdev, rstate);
regulator_unlock(rdev);
return ret;
@@ -5015,11 +5905,28 @@
static int regulator_resume(struct device *dev)
{
suspend_state_t state = pm_suspend_target_state;
+ struct regulator_dev *rdev = dev_to_rdev(dev);
+ struct regulator_state *rstate;
+ int ret = 0;
- return class_for_each_device(®ulator_class, NULL, &state,
- _regulator_resume);
+ rstate = regulator_get_suspend_state(rdev, state);
+ if (rstate == NULL)
+ return 0;
+
+ /* Avoid grabbing the lock if we don't need to */
+ if (!rdev->desc->ops->resume)
+ return 0;
+
+ regulator_lock(rdev);
+
+ if (rstate->enabled == ENABLE_IN_SUSPEND ||
+ rstate->enabled == DISABLE_IN_SUSPEND)
+ ret = rdev->desc->ops->resume(rdev);
+
+ regulator_unlock(rdev);
+
+ return ret;
}
-
#else /* !CONFIG_SUSPEND */
#define regulator_suspend NULL
@@ -5112,6 +6019,12 @@
}
EXPORT_SYMBOL_GPL(rdev_get_dev);
+struct regmap *rdev_get_regmap(struct regulator_dev *rdev)
+{
+ return rdev->regmap;
+}
+EXPORT_SYMBOL_GPL(rdev_get_regmap);
+
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
{
return reg_init_data->driver_data;
@@ -5131,23 +6044,8 @@
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(supply_map);
-static int supply_map_open(struct inode *inode, struct file *file)
-{
- return single_open(file, supply_map_show, inode->i_private);
-}
-#endif
-
-static const struct file_operations supply_map_fops = {
-#ifdef CONFIG_DEBUG_FS
- .open = supply_map_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-#endif
-};
-
-#ifdef CONFIG_DEBUG_FS
struct summary_data {
struct seq_file *s;
struct regulator_dev *parent;
@@ -5177,17 +6075,21 @@
struct regulation_constraints *c;
struct regulator *consumer;
struct summary_data summary_data;
+ unsigned int opmode;
if (!rdev)
return;
- seq_printf(s, "%*s%-*s %3d %4d %6d ",
+ opmode = _regulator_get_mode_unlocked(rdev);
+ seq_printf(s, "%*s%-*s %3d %4d %6d %7s ",
level * 3 + 1, "",
30 - level * 3, rdev_get_name(rdev),
- rdev->use_count, rdev->open_count, rdev->bypass_count);
+ rdev->use_count, rdev->open_count, rdev->bypass_count,
+ regulator_opmode_to_str(opmode));
- seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000);
- seq_printf(s, "%5dmA ", _regulator_get_current_limit(rdev) / 1000);
+ seq_printf(s, "%5dmV ", regulator_get_voltage_rdev(rdev) / 1000);
+ seq_printf(s, "%5dmA ",
+ _regulator_get_current_limit_unlocked(rdev) / 1000);
c = rdev->constraints;
if (c) {
@@ -5217,7 +6119,11 @@
switch (rdev->desc->type) {
case REGULATOR_VOLTAGE:
- seq_printf(s, "%37dmV %5dmV",
+ seq_printf(s, "%3d %33dmA%c%5dmV %5dmV",
+ consumer->enable_count,
+ consumer->uA_load / 1000,
+ consumer->uA_load && !consumer->enable_count ?
+ '*' : ' ',
consumer->voltage[PM_SUSPEND_ON].min_uV / 1000,
consumer->voltage[PM_SUSPEND_ON].max_uV / 1000);
break;
@@ -5236,6 +6142,106 @@
regulator_summary_show_children);
}
+struct summary_lock_data {
+ struct ww_acquire_ctx *ww_ctx;
+ struct regulator_dev **new_contended_rdev;
+ struct regulator_dev **old_contended_rdev;
+};
+
+static int regulator_summary_lock_one(struct device *dev, void *data)
+{
+ struct regulator_dev *rdev = dev_to_rdev(dev);
+ struct summary_lock_data *lock_data = data;
+ int ret = 0;
+
+ if (rdev != *lock_data->old_contended_rdev) {
+ ret = regulator_lock_nested(rdev, lock_data->ww_ctx);
+
+ if (ret == -EDEADLK)
+ *lock_data->new_contended_rdev = rdev;
+ else
+ WARN_ON_ONCE(ret);
+ } else {
+ *lock_data->old_contended_rdev = NULL;
+ }
+
+ return ret;
+}
+
+static int regulator_summary_unlock_one(struct device *dev, void *data)
+{
+ struct regulator_dev *rdev = dev_to_rdev(dev);
+ struct summary_lock_data *lock_data = data;
+
+ if (lock_data) {
+ if (rdev == *lock_data->new_contended_rdev)
+ return -EDEADLK;
+ }
+
+ regulator_unlock(rdev);
+
+ return 0;
+}
+
+static int regulator_summary_lock_all(struct ww_acquire_ctx *ww_ctx,
+ struct regulator_dev **new_contended_rdev,
+ struct regulator_dev **old_contended_rdev)
+{
+ struct summary_lock_data lock_data;
+ int ret;
+
+ lock_data.ww_ctx = ww_ctx;
+ lock_data.new_contended_rdev = new_contended_rdev;
+ lock_data.old_contended_rdev = old_contended_rdev;
+
+ ret = class_for_each_device(®ulator_class, NULL, &lock_data,
+ regulator_summary_lock_one);
+ if (ret)
+ class_for_each_device(®ulator_class, NULL, &lock_data,
+ regulator_summary_unlock_one);
+
+ return ret;
+}
+
+static void regulator_summary_lock(struct ww_acquire_ctx *ww_ctx)
+{
+ struct regulator_dev *new_contended_rdev = NULL;
+ struct regulator_dev *old_contended_rdev = NULL;
+ int err;
+
+ mutex_lock(®ulator_list_mutex);
+
+ ww_acquire_init(ww_ctx, ®ulator_ww_class);
+
+ do {
+ if (new_contended_rdev) {
+ ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx);
+ old_contended_rdev = new_contended_rdev;
+ old_contended_rdev->ref_cnt++;
+ old_contended_rdev->mutex_owner = current;
+ }
+
+ err = regulator_summary_lock_all(ww_ctx,
+ &new_contended_rdev,
+ &old_contended_rdev);
+
+ if (old_contended_rdev)
+ regulator_unlock(old_contended_rdev);
+
+ } while (err == -EDEADLK);
+
+ ww_acquire_done(ww_ctx);
+}
+
+static void regulator_summary_unlock(struct ww_acquire_ctx *ww_ctx)
+{
+ class_for_each_device(®ulator_class, NULL, NULL,
+ regulator_summary_unlock_one);
+ ww_acquire_fini(ww_ctx);
+
+ mutex_unlock(®ulator_list_mutex);
+}
+
static int regulator_summary_show_roots(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
@@ -5249,29 +6255,22 @@
static int regulator_summary_show(struct seq_file *s, void *data)
{
- seq_puts(s, " regulator use open bypass voltage current min max\n");
- seq_puts(s, "-------------------------------------------------------------------------------\n");
+ struct ww_acquire_ctx ww_ctx;
+
+ seq_puts(s, " regulator use open bypass opmode voltage current min max\n");
+ seq_puts(s, "---------------------------------------------------------------------------------------\n");
+
+ regulator_summary_lock(&ww_ctx);
class_for_each_device(®ulator_class, NULL, s,
regulator_summary_show_roots);
+ regulator_summary_unlock(&ww_ctx);
+
return 0;
}
-
-static int regulator_summary_open(struct inode *inode, struct file *file)
-{
- return single_open(file, regulator_summary_show, inode->i_private);
-}
-#endif
-
-static const struct file_operations regulator_summary_fops = {
-#ifdef CONFIG_DEBUG_FS
- .open = regulator_summary_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-#endif
-};
+DEFINE_SHOW_ATTRIBUTE(regulator_summary);
+#endif /* CONFIG_DEBUG_FS */
static int __init regulator_init(void)
{
@@ -5280,16 +6279,19 @@
ret = class_register(®ulator_class);
debugfs_root = debugfs_create_dir("regulator", NULL);
- if (!debugfs_root)
- pr_warn("regulator: Failed to create debugfs directory\n");
+ if (IS_ERR(debugfs_root))
+ pr_debug("regulator: Failed to create debugfs directory\n");
+#ifdef CONFIG_DEBUG_FS
debugfs_create_file("supply_map", 0444, debugfs_root, NULL,
&supply_map_fops);
debugfs_create_file("regulator_summary", 0444, debugfs_root,
NULL, ®ulator_summary_fops);
-
+#endif
regulator_dummy_init();
+
+ regulator_coupler_register(&generic_regulator_coupler);
return ret;
}
@@ -5304,9 +6306,8 @@
static int regulator_late_cleanup(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
- const struct regulator_ops *ops = rdev->desc->ops;
struct regulation_constraints *c = rdev->constraints;
- int enabled, ret;
+ int ret;
if (c && c->always_on)
return 0;
@@ -5319,13 +6320,8 @@
if (rdev->use_count)
goto unlock;
- /* If we can't read the status assume it's on. */
- if (ops->is_enabled)
- enabled = ops->is_enabled(rdev);
- else
- enabled = 1;
-
- if (!enabled)
+ /* If reading the status failed, assume that it's off. */
+ if (_regulator_is_enabled(rdev) <= 0)
goto unlock;
if (have_full_constraints()) {
@@ -5334,7 +6330,7 @@
rdev_info(rdev, "disabling\n");
ret = _regulator_do_disable(rdev);
if (ret != 0)
- rdev_err(rdev, "couldn't disable: %d\n", ret);
+ rdev_err(rdev, "couldn't disable: %pe\n", ERR_PTR(ret));
} else {
/* The intention is that in future we will
* assume that full constraints are provided
@@ -5374,49 +6370,6 @@
static DECLARE_DELAYED_WORK(regulator_init_complete_work,
regulator_init_complete_work_function);
-static void __init regulator_release_early_min_volt(void)
-{
- struct regulator_limit_volt *reg_early, *n;
- struct regulator *reg;
- struct regulator_dev *rdev;
- int min_uV = 0, max_uV = 0, ret = 0;
-
- if (list_empty(®ulator_early_min_volt_list))
- return;
-
- list_for_each_entry_safe(reg_early, n, ®ulator_early_min_volt_list,
- list) {
- rdev = reg_early->reg->rdev;
-
- regulator_lock_supply(rdev);
-
- reg_early->reg->voltage[PM_SUSPEND_ON].min_uV = 0;
- reg_early->reg->voltage[PM_SUSPEND_ON].max_uV = 0;
- min_uV = rdev->constraints->min_uV;
- max_uV = rdev->constraints->max_uV;
-
- list_for_each_entry(reg, &rdev->consumer_list, list) {
- if (!reg->voltage[PM_SUSPEND_ON].min_uV &&
- !reg->voltage[PM_SUSPEND_ON].max_uV)
- continue;
- ret = regulator_set_voltage_unlocked(reg_early->reg,
- min_uV,
- max_uV,
- PM_SUSPEND_ON);
- if (ret)
- rdev_err(rdev, "set voltage(%d, %d) failed\n",
- min_uV, max_uV);
- break;
- }
-
- regulator_unlock_supply(rdev);
-
- list_del(®_early->list);
- regulator_put(reg_early->reg);
- kfree(reg_early);
- }
-}
-
static int __init regulator_init_complete(void)
{
/*
@@ -5441,11 +6394,6 @@
*/
schedule_delayed_work(®ulator_init_complete_work,
msecs_to_jiffies(30000));
-
- class_for_each_device(®ulator_class, NULL, NULL,
- regulator_register_fill_coupling_array);
-
- regulator_release_early_min_volt();
return 0;
}
--
Gitblit v1.6.2