
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@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);
if (ret) { debug("%s: dm_gpio_requestf failed\n", __func__); goto err;nodename, list_name, index);
@@ -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);
return ret;__func__, nodename, list_name, index, 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