platform-driver-x86.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Daniel Scally <djrscally@gmail.com>
To: linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org
Cc: hdegoede@redhat.com, mgross@linux.intel.com,
	luzmaximilian@gmail.com, lgirdwood@gmail.com, broonie@kernel.org,
	andy.shevchenko@gmail.com, laurent.pinchart@ideasonboard.com,
	kieran.bingham@ideasonboard.com
Subject: [RFC PATCH 1/2] regulator: Add support for software node connections
Date: Thu,  8 Jul 2021 23:42:25 +0100	[thread overview]
Message-ID: <20210708224226.457224-2-djrscally@gmail.com> (raw)
In-Reply-To: <20210708224226.457224-1-djrscally@gmail.com>

On some x86 platforms, firmware provided by the OEM does not adequately
describe the constraints of regulator resources nor their connections to
consuming devices via ACPI. To compensate, extend the regulator framework
to allow discovery of constraints and supply-consumer relationships via
software node references and properties. This will allow us to define
those platform specific connections so that the resources can be used in
the usual way.

Signed-off-by: Daniel Scally <djrscally@gmail.com>
---

swnode_get_regulator_constraints() here is not as extensive as the equivalent
function in of_regulator...I could include all that now, but it didn't seem
worth it so we don't know what any of those values should be.

 drivers/regulator/Kconfig                  |   6 ++
 drivers/regulator/Makefile                 |   1 +
 drivers/regulator/core.c                   |  23 +++++
 drivers/regulator/swnode_regulator.c       | 111 +++++++++++++++++++++
 include/linux/regulator/swnode_regulator.h |  33 ++++++
 5 files changed, 174 insertions(+)
 create mode 100644 drivers/regulator/swnode_regulator.c
 create mode 100644 include/linux/regulator/swnode_regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 9d84d9245490..7e0351f8fe38 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1171,6 +1171,12 @@ config REGULATOR_SY8827N
 	help
 	  This driver supports SY8827N single output regulator.
 
+config REGULATOR_SWNODE
+	bool "Software Node Regulator Support"
+	help
+	  This option configures support for providing regulator constraints and
+	  mappings to consumers through the use of software nodes.
+
 config REGULATOR_TPS51632
 	tristate "TI TPS51632 Power Regulator"
 	depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 580b015296ea..25cb7bbad652 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
+obj-$(CONFIG_REGULATOR_SWNODE) += swnode_regulator.o
 
 obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o
 obj-$(CONFIG_REGULATOR_88PM800) += 88pm800-regulator.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index f192bf19492e..6e10f511db80 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -20,11 +20,13 @@
 #include <linux/gpio/consumer.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
+#include <linux/property.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/coupler.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/swnode_regulator.h>
 #include <linux/module.h>
 
 #define CREATE_TRACE_POINTS
@@ -1763,6 +1765,7 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
 						  const char *supply)
 {
 	struct regulator_dev *r = NULL;
+	struct fwnode_handle *swnode;
 	struct device_node *node;
 	struct regulator_map *map;
 	const char *devname = NULL;
@@ -1785,6 +1788,22 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
 		}
 	}
 
+	/* next, try software nodes */
+	if (dev && dev->fwnode && is_software_node(dev->fwnode->secondary)) {
+		swnode = swnode_get_regulator_node(dev, supply);
+		if (!IS_ERR(swnode)) {
+			r = swnode_find_regulator_by_node(swnode);
+			if (r)
+				return r;
+
+			/*
+			 * We have a node, but there is no device.
+			 * assume it has not registered yet.
+			 */
+			return ERR_PTR(-EPROBE_DEFER);
+		}
+	}
+
 	/* if not found, try doing it non-dt way */
 	if (dev)
 		devname = dev_name(dev);
@@ -5242,6 +5261,10 @@ regulator_register(const struct regulator_desc *regulator_desc,
 	init_data = regulator_of_get_init_data(dev, regulator_desc, config,
 					       &rdev->dev.of_node);
 
+	if (!init_data)
+		init_data = regulator_swnode_get_init_data(dev, regulator_desc,
+							   config, &rdev->dev.fwnode);
+
 	/*
 	 * Sometimes not all resources are probed already so we need to take
 	 * that into account. This happens most the time if the ena_gpiod comes
diff --git a/drivers/regulator/swnode_regulator.c b/drivers/regulator/swnode_regulator.c
new file mode 100644
index 000000000000..75718de74366
--- /dev/null
+++ b/drivers/regulator/swnode_regulator.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/property.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include "internal.h"
+
+static struct fwnode_handle *
+regulator_swnode_get_init_node(struct fwnode_handle *fwnode,
+			       const struct regulator_desc *desc)
+{
+	const struct software_node *parent, *child;
+
+	parent = to_software_node(fwnode->secondary);
+
+	if (desc->regulators_node)
+		child = software_node_find_by_name(parent,
+						   desc->regulators_node);
+	else
+		child = software_node_find_by_name(parent, desc->name);
+
+	return software_node_fwnode(child);
+}
+
+static int swnode_get_regulator_constraints(struct fwnode_handle *swnode,
+					    struct regulator_init_data *init_data)
+{
+	struct regulation_constraints *constraints = &init_data->constraints;
+	u32 pval;
+	int ret;
+
+	ret = fwnode_property_read_string(swnode, "regulator-name", &constraints->name);
+	if (ret)
+		return ret;
+
+	if (!fwnode_property_read_u32(swnode, "regulator-min-microvolt", &pval))
+		constraints->min_uV = pval;
+
+	if (!fwnode_property_read_u32(swnode, "regulator-max-microvolt", &pval))
+		constraints->max_uV = pval;
+
+	/* Voltage change possible? */
+	if (constraints->min_uV != constraints->max_uV)
+		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
+
+	/* Do we have a voltage range, if so try to apply it? */
+	if (constraints->min_uV && constraints->max_uV)
+		constraints->apply_uV = true;
+
+	constraints->boot_on = fwnode_property_read_bool(swnode, "regulator-boot-on");
+	constraints->always_on = fwnode_property_read_bool(swnode, "regulator-always-on");
+	if (!constraints->always_on) /* status change should be possible. */
+		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+
+	return 0;
+}
+
+struct regulator_init_data *
+regulator_swnode_get_init_data(struct device *dev,
+			       const struct regulator_desc *desc,
+			       struct regulator_config *config,
+			       struct fwnode_handle **regnode)
+{
+	struct fwnode_handle *fwnode = dev_fwnode(dev);
+	struct regulator_init_data *init_data;
+	struct fwnode_handle *regulator;
+	int ret;
+
+	if (!fwnode || !is_software_node(fwnode->secondary))
+		return NULL;
+
+	regulator = regulator_swnode_get_init_node(fwnode, desc);
+	if (!regulator)
+		return NULL;
+
+	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
+	if (!init_data)
+		return ERR_PTR(-ENOMEM);
+
+	ret = swnode_get_regulator_constraints(regulator, init_data);
+	if (ret)
+		return ERR_PTR(ret);
+
+	*regnode = regulator;
+
+	return init_data;
+}
+
+struct regulator_dev *
+swnode_find_regulator_by_node(struct fwnode_handle *swnode)
+{
+	struct device *dev;
+
+	dev = class_find_device_by_fwnode(&regulator_class, swnode);
+
+	return dev ? dev_to_rdev(dev) : NULL;
+}
+
+struct fwnode_handle *swnode_get_regulator_node(struct device *dev, const char *supply)
+{
+	struct fwnode_handle *fwnode = dev_fwnode(dev);
+	char *prop_name;
+
+	prop_name = devm_kasprintf(dev, GFP_KERNEL, "%s-supply", supply);
+	if (!prop_name)
+		return ERR_PTR(-ENOMEM);
+
+	return fwnode_find_reference(fwnode->secondary, prop_name, 0);
+}
diff --git a/include/linux/regulator/swnode_regulator.h b/include/linux/regulator/swnode_regulator.h
new file mode 100644
index 000000000000..97527f7dbe80
--- /dev/null
+++ b/include/linux/regulator/swnode_regulator.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Author: Dan Scally <djrscally@gmail.com> */
+#ifndef __LINUX_SWNODE_REG_H
+#define __LINUX_SWNODE_REG_H
+
+#if defined(CONFIG_REGULATOR_SWNODE)
+struct regulator_init_data *regulator_swnode_get_init_data(struct device *dev,
+							   const struct regulator_desc *desc,
+							   struct regulator_config *config,
+							   struct fwnode_handle **regnode);
+struct regulator_dev *swnode_find_regulator_by_node(struct fwnode_handle *swnode);
+struct fwnode_handle *swnode_get_regulator_node(struct device *dev, const char *supply);
+#else
+struct regulator_init_data *regulator_swnode_get_init_data(struct device *dev,
+							   const struct regulator_desc *desc,
+							   struct regulator_config *config)
+{
+	return NULL;
+}
+
+struct regulator_dev *swnode_find_regulator_by_node(struct fwnode_handle *swnode)
+{
+	return NULL;
+}
+
+struct fwnode_handle *swnode_get_regulator_node(struct device *dev, const char *supply)
+{
+	return NULL;
+}
+
+#endif
+
+#endif
-- 
2.25.1


  reply	other threads:[~2021-07-08 22:42 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-08 22:42 [RFC PATCH 0/2] Add software node support to regulator framework Daniel Scally
2021-07-08 22:42 ` Daniel Scally [this message]
2021-07-09 17:26   ` [RFC PATCH 1/2] regulator: Add support for software node connections Mark Brown
2021-07-08 22:42 ` [RFC PATCH 2/2] platform/surface: Add Surface Go 2 board file Daniel Scally
2021-07-09 17:40   ` Mark Brown
2021-07-09 17:04 ` [RFC PATCH 0/2] Add software node support to regulator framework Mark Brown
2021-07-10 22:48   ` Daniel Scally
2021-07-12 14:15     ` Mark Brown
2021-07-12 16:55       ` Laurent Pinchart
2021-07-12 17:32         ` Mark Brown
2021-07-11  9:37   ` Andy Shevchenko
2021-07-12 12:42     ` Mark Brown
2021-07-12 13:01       ` Andy Shevchenko
2021-07-12 13:34         ` Mark Brown
2021-07-12 16:08           ` Andy Shevchenko
2021-07-12 17:01             ` Mark Brown
2021-07-12 23:32               ` Daniel Scally
2021-07-13 15:24                 ` Mark Brown
2021-07-13 15:42                   ` Laurent Pinchart
2021-07-13 16:02                     ` Mark Brown
2021-07-13 16:06                       ` Laurent Pinchart
2021-07-13 18:24                         ` Mark Brown
2021-07-13 15:55                   ` Andy Shevchenko
2021-07-13 18:18                     ` Mark Brown
2021-07-13 19:46                       ` Andy Shevchenko
2021-07-14 16:05                         ` Mark Brown
2021-07-14  7:25                       ` Laurent Pinchart
2021-07-14 16:59                         ` Mark Brown
2021-07-14 17:18                           ` Laurent Pinchart
2021-07-14 17:28                             ` Mark Brown
2021-07-14 17:41                               ` Laurent Pinchart
2021-07-14 19:18                                 ` Mark Brown
2021-07-14 21:53                                   ` Laurent Pinchart
2021-07-13 22:06                   ` Daniel Scally
2021-07-10 22:28 ` Laurent Pinchart
2021-07-10 22:54   ` Daniel Scally
2021-07-11 16:55     ` Laurent Pinchart
2021-07-12  8:13       ` Daniel Scally
2021-07-12 11:50         ` Laurent Pinchart
2021-07-12 13:23         ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210708224226.457224-2-djrscally@gmail.com \
    --to=djrscally@gmail.com \
    --cc=andy.shevchenko@gmail.com \
    --cc=broonie@kernel.org \
    --cc=hdegoede@redhat.com \
    --cc=kieran.bingham@ideasonboard.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luzmaximilian@gmail.com \
    --cc=mgross@linux.intel.com \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).