Skip to content

Commit

Permalink
gpiolib: add gpio get direction callback support
Browse files Browse the repository at this point in the history
Add .get_direction callback to gpio_chip. This allows gpiolib
to check the current direction of a gpio.
Used to show the correct gpio direction in sysfs and debug entries.

If callback is not set then gpiolib will work as previously;
e.g. guessing everything is input until a direction is set.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Mathias Nyman authored and Linus Walleij committed Oct 26, 2012
1 parent d6a2fa0 commit 80b0a60
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 2 deletions.
38 changes: 37 additions & 1 deletion drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,32 @@ int __init gpiochip_reserve(int start, int ngpio)
return ret;
}

/* caller ensures gpio is valid and requested, chip->get_direction may sleep */
static int gpio_get_direction(unsigned gpio)
{
struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;

chip = gpio_to_chip(gpio);
gpio -= chip->base;

if (!chip->get_direction)
return status;

status = chip->get_direction(chip, gpio);
if (status > 0) {
/* GPIOF_DIR_IN, or other positive */
status = 1;
clear_bit(FLAG_IS_OUT, &desc->flags);
}
if (status == 0) {
/* GPIOF_DIR_OUT */
set_bit(FLAG_IS_OUT, &desc->flags);
}
return status;
}

#ifdef CONFIG_GPIO_SYSFS

/* lock protects against unexport_gpio() being called while
Expand Down Expand Up @@ -223,13 +249,15 @@ static ssize_t gpio_direction_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status;

mutex_lock(&sysfs_lock);

if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else
gpio_get_direction(gpio);
status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in");
Expand Down Expand Up @@ -1080,6 +1108,7 @@ int gpiochip_add(struct gpio_chip *chip)
* inputs (often with pullups enabled) so power
* usage is minimized. Linux code should set the
* gpio direction first thing; but until it does,
* and in case chip->get_direction is not set,
* we may expose the wrong direction in sysfs.
*/
gpio_desc[id].flags = !chip->direction_input
Expand Down Expand Up @@ -1231,9 +1260,15 @@ int gpio_request(unsigned gpio, const char *label)
desc_set_label(desc, NULL);
module_put(chip->owner);
clear_bit(FLAG_REQUESTED, &desc->flags);
goto done;
}
}

if (chip->get_direction) {
/* chip->get_direction may sleep */
spin_unlock_irqrestore(&gpio_lock, flags);
gpio_get_direction(gpio);
spin_lock_irqsave(&gpio_lock, flags);
}
done:
if (status)
pr_debug("gpio_request: gpio-%d (%s) status %d\n",
Expand Down Expand Up @@ -1769,6 +1804,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
continue;

gpio_get_direction(gpio);
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
gpio, gdesc->label,
Expand Down
5 changes: 4 additions & 1 deletion include/asm-generic/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ struct device_node;
* enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as
* disabling module power and clock; may sleep
* @get_direction: returns direction for signal "offset", 0=out, 1=in,
* (same as GPIOF_DIR_XXX), or negative error
* @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
Expand Down Expand Up @@ -100,7 +102,8 @@ struct gpio_chip {
unsigned offset);
void (*free)(struct gpio_chip *chip,
unsigned offset);

int (*get_direction)(struct gpio_chip *chip,
unsigned offset);
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,
Expand Down

0 comments on commit 80b0a60

Please sign in to comment.