[patch/rfc 2.6.19-rc5] arch-neutral GPIO calls

David Brownell
2006-11-11T23:41:41Z

I know there have been discussions about standardizing GPIOs before,
but nothing quite "took". One of the more recent ones was

http://marc.theaimsgroup.com/?l=linux-kernel&m=110873454720555&w=2

Below, find what I think is a useful proposal, trivially implementable on
many ARMs (at91, omap, pxa, ep93xx, ixp2000, pnx4008, davinci, more) as well
as the new AVR32.

Compared to the proposal above, key differences include:

- Only intended for use with "real" GPIOs that work from IRQ context;
e.g. pins on a SOC that are controlled by chip register access.

- Doesn't handle I2C or SPI based GPIOs. I think we actually need
a different API for those "message based" GPIOs, where synchronous
get/set requires sleeping (and is thus unusable from IRQ context).
That API could be used for "real" GPIOs; the converse is not true.

- No IORESOURCE_GPIO resource type (could be added though).

- Can be trivially implemented today, on many systems (see partial
list above) ... no "provider" or gpiochip API necessary.

- Provided in the form of a working patch, with sample implementation;
known to be viable on multiple architectures and platforms.

- Includes Documentation/gpio.txt

Comments?

- Dave

============================ CUT HERE
This defines a simple and minimalist convention for GPIO APIs, and an
implementation of it on one ARM platform (OMAP):

- Documentation/gpio.txt ... describes things (read it)

- include/asm-arm/gpio.h ... defines the ARM hook, which just punts
to <asm/arch/gpio.h> for any implementation

- include/asm-arm/arch-omap/gpio.h ... representative implementation
as a wrapper around existing OMAP-specific GPIO calls

The immediate need for such a cross-architecture API convention is to support
drivers that work the same on AT91 ARM and AVR32 AP7000 chips, which embed many
of the same controllers but have different CPUs.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Index: osk/Documentation/gpio.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ osk/Documentation/gpio.txt 2006-11-11 15:20:58.000000000 -0800
@@ -0,0 +1,233 @@
+GPIO Interfaces
+
+This provides an overview of GPIO access API conventions on Linux.
+
+
+What is a GPIO?
+===============
+A "General Purpose Input/Output" (GPIO) is a flexible software-controlled
+digital signal. They are provided from many kinds of chip, and are familiar
+to Linux developers working with embedded and custom hardware. Each GPIO
+represents a bit connected to a particular pin, or "ball" on Ball Grid Array
+(BGA) packages. Board schematics show which external hardware connects to
+which GPIOs. Drivers can be written generically, so that board setup code
+passes such pin configuration data to drivers.
+
+System-on-Chip (SOC) processors heavily rely on GPIOs. In many cases, every
+non-dedicated pin can be configured as a GPIO; and most chips have at least
+several dozen of them. Programmable logic devices (like FPGAs) can easily
+provide GPIOs, and I2C-connected chips like power managers, audio codecs,
+and "GPIO Expanders" often have a few such pins to help with pin scarcity on
+SOCs. Most PC southbridges have a few dozen GPIO-capable pins.
+
+The exact capabilities of GPIOs vary between systems. Common options:
+
+ - Output values are writable (high=1, low=0). Some chips also have
+ options about how that value is driven, so that for example only one
+ value might be driven ... supporting "wire-OR" and similar schemes
+ for the other value.
+
+ - Input values are likewise readable (1, 0). Some chips support readback
+ of pins configured as "output", which is very useful in such "wire-OR"
+ cases (to support bidirectional signaling). GPIO controllers may have
+ input de-glitch logic, sometimes with software controls.
+
+ - Inputs can often be used as IRQ signals, often edge triggered but
+ sometimes level triggered. Such IRQs may be configurable as system
+ wakeup events, to wake the system from a low power state.
+
+ - Usually a GPIO will be configurable as either input or output, as needed
+ by different product boards; single direction ones exist too.
+
+On a given board each GPIO is used for one specific purpose like monitoring
+MMC/SD card insertion/removal, detecting card writeprotect status, driving
+a LED, configuring a transceiver, and so on.
+
+
+What are the Linux GPIO API conventions?
+========================================
+Note that this is called a "convention" because you don't need to do it this
+way, and it's no crime if you don't. There **are** cases where portability
+is not the main issue; GPIOs are often used for the kind of board-specific
+glue logic that may even change between board revisions, and can't ever be
+used on a board that's wired differently. Also, see the notes later on what
+these conventions omit.
+
+That said, if the convention is supported on their platform, drivers should
+probably use it when possible:
+
+ #include <asm/gpio.h>
+
+If you stick to this convention then it'll be easier for other developers to
+see what your code is doing, and maintain it.
+
+
+Identifying GPIOs
+-----------------
+GPIOs are identified by unsigned integers in the range 0..MAX_INT. That
+reserves "negative" numbers for other purposes like marking signals as
+"not available on this board", or indicating faults.
+
+A given platform defines how it uses those integers. So for example one
+might not use "GPIO 0", instead using numbers 32-159. Another platform
+could use numbers 0..63 with one set of GPIO controllers, 64-79 with a
+different type of GPIO controller, and 80-95 with an FPGA used with one
+particular board family. GPIO numbers are not the same as IRQ numbers;
+see below for calls mapping between the two namespaces.
+
+A given platform may want to define symbols corresponding to GPIO lines,
+primarily for use in board-specific setup code. Most drivers should use
+GPIO numbers passed to them from that setup code, using platform_data to
+hold board-specific pin configuration data (along with other board
+specific data they need).
+
+
+Using GPIOs
+-----------
+One of the first things to do with a GPIO, often in board setup code when
+setting up a platform_device using the GPIO, is mark its direction:
+
+ /* set as input or output, returning 0 or negative errno */
+ int gpio_direction_input(unsigned gpio);
+ int gpio_direction_output(unsigned gpio);
+
+The return value is zero for success, else a negative errno; it must be
+checked, since the main calls don't have error returns.
+
+Setting the direction can fail if the GPIO number is invalid, or when
+that particular GPIO can't be used in that mode. It's generally a bad
+idea to rely on boot firmware to have set the direction correctly, since
+it probably wasn't validated to do more than boot Linux. (Similarly,
+that board setup code probably needs to multiplex that pin as a GPIO,
+and arrange pullups/pulldowns appropriately.)
+
+Driver code will then use this either as an input, or an output. These
+calls can safely be issued from inside IRQ handlers; they don't sleep.
+
+ /* GPIO INPUT: return zero or nonzero */
+ int gpio_get_value(unsigned gpio);
+
+ /* GPIO OUTPUT */
+ void gpio_set_value(unsigned gpio, int value);
+
+The get/set calls have no error returns because "invalid GPIO" would have
+been reported earlier in gpio_set_direction(). The values are boolean,
+zero for low, nonzero for high. When reading the value of an output pin,
+the value returned should be what's seen on the pin ... that won't always
+match the specified output value, because of issues including wire-OR and
+output latencies.
+
+Platform-specific implementations are encouraged to optimise the two
+calls to access the GPIO value in cases where the GPIO number (and for
+output, value) are constant. It's normal for them to need only a couple
+of instructions in such cases (reading or writing a hardware register),
+and not to need spinlocks. Such optimized calls can make bitbanging
+applications a lot more efficient (in both space and time) than spending
+dozens of instructions on subroutine calls.
+
+
+Claiming and Releasing GPIOs (OPTIONAL)
+---------------------------------------
+To help catch system configuration errors, two calls are defined.
+However, many platforms don't currently support this mechanism.
+
+ /* request GPIO, returning 0 or negative errno.
+ * non-null labels may be useful for diagnostics.
+ */
+ int gpio_request(unsigned gpio, const char *label);
+
+ /* release previously-claimed GPIO */
+ void gpio_free(unsigned gpio);
+
+Passing invalid GPIO numbers to gpio_request() will fail, as will requesting
+GPIOs that have already been claimed with that call. The return value of
+gpio_request() must be checked.
+
+These APIs serve two basic purposes. One is marking the signals which
+are actually in use as GPIOs, for better diagnostics; systems may have
+several hundred potential GPIOs, but often only a dozen are used on any
+given board. Another is to catch confusion between drivers, reporting
+errors when drivers wrongly think they have exclusive use of that signal.
+
+These two calls are optional because not not all current Linux platforms
+offer such functionality in their GPIO support; a valid implementation
+could return success for all gpio_request() calls. Unlike the other calls,
+the state they represent doesn't normally match anything from a hardware
+register; it's just a software bitmap which clearly is not necessary for
+correct operation of hardware or (bug free) drivers.
+
+Note that requesting a GPIO does NOT cause it to be configured in any
+way; it just marks that GPIO as in use. Separate code must handle any
+pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
+
+
+Identifying GPIO IRQs
+---------------------
+GPIO numbers are unsigned integers; so are IRQ numbers. These make up
+two logically distinct namespaces (GPIO 0 need not use IRQ 0). You can
+map between them using calls like:
+
+ /* map GPIO numbers to IRQ numbers */
+ int gpio_to_irq(unsigned gpio);
+
+ /* map IRQ numbers to GPIO numbers */
+ int irq_to_gpio(unsigned irq);
+
+Those return either the corresponding number in the other namespace, or
+else a negative errno code if the mapping can't be done. (For example,
+some GPIOs can't used as IRQs.) It is an unchecked error to use a GPIO
+number that hasn't been marked as an input using gpio_set_direction(), or
+to use an IRQ number that didn't originally come from gpio_to_irq().
+
+These two mapping calls are expected to cost on the order of a single
+addition or subtraction.
+
+Non-error values returned from gpio_to_irq() can be passed to request_irq()
+or free_irq(). They will often be stored into IRQ resources for platform
+devices, by the board-specific initialization code. Note that IRQ trigger
+options are part of the IRQ API, e.g. IRQF_TRIGGER_FALLING, as are system
+wakeup capabilities.
+
+Non-error values returned from irq_to_gpio() would most commonly be used
+with gpio_get_value().
+
+
+
+What do these conventions omit?
+===============================
+These conventions address least-common-denominator functionality, and
+nonportable features are left as platform-specific (but also accessible
+through <asm/gpio.h> inclusion). Some of these may also be configuration
+dependent; the hardware may support reading or writing GPIOs in gangs,
+but only for GPIOs sharing the same bank. (GPIOs are commonly grouped
+in banks of 16 or 32, with a given SOC having several such banks.)
+
+One of the biggest things these conventions omit is pin multiplexing, since
+this is highly chip-specific and nonportable. One platform might not need
+explicit multiplexing; another might have just two options for use of any
+given pin; another might have eight options per pin; another might be able
+to switch a given GPIO to any of several pins. (Yes, those examples all
+come from systems that run Linux today.)
+
+Related to multiplexing is configuration and enabling of the pullups or
+pulldowns integrated on some platforms. Not all platforms support them,
+or support them in the same way; and any given board may use external
+pullups (or pulldowns) so that the on-chip ones should not be used.
+
+There are other system-specific mechanisms that are not specified here,
+like the aforementioned options for input de-glitching and wire-OR output,
+or ganged I/O. Code relying on them will by definition be nonportable.
+
+GPIOs accessed through serial bus chips, like I2C GPIO expanders, are not
+supported here. The main issue with these calls is that reading or writing
+such GPIO values can't be done from IRQ handlers. Reading from an I2C chip
+involves sleeping to get to the head of a message queue (other chips on the
+bus may be using the controller already) and then get the response data;
+writing similarly involves sleeping. A secondary issue is how to address
+GPIOs on those chips; globally assigned unsigned integers are not good
+choices, better ones would look like "GPIO 7 on that chip". Managing the
+IRQs issued by such GPIOs is similarly troublesome.
+
+This API is purely for kernel space, but a userspace API could be built on
+top of it.
+
Index: osk/include/asm-arm/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ osk/include/asm-arm/gpio.h 2006-11-11 14:52:18.000000000 -0800
@@ -0,0 +1,7 @@
+#ifndef _ARCH_ARM_GPIO_H
+#define _ARCH_ARM_GPIO_H
+
+/* not all ARM platforms necessarily support this API ... */
+#include <asm/arch/gpio.h>
+
+#endif /* _ARCH_ARM_GPIO_H */
Index: osk/include/asm-arm/arch-omap/gpio.h
===================================================================
--- osk.orig/include/asm-arm/arch-omap/gpio.h 2006-11-11 14:52:16.000000000 -0800
+++ osk/include/asm-arm/arch-omap/gpio.h 2006-11-11 14:52:18.000000000 -0800
@@ -76,4 +76,58 @@ extern void omap_set_gpio_direction(int
extern void omap_set_gpio_dataout(int gpio, int enable);
extern int omap_get_gpio_datain(int gpio);

+/*-------------------------------------------------------------------------*/
+
+/* wrappers for "new style" GPIO calls. the old OMAP-specfic ones should
+ * eventually be removed (along with this errno.h inclusion), and maybe
+ * gpios should put MPUIOs last too.
+ */
+
+#include <asm/errno.h>
+
+static inline int __must_check gpio_request(unsigned gpio, const char *label)
+ { return omap_request_gpio(gpio); }
+
+static inline void gpio_free(unsigned gpio)
+ { omap_free_gpio(gpio); }
+
+
+static inline int __must_check
+__gpio_set_direction(unsigned gpio, int is_input)
+{
+ if (cpu_class_is_omap2()) {
+ if (gpio > OMAP_MAX_GPIO_LINES)
+ return -EINVAL;
+ } else {
+ if (gpio > (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */))
+ return -EINVAL;
+ }
+ omap_set_gpio_direction(gpio, is_input);
+ return 0;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+ { return __gpio_set_direction(gpio, 1); }
+
+static inline int gpio_direction_output(unsigned gpio)
+ { return __gpio_set_direction(gpio, 0); }
+
+
+static inline int gpio_get_value(unsigned gpio)
+ { return omap_get_gpio_datain(gpio); }
+
+static inline void gpio_set_value(unsigned gpio, int value)
+ { omap_set_gpio_dataout(gpio, value); }
+
+
+static inline int gpio_to_irq(unsigned gpio)
+ { return OMAP_GPIO_IRQ(gpio); }
+
+static inline int irq_to_gpio(unsigned irq)
+{
+ if (cpu_class_is_omap1() && (irq < (IH_MPUIO_BASE + 16)))
+ return (irq - IH_MPUIO_BASE) + OMAP_MAX_GPIO_LINES;
+ return irq - IH_GPIO_BASE;
+}
+
#endif