From: Alexandre Courbot <acourbot@nvidia.com>
To: Linus Walleij <linus.walleij@linaro.org>,
Arnd Bergmann <arnd@arndb.de>,
Grant Likely <grant.likely@linaro.org>,
Thierry Reding <thierry.reding@gmail.com>,
Stephen Warren <swarren@wwwdotorg.org>
Cc: <gnurou@gmail.com>, <linux-gpio@vger.kernel.org>,
<linux-doc@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<linux-arch@vger.kernel.org>, <devicetree@vger.kernel.org>,
Alexandre Courbot <acourbot@nvidia.com>
Subject: [RFC 4/5] gpiolib: add gpiod_get() and gpiod_put() functions
Date: Wed, 4 Sep 2013 20:29:28 +0900 [thread overview]
Message-ID: <1378294169-22661-5-git-send-email-acourbot@nvidia.com> (raw)
In-Reply-To: <1378294169-22661-1-git-send-email-acourbot@nvidia.com>
Add gpiod_get() and gpiod_put() functions that provide safer handling of
GPIOs.
These functions put the GPIO framework in line with the conventions of
other frameworks in the kernel, and help ensure every GPIO is declared
properly and valid while it is used.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/gpio/gpiolib.c | 166 ++++++++++++++++++++++++++++++++++++++++++
include/linux/gpio/consumer.h | 8 ++
include/linux/gpio/driver.h | 38 ++++++++++
3 files changed, 212 insertions(+)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e255eee..4a91e03 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -69,6 +69,8 @@ static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio)
+static DEFINE_MUTEX(gpio_lookup_lock);
+static LIST_HEAD(gpio_lookup_list);
static LIST_HEAD(gpio_chips);
#ifdef CONFIG_GPIO_SYSFS
@@ -1997,6 +1999,170 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
}
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
+/**
+ * gpiod_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,
+ unsigned long *flags)
+{
+ char prop_name[32]; /* 32 is max size of property name */
+ enum of_gpio_flags of_flags;
+ struct gpio_desc *desc;
+
+ if (con_id)
+ snprintf(prop_name, 32, "%s-gpios", con_id);
+ else
+ snprintf(prop_name, 32, "gpios");
+
+ desc = of_get_named_gpiod_flags(dev->of_node, prop_name, 0, &of_flags);
+
+ if (IS_ERR(desc))
+ return desc;
+
+ if (of_flags & OF_GPIO_ACTIVE_LOW)
+ *flags |= GPIOF_ACTIVE_LOW;
+
+ return desc;
+}
+#else
+static struct device_node *of_find_gpio(struct device *dev, const char *id
+ unsigned long flags)
+{
+ return NULL;
+}
+#endif
+
+static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
+ unsigned long *flags)
+{
+ 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);
+ *flags = p->flags;
+
+ 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;
+ unsigned long flags = 0;
+
+ 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, &flags);
+ } else {
+ dev_dbg(dev, "using lookup tables for GPIO lookup");
+ desc = gpiod_find(dev, con_id, &flags);
+ }
+
+ 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);
+
+ if (flags & GPIOF_ACTIVE_LOW)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+ 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 ba39e09..da9cdb2 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -18,6 +18,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(const struct gpio_desc *desc);
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index b84ca26..5aa26b5 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -121,5 +121,43 @@ extern int __must_check gpiochip_remove(struct gpio_chip *chip);
extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, void *data));
+/**
+ * Lookup table for associating GPIOs to specific devices and functions using
+ * platform data.
+ */
+struct gpiod_lookup {
+ struct list_head list;
+ /*
+ * name of the chip the GPIO belongs to
+ */
+ const char *chip_label;
+ /*
+ * hardware number (i.e. relative to the chip) of the GPIO
+ */
+ u16 chip_hwnum;
+ /*
+ * name of device that can claim this GPIO
+ */
+ const char *dev_id;
+ /*
+ * name of the GPIO from the device's point of view
+ */
+ const char *con_id;
+ /*
+ * mask of GPIOF_* values
+ */
+ unsigned long flags;
+};
+
+#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id, flags) \
+{ \
+ .chip_label = _chip_label, \
+ .chip_hwnum = _chip_hwnum, \
+ .dev_id = _dev_id, \
+ .con_id = _con_id, \
+ .flags = flags, \
+}
+
+void gpiod_add_table(struct gpiod_lookup *table, size_t size);
#endif
--
1.8.4
next prev parent reply other threads:[~2013-09-04 11:30 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-04 11:29 [RFC 0/5] New descriptor-based GPIO interface Alexandre Courbot
2013-09-04 11:29 ` [RFC 1/5] gpiolib: factorize gpiod_get/set functions Alexandre Courbot
2013-09-20 8:36 ` Linus Walleij
2013-09-21 12:39 ` Alexandre Courbot
2013-09-04 11:29 ` [RFC 2/5] gpiolib: export descriptor-based GPIO interface Alexandre Courbot
2013-09-04 19:58 ` Stephen Warren
2013-09-05 3:45 ` Alexandre Courbot
2013-09-04 11:29 ` [RFC 3/5] gpiolib: port of_ functions to use gpiod Alexandre Courbot
2013-09-04 11:29 ` Alexandre Courbot [this message]
2013-09-04 19:56 ` [RFC 4/5] gpiolib: add gpiod_get() and gpiod_put() functions Stephen Warren
2013-09-05 3:44 ` Alexandre Courbot
2013-09-11 13:57 ` Thierry Reding
2013-09-20 18:40 ` Linus Walleij
2013-09-23 9:31 ` Mika Westerberg
2013-09-04 11:29 ` [RFC 5/5] gpiolib: update documentation Alexandre Courbot
2013-09-20 17:59 ` Linus Walleij
2013-09-20 8:28 ` [RFC 0/5] New descriptor-based GPIO interface Linus Walleij
2013-09-20 18:06 ` Linus Walleij
2013-09-20 19:32 ` Thierry Reding
2013-09-20 21:23 ` Linus Walleij
2013-09-21 12:32 ` Alexandre Courbot
2013-09-23 10:21 ` Mika Westerberg
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=1378294169-22661-5-git-send-email-acourbot@nvidia.com \
--to=acourbot@nvidia.com \
--cc=arnd@arndb.de \
--cc=devicetree@vger.kernel.org \
--cc=gnurou@gmail.com \
--cc=grant.likely@linaro.org \
--cc=linus.walleij@linaro.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=swarren@wwwdotorg.org \
--cc=thierry.reding@gmail.com \
/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
Powered by JetHome