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 <h...@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@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@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.si...@xilinx.com> (zcu102) > > Thanks, > Michal For the patch Review and tested on stm32mp1 board. Tested-by: Patrick Delaunay <patrick.delau...@st.com> Regards PAtrick _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot