[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250610-gpio-sysfs-chip-export-v1-13-a8c7aa4478b1@linaro.org>
Date: Tue, 10 Jun 2025 16:38:28 +0200
From: Bartosz Golaszewski <brgl@...ev.pl>
To: Ahmad Fatoum <a.fatoum@...gutronix.de>,
Kent Gibson <warthog618@...il.com>,
Jan Lübbe <jlu@...gutronix.de>,
Marek Vasut <marex@...x.de>, Geert Uytterhoeven <geert+renesas@...der.be>,
Linus Walleij <linus.walleij@...aro.org>,
Bartosz Golaszewski <brgl@...ev.pl>
Cc: linux-gpio@...r.kernel.org, linux-kernel@...r.kernel.org,
Bartosz Golaszewski <bartosz.golaszewski@...aro.org>
Subject: [PATCH RFC/RFT 13/15] gpio: sysfs: export the GPIO directory
locally in the gpiochip<id> directory
From: Bartosz Golaszewski <bartosz.golaszewski@...aro.org>
As a way to allow the user-space to stop referring to GPIOs by their
global numbers, introduce a parallel group of line attributes for
exported GPIO that live inside the GPIO chip class device and are
referred to by their HW offset within their parent chip.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@...aro.org>
---
Documentation/ABI/obsolete/sysfs-gpio | 5 +++++
drivers/gpio/gpiolib-sysfs.c | 39 ++++++++++++++++++++++++++++++++++-
2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/obsolete/sysfs-gpio b/Documentation/ABI/obsolete/sysfs-gpio
index f856e286051d6bfa4990660dcb25b3fdb27cd0f2..3212cf64f43b67b23a1ac17df025638a52a5bb31 100644
--- a/Documentation/ABI/obsolete/sysfs-gpio
+++ b/Documentation/ABI/obsolete/sysfs-gpio
@@ -27,6 +27,11 @@ Description:
/base ... (r/o) same as N
/label ... (r/o) descriptive, not necessarily unique
/ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)
+ /gpio<OFFSET>
+ /value
+ /direction
+ /edge
+ /active-low
/chipX ... for each gpiochip; #X is the gpio device ID
/export ... asks the kernel to export a GPIO at HW offset X to userspace
/unexport ... to return a GPIO at HW offset X to the kernel
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index aa998d9e96cce5d64784645eea73f987471c7285..d8c17d71d5458011d15bc4239bd4c041244da3fd 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -47,11 +47,13 @@ struct gpiod_data {
struct mutex mutex;
struct kernfs_node *value_class_node;
+ struct kernfs_node *value_chip_node;
int irq;
unsigned char irq_flags;
bool direction_can_change;
+ struct kobject *parent;
struct device_attribute dir_attr;
struct device_attribute val_attr;
struct device_attribute edge_attr;
@@ -180,6 +182,7 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
struct gpiod_data *data = priv;
sysfs_notify_dirent(data->value_class_node);
+ kernfs_notify(data->value_chip_node);
return IRQ_HANDLED;
}
@@ -780,13 +783,46 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
gdev_data = gdev_get_data(gdev);
if (!gdev_data) {
status = -ENODEV;
- goto err_unregister_device;
+ goto err_put_dirent;
}
list_add(&desc_data->list, &gdev_data->exported_lines);
+ desc_data->attr_group.name = kasprintf(GFP_KERNEL, "gpio%u",
+ gpio_chip_hwgpio(desc));
+ if (!desc_data->attr_group.name) {
+ status = -ENOMEM;
+ goto err_put_dirent;
+ }
+
+ desc_data->parent = &gdev_data->cdev_id->kobj;
+ status = sysfs_create_groups(desc_data->parent,
+ desc_data->attr_groups);
+ if (status)
+ goto err_free_name;
+
+ char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
+ gpio_chip_hwgpio(desc));
+ if (!path) {
+ status = -ENOMEM;
+ goto err_remove_groups;
+ }
+
+ desc_data->value_chip_node = kernfs_walk_and_get(desc_data->parent->sd,
+ path);
+ if (!desc_data->value_chip_node) {
+ status = -ENODEV;
+ goto err_remove_groups;
+ }
+
return 0;
+err_remove_groups:
+ sysfs_remove_groups(desc_data->parent, desc_data->attr_groups);
+err_free_name:
+ kfree(desc_data->attr_group.name);
+err_put_dirent:
+ sysfs_put(desc_data->value_class_node);
err_unregister_device:
device_unregister(desc_data->dev);
err_free_data:
@@ -876,6 +912,7 @@ void gpiod_unexport(struct gpio_desc *desc)
clear_bit(FLAG_EXPORT, &desc->flags);
sysfs_put(desc_data->value_class_node);
device_unregister(desc_data->dev);
+ kernfs_put(desc_data->value_chip_node);
/*
* Release irq after deregistration to prevent race with
--
2.48.1
Powered by blists - more mailing lists