From patchwork Sat Apr 23 07:11:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pingbo Wen X-Patchwork-Id: 66515 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp54596qge; Sat, 23 Apr 2016 00:11:56 -0700 (PDT) X-Received: by 10.98.76.216 with SMTP id e85mr34186171pfj.121.1461395516874; Sat, 23 Apr 2016 00:11:56 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id kg11si12497267pab.171.2016.04.23.00.11.56; Sat, 23 Apr 2016 00:11:56 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751884AbcDWHLo (ORCPT + 29 others); Sat, 23 Apr 2016 03:11:44 -0400 Received: from mail-pf0-f181.google.com ([209.85.192.181]:34297 "EHLO mail-pf0-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751363AbcDWHLl (ORCPT ); Sat, 23 Apr 2016 03:11:41 -0400 Received: by mail-pf0-f181.google.com with SMTP id y69so29292749pfb.1 for ; Sat, 23 Apr 2016 00:11:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=0X1zh9kRWRBrxAl9NVCcQj5qFdKYNjHorO/TtbtrbIQ=; b=VWXrkiSQhYD04M3d753X19xlox6TVYi+Qisa7a7NbcZ0/d7/utY0uJsx0YPVP0zVbp O7cyW2y98Po09T2fzIZRP33g5n8tDuAnIpEl0TKRRwE7BnH9oSjtkIGUlXNE+bX67Ztc Xqig2yvxVts1AXgtNhks0eBL7LdVHu513vtOI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=0X1zh9kRWRBrxAl9NVCcQj5qFdKYNjHorO/TtbtrbIQ=; b=I9v4Kb4KYobrh6Z1QrXj4f+1qYa1Dr+r8m99g/URMffw7OG7ERIT4TazjI/ZqAkXE2 EbcRDcyMF9rvf+hbTPNn6W1CdhX5+1+2mqUACE3I78/6ogVNugIAIxHtQiQp9knD1BWd Kt92NJLSbQX3J4idzSpZSZbUlmbvse0FE3xnSuNjAJu2/A5ij0kD0iWcNSzXi0G9JCDA vDujz332qRKiSKsqDkwLkmx0czh55M4BsG2Q1F3dPweVFrpez0gBH84Aht//XX2kAFMU lKQCBnhxV8ZpSsycQW+B03fuBDLdwt7J0hBWGWxYg9mriJUsoST5w3mk5cf/2T3pS63O W9Dw== X-Gm-Message-State: AOPr4FUx+IxpbptaROpbjZfSRnMrlXHv3kcBnWWCgqv0+DQ/bi5+QejhxqBimMAP/sCYFNOs X-Received: by 10.98.10.202 with SMTP id 71mr22743236pfk.143.1461395500467; Sat, 23 Apr 2016 00:11:40 -0700 (PDT) Received: from localhost.localdomain ([103.26.122.10]) by smtp.gmail.com with ESMTPSA id b140sm12865434pfb.19.2016.04.23.00.11.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 23 Apr 2016 00:11:39 -0700 (PDT) From: WEN Pingbo To: linux-kernel@vger.kernel.org Cc: broonie@kernel.org, lgirdwood@gmail.com, vincent.guittot@linaro.org, stephen.boyd@linaro.org, WEN Pingbo Subject: [RFC PATCH 2/2] regulator: add boot protection flag Date: Sat, 23 Apr 2016 15:11:06 +0800 Message-Id: <1461395466-14896-2-git-send-email-pingbo.wen@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1461395466-14896-1-git-send-email-pingbo.wen@linaro.org> References: <1461395466-14896-1-git-send-email-pingbo.wen@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In some platform, some critical shared regulator is initialized before kernel loading. But in kernel booting, the driver probing order and conflict operation from other regulator consumer, may set the regulator in a undefined state, which will cause serious problem. This patch try to add a boot_protection flag in regulator constraints. So the regulator core will prevent the specified operation during kernel booting. The boot_protection flag only work before late_initicall. And as other constraints liked, you can specify this flag in a board file, or in dts file. By default, all operations of this regulator will be rejected during kernel booting, if you add this flag in a regulator. But you still have a chance to change this, by modifying boot_valid_ops_mask. [ This patch depends on regulator_ops_is_valid patch. And some document need to add, but I want to hear some voice first. ] Signed-off-by: WEN Pingbo --- drivers/regulator/core.c | 24 +++++++++++++++++++++--- drivers/regulator/of_regulator.c | 29 +++++++++++++++++++++++++++++ include/linux/regulator/machine.h | 2 ++ 3 files changed, 52 insertions(+), 3 deletions(-) -- 1.9.1 diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fe47d38..5b9dc22 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -55,6 +55,7 @@ static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); static bool has_full_constraints; +static bool regulator_has_booted; static struct dentry *debugfs_root; @@ -139,7 +140,15 @@ static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) return false; } - if (rdev->constraints->valid_ops_mask & ops) + /* + * Ignore regulator boot-protection, after later_initcall. + */ + if (!regulator_has_booted && rdev->constraints->boot_protection) { + if (rdev->constraints->boot_valid_ops_mask & ops) + return true; + else + rdev_info(rdev, "rejected operation 0x%02x\n", ops); + } else if (rdev->constraints->valid_ops_mask & ops) return true; return false; @@ -868,7 +877,7 @@ static void print_constraints(struct regulator_dev *rdev) rdev_dbg(rdev, "%s\n", buf); if ((constraints->min_uV != constraints->max_uV) && - !regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) + !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) rdev_warn(rdev, "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); } @@ -1309,7 +1318,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, * it is then we don't need to do nearly so much work for * enable/disable calls. */ - if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS) && + if (rdev->constraints && + !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) && _regulator_is_enabled(rdev)) regulator->always_on = true; @@ -4353,6 +4363,12 @@ static int __init regulator_late_cleanup(struct device *dev, void *data) struct regulation_constraints *c = rdev->constraints; int enabled, ret; + /* + * The kernel boot is finished, let's unset boot_protection + * Need a lock? + */ + c->boot_protection = 0; + if (c && c->always_on) return 0; @@ -4406,6 +4422,8 @@ static int __init regulator_init_complete(void) if (of_have_populated_dt()) has_full_constraints = true; + regulator_has_booted = true; + /* If we have a full configuration then disable any regulators * we have permission to change the status for and which are * not in use or always_on. This is effectively the default diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 6b0aa80..bfec59c 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -78,6 +78,35 @@ static void of_get_regulation_constraints(struct device_node *np, if (of_property_read_bool(np, "regulator-allow-set-load")) constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS; + constraints->boot_protection = of_property_read_bool(np, + "regulator-boot-protection"); + + if (constraints->boot_protection) { + if (of_property_read_bool(np, "boot-allow-set-voltage")) + constraints->boot_valid_ops_mask |= + REGULATOR_CHANGE_VOLTAGE; + if (of_property_read_bool(np, "boot-allow-set-current")) + constraints->boot_valid_ops_mask |= + REGULATOR_CHANGE_CURRENT; + if (of_property_read_bool(np, "boot-allow-set-mode")) + constraints->boot_valid_ops_mask |= + REGULATOR_CHANGE_MODE; + if (of_property_read_bool(np, "boot-allow-set-status")) + constraints->boot_valid_ops_mask |= + REGULATOR_CHANGE_STATUS; + if (of_property_read_bool(np, "boot-allow-set-load")) + constraints->boot_valid_ops_mask |= + REGULATOR_CHANGE_DRMS; + if (of_property_read_bool(np, "boot-allow-bypass")) + constraints->boot_valid_ops_mask |= + REGULATOR_CHANGE_BYPASS; + + /* + * boot_valid_ops_mask is a subset of valid_ops_mask + */ + constraints->boot_valid_ops_mask &= constraints->valid_ops_mask; + } + ret = of_property_read_u32(np, "regulator-ramp-delay", &pval); if (!ret) { if (pval) diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 5d627c8..a4f5c0f 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -134,6 +134,7 @@ struct regulation_constraints { /* valid operations for regulator on this machine */ unsigned int valid_ops_mask; + unsigned int boot_valid_ops_mask; /* regulator input voltage - only if supply is another regulator */ int input_uV; @@ -155,6 +156,7 @@ struct regulation_constraints { /* constraint flags */ unsigned always_on:1; /* regulator never off when system is on */ unsigned boot_on:1; /* bootloader/firmware enabled regulator */ + unsigned boot_protection:1; unsigned apply_uV:1; /* apply uV constraint if min == max */ unsigned ramp_disable:1; /* disable ramp delay */ unsigned soft_start:1; /* ramp voltage slowly */