summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpiolib-sysfs.c
diff options
context:
space:
mode:
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>2025-07-04 14:58:55 +0200
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>2025-07-16 10:27:08 +0200
commit4fa93223e03eea3243db83786f556b6c1494de3e (patch)
treeea856a2164e627f93ba414b999b9d115634f9283 /drivers/gpio/gpiolib-sysfs.c
parent1cd53df733c21ae0d344a2dec941a3e2a06fefd9 (diff)
gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory
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. Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Link: https://lore.kernel.org/r/20250704-gpio-sysfs-chip-export-v4-8-9289d8758243@linaro.org Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib-sysfs.c')
-rw-r--r--drivers/gpio/gpiolib-sysfs.c51
1 files changed, 50 insertions, 1 deletions
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index ccc293a4cc5d..563e38456c33 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -41,6 +41,13 @@ enum {
GPIO_SYSFS_LINE_CLASS_ATTR_SIZE,
};
+enum {
+ GPIO_SYSFS_LINE_CHIP_ATTR_DIRECTION = 0,
+ GPIO_SYSFS_LINE_CHIP_ATTR_VALUE,
+ GPIO_SYSFS_LINE_CHIP_ATTR_SENTINEL,
+ GPIO_SYSFS_LINE_CHIP_ATTR_SIZE,
+};
+
struct gpiod_data {
struct list_head list;
@@ -54,6 +61,7 @@ struct gpiod_data {
bool direction_can_change;
+ struct kobject *parent;
struct device_attribute dir_attr;
struct device_attribute val_attr;
struct device_attribute edge_attr;
@@ -62,6 +70,10 @@ struct gpiod_data {
struct attribute *class_attrs[GPIO_SYSFS_LINE_CLASS_ATTR_SIZE];
struct attribute_group class_attr_group;
const struct attribute_group *class_attr_groups[2];
+
+ struct attribute *chip_attrs[GPIO_SYSFS_LINE_CHIP_ATTR_SIZE];
+ struct attribute_group chip_attr_group;
+ const struct attribute_group *chip_attr_groups[2];
};
struct gpiodev_data {
@@ -691,6 +703,7 @@ static void gpiod_attr_init(struct device_attribute *dev_attr, const char *name,
*/
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{
+ char *path __free(kfree) = NULL;
struct gpiodev_data *gdev_data;
struct gpiod_data *desc_data;
struct gpio_device *gdev;
@@ -780,13 +793,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;
+ }
+
+ desc_data->chip_attr_group.name = kasprintf(GFP_KERNEL, "gpio%u",
+ gpio_chip_hwgpio(desc));
+ if (!desc_data->chip_attr_group.name) {
+ status = -ENOMEM;
+ goto err_put_dirent;
+ }
+
+ attrs = desc_data->chip_attrs;
+ desc_data->chip_attr_group.is_visible = gpio_is_visible;
+ attrs[GPIO_SYSFS_LINE_CHIP_ATTR_DIRECTION] = &desc_data->dir_attr.attr;
+ attrs[GPIO_SYSFS_LINE_CHIP_ATTR_VALUE] = &desc_data->val_attr.attr;
+
+ desc_data->chip_attr_group.attrs = attrs;
+ desc_data->chip_attr_groups[0] = &desc_data->chip_attr_group;
+
+ desc_data->parent = &gdev_data->cdev_id->kobj;
+ status = sysfs_create_groups(desc_data->parent,
+ desc_data->chip_attr_groups);
+ if (status)
+ goto err_free_name;
+
+ path = kasprintf(GFP_KERNEL, "gpio%u/value", gpio_chip_hwgpio(desc));
+ if (!path) {
+ status = -ENOMEM;
+ goto err_remove_groups;
}
list_add(&desc_data->list, &gdev_data->exported_lines);
return 0;
+err_remove_groups:
+ sysfs_remove_groups(desc_data->parent, desc_data->chip_attr_groups);
+err_free_name:
+ kfree(desc_data->chip_attr_group.name);
+err_put_dirent:
+ sysfs_put(desc_data->value_kn);
err_unregister_device:
device_unregister(desc_data->dev);
err_free_data:
@@ -883,6 +929,9 @@ void gpiod_unexport(struct gpio_desc *desc)
*/
if (desc_data->irq_flags)
gpio_sysfs_free_irq(desc_data);
+
+ sysfs_remove_groups(desc_data->parent,
+ desc_data->chip_attr_groups);
}
mutex_destroy(&desc_data->mutex);