mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08: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:
committed by
Linus Torvalds
parent
8b6dd98682
commit
d8f388d8dc
@@ -347,15 +347,12 @@ necessarily be nonportable.
|
||||
Dynamic definition of GPIOs is not currently standard; for example, as
|
||||
a side effect of configuring an add-on board with some GPIO expanders.
|
||||
|
||||
These calls are purely for kernel space, but a userspace API could be built
|
||||
on top of them.
|
||||
|
||||
|
||||
GPIO implementor's framework (OPTIONAL)
|
||||
=======================================
|
||||
As noted earlier, there is an optional implementation framework making it
|
||||
easier for platforms to support different kinds of GPIO controller using
|
||||
the same programming interface.
|
||||
the same programming interface. This framework is called "gpiolib".
|
||||
|
||||
As a debugging aid, if debugfs is available a /sys/kernel/debug/gpio file
|
||||
will be found there. That will list all the controllers registered through
|
||||
@@ -439,4 +436,120 @@ becomes available. That may mean the device should not be registered until
|
||||
calls for that GPIO can work. One way to address such dependencies is for
|
||||
such gpio_chip controllers to provide setup() and teardown() callbacks to
|
||||
board specific code; those board specific callbacks would register devices
|
||||
once all the necessary resources are available.
|
||||
once all the necessary resources are available, and remove them later when
|
||||
the GPIO controller device becomes unavailable.
|
||||
|
||||
|
||||
Sysfs Interface for Userspace (OPTIONAL)
|
||||
========================================
|
||||
Platforms which use the "gpiolib" implementors framework may choose to
|
||||
configure a sysfs user interface to GPIOs. This is different from the
|
||||
debugfs interface, since it provides control over GPIO direction and
|
||||
value instead of just showing a gpio state summary. Plus, it could be
|
||||
present on production systems without debugging support.
|
||||
|
||||
Given approprate hardware documentation for the system, userspace could
|
||||
know for example that GPIO #23 controls the write protect line used to
|
||||
protect boot loader segments in flash memory. System upgrade procedures
|
||||
may need to temporarily remove that protection, first importing a GPIO,
|
||||
then changing its output state, then updating the code before re-enabling
|
||||
the write protection. In normal use, GPIO #23 would never be touched,
|
||||
and the kernel would have no need to know about it.
|
||||
|
||||
Again depending on appropriate hardware documentation, on some systems
|
||||
userspace GPIO can be used to determine system configuration data that
|
||||
standard kernels won't know about. And for some tasks, simple userspace
|
||||
GPIO drivers could be all that the system really needs.
|
||||
|
||||
Note that standard kernel drivers exist for common "LEDs and Buttons"
|
||||
GPIO tasks: "leds-gpio" and "gpio_keys", respectively. Use those
|
||||
instead of talking directly to the GPIOs; they integrate with kernel
|
||||
frameworks better than your userspace code could.
|
||||
|
||||
|
||||
Paths in Sysfs
|
||||
--------------
|
||||
There are three kinds of entry in /sys/class/gpio:
|
||||
|
||||
- Control interfaces used to get userspace control over GPIOs;
|
||||
|
||||
- GPIOs themselves; and
|
||||
|
||||
- GPIO controllers ("gpio_chip" instances).
|
||||
|
||||
That's in addition to standard files including the "device" symlink.
|
||||
|
||||
The control interfaces are write-only:
|
||||
|
||||
/sys/class/gpio/
|
||||
|
||||
"export" ... Userspace may ask the kernel to export control of
|
||||
a GPIO to userspace by writing its number to this file.
|
||||
|
||||
Example: "echo 19 > export" will create a "gpio19" node
|
||||
for GPIO #19, if that's not requested by kernel code.
|
||||
|
||||
"unexport" ... Reverses the effect of exporting to userspace.
|
||||
|
||||
Example: "echo 19 > unexport" will remove a "gpio19"
|
||||
node exported using the "export" file.
|
||||
|
||||
GPIO signals have paths like /sys/class/gpio/gpio42/ (for GPIO #42)
|
||||
and have the following read/write attributes:
|
||||
|
||||
/sys/class/gpio/gpioN/
|
||||
|
||||
"direction" ... reads as either "in" or "out". This value may
|
||||
normally be written. Writing as "out" defaults to
|
||||
initializing the value as low. To ensure glitch free
|
||||
operation, values "low" and "high" may be written to
|
||||
configure the GPIO as an output with that initial value.
|
||||
|
||||
Note that this attribute *will not exist* if the kernel
|
||||
doesn't support changing the direction of a GPIO, or
|
||||
it was exported by kernel code that didn't explicitly
|
||||
allow userspace to reconfigure this GPIO's direction.
|
||||
|
||||
"value" ... reads as either 0 (low) or 1 (high). If the GPIO
|
||||
is configured as an output, this value may be written;
|
||||
any nonzero value is treated as high.
|
||||
|
||||
GPIO controllers have paths like /sys/class/gpio/chipchip42/ (for the
|
||||
controller implementing GPIOs starting at #42) and have the following
|
||||
read-only attributes:
|
||||
|
||||
/sys/class/gpio/gpiochipN/
|
||||
|
||||
"base" ... same as N, the first GPIO managed by this chip
|
||||
|
||||
"label" ... provided for diagnostics (not always unique)
|
||||
|
||||
"ngpio" ... how many GPIOs this manges (N to N + ngpio - 1)
|
||||
|
||||
Board documentation should in most cases cover what GPIOs are used for
|
||||
what purposes. However, those numbers are not always stable; GPIOs on
|
||||
a daughtercard might be different depending on the base board being used,
|
||||
or other cards in the stack. In such cases, you may need to use the
|
||||
gpiochip nodes (possibly in conjunction with schematics) to determine
|
||||
the correct GPIO number to use for a given signal.
|
||||
|
||||
|
||||
Exporting from Kernel code
|
||||
--------------------------
|
||||
Kernel code can explicitly manage exports of GPIOs which have already been
|
||||
requested using gpio_request():
|
||||
|
||||
/* export the GPIO to userspace */
|
||||
int gpio_export(unsigned gpio, bool direction_may_change);
|
||||
|
||||
/* reverse gpio_export() */
|
||||
void gpio_unexport();
|
||||
|
||||
After a kernel driver requests a GPIO, it may only be made available in
|
||||
the sysfs interface by gpio_export(). The driver can control whether the
|
||||
signal direction may change. This helps drivers prevent userspace code
|
||||
from accidentally clobbering important system state.
|
||||
|
||||
This explicit exporting can help with debugging (by making some kinds
|
||||
of experiments easier), or can provide an always-there interface that's
|
||||
suitable for documenting as part of a board support package.
|
||||
|
||||
@@ -1488,6 +1488,9 @@ static int __init _omap_gpio_init(void)
|
||||
bank->chip.set = gpio_set;
|
||||
if (bank_is_mpuio(bank)) {
|
||||
bank->chip.label = "mpuio";
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
bank->chip.dev = &omap_mpuio_device.dev;
|
||||
#endif
|
||||
bank->chip.base = OMAP_MPUIO(0);
|
||||
} else {
|
||||
bank->chip.label = "gpio";
|
||||
|
||||
@@ -360,6 +360,8 @@ static int __init pio_probe(struct platform_device *pdev)
|
||||
pio->chip.label = pio->name;
|
||||
pio->chip.base = pdev->id * 32;
|
||||
pio->chip.ngpio = 32;
|
||||
pio->chip.dev = &pdev->dev;
|
||||
pio->chip.owner = THIS_MODULE;
|
||||
|
||||
pio->chip.direction_input = direction_input;
|
||||
pio->chip.get = gpio_get;
|
||||
|
||||
@@ -23,6 +23,21 @@ config DEBUG_GPIO
|
||||
slower. The diagnostics help catch the type of setup errors
|
||||
that are most common when setting up new platforms or boards.
|
||||
|
||||
config GPIO_SYSFS
|
||||
bool "/sys/class/gpio/... (sysfs interface)"
|
||||
depends on SYSFS && EXPERIMENTAL
|
||||
help
|
||||
Say Y here to add a sysfs interface for GPIOs.
|
||||
|
||||
This is mostly useful to work around omissions in a system's
|
||||
kernel support. Those are common in custom and semicustom
|
||||
hardware assembled using standard kernels with a minimum of
|
||||
custom patches. In those cases, userspace code may import
|
||||
a given GPIO from the kernel, if no kernel driver requested it.
|
||||
|
||||
Kernel drivers may also request that a particular GPIO be
|
||||
exported to userspace; this can be useful when debugging.
|
||||
|
||||
# put expanders in the right section, in alphabetical order
|
||||
|
||||
comment "I2C GPIO expanders:"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -239,6 +239,7 @@ static int mcp23s08_probe(struct spi_device *spi)
|
||||
mcp->chip.base = pdata->base;
|
||||
mcp->chip.ngpio = 8;
|
||||
mcp->chip.can_sleep = 1;
|
||||
mcp->chip.dev = &spi->dev;
|
||||
mcp->chip.owner = THIS_MODULE;
|
||||
|
||||
spi_set_drvdata(spi, mcp);
|
||||
|
||||
@@ -188,6 +188,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
|
||||
gc->base = chip->gpio_start;
|
||||
gc->ngpio = gpios;
|
||||
gc->label = chip->client->name;
|
||||
gc->dev = &chip->client->dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +200,7 @@ static int pcf857x_probe(struct i2c_client *client,
|
||||
|
||||
gpio->chip.base = pdata->gpio_base;
|
||||
gpio->chip.can_sleep = 1;
|
||||
gpio->chip.dev = &client->dev;
|
||||
gpio->chip.owner = THIS_MODULE;
|
||||
|
||||
/* NOTE: the OnSemi jlc1562b is also largely compatible with
|
||||
|
||||
@@ -636,6 +636,8 @@ static int tps65010_probe(struct i2c_client *client,
|
||||
tps->outmask = board->outmask;
|
||||
|
||||
tps->chip.label = client->name;
|
||||
tps->chip.dev = &client->dev;
|
||||
tps->chip.owner = THIS_MODULE;
|
||||
|
||||
tps->chip.set = tps65010_gpio_set;
|
||||
tps->chip.direction_output = tps65010_output;
|
||||
|
||||
@@ -318,6 +318,8 @@ static int __init egpio_probe(struct platform_device *pdev)
|
||||
ei->chip[i].dev = &(pdev->dev);
|
||||
chip = &(ei->chip[i].chip);
|
||||
chip->label = "htc-egpio";
|
||||
chip->dev = &pdev->dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->get = egpio_get;
|
||||
chip->set = egpio_set;
|
||||
chip->direction_input = egpio_direction_input;
|
||||
|
||||
@@ -32,6 +32,8 @@ struct module;
|
||||
/**
|
||||
* struct gpio_chip - abstract a GPIO controller
|
||||
* @label: for diagnostics
|
||||
* @dev: optional device providing the GPIOs
|
||||
* @owner: helps prevent removal of modules exporting active GPIOs
|
||||
* @direction_input: configures signal "offset" as input, or returns error
|
||||
* @get: returns value for signal "offset"; for output signals this
|
||||
* returns either the value actually sensed, or zero
|
||||
@@ -59,6 +61,7 @@ struct module;
|
||||
*/
|
||||
struct gpio_chip {
|
||||
char *label;
|
||||
struct device *dev;
|
||||
struct module *owner;
|
||||
|
||||
int (*direction_input)(struct gpio_chip *chip,
|
||||
@@ -74,6 +77,7 @@ struct gpio_chip {
|
||||
int base;
|
||||
u16 ngpio;
|
||||
unsigned can_sleep:1;
|
||||
unsigned exported:1;
|
||||
};
|
||||
|
||||
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
|
||||
@@ -108,7 +112,18 @@ extern void __gpio_set_value(unsigned gpio, int value);
|
||||
extern int __gpio_cansleep(unsigned gpio);
|
||||
|
||||
|
||||
#else
|
||||
#ifdef CONFIG_GPIO_SYSFS
|
||||
|
||||
/*
|
||||
* A sysfs interface can be exported by individual drivers if they want,
|
||||
* but more typically is configured entirely from userspace.
|
||||
*/
|
||||
extern int gpio_export(unsigned gpio, bool direction_may_change);
|
||||
extern void gpio_unexport(unsigned gpio);
|
||||
|
||||
#endif /* CONFIG_GPIO_SYSFS */
|
||||
|
||||
#else /* !CONFIG_HAVE_GPIO_LIB */
|
||||
|
||||
static inline int gpio_is_valid(int number)
|
||||
{
|
||||
@@ -137,6 +152,20 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int 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 */
|
||||
|
||||
@@ -79,6 +79,19 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int gpio_export(unsigned gpio, bool direction_may_change)
|
||||
{
|
||||
/* GPIO can never have been requested or set as {in,out}put */
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void gpio_unexport(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been exported */
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been requested or set as input */
|
||||
|
||||
Reference in New Issue
Block a user