From: Mathias Nyman <mathias.nyman@linux.intel.com>
To: linus.walleij@stericsson.com
Cc: grant.likely@secretlab.ca, linux-kernel@vger.kernel.org,
Mathias Nyman <mathias.nyman@linux.intel.com>
Subject: [RFC PATCH] gpiolib: add gpio get direction support
Date: Mon, 22 Oct 2012 16:44:14 +0300 [thread overview]
Message-ID: <1350913454-26927-1-git-send-email-mathias.nyman@linux.intel.com> (raw)
Add gpio_get_direction() for checking the current direction of a gpio.
Returns 1 for input, 0 for output, or negative error.
Gpio drivers need to set the gpio_chip .get_direction callback for this
functionality, otherwise gpio_get_direction() returns error.
If the .get_direction callback is set, then gpiolib will use it
for showing correct gpio direction in sysfs and debug. If not set
then it will work the old way; e.g. guessing everything is input
until direction is set.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/gpio/gpiolib.c | 64 ++++++++++++++++++++++++++++++++++++++++++-
include/asm-generic/gpio.h | 6 +++-
include/linux/gpio.h | 5 +++
3 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index de0213c..28deb86 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -223,6 +223,7 @@ 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);
@@ -230,6 +231,7 @@ static ssize_t gpio_direction_show(struct device *dev,
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");
@@ -1073,6 +1075,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
@@ -1392,6 +1395,62 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* rely on gpio_request() having been called beforehand.
*/
+int gpio_get_direction(unsigned gpio)
+{
+ 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->get_direction)
+ 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(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.
+ */
+ 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;
+fail:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpio_get_direction);
+
int gpio_direction_input(unsigned gpio)
{
unsigned long flags;
@@ -1761,8 +1820,9 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
continue;
-
- is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
+ chip->get_direction
+ ? (is_out = !chip->get_direction(chip, i))
+ : (is_out = test_bit(FLAG_IS_OUT, &gdesc->flags));
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
gpio, gdesc->label,
is_out ? "out" : "in ",
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 365ea09..4e58743 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -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
@@ -98,7 +100,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,
@@ -153,6 +156,7 @@ extern struct gpio_chip *gpiochip_find(void *data,
extern int gpio_request(unsigned gpio, const char *label);
extern void gpio_free(unsigned gpio);
+extern int gpio_get_direction(unsigned gpio);
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 2e31e8b..9bfc008 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -141,6 +141,11 @@ static inline void gpio_free_array(const struct gpio *array, size_t num)
WARN_ON(1);
}
+static inline int gpio_get_direction(unsigned gpio)
+{
+ return -ENOSYS;
+}
+
static inline int gpio_direction_input(unsigned gpio)
{
return -ENOSYS;
--
1.7.4.1
next reply other threads:[~2012-10-22 13:42 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-22 13:44 Mathias Nyman [this message]
2012-10-22 22:23 ` [RFC PATCH] gpiolib: add gpio get direction support Linus Walleij
2012-10-23 11:06 ` Mathias Nyman
2012-10-24 5:39 ` Linus Walleij
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1350913454-26927-1-git-send-email-mathias.nyman@linux.intel.com \
--to=mathias.nyman@linux.intel.com \
--cc=grant.likely@secretlab.ca \
--cc=linus.walleij@stericsson.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.