Received: by 10.223.164.221 with SMTP id h29csp2789680wrb; Wed, 18 Oct 2017 07:02:29 -0700 (PDT) X-Google-Smtp-Source: AOwi7QDpv4NlmI/bBvpb+KJKtIMVeBmLL0wwcmf19zayT9VTPXCNy/PP1PuWduJW5nH7MFv57jk9 X-Received: by 10.98.56.18 with SMTP id f18mr14582884pfa.81.1508335349590; Wed, 18 Oct 2017 07:02:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1508335349; cv=none; d=google.com; s=arc-20160816; b=Vf5oH7k8L1jFpO3DpAPdu4DU8UvINzck7VUUiFxT6akOtgYWjX5FxBjsaNA8FLxzEk ynnH0kzzvl9mP+B9UMiL5t22YdpIwT2tchAaXhUFppsqoc0AQ+Ff9d1dkyHDcq0kr8YD VvSw9K/lR0oUE469IrYRWtLIC0z7VrMm09MtcrpcMA2dzUndVWnZC/PPSvCidWf/mvV+ UmTb49tBH1LzaunTufDwZINRZkw0qojmTtadj/QFEuAhQn4DSr+oRv3gZCKSfoXiMwzy AV+GbSfRxyxCX48PJO4kBCM+OmSPpZNNUO7gQqat9t9N0yivNEscsGXzyfvFtSXLNRVp ATdQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:cms-type:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=wHoFQctuHYme2FH1vWj2dqb+g+CPzdY0BW7jvd1jM78=; b=QB15eDmrhqRKqVzQ4rQMeDhReKPgjEArPBV+5b1MhD3cM4QzrOgV9tqqqzDpcO8W+o pkZtuuEPIj5W4BfKCrZaELZT9LVuvEIe+WvXVwWcgdLLo9Ybdml4Vg9pMRUWfnUddh4V USsyOv6ObL+WlvftulEIIe2TCzQPXJ/+3ILnv7Xwi8u0C081emQCNLQ5fZUeERcMhLsL w6JLpXUs90p/9ETBWwEcfO/L7F6n8jnHZzA8nyMufz6YLwlRHrlH2Z06z+lqqmEg+D0Z 2s0FIQMXuyBt17kPDNbGMhVLmbTqXCcMU8mbpfC3T/v/pP1UDSRHBdO8S+fn51Lv0gVx IG9Q== ARC-Authentication-Results: i=1; mx.google.com; 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=fail (p=NONE sp=NONE dis=NONE) header.from=samsung.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a6si6970539pgu.549.2017.10.18.07.02.14; Wed, 18 Oct 2017 07:02:29 -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; 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=fail (p=NONE sp=NONE dis=NONE) header.from=samsung.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965608AbdJRMrn (ORCPT + 99 others); Wed, 18 Oct 2017 08:47:43 -0400 Received: from mailout1.w1.samsung.com ([210.118.77.11]:37197 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756408AbdJRMrj (ORCPT ); Wed, 18 Oct 2017 08:47:39 -0400 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20171018124736euoutp01909b08c22a65b230cbc602de3b689ec0~uquw0CMwv2875928759euoutp01a; Wed, 18 Oct 2017 12:47:36 +0000 (GMT) Received: from eusmges1.samsung.com (unknown [203.254.199.239]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20171018124735eucas1p23e36dc99b8ff97623d09c864fce0ceaa~uquwJzAGx3028030280eucas1p2L; Wed, 18 Oct 2017 12:47:35 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges1.samsung.com (EUCPMTA) with SMTP id 8C.B7.12576.76D47E95; Wed, 18 Oct 2017 13:47:35 +0100 (BST) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20171018124735eucas1p2dc60191fb185f18dee16d4b3de8502cf~uquvZlkuY0255902559eucas1p2D; Wed, 18 Oct 2017 12:47:35 +0000 (GMT) X-AuditID: cbfec7ef-f79ee6d000003120-68-59e74d67a87b Received: from eusync3.samsung.com ( [203.254.199.213]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id 03.8D.18832.76D47E95; Wed, 18 Oct 2017 13:47:35 +0100 (BST) Received: from AMDC2075.DIGITAL.local ([106.120.51.25]) by eusync3.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OY000ISARIUEL70@eusync3.samsung.com>; Wed, 18 Oct 2017 13:47:35 +0100 (BST) From: Maciej Purski To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: Mark Brown , Liam Girdwood , Rob Herring , Mark Rutland , Marek Szyprowski , Bartlomiej Zolnierkiewicz , Maciej Purski Subject: [RFC PATCH v2 2/3] regulator: core: Parse coupled regulators properties Date: Wed, 18 Oct 2017 14:47:01 +0200 Message-id: <1508330822-8039-3-git-send-email-m.purski@samsung.com> X-Mailer: git-send-email 2.7.4 In-reply-to: <1508330822-8039-1-git-send-email-m.purski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrGIsWRmVeSWpSXmKPExsWy7djP87rpvs8jDSZNVLbYOGM9q8XUh0/Y LOYfOcdq8e1KB5PF5V1z2CwWvLzFYrH2yF12i6XXLzJZtO49wu7A6bFm3hpGj52z7rJ7bFrV yebRt2UVo8fnTXIBrFFcNimpOZllqUX6dglcGQenbmQueOtScWvONdYGxgPmXYycHBICJhIN C86zQthiEhfurWcDsYUEljFKTLmj18XIBWR/ZpS4uP81E0zDh+nrmSESQEULnyxngXD+M0r8 +/EKaBQHB5uAlsSa9niQBhEBG4m3Nw4wgtQwC8xjkph6dBIzSEJYIEjiylOQZk4OFgFViXNf PzGC2LwCzhJP929gg9gmJ3HzXCdYPaeAi8SlDc+ZQAZJCCxhk/j3+wAjRJGLRNPLhewQtrDE q+NboGwZic6Og1BnV0tc/LoLamiNROPtDVA11hKfJ20BW8AswCcxadt0ZpAHJAR4JTrahCBM D4kpvxMgqh0lri3sYYL4dzqjxPHZf5kmMEovYGRYxSiSWlqcm55abKhXnJhbXJqXrpecn7uJ ERi7p/8df7+D8WlzyCFGAQ5GJR7eAJVnkUKsiWXFlbmHGCU4mJVEeGNdnkcK8aYkVlalFuXH F5XmpBYfYpTmYFES57WNaosUEkhPLEnNTk0tSC2CyTJxcEo1MHp8WfE4oWtCRdKVbZWdnZ3v ZPo/Symfs49rqg2Y9tJvxYP0ZYvOy6tmhCyTW3lxyWmZ6rc27+RusZ86mx4bG+zNMLO00Dxz 9SKGaHGL9w/fVChHfFYoSpvF21MsrOzuXaYsfvXjqZcLOY17XtTmecfPVm6/lpFbWJzBuHSr wZymxQeeZ+24q8RSnJFoqMVcVJwIALRmoHzZAgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprLLMWRmVeSWpSXmKPExsVy+t/xq7rpvs8jDT4s4LDYOGM9q8XUh0/Y LOYfOcdq8e1KB5PF5V1z2CwWvLzFYrH2yF12i6XXLzJZtO49wu7A6bFm3hpGj52z7rJ7bFrV yebRt2UVo8fnTXIBrFFcNimpOZllqUX6dglcGQenbmQueOtScWvONdYGxgPmXYycHBICJhIf pq9nhrDFJC7cW8/WxcjFISSwhFHi8+y3jBBOI5PEp5cPWbsYOTjYBLQk1rTHgzSICNhIvL1x AKyGWWABk8S0rzPAJgkLBEicX7CWFcRmEVCVOPf1EyOIzSvgLPF0/wY2iG1yEjfPdYLVcwq4 SFza8JwJxBYCqjna94ltAiPvAkaGVYwiqaXFuem5xYZ6xYm5xaV56XrJ+bmbGIGBtu3Yz807 GC9tDD7EKMDBqMTDG6DyLFKINbGsuDL3EKMEB7OSCG+sy/NIId6UxMqq1KL8+KLSnNTiQ4zS HCxK4ry9e1ZHCgmkJ5akZqemFqQWwWSZODilGhjDao5k/X5Xylj+LmKH8M2OaaFPPh33WGv0 4DI/7xVtJwn+FtXy02fchY+1nv0wMepxhn/ZJ+kpvxdfNc9ocfp169qThUH38tZsLpcW/q12 3zTcUtDw1Zq+mrDW3g3ThGYn37FKd4nkiorSq52hHhfTcnJ3UsAd9Rfpe2r2BZzUeNF03qpz w1clluKMREMt5qLiRAD/JBA8MAIAAA== X-CMS-MailID: 20171018124735eucas1p2dc60191fb185f18dee16d4b3de8502cf X-Msg-Generator: CA X-Sender-IP: 182.198.249.179 X-Local-Sender: =?UTF-8?B?TWFjaWVqIFB1cnNraRtTZWN1cml0eSAoVFApG1NhbXN1bmcg?= =?UTF-8?B?RWxlY3Ryb25pY3MbVHJhaW5lZSAoKQ==?= X-Global-Sender: =?UTF-8?B?TWFjaWVqIFB1cnNraRtTZWN1cml0eSAoVFApG1NhbXN1bmcg?= =?UTF-8?B?RWxlY3Ryb25pY3MbVHJhaW5lZSAoKQ==?= X-Sender-Code: =?UTF-8?B?QzEwG0VIURtDMTBDRDAyQ0QwMjczOTU=?= CMS-TYPE: 201P X-CMS-RootMailID: 20171018124735eucas1p2dc60191fb185f18dee16d4b3de8502cf X-RootMTR: 20171018124735eucas1p2dc60191fb185f18dee16d4b3de8502cf References: <1508330822-8039-1-git-send-email-m.purski@samsung.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Odroid XU3/4 and other Exynos5422 based boards there is a case, that different devices on the board are supplied by different regulators with non-fixed voltages. If one of these devices temporarily requires higher voltage, there might occur a situation that the spread between devices' voltages is so high, that there is a risk of changing 'high' and 'low' states on the interconnection between devices powered by those regulators. Each coupled regulator, should have phandles to every other in their DTS. All coupled regulators must share common structure coupled_reg_desc, which contains information obtained from the device tree: array of pointers to other coupled regulators, maximum allowed voltage spread and number of coupled regulators, which can't be higher than defined MAX_COUPLED. Read all the necessary data from DTS in regulator_resolve_coupling(), which can succeed only if all the coupled regulators are already initialized, so it should be done only once per coupled regulators group by the last regulator initialized. Check if coupled regulators phandles arrays match for all coupled regulators and if their max_spread values are the same. Signed-off-by: Maciej Purski --- drivers/regulator/core.c | 195 +++++++++++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 17 ++++ 2 files changed, 212 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e567fa5..a6cf902 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3953,6 +3953,198 @@ static int regulator_register_resolve_supply(struct device *dev, void *data) return 0; } +/* Function returns regulator coupled with the given regulator_dev */ +static struct regulator_dev *parse_coupled_regulator(struct regulator_dev *rdev, + int index) +{ + struct device_node *node = rdev->dev.of_node; + struct device_node *c_node; + struct regulator_dev *c_rdev; + + c_node = of_parse_phandle(node, "regulator-coupled-with", index); + if (!c_node) + return NULL; + + c_rdev = of_find_regulator_by_node(c_node); + if (!c_rdev) + return NULL; + + return c_rdev; +} + +static int check_coupled_regulators_array(struct coupled_reg_desc *c_desc, + int index) +{ + struct regulator_dev *rdev = c_desc->coupled_rdevs[index]; + struct regulator_dev **rdevs = c_desc->coupled_rdevs; + struct regulator_dev *c_rdev, *tmp_rdev; + struct device_node *node = rdev->dev.of_node; + int n_coupled = c_desc->n_coupled; + int i, j; + + /* Different number of regulators coupled */ + if (of_count_phandle_with_args(node, "regulator-coupled-with", 0) != + (n_coupled - 1)) + return -1; + + /* Check if coupled regulators array match */ + for (i = 0; i < n_coupled; i++) { + c_rdev = rdevs[i]; + /* Don't look for rdev in rdev's phandles array */ + if (c_rdev == rdev) + continue; + + /* Look for c_rdev phandle */ + for (j = 0; j < n_coupled; j++) { + tmp_rdev = parse_coupled_regulator(rdev, j); + if (!tmp_rdev) + return -1; + + /* Regulator found */ + if (tmp_rdev == c_rdev) + break; + } + + /* Regulator can't be found */ + if (j == n_coupled && tmp_rdev != c_rdev) + return -1; + } + + return 0; +} + +static int check_coupled_regulator_constraints(struct coupled_reg_desc *c_desc, + int index) +{ + int c_max_spread; + struct regulator_dev *rdev = c_desc->coupled_rdevs[index]; + struct device_node *node = rdev->dev.of_node; + + if (of_property_read_u32(node, "regulator-couple-max-spread", + &c_max_spread)) + return -1; + + /* Max_spread value different than in coupled regulator or wrong */ + if (c_max_spread < 0 || c_desc->max_spread != c_max_spread) + return -1; + + return 0; +} + +static int check_coupled_regulator_ops(struct coupled_reg_desc *c_desc, + int index) +{ + struct regulator_dev *rdev = c_desc->coupled_rdevs[index]; + + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) + return -1; + + if (!rdev->desc->ops->set_voltage && + !rdev->desc->ops->set_voltage_sel) + return -1; + return 0; +} + +static void regulator_resolve_coupling(struct regulator_dev *rdev) +{ + struct coupled_reg_desc *c_desc; + struct device_node *node = rdev->dev.of_node; + struct regulator_dev *c_rdev = NULL; + int max_spread, n_phandles, i; + + c_desc = kzalloc(sizeof(*c_desc), GFP_KERNEL); + if (!c_desc) + return; + + n_phandles = of_count_phandle_with_args(node, "regulator-coupled-with", + 0); + if (n_phandles <= 0 || n_phandles >= MAX_COUPLED) + goto err; + + c_desc->n_coupled = n_phandles + 1; + + if (of_property_read_u32(node, "regulator-coupled-max-spread", + &max_spread)) { + rdev_err(rdev, "can't read max_spread for coupled regulator\n"); + goto err; + } + + c_desc->max_spread = max_spread; + + /* + * Fill rdevs array with pointers to regulators parsed from + * device tree + */ + c_desc->coupled_rdevs[0] = rdev; + for (i = 0; i < n_phandles; i++) { + c_rdev = parse_coupled_regulator(rdev, i); + if (!c_rdev) { + rdev_err(rdev, "can't parse coupled regulators array\n"); + goto err; + } + c_desc->coupled_rdevs[i + 1] = c_rdev; + } + + /* + * Each coupled regulator must have phandles to all regulators + * they are coupled with. This should be checked by comparing + * rdevs array with phandles array of each regulator. + * There's no need for checking rdevs[0] as its device_node + * was a source to fill rdevs array. + */ + for (i = 0; i < n_phandles; i++) { + if (check_coupled_regulators_array(c_desc, i + 1)) { + rdev_err(rdev, + "coupled regulators arrays don't match\n"); + goto err; + } + } + + for (i = 0; i < c_desc->n_coupled; i++) { + /* + * All coupled regulators need to have + * regulator-couple-max-spread property with + * the same value. + */ + if (check_coupled_regulator_constraints(c_desc, i)) { + rdev_err(rdev, "coupled regulators max_spread wrong\n"); + goto err; + } + + /* + * Regulators which can't change their voltage can't be + * coupled. + */ + if (check_coupled_regulator_ops(c_desc, i)) { + rdev_err(rdev, "coupled regulators ops not valid\n"); + goto err; + } + } + + for (i = 0; i < c_desc->n_coupled; i++) + c_desc->coupled_rdevs[i]->coupled_desc = c_desc; + + return; +err: + kfree(c_desc); +} + +static void regulator_clean_coupling(struct regulator_dev *rdev) +{ + struct regulator_dev *c_rdevs[MAX_COUPLED]; + struct coupled_reg_desc *c_desc; + int i; + + if (!rdev->coupled_desc) + return; + + c_desc = rdev->coupled_desc; + for (i = 0; i < c_desc->n_coupled; i++) + c_rdevs[0]->coupled_desc = NULL; + + kfree(c_desc); +} + /** * regulator_register - register regulator * @regulator_desc: regulator to register @@ -4116,6 +4308,8 @@ regulator_register(const struct regulator_desc *regulator_desc, dev_set_drvdata(&rdev->dev, rdev); rdev_init_debugfs(rdev); + regulator_resolve_coupling(rdev); + /* try to resolve regulators supply since a new one was registered */ class_for_each_device(®ulator_class, NULL, NULL, regulator_register_resolve_supply); @@ -4129,6 +4323,7 @@ regulator_register(const struct regulator_desc *regulator_desc, wash: kfree(rdev->constraints); mutex_lock(®ulator_list_mutex); + regulator_clean_coupling(rdev); regulator_ena_gpio_free(rdev); mutex_unlock(®ulator_list_mutex); clean: diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 94417b4..8ca3215 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -15,6 +15,8 @@ #ifndef __LINUX_REGULATOR_DRIVER_H_ #define __LINUX_REGULATOR_DRIVER_H_ +#define MAX_COUPLED 10 + #include #include #include @@ -402,6 +404,19 @@ struct regulator_config { }; /* + * struct coupled_reg_desc + * + * Describes coupling of regulators. Each coupled regulator + * contains a pointer to that structure. If the regulator is not + * coupled with any other, it should remain NULL. + */ +struct coupled_reg_desc { + struct regulator_dev *coupled_rdevs[MAX_COUPLED]; + int max_spread; + int n_coupled; +}; + +/* * struct regulator_dev * * Voltage / Current regulator class device. One for each @@ -424,6 +439,8 @@ struct regulator_dev { /* lists we own */ struct list_head consumer_list; /* consumers we supply */ + struct coupled_reg_desc *coupled_desc; + struct blocking_notifier_head notifier; struct mutex mutex; /* consumer lock */ struct module *owner; -- 2.7.4 From 1585425813298757890@xxx Wed Nov 29 18:24:38 +0000 2017 X-GM-THRID: 1585422347612228585 X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread