mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
			
			
This commit is contained in:
		
							parent
							
								
									8b6dd98682
								
							
						
					
					
						commit
						d8f388d8dc
					
				
					 12 changed files with 712 additions and 20 deletions
				
			
		| 
						 | 
					@ -347,15 +347,12 @@ necessarily be nonportable.
 | 
				
			||||||
Dynamic definition of GPIOs is not currently standard; for example, as
 | 
					Dynamic definition of GPIOs is not currently standard; for example, as
 | 
				
			||||||
a side effect of configuring an add-on board with some GPIO expanders.
 | 
					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)
 | 
					GPIO implementor's framework (OPTIONAL)
 | 
				
			||||||
=======================================
 | 
					=======================================
 | 
				
			||||||
As noted earlier, there is an optional implementation framework making it
 | 
					As noted earlier, there is an optional implementation framework making it
 | 
				
			||||||
easier for platforms to support different kinds of GPIO controller using
 | 
					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
 | 
					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
 | 
					will be found there.  That will list all the controllers registered through
 | 
				
			||||||
| 
						 | 
					@ -439,4 +436,120 @@ becomes available.  That may mean the device should not be registered until
 | 
				
			||||||
calls for that GPIO can work.  One way to address such dependencies is for
 | 
					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
 | 
					such gpio_chip controllers to provide setup() and teardown() callbacks to
 | 
				
			||||||
board specific code; those board specific callbacks would register devices
 | 
					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.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1488,6 +1488,9 @@ static int __init _omap_gpio_init(void)
 | 
				
			||||||
		bank->chip.set = gpio_set;
 | 
							bank->chip.set = gpio_set;
 | 
				
			||||||
		if (bank_is_mpuio(bank)) {
 | 
							if (bank_is_mpuio(bank)) {
 | 
				
			||||||
			bank->chip.label = "mpuio";
 | 
								bank->chip.label = "mpuio";
 | 
				
			||||||
 | 
					#ifdef CONFIG_ARCH_OMAP1
 | 
				
			||||||
 | 
								bank->chip.dev = &omap_mpuio_device.dev;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
			bank->chip.base = OMAP_MPUIO(0);
 | 
								bank->chip.base = OMAP_MPUIO(0);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			bank->chip.label = "gpio";
 | 
								bank->chip.label = "gpio";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -360,6 +360,8 @@ static int __init pio_probe(struct platform_device *pdev)
 | 
				
			||||||
	pio->chip.label = pio->name;
 | 
						pio->chip.label = pio->name;
 | 
				
			||||||
	pio->chip.base = pdev->id * 32;
 | 
						pio->chip.base = pdev->id * 32;
 | 
				
			||||||
	pio->chip.ngpio = 32;
 | 
						pio->chip.ngpio = 32;
 | 
				
			||||||
 | 
						pio->chip.dev = &pdev->dev;
 | 
				
			||||||
 | 
						pio->chip.owner = THIS_MODULE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pio->chip.direction_input = direction_input;
 | 
						pio->chip.direction_input = direction_input;
 | 
				
			||||||
	pio->chip.get = gpio_get;
 | 
						pio->chip.get = gpio_get;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,21 @@ config DEBUG_GPIO
 | 
				
			||||||
	  slower.  The diagnostics help catch the type of setup errors
 | 
						  slower.  The diagnostics help catch the type of setup errors
 | 
				
			||||||
	  that are most common when setting up new platforms or boards.
 | 
						  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
 | 
					# put expanders in the right section, in alphabetical order
 | 
				
			||||||
 | 
					
 | 
				
			||||||
comment "I2C GPIO expanders:"
 | 
					comment "I2C GPIO expanders:"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,11 @@
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/irq.h>
 | 
					#include <linux/irq.h>
 | 
				
			||||||
#include <linux/spinlock.h>
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					#include <linux/device.h>
 | 
				
			||||||
#include <asm/gpio.h>
 | 
					#include <linux/err.h>
 | 
				
			||||||
 | 
					#include <linux/debugfs.h>
 | 
				
			||||||
 | 
					#include <linux/seq_file.h>
 | 
				
			||||||
 | 
					#include <linux/gpio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Optional implementation infrastructure for GPIO interfaces.
 | 
					/* Optional implementation infrastructure for GPIO interfaces.
 | 
				
			||||||
| 
						 | 
					@ -44,6 +47,8 @@ struct gpio_desc {
 | 
				
			||||||
#define FLAG_REQUESTED	0
 | 
					#define FLAG_REQUESTED	0
 | 
				
			||||||
#define FLAG_IS_OUT	1
 | 
					#define FLAG_IS_OUT	1
 | 
				
			||||||
#define FLAG_RESERVED	2
 | 
					#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
 | 
					#ifdef CONFIG_DEBUG_FS
 | 
				
			||||||
	const char		*label;
 | 
						const char		*label;
 | 
				
			||||||
| 
						 | 
					@ -151,6 +156,482 @@ int __init gpiochip_reserve(int start, int ngpio)
 | 
				
			||||||
	return ret;
 | 
						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.p) {
 | 
				
			||||||
 | 
							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),
 | 
				
			||||||
 | 
										desc, "gpio%d", gpio);
 | 
				
			||||||
 | 
							if (dev) {
 | 
				
			||||||
 | 
								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, NULL, desc, match_export);
 | 
				
			||||||
 | 
							if (dev) {
 | 
				
			||||||
 | 
								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.p)
 | 
				
			||||||
 | 
							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), chip,
 | 
				
			||||||
 | 
									"gpiochip%d", chip->base);
 | 
				
			||||||
 | 
						if (dev) {
 | 
				
			||||||
 | 
							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, NULL, chip, match_export);
 | 
				
			||||||
 | 
						if (dev) {
 | 
				
			||||||
 | 
							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
 | 
					 * gpiochip_add() - register a gpio_chip
 | 
				
			||||||
 * @chip: the chip to register, with chip->base initialized
 | 
					 * @chip: the chip to register, with chip->base initialized
 | 
				
			||||||
| 
						 | 
					@ -160,6 +641,11 @@ int __init gpiochip_reserve(int start, int ngpio)
 | 
				
			||||||
 * because the chip->base is invalid or already associated with a
 | 
					 * because the chip->base is invalid or already associated with a
 | 
				
			||||||
 * different chip.  Otherwise it returns zero as a success code.
 | 
					 * 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
 | 
					 * If chip->base is negative, this requests dynamic assignment of
 | 
				
			||||||
 * a range of valid GPIOs.
 | 
					 * a range of valid GPIOs.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -182,7 +668,7 @@ int gpiochip_add(struct gpio_chip *chip)
 | 
				
			||||||
		base = gpiochip_find_base(chip->ngpio);
 | 
							base = gpiochip_find_base(chip->ngpio);
 | 
				
			||||||
		if (base < 0) {
 | 
							if (base < 0) {
 | 
				
			||||||
			status = base;
 | 
								status = base;
 | 
				
			||||||
			goto fail_unlock;
 | 
								goto unlock;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		chip->base = base;
 | 
							chip->base = base;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -197,12 +683,23 @@ int gpiochip_add(struct gpio_chip *chip)
 | 
				
			||||||
	if (status == 0) {
 | 
						if (status == 0) {
 | 
				
			||||||
		for (id = base; id < base + chip->ngpio; id++) {
 | 
							for (id = base; id < base + chip->ngpio; id++) {
 | 
				
			||||||
			gpio_desc[id].chip = chip;
 | 
								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);
 | 
						spin_unlock_irqrestore(&gpio_lock, flags);
 | 
				
			||||||
 | 
						if (status == 0)
 | 
				
			||||||
 | 
							status = gpiochip_export(chip);
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
	/* failures here can mean systems won't boot... */
 | 
						/* failures here can mean systems won't boot... */
 | 
				
			||||||
	if (status)
 | 
						if (status)
 | 
				
			||||||
| 
						 | 
					@ -239,6 +736,10 @@ int gpiochip_remove(struct gpio_chip *chip)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_unlock_irqrestore(&gpio_lock, flags);
 | 
						spin_unlock_irqrestore(&gpio_lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (status == 0)
 | 
				
			||||||
 | 
							gpiochip_unexport(chip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(gpiochip_remove);
 | 
					EXPORT_SYMBOL_GPL(gpiochip_remove);
 | 
				
			||||||
| 
						 | 
					@ -296,6 +797,8 @@ void gpio_free(unsigned gpio)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpio_unexport(gpio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irqsave(&gpio_lock, flags);
 | 
						spin_lock_irqsave(&gpio_lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	desc = &gpio_desc[gpio];
 | 
						desc = &gpio_desc[gpio];
 | 
				
			||||||
| 
						 | 
					@ -534,10 +1037,6 @@ EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_DEBUG_FS
 | 
					#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)
 | 
					static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned		i;
 | 
						unsigned		i;
 | 
				
			||||||
| 
						 | 
					@ -614,17 +1113,28 @@ static int gpiolib_show(struct seq_file *s, void *unused)
 | 
				
			||||||
	/* REVISIT this isn't locked against gpio_chip removal ... */
 | 
						/* REVISIT this isn't locked against gpio_chip removal ... */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (gpio = 0; gpio_is_valid(gpio); gpio++) {
 | 
						for (gpio = 0; gpio_is_valid(gpio); gpio++) {
 | 
				
			||||||
 | 
							struct device *dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (chip == gpio_desc[gpio].chip)
 | 
							if (chip == gpio_desc[gpio].chip)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		chip = gpio_desc[gpio].chip;
 | 
							chip = gpio_desc[gpio].chip;
 | 
				
			||||||
		if (!chip)
 | 
							if (!chip)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		seq_printf(s, "%sGPIOs %d-%d, %s%s:\n",
 | 
							seq_printf(s, "%sGPIOs %d-%d",
 | 
				
			||||||
				started ? "\n" : "",
 | 
									started ? "\n" : "",
 | 
				
			||||||
				chip->base, chip->base + chip->ngpio - 1,
 | 
									chip->base, chip->base + chip->ngpio - 1);
 | 
				
			||||||
				chip->label ? : "generic",
 | 
							dev = chip->dev;
 | 
				
			||||||
				chip->can_sleep ? ", can sleep" : "");
 | 
							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;
 | 
							started = 1;
 | 
				
			||||||
		if (chip->dbg_show)
 | 
							if (chip->dbg_show)
 | 
				
			||||||
			chip->dbg_show(s, chip);
 | 
								chip->dbg_show(s, chip);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -239,6 +239,7 @@ static int mcp23s08_probe(struct spi_device *spi)
 | 
				
			||||||
	mcp->chip.base = pdata->base;
 | 
						mcp->chip.base = pdata->base;
 | 
				
			||||||
	mcp->chip.ngpio = 8;
 | 
						mcp->chip.ngpio = 8;
 | 
				
			||||||
	mcp->chip.can_sleep = 1;
 | 
						mcp->chip.can_sleep = 1;
 | 
				
			||||||
 | 
						mcp->chip.dev = &spi->dev;
 | 
				
			||||||
	mcp->chip.owner = THIS_MODULE;
 | 
						mcp->chip.owner = THIS_MODULE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spi_set_drvdata(spi, mcp);
 | 
						spi_set_drvdata(spi, mcp);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -188,6 +188,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
 | 
				
			||||||
	gc->base = chip->gpio_start;
 | 
						gc->base = chip->gpio_start;
 | 
				
			||||||
	gc->ngpio = gpios;
 | 
						gc->ngpio = gpios;
 | 
				
			||||||
	gc->label = chip->client->name;
 | 
						gc->label = chip->client->name;
 | 
				
			||||||
 | 
						gc->dev = &chip->client->dev;
 | 
				
			||||||
	gc->owner = THIS_MODULE;
 | 
						gc->owner = THIS_MODULE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,6 +200,7 @@ static int pcf857x_probe(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gpio->chip.base = pdata->gpio_base;
 | 
						gpio->chip.base = pdata->gpio_base;
 | 
				
			||||||
	gpio->chip.can_sleep = 1;
 | 
						gpio->chip.can_sleep = 1;
 | 
				
			||||||
 | 
						gpio->chip.dev = &client->dev;
 | 
				
			||||||
	gpio->chip.owner = THIS_MODULE;
 | 
						gpio->chip.owner = THIS_MODULE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* NOTE:  the OnSemi jlc1562b is also largely compatible with
 | 
						/* NOTE:  the OnSemi jlc1562b is also largely compatible with
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -636,6 +636,8 @@ static int tps65010_probe(struct i2c_client *client,
 | 
				
			||||||
		tps->outmask = board->outmask;
 | 
							tps->outmask = board->outmask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tps->chip.label = client->name;
 | 
							tps->chip.label = client->name;
 | 
				
			||||||
 | 
							tps->chip.dev = &client->dev;
 | 
				
			||||||
 | 
							tps->chip.owner = THIS_MODULE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tps->chip.set = tps65010_gpio_set;
 | 
							tps->chip.set = tps65010_gpio_set;
 | 
				
			||||||
		tps->chip.direction_output = tps65010_output;
 | 
							tps->chip.direction_output = tps65010_output;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -318,6 +318,8 @@ static int __init egpio_probe(struct platform_device *pdev)
 | 
				
			||||||
		ei->chip[i].dev = &(pdev->dev);
 | 
							ei->chip[i].dev = &(pdev->dev);
 | 
				
			||||||
		chip = &(ei->chip[i].chip);
 | 
							chip = &(ei->chip[i].chip);
 | 
				
			||||||
		chip->label           = "htc-egpio";
 | 
							chip->label           = "htc-egpio";
 | 
				
			||||||
 | 
							chip->dev             = &pdev->dev;
 | 
				
			||||||
 | 
							chip->owner           = THIS_MODULE;
 | 
				
			||||||
		chip->get             = egpio_get;
 | 
							chip->get             = egpio_get;
 | 
				
			||||||
		chip->set             = egpio_set;
 | 
							chip->set             = egpio_set;
 | 
				
			||||||
		chip->direction_input = egpio_direction_input;
 | 
							chip->direction_input = egpio_direction_input;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,8 @@ struct module;
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct gpio_chip - abstract a GPIO controller
 | 
					 * struct gpio_chip - abstract a GPIO controller
 | 
				
			||||||
 * @label: for diagnostics
 | 
					 * @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
 | 
					 * @direction_input: configures signal "offset" as input, or returns error
 | 
				
			||||||
 * @get: returns value for signal "offset"; for output signals this
 | 
					 * @get: returns value for signal "offset"; for output signals this
 | 
				
			||||||
 *	returns either the value actually sensed, or zero
 | 
					 *	returns either the value actually sensed, or zero
 | 
				
			||||||
| 
						 | 
					@ -59,6 +61,7 @@ struct module;
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct gpio_chip {
 | 
					struct gpio_chip {
 | 
				
			||||||
	char			*label;
 | 
						char			*label;
 | 
				
			||||||
 | 
						struct device		*dev;
 | 
				
			||||||
	struct module		*owner;
 | 
						struct module		*owner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int			(*direction_input)(struct gpio_chip *chip,
 | 
						int			(*direction_input)(struct gpio_chip *chip,
 | 
				
			||||||
| 
						 | 
					@ -74,6 +77,7 @@ struct gpio_chip {
 | 
				
			||||||
	int			base;
 | 
						int			base;
 | 
				
			||||||
	u16			ngpio;
 | 
						u16			ngpio;
 | 
				
			||||||
	unsigned		can_sleep:1;
 | 
						unsigned		can_sleep:1;
 | 
				
			||||||
 | 
						unsigned		exported:1;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
 | 
					extern const char *gpiochip_is_requested(struct gpio_chip *chip,
 | 
				
			||||||
| 
						 | 
					@ -108,7 +112,18 @@ extern void __gpio_set_value(unsigned gpio, int value);
 | 
				
			||||||
extern int __gpio_cansleep(unsigned gpio);
 | 
					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)
 | 
					static inline int gpio_is_valid(int number)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -137,6 +152,20 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
 | 
				
			||||||
	gpio_set_value(gpio, value);
 | 
						gpio_set_value(gpio, value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif /* !CONFIG_HAVE_GPIO_LIB */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CONFIG_GPIO_SYSFS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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 */
 | 
					#endif /* _ASM_GENERIC_GPIO_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,6 +79,19 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
 | 
				
			||||||
	WARN_ON(1);
 | 
						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)
 | 
					static inline int gpio_to_irq(unsigned gpio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* GPIO can never have been requested or set as input */
 | 
						/* GPIO can never have been requested or set as input */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue