lkml.org 
[lkml]   [2008]   [Sep]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[patch 2.6.27-rc7] gpiolib: request/free hooks
    Date
    From: David Brownell <dbrownell@users.sourceforge.net>

    Add a new internal mechanism to gpiolib to support low power
    operations by letting gpio_chip instances see when their GPIOs
    are in use. When no GPIOs are active, chips may be able to
    enter lower powered runtime states by disabling clocks and/or
    power domains.

    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    ---
    Documentation/gpio.txt | 4 ++++
    drivers/gpio/gpiolib.c | 42 ++++++++++++++++++++++++++++++------------
    include/asm-generic/gpio.h | 9 +++++++++
    3 files changed, 43 insertions(+), 12 deletions(-)

    --- a/Documentation/gpio.txt
    +++ b/Documentation/gpio.txt
    @@ -240,6 +240,10 @@ signal, or (b) something wrongly believe
    needed to manage a signal that's in active use. That is, requesting a
    GPIO can serve as a kind of lock.

    +Some platforms may also use knowledge about what GPIOs are active for
    +power management, such as by powering down unused chip sectors and, more
    +easily, gating off unused clocks.
    +
    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,
    --- a/drivers/gpio/gpiolib.c
    +++ b/drivers/gpio/gpiolib.c
    @@ -69,14 +69,18 @@ static inline void desc_set_label(struct
    * those calls have no teeth) we can't avoid autorequesting. This nag
    * message should motivate switching to explicit requests...
    */
    -static void gpio_ensure_requested(struct gpio_desc *desc)
    +static void gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
    {
    if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
    - pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
    + struct gpio_chip *chip = desc->chip;
    + int gpio = chip->base + offset;
    +
    + pr_warning("GPIO-%d autorequested\n", gpio);
    desc_set_label(desc, "[auto]");
    - if (!try_module_get(desc->chip->owner))
    - pr_err("GPIO-%d: module can't be gotten \n",
    - (int)(desc - gpio_desc));
    + if (!try_module_get(chip->owner))
    + pr_err("GPIO-%d: module can't be gotten \n", gpio);
    + if (chip->request)
    + chip->request(chip, offset);
    }
    }

    @@ -781,6 +785,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
    int gpio_request(unsigned gpio, const char *label)
    {
    struct gpio_desc *desc;
    + struct gpio_chip *chip;
    int status = -EINVAL;
    unsigned long flags;

    @@ -789,22 +794,31 @@ int gpio_request(unsigned gpio, const ch
    if (!gpio_is_valid(gpio))
    goto done;
    desc = &gpio_desc[gpio];
    - if (desc->chip == NULL)
    + chip = desc->chip;
    + if (chip == NULL)
    goto done;

    - if (!try_module_get(desc->chip->owner))
    + if (!try_module_get(chip->owner))
    goto done;

    /* NOTE: gpio_request() can be called in early boot,
    - * before IRQs are enabled.
    + * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
    */

    + if (chip->request) {
    + status = chip->request(chip, gpio - chip->base);
    + if (status < 0) {
    + module_put(chip->owner);
    + goto done;
    + }
    + }
    +
    if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
    desc_set_label(desc, label ? : "?");
    status = 0;
    } else {
    status = -EBUSY;
    - module_put(desc->chip->owner);
    + module_put(chip->owner);
    }

    done:
    @@ -820,6 +834,7 @@ void gpio_free(unsigned gpio)
    {
    unsigned long flags;
    struct gpio_desc *desc;
    + struct gpio_chip *chip;

    if (!gpio_is_valid(gpio)) {
    WARN_ON(extra_checks);
    @@ -831,8 +846,11 @@ void gpio_free(unsigned gpio)
    spin_lock_irqsave(&gpio_lock, flags);

    desc = &gpio_desc[gpio];
    - if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
    + chip = desc->chip;
    + if (chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
    desc_set_label(desc, NULL);
    + if (chip->free)
    + chip->free(chip, gpio - chip->base);
    module_put(desc->chip->owner);
    } else
    WARN_ON(extra_checks);
    @@ -898,7 +916,7 @@ int gpio_direction_input(unsigned gpio)
    gpio -= chip->base;
    if (gpio >= chip->ngpio)
    goto fail;
    - gpio_ensure_requested(desc);
    + gpio_ensure_requested(desc, gpio);

    /* now we know the gpio is valid and chip won't vanish */

    @@ -936,7 +954,7 @@ int gpio_direction_output(unsigned gpio,
    gpio -= chip->base;
    if (gpio >= chip->ngpio)
    goto fail;
    - gpio_ensure_requested(desc);
    + gpio_ensure_requested(desc, gpio);

    /* now we know the gpio is valid and chip won't vanish */

    --- a/include/asm-generic/gpio.h
    +++ b/include/asm-generic/gpio.h
    @@ -35,6 +35,10 @@ struct module;
    * @label: for diagnostics
    * @dev: optional device providing the GPIOs
    * @owner: helps prevent removal of modules exporting active GPIOs
    + * @request: optional hook for chip-specific activation, such as
    + * enabling module power and clock; may sleep
    + * @free: optional hook for chip-specific deactivation, such as
    + * disabling module power and clock; may sleep
    * @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
    @@ -67,6 +71,11 @@ struct gpio_chip {
    struct device *dev;
    struct module *owner;

    + int (*request)(struct gpio_chip *chip,
    + unsigned offset);
    + void (*free)(struct gpio_chip *chip,
    + unsigned offset);
    +
    int (*direction_input)(struct gpio_chip *chip,
    unsigned offset);
    int (*get)(struct gpio_chip *chip,

    \
     
     \ /
      Last update: 2008-09-25 00:21    [W:4.479 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site