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:

committed by
Mark Brown

parent
a188339ca5
commit
d8ca7d184b
@@ -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)
|
||||
|
Reference in New Issue
Block a user