From: James Hilliard <james.hilliard1@gmail.com>
To: linux-gpio@vger.kernel.org
Cc: James Hilliard <james.hilliard1@gmail.com>,
Linus Walleij <linusw@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
Rob Herring <robh@kernel.org>,
Saravana Kannan <saravanak@kernel.org>,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org
Subject: [PATCH v2 1/1] gpiolib: of: add gpio-line node support
Date: Sat, 14 Feb 2026 14:32:37 -0700 [thread overview]
Message-ID: <20260214213239.2546012-1-james.hilliard1@gmail.com> (raw)
Allow GPIO controller child nodes marked with "gpio-line" to
configure direction/flags at probe time without hogging the line.
Teach OF gpiochip scanning and OF dynamic reconfiguration handlers to
process gpio-line nodes in addition to gpio-hog nodes.
Also parse "gpio-line-name" and apply it to desc->name. For gpio-hog
nodes, keep "line-name" semantics as the hog consumer label.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
Depends on:
- https://github.com/devicetree-org/dt-schema/pull/185
Changes v1 -> v2:
- drop documentation changes
- add depends on to changelog
---
drivers/gpio/gpiolib-of.c | 89 ++++++++++++++++++++++++++++-------
drivers/gpio/gpiolib-shared.c | 7 +--
drivers/of/property.c | 7 +--
scripts/dtc/checks.c | 4 +-
4 files changed, 82 insertions(+), 25 deletions(-)
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index ef1ac68b94b7..b10a21a63d46 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -744,6 +744,7 @@ struct gpio_desc *of_find_gpio(struct device_node *np, const char *con_id,
* @lflags: bitmask of gpio_lookup_flags GPIO_* values - returned from
* of_find_gpio() or of_parse_own_gpio()
* @dflags: gpiod_flags - optional GPIO initialization flags
+ * @hog: indicates if this is a gpio-hog node
*
* Returns:
* GPIO descriptor to use with Linux GPIO API, or one of the errno
@@ -753,11 +754,13 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
struct gpio_chip *chip,
unsigned int idx, const char **name,
unsigned long *lflags,
- enum gpiod_flags *dflags)
+ enum gpiod_flags *dflags,
+ bool hog)
{
struct device_node *chip_np;
enum of_gpio_flags xlate_flags;
struct of_phandle_args gpiospec;
+ const char *desc_name;
struct gpio_desc *desc;
unsigned int i;
u32 tmp;
@@ -797,15 +800,19 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
*dflags |= GPIOD_OUT_LOW;
else if (of_property_read_bool(np, "output-high"))
*dflags |= GPIOD_OUT_HIGH;
- else {
+ else if (hog) {
pr_warn("GPIO line %d (%pOFn): no hogging state specified, bailing out\n",
desc_to_gpio(desc), np);
return ERR_PTR(-EINVAL);
}
- if (name && of_property_read_string(np, "line-name", name))
+ if (hog && name && of_property_read_string(np, "line-name", name))
*name = np->name;
+ if (!of_property_read_string(np, "gpio-line-name", &desc_name) &&
+ desc_name[0])
+ desc->name = desc_name;
+
return desc;
}
@@ -827,7 +834,8 @@ static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
int ret;
for (i = 0;; i++) {
- desc = of_parse_own_gpio(hog, chip, i, &name, &lflags, &dflags);
+ desc = of_parse_own_gpio(hog, chip, i, &name, &lflags, &dflags,
+ true);
if (IS_ERR(desc))
break;
@@ -843,6 +851,36 @@ static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
return 0;
}
+/**
+ * of_gpiochip_add_line - Configure all lines in a gpio-line device node
+ * @chip: gpio chip to act on
+ * @line: device node describing GPIO lines to configure
+ *
+ * Returns:
+ * 0 on success, or negative errno on failure.
+ */
+static int of_gpiochip_add_line(struct gpio_chip *chip, struct device_node *line)
+{
+ enum gpiod_flags dflags;
+ struct gpio_desc *desc;
+ unsigned long lflags;
+ unsigned int i;
+ int ret;
+
+ for (i = 0;; i++) {
+ desc = of_parse_own_gpio(line, chip, i, NULL, &lflags, &dflags,
+ false);
+ if (IS_ERR(desc))
+ break;
+
+ ret = gpiod_configure_flags(desc, NULL, lflags, dflags);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
/**
* of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions
* @chip: gpio chip to act on
@@ -858,14 +896,22 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
int ret;
for_each_available_child_of_node_scoped(dev_of_node(&chip->gpiodev->dev), np) {
- if (!of_property_read_bool(np, "gpio-hog"))
+ if (of_property_read_bool(np, "gpio-hog")) {
+ ret = of_gpiochip_add_hog(chip, np);
+ if (ret < 0)
+ return ret;
+
+ of_node_set_flag(np, OF_POPULATED);
continue;
+ }
- ret = of_gpiochip_add_hog(chip, np);
- if (ret < 0)
- return ret;
+ if (of_property_read_bool(np, "gpio-line")) {
+ ret = of_gpiochip_add_line(chip, np);
+ if (ret < 0)
+ return ret;
- of_node_set_flag(np, OF_POPULATED);
+ of_node_set_flag(np, OF_POPULATED);
+ }
}
return 0;
@@ -905,14 +951,15 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
int ret;
/*
- * This only supports adding and removing complete gpio-hog nodes.
- * Modifying an existing gpio-hog node is not supported (except for
- * changing its "status" property, which is treated the same as
- * addition/removal).
+ * This only supports adding and removing complete gpio-hog and
+ * gpio-line nodes. Modifying an existing node is not supported
+ * (except for changing its "status" property, which is treated
+ * the same as addition/removal).
*/
switch (of_reconfig_get_state_change(action, arg)) {
case OF_RECONFIG_CHANGE_ADD:
- if (!of_property_read_bool(rd->dn, "gpio-hog"))
+ if (!of_property_read_bool(rd->dn, "gpio-hog") &&
+ !of_property_read_bool(rd->dn, "gpio-line"))
return NOTIFY_DONE; /* not for us */
if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
@@ -922,9 +969,12 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
if (!gdev)
return NOTIFY_DONE; /* not for us */
- ret = of_gpiochip_add_hog(gpio_device_get_chip(gdev), rd->dn);
+ if (of_property_read_bool(rd->dn, "gpio-hog"))
+ ret = of_gpiochip_add_hog(gpio_device_get_chip(gdev), rd->dn);
+ else
+ ret = of_gpiochip_add_line(gpio_device_get_chip(gdev), rd->dn);
if (ret < 0) {
- pr_err("%s: failed to add hogs for %pOF\n", __func__,
+ pr_err("%s: failed to configure lines for %pOF\n", __func__,
rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED);
return notifier_from_errno(ret);
@@ -932,6 +982,10 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
return NOTIFY_OK;
case OF_RECONFIG_CHANGE_REMOVE:
+ if (!of_property_read_bool(rd->dn, "gpio-hog") &&
+ !of_property_read_bool(rd->dn, "gpio-line"))
+ return NOTIFY_DONE; /* not for us */
+
if (!of_node_check_flag(rd->dn, OF_POPULATED))
return NOTIFY_DONE; /* already depopulated */
@@ -939,7 +993,8 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
if (!gdev)
return NOTIFY_DONE; /* not for us */
- of_gpiochip_remove_hog(gpio_device_get_chip(gdev), rd->dn);
+ if (of_property_read_bool(rd->dn, "gpio-hog"))
+ of_gpiochip_remove_hog(gpio_device_get_chip(gdev), rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED);
return NOTIFY_OK;
}
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index b3525d1f06a4..b934e58a07f0 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -147,10 +147,11 @@ static bool gpio_shared_of_node_ignore(struct device_node *node)
return true;
/*
- * GPIO hogs have a "gpios" property which is not a phandle and can't
- * possibly refer to a shared GPIO.
+ * GPIO hog and gpio-line nodes have a "gpios" property which is not a
+ * phandle and can't possibly refer to a shared GPIO.
*/
- if (of_property_present(node, "gpio-hog"))
+ if (of_property_present(node, "gpio-hog") ||
+ of_property_present(node, "gpio-line"))
return true;
return false;
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 50d95d512bf5..7689c4315115 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -1435,10 +1435,11 @@ static struct device_node *parse_gpio_compat(struct device_node *np,
return NULL;
/*
- * Ignore node with gpio-hog property since its gpios are all provided
- * by its parent.
+ * Ignore nodes with gpio-hog and gpio-line properties since their gpios
+ * are all provided by their parent.
*/
- if (of_property_read_bool(np, "gpio-hog"))
+ if (of_property_read_bool(np, "gpio-hog") ||
+ of_property_read_bool(np, "gpio-line"))
return NULL;
if (of_parse_phandle_with_args(np, prop_name, "#gpio-cells", index,
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
index 45d0213f3bf3..ee64cb4ada4f 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -1533,8 +1533,8 @@ static void check_gpios_property(struct check *c,
{
struct property *prop;
- /* Skip GPIO hog nodes which have 'gpios' property */
- if (get_property(node, "gpio-hog"))
+ /* Skip gpio-hog and gpio-line nodes which have 'gpios' property */
+ if (get_property(node, "gpio-hog") || get_property(node, "gpio-line"))
return;
for_each_property(node, prop) {
--
2.43.0
next reply other threads:[~2026-02-14 21:32 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-14 21:32 James Hilliard [this message]
2026-02-16 11:37 ` [PATCH v2 1/1] gpiolib: of: add gpio-line node support Bartosz Golaszewski
2026-02-16 21:20 ` James Hilliard
2026-02-17 13:18 ` Bartosz Golaszewski
2026-02-17 14:11 ` Rob Herring
2026-02-17 19:07 ` James Hilliard
2026-02-18 9:33 ` Bartosz Golaszewski
2026-02-18 23:44 ` Rob Herring
2026-02-18 23:56 ` James Hilliard
2026-02-19 9:15 ` Bartosz Golaszewski
2026-02-19 18:18 ` James Hilliard
2026-02-19 18:23 ` Linus Walleij
2026-02-19 21:33 ` Rob Herring
2026-02-19 22:48 ` Linus Walleij
2026-02-18 23:10 ` Linus Walleij
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=20260214213239.2546012-1-james.hilliard1@gmail.com \
--to=james.hilliard1@gmail.com \
--cc=brgl@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=linusw@kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=robh@kernel.org \
--cc=saravanak@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