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
					
				| @ -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 @@ err: | |||||||
| 	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 @@ err: | |||||||
|  * 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 New Issue
	
	Block a user