diff options
author | Florian Fainelli <florian@openwrt.org> | 2009-05-07 12:21:02 +0000 |
---|---|---|
committer | Florian Fainelli <florian@openwrt.org> | 2009-05-07 12:21:02 +0000 |
commit | 324d10e617f2c04538364d721fd6b68beb8023c9 (patch) | |
tree | ed323b06e5ee74919a66813b54930396ee02d91a /target/linux/generic-2.6/patches-2.6.26/980-backport_gpio_sysfs_support.patch | |
parent | 6239eb2c7bf24099a7516cef5bb14ca61b1a0a58 (diff) | |
download | master-31e0f0ae-324d10e617f2c04538364d721fd6b68beb8023c9.tar.gz master-31e0f0ae-324d10e617f2c04538364d721fd6b68beb8023c9.tar.bz2 master-31e0f0ae-324d10e617f2c04538364d721fd6b68beb8023c9.zip |
remove 2.6.26 since there are no remaining candidates for it
SVN-Revision: 15666
Diffstat (limited to 'target/linux/generic-2.6/patches-2.6.26/980-backport_gpio_sysfs_support.patch')
-rw-r--r-- | target/linux/generic-2.6/patches-2.6.26/980-backport_gpio_sysfs_support.patch | 1026 |
1 files changed, 0 insertions, 1026 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.26/980-backport_gpio_sysfs_support.patch b/target/linux/generic-2.6/patches-2.6.26/980-backport_gpio_sysfs_support.patch deleted file mode 100644 index efacb2512b..0000000000 --- a/target/linux/generic-2.6/patches-2.6.26/980-backport_gpio_sysfs_support.patch +++ /dev/null @@ -1,1026 +0,0 @@ -From: David Brownell <dbrownell@users.sourceforge.net> -Date: Fri, 25 Jul 2008 08:46:07 +0000 (-0700) -Subject: gpio: sysfs interface -X-Git-Tag: v2.6.27-rc1~449 -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=d8f388d8dc8d4f36539dd37c1fff62cc404ea0fc - -gpio: sysfs interface - -This adds a simple sysfs interface for GPIOs. - - /sys/class/gpio - /export ... asks the kernel to export a GPIO to userspace - /unexport ... to return a GPIO to the kernel - /gpioN ... for each exported GPIO #N - /value ... always readable, writes fail for input GPIOs - /direction ... r/w as: in, out (default low); write high, low - /gpiochipN ... for each gpiochip; #N is its first GPIO - /base ... (r/o) same as N - /label ... (r/o) descriptive, not necessarily unique - /ngpio ... (r/o) number of GPIOs; numbered N .. N+(ngpio - 1) - -GPIOs claimed by kernel code may be exported by its owner using a new -gpio_export() call, which should be most useful for driver debugging. -Such exports may optionally be done without a "direction" attribute. - -Userspace may ask to take over a GPIO by writing to a sysfs control file, -helping to cope with incomplete board support or other "one-off" -requirements that don't merit full kernel support: - - echo 23 > /sys/class/gpio/export - ... will gpio_request(23, "sysfs") and gpio_export(23); - use /sys/class/gpio/gpio-23/direction to (re)configure it, - when that GPIO can be used as both input and output. - echo 23 > /sys/class/gpio/unexport - ... will gpio_free(23), when it was exported as above - -The extra D-space footprint is a few hundred bytes, except for the sysfs -resources associated with each exported GPIO. The additional I-space -footprint is about two thirds of the current size of gpiolib (!). Since -no /dev node creation is involved, no "udev" support is needed. - -Related changes: - - * This adds a device pointer to "struct gpio_chip". When GPIO - providers initialize that, sysfs gpio class devices become children of - that device instead of being "virtual" devices. - - * The (few) gpio_chip providers which have such a device node have - been updated. - - * Some gpio_chip drivers also needed to update their module "owner" - field ... for which missing kerneldoc was added. - - * Some gpio_chips don't support input GPIOs. Those GPIOs are now - flagged appropriately when the chip is registered. - -Based on previous patches, and discussion both on and off LKML. - -A Documentation/ABI/testing/sysfs-gpio update is ready to submit once this -merges to mainline. - -[akpm@linux-foundation.org: a few maintenance build fixes] -Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> -Cc: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> -Cc: Greg KH <greg@kroah.com> -Cc: Kay Sievers <kay.sievers@vrfy.org> -Signed-off-by: Andrew Morton <akpm@linux-foundation.org> -Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> ---- - ---- a/Documentation/gpio.txt -+++ b/Documentation/gpio.txt -@@ -347,15 +347,12 @@ necessarily be nonportable. - Dynamic definition of GPIOs is not currently standard; for example, as - a side effect of configuring an add-on board with some GPIO expanders. - --These calls are purely for kernel space, but a userspace API could be built --on top of them. -- - - GPIO implementor's framework (OPTIONAL) - ======================================= - As noted earlier, there is an optional implementation framework making it - easier for platforms to support different kinds of GPIO controller using --the same programming interface. -+the same programming interface. This framework is called "gpiolib". - - As a debugging aid, if debugfs is available a /sys/kernel/debug/gpio file - will be found there. That will list all the controllers registered through -@@ -439,4 +436,120 @@ becomes available. That may mean the de - calls for that GPIO can work. One way to address such dependencies is for - such gpio_chip controllers to provide setup() and teardown() callbacks to - board specific code; those board specific callbacks would register devices --once all the necessary resources are available. -+once all the necessary resources are available, and remove them later when -+the GPIO controller device becomes unavailable. -+ -+ -+Sysfs Interface for Userspace (OPTIONAL) -+======================================== -+Platforms which use the "gpiolib" implementors framework may choose to -+configure a sysfs user interface to GPIOs. This is different from the -+debugfs interface, since it provides control over GPIO direction and -+value instead of just showing a gpio state summary. Plus, it could be -+present on production systems without debugging support. -+ -+Given approprate hardware documentation for the system, userspace could -+know for example that GPIO #23 controls the write protect line used to -+protect boot loader segments in flash memory. System upgrade procedures -+may need to temporarily remove that protection, first importing a GPIO, -+then changing its output state, then updating the code before re-enabling -+the write protection. In normal use, GPIO #23 would never be touched, -+and the kernel would have no need to know about it. -+ -+Again depending on appropriate hardware documentation, on some systems -+userspace GPIO can be used to determine system configuration data that -+standard kernels won't know about. And for some tasks, simple userspace -+GPIO drivers could be all that the system really needs. -+ -+Note that standard kernel drivers exist for common "LEDs and Buttons" -+GPIO tasks: "leds-gpio" and "gpio_keys", respectively. Use those -+instead of talking directly to the GPIOs; they integrate with kernel -+frameworks better than your userspace code could. -+ -+ -+Paths in Sysfs -+-------------- -+There are three kinds of entry in /sys/class/gpio: -+ -+ - Control interfaces used to get userspace control over GPIOs; -+ -+ - GPIOs themselves; and -+ -+ - GPIO controllers ("gpio_chip" instances). -+ -+That's in addition to standard files including the "device" symlink. -+ -+The control interfaces are write-only: -+ -+ /sys/class/gpio/ -+ -+ "export" ... Userspace may ask the kernel to export control of -+ a GPIO to userspace by writing its number to this file. -+ -+ Example: "echo 19 > export" will create a "gpio19" node -+ for GPIO #19, if that's not requested by kernel code. -+ -+ "unexport" ... Reverses the effect of exporting to userspace. -+ -+ Example: "echo 19 > unexport" will remove a "gpio19" -+ node exported using the "export" file. -+ -+GPIO signals have paths like /sys/class/gpio/gpio42/ (for GPIO #42) -+and have the following read/write attributes: -+ -+ /sys/class/gpio/gpioN/ -+ -+ "direction" ... reads as either "in" or "out". This value may -+ normally be written. Writing as "out" defaults to -+ initializing the value as low. To ensure glitch free -+ operation, values "low" and "high" may be written to -+ configure the GPIO as an output with that initial value. -+ -+ Note that this attribute *will not exist* if the kernel -+ doesn't support changing the direction of a GPIO, or -+ it was exported by kernel code that didn't explicitly -+ allow userspace to reconfigure this GPIO's direction. -+ -+ "value" ... reads as either 0 (low) or 1 (high). If the GPIO -+ is configured as an output, this value may be written; -+ any nonzero value is treated as high. -+ -+GPIO controllers have paths like /sys/class/gpio/chipchip42/ (for the -+controller implementing GPIOs starting at #42) and have the following -+read-only attributes: -+ -+ /sys/class/gpio/gpiochipN/ -+ -+ "base" ... same as N, the first GPIO managed by this chip -+ -+ "label" ... provided for diagnostics (not always unique) -+ -+ "ngpio" ... how many GPIOs this manges (N to N + ngpio - 1) -+ -+Board documentation should in most cases cover what GPIOs are used for -+what purposes. However, those numbers are not always stable; GPIOs on -+a daughtercard might be different depending on the base board being used, -+or other cards in the stack. In such cases, you may need to use the -+gpiochip nodes (possibly in conjunction with schematics) to determine -+the correct GPIO number to use for a given signal. -+ -+ -+Exporting from Kernel code -+-------------------------- -+Kernel code can explicitly manage exports of GPIOs which have already been -+requested using gpio_request(): -+ -+ /* export the GPIO to userspace */ -+ int gpio_export(unsigned gpio, bool direction_may_change); -+ -+ /* reverse gpio_export() */ -+ void gpio_unexport(); -+ -+After a kernel driver requests a GPIO, it may only be made available in -+the sysfs interface by gpio_export(). The driver can control whether the -+signal direction may change. This helps drivers prevent userspace code -+from accidentally clobbering important system state. -+ -+This explicit exporting can help with debugging (by making some kinds -+of experiments easier), or can provide an always-there interface that's -+suitable for documenting as part of a board support package. ---- a/arch/arm/plat-omap/gpio.c -+++ b/arch/arm/plat-omap/gpio.c -@@ -1488,6 +1488,9 @@ static int __init _omap_gpio_init(void) - bank->chip.set = gpio_set; - if (bank_is_mpuio(bank)) { - bank->chip.label = "mpuio"; -+#ifdef CONFIG_ARCH_OMAP1 -+ bank->chip.dev = &omap_mpuio_device.dev; -+#endif - bank->chip.base = OMAP_MPUIO(0); - } else { - bank->chip.label = "gpio"; ---- a/arch/avr32/mach-at32ap/pio.c -+++ b/arch/avr32/mach-at32ap/pio.c -@@ -358,6 +358,8 @@ static int __init pio_probe(struct platf - pio->chip.label = pio->name; - pio->chip.base = pdev->id * 32; - pio->chip.ngpio = 32; -+ pio->chip.dev = &pdev->dev; -+ pio->chip.owner = THIS_MODULE; - - pio->chip.direction_input = direction_input; - pio->chip.get = gpio_get; ---- a/drivers/gpio/Kconfig -+++ b/drivers/gpio/Kconfig -@@ -23,6 +23,21 @@ config DEBUG_GPIO - slower. The diagnostics help catch the type of setup errors - that are most common when setting up new platforms or boards. - -+config GPIO_SYSFS -+ bool "/sys/class/gpio/... (sysfs interface)" -+ depends on SYSFS && EXPERIMENTAL -+ help -+ Say Y here to add a sysfs interface for GPIOs. -+ -+ This is mostly useful to work around omissions in a system's -+ kernel support. Those are common in custom and semicustom -+ hardware assembled using standard kernels with a minimum of -+ custom patches. In those cases, userspace code may import -+ a given GPIO from the kernel, if no kernel driver requested it. -+ -+ Kernel drivers may also request that a particular GPIO be -+ exported to userspace; this can be useful when debugging. -+ - # put expanders in the right section, in alphabetical order - - comment "I2C GPIO expanders:" ---- a/drivers/gpio/gpiolib.c -+++ b/drivers/gpio/gpiolib.c -@@ -2,8 +2,11 @@ - #include <linux/module.h> - #include <linux/irq.h> - #include <linux/spinlock.h> -- --#include <asm/gpio.h> -+#include <linux/device.h> -+#include <linux/err.h> -+#include <linux/debugfs.h> -+#include <linux/seq_file.h> -+#include <linux/gpio.h> - - - /* Optional implementation infrastructure for GPIO interfaces. -@@ -44,6 +47,8 @@ struct gpio_desc { - #define FLAG_REQUESTED 0 - #define FLAG_IS_OUT 1 - #define FLAG_RESERVED 2 -+#define FLAG_EXPORT 3 /* protected by sysfs_lock */ -+#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ - - #ifdef CONFIG_DEBUG_FS - const char *label; -@@ -151,6 +156,486 @@ err: - return ret; - } - -+#ifdef CONFIG_GPIO_SYSFS -+ -+/* lock protects against unexport_gpio() being called while -+ * sysfs files are active. -+ */ -+static DEFINE_MUTEX(sysfs_lock); -+ -+/* -+ * /sys/class/gpio/gpioN... only for GPIOs that are exported -+ * /direction -+ * * MAY BE OMITTED if kernel won't allow direction changes -+ * * is read/write as "in" or "out" -+ * * may also be written as "high" or "low", initializing -+ * output value as specified ("out" implies "low") -+ * /value -+ * * always readable, subject to hardware behavior -+ * * may be writable, as zero/nonzero -+ * -+ * REVISIT there will likely be an attribute for configuring async -+ * notifications, e.g. to specify polling interval or IRQ trigger type -+ * that would for example trigger a poll() on the "value". -+ */ -+ -+static ssize_t gpio_direction_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ const struct gpio_desc *desc = dev_get_drvdata(dev); -+ ssize_t status; -+ -+ mutex_lock(&sysfs_lock); -+ -+ if (!test_bit(FLAG_EXPORT, &desc->flags)) -+ status = -EIO; -+ else -+ status = sprintf(buf, "%s\n", -+ test_bit(FLAG_IS_OUT, &desc->flags) -+ ? "out" : "in"); -+ -+ mutex_unlock(&sysfs_lock); -+ return status; -+} -+ -+static ssize_t gpio_direction_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ const struct gpio_desc *desc = dev_get_drvdata(dev); -+ unsigned gpio = desc - gpio_desc; -+ ssize_t status; -+ -+ mutex_lock(&sysfs_lock); -+ -+ if (!test_bit(FLAG_EXPORT, &desc->flags)) -+ status = -EIO; -+ else if (sysfs_streq(buf, "high")) -+ status = gpio_direction_output(gpio, 1); -+ else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) -+ status = gpio_direction_output(gpio, 0); -+ else if (sysfs_streq(buf, "in")) -+ status = gpio_direction_input(gpio); -+ else -+ status = -EINVAL; -+ -+ mutex_unlock(&sysfs_lock); -+ return status ? : size; -+} -+ -+static const DEVICE_ATTR(direction, 0644, -+ gpio_direction_show, gpio_direction_store); -+ -+static ssize_t gpio_value_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ const struct gpio_desc *desc = dev_get_drvdata(dev); -+ unsigned gpio = desc - gpio_desc; -+ ssize_t status; -+ -+ mutex_lock(&sysfs_lock); -+ -+ if (!test_bit(FLAG_EXPORT, &desc->flags)) -+ status = -EIO; -+ else -+ status = sprintf(buf, "%d\n", gpio_get_value_cansleep(gpio)); -+ -+ mutex_unlock(&sysfs_lock); -+ return status; -+} -+ -+static ssize_t gpio_value_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ const struct gpio_desc *desc = dev_get_drvdata(dev); -+ unsigned gpio = desc - gpio_desc; -+ ssize_t status; -+ -+ mutex_lock(&sysfs_lock); -+ -+ if (!test_bit(FLAG_EXPORT, &desc->flags)) -+ status = -EIO; -+ else if (!test_bit(FLAG_IS_OUT, &desc->flags)) -+ status = -EPERM; -+ else { -+ long value; -+ -+ status = strict_strtol(buf, 0, &value); -+ if (status == 0) { -+ gpio_set_value_cansleep(gpio, value != 0); -+ status = size; -+ } -+ } -+ -+ mutex_unlock(&sysfs_lock); -+ return status; -+} -+ -+static /*const*/ DEVICE_ATTR(value, 0644, -+ gpio_value_show, gpio_value_store); -+ -+static const struct attribute *gpio_attrs[] = { -+ &dev_attr_direction.attr, -+ &dev_attr_value.attr, -+ NULL, -+}; -+ -+static const struct attribute_group gpio_attr_group = { -+ .attrs = (struct attribute **) gpio_attrs, -+}; -+ -+/* -+ * /sys/class/gpio/gpiochipN/ -+ * /base ... matching gpio_chip.base (N) -+ * /label ... matching gpio_chip.label -+ * /ngpio ... matching gpio_chip.ngpio -+ */ -+ -+static ssize_t chip_base_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ const struct gpio_chip *chip = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%d\n", chip->base); -+} -+static DEVICE_ATTR(base, 0444, chip_base_show, NULL); -+ -+static ssize_t chip_label_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ const struct gpio_chip *chip = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%s\n", chip->label ? : ""); -+} -+static DEVICE_ATTR(label, 0444, chip_label_show, NULL); -+ -+static ssize_t chip_ngpio_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ const struct gpio_chip *chip = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%u\n", chip->ngpio); -+} -+static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); -+ -+static const struct attribute *gpiochip_attrs[] = { -+ &dev_attr_base.attr, -+ &dev_attr_label.attr, -+ &dev_attr_ngpio.attr, -+ NULL, -+}; -+ -+static const struct attribute_group gpiochip_attr_group = { -+ .attrs = (struct attribute **) gpiochip_attrs, -+}; -+ -+/* -+ * /sys/class/gpio/export ... write-only -+ * integer N ... number of GPIO to export (full access) -+ * /sys/class/gpio/unexport ... write-only -+ * integer N ... number of GPIO to unexport -+ */ -+static ssize_t export_store(struct class *class, const char *buf, size_t len) -+{ -+ long gpio; -+ int status; -+ -+ status = strict_strtol(buf, 0, &gpio); -+ if (status < 0) -+ goto done; -+ -+ /* No extra locking here; FLAG_SYSFS just signifies that the -+ * request and export were done by on behalf of userspace, so -+ * they may be undone on its behalf too. -+ */ -+ -+ status = gpio_request(gpio, "sysfs"); -+ if (status < 0) -+ goto done; -+ -+ status = gpio_export(gpio, true); -+ if (status < 0) -+ gpio_free(gpio); -+ else -+ set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags); -+ -+done: -+ if (status) -+ pr_debug("%s: status %d\n", __func__, status); -+ return status ? : len; -+} -+ -+static ssize_t unexport_store(struct class *class, const char *buf, size_t len) -+{ -+ long gpio; -+ int status; -+ -+ status = strict_strtol(buf, 0, &gpio); -+ if (status < 0) -+ goto done; -+ -+ status = -EINVAL; -+ -+ /* reject bogus commands (gpio_unexport ignores them) */ -+ if (!gpio_is_valid(gpio)) -+ goto done; -+ -+ /* No extra locking here; FLAG_SYSFS just signifies that the -+ * request and export were done by on behalf of userspace, so -+ * they may be undone on its behalf too. -+ */ -+ if (test_and_clear_bit(FLAG_SYSFS, &gpio_desc[gpio].flags)) { -+ status = 0; -+ gpio_free(gpio); -+ } -+done: -+ if (status) -+ pr_debug("%s: status %d\n", __func__, status); -+ return status ? : len; -+} -+ -+static struct class_attribute gpio_class_attrs[] = { -+ __ATTR(export, 0200, NULL, export_store), -+ __ATTR(unexport, 0200, NULL, unexport_store), -+ __ATTR_NULL, -+}; -+ -+static struct class gpio_class = { -+ .name = "gpio", -+ .owner = THIS_MODULE, -+ -+ .class_attrs = gpio_class_attrs, -+}; -+ -+ -+/** -+ * gpio_export - export a GPIO through sysfs -+ * @gpio: gpio to make available, already requested -+ * @direction_may_change: true if userspace may change gpio direction -+ * Context: arch_initcall or later -+ * -+ * When drivers want to make a GPIO accessible to userspace after they -+ * have requested it -- perhaps while debugging, or as part of their -+ * public interface -- they may use this routine. If the GPIO can -+ * change direction (some can't) and the caller allows it, userspace -+ * will see "direction" sysfs attribute which may be used to change -+ * the gpio's direction. A "value" attribute will always be provided. -+ * -+ * Returns zero on success, else an error. -+ */ -+int gpio_export(unsigned gpio, bool direction_may_change) -+{ -+ unsigned long flags; -+ struct gpio_desc *desc; -+ int status = -EINVAL; -+ -+ /* can't export until sysfs is available ... */ -+ if (!gpio_class.subsys.kobj.ktype) { -+ pr_debug("%s: called too early!\n", __func__); -+ return -ENOENT; -+ } -+ -+ if (!gpio_is_valid(gpio)) -+ goto done; -+ -+ mutex_lock(&sysfs_lock); -+ -+ spin_lock_irqsave(&gpio_lock, flags); -+ desc = &gpio_desc[gpio]; -+ if (test_bit(FLAG_REQUESTED, &desc->flags) -+ && !test_bit(FLAG_EXPORT, &desc->flags)) { -+ status = 0; -+ if (!desc->chip->direction_input -+ || !desc->chip->direction_output) -+ direction_may_change = false; -+ } -+ spin_unlock_irqrestore(&gpio_lock, flags); -+ -+ if (status == 0) { -+ struct device *dev; -+ -+ dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), -+ "gpio%d", gpio); -+ if (dev) { -+ dev_set_drvdata(dev, desc); -+ if (direction_may_change) -+ status = sysfs_create_group(&dev->kobj, -+ &gpio_attr_group); -+ else -+ status = device_create_file(dev, -+ &dev_attr_value); -+ if (status != 0) -+ device_unregister(dev); -+ } else -+ status = -ENODEV; -+ if (status == 0) -+ set_bit(FLAG_EXPORT, &desc->flags); -+ } -+ -+ mutex_unlock(&sysfs_lock); -+ -+done: -+ if (status) -+ pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); -+ -+ return status; -+} -+EXPORT_SYMBOL_GPL(gpio_export); -+ -+static int match_export(struct device *dev, void *data) -+{ -+ return dev_get_drvdata(dev) == data; -+} -+ -+/** -+ * gpio_unexport - reverse effect of gpio_export() -+ * @gpio: gpio to make unavailable -+ * -+ * This is implicit on gpio_free(). -+ */ -+void gpio_unexport(unsigned gpio) -+{ -+ struct gpio_desc *desc; -+ int status = -EINVAL; -+ -+ if (!gpio_is_valid(gpio)) -+ goto done; -+ -+ mutex_lock(&sysfs_lock); -+ -+ desc = &gpio_desc[gpio]; -+ if (test_bit(FLAG_EXPORT, &desc->flags)) { -+ struct device *dev = NULL; -+ -+ dev = class_find_device(&gpio_class, desc, match_export); -+ if (dev) { -+ dev_set_drvdata(dev, NULL); -+ clear_bit(FLAG_EXPORT, &desc->flags); -+ put_device(dev); -+ device_unregister(dev); -+ status = 0; -+ } else -+ status = -ENODEV; -+ } -+ -+ mutex_unlock(&sysfs_lock); -+done: -+ if (status) -+ pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); -+} -+EXPORT_SYMBOL_GPL(gpio_unexport); -+ -+static int gpiochip_export(struct gpio_chip *chip) -+{ -+ int status; -+ struct device *dev; -+ -+ /* Many systems register gpio chips for SOC support very early, -+ * before driver model support is available. In those cases we -+ * export this later, in gpiolib_sysfs_init() ... here we just -+ * verify that _some_ field of gpio_class got initialized. -+ */ -+ if (!gpio_class.subsys.kobj.ktype) -+ return 0; -+ -+ /* use chip->base for the ID; it's already known to be unique */ -+ mutex_lock(&sysfs_lock); -+ dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), -+ "gpiochip%d", chip->base); -+ if (dev) { -+ dev_set_drvdata(dev, chip); -+ status = sysfs_create_group(&dev->kobj, -+ &gpiochip_attr_group); -+ } else -+ status = -ENODEV; -+ chip->exported = (status == 0); -+ mutex_unlock(&sysfs_lock); -+ -+ if (status) { -+ unsigned long flags; -+ unsigned gpio; -+ -+ spin_lock_irqsave(&gpio_lock, flags); -+ gpio = chip->base; -+ while (gpio_desc[gpio].chip == chip) -+ gpio_desc[gpio++].chip = NULL; -+ spin_unlock_irqrestore(&gpio_lock, flags); -+ -+ pr_debug("%s: chip %s status %d\n", __func__, -+ chip->label, status); -+ } -+ -+ return status; -+} -+ -+static void gpiochip_unexport(struct gpio_chip *chip) -+{ -+ int status; -+ struct device *dev; -+ -+ mutex_lock(&sysfs_lock); -+ dev = class_find_device(&gpio_class, chip, match_export); -+ if (dev) { -+ dev_set_drvdata(dev, NULL); -+ put_device(dev); -+ device_unregister(dev); -+ chip->exported = 0; -+ status = 0; -+ } else -+ status = -ENODEV; -+ mutex_unlock(&sysfs_lock); -+ -+ if (status) -+ pr_debug("%s: chip %s status %d\n", __func__, -+ chip->label, status); -+} -+ -+static int __init gpiolib_sysfs_init(void) -+{ -+ int status; -+ unsigned long flags; -+ unsigned gpio; -+ -+ status = class_register(&gpio_class); -+ if (status < 0) -+ return status; -+ -+ /* Scan and register the gpio_chips which registered very -+ * early (e.g. before the class_register above was called). -+ * -+ * We run before arch_initcall() so chip->dev nodes can have -+ * registered, and so arch_initcall() can always gpio_export(). -+ */ -+ spin_lock_irqsave(&gpio_lock, flags); -+ for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { -+ struct gpio_chip *chip; -+ -+ chip = gpio_desc[gpio].chip; -+ if (!chip || chip->exported) -+ continue; -+ -+ spin_unlock_irqrestore(&gpio_lock, flags); -+ status = gpiochip_export(chip); -+ spin_lock_irqsave(&gpio_lock, flags); -+ } -+ spin_unlock_irqrestore(&gpio_lock, flags); -+ -+ -+ return status; -+} -+postcore_initcall(gpiolib_sysfs_init); -+ -+#else -+static inline int gpiochip_export(struct gpio_chip *chip) -+{ -+ return 0; -+} -+ -+static inline void gpiochip_unexport(struct gpio_chip *chip) -+{ -+} -+ -+#endif /* CONFIG_GPIO_SYSFS */ -+ - /** - * gpiochip_add() - register a gpio_chip - * @chip: the chip to register, with chip->base initialized -@@ -160,6 +645,11 @@ err: - * because the chip->base is invalid or already associated with a - * different chip. Otherwise it returns zero as a success code. - * -+ * When gpiochip_add() is called very early during boot, so that GPIOs -+ * can be freely used, the chip->dev device must be registered before -+ * the gpio framework's arch_initcall(). Otherwise sysfs initialization -+ * for GPIOs will fail rudely. -+ * - * If chip->base is negative, this requests dynamic assignment of - * a range of valid GPIOs. - */ -@@ -182,7 +672,7 @@ int gpiochip_add(struct gpio_chip *chip) - base = gpiochip_find_base(chip->ngpio); - if (base < 0) { - status = base; -- goto fail_unlock; -+ goto unlock; - } - chip->base = base; - } -@@ -197,12 +687,23 @@ int gpiochip_add(struct gpio_chip *chip) - if (status == 0) { - for (id = base; id < base + chip->ngpio; id++) { - gpio_desc[id].chip = chip; -- gpio_desc[id].flags = 0; -+ -+ /* REVISIT: most hardware initializes GPIOs as -+ * inputs (often with pullups enabled) so power -+ * usage is minimized. Linux code should set the -+ * gpio direction first thing; but until it does, -+ * we may expose the wrong direction in sysfs. -+ */ -+ gpio_desc[id].flags = !chip->direction_input -+ ? (1 << FLAG_IS_OUT) -+ : 0; - } - } - --fail_unlock: -+unlock: - spin_unlock_irqrestore(&gpio_lock, flags); -+ if (status == 0) -+ status = gpiochip_export(chip); - fail: - /* failures here can mean systems won't boot... */ - if (status) -@@ -239,6 +740,10 @@ int gpiochip_remove(struct gpio_chip *ch - } - - spin_unlock_irqrestore(&gpio_lock, flags); -+ -+ if (status == 0) -+ gpiochip_unexport(chip); -+ - return status; - } - EXPORT_SYMBOL_GPL(gpiochip_remove); -@@ -296,6 +801,8 @@ void gpio_free(unsigned gpio) - return; - } - -+ gpio_unexport(gpio); -+ - spin_lock_irqsave(&gpio_lock, flags); - - desc = &gpio_desc[gpio]; -@@ -534,10 +1041,6 @@ EXPORT_SYMBOL_GPL(gpio_set_value_canslee - - #ifdef CONFIG_DEBUG_FS - --#include <linux/debugfs.h> --#include <linux/seq_file.h> -- -- - static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) - { - unsigned i; -@@ -614,17 +1117,28 @@ static int gpiolib_show(struct seq_file - /* REVISIT this isn't locked against gpio_chip removal ... */ - - for (gpio = 0; gpio_is_valid(gpio); gpio++) { -+ struct device *dev; -+ - if (chip == gpio_desc[gpio].chip) - continue; - chip = gpio_desc[gpio].chip; - if (!chip) - continue; - -- seq_printf(s, "%sGPIOs %d-%d, %s%s:\n", -+ seq_printf(s, "%sGPIOs %d-%d", - started ? "\n" : "", -- chip->base, chip->base + chip->ngpio - 1, -- chip->label ? : "generic", -- chip->can_sleep ? ", can sleep" : ""); -+ chip->base, chip->base + chip->ngpio - 1); -+ dev = chip->dev; -+ if (dev) -+ seq_printf(s, ", %s/%s", -+ dev->bus ? dev->bus->name : "no-bus", -+ dev->bus_id); -+ if (chip->label) -+ seq_printf(s, ", %s", chip->label); -+ if (chip->can_sleep) -+ seq_printf(s, ", can sleep"); -+ seq_printf(s, ":\n"); -+ - started = 1; - if (chip->dbg_show) - chip->dbg_show(s, chip); ---- a/drivers/gpio/mcp23s08.c -+++ b/drivers/gpio/mcp23s08.c -@@ -239,6 +239,7 @@ static int mcp23s08_probe(struct spi_dev - mcp->chip.base = pdata->base; - mcp->chip.ngpio = 8; - mcp->chip.can_sleep = 1; -+ mcp->chip.dev = &spi->dev; - mcp->chip.owner = THIS_MODULE; - - spi_set_drvdata(spi, mcp); ---- a/drivers/gpio/pca953x.c -+++ b/drivers/gpio/pca953x.c -@@ -188,6 +188,7 @@ static void pca953x_setup_gpio(struct pc - gc->base = chip->gpio_start; - gc->ngpio = gpios; - gc->label = chip->client->name; -+ gc->dev = &chip->client->dev; - gc->owner = THIS_MODULE; - } - ---- a/drivers/gpio/pcf857x.c -+++ b/drivers/gpio/pcf857x.c -@@ -175,6 +175,7 @@ static int pcf857x_probe(struct i2c_clie - - gpio->chip.base = pdata->gpio_base; - gpio->chip.can_sleep = 1; -+ gpio->chip.dev = &client->dev; - gpio->chip.owner = THIS_MODULE; - - /* NOTE: the OnSemi jlc1562b is also largely compatible with ---- a/drivers/i2c/chips/tps65010.c -+++ b/drivers/i2c/chips/tps65010.c -@@ -636,6 +636,8 @@ static int tps65010_probe(struct i2c_cli - tps->outmask = board->outmask; - - tps->chip.label = client->name; -+ tps->chip.dev = &client->dev; -+ tps->chip.owner = THIS_MODULE; - - tps->chip.set = tps65010_gpio_set; - tps->chip.direction_output = tps65010_output; ---- a/drivers/mfd/htc-egpio.c -+++ b/drivers/mfd/htc-egpio.c -@@ -318,6 +318,8 @@ static int __init egpio_probe(struct pla - ei->chip[i].dev = &(pdev->dev); - chip = &(ei->chip[i].chip); - chip->label = "htc-egpio"; -+ chip->dev = &pdev->dev; -+ chip->owner = THIS_MODULE; - chip->get = egpio_get; - chip->set = egpio_set; - chip->direction_input = egpio_direction_input; ---- a/include/asm-generic/gpio.h -+++ b/include/asm-generic/gpio.h -@@ -32,6 +32,8 @@ struct module; - /** - * struct gpio_chip - abstract a GPIO controller - * @label: for diagnostics -+ * @dev: optional device providing the GPIOs -+ * @owner: helps prevent removal of modules exporting active GPIOs - * @direction_input: configures signal "offset" as input, or returns error - * @get: returns value for signal "offset"; for output signals this - * returns either the value actually sensed, or zero -@@ -59,6 +61,7 @@ struct module; - */ - struct gpio_chip { - char *label; -+ struct device *dev; - struct module *owner; - - int (*direction_input)(struct gpio_chip *chip, -@@ -74,6 +77,7 @@ struct gpio_chip { - int base; - u16 ngpio; - unsigned can_sleep:1; -+ unsigned exported:1; - }; - - extern const char *gpiochip_is_requested(struct gpio_chip *chip, -@@ -108,7 +112,18 @@ extern void __gpio_set_value(unsigned gp - extern int __gpio_cansleep(unsigned gpio); - - --#else -+#ifdef CONFIG_GPIO_SYSFS -+ -+/* -+ * A sysfs interface can be exported by individual drivers if they want, -+ * but more typically is configured entirely from userspace. -+ */ -+extern int gpio_export(unsigned gpio, bool direction_may_change); -+extern void gpio_unexport(unsigned gpio); -+ -+#endif /* CONFIG_GPIO_SYSFS */ -+ -+#else /* !CONFIG_HAVE_GPIO_LIB */ - - static inline int gpio_is_valid(int number) - { -@@ -137,6 +152,22 @@ static inline void gpio_set_value_cansle - gpio_set_value(gpio, value); - } - --#endif -+#endif /* !CONFIG_HAVE_GPIO_LIB */ -+ -+#ifndef CONFIG_GPIO_SYSFS -+ -+#include <asm/errno.h> -+ -+/* sysfs support is only available with gpiolib, where it's optional */ -+ -+static inline int gpio_export(unsigned gpio, bool direction_may_change) -+{ -+ return -ENOSYS; -+} -+ -+static inline void gpio_unexport(unsigned gpio) -+{ -+} -+#endif /* CONFIG_GPIO_SYSFS */ - - #endif /* _ASM_GENERIC_GPIO_H */ ---- a/include/linux/gpio.h -+++ b/include/linux/gpio.h -@@ -79,6 +79,19 @@ static inline void gpio_set_value_cansle - WARN_ON(1); - } - -+static inline int gpio_export(unsigned gpio, bool direction_may_change) -+{ -+ /* GPIO can never have been requested or set as {in,out}put */ -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+static inline void gpio_unexport(unsigned gpio) -+{ -+ /* GPIO can never have been exported */ -+ WARN_ON(1); -+} -+ - static inline int gpio_to_irq(unsigned gpio) - { - /* GPIO can never have been requested or set as input */ |