From: Alexandre Courbot <acourbot@nvidia.com>
To: Grant Likely <grant.likely@secretlab.ca>,
Linus Walleij <linus.walleij@linaro.org>,
Arnd Bergmann <arnd@arndb.de>
Cc: Guenter Roeck <linux@roeck-us.net>,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
devicetree-discuss@lists.ozlabs.org,
Alexandre Courbot <gnurou@gmail.com>,
Alexandre Courbot <acourbot@nvidia.com>
Subject: [PATCH 2/4] gpiolib: add gpiod_get and gpiod_put functions
Date: Tue, 8 Jan 2013 16:18:53 +0900 [thread overview]
Message-ID: <1357629535-26033-3-git-send-email-acourbot@nvidia.com> (raw)
In-Reply-To: <1357629535-26033-1-git-send-email-acourbot@nvidia.com>
Adds new GPIO allocation functions that work with the opaque descriptor
interface.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/gpio/gpiolib.c | 164 ++++++++++++++++++++++++++++++++++++++++++
include/linux/gpio/consumer.h | 8 +++
include/linux/gpio/driver.h | 21 ++++++
3 files changed, 193 insertions(+)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d04b90b..06ffadb 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3,6 +3,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
+#include <linux/list.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/debugfs.h>
@@ -74,6 +75,11 @@ struct gpio_desc {
};
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
+/* protects both gpio_lookup_list and gpio_chips */
+static DEFINE_MUTEX(gpio_lookup_lock);
+static LIST_HEAD(gpio_lookup_list);
+static LIST_HEAD(gpio_chips);
+
#ifdef CONFIG_GPIO_SYSFS
static DEFINE_IDR(dirent_idr);
#endif
@@ -1162,6 +1168,11 @@ int gpiochip_add(struct gpio_chip *chip)
of_gpiochip_add(chip);
+ INIT_LIST_HEAD(&chip->list);
+ mutex_lock(&gpio_lookup_lock);
+ list_add(&chip->list, &gpio_chips);
+ mutex_unlock(&gpio_lookup_lock);
+
unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
@@ -1200,6 +1211,10 @@ int gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags);
+ mutex_lock(&gpio_lookup_lock);
+ list_del_init(&chip->list);
+ mutex_unlock(&gpio_lookup_lock);
+
gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip);
@@ -1924,6 +1939,155 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
}
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
+
+/**
+ * gpioh_add_table() - register GPIO device consumers
+ * @table: array of consumers to register
+ * @num: number of consumers in table
+ */
+void gpiod_add_table(struct gpiod_lookup *table, size_t size)
+{
+ mutex_lock(&gpio_lookup_lock);
+
+ while (size--) {
+ list_add_tail(&table->list, &gpio_lookup_list);
+ table++;
+ }
+
+ mutex_unlock(&gpio_lookup_lock);
+}
+
+/*
+ * Caller must have a acquired gpio_lookup_lock
+ */
+static struct gpio_chip *find_chip_by_name(const char *name)
+{
+ struct gpio_chip *chip = NULL;
+
+ list_for_each_entry(chip, &gpio_lookup_list, list) {
+ if (chip->label == NULL)
+ continue;
+ if (!strcmp(chip->label, name))
+ break;
+ }
+
+ return chip;
+}
+
+#ifdef CONFIG_OF
+static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id)
+{
+ char prop_name[32]; /* 32 is max size of property name */
+
+ if (con_id)
+ snprintf(prop_name, 32, "%s-gpios", con_id);
+ else
+ snprintf(prop_name, 32, "gpios");
+
+ return of_get_named_gpiod_flags(dev->of_node, prop_name, 0, NULL);
+}
+#else
+static struct device_node *of_find_gpio(struct device *dev, const char *id)
+{
+ return NULL;
+}
+#endif
+
+static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id)
+{
+ const char *dev_id = dev ? dev_name(dev) : NULL;
+ struct gpio_desc *desc = ERR_PTR(-ENODEV);
+ unsigned int match, best = 0;
+ struct gpiod_lookup *p;
+
+ mutex_lock(&gpio_lookup_lock);
+
+ list_for_each_entry(p, &gpio_lookup_list, list) {
+ match = 0;
+
+ if (p->dev_id) {
+ if (!dev_id || strcmp(p->dev_id, dev_id))
+ continue;
+
+ match += 2;
+ }
+
+ if (p->con_id) {
+ if (!con_id || strcmp(p->con_id, con_id))
+ continue;
+
+ match += 1;
+ }
+
+ if (match > best) {
+ struct gpio_chip *chip;
+
+ chip = find_chip_by_name(p->chip_label);
+ if (!chip) {
+ dev_warn(dev, "cannot find GPIO chip %s\n",
+ p->chip_label);
+ continue;
+ }
+
+ if (chip->ngpio >= p->chip_hwnum) {
+ dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
+ chip->label, chip->ngpio);
+ continue;
+ }
+
+ desc = gpio_to_desc(chip->base + p->chip_hwnum);
+
+ if (match != 3)
+ best = match;
+ else
+ break;
+ }
+ }
+
+ mutex_unlock(&gpio_lookup_lock);
+
+ return desc;
+}
+
+/**
+ *
+ */
+struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id)
+{
+ struct gpio_desc *desc;
+ int status;
+
+ dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
+
+ /* Using device tree? */
+ if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) {
+ dev_dbg(dev, "using device tree for GPIO lookup\n");
+ desc = of_find_gpio(dev, con_id);
+ } else {
+ dev_dbg(dev, "using lookup tables for GPIO lookup");
+ desc = gpiod_find(dev, con_id);
+ }
+
+ if (IS_ERR(desc)) {
+ dev_warn(dev, "lookup for GPIO %s failed\n", con_id);
+ return desc;
+ }
+
+ status = gpiod_request(desc, con_id);
+
+ if (status < 0)
+ return ERR_PTR(status);
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(gpiod_get);
+
+void gpiod_put(struct gpio_desc *desc)
+{
+ gpiod_free(desc);
+}
+EXPORT_SYMBOL_GPL(gpiod_put);
+
#ifdef CONFIG_DEBUG_FS
static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 0ce96cf..2f30761 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -15,6 +15,14 @@ struct gpio_chip;
*/
struct gpio_desc;
+struct gpio_desc *__must_check gpiod_get(struct device *dev,
+ const char *con_id);
+void gpiod_put(struct gpio_desc *desc);
+
+struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
+ const char *con_id);
+void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
+
struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc);
struct gpio_chip *gpiod_to_chip(struct gpio_desc *desc);
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index d42f941..d43d671 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -4,12 +4,14 @@
#ifdef CONFIG_GPIOLIB
#include <linux/types.h>
+#include <linux/list.h>
/**
* struct gpio_chip - abstract a GPIO controller
* @label: for diagnostics
* @dev: optional device providing the GPIOs
* @owner: helps prevent removal of modules exporting active GPIOs
+ * @list: links gpio_chips together for traversal
* @request: optional hook for chip-specific activation, such as
* enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as
@@ -55,6 +57,7 @@ struct gpio_chip {
const char *label;
struct device *dev;
struct module *owner;
+ struct list_head list;
int (*request)(struct gpio_chip *chip,
unsigned offset);
@@ -107,6 +110,24 @@ struct gpio_chip {
#endif
};
+struct gpiod_lookup {
+ struct list_head list;
+ const char *chip_label;
+ u16 chip_hwnum;
+ const char *dev_id;
+ const char *con_id;
+};
+
+#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id) \
+{ \
+ .chip_label = _chip_label, \
+ .chip_hwnum = _chip_hwnum, \
+ .dev_id = _dev_id, \
+ .con_id = _con_id, \
+}
+
+void gpiod_add_table(struct gpiod_lookup *table, size_t size);
+
#endif /* CONFIG_GPIOLIB */
#endif
--
1.8.1
next prev parent reply other threads:[~2013-01-08 7:18 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-01-08 7:18 [PATCH 0/4] gpio: introduce descriptor-based interface Alexandre Courbot
2013-01-08 7:18 ` [PATCH 1/4] gpiolib: introduce descriptor-based GPIO interface Alexandre Courbot
2013-01-08 7:18 ` Alexandre Courbot
2013-01-08 12:59 ` Arnd Bergmann
2013-01-09 1:06 ` Alexandre Courbot
2013-01-09 10:25 ` Russell King - ARM Linux
2013-01-09 10:35 ` Arnd Bergmann
2013-01-09 10:44 ` Russell King - ARM Linux
2013-01-09 11:10 ` Russell King - ARM Linux
[not found] ` <20130109111055.GG3931-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2013-01-09 11:52 ` Arnd Bergmann
2013-01-09 11:52 ` Arnd Bergmann
2013-01-09 14:44 ` Nicolas Pitre
2013-01-09 15:04 ` [PATCH] Proposed removal of IS_ERR_OR_NULL() (was: Re: [PATCH 1/4] gpiolib: introduce descriptor-based GPIO interface) Russell King - ARM Linux
[not found] ` <20130109150427.GL3931-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2013-01-09 15:21 ` Grant Likely
2013-01-09 15:21 ` Grant Likely
2013-01-09 15:26 ` Arnd Bergmann
2013-01-09 15:27 ` Nicolas Pitre
2013-01-09 15:27 ` Nicolas Pitre
2013-01-09 15:51 ` Russell King - ARM Linux
2013-01-09 16:09 ` Nicolas Pitre
2013-01-09 16:21 ` Russell King - ARM Linux
2013-01-09 17:12 ` Russell King - ARM Linux
2013-01-09 17:52 ` Tony Lindgren
2013-01-17 10:28 ` Linus Walleij
2013-01-10 8:36 ` [PATCH 1/4] gpiolib: introduce descriptor-based GPIO interface Thierry Reding
2013-01-10 8:36 ` Thierry Reding
2013-01-08 7:18 ` Alexandre Courbot [this message]
2013-01-08 7:18 ` [PATCH 2/4] gpiolib: add gpiod_get and gpiod_put functions Alexandre Courbot
2013-01-08 13:07 ` Arnd Bergmann
2013-01-09 1:49 ` Alexandre Courbot
2013-01-08 7:18 ` [PATCH 3/4] gpiolib: of: convert OF helpers to descriptor API Alexandre Courbot
2013-01-08 7:18 ` Alexandre Courbot
2013-01-08 7:18 ` [PATCH 4/4] gpiolib: add documentation for new gpiod_ API Alexandre Courbot
2013-01-08 7:18 ` Alexandre Courbot
2013-01-08 13:06 ` [PATCH 0/4] gpio: introduce descriptor-based interface Arnd Bergmann
2013-01-08 13:06 ` Arnd Bergmann
2013-01-09 1:48 ` Alexandre Courbot
2013-01-09 10:46 ` Arnd Bergmann
2013-01-10 4:07 ` Alex Courbot
2013-01-10 10:08 ` Arnd Bergmann
2013-01-14 10:21 ` Alex Courbot
2013-01-14 10:46 ` Arnd Bergmann
2013-01-14 10:46 ` Arnd Bergmann
2013-01-17 11:15 ` Linus Walleij
2013-01-17 11:15 ` Linus Walleij
2013-01-17 12:02 ` Greg Ungerer
2013-01-17 16:50 ` Steven King
2013-01-17 16:50 ` Steven King
2013-01-17 19:22 ` Arnd Bergmann
2013-01-20 6:07 ` Alex Courbot
2013-01-22 8:55 ` Linus Walleij
2013-01-22 8:55 ` Linus Walleij
2013-01-17 11:25 ` 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=1357629535-26033-3-git-send-email-acourbot@nvidia.com \
--to=acourbot@nvidia.com \
--cc=arnd@arndb.de \
--cc=devicetree-discuss@lists.ozlabs.org \
--cc=gnurou@gmail.com \
--cc=grant.likely@secretlab.ca \
--cc=linus.walleij@linaro.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).