U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Mehmet Fide <mehmet.fide@gmail.com>
To: Simon Glass <sjg@chromium.org>
Cc: Tom Rini <trini@konsulko.com>,
	Jaehoon Chung <jh80.chung@samsung.com>,
	Peng Fan <peng.fan@nxp.com>, Vincent Jardin <vjardin@free.fr>,
	Ye Li <ye.li@nxp.com>, Michal Simek <michal.simek@amd.com>,
	Aristo Chen <aristo.chen@canonical.com>,
	u-boot@lists.u-boot-project.org,
	Mehmet Fide <mehmet.fide@screeningeagle.com>
Subject: [PATCH v2 1/4] gpio: add a way to parse a GPIO now and request it later
Date: Fri, 11 Sep 2026 00:08:15 +0200	[thread overview]
Message-ID: <20260910220818.3093364-2-mehmet.fide@gmail.com> (raw)
In-Reply-To: <20260910220818.3093364-1-mehmet.fide@gmail.com>

From: Mehmet Fide <mehmet.fide@screeningeagle.com>

A driver's of_to_plat() method must only read the devicetree; probing
other devices or claiming resources belongs in probe(). Several drivers
nevertheless call gpio_request_by_name() from of_to_plat(), because it
is the only way to pick a GPIO out of the devicetree: it resolves and
probes the controller and claims the GPIO in one go. On boards where
the consumer's pinctrl touches the same pad, the pinctrl state, applied
between the two phases, then undoes the direction the early claim set.

Split the two halves: gpio_parse_by_name() reads the phandle into a new
struct gpio_dt_spec without touching any device, so it can live in the
platform data; gpio_request_parsed() resolves the controller, claims
the GPIO under the same label gpio_request_by_name() would have used,
and applies the direction flags, for use in probe(). A spec whose
property was missing requests as -ENOENT on purpose, so a caller with
an optional GPIO does not need to check it first.

Signed-off-by: Mehmet Fide <mehmet.fide@screeningeagle.com>
---

Notes:
    Changes in v2:
    - keep the list index in the spec so the request label matches
      gpio_request_by_name() (Simon Glass)
    - rename struct gpio_dt_desc to gpio_dt_spec (Simon Glass)
    - document the list_name lifetime and the deliberate -ENOENT (Simon Glass)
    - test: check the pin is unclaimed between parse and request, and the
      request label (Simon Glass)

 drivers/gpio/gpio-uclass.c | 34 +++++++++++++++++++++
 include/asm-generic/gpio.h | 60 ++++++++++++++++++++++++++++++++++++++
 test/dm/gpio.c             | 39 +++++++++++++++++++++++++
 3 files changed, 133 insertions(+)

diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index ff17cabd601..33eaf2a2022 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -1219,6 +1219,40 @@ int gpio_request_by_name_nodev(ofnode node, const char *list_name, int index,
 					   index > 0);
 }
 
+int gpio_parse_by_name(struct udevice *dev, const char *list_name, int index,
+		       int flags, struct gpio_dt_spec *spec)
+{
+	int ret;
+
+	spec->present = false;
+	ret = dev_read_phandle_with_args(dev, list_name, "#gpio-cells", 0,
+					 index, &spec->args);
+	if (ret)
+		return ret;
+	spec->list_name = list_name;
+	spec->index = index;
+	spec->flags = flags;
+	spec->present = true;
+
+	return 0;
+}
+
+int gpio_request_parsed(struct udevice *dev, const struct gpio_dt_spec *spec,
+			struct gpio_desc *desc)
+{
+	struct ofnode_phandle_args args;
+
+	if (!spec->present) {
+		gpio_desc_init(desc, NULL, 0);
+		return -ENOENT;
+	}
+
+	args = spec->args;
+	return gpio_request_tail(0, ofnode_get_name(dev_ofnode(dev)), &args,
+				 spec->list_name, spec->index, desc, spec->flags,
+				 spec->index > 0, NULL);
+}
+
 int gpio_request_by_name(struct udevice *dev, const char *list_name, int index,
 			 struct gpio_desc *desc, int flags)
 {
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index a21c606f2b8..8229a5faac1 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -574,6 +574,66 @@ int gpio_claim_vector(const int *gpio_num_array, const char *fmt);
 int gpio_request_by_name(struct udevice *dev, const char *list_name,
 			 int index, struct gpio_desc *desc, int flags);
 
+/**
+ * struct gpio_dt_spec - devicetree specification of a GPIO, not yet requested
+ *
+ * Filled by gpio_parse_by_name() from an of_to_plat() method, which must not
+ * probe other devices or claim the GPIO, and consumed by
+ * gpio_request_parsed() from the probe() method.
+ *
+ * @args: phandle arguments naming the controller node and the GPIO
+ * @list_name: name of the devicetree property that was parsed. Only the
+ *	pointer is kept, so the string must outlive the spec; callers pass
+ *	string literals
+ * @index: index of the GPIO in the property, kept for the request label
+ * @flags: GPIOD_... flags requested by the caller
+ * @present: true if the property exists and was parsed
+ */
+struct gpio_dt_spec {
+	struct ofnode_phandle_args args;
+	const char *list_name;
+	int index;
+	int flags;
+	bool present;
+};
+
+/**
+ * gpio_parse_by_name() - read a GPIO from the devicetree without requesting it
+ *
+ * This only reads the devicetree, so it is safe to call from an of_to_plat()
+ * method; the GPIO controller is neither probed nor touched. Request the GPIO
+ * in the probe() method with gpio_request_parsed().
+ *
+ * @dev:	Device requesting the GPIO
+ * @list_name:	Name of devicetree property containing the GPIO
+ * @index:	Index of the GPIO in the list of GPIOs
+ * @flags:	GPIOD_... flags to use when the GPIO is requested later
+ * @spec:	Returns the parsed specification
+ * Return: 0 if OK, -ENOENT if the property is missing, other -ve on error
+ */
+int gpio_parse_by_name(struct udevice *dev, const char *list_name, int index,
+		       int flags, struct gpio_dt_spec *spec);
+
+/**
+ * gpio_request_parsed() - request a GPIO parsed by gpio_parse_by_name()
+ *
+ * This does the second half of gpio_request_by_name(): resolve the
+ * controller, claim the GPIO and apply the direction flags. Call it from the
+ * probe() method. The request label is the same one gpio_request_by_name()
+ * would have used.
+ *
+ * A spec whose property was missing is deliberately accepted and answered
+ * with -ENOENT, with @desc left invalid, so a caller with an optional GPIO
+ * need not check @present first and can simply tolerate -ENOENT.
+ *
+ * @dev:	Device requesting the GPIO (used for the request label)
+ * @spec:	Specification returned by gpio_parse_by_name()
+ * @desc:	Returns the GPIO description, ready for use
+ * Return: 0 if OK, -ENOENT if @spec holds no GPIO, other -ve on error
+ */
+int gpio_request_parsed(struct udevice *dev, const struct gpio_dt_spec *spec,
+			struct gpio_desc *desc);
+
 /* gpio_request_by_line_name - Locate and request a GPIO by line name
  *
  * Request a GPIO using the offset of the provided line name in the
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index 3d966e0d1a6..2401c5ed1be 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -257,6 +257,45 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts)
 DM_TEST(dm_test_gpio_opendrain_opensource,
 	UTF_SCAN_PDATA | UTF_SCAN_FDT);
 
+/* Test parsing a GPIO in one phase and requesting it in another */
+static int dm_test_gpio_parse_request(struct unit_test_state *uts)
+{
+	struct gpio_dt_spec spec;
+	struct gpio_desc desc, chk;
+	struct udevice *dev;
+	const char *label;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	/* test2-gpios index 1 is a4: parsing alone must not claim it */
+	ut_assertok(dm_gpio_lookup_name("a4", &chk));
+	ut_assertok(gpio_parse_by_name(dev, "test2-gpios", 1, GPIOD_IS_OUT,
+				       &spec));
+	ut_asserteq(true, spec.present);
+	ut_asserteq(GPIOF_UNUSED, gpio_get_function(chk.dev, chk.offset,
+						    NULL));
+	ut_asserteq(0, sandbox_gpio_get_direction(chk.dev, chk.offset));
+
+	/* the request claims it with the label gpio_request_by_name() uses */
+	ut_assertok(gpio_request_parsed(dev, &spec, &desc));
+	ut_asserteq_ptr(chk.dev, desc.dev);
+	ut_asserteq(chk.offset, desc.offset);
+	ut_asserteq(GPIOF_OUTPUT, gpio_get_function(desc.dev, desc.offset,
+						    &label));
+	ut_asserteq_str("a-test.test2-gpios1", label);
+	ut_assertok(dm_gpio_free(dev, &desc));
+
+	/* a missing property parses and requests as -ENOENT */
+	ut_asserteq(-ENOENT,
+		    gpio_parse_by_name(dev, "no-such-gpios", 0, 0, &spec));
+	ut_asserteq(-ENOENT, gpio_request_parsed(dev, &spec, &desc));
+	ut_asserteq(false, dm_gpio_is_valid(&desc));
+
+	return 0;
+}
+DM_TEST(dm_test_gpio_parse_request, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
 /* Test that sandbox anonymous GPIOs work correctly */
 static int dm_test_gpio_anon(struct unit_test_state *uts)
 {
-- 
2.55.0


  reply	other threads:[~2026-09-10 22:08 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-10 22:08 [PATCH v2 0/4] dm: gpio: read GPIOs in of_to_plat(), request them in probe() Mehmet Fide
2026-09-10 22:08 ` Mehmet Fide [this message]
2026-09-10 22:08 ` [PATCH v2 2/4] regulator: claim the enable GPIO at probe time, not in of_to_plat() Mehmet Fide
2026-09-10 22:08 ` [PATCH v2 3/4] doc: driver-model: state that of_to_plat() must not probe or claim Mehmet Fide
2026-09-10 22:08 ` [PATCH v2 4/4] test: dm: check the regulators claim their GPIOs at probe time Mehmet Fide

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=20260910220818.3093364-2-mehmet.fide@gmail.com \
    --to=mehmet.fide@gmail.com \
    --cc=aristo.chen@canonical.com \
    --cc=jh80.chung@samsung.com \
    --cc=mehmet.fide@screeningeagle.com \
    --cc=michal.simek@amd.com \
    --cc=peng.fan@nxp.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.u-boot-project.org \
    --cc=vjardin@free.fr \
    --cc=ye.li@nxp.com \
    /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