mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 14:41:22 -05:00
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>
This commit is contained in:
@@ -27,6 +27,9 @@ Description:
|
||||
/base ... (r/o) same as N
|
||||
/label ... (r/o) descriptive chip name
|
||||
/ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)
|
||||
/gpio<OFFSET>
|
||||
/value ... always readable, writes fail for input GPIOs
|
||||
/direction ... r/w as: in, out (default low); write: high, 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user