regulator: core: Introduce API for regulators coupling customization

Right now regulator core supports only one type of regulators coupling,
the "voltage max-spread" which keeps voltages of coupled regulators in a
given range from each other. A more sophisticated coupling may be required
in practice, one example is the NVIDIA Tegra SoCs which besides the
max-spreading have other restrictions that must be adhered. Introduce API
that allow platforms to provide their own customized coupling algorithms.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Dmitry Osipenko
2019-06-24 00:08:31 +03:00
committed by Mark Brown
parent a188339ca5
commit d8ca7d184b
5 changed files with 228 additions and 47 deletions

View File

@@ -25,7 +25,8 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
[PM_SUSPEND_MAX] = "regulator-state-disk",
};
static void of_get_regulation_constraints(struct device_node *np,
static int of_get_regulation_constraints(struct device *dev,
struct device_node *np,
struct regulator_init_data **init_data,
const struct regulator_desc *desc)
{
@@ -34,8 +35,13 @@ static void of_get_regulation_constraints(struct device_node *np,
struct device_node *suspend_np;
unsigned int mode;
int ret, i, len;
int n_phandles;
u32 pval;
n_phandles = of_count_phandle_with_args(np, "regulator-coupled-with",
NULL);
n_phandles = max(n_phandles, 0);
constraints->name = of_get_property(np, "regulator-name", NULL);
if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
@@ -167,9 +173,17 @@ static void of_get_regulation_constraints(struct device_node *np,
if (!of_property_read_u32(np, "regulator-system-load", &pval))
constraints->system_load = pval;
if (!of_property_read_u32(np, "regulator-coupled-max-spread",
&pval))
constraints->max_spread = pval;
if (n_phandles) {
constraints->max_spread = devm_kzalloc(dev,
sizeof(*constraints->max_spread) * n_phandles,
GFP_KERNEL);
if (!constraints->max_spread)
return -ENOMEM;
of_property_read_u32_array(np, "regulator-coupled-max-spread",
constraints->max_spread, n_phandles);
}
if (!of_property_read_u32(np, "regulator-max-step-microvolt",
&pval))
@@ -246,6 +260,8 @@ static void of_get_regulation_constraints(struct device_node *np,
suspend_state = NULL;
suspend_np = NULL;
}
return 0;
}
/**
@@ -271,7 +287,9 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
if (!init_data)
return NULL; /* Out of memory? */
of_get_regulation_constraints(node, &init_data, desc);
if (of_get_regulation_constraints(dev, node, &init_data, desc))
return NULL;
return init_data;
}
EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
@@ -477,7 +495,8 @@ int of_get_n_coupled(struct regulator_dev *rdev)
/* Looks for "to_find" device_node in src's "regulator-coupled-with" property */
static bool of_coupling_find_node(struct device_node *src,
struct device_node *to_find)
struct device_node *to_find,
int *index)
{
int n_phandles, i;
bool found = false;
@@ -499,8 +518,10 @@ static bool of_coupling_find_node(struct device_node *src,
of_node_put(tmp);
if (found)
if (found) {
*index = i;
break;
}
}
return found;
@@ -521,22 +542,23 @@ static bool of_coupling_find_node(struct device_node *src,
*/
bool of_check_coupling_data(struct regulator_dev *rdev)
{
int max_spread = rdev->constraints->max_spread;
struct device_node *node = rdev->dev.of_node;
int n_phandles = of_get_n_coupled(rdev);
struct device_node *c_node;
int index;
int i;
bool ret = true;
if (max_spread <= 0) {
dev_err(&rdev->dev, "max_spread value invalid\n");
return false;
}
/* iterate over rdev's phandles */
for (i = 0; i < n_phandles; i++) {
int max_spread = rdev->constraints->max_spread[i];
int c_max_spread, c_n_phandles;
if (max_spread <= 0) {
dev_err(&rdev->dev, "max_spread value invalid\n");
return false;
}
c_node = of_parse_phandle(node,
"regulator-coupled-with", i);
@@ -553,8 +575,14 @@ bool of_check_coupling_data(struct regulator_dev *rdev)
goto clean;
}
if (of_property_read_u32(c_node, "regulator-coupled-max-spread",
&c_max_spread)) {
if (!of_coupling_find_node(c_node, node, &index)) {
dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
ret = false;
goto clean;
}
if (of_property_read_u32_index(c_node, "regulator-coupled-max-spread",
index, &c_max_spread)) {
ret = false;
goto clean;
}
@@ -566,11 +594,6 @@ bool of_check_coupling_data(struct regulator_dev *rdev)
goto clean;
}
if (!of_coupling_find_node(c_node, node)) {
dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
ret = false;
}
clean:
of_node_put(c_node);
if (!ret)