2005-02-18 13:46:36

by Jamey Hicks

[permalink] [raw]
Subject: gpio api


GPIO API

Motivation: On many of the little Linux devices I've seen, there are
multiple
chips providing GPIO and in many cases GPIO pins from one chip are
used to control unrelated functions. The first approach I took to
solving this problem was to implement a per-function framework. I
wrote the first version of the lcd_device and backlight_device
framework to separate out the platform-specific parts of a framebuffer
video driver from the framebuffer chip parts. (That framework was
finished by Andrew Zabolotny and has been accepted into the main
kernel tree.) However, such a framework is quite a bit of overhead for
very simple controls, so I think it would be worthwhile to have a
generic GPIO API.

My initial thought was to provide a synchronous API for configuring
GPIO mode and setting and getting values. However, GPIOs are
sometimes implemented by chips on slow buses such as I2C and SPI, so
an asynchronous interface should be provided. For example, a bus
extender such as the MAX7317 provides a set of GPIO pins accessible
via SPI. There are similar I2C parts. Since SPI and I2C are much
slower than CPU speeds, it seems best to treat operations on those
GPIO pins as asynchronous. The SPI bus used to reach the MAX7317
could in turn be implemented by other onchip GPIO pins. The next
question is to separate the sync and async APIs or combine them. I
have a feeling that if two separate sets of calls are provided that
people using boards with async GPIOs will end up having to rewrite
drivers.

This proposal provides an async interface via a callback registered
via request_gpio. If a driver supports async operations, it should
provide flags GPIOF_SYNC|GPIOF_ASYNC, a non-NULL callback. This will
work for both sync and async gpios. If a driver only supports sync
GPIOs, then it should only provide the GPIOF_SYNC flag and a NULL
callback. If at runtime the requested gpio is async, then
request_gpio will return -EINVAL. It is a BUG to go ahead and call
set_gpio_mode, set_gpio_value, or get_gpio_value on an async gpio
without registering a callback.

Platform GPIO Resource

In order to use platform_device to specify the GPIOs used by a device,
we need a definition of IORESOURCE_GPIO.

#define IORESOURCE_GPIO 0x08000000

An alternative is to reuse IORESOURCE_IRQ with a flag set.
#define IORESOURCE_IRQ_GPIO (1<<4)


SYFS Interface to GPIOs

For debugging purposes and for one-off gpio uses, it is very useful to
have a userspace interface to particular gpios. However, exposing all
gpios this way is a grave security (denial of service) and possibly
safety risk. The implementation will include an optional sysfs
interface that exposes unrequested GPIOs that have their GPIOF_SYSFS
flag set.

One of the flags could enable a gpio sysfs module to expose the GPIO
to user space. I am in favor of a sysfs module that only has access
to explicitly exposed GPIOs, as you did in your driver.


GPIO Client Driver API

The first two calls are analogous to request_irq/free_irq, so that
driver can ensure that they have exclusive access to a GPIO and can
specify asynchronous or synchronous access. I have run into problems
due to out-of-date or misconfigured drivers that would be prevented by
the use of these calls.

#define GPIOF_SYNC (1 << 0)
#define GPIOF_ASYNC (1 << 1)
#define GPIOF_SYSFS (1 << 2)
#define GPIOF_VALID (1 << 3)

int request_gpio(int gpio_num, const char *name,
void (*callback)(int gpionum, void *devid), int flags, void *devid);
void free_gpio(int gpio_num, void *devid);

It is a BUG to supply a NULL callback if GPIO is successfully
requested with GPIOF_ASYNCH set. [Alternatively, split into sync and
async calls and consider it a BUG to use the synchronous calls on a
GPIO requested with GPIOF_ASYNC set.]

int set_gpio_mode(int gpionum, int modeflags);
int set_gpio_value(int gpionum, int value);
int get_gpio_value(int gpionum);

GPIO Provider API

struct gpiochip {
int (*set)(struct gpiochip *chip, void *context, int value);
int (*get)(struct gpiochip *chip void *context);
int (*mode)(struct gpiochip *chip, void *context, int modeflags);
};

GPIOs are associated with gpiochip instances by calling set_gpio_chip.
If the -1 is provided as the gpionum, then the next free gpionum is
returned. If a positive gpionum is provided and it is already
allocated, then -EINVAL is returned. If there are no free gpionums,
then -ENOMEM is returned.

int set_gpio_chip(int gpionum, struct gpiochip *chip, void *context,
int flags);
int free_gpio_chip(int gpionum);

=end-of-proposal=


2005-02-18 14:35:42

by Jörn Engel

[permalink] [raw]
Subject: Re: gpio api

On Fri, 18 February 2005 08:46:08 -0500, Jamey Hicks wrote:
>
> GPIO Client Driver API
>
> The first two calls are analogous to request_irq/free_irq, so that
> driver can ensure that they have exclusive access to a GPIO and can
> specify asynchronous or synchronous access. I have run into problems
> due to out-of-date or misconfigured drivers that would be prevented by
> the use of these calls.
>
> #define GPIOF_SYNC (1 << 0)
> #define GPIOF_ASYNC (1 << 1)
> #define GPIOF_SYSFS (1 << 2)
> #define GPIOF_VALID (1 << 3)
>
> int request_gpio(int gpio_num, const char *name,
> void (*callback)(int gpionum, void *devid), int flags, void *devid);
> void free_gpio(int gpio_num, void *devid);
>
> It is a BUG to supply a NULL callback if GPIO is successfully
> requested with GPIOF_ASYNCH set. [Alternatively, split into sync and
> async calls and consider it a BUG to use the synchronous calls on a
> GPIO requested with GPIOF_ASYNC set.]

Don't split the interface. BUG_ON((flags&GPIOF_ASYNC) && !callback)
might be a good idea, but most likely there are valid reasons for NULL
callbacks as well.

Also, it's not unusual to request several pins at one. If the
requester can simply provide a bitmask, the calling code is *much*
simpler.

> int set_gpio_mode(int gpionum, int modeflags);
> int set_gpio_value(int gpionum, int value);
> int get_gpio_value(int gpionum);

These functions either lack a struct gpiochip argument or could be
omitted completely.

> GPIO Provider API
>
> struct gpiochip {
> int (*set)(struct gpiochip *chip, void *context, int value);
> int (*get)(struct gpiochip *chip void *context);
> int (*mode)(struct gpiochip *chip, void *context, int modeflags);
> };

A private structure is surely needed, no?


Overall, I like the idea. Having a standard interface for gpio
drivers makes life somewhat easier when writing a driver, and a *lot*
easier when using one. With every driver having their own custom
interface, some *will* end up broken and unusable.

J?rn

--
He that composes himself is wiser than he that composes a book.
-- B. Franklin

2005-02-21 10:01:35

by Asier Llano Palacios

[permalink] [raw]
Subject: Re: gpio api

I think that implementing a GPIO interface is a must-have. And I also
think that your proposal is awesome. I work with GPIOs a lot, and I hate
not doing it in a cross-platform way.

I generally agree with your proposal but I see some missing behaviours.

Configuration that should be done on GPIOs.
- GPIO direction (input/output)
- GPIO modes (standard CMOS / open drain).
- GPIO interruption generation (by level or edge, high, low, raising,
falling)

The GPIOs requesting and numbering should be done by specifying the
chip, the port and the pin. We should be able to manipulate easily a
GPIO from one of 3 I2C chips and another one from our microprocessor.

We should be able to change several pins on the same port simultaneously
(if the driver of the port allows it). Maybe, all the operations should
be done by port (and not by pin), so that we can change several ports
simultaneously. We should be able to register several pins of a port,
and write and read from the port.

I'd like some comments about these features.

--
Asier Llano Palacios <[email protected]>

2005-02-21 10:19:01

by Russell King

[permalink] [raw]
Subject: Re: gpio api

On Mon, Feb 21, 2005 at 11:02:24AM +0100, Asier Llano Palacios wrote:
> The GPIOs requesting and numbering should be done by specifying the
> chip, the port and the pin. We should be able to manipulate easily a
> GPIO from one of 3 I2C chips and another one from our microprocessor.

I think there's a problem with this approach:

- I2C chips require you to talk to them via a relatively slow bus.
The I2C subsystem takes a semaphore, so it can be used from interrupt
context.
- You may wish to use GPIOs (especially on-chip GPIOs) from interrupt
context.

Therefore, you don't have a clear locking model for a GPIO subsystem.
You'll probably be in the situation where some GPIOs may be locked by
spinlocks (which are fine to manipulate from interrupt context) and
others which are locked by semaphores - so you don't actually know
what's going on beneath the GPIO API.

This is real bad news in terms of ensuring correctness and being able to
review.

--
Russell King

2005-02-22 02:18:18

by Yoichi Yuasa

[permalink] [raw]
Subject: Re: gpio api

On Mon, 21 Feb 2005 11:02:24 +0100
Asier Llano Palacios <[email protected]> wrote:

> I think that implementing a GPIO interface is a must-have. And I also
> think that your proposal is awesome. I work with GPIOs a lot, and I hate
> not doing it in a cross-platform way.
>
> I generally agree with your proposal but I see some missing behaviours.

me too,

> Configuration that should be done on GPIOs.
> - GPIO direction (input/output)
> - GPIO modes (standard CMOS / open drain).

I also need pull-up/pull-down.

> - GPIO interruption generation (by level or edge, high, low, raising,
> falling)

We also need a method that GPIO cascade to IRQ.

Yoichi