From patchwork Mon May 26 14:58:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris BREZILLON X-Patchwork-Id: 4243131 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D71889F1E7 for ; Mon, 26 May 2014 15:02:50 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3D183201FA for ; Mon, 26 May 2014 15:02:47 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8B7EB2017D for ; Mon, 26 May 2014 15:02:43 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WowO4-0004cG-Tx; Mon, 26 May 2014 15:00:28 +0000 Received: from top.free-electrons.com ([176.31.233.9] helo=mail.free-electrons.com) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WowMz-0002uu-Ln for linux-arm-kernel@lists.infradead.org; Mon, 26 May 2014 14:59:22 +0000 Received: by mail.free-electrons.com (Postfix, from userid 106) id 7300FF6E; Mon, 26 May 2014 16:58:41 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from localhost.localdomain (col31-4-88-188-83-94.fbx.proxad.net [88.188.83.94]) by mail.free-electrons.com (Postfix) with ESMTPSA id A334D6E4; Mon, 26 May 2014 16:58:40 +0200 (CEST) From: Boris BREZILLON To: Samuel Ortiz , Lee Jones , Liam Girdwood , Mark Brown Subject: [PATCH v2 5/5] regulator: axp20x: resolve self dependency issue Date: Mon, 26 May 2014 16:58:12 +0200 Message-Id: <1401116292-24066-6-git-send-email-boris.brezillon@free-electrons.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1401116292-24066-1-git-send-email-boris.brezillon@free-electrons.com> References: <1401116292-24066-1-git-send-email-boris.brezillon@free-electrons.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140526_075922_030258_0D131A07 X-CRM114-Status: GOOD ( 18.22 ) X-Spam-Score: 0.3 (/) Cc: Boris BREZILLON , dev@linux-sunxi.org, linux-kernel@vger.kernel.org, Shuge , Carlo Caione , Maxime Ripard , kevin@allwinnertech.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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, ®ulators[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, + ®ulators[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; }