All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH] gpio: add gpio-hog support
@ 2019-05-27  6:30 Heiko Schocher
  2019-05-27  7:13 ` Michal Simek
  0 siblings, 1 reply; 4+ messages in thread
From: Heiko Schocher @ 2019-05-27  6:30 UTC (permalink / raw)
  To: u-boot

add gpio-hog support. GPIO hogging is a mechanism
providing automatic GPIO request and configuration
as part of the gpio-controller's driver probe function.

for more infos see:
doc/device-tree-bindings/gpio/gpio.txt

Signed-off-by: Heiko Schocher <hs@denx.de>

---
clean travis build, see:
https://travis-ci.org/hsdenx/u-boot-test/builds/537358599

 doc/device-tree-bindings/gpio/gpio.txt |  52 ++++++++
 drivers/gpio/Kconfig                   |  10 ++
 drivers/gpio/gpio-uclass.c             | 162 +++++++++++++++++++++++--
 include/asm-generic/gpio.h             |  24 ++++
 4 files changed, 236 insertions(+), 12 deletions(-)

diff --git a/doc/device-tree-bindings/gpio/gpio.txt b/doc/device-tree-bindings/gpio/gpio.txt
index f7a158d858..54f5ff6c7f 100644
--- a/doc/device-tree-bindings/gpio/gpio.txt
+++ b/doc/device-tree-bindings/gpio/gpio.txt
@@ -210,3 +210,55 @@ Example 2:
 Here, three GPIO ranges are defined wrt. two pin controllers. pinctrl1 GPIO
 ranges are defined using pin numbers whereas the GPIO ranges wrt. pinctrl2
 are named "foo" and "bar".
+
+3) GPIO hog definitions
+-----------------------
+
+The GPIO chip may 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:
+- gpio-hog:   A property specifying that this child node represents a GPIO hog.
+- gpios:      Store the GPIO information (id, flags) for the GPIO to
+	      affect.
+
+              ! Not yet support more than one gpio !
+
+Only one of the following properties scanned in the order shown below.
+- input:      A property specifying to set the GPIO direction as input.
+- output-low  A property specifying to set the GPIO direction as output with
+	      the value low.
+- output-high A property specifying to set the GPIO direction as output with
+	      the value high.
+
+Example:
+
+        tca6416 at 20 {
+                compatible = "ti,tca6416";
+                reg = <0x20>;
+                #gpio-cells = <2>;
+                gpio-controller;
+
+                env_reset {
+                        gpio-hog;
+                        input;
+                        gpios = <6 GPIO_ACTIVE_LOW>;
+                };
+                boot_rescue {
+                        gpio-hog;
+                        input;
+                        gpios = <7 GPIO_ACTIVE_LOW>;
+                };
+        };
+
+For the above Example you can than access the gpio in your boardcode
+with:
+
+        desc = gpio_hog_lookup_name("boot_rescue.gpio-hog");
+        if (desc) {
+                if (dm_gpio_get_value(desc))
+                        printf("\nBooting into Rescue System\n");
+		else
+			printf("\nBoot normal\n");
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e36a8abc42..fa1c99700f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -14,6 +14,16 @@ config DM_GPIO
 	  particular GPIOs that they provide. The uclass interface
 	  is defined in include/asm-generic/gpio.h.
 
+config DM_GPIO_HOG
+	bool "Enable GPIO hog support"
+	depends on DM_GPIO
+	default n
+	help
+	  Enable gpio hog support
+	  The GPIO chip may contain GPIO hog definitions. GPIO hogging
+	  is a mechanism providing automatic GPIO request and config-
+	  uration as part of the gpio-controller's driver probe function.
+
 config ALTERA_PIO
 	bool "Altera PIO driver"
 	depends on DM_GPIO
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index da5e9ba6e5..193dd841fc 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -5,6 +5,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dm/device-internal.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <errno.h>
 #include <fdtdec.h>
@@ -15,6 +16,17 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+struct gpio_priv_one {
+	struct list_head list;
+	char *name;
+	struct gpio_desc gpiod;
+};
+
+#if defined(CONFIG_DM_GPIO_HOG)
+static struct list_head hogs;
+static int probed_hogs;
+#endif
+
 /**
  * gpio_to_device() - Convert global GPIO number to device, number
  *
@@ -141,6 +153,105 @@ static int gpio_find_and_xlate(struct gpio_desc *desc,
 		return gpio_xlate_offs_flags(desc->dev, desc, args);
 }
 
+#if defined(CONFIG_DM_GPIO_HOG)
+struct gpio_desc *gpio_hog_lookup_name(const char *name)
+{
+	struct list_head *entry;
+	struct gpio_priv_one *cur;
+
+	list_for_each(entry, &hogs) {
+		cur = list_entry(entry, struct gpio_priv_one, list);
+		if (strcmp(cur->name, name) == 0)
+			return &cur->gpiod;
+	}
+
+	/* OK, not found ... may gpio driver is not probed ? */
+	if (!probed_hogs) {
+		struct udevice *dev;
+
+		/* probe all ... may we find a better way ... */
+		for (uclass_first_device(UCLASS_GPIO, &dev);
+		     dev;
+		     uclass_next_device(&dev)) {
+			device_probe(dev);
+		}
+		probed_hogs = 1;
+	}
+	return NULL;
+}
+
+static int gpio_hog(struct udevice *dev)
+{
+	ofnode node;
+	struct gpio_dev_priv *uc_priv = NULL;
+
+	uc_priv = dev_get_uclass_priv(dev);
+	if (!uc_priv) {
+		printf("%s: missing private data.\n", __func__);
+		return -EINVAL;
+	}
+
+	/* scan for gpio-hog subnodes */
+	dev_for_each_subnode(node, dev) {
+		int ret;
+		u32 val[2];
+		int value = 0;
+		int gpiod_flags;
+		struct gpio_priv_one *new;
+
+		if (!ofnode_read_bool(node, "gpio-hog"))
+			continue;
+
+		if (ofnode_read_bool(node, "input")) {
+			gpiod_flags = GPIOD_IS_IN;
+		} else if (ofnode_read_bool(node, "output-high")) {
+			value = 1;
+			gpiod_flags = GPIOD_IS_OUT;
+		} else if (ofnode_read_bool(node, "output-low")) {
+			gpiod_flags = GPIOD_IS_OUT;
+		} else {
+			printf("%s: missing gpio-hog state.\n", __func__);
+			return -EINVAL;
+		}
+
+		ret = ofnode_read_u32_array(node, "gpios", val, 2);
+		if (ret) {
+			printf("%s: wrong gpios property, 2 values needed, ret: %d\n", __func__, ret);
+			return ret;
+		}
+
+		new = calloc(1, sizeof(struct gpio_priv_one));
+		ret = gpio_dev_request_index(dev, node, "gpio-hog", val[0], gpiod_flags,
+					     val[1], &new->gpiod);
+		if (ret < 0) {
+			debug("%s: node %s could not get gpio.\n", __func__,
+			      ofnode_get_name(node));
+			free(new);
+			return ret;
+		}
+
+		new->name = uc_priv->name[new->gpiod.offset];
+		list_add_tail(&new->list, &hogs);
+		if (gpiod_flags == GPIOD_IS_OUT) {
+			dm_gpio_set_dir(&new->gpiod);
+			dm_gpio_set_value(&new->gpiod, value);
+		}
+	}
+
+	return 0;
+}
+#else
+static int gpio_hog(struct udevice *dev)
+{
+	return 0;
+}
+
+struct gpio_desc *gpio_hog_lookup_name(const char *name)
+{
+	return NULL;
+}
+#endif
+
 int dm_gpio_request(struct gpio_desc *desc, const char *label)
 {
 	struct udevice *dev = desc->dev;
@@ -149,8 +260,9 @@ int dm_gpio_request(struct gpio_desc *desc, const char *label)
 	int ret;
 
 	uc_priv = dev_get_uclass_priv(dev);
-	if (uc_priv->name[desc->offset])
-		return -EBUSY;
+	if (uc_priv)
+		if (uc_priv->name[desc->offset])
+			return -EBUSY;
 	str = strdup(label);
 	if (!str)
 		return -ENOMEM;
@@ -643,19 +755,22 @@ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count)
 static int gpio_request_tail(int ret, ofnode node,
 			     struct ofnode_phandle_args *args,
 			     const char *list_name, int index,
-			     struct gpio_desc *desc, int flags, bool add_index)
+			     struct gpio_desc *desc, int flags,
+			     bool add_index, struct udevice *dev)
 {
-	desc->dev = NULL;
+	desc->dev = dev;
 	desc->offset = 0;
 	desc->flags = 0;
 	if (ret)
 		goto err;
 
-	ret = uclass_get_device_by_ofnode(UCLASS_GPIO, args->node,
-					  &desc->dev);
-	if (ret) {
-		debug("%s: uclass_get_device_by_ofnode failed\n", __func__);
-		goto err;
+	if (!desc->dev) {
+		ret = uclass_get_device_by_ofnode(UCLASS_GPIO, args->node,
+						  &desc->dev);
+		if (ret) {
+			debug("%s: uclass_get_device_by_ofnode failed\n", __func__);
+			goto err;
+		}
 	}
 	ret = gpio_find_and_xlate(desc, args);
 	if (ret) {
@@ -693,7 +808,7 @@ static int _gpio_request_by_name_nodev(ofnode node, const char *list_name,
 					     index, &args);
 
 	return gpio_request_tail(ret, node, &args, list_name, index, desc,
-				 flags, add_index);
+				 flags, add_index, NULL);
 }
 
 int gpio_request_by_name_nodev(ofnode node, const char *list_name, int index,
@@ -713,7 +828,7 @@ int gpio_request_by_name(struct udevice *dev, const char *list_name, int index,
 					 index, &args);
 
 	return gpio_request_tail(ret, dev_ofnode(dev), &args, list_name,
-				 index, desc, flags, index > 0);
+				 index, desc, flags, index > 0, NULL);
 }
 
 int gpio_request_list_by_name_nodev(ofnode node, const char *list_name,
@@ -832,12 +947,17 @@ int gpio_get_number(const struct gpio_desc *desc)
 static int gpio_post_probe(struct udevice *dev)
 {
 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	int ret;
 
 	uc_priv->name = calloc(uc_priv->gpio_count, sizeof(char *));
 	if (!uc_priv->name)
 		return -ENOMEM;
 
-	return gpio_renumber(NULL);
+	ret = gpio_renumber(NULL);
+	if (ret)
+		return ret;
+
+	return gpio_hog(dev);
 }
 
 static int gpio_pre_remove(struct udevice *dev)
@@ -854,6 +974,20 @@ static int gpio_pre_remove(struct udevice *dev)
 	return gpio_renumber(dev);
 }
 
+int gpio_dev_request_index(struct udevice *dev, ofnode node, char *list_name,
+			   int index, int flags, int dtflags,
+			   struct gpio_desc *desc)
+{
+	struct ofnode_phandle_args args;
+
+	args.node =  ofnode_null();
+	args.args_count = 2;
+	args.args[0] = index;
+	args.args[1] = dtflags;
+
+	return gpio_request_tail(0, node, &args, list_name, index, desc, flags, 0, dev);
+}
+
 static int gpio_post_bind(struct udevice *dev)
 {
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
@@ -885,6 +1019,10 @@ static int gpio_post_bind(struct udevice *dev)
 		reloc_done++;
 	}
 #endif
+
+#if defined(CONFIG_DM_GPIO_HOG)
+	INIT_LIST_HEAD(&hogs);
+#endif
 	return 0;
 }
 
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d03602696f..1894e497c7 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -348,6 +348,14 @@ const char *gpio_get_bank_info(struct udevice *dev, int *offset_count);
  */
 int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc);
 
+/**
+ * gpio_hog_lookup_name() - Look up a named GPIO and return the gpio descr.
+ *
+ * @name:	Name to look up
+ * @return:	Returns gpio_desc for gpio
+ */
+struct gpio_desc *gpio_hog_lookup_name(const char *name);
+
 /**
  * gpio_lookup_name - Look up a GPIO name and return its details
  *
@@ -503,6 +511,22 @@ int gpio_request_list_by_name_nodev(ofnode node, const char *list_name,
 				    struct gpio_desc *desc_list, int max_count,
 				    int flags);
 
+/**
+ * gpio_dev_request_index() - request single GPIO from gpio device
+ *
+ * @dev:	GPIO device
+ * @ofnode:	of node wich requests the GPIO
+ * @list_name:	Name of GPIO list (e.g. "board-id-gpios")
+ * @index:	Index number of the GPIO in that list use request (0=first)
+ * @flags:	GPIOD_* flags
+ * @dtflags:	GPIO flags read from DT
+ * @desc:	GPIO descriotor filled from this function
+ * @return:	return value from gpio_request_tail()
+ */
+int gpio_dev_request_index(struct udevice *dev, ofnode node, char *list_name,
+			   int index, int flags, int dtflags,
+			   struct gpio_desc *desc);
+
 /**
  * dm_gpio_free() - Free a single GPIO
  *
-- 
2.21.0

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

* [U-Boot] [PATCH] gpio: add gpio-hog support
  2019-05-27  6:30 [U-Boot] [PATCH] gpio: add gpio-hog support Heiko Schocher
@ 2019-05-27  7:13 ` Michal Simek
  2019-05-27  9:36   ` Heiko Schocher
  0 siblings, 1 reply; 4+ messages in thread
From: Michal Simek @ 2019-05-27  7:13 UTC (permalink / raw)
  To: u-boot

On 27. 05. 19 8:30, Heiko Schocher wrote:
> add gpio-hog support. GPIO hogging is a mechanism
> providing automatic GPIO request and configuration
> as part of the gpio-controller's driver probe function.
> 
> for more infos see:
> doc/device-tree-bindings/gpio/gpio.txt
> 
> Signed-off-by: Heiko Schocher <hs@denx.de>

I have tested it on zcu102 where I use gpio hogs for gt muxes.
gpio hogs are handled and setup only when gpio controller is probed.
Do we have a way how to say that controllers with gpio hogs should be
probed automatically?

Right now you are calling it in post_probe which make sense but on the
other hand if you find gpio hog in bind you should probe the whole
driver without asking for request.

Thanks,
Michal

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

* [U-Boot] [PATCH] gpio: add gpio-hog support
  2019-05-27  7:13 ` Michal Simek
@ 2019-05-27  9:36   ` Heiko Schocher
  2019-05-27 11:15     ` Michal Simek
  0 siblings, 1 reply; 4+ messages in thread
From: Heiko Schocher @ 2019-05-27  9:36 UTC (permalink / raw)
  To: u-boot

Hello Michal,

Am 27.05.2019 um 09:13 schrieb Michal Simek:
> On 27. 05. 19 8:30, Heiko Schocher wrote:
>> add gpio-hog support. GPIO hogging is a mechanism
>> providing automatic GPIO request and configuration
>> as part of the gpio-controller's driver probe function.
>>
>> for more infos see:
>> doc/device-tree-bindings/gpio/gpio.txt
>>
>> Signed-off-by: Heiko Schocher <hs@denx.de>
> 
> I have tested it on zcu102 where I use gpio hogs for gt muxes.

Thanks!

> gpio hogs are handled and setup only when gpio controller is probed.

Yes, with my current approach ... If you need a gpio-hog in a gpio
device, wich is not used, you can add in board code:

gpio_hog_lookup_name("name_of_the_gpio_hog");

and gpio driver (and gpio hogs) get probed ... but not really nice...

> Do we have a way how to say that controllers with gpio hogs should be
> probed automatically?

No yet, but I am open for suggestions ;-)

> Right now you are calling it in post_probe which make sense but on the
> other hand if you find gpio hog in bind you should probe the whole
> driver without asking for request.

Yes, I also thought about this approach, but the problem is in

static int gpio_hog(struct udevice *dev)
{
         ofnode node;
         struct gpio_dev_priv *uc_priv = NULL;

         uc_priv = dev_get_uclass_priv(dev);
         if (!uc_priv) {
                 printf("%s: missing private data.\n", __func__);
                 return -EINVAL;
         }

uc_priv is not valid @bind stage ...

But I can think of a function which scans all gpio nodes for
gpio hog subnodes, and call device_probe() ?

But from where should this function be called?

bye,
Heiko
-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-52   Fax: +49-8142-66989-80   Email: hs at denx.de

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

* [U-Boot] [PATCH] gpio: add gpio-hog support
  2019-05-27  9:36   ` Heiko Schocher
@ 2019-05-27 11:15     ` Michal Simek
  0 siblings, 0 replies; 4+ messages in thread
From: Michal Simek @ 2019-05-27 11:15 UTC (permalink / raw)
  To: u-boot

On 27. 05. 19 11:36, Heiko Schocher wrote:
> Hello Michal,
> 
> Am 27.05.2019 um 09:13 schrieb Michal Simek:
>> On 27. 05. 19 8:30, Heiko Schocher wrote:
>>> add gpio-hog support. GPIO hogging is a mechanism
>>> providing automatic GPIO request and configuration
>>> as part of the gpio-controller's driver probe function.
>>>
>>> for more infos see:
>>> doc/device-tree-bindings/gpio/gpio.txt
>>>
>>> Signed-off-by: Heiko Schocher <hs@denx.de>
>>
>> I have tested it on zcu102 where I use gpio hogs for gt muxes.
> 
> Thanks!
> 
>> gpio hogs are handled and setup only when gpio controller is probed.
> 
> Yes, with my current approach ... If you need a gpio-hog in a gpio
> device, wich is not used, you can add in board code:
> 
> gpio_hog_lookup_name("name_of_the_gpio_hog");
> 
> and gpio driver (and gpio hogs) get probed ... but not really nice...
> 
>> Do we have a way how to say that controllers with gpio hogs should be
>> probed automatically?
> 
> No yet, but I am open for suggestions ;-)
> 
>> Right now you are calling it in post_probe which make sense but on the
>> other hand if you find gpio hog in bind you should probe the whole
>> driver without asking for request.
> 
> Yes, I also thought about this approach, but the problem is in
> 
> static int gpio_hog(struct udevice *dev)
> {
>         ofnode node;
>         struct gpio_dev_priv *uc_priv = NULL;
> 
>         uc_priv = dev_get_uclass_priv(dev);
>         if (!uc_priv) {
>                 printf("%s: missing private data.\n", __func__);
>                 return -EINVAL;
>         }
> 
> uc_priv is not valid @bind stage ...
> 
> But I can think of a function which scans all gpio nodes for
> gpio hog subnodes, and call device_probe() ?
> 
> But from where should this function be called?

The question is if this patch is reading that gpio-hogs at right stage.
Right now you are decoding them in post_probe. Normally getting
information from DT is done in ofdata_to_platdata.
It is question if this approach is also working for non DT case.

Anyway let's say you setup a flag in ofdata_to_platdata that there are
gpio hogs and then you know if you should probe that device or not.

btw: didn't send this before you v2 but should be still valid.
Let me test v2 now.

M

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

end of thread, other threads:[~2019-05-27 11:15 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-27  6:30 [U-Boot] [PATCH] gpio: add gpio-hog support Heiko Schocher
2019-05-27  7:13 ` Michal Simek
2019-05-27  9:36   ` Heiko Schocher
2019-05-27 11:15     ` Michal Simek

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.