All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rojhalat Ibrahim <imr@rtschenk.de>
To: linux-gpio@vger.kernel.org
Subject: [RFC PATCH] gpiolib: introduce gpio_set_multiple function
Date: Thu, 23 Jan 2014 13:19:42 +0100	[thread overview]
Message-ID: <2473803.SebQ52F62q@pcimr> (raw)

This patch introduces a new function gpio_set_multiple which allows setting
multiple GPIO lines on the same chip with just one function call. If a
corresponding set_multi function is defined for the chip performance can be
significantly improved. Otherwise gpio_set_multiple uses the chip's set
function and the performance stays the same as without the new function.
For my application, where I have to frequently set 9 GPIO lines in order to
configure an FPGA, configuration time goes down from 48 s to 15 s when I use
this new function. (Tested with a modified gpio-mpc8xxx module.)

Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de>
---
 drivers/gpio/gpiolib.c        |   59 ++++++++++++++++++++++++++++++++++++++++++
 include/asm-generic/gpio.h    |   17 ++++++++++++
 include/linux/gpio.h          |   20 ++++++++++++++
 include/linux/gpio/consumer.h |   14 +++++++++
 include/linux/gpio/driver.h   |    3 ++
 5 files changed, 113 insertions(+)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 50c4922..8355acb 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2099,6 +2099,44 @@ void gpiod_set_value(struct gpio_desc *desc, int value)
 }
 EXPORT_SYMBOL_GPL(gpiod_set_value);
 
+static void _gpiod_set_raw_multiple(struct gpio_chip *chip,
+				    u64 mask, u64 value)
+{
+	if (chip->set_multi)
+		chip->set_multi(chip, mask, value);
+	else {
+		int i;
+		for (i=0; i<64; i++) {
+			if (i > chip->ngpio - 1)
+				break;
+			if (mask & ((u64)(1) << i))
+				chip->set(chip, i, (value >> i) & 1);
+		}
+	}
+}
+
+/**
+ * gpiod_set_raw_multiple() - assign values to multiple GPIOs
+ * @chip: chip the GPIOs belong to
+ * @mask: only GPIOs with corresponding bits in mask set are modified
+ * @value: value bits to assign to GPIOs
+ *
+ * Set the raw values of multiple GPIOs, i.e. physical line values without
+ * regard for their ACTIVE_LOW status.
+ *
+ * This function should be called from contexts where we cannot sleep, and will
+ * complain if the GPIO chip functions potentially sleep.
+ */
+void gpiod_set_raw_multiple(struct gpio_chip *chip, u64 mask, u64 value)
+{
+	if (!chip)
+		return;
+	/* Should be using gpio_set_multiple_cansleep() */
+	WARN_ON(chip->can_sleep);
+	_gpiod_set_raw_multiple(chip, mask, value);
+}
+EXPORT_SYMBOL_GPL(gpiod_set_raw_multiple);
+
 /**
  * gpiod_cansleep() - report whether gpio value access may sleep
  * @desc: gpio to check
@@ -2272,6 +2310,27 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
 EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
 
 /**
+ * gpiod_set_raw_multiple_cansleep() - assign values to multiple GPIOs
+ * @chip: chip the GPIOs belong to
+ * @mask: only GPIOs with corresponding bits in mask set are modified
+ * @value: value bits to assign to GPIOs
+ *
+ * Set the raw values of multiple GPIOs, i.e. physical line values without
+ * regard for their ACTIVE_LOW status.
+ *
+ * This function is to be called from contexts that can sleep.
+ */
+void gpiod_set_raw_multiple_cansleep(struct gpio_chip *chip,
+				     u64 mask, u64 value)
+{
+	might_sleep_if(extra_checks);
+	if (!chip)
+		return;
+	_gpiod_set_raw_multiple(chip, mask, value);
+}
+EXPORT_SYMBOL_GPL(gpiod_set_raw_multiple_cansleep);
+
+/**
  * gpiod_add_lookup_table() - register GPIO device consumers
  * @table: table of consumers to register
  */
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index a5f56a0..c53d8ac 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -85,6 +85,11 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
 {
 	return gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value);
 }
+static inline void gpio_set_multiple_cansleep(struct gpio_chip *chip, u64 mask,
+					      u64 value)
+{
+	return gpiod_set_raw_multiple_cansleep(chip, mask, value);
+}
 
 
 /* A platform's <asm/gpio.h> code may want to inline the I/O calls when
@@ -99,6 +104,11 @@ static inline void __gpio_set_value(unsigned gpio, int value)
 {
 	return gpiod_set_raw_value(gpio_to_desc(gpio), value);
 }
+static inline void __gpio_set_multiple(struct gpio_chip *chip, u64 mask,
+				       u64 value)
+{
+	return gpiod_set_raw_multiple(chip, mask, value);
+}
 
 static inline int __gpio_cansleep(unsigned gpio)
 {
@@ -218,6 +228,13 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
 	__gpio_set_value(gpio, value);
 }
 
+static inline void gpio_set_multiple_cansleep(struct gpio_chip *chip, u64 mask,
+					      u64 value)
+{
+	might_sleep();
+	__gpio_set_multiple(chip, mask, value);
+}
+
 #endif /* !CONFIG_GPIOLIB */
 
 #endif /* _ASM_GENERIC_GPIO_H */
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index b581b13..cbb4725 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -60,6 +60,12 @@ static inline void gpio_set_value(unsigned int gpio, int value)
 	__gpio_set_value(gpio, value);
 }
 
+static inline void gpio_set_multiple(struct gpio_chip *chip, u64 mask,
+				     u64 value)
+{
+	__gpio_set_multiple(chip, mask, value);
+}
+
 static inline int gpio_cansleep(unsigned int gpio)
 {
 	return __gpio_cansleep(gpio);
@@ -161,6 +167,13 @@ static inline void gpio_set_value(unsigned gpio, int value)
 	WARN_ON(1);
 }
 
+static inline void gpio_set_multiple(struct gpio_chip *chip, u64 mask,
+				     u64 value)
+{
+	/* 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 */
@@ -181,6 +194,13 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
 	WARN_ON(1);
 }
 
+static inline void gpio_set_multiple_cansleep(struct gpio_chip *chip,
+					      u64 mask, u64 value)
+{
+	/* GPIO can never have been requested or set as output */
+	WARN_ON(1);
+}
+
 static inline int gpio_export(unsigned gpio, bool direction_may_change)
 {
 	/* GPIO can never have been requested or set as {in,out}put */
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 4d34dbb..5ffdbd0 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -42,12 +42,14 @@ int gpiod_get_value(const struct gpio_desc *desc);
 void gpiod_set_value(struct gpio_desc *desc, int value);
 int gpiod_get_raw_value(const struct gpio_desc *desc);
 void gpiod_set_raw_value(struct gpio_desc *desc, int value);
+void gpiod_set_raw_multiple(struct gpio_chip *chip, u64 mask, u64 value);
 
 /* Value get/set from sleeping context */
 int gpiod_get_value_cansleep(const struct gpio_desc *desc);
 void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
 int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
 void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
+void gpiod_set_raw_multiple_cansleep(struct gpio_chip *chip, u64 mask, u64 value);
 
 int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
 
@@ -145,6 +147,12 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
 	/* GPIO can never have been requested */
 	WARN_ON(1);
 }
+static inline void gpiod_set_raw_multiple(struct gpio_chip *chip, u64 mask,
+					  u64 value)
+{
+	/* GPIO can never have been requested */
+	WARN_ON(1);
+}
 
 static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
 {
@@ -169,6 +177,12 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
 	/* GPIO can never have been requested */
 	WARN_ON(1);
 }
+static inline void gpiod_set_raw_multiple_cansleep(struct gpio_chip *chip,
+						   u64 mask, u64 value)
+{
+	/* GPIO can never have been requested */
+	WARN_ON(1);
+}
 
 static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
 {
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index a3e181e..571ad82 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -27,6 +27,7 @@ struct seq_file;
  * @get: returns value for signal "offset"; for output signals this
  *	returns either the value actually sensed, or zero
  * @set: assigns output value for signal "offset"
+ * @set_multi: assigns output values for multiple signals defined by "mask"
  * @set_debounce: optional hook for setting debounce time for specified gpio in
  *      interrupt triggered gpio chips
  * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
@@ -79,6 +80,8 @@ struct gpio_chip {
 						unsigned offset);
 	void			(*set)(struct gpio_chip *chip,
 						unsigned offset, int value);
+	void			(*set_multi)(struct gpio_chip *chip,
+					        u64 mask, u64 value);
 	int			(*set_debounce)(struct gpio_chip *chip,
 						unsigned offset,
 						unsigned debounce);
--
1.8.3.2


             reply	other threads:[~2014-01-23 12:19 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-01-23 12:19 Rojhalat Ibrahim [this message]
2014-01-24  2:44 ` [RFC PATCH] gpiolib: introduce gpio_set_multiple function Alexandre Courbot
2014-01-24 12:36 ` Gerhard Sittig
2014-01-27  8:12   ` Rojhalat Ibrahim

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=2473803.SebQ52F62q@pcimr \
    --to=imr@rtschenk.de \
    --cc=linux-gpio@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.