Hello Patrick,

Am 04.06.2019 um 13:49 schrieb Patrick DELAUNAY:
Hi Heiko,


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 <h...@denx.de>

It seens the hog function can be called several times, for gpio bank probed in 
pre-reloc phasis:
        
- before recocation : gpio_post_probe()  => gpio_hog() .... gpio_hogs_probed = 0
- after relocation :
        gpio_post_probe()  => gpio_hog()... gpio_hogs_probed = 0
        gpio_hog_probe_all() => gpio_post_probe()  => gpio_hog()... 
gpio_hogs_probed = 1
        
I don't known if it is expected behavior:
        hog configuration 2 times in Uboot = before and after relocation

No, not expected.

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

Changes in v3:
- probe now all gpio devices with gpio-hogs
   from board_r before board_late_init() call
   or if someone wants to access gpio-hog
   based gpios with gpio_hog_lookup_name()
   This is needed, because we cannot be sure,
   if a gpio device which contains gpio-hogs
   is probed.
- add line-name property as Michal recommended
- renamed gpio_priv_one into gpio_priv_one_hog
   and protected through CONFIG_DM_GPIO_HOG

Changes in v2:
- move gpio_hog() call from post_probe() to post_bind()
   call. Check if current gpio device has gpio-hog
   definitions, if so, probe it.

  common/board_r.c                       |   6 +
  doc/device-tree-bindings/gpio/gpio.txt |  55 +++++++
  drivers/gpio/Kconfig                   |  10 ++
  drivers/gpio/gpio-uclass.c             | 217 ++++++++++++++++++++++---
  include/asm-generic/gpio.h             |  32 ++++
  5 files changed, 301 insertions(+), 19 deletions(-)

[...]
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index
da5e9ba6e5..4ecff115f1 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,18 @@

  DECLARE_GLOBAL_DATA_PTR;

+#if defined(CONFIG_DM_GPIO_HOG)
+struct gpio_priv_one_hog {
+       struct list_head list;
+       char *name;
+       struct gpio_desc gpiod;
+};
+
+static struct list_head hogs;
+static int list_init;
+static int gpio_hogs_probed;
+#endif
+
  /**
   * gpio_to_device() - Convert global GPIO number to device, number
   *
@@ -141,6 +154,147 @@ 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)
+int gpio_hog_probe_all(void)
+{
+       struct udevice *dev;
+       ofnode node;
+       int ret;
+
+       /*
+        * We need to probe all gpio-hog devices
+        * at some point, as we cannot be sure,
+        * that all gpio devices, which contain a
+        * gpio-hog definition are probed.
+        *
+        */
+       if (gpio_hogs_probed)
+               return 0;
+
+       for (uclass_first_device(UCLASS_GPIO, &dev);
+            dev;
+            uclass_next_device(&dev)) {

uclass_next_device automatically call probe for the class (in 
uclass_get_device_tail)
in this context, I think that uclass_find_next_device is better

The idea was to only probe gpio devices with gpio-hog subnodes...

+               dev_for_each_subnode(node, dev) {
+                       if (ofnode_read_bool(node, "gpio-hog")) {
+                               ret = device_probe(dev);
+                               if (ret)
+                                       return ret;
+                               break;
+                       }
+               }
+       }
+       gpio_hogs_probed = 1;
+
+       return 0;
+}
+
+struct gpio_desc *gpio_hog_lookup_name(const char *name) {
+       struct list_head *entry;
+       struct gpio_priv_one_hog *cur;
+
+       /* be sure, all gpio devices with gpio-hogs are probed */
+       gpio_hog_probe_all();
+       list_for_each(entry, &hogs) {
+               cur = list_entry(entry, struct gpio_priv_one_hog, list);
+               if (strcmp(cur->name, name) == 0)
+                       return &cur->gpiod;
+       }
+
+       return NULL;
+}
+
+static int gpio_hog(struct udevice *dev) {
+       ofnode node;
+       int found = 0;
+       int ret;
+       struct gpio_dev_priv *uc_priv = NULL;
+
+       if (!list_init) {
+               INIT_LIST_HEAD(&hogs);
+               list_init = 1;
+       }
+       dev_for_each_subnode(node, dev) {
+               if (ofnode_read_bool(node, "gpio-hog")) {
+                       found = 1;
+                       break;
+               }
+       }

This check is really needed, as it is already done in the main loop ?
I think you can remove this first  'found' loop.

Yes if we only setup the gpio-hogs from main loop.

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

It is prossible to have uc_priv = 0 ?
by construction, is is not allowed in driver mode, so this test can be remove I 
think.

Yes, just panic check. I remove this.

+
+       /* scan for gpio-hog subnodes */
+       dev_for_each_subnode(node, dev) {
+               u32 val[2];
+               int value = 0;
+               int gpiod_flags;
+               struct gpio_priv_one_hog *new;
+               const char *nodename;
+
+               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_hog));
+               nodename = ofnode_read_string(node, "line-name");
+               if (!nodename)
+                       nodename = ofnode_get_name(node);
+               ret = gpio_dev_request_index(dev, nodename, "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);
+               dm_gpio_set_dir(&new->gpiod);
+               if (gpiod_flags == GPIOD_IS_OUT)
+                       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 +303,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;
@@ -640,22 +795,25 @@ int dm_gpio_get_values_as_int(const struct gpio_desc
*desc_list, int count)
        return vector;
  }

-static int gpio_request_tail(int ret, ofnode node,
+static int gpio_request_tail(int ret, const char *nodename,
                             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) {
@@ -663,8 +821,7 @@ static int gpio_request_tail(int ret, ofnode node,
                goto err;
        }
        ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s",
-                              ofnode_get_name(node),
-                              list_name, index);
+                              nodename, list_name, index);
        if (ret) {
                debug("%s: dm_gpio_requestf failed\n", __func__);
                goto err;
@@ -678,7 +835,7 @@ static int gpio_request_tail(int ret, ofnode node,
        return 0;
  err:
        debug("%s: Node '%s', property '%s', failed to request GPIO index %d:
%d\n",
-             __func__, ofnode_get_name(node), list_name, index, ret);
+             __func__, nodename, list_name, index, ret);
        return ret;
  }

@@ -692,8 +849,8 @@ static int _gpio_request_by_name_nodev(ofnode node,
const char *list_name,
        ret = ofnode_parse_phandle_with_args(node, list_name, "#gpio-cells", 0,
                                             index, &args);

-       return gpio_request_tail(ret, node, &args, list_name, index, desc,
-                                flags, add_index);
+       return gpio_request_tail(ret, ofnode_get_name(node), &args, list_name,
+                                index, desc, flags, add_index, NULL);
  }

  int gpio_request_by_name_nodev(ofnode node, const char *list_name, int index,
@@ -707,13 +864,14 @@ int gpio_request_by_name(struct udevice *dev, const
char *list_name, int index,
                         struct gpio_desc *desc, int flags)
  {
        struct ofnode_phandle_args args;
+       ofnode node;
        int ret;

        ret = dev_read_phandle_with_args(dev, list_name, "#gpio-cells", 0,
                                         index, &args);
-
-       return gpio_request_tail(ret, dev_ofnode(dev), &args, list_name,
-                                index, desc, flags, index > 0);
+       node = dev_ofnode(dev);
+       return gpio_request_tail(ret, ofnode_get_name(node), &args, list_name,
+                                index, desc, flags, index > 0, NULL);
  }

  int gpio_request_list_by_name_nodev(ofnode node, const char *list_name, @@ -
832,12 +990,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;
+

It is strange for me to have many device tree parsing in probe function....

For me
=> hog detection + DT parsing in gpio_post_bind() .... info saved in platdata
=> gpio configuration for hog (request and set_dir) => probe function

Yes, this approach is much more cleaner.

+       return gpio_hog(dev);
  }


One other solution to do it is to manage a hog with uclass  (using the new 
UCLASS_NOP or misc for example)
http://patchwork.ozlabs.org/patch/1098913/

Ah, thanks for this hint, wasn;t aware of it.

Ps: we can also create a new UCLASS_GPIOHOG

Heh, I had a version (never posted) with such an approach. Thought this
is to much overhead ... I try first with UCLASS_NOP.

And we to bind this class during GPIO binding; the parsing of DT is done only 
one time
and manage privdata and platdata as expected by driver model....

Yes, cleaner.

For example something like (not tested)
[...]

Thanks for your input! I try to rework this soon.

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: h...@denx.de
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to