devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH] gpio: add GPIO hogging mechanism
@ 2013-12-19 14:34 Boris BREZILLON
       [not found] ` <1387463671-1164-1-git-send-email-b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
  0 siblings, 1 reply; 34+ messages in thread
From: Boris BREZILLON @ 2013-12-19 14:34 UTC (permalink / raw)
  To: Rob Landley, Linus Walleij, Alexandre Courbot, Jiri Prchal,
	Ben Gamari, Mark Rutland, Greg Kroah-Hartman
  Cc: linux-doc, linux-kernel, linux-gpio, devicetree, Boris BREZILLON

Hello,

This a proposal for the GPIO hog concept described by Linus (Walleij).

I know there were work in progress on this subject (Jiri and Ben at least:
https://www.mail-archive.com/linux-gpio@vger.kernel.org/msg00864.html),
so don't hesitate to point out if something similar has already been posted.

Best Regards,

Boris 

Boris BREZILLON (1):
  gpio: add GPIO hogging mechanism

 Documentation/devicetree/bindings/gpio/gpio.txt |   47 ++++++++
 drivers/base/Makefile                           |    1 +
 drivers/base/dd.c                               |    5 +
 drivers/base/gpio.c                             |   59 ++++++++++
 drivers/gpio/devres.c                           |   39 +++++++
 drivers/gpio/gpiolib-of.c                       |  134 +++++++++++++++++++++++
 drivers/gpio/gpiolib.c                          |  103 +++++++++++++++++
 include/linux/device.h                          |    5 +
 include/linux/gpio/consumer.h                   |   25 +++++
 include/linux/gpio/devinfo.h                    |   38 +++++++
 include/linux/of_gpio.h                         |   19 ++++
 11 files changed, 475 insertions(+)
 create mode 100644 drivers/base/gpio.c
 create mode 100644 include/linux/gpio/devinfo.h

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 34+ messages in thread
* [RFC Patch] gpio: add GPIO hogging mechanism
@ 2014-10-21 20:09 Benoit Parrot
  2014-10-29  7:09 ` Alexandre Courbot
                   ` (3 more replies)
  0 siblings, 4 replies; 34+ messages in thread
From: Benoit Parrot @ 2014-10-21 20:09 UTC (permalink / raw)
  To: linus.walleij, linux-gpio; +Cc: linux-kernel, devicetree, Benoit Parrot

Based on Boris Brezillion work this is a reworked patch
of his initial GPIO hogging mechanism.
This patch provides a way to initally configure specific GPIO
when the gpio controller is probe.

The actual DT scanning to collect the GPIO specific data is performed
as part of the gpiochip_add().

The purpose of this is to allows specific GPIOs to be configured
without any driver specific code.
This particularly usueful because board design are getting
increassingly complex and given SoC pins can now have upward
of 10 mux values a lot of connections are now dependent on
external IO muxes to switch various modes and combination.

Specific drivers should not necessarily need to be aware of
what accounts to a specific board implementation. This board level
"description" should be best kept as part of the dts file.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 Documentation/devicetree/bindings/gpio/gpio.txt | 33 +++++++++
 drivers/gpio/gpiolib-of.c                       | 99 +++++++++++++++++++++++++
 drivers/gpio/gpiolib.c                          | 81 ++++++++++++++++++++
 include/linux/of_gpio.h                         | 11 +++
 4 files changed, 224 insertions(+)

diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index 3fb8f53..a9700d8 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -103,6 +103,26 @@ Every GPIO controller node must contain both an empty "gpio-controller"
 property, and a #gpio-cells integer property, which indicates the number of
 cells in a gpio-specifier.
 
+It might contain GPIO hog definitions. GPIO hogging is a mechanism providing
+automatic GPIO request and configuration as part of the gpio-controller's
+driver probe function.
+
+Each GPIO hog definition is represented as a child node of the GPIO controller.
+Required properties:
+- gpios: store the gpio information (id, flags, ...). Shall contain the
+  number of cells specified in its parent node (GPIO controller node).
+- input: a property specifying to set the GPIO direction as input.
+- output-high: a property specifying to set the GPIO direction to output with
+  the value high.
+- output-low: a property specifying to set the GPIO direction to output with
+  the value low.
+
+Optional properties:
+- line-name: the GPIO label name. If not present the node name is used.
+
+A GPIO controller can request GPIO hogs using the "gpio-hogs" property, which
+encodes a list of requested GPIO hogs.
+
 Example of two SOC GPIO banks defined as gpio-controller nodes:
 
 	qe_pio_a: gpio-controller@1400 {
@@ -110,6 +130,19 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
 		reg = <0x1400 0x18>;
 		gpio-controller;
 		#gpio-cells = <2>;
+		gpio-hogs = <&line_b>;
+
+		/* line_a hog is defined but not enabled in this example*/
+		line_a: line_a {
+			gpios = <5 0>;
+			input;
+		};
+
+		line_b: line_b {
+			gpios = <6 0>;
+			output-low;
+			line-name = "foo-bar-gpio";
+		};
 	};
 
 	qe_pio_e: gpio-controller@1460 {
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 604dbe6..7308dfc 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -111,6 +111,105 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
 EXPORT_SYMBOL(of_get_named_gpio_flags);
 
 /**
+ * of_get_gpio_hog() - Get a GPIO hog descriptor, names and flags for GPIO API
+ * @np:		device node to get GPIO from
+ * @index:	index of the GPIO
+ * @name:	GPIO line name
+ * @flags:	a flags pointer to fill in
+ *
+ * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
+ * value on the error condition.
+ */
+struct gpio_desc *of_get_gpio_hog(struct device_node *np, int index,
+				  const char **name, unsigned long *flags)
+{
+	struct device_node *cfg_np, *chip_np;
+	enum of_gpio_flags xlate_flags;
+	unsigned long req_flags = 0;
+	struct gpio_desc *desc;
+	struct gg_data gg_data = {
+		.flags = &xlate_flags,
+		.out_gpio = NULL,
+	};
+	u32 tmp;
+	int i;
+	int ret;
+
+	cfg_np = of_parse_phandle(np, "gpio-hogs", index);
+	if (!cfg_np)
+		return ERR_PTR(-EINVAL);
+
+	chip_np = cfg_np->parent;
+	if (!chip_np) {
+		desc = ERR_PTR(-EINVAL);
+		goto out;
+	}
+
+	ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
+	if (ret) {
+		desc = ERR_PTR(ret);
+		goto out;
+	}
+
+	if (tmp > MAX_PHANDLE_ARGS) {
+		desc = ERR_PTR(-EINVAL);
+		goto out;
+	}
+
+	gg_data.gpiospec.args_count = tmp;
+	gg_data.gpiospec.np = chip_np;
+	for (i = 0; i < tmp; i++) {
+		ret = of_property_read_u32(cfg_np, "gpios",
+					   &gg_data.gpiospec.args[i]);
+		if (ret) {
+			desc = ERR_PTR(ret);
+			goto out;
+		}
+	}
+
+	gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
+	if (!gg_data.out_gpio) {
+		if (cfg_np->parent == np)
+			desc = ERR_PTR(-ENXIO);
+		else
+			desc = ERR_PTR(-EPROBE_DEFER);
+
+		goto out;
+	}
+
+	if (xlate_flags & OF_GPIO_ACTIVE_LOW)
+		req_flags |= GPIOF_ACTIVE_LOW;
+
+	if (of_property_read_bool(cfg_np, "input")) {
+		req_flags |= GPIOF_DIR_IN;
+	} else if (of_property_read_bool(cfg_np, "output-high")) {
+		req_flags |= GPIOF_INIT_HIGH;
+	} else if (!of_property_read_bool(cfg_np, "output-low")) {
+		desc = ERR_PTR(-EINVAL);
+		goto out;
+	}
+
+	if (of_property_read_bool(cfg_np, "open-drain-line"))
+		req_flags |= GPIOF_OPEN_DRAIN;
+
+	if (of_property_read_bool(cfg_np, "open-source-line"))
+		req_flags |= GPIOF_OPEN_DRAIN;
+
+	if (name && of_property_read_string(cfg_np, "line-name", name))
+		*name = cfg_np->name;
+
+	if (flags)
+		*flags = req_flags;
+
+	desc = gg_data.out_gpio;
+
+out:
+	of_node_put(cfg_np);
+
+	return desc;
+}
+
+/**
  * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
  * @gc:		pointer to the gpio_chip structure
  * @np:		device node of the GPIO chip
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e8e98ca..b6f5bdb 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -55,6 +55,9 @@ static DEFINE_MUTEX(gpio_lookup_lock);
 static LIST_HEAD(gpio_lookup_list);
 LIST_HEAD(gpio_chips);
 
+struct gpio_desc *__must_check gpiod_get_hog_index(struct device *dev,
+						   unsigned int idx);
+
 static inline void desc_set_label(struct gpio_desc *d, const char *label)
 {
 	d->label = label;
@@ -226,6 +229,8 @@ int gpiochip_add(struct gpio_chip *chip)
 	int		status = 0;
 	unsigned	id;
 	int		base = chip->base;
+	struct gpio_desc	*desc;
+	int		i;
 
 	if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
 			&& base >= 0) {
@@ -275,6 +280,16 @@ int gpiochip_add(struct gpio_chip *chip)
 	of_gpiochip_add(chip);
 	acpi_gpiochip_add(chip);
 
+	/*
+	 * Instantiate GPIO hogs
+	 * There shouldn't be mores hogs then gpio available on this chip
+	 */
+	for (i = 0; i < chip->ngpio; i++) {
+		desc = gpiod_get_hog_index(chip->dev, i);
+		if (IS_ERR(desc))
+			break;
+	}
+
 	if (status)
 		goto fail;
 
@@ -1742,6 +1757,72 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,
 EXPORT_SYMBOL_GPL(__gpiod_get_index_optional);
 
 /**
+ * gpiod_get_hog_index - obtain a GPIO from a multi-index GPIO hog
+ * @dev:	GPIO consumer
+ * @idx:	index of the GPIO to obtain
+ *
+ * This should only be used by the gpiochip_add to request/set GPIO initial
+ * configuration.
+ *
+ * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error.
+ */
+struct gpio_desc *__must_check gpiod_get_hog_index(struct device *dev,
+						   unsigned int idx)
+{
+	struct gpio_desc *desc = NULL;
+	int err;
+	unsigned long flags;
+	const char *name;
+
+	/* Using device tree? */
+	if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
+		desc = of_get_gpio_hog(dev->of_node, idx, &name, &flags);
+
+	if (!desc)
+		return ERR_PTR(-ENOTSUPP);
+	else if (IS_ERR(desc))
+		return desc;
+
+	dev_dbg(dev, "gpio-hog: GPIO:%d (%s) as %s%s\n",
+		desc_to_gpio(desc), name, (flags&GPIOF_DIR_IN)?"input":"output",
+		(flags&GPIOF_DIR_IN)?"":(flags&GPIOF_INIT_HIGH)?"/high":"/low");
+
+	err = gpiod_request(desc, name);
+	if (err)
+		return ERR_PTR(err);
+
+	if (flags & GPIOF_OPEN_DRAIN)
+		set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+
+	if (flags & GPIOF_OPEN_SOURCE)
+		set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+	if (flags & GPIOF_ACTIVE_LOW)
+		set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+	if (flags & GPIOF_DIR_IN)
+		err = gpiod_direction_input(desc);
+	else
+		err = gpiod_direction_output_raw(desc,
+				(flags & GPIOF_INIT_HIGH) ? 1 : 0);
+
+	if (err)
+		goto free_gpio;
+
+	if (flags & GPIOF_EXPORT) {
+		err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
+		if (err)
+			goto free_gpio;
+	}
+
+	return desc;
+
+free_gpio:
+	gpiod_free(desc);
+	return ERR_PTR(err);
+}
+
+/**
  * gpiod_put - dispose of a GPIO descriptor
  * @desc:	GPIO descriptor to dispose of
  *
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 38fc050..52d154c 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -59,6 +59,9 @@ extern int of_gpio_simple_xlate(struct gpio_chip *gc,
 				const struct of_phandle_args *gpiospec,
 				u32 *flags);
 
+extern struct gpio_desc *of_get_gpio_hog(struct device_node *np, int index,
+					 const char **name,
+					 unsigned long *flags);
 #else /* CONFIG_OF_GPIO */
 
 /* Drivers may not strictly depend on the GPIO support, so let them link. */
@@ -78,6 +81,14 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
 static inline void of_gpiochip_add(struct gpio_chip *gc) { }
 static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
 
+static inline struct gpio_desc *of_get_gpio_hog(struct device_node *np,
+						int index,
+						const char **name,
+						unsigned long *flags)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
 #endif /* CONFIG_OF_GPIO */
 
 /**
-- 
1.8.5.1


^ permalink raw reply related	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2014-11-14 10:22 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-19 14:34 [RFC PATCH] gpio: add GPIO hogging mechanism Boris BREZILLON
     [not found] ` <1387463671-1164-1-git-send-email-b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ@public.gmane.org>
2013-12-19 14:34   ` Boris BREZILLON
2013-12-19 16:41     ` Greg Kroah-Hartman
2013-12-19 16:47       ` Felipe Balbi
2013-12-19 17:18         ` boris brezillon
2013-12-19 18:22           ` Felipe Balbi
2013-12-30  9:48             ` boris brezillon
2014-01-08  9:45               ` Linus Walleij
     [not found]       ` <20131219164109.GB27409-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2013-12-19 17:13         ` boris brezillon
2014-09-20 21:37       ` Ben Gamari
2014-09-20 22:26         ` Ben Gamari
2014-01-08  9:37     ` Linus Walleij
2014-01-08 10:18       ` boris brezillon
2014-01-14 10:27         ` Linus Walleij
  -- strict thread matches above, loose matches on Subject: below --
2014-10-21 20:09 [RFC Patch] " Benoit Parrot
2014-10-29  7:09 ` Alexandre Courbot
2014-10-29 16:21   ` Benoit Parrot
2014-10-30  0:29     ` Alexandre Courbot
2014-11-14  9:19   ` Linus Walleij
2014-11-14 10:22     ` Maxime Ripard
2014-10-29  8:53 ` Pantelis Antoniou
2014-10-29 16:34   ` Benoit Parrot
2014-10-29 16:42     ` Pantelis Antoniou
2014-10-29 19:36       ` Benoit Parrot
2014-10-30  0:31       ` Alexandre Courbot
2014-11-03  9:43   ` Linus Walleij
2014-10-29 10:45 ` Maxime Ripard
2014-10-29 16:41   ` Benoit Parrot
2014-10-29 16:47     ` Maxime Ripard
2014-10-29 23:09       ` Benoit Parrot
2014-10-30 17:16         ` Maxime Ripard
2014-11-03  9:59 ` Linus Walleij
2014-11-04  0:38   ` Benoit Parrot
     [not found]     ` <20141104003827.GA24005-l0cyMroinI0@public.gmane.org>
2014-11-14  9:16       ` Linus Walleij

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).