Skip to content

Commit

Permalink
regulator: axp20x: resolve self dependency issue
Browse files Browse the repository at this point in the history
Some regulators might take their power supply from other regulators defined
by the same PMIC.

Retry regulators registration until all regulators are registered or the
last iteration didn't manage to register any new regulator (which means
there's an external dependency missing and we can thus return
EPROBE_DEFER).

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
  • Loading branch information
Boris BREZILLON authored and jwrdegoede committed Jun 13, 2014
1 parent b877c66 commit ecc8b97
Showing 1 changed file with 58 additions and 17 deletions.
75 changes: 58 additions & 17 deletions drivers/regulator/axp20x-regulator.c
Expand Up @@ -147,6 +147,8 @@ static const struct regulator_desc axp20x_regulators[] = {
AXP20X_IO_DISABLED),
};

static bool axp20x_registered_regulators[AXP20X_REG_ID_MAX];

static const struct regulator_desc axp22x_regulators[] = {
AXP_DESC(AXP22X, DCDC1, "vin1", 1600, 3400, 100, AXP22X_DCDC1_V_OUT, 0x1f,
AXP22X_PWR_OUT_CTRL1, BIT(1)),
Expand Down Expand Up @@ -189,6 +191,8 @@ static const struct regulator_desc axp22x_regulators[] = {
AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtcldoin", 3000),
};

static bool axp22x_registered_regulators[AXP22X_REG_ID_MAX];

#define AXP_MATCH(_family, _name, _id) \
[_family##_##_id] = { \
.name = #_name, \
Expand Down Expand Up @@ -309,6 +313,9 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
int nmatches;
const struct regulator_desc *regulators;
int nregulators;
bool *registered;
int nregistered = 0;
int prev_nregistered = -1;
int ret, i;
u32 workmode;

Expand All @@ -321,11 +328,13 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
nmatches = ARRAY_SIZE(axp22x_matches);
regulators = axp22x_regulators;
nregulators = AXP22X_REG_ID_MAX;
registered = axp22x_registered_regulators;
} else {
matches = axp20x_matches;
nmatches = ARRAY_SIZE(axp20x_matches);
regulators = axp20x_regulators;
nregulators = AXP20X_REG_ID_MAX;
registered = axp20x_registered_regulators;
}

/*
Expand All @@ -337,36 +346,68 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
matches[i].of_node = NULL;
}

/*
* Reset registered status table (this table might have been modified
* by a previous AXP2xx device probe).
*/
memset(registered, 0, nregulators * sizeof(*registered));

ret = axp20x_regulator_parse_dt(pdev, matches, nmatches);
if (ret)
return ret;

for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
init_data = matches[i].init_data;
/*
* Some regulators might take their power supply from other regulators
* defined by the same PMIC.
*
* Retry regulators registration until all regulators are registered
* or the last iteration didn't manage to register any new regulator
* (which means there's an external dependency missing and we can thus
* return EPROBE_DEFER).
*/
while (nregistered < nregulators &&
prev_nregistered < nregistered) {

config.dev = &pdev->dev;
config.init_data = init_data;
config.regmap = axp20x->regmap;
config.of_node = matches[i].of_node;
prev_nregistered = nregistered;

rdev = devm_regulator_register(&pdev->dev, &regulators[i],
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "Failed to register %s\n",
for (i = 0; i < nregulators; i++) {
if (registered[i])
continue;

init_data = matches[i].init_data;

config.dev = &pdev->dev;
config.init_data = init_data;
config.regmap = axp20x->regmap;
config.of_node = matches[i].of_node;

rdev = devm_regulator_register(&pdev->dev,
&regulators[i],
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "Failed to register %s\n",
regulators[i].name);

return PTR_ERR(rdev);
}
return PTR_ERR(rdev);
}

ret = of_property_read_u32(matches[i].of_node, "x-powers,dcdc-workmode",
&workmode);
if (!ret) {
if (axp20x_set_dcdc_workmode(rdev, i, workmode))
dev_err(&pdev->dev, "Failed to set workmode on %s\n",
ret = of_property_read_u32(matches[i].of_node,
"x-powers,dcdc-workmode",
&workmode);
if (!ret &&
axp20x_set_dcdc_workmode(rdev, i, workmode))
dev_err(&pdev->dev,
"Failed to set workmode on %s\n",
regulators[i].name);

registered[i] = true;
nregistered++;
}
}

if (nregistered < nregulators)
return -EPROBE_DEFER;

return 0;
}

Expand Down

0 comments on commit ecc8b97

Please sign in to comment.