Commit e48d194d authored by Linus Walleij's avatar Linus Walleij

gpio: Add comments on single direction chips

A patch from Ricardo got me thinking about some gpio chip
semantics so let's drop in some comments to make things
more clear around that.

Cc: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Cc: Bartosz Golaszewski <brgl@bgdev.pl>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent ae9847f4
...@@ -2548,19 +2548,30 @@ int gpiod_direction_input(struct gpio_desc *desc) ...@@ -2548,19 +2548,30 @@ int gpiod_direction_input(struct gpio_desc *desc)
VALIDATE_DESC(desc); VALIDATE_DESC(desc);
chip = desc->gdev->chip; chip = desc->gdev->chip;
/*
* It is legal to have no .get() and .direction_input() specified if
* the chip is output-only, but you can't specify .direction_input()
* and not support the .get() operation, that doesn't make sense.
*/
if (!chip->get && chip->direction_input) { if (!chip->get && chip->direction_input) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing get() and direction_input() operations\n", "%s: missing get() but have direction_input()\n",
__func__); __func__);
return -EIO; return -EIO;
} }
/*
* If we have a .direction_input() callback, things are simple,
* just call it. Else we are some input-only chip so try to check the
* direction (if .get_direction() is supported) else we silently
* assume we are in input mode after this.
*/
if (chip->direction_input) { if (chip->direction_input) {
status = chip->direction_input(chip, gpio_chip_hwgpio(desc)); status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
} else if (chip->get_direction && } else if (chip->get_direction &&
(chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) { (chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing direction_input() operation\n", "%s: missing direction_input() operation and line is output\n",
__func__); __func__);
return -EIO; return -EIO;
} }
...@@ -2587,6 +2598,11 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) ...@@ -2587,6 +2598,11 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
int val = !!value; int val = !!value;
int ret = 0; int ret = 0;
/*
* It's OK not to specify .direction_output() if the gpiochip is
* output-only, but if there is then not even a .set() operation it
* is pretty tricky to drive the output line.
*/
if (!gc->set && !gc->direction_output) { if (!gc->set && !gc->direction_output) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing set() and direction_output() operations\n", "%s: missing set() and direction_output() operations\n",
...@@ -2597,6 +2613,7 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) ...@@ -2597,6 +2613,7 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
if (gc->direction_output) { if (gc->direction_output) {
ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val); ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val);
} else { } else {
/* Check that we are in output mode if we can */
if (gc->get_direction && if (gc->get_direction &&
gc->get_direction(gc, gpio_chip_hwgpio(desc))) { gc->get_direction(gc, gpio_chip_hwgpio(desc))) {
gpiod_warn(desc, gpiod_warn(desc,
...@@ -2604,6 +2621,10 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) ...@@ -2604,6 +2621,10 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
__func__); __func__);
return -EIO; return -EIO;
} }
/*
* If we can't actively set the direction, we are some
* output-only chip, so just drive the output as desired.
*/
gc->set(gc, gpio_chip_hwgpio(desc), val); gc->set(gc, gpio_chip_hwgpio(desc), val);
} }
......
...@@ -178,9 +178,13 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip) ...@@ -178,9 +178,13 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
* @free: optional hook for chip-specific deactivation, such as * @free: optional hook for chip-specific deactivation, such as
* disabling module power and clock; may sleep * disabling module power and clock; may sleep
* @get_direction: returns direction for signal "offset", 0=out, 1=in, * @get_direction: returns direction for signal "offset", 0=out, 1=in,
* (same as GPIOF_DIR_XXX), or negative error * (same as GPIOF_DIR_XXX), or negative error.
* It is recommended to always implement this function, even on
* input-only or output-only gpio chips.
* @direction_input: configures signal "offset" as input, or returns error * @direction_input: configures signal "offset" as input, or returns error
* This can be omitted on input-only or output-only gpio chips.
* @direction_output: configures signal "offset" as output, or returns error * @direction_output: configures signal "offset" as output, or returns error
* This can be omitted on input-only or output-only gpio chips.
* @get: returns value for signal "offset", 0=low, 1=high, or negative error * @get: returns value for signal "offset", 0=low, 1=high, or negative error
* @get_multiple: reads values for multiple signals defined by "mask" and * @get_multiple: reads values for multiple signals defined by "mask" and
* stores them in "bits", returns 0 on success or negative error * stores them in "bits", returns 0 on success or negative error
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment