diff options
author | Johan Hovold <johan@kernel.org> | 2015-05-04 11:10:37 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-05-12 04:47:12 -0400 |
commit | c43960fbcc514b0ec8169a66ba9955608e6775a7 (patch) | |
tree | 10c73074ebb45203f2d7446ed7c24f06a19ce8e1 /drivers/gpio/gpiolib-sysfs.c | |
parent | f0b7866a02370d9a03b0be497b9f88d982b8b67d (diff) |
gpio: sysfs: add gpiod class-device data
Add gpiod class-device data.
This is a first step in getting rid of the insane gpio-descriptor flag
overloading, backward irq-interface implementation, and course grained
sysfs-interface locking (a single static mutex for every operation on
all exported gpios in a system).
Signed-off-by: Johan Hovold <johan@kernel.org>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib-sysfs.c')
-rw-r--r-- | drivers/gpio/gpiolib-sysfs.c | 62 |
1 files changed, 46 insertions, 16 deletions
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 10baf31efe74..097e7e539c9d 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c | |||
@@ -6,9 +6,14 @@ | |||
6 | #include <linux/gpio/driver.h> | 6 | #include <linux/gpio/driver.h> |
7 | #include <linux/interrupt.h> | 7 | #include <linux/interrupt.h> |
8 | #include <linux/kdev_t.h> | 8 | #include <linux/kdev_t.h> |
9 | #include <linux/slab.h> | ||
9 | 10 | ||
10 | #include "gpiolib.h" | 11 | #include "gpiolib.h" |
11 | 12 | ||
13 | struct gpiod_data { | ||
14 | struct gpio_desc *desc; | ||
15 | }; | ||
16 | |||
12 | static DEFINE_IDR(dirent_idr); | 17 | static DEFINE_IDR(dirent_idr); |
13 | 18 | ||
14 | 19 | ||
@@ -41,7 +46,8 @@ static DEFINE_MUTEX(sysfs_lock); | |||
41 | static ssize_t direction_show(struct device *dev, | 46 | static ssize_t direction_show(struct device *dev, |
42 | struct device_attribute *attr, char *buf) | 47 | struct device_attribute *attr, char *buf) |
43 | { | 48 | { |
44 | struct gpio_desc *desc = dev_get_drvdata(dev); | 49 | struct gpiod_data *data = dev_get_drvdata(dev); |
50 | struct gpio_desc *desc = data->desc; | ||
45 | ssize_t status; | 51 | ssize_t status; |
46 | 52 | ||
47 | mutex_lock(&sysfs_lock); | 53 | mutex_lock(&sysfs_lock); |
@@ -58,7 +64,8 @@ static ssize_t direction_show(struct device *dev, | |||
58 | static ssize_t direction_store(struct device *dev, | 64 | static ssize_t direction_store(struct device *dev, |
59 | struct device_attribute *attr, const char *buf, size_t size) | 65 | struct device_attribute *attr, const char *buf, size_t size) |
60 | { | 66 | { |
61 | struct gpio_desc *desc = dev_get_drvdata(dev); | 67 | struct gpiod_data *data = dev_get_drvdata(dev); |
68 | struct gpio_desc *desc = data->desc; | ||
62 | ssize_t status; | 69 | ssize_t status; |
63 | 70 | ||
64 | mutex_lock(&sysfs_lock); | 71 | mutex_lock(&sysfs_lock); |
@@ -80,7 +87,8 @@ static DEVICE_ATTR_RW(direction); | |||
80 | static ssize_t value_show(struct device *dev, | 87 | static ssize_t value_show(struct device *dev, |
81 | struct device_attribute *attr, char *buf) | 88 | struct device_attribute *attr, char *buf) |
82 | { | 89 | { |
83 | struct gpio_desc *desc = dev_get_drvdata(dev); | 90 | struct gpiod_data *data = dev_get_drvdata(dev); |
91 | struct gpio_desc *desc = data->desc; | ||
84 | ssize_t status; | 92 | ssize_t status; |
85 | 93 | ||
86 | mutex_lock(&sysfs_lock); | 94 | mutex_lock(&sysfs_lock); |
@@ -94,7 +102,8 @@ static ssize_t value_show(struct device *dev, | |||
94 | static ssize_t value_store(struct device *dev, | 102 | static ssize_t value_store(struct device *dev, |
95 | struct device_attribute *attr, const char *buf, size_t size) | 103 | struct device_attribute *attr, const char *buf, size_t size) |
96 | { | 104 | { |
97 | struct gpio_desc *desc = dev_get_drvdata(dev); | 105 | struct gpiod_data *data = dev_get_drvdata(dev); |
106 | struct gpio_desc *desc = data->desc; | ||
98 | ssize_t status; | 107 | ssize_t status; |
99 | 108 | ||
100 | mutex_lock(&sysfs_lock); | 109 | mutex_lock(&sysfs_lock); |
@@ -225,7 +234,8 @@ static const struct { | |||
225 | static ssize_t edge_show(struct device *dev, | 234 | static ssize_t edge_show(struct device *dev, |
226 | struct device_attribute *attr, char *buf) | 235 | struct device_attribute *attr, char *buf) |
227 | { | 236 | { |
228 | const struct gpio_desc *desc = dev_get_drvdata(dev); | 237 | struct gpiod_data *data = dev_get_drvdata(dev); |
238 | struct gpio_desc *desc = data->desc; | ||
229 | unsigned long mask; | 239 | unsigned long mask; |
230 | ssize_t status = 0; | 240 | ssize_t status = 0; |
231 | int i; | 241 | int i; |
@@ -247,7 +257,8 @@ static ssize_t edge_show(struct device *dev, | |||
247 | static ssize_t edge_store(struct device *dev, | 257 | static ssize_t edge_store(struct device *dev, |
248 | struct device_attribute *attr, const char *buf, size_t size) | 258 | struct device_attribute *attr, const char *buf, size_t size) |
249 | { | 259 | { |
250 | struct gpio_desc *desc = dev_get_drvdata(dev); | 260 | struct gpiod_data *data = dev_get_drvdata(dev); |
261 | struct gpio_desc *desc = data->desc; | ||
251 | ssize_t status; | 262 | ssize_t status; |
252 | int i; | 263 | int i; |
253 | 264 | ||
@@ -297,7 +308,8 @@ static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev, | |||
297 | static ssize_t active_low_show(struct device *dev, | 308 | static ssize_t active_low_show(struct device *dev, |
298 | struct device_attribute *attr, char *buf) | 309 | struct device_attribute *attr, char *buf) |
299 | { | 310 | { |
300 | const struct gpio_desc *desc = dev_get_drvdata(dev); | 311 | struct gpiod_data *data = dev_get_drvdata(dev); |
312 | struct gpio_desc *desc = data->desc; | ||
301 | ssize_t status; | 313 | ssize_t status; |
302 | 314 | ||
303 | mutex_lock(&sysfs_lock); | 315 | mutex_lock(&sysfs_lock); |
@@ -313,7 +325,8 @@ static ssize_t active_low_show(struct device *dev, | |||
313 | static ssize_t active_low_store(struct device *dev, | 325 | static ssize_t active_low_store(struct device *dev, |
314 | struct device_attribute *attr, const char *buf, size_t size) | 326 | struct device_attribute *attr, const char *buf, size_t size) |
315 | { | 327 | { |
316 | struct gpio_desc *desc = dev_get_drvdata(dev); | 328 | struct gpiod_data *data = dev_get_drvdata(dev); |
329 | struct gpio_desc *desc = data->desc; | ||
317 | ssize_t status; | 330 | ssize_t status; |
318 | long value; | 331 | long value; |
319 | 332 | ||
@@ -333,7 +346,8 @@ static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr, | |||
333 | int n) | 346 | int n) |
334 | { | 347 | { |
335 | struct device *dev = container_of(kobj, struct device, kobj); | 348 | struct device *dev = container_of(kobj, struct device, kobj); |
336 | struct gpio_desc *desc = dev_get_drvdata(dev); | 349 | struct gpiod_data *data = dev_get_drvdata(dev); |
350 | struct gpio_desc *desc = data->desc; | ||
337 | umode_t mode = attr->mode; | 351 | umode_t mode = attr->mode; |
338 | bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags); | 352 | bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags); |
339 | 353 | ||
@@ -525,6 +539,7 @@ static struct class gpio_class = { | |||
525 | int gpiod_export(struct gpio_desc *desc, bool direction_may_change) | 539 | int gpiod_export(struct gpio_desc *desc, bool direction_may_change) |
526 | { | 540 | { |
527 | struct gpio_chip *chip; | 541 | struct gpio_chip *chip; |
542 | struct gpiod_data *data; | ||
528 | unsigned long flags; | 543 | unsigned long flags; |
529 | int status; | 544 | int status; |
530 | const char *ioname = NULL; | 545 | const char *ioname = NULL; |
@@ -549,7 +564,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) | |||
549 | /* check if chip is being removed */ | 564 | /* check if chip is being removed */ |
550 | if (!chip || !chip->cdev) { | 565 | if (!chip || !chip->cdev) { |
551 | status = -ENODEV; | 566 | status = -ENODEV; |
552 | goto fail_unlock; | 567 | goto err_unlock; |
553 | } | 568 | } |
554 | 569 | ||
555 | spin_lock_irqsave(&gpio_lock, flags); | 570 | spin_lock_irqsave(&gpio_lock, flags); |
@@ -561,7 +576,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) | |||
561 | test_bit(FLAG_REQUESTED, &desc->flags), | 576 | test_bit(FLAG_REQUESTED, &desc->flags), |
562 | test_bit(FLAG_EXPORT, &desc->flags)); | 577 | test_bit(FLAG_EXPORT, &desc->flags)); |
563 | status = -EPERM; | 578 | status = -EPERM; |
564 | goto fail_unlock; | 579 | goto err_unlock; |
565 | } | 580 | } |
566 | 581 | ||
567 | if (chip->direction_input && chip->direction_output && | 582 | if (chip->direction_input && chip->direction_output && |
@@ -571,33 +586,45 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) | |||
571 | 586 | ||
572 | spin_unlock_irqrestore(&gpio_lock, flags); | 587 | spin_unlock_irqrestore(&gpio_lock, flags); |
573 | 588 | ||
589 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
590 | if (!data) { | ||
591 | status = -ENOMEM; | ||
592 | goto err_unlock; | ||
593 | } | ||
594 | |||
595 | data->desc = desc; | ||
596 | |||
574 | offset = gpio_chip_hwgpio(desc); | 597 | offset = gpio_chip_hwgpio(desc); |
575 | if (chip->names && chip->names[offset]) | 598 | if (chip->names && chip->names[offset]) |
576 | ioname = chip->names[offset]; | 599 | ioname = chip->names[offset]; |
577 | 600 | ||
578 | dev = device_create_with_groups(&gpio_class, chip->dev, | 601 | dev = device_create_with_groups(&gpio_class, chip->dev, |
579 | MKDEV(0, 0), desc, gpio_groups, | 602 | MKDEV(0, 0), data, gpio_groups, |
580 | ioname ? ioname : "gpio%u", | 603 | ioname ? ioname : "gpio%u", |
581 | desc_to_gpio(desc)); | 604 | desc_to_gpio(desc)); |
582 | if (IS_ERR(dev)) { | 605 | if (IS_ERR(dev)) { |
583 | status = PTR_ERR(dev); | 606 | status = PTR_ERR(dev); |
584 | goto fail_unlock; | 607 | goto err_free_data; |
585 | } | 608 | } |
586 | 609 | ||
587 | set_bit(FLAG_EXPORT, &desc->flags); | 610 | set_bit(FLAG_EXPORT, &desc->flags); |
588 | mutex_unlock(&sysfs_lock); | 611 | mutex_unlock(&sysfs_lock); |
589 | return 0; | 612 | return 0; |
590 | 613 | ||
591 | fail_unlock: | 614 | err_free_data: |
615 | kfree(data); | ||
616 | err_unlock: | ||
592 | mutex_unlock(&sysfs_lock); | 617 | mutex_unlock(&sysfs_lock); |
593 | gpiod_dbg(desc, "%s: status %d\n", __func__, status); | 618 | gpiod_dbg(desc, "%s: status %d\n", __func__, status); |
594 | return status; | 619 | return status; |
595 | } | 620 | } |
596 | EXPORT_SYMBOL_GPL(gpiod_export); | 621 | EXPORT_SYMBOL_GPL(gpiod_export); |
597 | 622 | ||
598 | static int match_export(struct device *dev, const void *data) | 623 | static int match_export(struct device *dev, const void *desc) |
599 | { | 624 | { |
600 | return dev_get_drvdata(dev) == data; | 625 | struct gpiod_data *data = dev_get_drvdata(dev); |
626 | |||
627 | return data->desc == desc; | ||
601 | } | 628 | } |
602 | 629 | ||
603 | /** | 630 | /** |
@@ -653,6 +680,7 @@ EXPORT_SYMBOL_GPL(gpiod_export_link); | |||
653 | */ | 680 | */ |
654 | void gpiod_unexport(struct gpio_desc *desc) | 681 | void gpiod_unexport(struct gpio_desc *desc) |
655 | { | 682 | { |
683 | struct gpiod_data *data; | ||
656 | int status = 0; | 684 | int status = 0; |
657 | struct device *dev = NULL; | 685 | struct device *dev = NULL; |
658 | 686 | ||
@@ -676,6 +704,7 @@ void gpiod_unexport(struct gpio_desc *desc) | |||
676 | mutex_unlock(&sysfs_lock); | 704 | mutex_unlock(&sysfs_lock); |
677 | 705 | ||
678 | if (dev) { | 706 | if (dev) { |
707 | data = dev_get_drvdata(dev); | ||
679 | device_unregister(dev); | 708 | device_unregister(dev); |
680 | /* | 709 | /* |
681 | * Release irq after deregistration to prevent race with | 710 | * Release irq after deregistration to prevent race with |
@@ -683,6 +712,7 @@ void gpiod_unexport(struct gpio_desc *desc) | |||
683 | */ | 712 | */ |
684 | gpio_setup_irq(desc, dev, 0); | 713 | gpio_setup_irq(desc, dev, 0); |
685 | put_device(dev); | 714 | put_device(dev); |
715 | kfree(data); | ||
686 | } | 716 | } |
687 | 717 | ||
688 | if (status) | 718 | if (status) |