lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1401116292-24066-6-git-send-email-boris.brezillon@free-electrons.com>
Date:	Mon, 26 May 2014 16:58:12 +0200
From:	Boris BREZILLON <boris.brezillon@...e-electrons.com>
To:	Samuel Ortiz <sameo@...ux.intel.com>,
	Lee Jones <lee.jones@...aro.org>,
	Liam Girdwood <lgirdwood@...il.com>,
	Mark Brown <broonie@...nel.org>
Cc:	Maxime Ripard <maxime.ripard@...e-electrons.com>,
	Carlo Caione <carlo@...one.org>,
	Shuge <shuge@...winnertech.com>, kevin@...winnertech.com,
	linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
	dev@...ux-sunxi.org,
	Boris BREZILLON <boris.brezillon@...e-electrons.com>
Subject: [PATCH v2 5/5] regulator: axp20x: resolve self dependency issue

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@...e-electrons.com>
---
 drivers/regulator/axp20x-regulator.c | 75 ++++++++++++++++++++++++++++--------
 1 file changed, 58 insertions(+), 17 deletions(-)

diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 4486517..c5b665e 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -146,6 +146,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)),
@@ -188,6 +190,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, \
@@ -308,6 +312,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;
 
@@ -316,11 +323,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;
 	}
 
 	/*
@@ -332,36 +341,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;
 }
 
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ