From nobody Sun Feb 8 00:11:51 2026 Received: from mout02.posteo.de (mout02.posteo.de [185.67.36.66]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 93AB62727EA for ; Thu, 2 Oct 2025 21:58:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.67.36.66 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759442301; cv=none; b=VXmyWPGrMPEdyxQ39cVV2C8x3NQI8mokxhS2sysoo4JuYun+SS4Y32V1uHnLd5XDbT4DcwFhgJIAdNmXiodkuhMn9Or7C7T6MIcNhfMM8FQLzeJLStCA40Dimy9Qbi5QBfD/NUYTQi+IIWH2HUfTa1OvDwKXyU/Z2pn2lgxEK5A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759442301; c=relaxed/simple; bh=iRbv56XOHuj5ELLYlYMS6qWgcR4X5GjCSiHFhQd/DR4=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=phUkR/rKG4WdQAJ+ZumoT6jxnXu+yrgJPaljEznhmckfstMXW0sizogTdfEUh/ICidiIe9WAWkywQIzsNG5osHLd/QmJ3SAd5qZLX/ODZA8gIn/TEVx4nRZuFpda2QnBQ5v8TXlqY7Rq+zmt060Kcttkr5LmMleA2p82Ytb1pGk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=posteo.de; spf=pass smtp.mailfrom=posteo.de; dkim=pass (2048-bit key) header.d=posteo.de header.i=@posteo.de header.b=pwx3ev9u; arc=none smtp.client-ip=185.67.36.66 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=posteo.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=posteo.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=posteo.de header.i=@posteo.de header.b="pwx3ev9u" Received: from submission (posteo.de [185.67.36.169]) by mout02.posteo.de (Postfix) with ESMTPS id BE1A0240101 for ; Thu, 2 Oct 2025 23:58:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.de; s=2017; t=1759442290; bh=+jy0sLZI4pDAMVQyKmSWdbBXDUNmQ1tBUCM7y3g5Dgk=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version: Content-Transfer-Encoding:Autocrypt:OpenPGP:From; b=pwx3ev9uFe75MNhBcVNp8UpJ3QYehroUE5aoodF53gExTxcokwSw9tlKa8UTWxYu9 SPa+3Tbu/LHn/qT8g6FVOgu/ZfvvijKK5zoEPhMqgY1BW0c2RGsxl0YZud6Fp9ezn/ dYXFMt1DzMuJSGUemTuNsDcKoWa08QONho4aWbcI/wMu6CORdz+qTVHuu3U9ExGYGW 76Sdb5MpGxLtvzA3AjqcYttj3OtoSs5ZvKfILj6Cbz4mrEafC+EecKjNXhVcldttNs nK+ytXG5ORb+DuqiFSP4BrLfVzx1iFhKr/3jYwWp2hEkIyms1+/1LqvyUzSAQVfnBu fmYOQXvsOP4ug== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4cd5JX1by1z9rxF; Thu, 2 Oct 2025 23:58:04 +0200 (CEST) From: Markus Probst To: Linus Walleij , Bartosz Golaszewski , Mika Westerberg , Andy Shevchenko Cc: linux-gpio@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, Markus Probst Subject: [PATCH] gpio: of: make it possible to reference gpios probed in acpi in device tree Date: Thu, 02 Oct 2025 21:58:05 +0000 Message-ID: <20251002215759.1836706-1-markus.probst@posteo.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Autocrypt: addr=markus.probst@posteo.de; prefer-encrypt=mutual; keydata=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 aBeNN4ijKZchBXHPgVx+YtWRHfcm4l8= OpenPGP: url=https://posteo.de/keys/markus.probst@posteo.de.asc; preference=encrypt Content-Type: text/plain; charset="utf-8" sometimes it is necessary to use both acpi and device tree to declare devices. Not every gpio device driver which has an acpi_match_table has an of_match table (e.g. amd-pinctrl). Furthermore gpio is an device which can't be easily disabled in acpi and then redeclared in device tree, as it often gets used by other devices declared in acpi (e.g. via GpioInt or GpioIo). Thus a disable of acpi and migration to device tree is not always possible or very time consuming, while acpi by itself is very limited and not always sufficient. This won't affect most configurations, as most of the time either CONFIG_ACPI or CONFIG_OF gets enabled, not both. Signed-off-by: Markus Probst --- drivers/gpio/gpiolib-of.c | 241 +++++++++++++++++++++++--------------- 1 file changed, 145 insertions(+), 96 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 37ab78243fab..c472b86148b3 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -18,6 +18,7 @@ #include #include #include +#include =20 #include #include @@ -118,6 +119,107 @@ int of_gpio_count(const struct fwnode_handle *fwnode,= const char *con_id) return ret ? ret : -ENOENT; } =20 +/** + * of_gpio_twocell_xlate - translate twocell gpiospec to the GPIO number a= nd flags + * @gc: pointer to the gpio_chip structure + * @gpiospec: GPIO specifier as found in the device tree + * @flags: a flags pointer to fill in + * + * This is simple translation function, suitable for the most 1:1 mapped + * GPIO chips. This function performs only one sanity check: whether GPIO + * is less than ngpios (that is specified in the gpio_chip). + * + * Returns: + * GPIO number (>=3D 0) on success, negative errno on failure. + */ +static int of_gpio_twocell_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + /* + * We're discouraging gpio_cells < 2, since that way you'll have to + * write your own xlate function (that will have to retrieve the GPIO + * number and the flags from a single gpio cell -- this is possible, + * but not recommended). + */ + if (gc->of_gpio_n_cells !=3D 2) { + WARN_ON(1); + return -EINVAL; + } + + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + + if (gpiospec->args[0] >=3D gc->ngpio) + return -EINVAL; + + if (flags) + *flags =3D gpiospec->args[1]; + + return gpiospec->args[0]; +} + +/** + * of_gpio_threecell_xlate - translate threecell gpiospec to the GPIO numb= er and flags + * @gc: pointer to the gpio_chip structure + * @gpiospec: GPIO specifier as found in the device tree + * @flags: a flags pointer to fill in + * + * This is simple translation function, suitable for the most 1:n mapped + * GPIO chips, i.e. several GPIO chip instances from one device tree node. + * In this case the following binding is implied: + * + * foo-gpios =3D <&gpio instance offset flags>; + * + * Returns: + * GPIO number (>=3D 0) on success, negative errno on failure. + */ +static int of_gpio_threecell_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + if (gc->of_gpio_n_cells !=3D 3) { + WARN_ON(1); + return -EINVAL; + } + + if (WARN_ON(gpiospec->args_count !=3D 3)) + return -EINVAL; + + /* + * Check chip instance number, the driver responds with true if + * this is the chip we are looking for. + */ + if (!gc->of_node_instance_match(gc, gpiospec->args[0])) + return -EINVAL; + + if (gpiospec->args[1] >=3D gc->ngpio) + return -EINVAL; + + if (flags) + *flags =3D gpiospec->args[2]; + + return gpiospec->args[1]; +} + +static int of_gpiochip_init(struct gpio_chip *chip) +{ + if (!chip->of_xlate) { + if (chip->of_gpio_n_cells =3D=3D 3) { + if (!chip->of_node_instance_match) + return -EINVAL; + chip->of_xlate =3D of_gpio_threecell_xlate; + } else { + chip->of_gpio_n_cells =3D 2; + chip->of_xlate =3D of_gpio_twocell_xlate; + } + } + + if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS) + return -EINVAL; + return 0; +} + static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, const void *data) { @@ -134,6 +236,40 @@ of_find_gpio_device_by_xlate(const struct of_phandle_a= rgs *gpiospec) return gpio_device_find(gpiospec, of_gpiochip_match_node_and_xlate); } =20 +#ifdef CONFIG_ACPI +static int of_gpiochip_match_acpi_path(struct gpio_chip *chip, + const void *data) +{ + const char *acpi_path =3D data; + const char *chip_acpi_path; + acpi_handle handle; + int ret; + + handle =3D ACPI_HANDLE(chip->parent); + if (!handle) + return 0; + chip_acpi_path =3D acpi_handle_path(handle); + if (!chip_acpi_path) + return 0; + + ret =3D !strcmp(acpi_path, chip_acpi_path); + + if (ret) + ret =3D !of_gpiochip_init(chip); + + return ret; +} + +static struct gpio_device *of_find_gpio_device_by_acpi(const struct of_pha= ndle_args *gpiospec) +{ + const char *acpi_path =3D NULL; + + if (of_property_read_string(gpiospec->np, "acpi-path", &acpi_path)) + return NULL; + return gpio_device_find(acpi_path, of_gpiochip_match_acpi_path); +} +#endif + static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *ch= ip, struct of_phandle_args *gpiospec, enum of_gpio_flags *flags) @@ -423,6 +559,12 @@ static struct gpio_desc *of_get_named_gpiod_flags(cons= t struct device_node *np, =20 struct gpio_device *gdev __free(gpio_device_put) =3D of_find_gpio_device_by_xlate(&gpiospec); + #ifdef CONFIG_ACPI + if (!gdev) { + gdev =3D of_find_gpio_device_by_acpi(&gpiospec); + } + #endif + if (!gdev) { desc =3D ERR_PTR(-EPROBE_DEFER); goto out; @@ -948,89 +1090,6 @@ struct notifier_block gpio_of_notifier =3D { }; #endif /* CONFIG_OF_DYNAMIC */ =20 -/** - * of_gpio_twocell_xlate - translate twocell gpiospec to the GPIO number a= nd flags - * @gc: pointer to the gpio_chip structure - * @gpiospec: GPIO specifier as found in the device tree - * @flags: a flags pointer to fill in - * - * This is simple translation function, suitable for the most 1:1 mapped - * GPIO chips. This function performs only one sanity check: whether GPIO - * is less than ngpios (that is specified in the gpio_chip). - * - * Returns: - * GPIO number (>=3D 0) on success, negative errno on failure. - */ -static int of_gpio_twocell_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, - u32 *flags) -{ - /* - * We're discouraging gpio_cells < 2, since that way you'll have to - * write your own xlate function (that will have to retrieve the GPIO - * number and the flags from a single gpio cell -- this is possible, - * but not recommended). - */ - if (gc->of_gpio_n_cells !=3D 2) { - WARN_ON(1); - return -EINVAL; - } - - if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) - return -EINVAL; - - if (gpiospec->args[0] >=3D gc->ngpio) - return -EINVAL; - - if (flags) - *flags =3D gpiospec->args[1]; - - return gpiospec->args[0]; -} - -/** - * of_gpio_threecell_xlate - translate threecell gpiospec to the GPIO numb= er and flags - * @gc: pointer to the gpio_chip structure - * @gpiospec: GPIO specifier as found in the device tree - * @flags: a flags pointer to fill in - * - * This is simple translation function, suitable for the most 1:n mapped - * GPIO chips, i.e. several GPIO chip instances from one device tree node. - * In this case the following binding is implied: - * - * foo-gpios =3D <&gpio instance offset flags>; - * - * Returns: - * GPIO number (>=3D 0) on success, negative errno on failure. - */ -static int of_gpio_threecell_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, - u32 *flags) -{ - if (gc->of_gpio_n_cells !=3D 3) { - WARN_ON(1); - return -EINVAL; - } - - if (WARN_ON(gpiospec->args_count !=3D 3)) - return -EINVAL; - - /* - * Check chip instance number, the driver responds with true if - * this is the chip we are looking for. - */ - if (!gc->of_node_instance_match(gc, gpiospec->args[0])) - return -EINVAL; - - if (gpiospec->args[1] >=3D gc->ngpio) - return -EINVAL; - - if (flags) - *flags =3D gpiospec->args[2]; - - return gpiospec->args[1]; -} - #if IS_ENABLED(CONFIG_OF_GPIO_MM_GPIOCHIP) #include /** @@ -1256,19 +1315,9 @@ int of_gpiochip_add(struct gpio_chip *chip) if (!np) return 0; =20 - if (!chip->of_xlate) { - if (chip->of_gpio_n_cells =3D=3D 3) { - if (!chip->of_node_instance_match) - return -EINVAL; - chip->of_xlate =3D of_gpio_threecell_xlate; - } else { - chip->of_gpio_n_cells =3D 2; - chip->of_xlate =3D of_gpio_twocell_xlate; - } - } - - if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS) - return -EINVAL; + ret =3D of_gpiochip_init(chip); + if (ret) + return ret; =20 ret =3D of_gpiochip_add_pin_range(chip); if (ret) --=20 2.49.1