From: Anton Vorontsov <avorontsov@ru.mvista.com>
To: David Brownell <dbrownell@users.sourceforge.net>
Cc: linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org
Subject: [PATCH 1/2] gpiolib: Implement gpio_set_values_sync()
Date: Mon, 13 Jul 2009 19:19:42 +0400 [thread overview]
Message-ID: <20090713151942.GA4486@oksana.dev.rtsoft.ru> (raw)
In-Reply-To: <20090713151911.GA28114@oksana.dev.rtsoft.ru>
Sometimes it's necessary to set GPIO values synchronously, e.g.
when CPU's GPIOs go to a FPGA and the FPGA has no latch-enable line,
so intermediate values on GPIO lines may trigger unnecessary actions
by the FPGA.
Another usage is chip-select muxes, e.g. using X GPIOs as address lines
to mux 2^X chip-selects, and setting some amount of GPIOs at once may
be a huge win.
Note that it's not always possible to set up GPIOs synchronously, so
gpio_can_set_values_sync() call is implemented. Currently it checks
for two things:
1. Whether gpio_chip has .set_sync() callback;
2. Whether all passed GPIOs belong to one particular gpio_chip.
Someday we may want to implement chip-specific .can_set_sync() check,
but currently this isn't needed.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/gpio/gpiolib.c | 57 ++++++++++++++++++++++++++++++++++++++++++++
include/asm-generic/gpio.h | 8 ++++++
include/linux/gpio.h | 14 ++++++++++
3 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 51a8d41..cf714ad 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1067,6 +1067,53 @@ void __gpio_set_value(unsigned gpio, int value)
EXPORT_SYMBOL_GPL(__gpio_set_value);
/**
+ * __gpio_can_set_values_sync() - check if gpios can be set synchronously
+ * @num: amount of gpios
+ * @gpios: gpios in question
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_can_set_values_sync().
+ * It returns nonzero if an array of gpios can be set simultaneously.
+ */
+int __gpio_can_set_values_sync(unsigned num, unsigned *gpios)
+{
+ struct gpio_chip *chip;
+ unsigned i;
+
+ chip = gpio_to_chip(gpios[0]);
+ if (!chip->set_sync)
+ return 0;
+
+ for (i = 1; i < num; i++) {
+ if (chip != gpio_to_chip(gpios[i]))
+ return 0;
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(__gpio_can_set_values_sync);
+
+/**
+ * __gpio_set_values_sync() - assign gpios' values synchronously
+ * @num: amount of gpios
+ * @gpios: gpios whose value will be assigned
+ * @values: value to assign
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_set_values_sync().
+ * It invokes the associated gpio_chip.set_sync() method.
+ */
+void __gpio_set_values_sync(unsigned num, unsigned *gpios, int *values)
+{
+ struct gpio_chip *chip;
+
+ chip = gpio_to_chip(gpios[0]);
+ WARN_ON(extra_checks && chip->can_sleep);
+ chip->set_sync(chip, num, gpios, values);
+}
+EXPORT_SYMBOL_GPL(__gpio_set_values_sync);
+
+/**
* __gpio_cansleep() - report whether gpio value access will sleep
* @gpio: gpio in question
* Context: any
@@ -1129,6 +1176,16 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
}
EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+void gpio_set_values_sync_cansleep(unsigned num, unsigned *gpios, int *values)
+{
+ struct gpio_chip *chip;
+
+ might_sleep_if(extra_checks);
+ chip = gpio_to_chip(gpios[0]);
+ chip->set_sync(chip, num, gpios, values);
+}
+EXPORT_SYMBOL_GPL(gpio_set_values_sync_cansleep);
+
#ifdef CONFIG_DEBUG_FS
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d6c379d..c181623 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -88,6 +88,10 @@ struct gpio_chip {
unsigned offset, int value);
void (*set)(struct gpio_chip *chip,
unsigned offset, int value);
+ /* NOTE: _sync() version accepts gpios, not offsets. */
+ void (*set_sync)(struct gpio_chip *chip,
+ unsigned num, unsigned *gpios,
+ int *values);
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);
@@ -121,6 +125,8 @@ extern int gpio_direction_output(unsigned gpio, int value);
extern int gpio_get_value_cansleep(unsigned gpio);
extern void gpio_set_value_cansleep(unsigned gpio, int value);
+extern void gpio_set_values_sync_cansleep(unsigned num, unsigned *gpios,
+ int *values);
/* A platform's <asm/gpio.h> code may want to inline the I/O calls when
@@ -129,6 +135,8 @@ extern void gpio_set_value_cansleep(unsigned gpio, int value);
*/
extern int __gpio_get_value(unsigned gpio);
extern void __gpio_set_value(unsigned gpio, int value);
+extern int __gpio_can_set_values_sync(unsigned num, unsigned *gpios);
+extern void __gpio_set_values_sync(unsigned num, unsigned *gpios, int *values);
extern int __gpio_cansleep(unsigned gpio);
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index e10c49a..ff62c1e 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -62,6 +62,20 @@ static inline void gpio_set_value(unsigned gpio, int value)
WARN_ON(1);
}
+static inline int gpio_can_set_values_sync(unsigned num, unsigned *gpios)
+{
+ /* GPIO can never have been requested or set as output */
+ WARN_ON(1);
+ return 0;
+}
+
+static inline void gpio_set_values_sync(unsigned num, unsigned *gpios,
+ int *values)
+{
+ /* GPIO can never have been requested or set as output */
+ WARN_ON(1);
+}
+
static inline int gpio_cansleep(unsigned gpio)
{
/* GPIO can never have been requested or set as {in,out}put */
--
1.6.3.3
WARNING: multiple messages have this Message-ID (diff)
From: Anton Vorontsov <avorontsov@ru.mvista.com>
To: David Brownell <dbrownell@users.sourceforge.net>
Cc: Joakim Tjernlund <joakim.tjernlund@transmode.se>,
linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org
Subject: [PATCH 1/2] gpiolib: Implement gpio_set_values_sync()
Date: Mon, 13 Jul 2009 19:19:42 +0400 [thread overview]
Message-ID: <20090713151942.GA4486@oksana.dev.rtsoft.ru> (raw)
In-Reply-To: <20090713151911.GA28114@oksana.dev.rtsoft.ru>
Sometimes it's necessary to set GPIO values synchronously, e.g.
when CPU's GPIOs go to a FPGA and the FPGA has no latch-enable line,
so intermediate values on GPIO lines may trigger unnecessary actions
by the FPGA.
Another usage is chip-select muxes, e.g. using X GPIOs as address lines
to mux 2^X chip-selects, and setting some amount of GPIOs at once may
be a huge win.
Note that it's not always possible to set up GPIOs synchronously, so
gpio_can_set_values_sync() call is implemented. Currently it checks
for two things:
1. Whether gpio_chip has .set_sync() callback;
2. Whether all passed GPIOs belong to one particular gpio_chip.
Someday we may want to implement chip-specific .can_set_sync() check,
but currently this isn't needed.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/gpio/gpiolib.c | 57 ++++++++++++++++++++++++++++++++++++++++++++
include/asm-generic/gpio.h | 8 ++++++
include/linux/gpio.h | 14 ++++++++++
3 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 51a8d41..cf714ad 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1067,6 +1067,53 @@ void __gpio_set_value(unsigned gpio, int value)
EXPORT_SYMBOL_GPL(__gpio_set_value);
/**
+ * __gpio_can_set_values_sync() - check if gpios can be set synchronously
+ * @num: amount of gpios
+ * @gpios: gpios in question
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_can_set_values_sync().
+ * It returns nonzero if an array of gpios can be set simultaneously.
+ */
+int __gpio_can_set_values_sync(unsigned num, unsigned *gpios)
+{
+ struct gpio_chip *chip;
+ unsigned i;
+
+ chip = gpio_to_chip(gpios[0]);
+ if (!chip->set_sync)
+ return 0;
+
+ for (i = 1; i < num; i++) {
+ if (chip != gpio_to_chip(gpios[i]))
+ return 0;
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(__gpio_can_set_values_sync);
+
+/**
+ * __gpio_set_values_sync() - assign gpios' values synchronously
+ * @num: amount of gpios
+ * @gpios: gpios whose value will be assigned
+ * @values: value to assign
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_set_values_sync().
+ * It invokes the associated gpio_chip.set_sync() method.
+ */
+void __gpio_set_values_sync(unsigned num, unsigned *gpios, int *values)
+{
+ struct gpio_chip *chip;
+
+ chip = gpio_to_chip(gpios[0]);
+ WARN_ON(extra_checks && chip->can_sleep);
+ chip->set_sync(chip, num, gpios, values);
+}
+EXPORT_SYMBOL_GPL(__gpio_set_values_sync);
+
+/**
* __gpio_cansleep() - report whether gpio value access will sleep
* @gpio: gpio in question
* Context: any
@@ -1129,6 +1176,16 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
}
EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+void gpio_set_values_sync_cansleep(unsigned num, unsigned *gpios, int *values)
+{
+ struct gpio_chip *chip;
+
+ might_sleep_if(extra_checks);
+ chip = gpio_to_chip(gpios[0]);
+ chip->set_sync(chip, num, gpios, values);
+}
+EXPORT_SYMBOL_GPL(gpio_set_values_sync_cansleep);
+
#ifdef CONFIG_DEBUG_FS
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d6c379d..c181623 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -88,6 +88,10 @@ struct gpio_chip {
unsigned offset, int value);
void (*set)(struct gpio_chip *chip,
unsigned offset, int value);
+ /* NOTE: _sync() version accepts gpios, not offsets. */
+ void (*set_sync)(struct gpio_chip *chip,
+ unsigned num, unsigned *gpios,
+ int *values);
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);
@@ -121,6 +125,8 @@ extern int gpio_direction_output(unsigned gpio, int value);
extern int gpio_get_value_cansleep(unsigned gpio);
extern void gpio_set_value_cansleep(unsigned gpio, int value);
+extern void gpio_set_values_sync_cansleep(unsigned num, unsigned *gpios,
+ int *values);
/* A platform's <asm/gpio.h> code may want to inline the I/O calls when
@@ -129,6 +135,8 @@ extern void gpio_set_value_cansleep(unsigned gpio, int value);
*/
extern int __gpio_get_value(unsigned gpio);
extern void __gpio_set_value(unsigned gpio, int value);
+extern int __gpio_can_set_values_sync(unsigned num, unsigned *gpios);
+extern void __gpio_set_values_sync(unsigned num, unsigned *gpios, int *values);
extern int __gpio_cansleep(unsigned gpio);
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index e10c49a..ff62c1e 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -62,6 +62,20 @@ static inline void gpio_set_value(unsigned gpio, int value)
WARN_ON(1);
}
+static inline int gpio_can_set_values_sync(unsigned num, unsigned *gpios)
+{
+ /* GPIO can never have been requested or set as output */
+ WARN_ON(1);
+ return 0;
+}
+
+static inline void gpio_set_values_sync(unsigned num, unsigned *gpios,
+ int *values)
+{
+ /* GPIO can never have been requested or set as output */
+ WARN_ON(1);
+}
+
static inline int gpio_cansleep(unsigned gpio)
{
/* GPIO can never have been requested or set as {in,out}put */
--
1.6.3.3
next prev parent reply other threads:[~2009-07-13 15:19 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-07-13 15:19 [PATCH 0/2] Setting GPIOs simultaneously Anton Vorontsov
2009-07-13 15:19 ` Anton Vorontsov
2009-07-13 15:19 ` Anton Vorontsov [this message]
2009-07-13 15:19 ` [PATCH 1/2] gpiolib: Implement gpio_set_values_sync() Anton Vorontsov
2009-07-13 15:19 ` [PATCH 2/2] powerpc/qe: Implement set_sync() callback for QE GPIOs Anton Vorontsov
2009-07-13 15:19 ` Anton Vorontsov
2009-07-13 16:01 ` [PATCH 0/2] Setting GPIOs simultaneously Joakim Tjernlund
2009-07-13 16:01 ` Joakim Tjernlund
2009-07-13 17:34 ` Anton Vorontsov
2009-07-13 17:34 ` Anton Vorontsov
2009-07-13 19:59 ` Joakim Tjernlund
2009-07-13 19:59 ` Joakim Tjernlund
2009-07-13 22:20 ` Anton Vorontsov
2009-07-13 22:20 ` Anton Vorontsov
2009-07-14 21:20 ` Ang: " Joakim Tjernlund
2009-07-14 21:20 ` Joakim Tjernlund
2009-07-14 22:09 ` Anton Vorontsov
2009-07-14 22:09 ` Anton Vorontsov
2009-08-04 13:38 ` Joakim Tjernlund
2009-08-04 13:38 ` Joakim Tjernlund
2009-08-04 14:22 ` Anton Vorontsov
2009-08-04 14:22 ` Anton Vorontsov
2009-08-04 14:59 ` Joakim Tjernlund
2009-08-04 14:59 ` Joakim Tjernlund
2009-08-04 15:33 ` Anton Vorontsov
2009-08-04 15:33 ` Anton Vorontsov
[not found] ` <OFF188389D.68E638A2-ONC12575F2.00568C5B-C12575F2.0057FC95@LocalDomain>
2009-07-13 17:17 ` Joakim Tjernlund
2009-07-13 17:17 ` Joakim Tjernlund
2009-11-05 14:49 ` Kumar Gala
2009-11-05 14:49 ` Kumar Gala
2009-11-05 14:58 ` Anton Vorontsov
2009-11-05 14:58 ` Anton Vorontsov
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=20090713151942.GA4486@oksana.dev.rtsoft.ru \
--to=avorontsov@ru.mvista.com \
--cc=dbrownell@users.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc-dev@ozlabs.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.