General Purpose Input/Output Framework

Submitted by Jeremy
on October 30, 2007 - 9:07am

"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, begins Documentation/gpio.txt. In a recent four patch series, David Brownell noted, "when we hashed out the Documentation/gpio.txt GPIO programming interfaces last year, there were a few features in the 'we want this eventually, but can live without it for now' category. Following this post are patches adding some of those features." He went on to describe the two new features introduced in his patches:

"1) Implementation framework in lib/gpiolib.c ... the interface provided to GPIO _users_ is unchanged, but providers can now hook up through a 'gpio_chip' that lets multiple types of GPIO provider coexist. Examples: SOC-native GPIOs, ones provided by an FPGA, I2C or SPI GPIO expanders, etc."

"2) I2C driver for common pcf8574/8575 GPIO expanders ... these are pretty common on embedded hardware, and it's routine for external trees to have ugly board-specific hacks exposing those GPIOs to drivers. Unlike such hacks, I think support using standard GPIO calls should be mergable upstream."


From: David Brownell <david-b@...>
Subject: [patch/rfc 0/4] GPIO implementation framework
Date: Oct 29, 9:50 pm 2007

When we hashed out the Documentation/gpio.txt GPIO programming
interfaces last year, there were a few features in the "we want
this eventually, but can live without it for now" category.
Following this post are patches adding some of those features.

Two core patches are:

- Implementation framework in lib/gpiolib.c ... the interface
provided to GPIO _users_ is unchanged, but providers can now
hook up through a "gpio_chip" that lets multiple types of
GPIO provider coexist. Examples: SOC-native GPIOs, ones
provided by an FPGA, I2C or SPI GPIO expanders, etc.

(I'm thinking this is pretty much ready to merge into MM,
unless someone turns up a blocking issue...)

- I2C driver for common pcf8574/8575 GPIO expanders ... these
are pretty common on embedded hardware, and it's routine for
external trees to have ugly board-specific hacks exposing
those GPIOs to drivers. Unlike such hacks, I think support
using standard GPIO calls should be mergable upstream.

(IMO this is ready to merge too, although I know Jean would
like additional infrastructure which could let us obsolete
existing drivers, instead of just offering an alternative for
systems that need kernel access instead of userspace access.)

Two more patches show how they can be used:

- Platform conversion for DaVinci ... making the SOC-native
GPIOs plug in through gpiolib instead of directly, except
when callers can leverage the inline optimization.

- Board conversion (partial) for DaVinci EVM ... exposing
the LEDs hooked up to one pcf8574a chip using leds-gpio,
along with the A/V clocks (and a random user switch) on
another pcf chip. A third pcf chip isn't converted; it'd
mean changing half a dozen drivers, none of which are yet
upstream.

If the gpiolib patch merges into MM, then I think it'd be
realistic to expect some platforms and boards to be using
this new infrastructure in 2.6.25 ...

- Dave

-

From: David Brownell <david-b@...>
Subject: [patch/rfc 1/4] GPIO implementation framework
Date: Oct 29, 9:51 pm 2007

Provides new implementation infrastructure that platforms may choose to use
when implementing the GPIO programming interface. Platforms can update their
GPIO support to use this. The downside is slower access to non-inlined GPIOs;
rarely a problem except when bitbanging some protocol. The upside is:

* Providing two features which were "want to have (but OK to defer)" when
GPIO interfaces were first discussed in November 2006:

- A "struct gpio_chip" to plug in GPIOs that aren't directly supported
by SOC platforms, but come from FPGAs or other multifunction devices
(like UCB-1x00 GPIOs).

- Full support for message-based GPIO expanders, needing a gpio_chip
hookup; previous support for this part of the programming interface
was just stubs. (One example: the widely used pcf8574 I2C chips,
with 8 GPIOs each.)

* Including a non-stub implementation of the gpio_{request,free}() calls,
which makes those calls much more useful. The diagnostic labels are
also recorded given DEBUG_FS, so /sys/kernel/debug/gpio can show a
snapshot of all GPIOs known to this infrastructure.

The driver programming interfaces introduced in 2.6.21 do not change at all;
this new infrastructure is entirely below the covers.

One open issue is how to handle IRQs reported through GPIO expanders. For
example, I2C chips may be able to report IRQs, but the genirq framework
won't much like the need to manage them in can-sleep contexts or the way
their irq_chip structures can be removed.

This opens the door to an augmented programming interface, addressing GPIOs
by chip and index. That could be used as a performance tweak (lookup once
and cache, avoiding locking and lookup overheads) or to support transient
GPIOs which aren't registered in the integer GPIO namespace (a USB-to-GPIO
adapter, GPIOs coupled to some other type of add-on card, etc).

Signed-off-by: David Brownell
---
Documentation/gpio.txt | 12 -
include/asm-generic/gpio.h | 127 +++++++++++
lib/Kconfig | 6
lib/Makefile | 2
lib/gpiolib.c | 500 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 644 insertions(+), 3 deletions(-)

--- a/Documentation/gpio.txt 2007-10-29 01:27:23.000000000 -0700
+++ b/Documentation/gpio.txt 2007-10-29 01:30:02.000000000 -0700
@@ -63,7 +63,9 @@ and that can be critical for glue logic.
Plus, this doesn't define an implementation framework, just an interface.
One platform might implement it as simple inline functions accessing chip
registers; another might implement it by delegating through abstractions
-used for several very different kinds of GPIO controller.
+used for several very different kinds of GPIO controller. (There is some
+library code supporting such an implementation strategy, but drivers using
+the interface should not care if that's how the interface is implemented.)

That said, if the convention is supported on their platform, drivers should
use it when possible. Platforms should declare GENERIC_GPIO support in
@@ -223,6 +225,9 @@ Note that requesting a GPIO does NOT cau
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).

+Also note that it's your responsibility to have stopped using a GPIO
+before you free it.
+

GPIOs mapped to IRQs
--------------------
@@ -238,7 +243,7 @@ map between them using calls like:

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
+some GPIOs can't be used as IRQs.) It is an unchecked error to use a GPIO
number that wasn't set up as an input using gpio_direction_input(), or
to use an IRQ number that didn't originally come from gpio_to_irq().

@@ -299,6 +304,7 @@ Related to multiplexing is configuration
pulldowns integrated on some platforms. Not all platforms support them,
or support them in the same way; and any given board might use external
pullups (or pulldowns) so that the on-chip ones should not be used.
+(When a circuit needs 5 kOhm, on-chip 100 kOhm resistors won't do.)

There are other system-specific mechanisms that are not specified here,
like the aforementioned options for input de-glitching and wire-OR output.
@@ -312,4 +318,4 @@ Dynamic definition of GPIOs is not curre
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 it.
+on top of them.
--- a/lib/Kconfig 2007-10-29 01:27:23.000000000 -0700
+++ b/lib/Kconfig 2007-10-29 01:30:02.000000000 -0700
@@ -141,4 +141,10 @@ config HAS_DMA
config CHECK_SIGNATURE
bool

+#
+# gpiolib is selected if needed
+#
+config GPIO_LIB
+ boolean
+
endmenu
--- a/include/asm-generic/gpio.h 2007-10-29 01:27:23.000000000 -0700
+++ b/include/asm-generic/gpio.h 2007-10-29 01:30:02.000000000 -0700
@@ -1,6 +1,131 @@
#ifndef _ASM_GENERIC_GPIO_H
#define _ASM_GENERIC_GPIO_H

+#ifdef CONFIG_GPIO_LIB
+
+/* Platforms may implement their GPIO interface with library code,
+ * at the cost of performance for non-inlined operations.
+ *
+ * While the GPIO programming interface defines valid GPIO numbers
+ * to be in the range 0..MAX_INT, this library restricts them to the
+ * smaller range 0..ARCH_NR_GPIOS and allocates them in groups of
+ * ARCH_GPIOS_PER_CHIP (which will usually be the word size used for
+ * each bank of a SOC processor's integrated GPIO modules).
+ */
+
+#ifndef ARCH_NR_GPIOS
+#define ARCH_NR_GPIOS 512
+#endif
+
+#ifndef ARCH_GPIOS_PER_CHIP
+#define ARCH_GPIOS_PER_CHIP BITS_PER_LONG
+#endif
+
+struct seq_file;
+
+/**
+ * struct gpio_chip - abstract a GPIO controller
+ * @label: for diagnostics
+ * @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
+ * @direction_output: configures signal "offset" as output, or returns error
+ * @set: assigns output value for signal "offset"
+ * @dbg_show: optional routine to show contents in debugfs; default code
+ * will be used when this is omitted, but custom code can show extra
+ * state (such as pullup/pulldown configuration).
+ * @base: identifies the first GPIO number handled by this chip; or, if
+ * negative during registration, requests dynamic ID allocation.
+ * @ngpio: the number of GPIOs handled by this controller; the value must
+ * be at most ARCH_GPIOS_PER_CHIP, so the last GPIO handled is
+ * (base + ngpio - 1).
+ * @can_sleep: flag must be set iff get()/set() methods sleep, as they
+ * must while accessing GPIO expander chips over I2C or SPI
+ * @is_out: bit array where bit N is true iff GPIO with offset N has been
+ * called successfully to configure this as an output
+ *
+ * A gpio_chip can help platforms abstract various sources of GPIOs so
+ * they can all be accessed through a common programing interface.
+ * Example sources would be SOC controllers, FPGAs, multifunction
+ * chips, dedicated GPIO expanders, and so on.
+ *
+ * Each chip controls a number of signals, numbered 0..@ngpio, which are
+ * identified in method calls by an "offset" value. When those signals
+ * are referenced through calls like gpio_get_value(gpio), the offset
+ * is calculated by subtracting @base from the gpio number.
+ */
+struct gpio_chip {
+ char *label;
+
+ int (*direction_input)(struct gpio_chip *chip,
+ unsigned offset);
+ int (*get)(struct gpio_chip *chip,
+ unsigned offset);
+ int (*direction_output)(struct gpio_chip *chip,
+ unsigned offset, int value);
+ void (*set)(struct gpio_chip *chip,
+ unsigned offset, int value);
+ void (*dbg_show)(struct seq_file *s,
+ struct gpio_chip *chip);
+ int base;
+ u16 ngpio;
+ unsigned can_sleep:1;
+
+ /* other fields are modified by the gpio library only */
+ DECLARE_BITMAP(is_out, ARCH_GPIOS_PER_CHIP);
+
+#ifdef CONFIG_DEBUG_FS
+ /* fat bits */
+ const char *requested[ARCH_GPIOS_PER_CHIP];
+#else
+ /* thin bits */
+ DECLARE_BITMAP(requested, ARCH_GPIOS_PER_CHIP);
+#endif
+};
+
+/* returns true iff a given gpio signal has been requested;
+ * primarily for code dumping gpio_chip state.
+ */
+static inline int
+gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
+{
+#ifdef CONFIG_DEBUG_FS
+ return chip->requested[offset] != NULL;
+#else
+ return test_bit(offset, chip->requested);
+#endif
+}
+
+/* add/remove chips */
+extern int gpiochip_add(struct gpio_chip *chip);
+extern int __must_check gpiochip_remove(struct gpio_chip *chip);
+
+
+/* Always use the library code for GPIO management calls,
+ * or when sleeping may be involved.
+ */
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+
+extern int gpio_direction_input(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio, int value);
+
+extern int gpio_get_value_cansleep(unsigned gpio);
+extern void gpio_set_value_cansleep(unsigned gpio, int value);
+
+
+/* A platform's code may want to inline the I/O calls when
+ * the GPIO is constant and refers to some always-present controller,
+ * giving direct access to chip registers and tight bitbanging loops.
+ */
+extern int __gpio_get_value(unsigned gpio);
+extern void __gpio_set_value(unsigned gpio, int value);
+
+extern int __gpio_cansleep(unsigned gpio);
+
+
+#else
+
/* platforms that don't directly support access to GPIOs through I2C, SPI,
* or other blocking infrastructure can use these wrappers.
*/
@@ -22,4 +147,6 @@ static inline void gpio_set_value_cansle
gpio_set_value(gpio, value);
}

+#endif
+
#endif /* _ASM_GENERIC_GPIO_H */
--- a/lib/Makefile 2007-10-29 01:27:23.000000000 -0700
+++ b/lib/Makefile 2007-10-29 01:30:02.000000000 -0700
@@ -68,6 +68,8 @@ obj-$(CONFIG_FAULT_INJECTION) += fault-i

lib-$(CONFIG_GENERIC_BUG) += bug.o

+lib-$(CONFIG_GPIO_LIB) += gpiolib.o
+
hostprogs-y := gen_crc32table
clean-files := crc32table.h

--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ b/lib/gpiolib.c 2007-10-29 07:30:04.000000000 -0700
@@ -0,0 +1,500 @@
+#include
+#include
+#include
+#include
+
+#include
+
+
+/* Optional implementation infrastructure for GPIO interfaces.
+ *
+ * Platforms may want to use this if they tend to use very many GPIOs
+ * that aren't part of a System-On-Chip core; or across I2C/SPI/etc.
+ *
+ * When kernel footprint or instruction count is an issue, simpler
+ * implementations may be preferred.
+ */
+
+
+/* When debugging, extend minimal trust to callers and platform code;
+ * otherwise, minimize overhead in what may be bitbanging codepaths.
+ */
+#ifdef CONFIG_DEBUG_GPIO
+#define extra_checks 1
+#else
+#define extra_checks 0
+#endif
+
+/* gpio_lock protects modification to the table of chips and to
+ * gpio_chip->requested. If a gpio is requested, its gpio_chip
+ * is not removable.
+ */
+static DEFINE_SPINLOCK(gpio_lock);
+static struct gpio_chip *chips[DIV_ROUND_UP(ARCH_NR_GPIOS,
+ ARCH_GPIOS_PER_CHIP)];
+
+/* Warn when drivers omit gpio_request() calls -- legal but
+ * ill-advised when setting direction, and otherwise illegal.
+ */
+static void gpio_ensure_requested(struct gpio_chip *chip, unsigned offset)
+{
+ int requested;
+
+#ifdef CONFIG_DEBUG_FS
+ requested = (int) chip->requested[offset];
+ if (!requested)
+ chip->requested[offset] = "(auto)";
+#else
+ requested = test_and_set_bit(offset, chip->requested);
+#endif
+
+ if (!requested)
+ printk(KERN_DEBUG "GPIO-%d autorequested\n",
+ chip->base + offset);
+}
+
+/* caller holds gpio_lock */
+static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
+{
+ return chips[gpio / ARCH_GPIOS_PER_CHIP];
+}
+
+/**
+ * gpiochip_add() - register a gpio_chip
+ * @chip: the chip to register, with chip->base initialized
+ * Context: potentially before irqs or kmalloc will work
+ *
+ * Returns a negative errno if the chip can't be registered, such as
+ * because the chip->base is invalid or already associated with a
+ * different chip. Otherwise it returns zero as a success code.
+ */
+int gpiochip_add(struct gpio_chip *chip)
+{
+ unsigned long flags;
+ int status = 0;
+ unsigned id;
+
+ if (chip->base < 0 || (chip->base % ARCH_GPIOS_PER_CHIP) != 0)
+ return -EINVAL;
+ if ((chip->base + chip->ngpio) >= ARCH_NR_GPIOS)
+ return -EINVAL;
+ if (chip->ngpio > ARCH_GPIOS_PER_CHIP)
+ return -EINVAL;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ id = chip->base / ARCH_GPIOS_PER_CHIP;
+ if (chips[id] == NULL)
+ chips[id] = chip;
+ else
+ status = -EBUSY;
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add);
+
+/**
+ * gpiochip_remove() - unregister a gpio_chip
+ * @chip: the chip to unregister
+ *
+ * A gpio_chip with any GPIOs still requested may not be removed.
+ */
+int gpiochip_remove(struct gpio_chip *chip)
+{
+ unsigned long flags;
+ int status = 0;
+ int offset;
+ unsigned id = chip->base / ARCH_GPIOS_PER_CHIP;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ for (offset = 0; offset < chip->ngpio; offset++) {
+ if (gpiochip_is_requested(chip, offset)) {
+ status = -EBUSY;
+ break;
+ }
+ }
+
+ if (status == 0) {
+ if (chips[id] == chip)
+ chips[id] = NULL;
+ else
+ status = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpiochip_remove);
+
+
+/* These "optional" allocation calls help prevent drivers from stomping
+ * on each other, and help provide better diagnostics in debugfs.
+ * They're called even less than the "set direction" calls.
+ */
+int gpio_request(unsigned gpio, const char *label)
+{
+ struct gpio_chip *chip;
+ int status = -EINVAL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ chip = gpio_to_chip(gpio);
+ if (!chip)
+ goto done;
+ gpio -= chip->base;
+ if (gpio >= chip->ngpio)
+ goto done;
+
+ /* NOTE: gpio_request() can be called in early boot,
+ * before IRQs are enabled.
+ */
+
+ status = 0;
+#ifdef CONFIG_DEBUG_FS
+ if (!label)
+ label = "?";
+ if (chip->requested[gpio])
+ status = -EBUSY;
+ else
+ chip->requested[gpio] = label;
+#else
+ if (test_and_set_bit(gpio, chip->requested))
+ status = -EBUSY;
+#endif
+
+done:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ chip = gpio_to_chip(gpio);
+ if (!chip)
+ goto done;
+ gpio -= chip->base;
+ if (gpio >= chip->ngpio)
+ goto done;
+
+#ifdef CONFIG_DEBUG_FS
+ if (chip->requested[gpio])
+ chip->requested[gpio] = NULL;
+ else
+ chip = NULL;
+#else
+ if (!test_and_clear_bit(gpio, chip->requested))
+ chip = NULL;
+#endif
+ WARN_ON(extra_checks && chip == NULL);
+done:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gpio_free);
+
+
+
+/* Drivers MUST make configuration calls before get/set calls
+ *
+ * As a rule these aren't called more than once (except for
+ * drivers using the open-drain emulation idiom) so these are
+ * natural places to accumulate extra debugging checks. Note
+ * that we can't rely on gpio_request() having been called.
+ */
+
+int gpio_direction_input(unsigned gpio)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+ int status = -EINVAL;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ chip = gpio_to_chip(gpio);
+ if (!chip || !chip->get || !chip->direction_input)
+ goto fail;
+ gpio -= chip->base;
+ if (gpio >= chip->ngpio)
+ goto fail;
+ gpio_ensure_requested(chip, gpio);
+
+ /* now we know the gpio is valid and chip won't vanish */
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ might_sleep_if(extra_checks && chip->can_sleep);
+
+ status = chip->direction_input(chip, gpio);
+ if (status == 0)
+ clear_bit(gpio, chip->is_out);
+ return status;
+fail:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+ int status = -EINVAL;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ chip = gpio_to_chip(gpio);
+ if (!chip || !chip->get || !chip->direction_output)
+ goto fail;
+ gpio -= chip->base;
+ if (gpio >= chip->ngpio)
+ goto fail;
+ gpio_ensure_requested(chip, gpio);
+
+ /* now we know the gpio is valid and chip won't vanish */
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ might_sleep_if(extra_checks && chip->can_sleep);
+
+ status = chip->direction_output(chip, gpio, value);
+ if (status == 0)
+ set_bit(gpio, chip->is_out);
+ return status;
+fail:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpio_direction_output);
+
+
+/* I/O calls are only valid after configuration completed; the relevant
+ * "is this a valid GPIO" error checks should already have been done.
+ *
+ * "Get" operations are often inlinable as reading a pin value register,
+ * and masking the relevant bit in that register.
+ *
+ * When "set" operations are inlinable, they involve writing that mask to
+ * one register to set a low value, or a different register to set it high.
+ * Otherwise a spinlock is needed, and there's little value to inlining.
+ */
+int __gpio_get_value(unsigned gpio)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ chip = gpio_to_chip(gpio);
+ if (extra_checks)
+ gpio_ensure_requested(chip, gpio - chip->base);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ if (unlikely(chip->can_sleep)) {
+ WARN_ON(extra_checks);
+ return 0;
+ } else
+ return chip->get(chip, gpio - chip->base);
+}
+EXPORT_SYMBOL_GPL(__gpio_get_value);
+
+void __gpio_set_value(unsigned gpio, int value)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ chip = gpio_to_chip(gpio);
+ if (extra_checks)
+ gpio_ensure_requested(chip, gpio - chip->base);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ if (unlikely(chip->can_sleep))
+ WARN_ON(extra_checks);
+ else
+ chip->set(chip, gpio - chip->base, value);
+}
+EXPORT_SYMBOL_GPL(__gpio_set_value);
+
+int __gpio_cansleep(unsigned gpio)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ chip = gpio_to_chip(gpio);
+ if (extra_checks)
+ gpio_ensure_requested(chip, gpio - chip->base);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return chip->can_sleep;
+}
+EXPORT_SYMBOL_GPL(__gpio_cansleep);
+
+
+
+/* There's no value in inlining GPIO calls that may sleep.
+ * Common examples include ones connected to I2C or SPI chips.
+ */
+
+int gpio_get_value_cansleep(unsigned gpio)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+
+ might_sleep_if(extra_checks);
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ chip = gpio_to_chip(gpio);
+ if (extra_checks)
+ gpio_ensure_requested(chip, gpio - chip->base);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ return chip->get(chip, gpio - chip->base);
+}
+EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
+
+void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+
+ might_sleep_if(extra_checks);
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ chip = gpio_to_chip(gpio);
+ if (extra_checks)
+ gpio_ensure_requested(chip, gpio - chip->base);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ chip->set(chip, gpio - chip->base, value);
+}
+EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+
+
+#ifdef CONFIG_DEBUG_FS
+
+#include
+#include
+
+
+static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ unsigned i;
+
+ for (i = 0; i < chip->ngpio; i++) {
+ unsigned gpio;
+ int is_out;
+
+ if (!chip->requested[i])
+ continue;
+
+ gpio = chip->base + i;
+ is_out = test_bit(i, chip->is_out);
+
+ seq_printf(s, " gpio-%-3d (%-12s) %s %s",
+ gpio, chip->requested[i],
+ is_out ? "out" : "in ",
+ chip->get
+ ? (chip->get(chip, i) ? "hi" : "lo")
+ : "? ");
+
+ if (!is_out) {
+ int irq = gpio_to_irq(gpio);
+ struct irq_desc *desc = irq_desc + irq;
+
+ /* This races with request_irq(), set_irq_type(),
+ * and set_irq_wake() ... but those are "rare".
+ *
+ * More significantly, trigger type flags aren't
+ * currently maintained by genirq.
+ */
+ if (irq >= 0 && desc->action) {
+ char *trigger;
+
+ switch (desc->status & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_NONE:
+ trigger = "(default)";
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = "edge-falling";
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = "edge-rising";
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ trigger = "edge-both";
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = "level-high";
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = "level-low";
+ break;
+ default:
+ trigger = "?trigger?";
+ break;
+ }
+
+ seq_printf(s, " irq-%d %s%s",
+ irq, trigger,
+ (desc->status & IRQ_WAKEUP)
+ ? " wakeup" : "");
+ }
+ }
+
+ seq_printf(s, "\n");
+ }
+}
+
+static int gpiolib_show(struct seq_file *s, void *unused)
+{
+ struct gpio_chip *chip;
+ unsigned id;
+ int started = 0;
+
+ /* REVISIT this isn't locked against gpio_chip removal ... */
+
+ for (id = 0; id < ARRAY_SIZE(chips); id++) {
+ chip = chips[id];
+ if (!chip)
+ continue;
+
+ seq_printf(s, "%sGPIOs %d-%d, %s%s:\n",
+ started ? "\n" : "",
+ chip->base, chip->base + chip->ngpio - 1,
+ chip->label ? : "generic",
+ chip->can_sleep ? ", can sleep" : "");
+ started = 1;
+ if (chip->dbg_show)
+ chip->dbg_show(s, chip);
+ else
+ gpiolib_dbg_show(s, chip);
+ }
+ return 0;
+}
+
+static int gpiolib_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gpiolib_show, NULL);
+}
+
+static struct file_operations gpiolib_operations = {
+ .open = gpiolib_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init gpiolib_debugfs_init(void)
+{
+ /* /sys/kernel/debug/gpio */
+ (void) debugfs_create_file("gpio", S_IFREG | S_IRUGO,
+ NULL, NULL, &gpiolib_operations);
+ return 0;
+}
+postcore_initcall(gpiolib_debugfs_init);
+
+#endif /* DEBUG_FS */
-

From: David Brownell <david-b@...>
Subject: [patch/rfc 2/4] pcf875x I2C GPIO expander driver
Date: Oct 29, 9:51 pm 2007

This is a new-style I2C driver for some common 8 and 16 bit I2C based
GPIO expanders: pcf8574 and pcf8575. Since it's a new-style driver,
it's configured as part of board-specific init ... eliminating the
need for error-prone manual configuration of module parameters.

The driver exposes the GPIO signals using the platform-neutral GPIO
programming interface, so they are easily accessed by other kernel
code. The lack of such a flexible kernel API is what has ensured
the proliferation of board-specific hacks for these chips... stuff
that rarely makes it upstream since it's so ugly. This driver will
let such board-specific code use standard GPIO calls.

Signed-off-by: David Brownell
---
Note that there's currently a drivers/i2c/chips/pcf8574.c driver.

Key differences include: this one talks to other kernel code so
it can use the GPIOs "normally", but that one talks to userspace
through sysfs. Also, this one is a "new style" I2C driver, so it's
smaller and doesn't need all those error-prone module parameters.
Plus, this one handles both 8 and 16 bit chip versions.

drivers/i2c/chips/Kconfig | 18 ++
drivers/i2c/chips/Makefile | 1
drivers/i2c/chips/pcf857x.c | 309 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/pcf857x.h | 43 ++++++
4 files changed, 371 insertions(+)

--- a/drivers/i2c/chips/Kconfig 2007-10-28 21:04:06.000000000 -0700
+++ b/drivers/i2c/chips/Kconfig 2007-10-29 14:16:01.000000000 -0700
@@ -51,6 +51,24 @@ config SENSORS_EEPROM
This driver can also be built as a module. If so, the module
will be called eeprom.

+config GPIO_PCF857X
+ tristate "PCF875x GPIO expanders"
+ depends on GPIO_LIB
+ help
+ Say yes here to provide access to some I2C GPIO expanders which
+ may be used for additional digital outputs or inputs:
+
+ - pcf8574, pcf8574a ... 8 bits, from NXP or TI
+ - pcf8575, pcf8575c ... 16 bits, from NXP or TI
+
+ Your board setup code will need to declare the expanders in
+ use, and assign numbers to the GPIOs they expose. Those GPIOs
+ can then be used from drivers and other kernel code, just like
+ other GPIOs, but only accessible from task contexts.
+
+ This driver provides only an in-kernel interface to those GPIOs.
+ Any sysfs interface to userspace would be provided separately.
+
config SENSORS_PCF8574
tristate "Philips PCF8574 and PCF8574A"
depends on EXPERIMENTAL
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ b/include/linux/pcf857x.h 2007-10-28 21:09:49.000000000 -0700
@@ -0,0 +1,43 @@
+#ifndef __LINUX_PCF857X_H
+#define __LINUX_PCF857X_H
+
+/**
+ * struct pcf857x_platform_data - data to set up pcf857x driver
+ * @gpio_base: number of the chip's first GPIO
+ * @n_latch: optional bit-inverse of initial output state
+ * @context: optional parameter passed to setup() and teardown()
+ * @setup: optional callback issued once the GPIOs are valid
+ * @teardown: optional callback issued before the GPIOs are invvalidated
+ *
+ * In addition to the I2C_BOARD_INFO() state appropriate to each chip,
+ * the i2c_board_info used with the pcf875x driver must provide the
+ * chip "type" ("pcf8574", "pcf8574a", "pcf8575", "pcf8575c") and its
+ * platform_data (pointer to one of these structures) with at least
+ * the gpio_base value initialized.
+ *
+ * The @setup callback may be used with the kind of board-specific glue
+ * which hands the (now-valid) GPIOs to other drivers, or which puts
+ * devices in their initial states using these GPIOs.
+ *
+ * Since these GPIO chips don't have conventional registers recording
+ * whether a pin is used for input or output, or an output latch to
+ * record the values being driven, the n_latch value may be used to
+ * avoid intialization glitches. Its inverted value initializes the
+ * value into which bits are masked before they're written to the PCF
+ * chip. That means that if it's left at zero, the chip is treated as
+ * if it came from power-up reset.
+ */
+struct pcf857x_platform_data {
+ unsigned gpio_base;
+ unsigned n_latch;
+
+ void *context;
+ int (*setup)(struct i2c_client *client,
+ int gpio, unsigned ngpio,
+ void *context);
+ int (*teardown)(struct i2c_client *client,
+ int gpio, unsigned ngpio,
+ void *context);
+};
+
+#endif /* __LINUX_PCF857X_H */
--- a/drivers/i2c/chips/Makefile 2007-10-28 21:04:06.000000000 -0700
+++ b/drivers/i2c/chips/Makefile 2007-10-28 21:09:49.000000000 -0700
@@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_SENSORS_TLV320AIC23) += tlv320aic23.o
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/i2c/chips/pcf857x.c 2007-10-29 14:12:21.000000000 -0700
@@ -0,0 +1,309 @@
+/*
+ * pcf857x - driver for pcf857{4,4a,5,5c} I2C GPIO expanders
+ *
+ * Copyright (C) 2007 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include
+#include
+#include
+
+#include
+
+
+/*
+ * The pcf857x chips only expose a one read register and one write register.
+ * Writing a "one" bit (to match the reset state) lets that pin be used as
+ * an input; it's not an open-drain model, but it acts a bit like that.
+ *
+ * Some other I2C GPIO expander chips (like the pca9534, pca9535, pca9555,
+ * pca9539, mcp23008, and mc23017) have a more complex register model with
+ * more conventional input circuitry, often using 0x20..0x27 addresses.
+ */
+struct pcf857x {
+ struct gpio_chip chip;
+ struct i2c_client *client;
+ unsigned out; /* software latch */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Talk to 8-bit I/O expander */
+
+static int pcf857x_input8(struct gpio_chip *chip, unsigned offset)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+
+ gpio->out |= (1 << offset);
+ return i2c_smbus_write_byte(gpio->client, (u8) gpio->out);
+}
+
+static int pcf857x_get8(struct gpio_chip *chip, unsigned offset)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ s32 value;
+
+ value = i2c_smbus_read_byte(gpio->client);
+ return (value < 0) ? 0 : !!(value & (1 << offset));
+}
+
+static int pcf857x_output8(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ unsigned bit = 1 << offset;
+
+ if (value)
+ gpio->out |= bit;
+ else
+ gpio->out &= ~bit;
+ return i2c_smbus_write_byte(gpio->client, (u8) gpio->out);
+}
+
+static void pcf857x_set8(struct gpio_chip *chip, unsigned offset, int value)
+{
+ pcf857x_output8(chip, offset, value);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Talk to 16-bit I/O expander */
+
+static int i2c_write_le16(struct i2c_client *client, u16 word)
+{
+ u8 buf[2] = { word & 0xff, word >> 8, };
+ int status;
+
+ status = i2c_master_send(client, buf, 2);
+ return (status < 0) ? status : 0;
+}
+
+static int i2c_read_le16(struct i2c_client *client)
+{
+ u8 buf[2];
+ int status;
+
+ status = i2c_master_recv(client, buf, 2);
+ if (status < 0)
+ return status;
+ return (buf[1] << 8) | buf[0];
+}
+
+static int pcf857x_input16(struct gpio_chip *chip, unsigned offset)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+
+ gpio->out |= (1 << offset);
+ return i2c_write_le16(gpio->client, (u16) gpio->out);
+}
+
+static int pcf857x_get16(struct gpio_chip *chip, unsigned offset)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ int value;
+
+ value = i2c_read_le16(gpio->client);
+ return (value < 0) ? 0 : !!(value & (1 << offset));
+}
+
+static int pcf857x_output16(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ unsigned bit = 1 << offset;
+
+ if (value)
+ gpio->out |= bit;
+ else
+ gpio->out &= ~bit;
+ return i2c_write_le16(gpio->client, (u16) gpio->out);
+}
+
+static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value)
+{
+ pcf857x_output16(chip, offset, value);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int pcf857x_probe(struct i2c_client *client)
+{
+ struct pcf857x_platform_data *pdata;
+ struct pcf857x *gpio;
+ int status = 0;
+
+ pdata = client->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ /* Allocate, initialize, and register this gpio_chip. */
+ gpio = kzalloc(sizeof *gpio, GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+
+ gpio->chip.base = pdata->gpio_base;
+ gpio->chip.can_sleep = 1;
+
+ /* NOTE: the OnSemi jlc1562b is also largely compatible with
+ * these parts, notably for output. It has a low-resolution
+ * DAC instead of pin change IRQs; and its inputs can be the
+ * result of comparators.
+ */
+
+ /* '74a addresses are 0x38..0x3f; '74 uses 0x20..0x27 */
+ if (strcmp(client->name, "pcf8574a") == 0
+ || strcmp(client->name, "pcf8574") == 0) {
+ gpio->chip.ngpio = 8;
+ gpio->chip.direction_input = pcf857x_input8;
+ gpio->chip.get = pcf857x_get8;
+ gpio->chip.direction_output = pcf857x_output8;
+ gpio->chip.set = pcf857x_set8;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE))
+ status = -EIO;
+
+ /* fail if there's no chip present */
+ status = i2c_smbus_read_byte(client);
+
+ /* '75/'75c addresses are 0x20..0x27, just like the '74;
+ * the '75c doesn't have a current source pulling high.
+ */
+ } else if (strcmp(client->name, "pcf8575c") == 0
+ || strcmp(client->name, "pcf8575") == 0) {
+ gpio->chip.ngpio = 16;
+ gpio->chip.direction_input = pcf857x_input16;
+ gpio->chip.get = pcf857x_get16;
+ gpio->chip.direction_output = pcf857x_output16;
+ gpio->chip.set = pcf857x_set16;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ status = -EIO;
+
+ /* fail if there's no chip present */
+ status = i2c_read_le16(client);
+
+ } else
+ status = -ENODEV;
+
+ if (status < 0) {
+ dev_dbg(&client->dev, "probe error %d for '%s'\n",
+ status, client->name);
+ kfree(gpio);
+ return status;
+ }
+
+ gpio->chip.label = client->name;
+
+ gpio->client = client;
+ i2c_set_clientdata(client, gpio);
+
+ /* NOTE: these chips have strange "pseudo-bidirectional" I/O pins.
+ * We can't actually know whether a pin is configured (a) as output
+ * and driving the signal low, or (b) as input and reporting a low
+ * value ... without knowing the last value written since the chip
+ * came out of reset (if any). We can't read the latched output.
+ *
+ * In short, the only reliable solution for setting up pin direction
+ * is to do it explicitly. The setup() method can do that.
+ *
+ * We use pdata->n_latch to avoid trouble. In the typical case it's
+ * left initialized to zero; our software copy of the "latch" then
+ * matches the chip's reset state. But there may be cases where a
+ * system must drive some pins low, without transient glitching.
+ * Handle those cases by assigning n_latch to a nonzero value.
+ */
+ gpio->out = ~pdata->n_latch;
+
+ status = gpiochip_add(&gpio->chip);
+ if (status < 0) {
+ kfree(gpio);
+ return status;
+ }
+
+ /* NOTE: these chips can issue "some pin-changed" IRQs, which we
+ * don't yet even try to use. Among other issues, the relevant
+ * genirq state isn't available to modular drivers; and most irq
+ * methods can't be called from sleeping contexts.
+ */
+
+ dev_info(&client->dev, "gpios %d..%d on a %s%s\n",
+ gpio->chip.base,
+ gpio->chip.base + gpio->chip.ngpio - 1,
+ client->name,
+ client->irq ? " (irq ignored)" : "");
+
+ /* Let platform code set up the GPIOs and their users.
+ * Now is the first time anyone can use them.
+ */
+ if (pdata->setup) {
+ status = pdata->setup(client,
+ gpio->chip.base, gpio->chip.ngpio,
+ pdata->context);
+ if (status < 0)
+ dev_dbg(&client->dev, "setup --> %d\n", status);
+ }
+
+ return 0;
+}
+
+static int pcf857x_remove(struct i2c_client *client)
+{
+ struct pcf857x_platform_data *pdata = client->dev.platform_data;
+ struct pcf857x *gpio = i2c_get_clientdata(client);
+ int status = 0;
+
+ if (pdata->teardown) {
+ status = pdata->teardown(client,
+ gpio->chip.base, gpio->chip.ngpio,
+ pdata->context);
+ if (status < 0) {
+ dev_err(&client->dev, "%s --> %d\n",
+ "teardown", status);
+ return status;
+ }
+ }
+
+ status = gpiochip_remove(&gpio->chip);
+ if (status == 0)
+ kfree(gpio);
+ else
+ dev_err(&client->dev, "%s --> %d\n", "remove", status);
+ return status;
+}
+
+static struct i2c_driver pcf857x_driver = {
+ .driver = {
+ .name = "pcf857x",
+ .owner = THIS_MODULE,
+ },
+ .probe = pcf857x_probe,
+ .remove = pcf857x_remove,
+};
+
+static int __init pcf857x_init(void)
+{
+ return i2c_add_driver(&pcf857x_driver);
+}
+/* we want GPIOs to be ready at device_initcall() time */
+subsys_initcall(pcf857x_init);
+
+static void __exit pcf857x_exit(void)
+{
+ i2c_del_driver(&pcf857x_driver);
+}
+module_exit(pcf857x_exit);
+
+MODULE_LICENSE("GPL");
-


Userspace?

Anonymous (not verified)
on
October 30, 2007 - 2:59pm

It'd be really nice to see this interface exposed to userspace. Lots of GPIO uses don't have particularly strong realtime requirements - certainly nothing you can't use a userspace RT task for - and it'd be a *LOT* nicer to be able to do this sort of thing in userspace.

--
Craig Ringer

Re: Userspace?

Anonymous (not verified)
on
October 31, 2007 - 7:09pm

I don't understand what you mean with "this sort of thing", but there are already several interfaces to do typical GPIO tasks from userspace. gpio-keys, gpio-mouse and gpio-leds are some of them. The former two drivers hook up to the input layer and act like a keyboard or a mouse respectively, while the latter allows you to control LEDs through sysfs.

If you're thinking about bitbanging, it will always be a _lot_ slower to do from userspace no matter how good the interface is.

Unified embedded drivers are hard

Anonymous (not verified)
on
October 31, 2007 - 10:30am

Having programmed GPIO, SPI, and I2C on many chips I can say from experience it would be hard to write a unified driver for any of these on one target let alone many. For SPI in particular you are talking about dozens of registers and capabilities that will vary wildly from target to target. Good luck to these guys that are trying.

I'm not sure what you mean

Anonymous (not verified)
on
October 31, 2007 - 8:27pm

I'm not sure what you mean by "unified driver". Linux has programming interfaces to SPI, I2C, and (proposed) GPIO, which offer the same operations on top of varied hardware. There's no single driver underneath those interfaces, so no "unified driver" would be involved. Any difficulty is coming up with the programming interfaces and abstractions. And in all those cases, that's been done already...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.