From: Mehmet Fide <[email protected]> A driver's of_to_plat() method must only read the devicetree; probing other devices or claiming resources belongs in probe(). Several drivers nevertheless call gpio_request_by_name() from of_to_plat(), because it is the only way to pick a GPIO out of the devicetree: it resolves and probes the controller and claims the GPIO in one go. On boards where the consumer's pinctrl touches the same pad, the pinctrl state, applied between the two phases, then undoes the direction the early claim set.
Split the two halves: gpio_parse_by_name() reads the phandle into a new struct gpio_dt_desc without touching any device, and can be stored in the platform data; gpio_request_parsed() resolves the controller, claims the GPIO and applies the direction flags, for use in probe(). Signed-off-by: Mehmet Fide <[email protected]> --- drivers/gpio/gpio-uclass.c | 33 ++++++++++++++++++++++++ include/asm-generic/gpio.h | 51 ++++++++++++++++++++++++++++++++++++++ test/dm/gpio.c | 29 ++++++++++++++++++++++ 3 files changed, 113 insertions(+) diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 4d40738e5aa..b65500eafb0 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -1216,6 +1216,39 @@ int gpio_request_by_name_nodev(ofnode node, const char *list_name, int index, index > 0); } +int gpio_parse_by_name(struct udevice *dev, const char *list_name, int index, + int flags, struct gpio_dt_desc *dt) +{ + int ret; + + dt->present = false; + ret = dev_read_phandle_with_args(dev, list_name, "#gpio-cells", 0, + index, &dt->args); + if (ret) + return ret; + dt->list_name = list_name; + dt->flags = flags; + dt->present = true; + + return 0; +} + +int gpio_request_parsed(struct udevice *dev, const struct gpio_dt_desc *dt, + struct gpio_desc *desc) +{ + struct ofnode_phandle_args args; + + if (!dt->present) { + gpio_desc_init(desc, NULL, 0); + return -ENOENT; + } + + args = dt->args; + return gpio_request_tail(0, ofnode_get_name(dev_ofnode(dev)), &args, + dt->list_name, 0, desc, dt->flags, false, + NULL); +} + int gpio_request_by_name(struct udevice *dev, const char *list_name, int index, struct gpio_desc *desc, int flags) { diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a21c606f2b8..9d64f78e642 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -574,6 +574,57 @@ int gpio_claim_vector(const int *gpio_num_array, const char *fmt); int gpio_request_by_name(struct udevice *dev, const char *list_name, int index, struct gpio_desc *desc, int flags); +/** + * struct gpio_dt_desc - devicetree description of a GPIO, not yet requested + * + * Filled by gpio_parse_by_name() from an of_to_plat() method, which must not + * probe other devices or claim the GPIO, and consumed by + * gpio_request_parsed() from the probe() method. + * + * @args: phandle arguments naming the controller node and the GPIO + * @list_name: name of the devicetree property that was parsed + * @flags: GPIOD_... flags requested by the caller + * @present: true if the property exists and was parsed + */ +struct gpio_dt_desc { + struct ofnode_phandle_args args; + const char *list_name; + int flags; + bool present; +}; + +/** + * gpio_parse_by_name() - read a GPIO from the devicetree without requesting it + * + * This only reads the devicetree, so it is safe to call from an of_to_plat() + * method; the GPIO controller is neither probed nor touched. Request the GPIO + * in the probe() method with gpio_request_parsed(). + * + * @dev: Device requesting the GPIO + * @list_name: Name of devicetree property containing the GPIO + * @index: Index of the GPIO in the list of GPIOs + * @flags: GPIOD_... flags to use when the GPIO is requested later + * @dt: Returns the parsed description + * Return: 0 if OK, -ENOENT if the property is missing, other -ve on error + */ +int gpio_parse_by_name(struct udevice *dev, const char *list_name, int index, + int flags, struct gpio_dt_desc *dt); + +/** + * gpio_request_parsed() - request a GPIO parsed by gpio_parse_by_name() + * + * This does the second half of gpio_request_by_name(): resolve the + * controller, claim the GPIO and apply the direction flags. Call it from the + * probe() method. + * + * @dev: Device requesting the GPIO (used for the request label) + * @dt: Description returned by gpio_parse_by_name() + * @desc: Returns the GPIO description, ready for use + * Return: 0 if OK, -ENOENT if @dt holds no GPIO, other -ve on error + */ +int gpio_request_parsed(struct udevice *dev, const struct gpio_dt_desc *dt, + struct gpio_desc *desc); + /* gpio_request_by_line_name - Locate and request a GPIO by line name * * Request a GPIO using the offset of the provided line name in the diff --git a/test/dm/gpio.c b/test/dm/gpio.c index 0fb05b5ca06..4df9cb902eb 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -257,6 +257,35 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) DM_TEST(dm_test_gpio_opendrain_opensource, UTF_SCAN_PDATA | UTF_SCAN_FDT); +/* Test parsing a GPIO in one phase and requesting it in another */ +static int dm_test_gpio_parse_request(struct unit_test_state *uts) +{ + struct gpio_dt_desc dt; + struct gpio_desc desc; + struct udevice *dev; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + + /* parsing alone must not claim the GPIO */ + ut_assertok(gpio_parse_by_name(dev, "test2-gpios", 1, GPIOD_IS_OUT, + &dt)); + ut_asserteq(true, dt.present); + + ut_assertok(gpio_request_parsed(dev, &dt, &desc)); + ut_asserteq(GPIOF_OUTPUT, gpio_get_function(desc.dev, desc.offset, + NULL)); + ut_assertok(dm_gpio_free(dev, &desc)); + + /* a missing property parses and requests as -ENOENT */ + ut_asserteq(-ENOENT, + gpio_parse_by_name(dev, "no-such-gpios", 0, 0, &dt)); + ut_asserteq(-ENOENT, gpio_request_parsed(dev, &dt, &desc)); + + return 0; +} +DM_TEST(dm_test_gpio_parse_request, UTF_SCAN_PDATA | UTF_SCAN_FDT); + /* Test that sandbox anonymous GPIOs work correctly */ static int dm_test_gpio_anon(struct unit_test_state *uts) { base-commit: 527115ef6783cec49e5610c523c124b399011361 -- 2.54.0
