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>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
needed to manage a signal that's in active use. That is, requesting a
GPIO can serve as a kind of lock.
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,
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,
* when setting direction, and otherwise illegal. Until board setup code
* and drivers use explicit requests everywhere (which won't happen when
* those calls have no teeth) we can't avoid autorequesting. This nag
* when setting direction, and otherwise illegal. Until board setup code
* and drivers use explicit requests everywhere (which won't happen when
* those calls have no teeth) we can't avoid autorequesting. This nag
- * message should motivate switching to explicit requests...
+ * message should motivate switching to explicit requests... so should
+ * the weaker cleanup after faults, compared to gpio_request().
-static void gpio_ensure_requested(struct gpio_desc *desc)
+static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
{
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
{
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;
+
+ if (!try_module_get(chip->owner)) {
+ pr_err("GPIO-%d: module can't be gotten \n", gpio);
+ clear_bit(FLAG_REQUESTED, &desc->flags);
+ /* lose */
+ return -EIO;
+ }
+ pr_warning("GPIO-%d autorequested\n", gpio);
desc_set_label(desc, "[auto]");
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));
+ /* caller must chip->request() w/o spinlock */
+ if (chip->request)
+ return 1;
}
/* caller holds gpio_lock *OR* gpio is marked as requested */
}
/* caller holds gpio_lock *OR* gpio is marked as requested */
int gpio_request(unsigned gpio, const char *label)
{
struct gpio_desc *desc;
int gpio_request(unsigned gpio, const char *label)
{
struct gpio_desc *desc;
+ struct gpio_chip *chip;
int status = -EINVAL;
unsigned long flags;
int status = -EINVAL;
unsigned long flags;
if (!gpio_is_valid(gpio))
goto done;
desc = &gpio_desc[gpio];
if (!gpio_is_valid(gpio))
goto done;
desc = &gpio_desc[gpio];
- if (desc->chip == NULL)
+ chip = desc->chip;
+ if (chip == NULL)
- if (!try_module_get(desc->chip->owner))
+ if (!try_module_get(chip->owner))
goto done;
/* NOTE: gpio_request() can be called in early boot,
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 (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
*/
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
status = 0;
} else {
status = -EBUSY;
status = 0;
} else {
status = -EBUSY;
- module_put(desc->chip->owner);
+ module_put(chip->owner);
+ }
+
+ if (chip->request) {
+ /* chip->request may sleep */
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ status = chip->request(chip, gpio - chip->base);
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ if (status < 0) {
+ desc_set_label(desc, NULL);
+ module_put(chip->owner);
+ clear_bit(FLAG_REQUESTED, &desc->flags);
+ }
{
unsigned long flags;
struct gpio_desc *desc;
{
unsigned long flags;
struct gpio_desc *desc;
+ struct gpio_chip *chip;
if (!gpio_is_valid(gpio)) {
WARN_ON(extra_checks);
if (!gpio_is_valid(gpio)) {
WARN_ON(extra_checks);
spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[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_bit(FLAG_REQUESTED, &desc->flags)) {
+ if (chip->free) {
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ might_sleep_if(extra_checks && chip->can_sleep);
+ chip->free(chip, gpio - chip->base);
+ spin_lock_irqsave(&gpio_lock, flags);
+ }
desc_set_label(desc, NULL);
module_put(desc->chip->owner);
desc_set_label(desc, NULL);
module_put(desc->chip->owner);
+ clear_bit(FLAG_REQUESTED, &desc->flags);
} else
WARN_ON(extra_checks);
} else
WARN_ON(extra_checks);
gpio -= chip->base;
if (gpio >= chip->ngpio)
goto fail;
gpio -= chip->base;
if (gpio >= chip->ngpio)
goto fail;
- gpio_ensure_requested(desc);
+ status = gpio_ensure_requested(desc, gpio);
+ if (status < 0)
+ goto fail;
/* now we know the gpio is valid and chip won't vanish */
/* now we know the gpio is valid and chip won't vanish */
might_sleep_if(extra_checks && chip->can_sleep);
might_sleep_if(extra_checks && chip->can_sleep);
+ if (status) {
+ status = chip->request(chip, gpio);
+ if (status < 0) {
+ pr_debug("GPIO-%d: chip request fail, %d\n",
+ chip->base + gpio, status);
+ /* and it's not available to anyone else ...
+ * gpio_request() is the fully clean solution.
+ */
+ goto lose;
+ }
+ }
+
status = chip->direction_input(chip, gpio);
if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags);
status = chip->direction_input(chip, gpio);
if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags);
return status;
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
return status;
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
gpio -= chip->base;
if (gpio >= chip->ngpio)
goto fail;
gpio -= chip->base;
if (gpio >= chip->ngpio)
goto fail;
- gpio_ensure_requested(desc);
+ status = gpio_ensure_requested(desc, gpio);
+ if (status < 0)
+ goto fail;
/* now we know the gpio is valid and chip won't vanish */
/* now we know the gpio is valid and chip won't vanish */
might_sleep_if(extra_checks && chip->can_sleep);
might_sleep_if(extra_checks && chip->can_sleep);
+ if (status) {
+ status = chip->request(chip, gpio);
+ if (status < 0) {
+ pr_debug("GPIO-%d: chip request fail, %d\n",
+ chip->base + gpio, status);
+ /* and it's not available to anyone else ...
+ * gpio_request() is the fully clean solution.
+ */
+ goto lose;
+ }
+ }
+
status = chip->direction_output(chip, gpio, value);
if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags);
status = chip->direction_output(chip, gpio, value);
if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags);
return status;
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
return status;
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
* @label: for diagnostics
* @dev: optional device providing the GPIOs
* @owner: helps prevent removal of modules exporting active GPIOs
* @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
* @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
struct device *dev;
struct module *owner;
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,
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,