All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Scally <djrscally@gmail.com>
To: linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org
Cc: Liam Girdwood <lgirdwood@gmail.com>,
	Mark Brown <broonie@kernel.org>,
	Hans de Goede <hdegoede@redhat.com>,
	Mark Gross <mgross@linux.intel.com>,
	Maximilian Luz <luzmaximilian@gmail.com>,
	Kieran Bingham <kieran.bingham@ideasonboard.com>,
	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Subject: [RFC PATCH v2 1/3] regulator: core: Add regulator_lookup_list
Date: Wed, 25 Aug 2021 00:06:18 +0100	[thread overview]
Message-ID: <20210824230620.1003828-2-djrscally@gmail.com> (raw)
In-Reply-To: <20210824230620.1003828-1-djrscally@gmail.com>

In some situations regulator devices can be enumerated via either
devicetree or ACPI and bound to regulator drivers but without any
init data being provided in firmware. This leaves their consumers
unable to acquire them via regulator_get().

To fix the issue, add the ability to register a lookup table to a
list within regulator core, which will allow board files to provide
init data via matching against the regulator name and device name in
the same fashion as the gpiod lookup table.

Signed-off-by: Daniel Scally <djrscally@gmail.com>
---
Changes in v2:
	- Patch introduced

 drivers/regulator/core.c          | 119 +++++++++++++++++++++++++++++-
 include/linux/regulator/machine.h |  23 ++++++
 2 files changed, 141 insertions(+), 1 deletion(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index ca6caba8a191..6a6c1f34d9d6 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -36,6 +36,8 @@
 static DEFINE_WW_CLASS(regulator_ww_class);
 static DEFINE_MUTEX(regulator_nesting_mutex);
 static DEFINE_MUTEX(regulator_list_mutex);
+static DEFINE_MUTEX(regulator_lookup_mutex);
+static LIST_HEAD(regulator_lookup_list);
 static LIST_HEAD(regulator_map_list);
 static LIST_HEAD(regulator_ena_gpio_list);
 static LIST_HEAD(regulator_supply_alias_list);
@@ -1868,6 +1870,7 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
 static struct regulator_dev *regulator_dev_lookup(struct device *dev,
 						  const char *supply)
 {
+	struct regulator_lookup *lookup;
 	struct regulator_dev *r = NULL;
 	struct device_node *node;
 	struct regulator_map *map;
@@ -1917,7 +1920,34 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
 	if (r)
 		return r;
 
-	return ERR_PTR(-ENODEV);
+	/*
+	 * The regulator might still exist and be called out in a lookup table,
+	 * but simply not yet have probed. Check to see if the consumer device
+	 * is referenced in any init data in the lookups.
+	 */
+
+	mutex_lock(&regulator_lookup_mutex);
+	list_for_each_entry(lookup, &regulator_lookup_list, list) {
+		struct regulator_init_data *init_data = &lookup->init_data;
+		unsigned int i;
+
+		if (!devname)
+			break;
+
+		for (i = 0; i < init_data->num_consumer_supplies; i++) {
+			if (strcmp(init_data->consumer_supplies[i].dev_name, devname))
+				continue;
+
+			r = ERR_PTR(-EPROBE_DEFER);
+			goto out;
+		}
+	}
+
+	r = ERR_PTR(-ENODEV);
+
+out:
+	mutex_unlock(&regulator_lookup_mutex);
+	return r;
 }
 
 static int regulator_resolve_supply(struct regulator_dev *rdev)
@@ -5302,6 +5332,54 @@ static struct regulator_coupler generic_regulator_coupler = {
 	.attach_regulator = generic_coupler_attach,
 };
 
+/**
+ * regulator_lookup_init_data - Check regulator_lookup_list for matching entries
+ * @desc:	Regulator desc containing name of the regulator
+ * @cfg:	Regulator config containing pointer to the registering device
+ *
+ * Calling this function scans the regulator_lookup_list and checks each entry
+ * to see if the .device_name and .regulator_name fields match the device name
+ * and regulator name contained in @cfg and @desc. If so, a pointer to the
+ * embedded &struct regulator_init_data is returned. No matches returns NULL.
+ */
+struct regulator_init_data *
+regulator_lookup_init_data(const struct regulator_desc *desc,
+			   const struct regulator_config *cfg)
+{
+	struct regulator_lookup *lookup;
+
+	if (!desc || !cfg || !cfg->dev)
+		return NULL;
+
+	mutex_lock(&regulator_lookup_mutex);
+
+	list_for_each_entry(lookup, &regulator_lookup_list, list) {
+		/*
+		 * We need the lookup to have at least a device_name or there's
+		 * no guarantee of a match, and regulator_register() checks to
+		 * make sure that desc->name is not null, so any entry with
+		 * either field null is invalid.
+		 */
+		if (!lookup->device_name || !lookup->regulator_name)
+			continue;
+
+		if (strcmp(lookup->device_name, dev_name(cfg->dev)))
+			continue;
+
+		if (strcmp(lookup->regulator_name, desc->name))
+			continue;
+
+		goto found;
+	}
+
+	lookup = NULL;
+
+found:
+	mutex_unlock(&regulator_lookup_mutex);
+
+	return lookup ? &lookup->init_data : NULL;
+}
+
 /**
  * regulator_register - register regulator
  * @regulator_desc: regulator to register
@@ -5386,6 +5464,9 @@ 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_lookup_init_data(regulator_desc, config);
+
 	/*
 	 * 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
@@ -5740,6 +5821,42 @@ void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
 }
 EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
 
+/**
+ * regulator_add_lookup - Add an entry to regulator_lookup_list
+ * @lookup:	Pointer to the &struct regulator_lookup to add to the list
+ *
+ * This function can be used in board files to add an entry to the
+ * regulator_lookup_list. During regulator_register(), entries will be checked
+ * for matching device name and regulator name and when matching, the associated
+ * &struct regulator_init_data will be used.
+ */
+void regulator_add_lookup(struct regulator_lookup *lookup)
+{
+	mutex_lock(&regulator_lookup_mutex);
+
+	list_add_tail(&lookup->list, &regulator_lookup_list);
+
+	mutex_unlock(&regulator_lookup_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_add_lookup);
+
+/**
+ * regulator_remove_lookup - Remove an entry from regulator_lookup_list
+ * @lookup:	Pointer to the &struct regulator_lookup to remove from the list
+ *
+ * Calling this function will remove the passed regulator_lookup from the list,
+ * intended for error handling paths in board files.
+ */
+void regulator_remove_lookup(struct regulator_lookup *lookup)
+{
+	mutex_lock(&regulator_lookup_mutex);
+
+	list_del(&lookup->list);
+
+	mutex_unlock(&regulator_lookup_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_remove_lookup);
+
 #ifdef CONFIG_DEBUG_FS
 static int supply_map_show(struct seq_file *sf, void *data)
 {
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 68b4a514a410..d1b62a3962d8 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -12,6 +12,7 @@
 #ifndef __LINUX_REGULATOR_MACHINE_H_
 #define __LINUX_REGULATOR_MACHINE_H_
 
+#include <linux/list.h>
 #include <linux/regulator/consumer.h>
 #include <linux/suspend.h>
 
@@ -272,12 +273,34 @@ struct regulator_init_data {
 	void *driver_data;	/* core does not touch this */
 };
 
+/**
+ * struct regulator_lookup - lookup table entry for regulator_init_data
+ *
+ * @device_name:	The name of the device from regulator_config.dev
+ * @regulator_name:	The name of the regulator from the &struct regulator_desc
+ *			to match to during regulator_register()
+ * @init_data:		An instance of &struct regulator_init_data that you
+ *			wish to pass to the regulator during regulator_register()
+ */
+struct regulator_lookup {
+	const char *device_name;
+	const char *regulator_name;
+
+	struct regulator_init_data init_data;
+
+	struct list_head list;
+};
+
 #ifdef CONFIG_REGULATOR
 void regulator_has_full_constraints(void);
+void regulator_add_lookup(struct regulator_lookup *lookup);
+void regulator_remove_lookup(struct regulator_lookup *lookup);
 #else
 static inline void regulator_has_full_constraints(void)
 {
 }
+static inline void regulator_add_lookup(struct regulator_lookup *lookup) { }
+static inline void regulator_remove_lookup(struct regulator_lookup *lookup) { }
 #endif
 
 static inline int regulator_suspend_prepare(suspend_state_t state)
-- 
2.25.1


  reply	other threads:[~2021-08-24 23:06 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-24 23:06 [RFC PATCH v2 0/3] Add regulator_lookup_list and API Daniel Scally
2021-08-24 23:06 ` Daniel Scally [this message]
2021-08-25  2:45   ` [RFC PATCH v2 1/3] regulator: core: Add regulator_lookup_list kernel test robot
2021-08-25  3:57   ` kernel test robot
2021-08-25  3:57   ` [RFC PATCH] regulator: core: regulator_lookup_init_data can be static kernel test robot
2021-08-25 10:33   ` [RFC PATCH v2 1/3] regulator: core: Add regulator_lookup_list Mark Brown
2021-08-25 11:10     ` Andy Shevchenko
2021-08-25 11:30       ` Mark Brown
2021-08-25 12:26         ` Andy Shevchenko
2021-08-25 13:11           ` Mark Brown
2021-08-25 13:59             ` Laurent Pinchart
2021-08-25 14:03               ` Laurent Pinchart
2021-08-25 14:33                 ` Andy Shevchenko
2021-08-25 14:12               ` Daniel Scally
2021-08-25 14:22                 ` Laurent Pinchart
2021-08-25 14:52                   ` Mark Brown
2021-08-25 22:09                     ` Daniel Scally
2021-08-26 12:40                       ` Mark Brown
2021-08-25 14:41               ` Mark Brown
2021-08-25 14:48     ` Hans de Goede
2021-08-25 15:27       ` Mark Brown
2021-08-25 15:42         ` Laurent Pinchart
2021-08-25 16:13           ` Mark Brown
2021-08-25 20:25           ` Hans de Goede
2021-08-25 20:40             ` Laurent Pinchart
2021-08-25 21:24               ` Daniel Scally
2021-08-25 21:17       ` Daniel Scally
2021-08-24 23:06 ` [RFC PATCH v2 2/3] Documentation: power: Document regulator_lookup_list Daniel Scally
2021-08-24 23:06 ` [RFC PATCH v2 3/3] platform/surface: Add Surface Go 2 board file Daniel Scally

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=20210824230620.1003828-2-djrscally@gmail.com \
    --to=djrscally@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.