lkml.org 
[lkml]   [2010]   [Feb]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 1/3] gpiolib: add gpio_set_direction()
Date
Combine gpio_direction_input() and gpio_direction_output() into
gpio_set_direction().
Add 'none' and 'inout' directions to the sysfs interface.

Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
CC: Andres Salomon <dilinger@collabora.co.uk>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: David Brownell <dbrownell@users.sourceforge.net>
CC: Jani Nikula <ext-jani.1.nikula@nokia.com>
---
drivers/gpio/gpiolib.c | 123 ++++++++++++++++++++++----------------------
include/asm-generic/gpio.h | 6 ++
include/linux/gpio.h | 5 ++
3 files changed, 73 insertions(+), 61 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 350842a..4dd6e44 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -47,13 +47,14 @@ struct gpio_desc {
unsigned long flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED 0
-#define FLAG_IS_OUT 1
+#define FLAG_IS_OUT 1 /* output is enabled */
#define FLAG_RESERVED 2
#define FLAG_EXPORT 3 /* protected by sysfs_lock */
#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */
#define FLAG_TRIG_FALL 5 /* trigger on falling edge */
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
+#define FLAG_IS_IN 8 /* input is enabled */

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

@@ -228,10 +229,14 @@ static ssize_t gpio_direction_show(struct device *dev,

if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
- else
- status = sprintf(buf, "%s\n",
- test_bit(FLAG_IS_OUT, &desc->flags)
- ? "out" : "in");
+ else {
+ status = ((test_bit(FLAG_IS_IN, &desc->flags) ? 1 : 0) |
+ (test_bit(FLAG_IS_OUT, &desc->flags) ? 2 : 0));
+ status = sprintf(buf, "%s%s%s\n",
+ (status == 0) ? "none" : "",
+ (status & 1) ? "in" : "",
+ (status & 2) ? "out" : "");
+ }

mutex_unlock(&sysfs_lock);
return status;
@@ -249,11 +254,15 @@ static ssize_t gpio_direction_store(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else if (sysfs_streq(buf, "high"))
- status = gpio_direction_output(gpio, 1);
+ status = gpio_set_direction(gpio, 2, 1);
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
- status = gpio_direction_output(gpio, 0);
+ status = gpio_set_direction(gpio, 2, 0);
else if (sysfs_streq(buf, "in"))
- status = gpio_direction_input(gpio);
+ status = gpio_set_direction(gpio, 1, 0);
+ else if (sysfs_streq(buf, "inout"))
+ status = gpio_set_direction(gpio, 3, 0);
+ else if (sysfs_streq(buf, "none"))
+ status = gpio_set_direction(gpio, 0, 0);
else
status = -EINVAL;

@@ -1277,7 +1286,7 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* rely on gpio_request() having been called beforehand.
*/

-int gpio_direction_input(unsigned gpio)
+int gpio_set_direction(unsigned gpio, int direction, int value)
{
unsigned long flags;
struct gpio_chip *chip;
@@ -1289,7 +1298,13 @@ int gpio_direction_input(unsigned gpio)
if (!gpio_is_valid(gpio))
goto fail;
chip = desc->chip;
- if (!chip || !chip->get || !chip->direction_input)
+ if (!chip)
+ goto fail;
+ if ((direction & 1) &&
+ (!chip->get || (!chip->direction_input && !chip->set_direction)))
+ goto fail;
+ if ((direction & 2) &&
+ (!chip->set || (!chip->direction_output && !chip->set_direction)))
goto fail;
gpio -= chip->base;
if (gpio >= chip->ngpio)
@@ -1316,9 +1331,36 @@ int gpio_direction_input(unsigned gpio)
}
}

- status = chip->direction_input(chip, gpio);
- if (status == 0)
- clear_bit(FLAG_IS_OUT, &desc->flags);
+ if (chip->set_direction) {
+ status = chip->set_direction(chip, gpio, direction, value);
+ if (status == 0) {
+ if (direction & 1)
+ set_bit(FLAG_IS_IN, &desc->flags);
+ else
+ clear_bit(FLAG_IS_IN, &desc->flags);
+ if (direction & 2)
+ set_bit(FLAG_IS_OUT, &desc->flags);
+ else
+ clear_bit(FLAG_IS_OUT, &desc->flags);
+ }
+ }
+ else if (direction == 1) {
+ status = chip->direction_input(chip, gpio);
+ if (status == 0) {
+ clear_bit(FLAG_IS_OUT, &desc->flags);
+ set_bit(FLAG_IS_IN, &desc->flags);
+ }
+ }
+ else if (direction == 2) {
+ status = chip->direction_output(chip, gpio, value);
+ if (status == 0) {
+ clear_bit(FLAG_IS_IN, &desc->flags);
+ set_bit(FLAG_IS_OUT, &desc->flags);
+ }
+ }
+ else
+ /* cannot do 'none' or 'inout' without chip->set_direction */
+ status = -ENOTSUPP;
lose:
return status;
fail:
@@ -1328,58 +1370,17 @@ fail:
__func__, gpio, status);
return status;
}
+EXPORT_SYMBOL_GPL(gpio_set_direction);
+
+int gpio_direction_input(unsigned gpio)
+{
+ return gpio_set_direction(gpio, 1, 0);
+}
EXPORT_SYMBOL_GPL(gpio_direction_input);

int gpio_direction_output(unsigned gpio, int value)
{
- unsigned long flags;
- struct gpio_chip *chip;
- struct gpio_desc *desc = &gpio_desc[gpio];
- int status = -EINVAL;
-
- spin_lock_irqsave(&gpio_lock, flags);
-
- if (!gpio_is_valid(gpio))
- goto fail;
- chip = desc->chip;
- if (!chip || !chip->set || !chip->direction_output)
- goto fail;
- gpio -= chip->base;
- if (gpio >= chip->ngpio)
- goto fail;
- status = gpio_ensure_requested(desc, gpio);
- if (status < 0)
- goto fail;
-
- /* now we know the gpio is valid and chip won't vanish */
-
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- 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);
-lose:
- return status;
-fail:
- spin_unlock_irqrestore(&gpio_lock, flags);
- if (status)
- pr_debug("%s: gpio-%d status %d\n",
- __func__, gpio, status);
- return status;
+ return gpio_set_direction(gpio, 2, value);
}
EXPORT_SYMBOL_GPL(gpio_direction_output);

diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 485eeb6..17c7642 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -41,6 +41,8 @@ struct module;
* enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as
* disabling module power and clock; may sleep
+ * @set_direction: configures signal "offset" as "direction" (0-3, bit0=input,
+ * bit1=output) or returns 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
@@ -82,6 +84,9 @@ struct gpio_chip {
void (*free)(struct gpio_chip *chip,
unsigned offset);

+ int (*set_direction)(struct gpio_chip *chip,
+ unsigned offset,
+ int direction, int value);
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,
@@ -118,6 +123,7 @@ extern int __must_check gpiochip_remove(struct gpio_chip *chip);
extern int gpio_request(unsigned gpio, const char *label);
extern void gpio_free(unsigned gpio);

+extern int gpio_set_direction(unsigned gpio, int direction, int value);
extern int gpio_direction_input(unsigned gpio);
extern int gpio_direction_output(unsigned gpio, int value);

diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 4e949a5..cdc2117 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -41,6 +41,11 @@ static inline void gpio_free(unsigned gpio)
WARN_ON(1);
}

+static inline int gpio_set_direction(unsigned gpio, int direction, int value)
+{
+ return -ENOSYS;
+}
+
static inline int gpio_direction_input(unsigned gpio)
{
return -ENOSYS;
--
1.7.0


\
 
 \ /
  Last update: 2010-02-27 00:29    [W:0.105 / U:1.048 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site