diff options
Diffstat (limited to 'drivers/gpio/gpiolib-sysfs.c')
-rw-r--r-- | drivers/gpio/gpiolib-sysfs.c | 92 |
1 files changed, 52 insertions, 40 deletions
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 2ac1800b58bb..f62aa115d79a 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c | |||
@@ -128,7 +128,7 @@ static ssize_t gpio_value_store(struct device *dev, | |||
128 | return status; | 128 | return status; |
129 | } | 129 | } |
130 | 130 | ||
131 | static const DEVICE_ATTR(value, 0644, | 131 | static DEVICE_ATTR(value, 0644, |
132 | gpio_value_show, gpio_value_store); | 132 | gpio_value_show, gpio_value_store); |
133 | 133 | ||
134 | static irqreturn_t gpio_sysfs_irq(int irq, void *priv) | 134 | static irqreturn_t gpio_sysfs_irq(int irq, void *priv) |
@@ -353,17 +353,46 @@ static ssize_t gpio_active_low_store(struct device *dev, | |||
353 | return status ? : size; | 353 | return status ? : size; |
354 | } | 354 | } |
355 | 355 | ||
356 | static const DEVICE_ATTR(active_low, 0644, | 356 | static DEVICE_ATTR(active_low, 0644, |
357 | gpio_active_low_show, gpio_active_low_store); | 357 | gpio_active_low_show, gpio_active_low_store); |
358 | 358 | ||
359 | static const struct attribute *gpio_attrs[] = { | 359 | static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr, |
360 | int n) | ||
361 | { | ||
362 | struct device *dev = container_of(kobj, struct device, kobj); | ||
363 | struct gpio_desc *desc = dev_get_drvdata(dev); | ||
364 | umode_t mode = attr->mode; | ||
365 | bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags); | ||
366 | |||
367 | if (attr == &dev_attr_direction.attr) { | ||
368 | if (!show_direction) | ||
369 | mode = 0; | ||
370 | } else if (attr == &dev_attr_edge.attr) { | ||
371 | if (gpiod_to_irq(desc) < 0) | ||
372 | mode = 0; | ||
373 | if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags)) | ||
374 | mode = 0; | ||
375 | } | ||
376 | |||
377 | return mode; | ||
378 | } | ||
379 | |||
380 | static struct attribute *gpio_attrs[] = { | ||
381 | &dev_attr_direction.attr, | ||
382 | &dev_attr_edge.attr, | ||
360 | &dev_attr_value.attr, | 383 | &dev_attr_value.attr, |
361 | &dev_attr_active_low.attr, | 384 | &dev_attr_active_low.attr, |
362 | NULL, | 385 | NULL, |
363 | }; | 386 | }; |
364 | 387 | ||
365 | static const struct attribute_group gpio_attr_group = { | 388 | static const struct attribute_group gpio_group = { |
366 | .attrs = (struct attribute **) gpio_attrs, | 389 | .attrs = gpio_attrs, |
390 | .is_visible = gpio_is_visible, | ||
391 | }; | ||
392 | |||
393 | static const struct attribute_group *gpio_groups[] = { | ||
394 | &gpio_group, | ||
395 | NULL | ||
367 | }; | 396 | }; |
368 | 397 | ||
369 | /* | 398 | /* |
@@ -400,16 +429,13 @@ static ssize_t chip_ngpio_show(struct device *dev, | |||
400 | } | 429 | } |
401 | static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); | 430 | static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); |
402 | 431 | ||
403 | static const struct attribute *gpiochip_attrs[] = { | 432 | static struct attribute *gpiochip_attrs[] = { |
404 | &dev_attr_base.attr, | 433 | &dev_attr_base.attr, |
405 | &dev_attr_label.attr, | 434 | &dev_attr_label.attr, |
406 | &dev_attr_ngpio.attr, | 435 | &dev_attr_ngpio.attr, |
407 | NULL, | 436 | NULL, |
408 | }; | 437 | }; |
409 | 438 | ATTRIBUTE_GROUPS(gpiochip); | |
410 | static const struct attribute_group gpiochip_attr_group = { | ||
411 | .attrs = (struct attribute **) gpiochip_attrs, | ||
412 | }; | ||
413 | 439 | ||
414 | /* | 440 | /* |
415 | * /sys/class/gpio/export ... write-only | 441 | * /sys/class/gpio/export ... write-only |
@@ -556,45 +582,30 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) | |||
556 | goto fail_unlock; | 582 | goto fail_unlock; |
557 | } | 583 | } |
558 | 584 | ||
559 | if (!desc->chip->direction_input || !desc->chip->direction_output) | 585 | if (desc->chip->direction_input && desc->chip->direction_output && |
560 | direction_may_change = false; | 586 | direction_may_change) { |
587 | set_bit(FLAG_SYSFS_DIR, &desc->flags); | ||
588 | } | ||
589 | |||
561 | spin_unlock_irqrestore(&gpio_lock, flags); | 590 | spin_unlock_irqrestore(&gpio_lock, flags); |
562 | 591 | ||
563 | offset = gpio_chip_hwgpio(desc); | 592 | offset = gpio_chip_hwgpio(desc); |
564 | if (desc->chip->names && desc->chip->names[offset]) | 593 | if (desc->chip->names && desc->chip->names[offset]) |
565 | ioname = desc->chip->names[offset]; | 594 | ioname = desc->chip->names[offset]; |
566 | 595 | ||
567 | dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), | 596 | dev = device_create_with_groups(&gpio_class, desc->chip->dev, |
568 | desc, ioname ? ioname : "gpio%u", | 597 | MKDEV(0, 0), desc, gpio_groups, |
569 | desc_to_gpio(desc)); | 598 | ioname ? ioname : "gpio%u", |
599 | desc_to_gpio(desc)); | ||
570 | if (IS_ERR(dev)) { | 600 | if (IS_ERR(dev)) { |
571 | status = PTR_ERR(dev); | 601 | status = PTR_ERR(dev); |
572 | goto fail_unlock; | 602 | goto fail_unlock; |
573 | } | 603 | } |
574 | 604 | ||
575 | status = sysfs_create_group(&dev->kobj, &gpio_attr_group); | ||
576 | if (status) | ||
577 | goto fail_unregister_device; | ||
578 | |||
579 | if (direction_may_change) { | ||
580 | status = device_create_file(dev, &dev_attr_direction); | ||
581 | if (status) | ||
582 | goto fail_unregister_device; | ||
583 | } | ||
584 | |||
585 | if (gpiod_to_irq(desc) >= 0 && (direction_may_change || | ||
586 | !test_bit(FLAG_IS_OUT, &desc->flags))) { | ||
587 | status = device_create_file(dev, &dev_attr_edge); | ||
588 | if (status) | ||
589 | goto fail_unregister_device; | ||
590 | } | ||
591 | |||
592 | set_bit(FLAG_EXPORT, &desc->flags); | 605 | set_bit(FLAG_EXPORT, &desc->flags); |
593 | mutex_unlock(&sysfs_lock); | 606 | mutex_unlock(&sysfs_lock); |
594 | return 0; | 607 | return 0; |
595 | 608 | ||
596 | fail_unregister_device: | ||
597 | device_unregister(dev); | ||
598 | fail_unlock: | 609 | fail_unlock: |
599 | mutex_unlock(&sysfs_lock); | 610 | mutex_unlock(&sysfs_lock); |
600 | gpiod_dbg(desc, "%s: status %d\n", __func__, status); | 611 | gpiod_dbg(desc, "%s: status %d\n", __func__, status); |
@@ -718,6 +729,7 @@ void gpiod_unexport(struct gpio_desc *desc) | |||
718 | dev = class_find_device(&gpio_class, NULL, desc, match_export); | 729 | dev = class_find_device(&gpio_class, NULL, desc, match_export); |
719 | if (dev) { | 730 | if (dev) { |
720 | gpio_setup_irq(desc, dev, 0); | 731 | gpio_setup_irq(desc, dev, 0); |
732 | clear_bit(FLAG_SYSFS_DIR, &desc->flags); | ||
721 | clear_bit(FLAG_EXPORT, &desc->flags); | 733 | clear_bit(FLAG_EXPORT, &desc->flags); |
722 | } else | 734 | } else |
723 | status = -ENODEV; | 735 | status = -ENODEV; |
@@ -750,13 +762,13 @@ int gpiochip_export(struct gpio_chip *chip) | |||
750 | 762 | ||
751 | /* use chip->base for the ID; it's already known to be unique */ | 763 | /* use chip->base for the ID; it's already known to be unique */ |
752 | mutex_lock(&sysfs_lock); | 764 | mutex_lock(&sysfs_lock); |
753 | dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip, | 765 | dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0), |
754 | "gpiochip%d", chip->base); | 766 | chip, gpiochip_groups, |
755 | if (!IS_ERR(dev)) { | 767 | "gpiochip%d", chip->base); |
756 | status = sysfs_create_group(&dev->kobj, | 768 | if (IS_ERR(dev)) |
757 | &gpiochip_attr_group); | ||
758 | } else | ||
759 | status = PTR_ERR(dev); | 769 | status = PTR_ERR(dev); |
770 | else | ||
771 | status = 0; | ||
760 | chip->exported = (status == 0); | 772 | chip->exported = (status == 0); |
761 | mutex_unlock(&sysfs_lock); | 773 | mutex_unlock(&sysfs_lock); |
762 | 774 | ||