[U-Boot] [PATCH v2] gpio: add gpio-hog support

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
--- not yet started clean travis build, see result: https://travis-ci.org/hsdenx/u-boot-test/builds/537732421
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.
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@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..4a21554d45 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,112 @@ 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; + } + + return NULL; +} + +static int gpio_hog(struct udevice *dev) +{ + ofnode node; + int found = 0; + int ret; + struct gpio_dev_priv *uc_priv = NULL; + + if (!probed_hogs) { + INIT_LIST_HEAD(&hogs); + probed_hogs = 1; + } + dev_for_each_subnode(node, dev) { + if (ofnode_read_bool(node, "gpio-hog")) { + ret = device_probe(dev); + if (ret) + return ret; + found = 1; + break; + } + } + + if (!found) + return 0; + + uc_priv = dev_get_uclass_priv(dev); + if (!uc_priv) { + printf("%s: missing private data.\n", __func__); + return 0; + } + + /* 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); + 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 +267,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 +762,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 +815,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 +835,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, @@ -854,6 +976,21 @@ 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,7 +1022,8 @@ static int gpio_post_bind(struct udevice *dev) reloc_done++; } #endif - return 0; + + return gpio_hog(dev); }
UCLASS_DRIVER(gpio) = { 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 *

On 27. 05. 19 12:49, 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
not yet started clean travis build, see result: https://travis-ci.org/hsdenx/u-boot-test/builds/537732421
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.
I am using i2c to gpio chip and with v2 this chip is not listed via dm completely. It means something is wrong for sure. It looks like that parent is not probed that's why it is failing.
Thanks, Michal

Hello Michal,
Am 27.05.2019 um 13:34 schrieb Michal Simek:
On 27. 05. 19 12:49, 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
not yet started clean travis build, see result: https://travis-ci.org/hsdenx/u-boot-test/builds/537732421
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.
I am using i2c to gpio chip and with v2 this chip is not listed via dm completely. It means something is wrong for sure.
What do you mean with "this chip is not listed via dm completely" ?
It looks like that parent is not probed that's why it is failing.
I use this on the aristainetos board, work currently on rework for DM/DT usage in U-Boot, dts not yet in u-boot but in linux, see:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch...
and added for u-boot now gpio hog definitons:
&i2c3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; status = "okay";
expander: tca6416@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>; }; }; };
works fine for me ...
=> dm tree Class Index Probed Driver Name ----------------------------------------------------------- root 0 [ + ] root_driver root_driver [...] i2c 2 [ + ] i2c_mxc | | |-- i2c@21a8000 gpio 7 [ + ] pca953x | | | |-- tca6416@20
=> gpio status [...] Bank gpio@20_: gpio@20_6: input: 0 [x] env_reset.gpio-hog gpio@20_7: input: 1 [x] boot_rescue.gpio-hog =>
Hmm.. how can I reproduce your problem?
bye, Heiko

Hi,
On 27. 05. 19 14:06, Heiko Schocher wrote:
Hello Michal,
Am 27.05.2019 um 13:34 schrieb Michal Simek:
On 27. 05. 19 12:49, 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
not yet started clean travis build, see result: https://travis-ci.org/hsdenx/u-boot-test/builds/537732421
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.
I am using i2c to gpio chip and with v2 this chip is not listed via dm completely. It means something is wrong for sure.
What do you mean with "this chip is not listed via dm completely" ?
first of all I am using zcu102 http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/dts/zynqmp-zcu102-revA.dt...
There are 2 i2c-gpio chips @20 and @21. @20 has hogs and it is not listed via dm tree when v2 is applied (v1 is without any issue). @21 is seen there.
It looks like that parent is not probed that's why it is failing.
I use this on the aristainetos board, work currently on rework for DM/DT usage in U-Boot, dts not yet in u-boot but in linux, see:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch...
and added for u-boot now gpio hog definitons:
&i2c3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; status = "okay";
expander: tca6416@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>;
nit: there could be also line-name setup.
}; }; };
The setup looks the same as I have here.
works fine for me ...
=> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver [...] i2c 2 [ + ] i2c_mxc | | |-- i2c@21a8000 gpio 7 [ + ] pca953x | | | |-- tca6416@20
=> gpio status [...] Bank gpio@20_: gpio@20_6: input: 0 [x] env_reset.gpio-hog gpio@20_7: input: 1 [x] boot_rescue.gpio-hog =>
Hmm.. how can I reproduce your problem?
Take a look but IIRC you should have zcu102 around too.
Thanks, Michal

Hello Michal,
Am 27.05.2019 um 14:31 schrieb Michal Simek:
Hi,
On 27. 05. 19 14:06, Heiko Schocher wrote:
Hello Michal,
Am 27.05.2019 um 13:34 schrieb Michal Simek:
On 27. 05. 19 12:49, 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
not yet started clean travis build, see result: https://travis-ci.org/hsdenx/u-boot-test/builds/537732421
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.
I am using i2c to gpio chip and with v2 this chip is not listed via dm completely. It means something is wrong for sure.
What do you mean with "this chip is not listed via dm completely" ?
first of all I am using zcu102 http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/dts/zynqmp-zcu102-revA.dt...
There are 2 i2c-gpio chips @20 and @21. @20 has hogs and it is not listed via dm tree when v2 is applied (v1 is without any issue). @21 is seen there.
Hmm... look like the same setup as mine ...
It looks like that parent is not probed that's why it is failing.
I use this on the aristainetos board, work currently on rework for DM/DT usage in U-Boot, dts not yet in u-boot but in linux, see:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch...
and added for u-boot now gpio hog definitons:
&i2c3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; status = "okay";
expander: tca6416@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>;
nit: there could be also line-name setup.
Ok, I add support for it.
}; }; };
The setup looks the same as I have here.
Yes.
works fine for me ...
=> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver [...] i2c 2 [ + ] i2c_mxc | | |-- i2c@21a8000 gpio 7 [ + ] pca953x | | | |-- tca6416@20
=> gpio status [...] Bank gpio@20_: gpio@20_6: input: 0 [x] env_reset.gpio-hog gpio@20_7: input: 1 [x] boot_rescue.gpio-hog =>
Hmm.. how can I reproduce your problem?
Take a look but IIRC you should have zcu102 around too.
Indeed we have one:
$ remote_power -l | grep zcu102 katmai3 off r360 off zcu102 off
I have to look, how I can test without breaking the board... Is there something like a bootmode switch, so I can restore the board if I broke it? (Sorry if dummy question, never worked on the board).
bye, Heiko

On 27. 05. 19 14:48, Heiko Schocher wrote:
Hello Michal,
Am 27.05.2019 um 14:31 schrieb Michal Simek:
Hi,
On 27. 05. 19 14:06, Heiko Schocher wrote:
Hello Michal,
Am 27.05.2019 um 13:34 schrieb Michal Simek:
On 27. 05. 19 12:49, 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
not yet started clean travis build, see result: https://travis-ci.org/hsdenx/u-boot-test/builds/537732421
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.
I am using i2c to gpio chip and with v2 this chip is not listed via dm completely. It means something is wrong for sure.
What do you mean with "this chip is not listed via dm completely" ?
first of all I am using zcu102 http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/dts/zynqmp-zcu102-revA.dt...
There are 2 i2c-gpio chips @20 and @21. @20 has hogs and it is not listed via dm tree when v2 is applied (v1 is without any issue). @21 is seen there.
Hmm... look like the same setup as mine ...
It looks like that parent is not probed that's why it is failing.
I use this on the aristainetos board, work currently on rework for DM/DT usage in U-Boot, dts not yet in u-boot but in linux, see:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch...
and added for u-boot now gpio hog definitons:
&i2c3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; status = "okay";
expander: tca6416@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>;
nit: there could be also line-name setup.
Ok, I add support for it.
}; }; };
The setup looks the same as I have here.
Yes.
works fine for me ...
=> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver [...] i2c 2 [ + ] i2c_mxc | | |-- i2c@21a8000 gpio 7 [ + ] pca953x | | | |-- tca6416@20
=> gpio status [...] Bank gpio@20_: gpio@20_6: input: 0 [x] env_reset.gpio-hog gpio@20_7: input: 1 [x] boot_rescue.gpio-hog =>
Hmm.. how can I reproduce your problem?
Take a look but IIRC you should have zcu102 around too.
Indeed we have one:
$ remote_power -l | grep zcu102 katmai3 off r360 off zcu102 off
I have to look, how I can test without breaking the board... Is there something like a bootmode switch, so I can restore the board if I broke it? (Sorry if dummy question, never worked on the board).
yes - there are easy way how to restore the board. Not sure if you use jtag, qspi or sd boot mode.
Thanks, Michal
participants (2)
-
Heiko Schocher
-
Michal Simek