2010-01-08 05:15:20

by Eric Miao

[permalink] [raw]
Subject: [PATCH] gpio: introduce gpio_request_one() and friends

commit 29cd35f57699fd93a12132186d52109a55ed57e7
Author: Eric Miao <[email protected]>
Date: Fri Jan 8 12:16:28 2010 +0800

gpio: introduce gpio_request_one() and friends

gpio_request() without initial configuration of the GPIO is normally
useless, introduce gpio_request_one() together with GPIOF_ flags for
input/output direction and initial output level.

gpio_{request,free}_array() for multiple GPIOs.

Cc: David Brownell <[email protected]>
Signed-off-by: Eric Miao <[email protected]>

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index a25ad28..e80a1f8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1239,6 +1239,48 @@ void gpio_free(unsigned gpio)
}
EXPORT_SYMBOL_GPL(gpio_free);

+int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+{
+ int err;
+
+ err = gpio_request(gpio, label);
+ if (err)
+ return err;
+
+ if (flags & GPIOF_DIR_IN)
+ err = gpio_direction_input(gpio);
+ else
+ err = gpio_direction_output(gpio,
+ (flags & GPIOF_INIT_HIGH) ? 1 : 0);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_one);
+
+int gpio_request_array(struct gpio *array, size_t num)
+{
+ int i, err;
+
+ for (i = 0; i < num; i++, array++) {
+ err = gpio_request_one(array->gpio, array->flags, array->label);
+ if (err)
+ goto err_free;
+ }
+ return 0;
+
+err_free:
+ while (i--)
+ gpio_free((--array)->gpio);
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_array);
+
+void gpio_free_array(struct gpio *array, size_t num)
+{
+ while (num--)
+ gpio_free((array++)->gpio);
+}
+EXPORT_SYMBOL_GPL(gpio_free_array);

/**
* gpiochip_is_requested - return string iff signal was requested
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 485eeb6..a9e0b94 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -136,6 +136,26 @@ extern int __gpio_cansleep(unsigned gpio);

extern int __gpio_to_irq(unsigned gpio);

+#define GPIOF_DIR_OUT (0 << 0)
+#define GPIOF_DIR_IN (1 << 0)
+
+#define GPIOF_INIT_LOW (0 << 1)
+#define GPIOF_INIT_HIGH (1 << 1)
+
+#define GPIOF_IN (GPIO_DIR_IN)
+#define GPIOF_OUT_INIT_LOW (GPIO_DIR_OUT | GPIO_INIT_LOW)
+#define GPIOF_OUT_INIT_HIGH (GPIO_DIR_OUT | GPIO_INIT_HIGH)
+
+struct gpio {
+ unsigned gpio;
+ unsigned long flags;
+ const char *label;
+};
+
+extern int gpio_request_one(unsigned gpio, unsigned long flags, const
char *label);
+extern int gpio_request_array(struct gpio *array, size_t num);
+extern void gpio_free_array(struct gpio *array, size_t num);
+
#ifdef CONFIG_GPIO_SYSFS

/*


2010-01-08 05:29:19

by Eric Miao

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends

Typo in GPIOF_* definitions, updated patch follows:

commit 29cd35f57699fd93a12132186d52109a55ed57e7
Author: Eric Miao <[email protected]>
Date: Fri Jan 8 12:16:28 2010 +0800

gpio: introduce gpio_request_one() and friends

gpio_request() without initial configuration of the GPIO is normally
useless, introduce gpio_request_one() together with GPIOF_ flags for
input/output direction and initial output level.

gpio_{request,free}_array() for multiple GPIOs.

Cc: David Brownell <[email protected]>
Signed-off-by: Eric Miao <[email protected]>

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index a25ad28..e80a1f8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1239,6 +1239,48 @@ void gpio_free(unsigned gpio)
}
EXPORT_SYMBOL_GPL(gpio_free);

+int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+{
+ int err;
+
+ err = gpio_request(gpio, label);
+ if (err)
+ return err;
+
+ if (flags & GPIOF_DIR_IN)
+ err = gpio_direction_input(gpio);
+ else
+ err = gpio_direction_output(gpio,
+ (flags & GPIOF_INIT_HIGH) ? 1 : 0);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_one);
+
+int gpio_request_array(struct gpio *array, size_t num)
+{
+ int i, err;
+
+ for (i = 0; i < num; i++, array++) {
+ err = gpio_request_one(array->gpio, array->flags, array->label);
+ if (err)
+ goto err_free;
+ }
+ return 0;
+
+err_free:
+ while (i--)
+ gpio_free((--array)->gpio);
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_array);
+
+void gpio_free_array(struct gpio *array, size_t num)
+{
+ while (num--)
+ gpio_free((array++)->gpio);
+}
+EXPORT_SYMBOL_GPL(gpio_free_array);

/**
* gpiochip_is_requested - return string iff signal was requested
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 485eeb6..a9e0b94 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -136,6 +136,26 @@ extern int __gpio_cansleep(unsigned gpio);

extern int __gpio_to_irq(unsigned gpio);

+#define GPIOF_DIR_OUT (0 << 0)
+#define GPIOF_DIR_IN (1 << 0)
+
+#define GPIOF_INIT_LOW (0 << 1)
+#define GPIOF_INIT_HIGH (1 << 1)
+
+#define GPIOF_IN (GPIOF_DIR_IN)
+#define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
+#define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
+
+struct gpio {
+ unsigned gpio;
+ unsigned long flags;
+ const char *label;
+};
+
+extern int gpio_request_one(unsigned gpio, unsigned long flags, const
char *label);
+extern int gpio_request_array(struct gpio *array, size_t num);
+extern void gpio_free_array(struct gpio *array, size_t num);
+
#ifdef CONFIG_GPIO_SYSFS

/*

2010-01-08 06:08:34

by Ben Nizette

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends


On 08/01/2010, at 4:14 PM, Eric Miao wrote:

> commit 29cd35f57699fd93a12132186d52109a55ed57e7
> Author: Eric Miao <[email protected]>
> Date: Fri Jan 8 12:16:28 2010 +0800
>
> gpio: introduce gpio_request_one() and friends
>
> gpio_request() without initial configuration of the GPIO is normally
> useless, introduce gpio_request_one() together with GPIOF_ flags for
> input/output direction and initial output level.

Well yea it is useless without initial configuration but I've always done that configuration before any gpiolib calls. The initial direction and state stuff really has to be set up and pin-mux or gpio-chip-activate time otherwise it'll glitch; by the time we get to gpio_request time I've got everything just how I like it and just want the refcount aspect of gpio_request.

I'm obviously thinking in a very small-minded platform-gpio-only kind of a way, what system have you got which uses this (and how does it not glitch)?

Thanks,
--Ben.

2010-01-08 07:16:23

by Eric Miao

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends

On Fri, Jan 8, 2010 at 2:08 PM, Ben Nizette <[email protected]> wrote:
>
> On 08/01/2010, at 4:14 PM, Eric Miao wrote:
>
>> commit 29cd35f57699fd93a12132186d52109a55ed57e7
>> Author: Eric Miao <[email protected]>
>> Date:   Fri Jan 8 12:16:28 2010 +0800
>>
>>    gpio: introduce gpio_request_one() and friends
>>
>>    gpio_request() without initial configuration of the GPIO is normally
>>    useless, introduce gpio_request_one() together with GPIOF_ flags for
>>    input/output direction and initial output level.
>
> Well yea it is useless without initial configuration but I've always done that configuration before any gpiolib calls.  The initial direction and state stuff really has to be set up and pin-mux or gpio-chip-activate time otherwise it'll glitch; by the time we get to gpio_request time I've got everything just how I like it and just want the refcount aspect of gpio_request.
>

The hardware will anyway glitch if the pin mux and GPIO registers are
different, which is almost true on every platform. The problem is not
to prevent GPIO from being glitch, but how to survive GPIO glitch.

1. from HW, in some cases the reset state of GPIOs are input, which
is basically high-z from the outside, so is not likely to cause problems.

2. if the GPIO reset state is output, with a fixed level (either high or low),
yet the software initializes it to be the opposite, then glitch happens, and
this will impact the external. In such cases, software needs to make sure
there will be no negative impact, e.g. put the external impact chip into
reset or power off state until GPIOs connected are configured to known state.

> I'm obviously thinking in a very small-minded platform-gpio-only kind of a way, what system have you got which uses this (and how does it not glitch)?
>

Mostly PXA processor based systems and they do glitch with careless
configuration and hw design. The patch here is not going to solve the
glitch problem, but to group the request and configuration together as
most GPIO API users are using these two together, and some are using
gpio_request + gpio_direction_* again and again repeatedly for a bunch
of GPIOs, which is not clean.

2010-01-08 07:43:56

by Ben Nizette

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends


On 08/01/2010, at 6:16 PM, Eric Miao wrote:

> On Fri, Jan 8, 2010 at 2:08 PM, Ben Nizette <[email protected]> wrote:
>>
>> On 08/01/2010, at 4:14 PM, Eric Miao wrote:
>>
>>> commit 29cd35f57699fd93a12132186d52109a55ed57e7
>>> Author: Eric Miao <[email protected]>
>>> Date: Fri Jan 8 12:16:28 2010 +0800
>>>
>>> gpio: introduce gpio_request_one() and friends
>>>
>>> gpio_request() without initial configuration of the GPIO is normally
>>> useless, introduce gpio_request_one() together with GPIOF_ flags for
>>> input/output direction and initial output level.
>>
>> Well yea it is useless without initial configuration but I've always done that configuration before any gpiolib calls. The initial direction and state stuff really has to be set up and pin-mux or gpio-chip-activate time otherwise it'll glitch; by the time we get to gpio_request time I've got everything just how I like it and just want the refcount aspect of gpio_request.
>>
>
> The hardware will anyway glitch if the pin mux and GPIO registers are
> different, which is almost true on every platform. The problem is not
> to prevent GPIO from being glitch, but how to survive GPIO glitch.

Well not if you bunt the port mux calls to after the gpio initialisation stuff so none of the glitches actually make it to the pin..

.. but OK, I see the point of this patch. I guess my real issue belongs in another patchset; to change the platforms I deal with to allow gpiolib calls before the portmux ones (and make sure the portmux calls don't trounce the gpiolib setup).

Thanks,
--Ben.-

2010-01-12 23:10:00

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends

On Fri, 8 Jan 2010 13:28:57 +0800
Eric Miao <[email protected]> wrote:

> Typo in GPIOF_* definitions, updated patch follows:
>
> commit 29cd35f57699fd93a12132186d52109a55ed57e7
> Author: Eric Miao <[email protected]>
> Date: Fri Jan 8 12:16:28 2010 +0800
>
> gpio: introduce gpio_request_one() and friends
>
> gpio_request() without initial configuration of the GPIO is normally
> useless, introduce gpio_request_one() together with GPIOF_ flags for
> input/output direction and initial output level.
>
> gpio_{request,free}_array() for multiple GPIOs.
>
> Cc: David Brownell <[email protected]>
> Signed-off-by: Eric Miao <[email protected]>
>
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index a25ad28..e80a1f8 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -1239,6 +1239,48 @@ void gpio_free(unsigned gpio)
> }
> EXPORT_SYMBOL_GPL(gpio_free);
>
> +int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
> +{
> + int err;
> +
> + err = gpio_request(gpio, label);
> + if (err)
> + return err;
> +
> + if (flags & GPIOF_DIR_IN)
> + err = gpio_direction_input(gpio);
> + else
> + err = gpio_direction_output(gpio,
> + (flags & GPIOF_INIT_HIGH) ? 1 : 0);
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(gpio_request_one);
> +
> +int gpio_request_array(struct gpio *array, size_t num)
> +{
> + int i, err;
> +
> + for (i = 0; i < num; i++, array++) {
> + err = gpio_request_one(array->gpio, array->flags, array->label);
> + if (err)
> + goto err_free;
> + }
> + return 0;
> +
> +err_free:
> + while (i--)
> + gpio_free((--array)->gpio);
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(gpio_request_array);
> +
> +void gpio_free_array(struct gpio *array, size_t num)
> +{
> + while (num--)
> + gpio_free((array++)->gpio);
> +}
> +EXPORT_SYMBOL_GPL(gpio_free_array);

Global, exported-to-modules interfaces should be documented, IMO.

> /**
> * gpiochip_is_requested - return string iff signal was requested
> diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
> index 485eeb6..a9e0b94 100644
> --- a/include/asm-generic/gpio.h
> +++ b/include/asm-generic/gpio.h
> @@ -136,6 +136,26 @@ extern int __gpio_cansleep(unsigned gpio);
>
> extern int __gpio_to_irq(unsigned gpio);
>
> +#define GPIOF_DIR_OUT (0 << 0)
> +#define GPIOF_DIR_IN (1 << 0)
> +
> +#define GPIOF_INIT_LOW (0 << 1)
> +#define GPIOF_INIT_HIGH (1 << 1)
> +
> +#define GPIOF_IN (GPIOF_DIR_IN)
> +#define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
> +#define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
> +
> +struct gpio {
> + unsigned gpio;
> + unsigned long flags;
> + const char *label;
> +};

hm. Was "struct gpio" a well-chosen identifier? The name implies that
this structure is the definitive, unified, generic kernel-wide
representation of a "gpio", whatever that is.

> +extern int gpio_request_one(unsigned gpio, unsigned long flags, const
> char *label);

Your email client is wordwrapping the patches.

2010-01-13 03:24:17

by Eric Miao

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends

On Wed, Jan 13, 2010 at 7:09 AM, Andrew Morton
<[email protected]> wrote:
> On Fri, 8 Jan 2010 13:28:57 +0800
> Eric Miao <[email protected]> wrote:
>
>> Typo in GPIOF_* definitions, updated patch follows:
>>
>> commit 29cd35f57699fd93a12132186d52109a55ed57e7
>> Author: Eric Miao <[email protected]>
>> Date:   Fri Jan 8 12:16:28 2010 +0800
>>
>>     gpio: introduce gpio_request_one() and friends
>>
>>     gpio_request() without initial configuration of the GPIO is normally
>>     useless, introduce gpio_request_one() together with GPIOF_ flags for
>>     input/output direction and initial output level.
>>
>>     gpio_{request,free}_array() for multiple GPIOs.
>>
>>     Cc: David Brownell <[email protected]>
>>     Signed-off-by: Eric Miao <[email protected]>
>>
>> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
>> index a25ad28..e80a1f8 100644
>> --- a/drivers/gpio/gpiolib.c
>> +++ b/drivers/gpio/gpiolib.c
>> @@ -1239,6 +1239,48 @@ void gpio_free(unsigned gpio)
>>  }
>>  EXPORT_SYMBOL_GPL(gpio_free);
>>
>> +int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
>> +{
>> +     int err;
>> +
>> +     err = gpio_request(gpio, label);
>> +     if (err)
>> +             return err;
>> +
>> +     if (flags & GPIOF_DIR_IN)
>> +             err = gpio_direction_input(gpio);
>> +     else
>> +             err = gpio_direction_output(gpio,
>> +                             (flags & GPIOF_INIT_HIGH) ? 1 : 0);
>> +
>> +     return err;
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_request_one);
>> +
>> +int gpio_request_array(struct gpio *array, size_t num)
>> +{
>> +     int i, err;
>> +
>> +     for (i = 0; i < num; i++, array++) {
>> +             err = gpio_request_one(array->gpio, array->flags, array->label);
>> +             if (err)
>> +                     goto err_free;
>> +     }
>> +     return 0;
>> +
>> +err_free:
>> +     while (i--)
>> +             gpio_free((--array)->gpio);
>> +     return err;
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_request_array);
>> +
>> +void gpio_free_array(struct gpio *array, size_t num)
>> +{
>> +     while (num--)
>> +             gpio_free((array++)->gpio);
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_free_array);
>
> Global, exported-to-modules interfaces should be documented, IMO.
>

OK, will do.

>>  /**
>>   * gpiochip_is_requested - return string iff signal was requested
>> diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
>> index 485eeb6..a9e0b94 100644
>> --- a/include/asm-generic/gpio.h
>> +++ b/include/asm-generic/gpio.h
>> @@ -136,6 +136,26 @@ extern int __gpio_cansleep(unsigned gpio);
>>
>>  extern int __gpio_to_irq(unsigned gpio);
>>
>> +#define GPIOF_DIR_OUT        (0 << 0)
>> +#define GPIOF_DIR_IN (1 << 0)
>> +
>> +#define GPIOF_INIT_LOW       (0 << 1)
>> +#define GPIOF_INIT_HIGH      (1 << 1)
>> +
>> +#define GPIOF_IN             (GPIOF_DIR_IN)
>> +#define GPIOF_OUT_INIT_LOW   (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
>> +#define GPIOF_OUT_INIT_HIGH  (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
>> +
>> +struct gpio {
>> +     unsigned        gpio;
>> +     unsigned long   flags;
>> +     const char      *label;
>> +};
>
> hm.  Was "struct gpio" a well-chosen identifier?  The name implies that
> this structure is the definitive, unified, generic kernel-wide
> representation of a "gpio", whatever that is.
>

These three fields should be sufficient to support future requirements
of GPIO by using additional flags (e.g. open-drain capable can be
actually made a flag quite easy here), so in my opinion - yes, this
should be a proper name.

>> +extern int gpio_request_one(unsigned gpio, unsigned long flags, const
>> char *label);
>
> Your email client is wordwrapping the patches.
>

Sorry.

2010-01-13 08:23:57

by Eric Miao

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends

> > Global, exported-to-modules interfaces should be documented, IMO.
> >
>
> OK, will do.
>

Andrew,

Attached is the patch against Documentation/gpio.txt (also inlined),
which you may either use as an incremental patch, or merge with
the last one, or if you want, use the other one attached for a merged
version.

diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index 1866c27..c2c6e9b 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -253,6 +253,70 @@ 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.

+Considering in most cases GPIOs are actually configured right after they
+are claimed, three additional calls are defined:
+
+ /* request a single GPIO, with initial configuration specified by
+ * 'flags', identical to gpio_request() wrt other arguments and
+ * return value
+ */
+ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
+
+ /* request multiple GPIOs in a single call
+ */
+ int gpio_request_array(struct gpio *array, size_t num);
+
+ /* release multiple GPIOs in a single call
+ */
+ void gpio_free_array(struct gpio *array, size_t num);
+
+where 'flags' is currently defined to specify the following properties:
+
+ * GPIOF_DIR_IN - to configure direction as input
+ * GPIOF_DIR_OUT - to configure direction as output
+
+ * GPIOF_INIT_LOW - as output, set initial level to LOW
+ * GPIOF_INIT_HIGH - as output, set initial level to HIGH
+
+since GPIOF_INIT_* are only valid when configured as output, so group valid
+combinations as:
+
+ * GPIOF_IN - configure as input
+ * GPIOF_OUT_INIT_LOW - configured as output, initial level LOW
+ * GPIOF_OUT_INIT_HIGH - configured as output, initial level HIGH
+
+In the future, these flags can be extended to support more properties such
+as open-drain status.
+
+Further more, to ease the claim/release of multiple GPIOs, 'struct gpio' is
+introduced to encapsulate all three fields as:
+
+ struct gpio {
+ unsigned gpio;
+ unsigned long flags;
+ const char *label;
+ };
+
+A typical example of usage:
+
+ static struct gpio leds_gpios[] = {
+ { 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* default to ON */
+ { 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* default to OFF */
+ { 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* default to OFF */
+ { 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* default to OFF */
+ { ... },
+ };
+
+ err = gpio_request_one(31, GPIOF_IN, "Reset Button");
+ if (err)
+ ...
+
+ err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
+ if (err)
+ ...
+
+ gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
+

GPIOs mapped to IRQs
--------------------


Attachments:
Documentation_gpio_txt.diff (2.36 kB)
0001-gpio-introduce-gpio_request_one-and-friends.patch (5.17 kB)
Download all attachments

2010-01-13 08:29:47

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends

On Wed, 13 Jan 2010 16:23:35 +0800 Eric Miao <[email protected]> wrote:

> Attached is the patch against Documentation/gpio.txt

Thanks.

I was thinking kerneldoc in the .c file actually - most/all of the
other interface functions in gpiolib.c seem to be done that way.

2010-01-13 09:27:58

by Eric Miao

[permalink] [raw]
Subject: Re: [PATCH] gpio: introduce gpio_request_one() and friends

On Wed, Jan 13, 2010 at 4:29 PM, Andrew Morton
<[email protected]> wrote:
> On Wed, 13 Jan 2010 16:23:35 +0800 Eric Miao <[email protected]> wrote:
>
>> Attached is the patch against Documentation/gpio.txt
>
> Thanks.
>
> I was thinking kerneldoc in the .c file actually - most/all of the
> other interface functions in gpiolib.c seem to be done that way.
>

OK, updated as follows (I've also make this an attached patch in
case gmail wraps my line again):

commit db30b9c15be3ee3ddcd914aadecfc8815c1a0170
Author: Eric Miao <[email protected]>
Date: Fri Jan 8 12:16:28 2010 +0800

gpio: introduce gpio_request_one() and friends

gpio_request() without initial configuration of the GPIO is normally
useless, introduce gpio_request_one() together with GPIOF_ flags for
input/output direction and initial output level.

gpio_{request,free}_array() for multiple GPIOs.

Cc: David Brownell <[email protected]>
Signed-off-by: Eric Miao <[email protected]>

diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index 1866c27..c2c6e9b 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -253,6 +253,70 @@ 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.

+Considering in most cases GPIOs are actually configured right after they
+are claimed, three additional calls are defined:
+
+ /* request a single GPIO, with initial configuration specified by
+ * 'flags', identical to gpio_request() wrt other arguments and
+ * return value
+ */
+ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
+
+ /* request multiple GPIOs in a single call
+ */
+ int gpio_request_array(struct gpio *array, size_t num);
+
+ /* release multiple GPIOs in a single call
+ */
+ void gpio_free_array(struct gpio *array, size_t num);
+
+where 'flags' is currently defined to specify the following properties:
+
+ * GPIOF_DIR_IN - to configure direction as input
+ * GPIOF_DIR_OUT - to configure direction as output
+
+ * GPIOF_INIT_LOW - as output, set initial level to LOW
+ * GPIOF_INIT_HIGH - as output, set initial level to HIGH
+
+since GPIOF_INIT_* are only valid when configured as output, so group valid
+combinations as:
+
+ * GPIOF_IN - configure as input
+ * GPIOF_OUT_INIT_LOW - configured as output, initial level LOW
+ * GPIOF_OUT_INIT_HIGH - configured as output, initial level HIGH
+
+In the future, these flags can be extended to support more properties such
+as open-drain status.
+
+Further more, to ease the claim/release of multiple GPIOs, 'struct gpio' is
+introduced to encapsulate all three fields as:
+
+ struct gpio {
+ unsigned gpio;
+ unsigned long flags;
+ const char *label;
+ };
+
+A typical example of usage:
+
+ static struct gpio leds_gpios[] = {
+ { 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* default to ON */
+ { 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* default to OFF */
+ { 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* default to OFF */
+ { 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* default to OFF */
+ { ... },
+ };
+
+ err = gpio_request_one(31, GPIOF_IN, "Reset Button");
+ if (err)
+ ...
+
+ err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
+ if (err)
+ ...
+
+ gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
+

GPIOs mapped to IRQs
--------------------
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index a25ad28..0a81a1e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1239,6 +1239,64 @@ void gpio_free(unsigned gpio)
}
EXPORT_SYMBOL_GPL(gpio_free);

+/**
+ * gpio_request_one - request a single GPIO with initial configuration
+ * @gpio: the GPIO number
+ * @flags: GPIO configuration as specified by GPIOF_*
+ * @label: a literal description string of this GPIO
+ */
+int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+{
+ int err;
+
+ err = gpio_request(gpio, label);
+ if (err)
+ return err;
+
+ if (flags & GPIOF_DIR_IN)
+ err = gpio_direction_input(gpio);
+ else
+ err = gpio_direction_output(gpio,
+ (flags & GPIOF_INIT_HIGH) ? 1 : 0);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_one);
+
+/**
+ * gpio_request_array - request multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+int gpio_request_array(struct gpio *array, size_t num)
+{
+ int i, err;
+
+ for (i = 0; i < num; i++, array++) {
+ err = gpio_request_one(array->gpio, array->flags, array->label);
+ if (err)
+ goto err_free;
+ }
+ return 0;
+
+err_free:
+ while (i--)
+ gpio_free((--array)->gpio);
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_array);
+
+/**
+ * gpio_free_array - release multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+void gpio_free_array(struct gpio *array, size_t num)
+{
+ while (num--)
+ gpio_free((array++)->gpio);
+}
+EXPORT_SYMBOL_GPL(gpio_free_array);

/**
* gpiochip_is_requested - return string iff signal was requested
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 485eeb6..979c6a5 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -136,6 +136,32 @@ extern int __gpio_cansleep(unsigned gpio);

extern int __gpio_to_irq(unsigned gpio);

+#define GPIOF_DIR_OUT (0 << 0)
+#define GPIOF_DIR_IN (1 << 0)
+
+#define GPIOF_INIT_LOW (0 << 1)
+#define GPIOF_INIT_HIGH (1 << 1)
+
+#define GPIOF_IN (GPIOF_DIR_IN)
+#define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
+#define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
+
+/**
+ * struct gpio - a structure describing a GPIO with configuration
+ * @gpio: the GPIO number
+ * @flags: GPIO configuration as specified by GPIOF_*
+ * @label: a literal description string of this GPIO
+ */
+struct gpio {
+ unsigned gpio;
+ unsigned long flags;
+ const char *label;
+};
+
+extern int gpio_request_one(unsigned gpio, unsigned long flags, const
char *label);
+extern int gpio_request_array(struct gpio *array, size_t num);
+extern void gpio_free_array(struct gpio *array, size_t num);
+
#ifdef CONFIG_GPIO_SYSFS

/*


Attachments:
0001-gpio-introduce-gpio_request_one-and-friends.patch (5.90 kB)