Skip to content

Commit

Permalink
gpio: gpiolib: Support for open source/emitter gpios
Browse files Browse the repository at this point in the history
Adding support for the open source gpio on which client
can specify the open source property through GPIO flag
GPIOF_OPEN_SOURCE at the time of gpio request.
The open source pins are normally pulled low and it
cannot be driven to output with value of 0 and so
when client request for setting the pin to LOW, the
gpio will be set to input direction to make pin in tristate
and hence PULL-DOWN on pins will make the state to LOW.
The open source pin can be driven to HIGH by setting output
with value of 1.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviwed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
  • Loading branch information
Laxman Dewangan authored and Grant Likely committed Mar 5, 2012
1 parent aca5ce1 commit 25553ff
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
39 changes: 39 additions & 0 deletions drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct gpio_desc {
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */

#define ID_SHIFT 16 /* add new flags before this one */

Expand Down Expand Up @@ -1266,6 +1267,7 @@ void gpio_free(unsigned gpio)
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
} else
WARN_ON(extra_checks);

Expand All @@ -1290,6 +1292,9 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
if (flags & GPIOF_OPEN_DRAIN)
set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags);

if (flags & GPIOF_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags);

if (flags & GPIOF_DIR_IN)
err = gpio_direction_input(gpio);
else
Expand Down Expand Up @@ -1443,6 +1448,10 @@ int gpio_direction_output(unsigned gpio, int value)
if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags))
return gpio_direction_input(gpio);

/* Open source pin should not be driven to 0 */
if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags))
return gpio_direction_input(gpio);

spin_lock_irqsave(&gpio_lock, flags);

if (!gpio_is_valid(gpio))
Expand Down Expand Up @@ -1604,6 +1613,32 @@ static void _gpio_set_open_drain_value(unsigned gpio,
__func__, gpio, err);
}

/*
* _gpio_set_open_source() - Set the open source gpio's value.
* @gpio: Gpio whose state need to be set.
* @chip: Gpio chip.
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/
static void _gpio_set_open_source_value(unsigned gpio,
struct gpio_chip *chip, int value)
{
int err = 0;
if (value) {
err = chip->direction_output(chip, gpio - chip->base, 1);
if (!err)
set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
} else {
err = chip->direction_input(chip, gpio - chip->base);
if (!err)
clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
}
trace_gpio_direction(gpio, !value, err);
if (err < 0)
pr_err("%s: Error in set_value for open source gpio%d err %d\n",
__func__, gpio, err);
}


/**
* __gpio_set_value() - assign a gpio's value
* @gpio: gpio whose value will be assigned
Expand All @@ -1622,6 +1657,8 @@ void __gpio_set_value(unsigned gpio, int value)
trace_gpio_value(gpio, 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags))
_gpio_set_open_drain_value(gpio, chip, value);
else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags))
_gpio_set_open_source_value(gpio, chip, value);
else
chip->set(chip, gpio - chip->base, value);
}
Expand Down Expand Up @@ -1692,6 +1729,8 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
trace_gpio_value(gpio, 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags))
_gpio_set_open_drain_value(gpio, chip, value);
else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags))
_gpio_set_open_source_value(gpio, chip, value);
else
chip->set(chip, gpio - chip->base, value);
}
Expand Down
3 changes: 3 additions & 0 deletions include/linux/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
/* Gpio pin is open drain */
#define GPIOF_OPEN_DRAIN (1 << 2)

/* Gpio pin is open source */
#define GPIOF_OPEN_SOURCE (1 << 3)

/**
* struct gpio - a structure describing a GPIO with configuration
* @gpio: the GPIO number
Expand Down

0 comments on commit 25553ff

Please sign in to comment.