All of lore.kernel.org
 help / color / mirror / Atom feed
From: Patrick DELAUNAY <patrick.delaunay@st.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v4] gpio: add gpio-hog support
Date: Fri, 21 Jun 2019 16:09:32 +0000	[thread overview]
Message-ID: <3c3cdcc2d6ca4146a314bf73d06e9368@SFHDAG6NODE3.st.com> (raw)
In-Reply-To: <10393bfd-8a9a-9b58-839e-65327965aea1@xilinx.com>

Hi Mickael

> Subject: Re: [PATCH v4] gpio: add gpio-hog support
> Importance: High
> 
> On 12. 06. 19 6:11, 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>
> >
> > ---
> > clean travis build, see result:
> > https://travis-ci.org/hsdenx/u-boot-test/builds/544040419
> >
> > Changes in v4:
> > - rework as suggested by Patrick
> >   based on patch:
> >   http://patchwork.ozlabs.org/patch/1098913/
> >   use new UCLASS_NOP
> >   hog detection + DT parsing in gpio_post_bind() .... info saved in platdata
> >   gpio configuration for hog (request and set_dir) => probe function
> >
> > 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             | 181 ++++++++++++++++++++++---
> >  include/asm-generic/gpio.h             |  32 +++++
> >  5 files changed, 268 insertions(+), 16 deletions(-)
> >
> > diff --git a/common/board_r.c b/common/board_r.c index
> > 150e8cd424..507da4c74a 100644
> > --- a/common/board_r.c
> > +++ b/common/board_r.c
> > @@ -49,6 +49,9 @@
> >  #include <linux/err.h>
> >  #include <efi_loader.h>
> >  #include <wdt.h>
> > +#if defined(CONFIG_DM_GPIO_HOG)
> > +#include <asm/gpio.h>
> > +#endif
> >
> >  DECLARE_GLOBAL_DATA_PTR;
> >
> > @@ -796,6 +799,9 @@ static init_fnc_t init_sequence_r[] = {  #ifdef
> > CONFIG_CMD_NET
> >  	initr_ethaddr,
> >  #endif
> > +#if defined(CONFIG_DM_GPIO_HOG)
> > +	gpio_hog_probe_all,
> > +#endif

Any reason to have hog at this place ? 
Before board_late_init....

I expect more before board_init() for my future use-case, 
to replace the current (dirty)  implementation with pinctrl-0

#if defined(CONFIG_WDT)
	initr_watchdog,
#endif
+#if defined(CONFIG_DM_GPIO_HOG)
+	gpio_hog_probe_all,
+#endif
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \
	defined(CONFIG_SANDBOX)
	board_init,	/* Setup chipselects */
#endif


In my device tree I have :

	stmfx: stmfx at 42 {
		compatible = "st,stmfx-0300";
		reg = <0x42>;
		interrupts = <8 IRQ_TYPE_EDGE_RISING>;
		interrupt-parent = <&gpioi>;
		vdd-supply = <&v3v3>;

		stmfx_pinctrl: stmfx-pin-controller {
			compatible = "st,stmfx-0300-pinctrl";
			gpio-controller;
			#gpio-cells = <2>;
			interrupt-controller;
			#interrupt-cells = <2>;
			gpio-ranges = <&stmfx_pinctrl 0 0 24>;
			pinctrl-names = "default";
			pinctrl-0 = <&hog_pins>;

			hog_pins: hog {
				pins = "gpio14";
				drive-push-pull;
				bias-pull-down;
			};
	};


And in board, I force probe to configure HOG....before to initialize the DISPLAY, so in 

./board/st/stm32mp1/stm32mp1.c : board _init()

/* board dependent setup after realloc */
int board_init(void)
{
.....
	/* probe all PINCTRL for hog */
	for (uclass_first_device(UCLASS_PINCTRL, &dev);
	     dev;
	     uclass_next_device(&dev)) {
		pr_debug("probe pincontrol = %s\n", dev->name);
	}


Or you can let each board choose when call the function
as it is already done for other function as regulators_enable_boot_on()
So  don't add it in init_sequence_r[]  / board_r.c ?...

Anyway it is not blocking for me, it just a question.

> >  #ifdef CONFIG_BOARD_LATE_INIT
> >  	board_late_init,
> >  #endif
> > diff --git a/doc/device-tree-bindings/gpio/gpio.txt
> > b/doc/device-tree-bindings/gpio/gpio.txt
> > index f7a158d858..e774439369 100644
> > --- a/doc/device-tree-bindings/gpio/gpio.txt
> > +++ b/doc/device-tree-bindings/gpio/gpio.txt
> > @@ -210,3 +210,58 @@ 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.
> > +
> > +Optional properties:
> > +- line-name:  The GPIO label name. If not present the node name is used.
> > +
> > +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..308d0863ad 100644
> > --- a/drivers/gpio/gpio-uclass.c
> > +++ b/drivers/gpio/gpio-uclass.c
> > @@ -5,6 +5,9 @@
> >
> >  #include <common.h>
> >  #include <dm.h>
> > +#include <dm/device-internal.h>
> > +#include <dm/lists.h>
> > +#include <dm/uclass-internal.h>
> >  #include <dt-bindings/gpio/gpio.h>
> >  #include <errno.h>
> >  #include <fdtdec.h>
> > @@ -141,6 +144,118 @@ 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_hog_priv {
> > +	struct gpio_desc gpiod;
> > +};
> > +
> > +struct gpio_hog_data {
> > +	int gpiod_flags;
> > +	int value;
> > +	u32 val[2];
> > +};
> > +
> > +static int gpio_hog_ofdata_to_platdata(struct udevice *dev) {
> > +	struct gpio_hog_data *plat = dev_get_platdata(dev);
> > +	const char *nodename;
> > +	int ret;
> > +
> > +	plat->value = 0;
> > +	if (dev_read_bool(dev, "input")) {
> > +		plat->gpiod_flags = GPIOD_IS_IN;
> > +	} else if (dev_read_bool(dev, "output-high")) {
> > +		plat->value = 1;
> > +		plat->gpiod_flags = GPIOD_IS_OUT;
> > +	} else if (dev_read_bool(dev, "output-low")) {
> > +		plat->gpiod_flags = GPIOD_IS_OUT;
> > +	} else {
> > +		printf("%s: missing gpio-hog state.\n", __func__);
> > +		return -EINVAL;
> > +	}
> > +	ret = dev_read_u32_array(dev, "gpios", plat->val, 2);
> > +	if (ret) {
> > +		printf("%s: wrong gpios property, 2 values needed %d\n",
> > +		       __func__, ret);
> > +		return ret;
> > +	}
> > +	nodename = dev_read_string(dev, "line-name");
> > +	if (!nodename)
> > +		nodename = dev_read_name(dev);
> > +	device_set_name(dev, nodename);
> > +
> > +	return 0;
> > +}
> > +
> > +static int gpio_hog_probe(struct udevice *dev) {
> > +	struct gpio_hog_data *plat = dev_get_platdata(dev);
> > +	struct gpio_hog_priv *priv = dev_get_priv(dev);
> > +	int ret;
> > +
> > +	ret = gpio_dev_request_index(dev->parent, dev->name, "gpio-hog",
> > +				     plat->val[0], plat->gpiod_flags,
> > +				     plat->val[1], &priv->gpiod);
> > +	if (ret < 0) {
> > +		debug("%s: node %s could not get gpio.\n", __func__,
> > +		      dev->name);
> > +		return ret;
> > +	}
> > +	dm_gpio_set_dir(&priv->gpiod);
> > +	if (plat->gpiod_flags == GPIOD_IS_OUT)
> > +		dm_gpio_set_value(&priv->gpiod, plat->value);
> > +
> > +	return 0;
> > +}
> > +
> > +int gpio_hog_probe_all(void)
> > +{
> > +	struct udevice *dev;
> > +	int ret;
> > +
> > +	for (uclass_first_device(UCLASS_NOP, &dev);
> > +	     dev;
> > +	     uclass_find_next_device(&dev)) {
> > +		if (dev->driver == DM_GET_DRIVER(gpio_hog)) {
> > +			ret = device_probe(dev);
> > +			if (ret)
> > +				return ret;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +struct gpio_desc *gpio_hog_lookup_name(const char *name) {
> > +	struct udevice *dev;
> > +
> > +	gpio_hog_probe_all();
> > +	if (!uclass_get_device_by_name(UCLASS_NOP, name, &dev)) {
> > +		struct gpio_hog_priv *priv = dev_get_priv(dev);
> > +
> > +		return &priv->gpiod;
> > +	}
> > +
> > +	return NULL;
> > +}
> > +
> > +U_BOOT_DRIVER(gpio_hog) = {
> > +	.name	= "gpio_hog",
> > +	.id	= UCLASS_NOP,
> > +	.ofdata_to_platdata = gpio_hog_ofdata_to_platdata,
> > +	.probe = gpio_hog_probe,
> > +	.priv_auto_alloc_size = sizeof(struct gpio_hog_priv),
> > +	.platdata_auto_alloc_size = sizeof(struct gpio_hog_data), }; #else
> > +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;
> > @@ -640,22 +755,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 +781,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 +795,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 +809,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 +824,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, @@ -854,8 +972,28 @@ static int gpio_pre_remove(struct udevice
> *dev)
> >  	return gpio_renumber(dev);
> >  }
> >
> > +int gpio_dev_request_index(struct udevice *dev, const char *nodename,
> > +			   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, nodename, &args, list_name, index, desc,
> > +				 flags, 0, dev);
> > +}
> > +
> >  static int gpio_post_bind(struct udevice *dev)  {
> > +#if defined(CONFIG_DM_GPIO_HOG)
> > +	struct udevice *child;
> > +	ofnode node;
> > +#endif
> > +
> >  #if defined(CONFIG_NEEDS_MANUAL_RELOC)
> >  	struct dm_gpio_ops *ops = (struct dm_gpio_ops *)device_get_ops(dev);
> >  	static int reloc_done;
> > @@ -885,6 +1023,17 @@ static int gpio_post_bind(struct udevice *dev)
> >  		reloc_done++;
> >  	}
> >  #endif
> > +
> > +#if defined(CONFIG_DM_GPIO_HOG)
> > +	dev_for_each_subnode(node, dev) {
> > +		if (ofnode_read_bool(node, "gpio-hog")) {
> > +			const char *name = ofnode_get_name(node);
> > +
> > +			device_bind_driver_to_node(dev, "gpio_hog", name,
> > +						   node, &child);
> > +		}
> > +	}
> > +#endif
> >  	return 0;
> >  }
> >
> > diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
> > index d03602696f..37f71e5708 100644
> > --- a/include/asm-generic/gpio.h
> > +++ b/include/asm-generic/gpio.h
> > @@ -348,6 +348,22 @@ 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_hog_probe_all() - probe all gpio devices with
> > + * gpio-hog subnodes.
> > + *
> > + * @return:	Returns return value from device_probe()
> > + */
> > +int gpio_hog_probe_all(void);
> > +
> >  /**
> >   * gpio_lookup_name - Look up a GPIO name and return its details
> >   *
> > @@ -503,6 +519,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
> > + * @nodename:	Name of node
> > + * @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, const char *nodename,
> > +			   char *list_name, int index, int flags,
> > +			   int dtflags, struct gpio_desc *desc);
> > +
> >  /**
> >   * dm_gpio_free() - Free a single GPIO
> >   *
> >
> 
> Tested-by: Michal Simek <michal.simek@xilinx.com> (zcu102)
> 
> Thanks,
> Michal


For the patch Review and tested on stm32mp1 board.

Tested-by: Patrick Delaunay <patrick.delaunay@st.com>

Regards
PAtrick

  reply	other threads:[~2019-06-21 16:09 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-12  4:11 [U-Boot] [PATCH v4] gpio: add gpio-hog support Heiko Schocher
2019-06-12  8:13 ` Michal Simek
2019-06-21 16:09   ` Patrick DELAUNAY [this message]
2019-06-22  5:32     ` Heiko Schocher
2019-06-25  7:20       ` Patrick DELAUNAY
2019-06-22 19:09 ` Simon Glass
2019-06-24  7:15   ` Heiko Schocher
2019-06-26 15:07     ` Simon Glass
2019-06-27  4:12       ` Heiko Schocher
2019-07-08  5:11         ` Heiko Schocher
2019-07-12 21:11         ` Simon Glass
2019-07-15  6:15           ` Heiko Schocher
2019-07-14 13:08 ` Tom Rini
2019-07-15  6:21   ` Heiko Schocher
2019-07-15 12:03     ` Tom Rini

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=3c3cdcc2d6ca4146a314bf73d06e9368@SFHDAG6NODE3.st.com \
    --to=patrick.delaunay@st.com \
    --cc=u-boot@lists.denx.de \
    /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 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.