From nobody Fri Oct 3 11:22:57 2025 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 91B4231E0FE for ; Tue, 2 Sep 2025 11:59:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756814392; cv=none; b=KlHq4dxxA4ZIy14SkGAIOfHWvoucKgPJg73/jVXeMyd+BlkBOf4d21y+EwixqmiEUB4AebtkbH/LIBQ5/OUXVZgN/5RSnTFWID8Sxd1qzzVWouQAEynKoarUqhL3p3k4uR5xz6BEVU3AL3lVYYlgLF47N4IpPSc7H+gLcSDsVZc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756814392; c=relaxed/simple; bh=TDxN/uH8qTcnKwV5wkk294D5MKsLXAiZ97ovdM0wb3o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eV0MtdGGUC2dABIHpAn83u57MzyfdD/3JAf8bRzMmg1Ljo/joYp9wboboLyU+ZexDMmgA6FHxw+oyh6s6b9Qf9w71DIxiX8cV63Ybk2m/uXntWNPLZ22HFwy4DOZGmDi8N+tgKdrAOB5jEyVenEYohYg9qY+r+HTYWmJ0Pcg+9k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=bgdev.pl; spf=none smtp.mailfrom=bgdev.pl; dkim=pass (2048-bit key) header.d=bgdev-pl.20230601.gappssmtp.com header.i=@bgdev-pl.20230601.gappssmtp.com header.b=V1k/TMzJ; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=bgdev.pl Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=bgdev.pl Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bgdev-pl.20230601.gappssmtp.com header.i=@bgdev-pl.20230601.gappssmtp.com header.b="V1k/TMzJ" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-45b8b25296fso15504845e9.2 for ; Tue, 02 Sep 2025 04:59:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20230601.gappssmtp.com; s=20230601; t=1756814381; x=1757419181; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=d/xhHenXAsMplf3u6s5pmBuHZgaTHex9nceZrFvuNAk=; b=V1k/TMzJ5l939gOWFeKDNdmkUUEh618t+ftH0f88uQM2wXCbagvdPHrnHlBZ9li1dN 6LQgkzePJeb0sZ5yVJCNWV9B4Zg9JKZRG6aqZjo3xfGRq0KQ/i+1d8DaeZfQTzHY5HPe 5RfDKE6MEuKiVKkz50i291GFBLBAgoVGEHJtem5m/N/hEBAim45QodjzvN5AIO4fhYVr GCf0D3QGAgCeXsrTiEUHtdJcHUE/An6tp+8yBP9rl2UOuKSfgPutQdSBkxYcyZrF2/dE hE8pNHwlTAGsw3p7oYRUig0ehdXZbLh2j4FdTUXju7W9e5GPFJeYg5w1GHJPHZyLzAe1 vgiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756814381; x=1757419181; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=d/xhHenXAsMplf3u6s5pmBuHZgaTHex9nceZrFvuNAk=; b=u9QTZst8Lzo19LQYZTon5JjX+DNjHRLsZvu+peThOtw2b01dAZF408bFpGiLm8PqH6 IRvRkl5FarBZc+ASxBF+ukl/p3Z5DSZlE0qhb6vQrBeOVC0WOfx6QFWdmidQ+1FpbRim N1Fc5+ALaGbWuv/BEfUnB2szwTW7+rrmQS4HeWcNcrQPPa+RMnx5MqPN4PWVASgFMPfK XL89SoznHq7uSneYfMnDDKqp0ufFrHPuCIuH44EDYRgyZiI4yj69adeCwnLscIKZcxS/ TVg/p4ZVMjEbGp+s2oQ3vc9jYngMTm9ce8uouikY/u7f01FfAJNUIrMsyNwL17myniot LIAw== X-Forwarded-Encrypted: i=1; AJvYcCUiO2S+gxdsBGvAwZrj7Has3BuvpPKG9PsqmJwmNwd3uZWPIAwFppDIZvAKVnK785P7U1+zFown96Hgfpc=@vger.kernel.org X-Gm-Message-State: AOJu0Yw2gDSmaWOjB2Y/9ehCCy3pM7dn/exf0a/inNxevg61y+Pxaow4 b259+Rl/4zssu1SSMzyW/OYi1y/vkwOTOgAQRX29r1GRTFGyogc9b4GfqOnJhwSxJjk= X-Gm-Gg: ASbGncu8OdYV6901xpmQIvOmY5TCxyUYojR4uPslG9wTjhSvjuEEn/PFSDl0FIKVQQ8 CGhWO8f3Z2qz/qmQwpvn6q6RL8Ou1YR1ZQeg4nAfcB+hXe2Vl7rcEVEnCjeQsJpNhdfZ5MmAz1k ++F5Izmi/EvM14Nuo6ACFO/0qSasMtIUyBHGiwQ2dno+OlbFewWQ0XtPDoU/O951fbojHsz7FJ8 T8613l2C3Y8OIN4bStbDoyqJ5Kp0f1cg7ssQTdfxR0hzR2K4rsZiIOhOSub8/jxt1YfnvCBN3IN Ho/zIL1k5sCBIts1aKWZ+a5H48iUAMvmtBzxX1CQ9OZaYGT/sd+giSBRPzHljuwq0m2mLfi7yoO 4sKyTJ5HH1BA8lEuI X-Google-Smtp-Source: AGHT+IFFcOpY3Utnvjf65Nu64vvFfevq/JcfMRRsoKc8OiO51qRcKypbCk0ggH7PazTdXylK2/FTOg== X-Received: by 2002:a05:600c:138c:b0:45b:75f0:2d66 with SMTP id 5b1f17b1804b1-45b8553da82mr85386745e9.4.1756814380994; Tue, 02 Sep 2025 04:59:40 -0700 (PDT) Received: from [127.0.1.1] ([2a01:cb1d:dc:7e00:3327:447f:34e9:44f7]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b9c234b24sm10224195e9.16.2025.09.02.04.59.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Sep 2025 04:59:40 -0700 (PDT) From: Bartosz Golaszewski Date: Tue, 02 Sep 2025 13:59:22 +0200 Subject: [PATCH v7 13/16] pinctrl: allow to mark pin functions as requestable GPIOs Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250902-pinctrl-gpio-pinfuncs-v7-13-bb091daedc52@linaro.org> References: <20250902-pinctrl-gpio-pinfuncs-v7-0-bb091daedc52@linaro.org> In-Reply-To: <20250902-pinctrl-gpio-pinfuncs-v7-0-bb091daedc52@linaro.org> To: Linus Walleij , Bjorn Andersson , Konrad Dybcio , Alexey Klimov , Lorenzo Bianconi , Sean Wang , Matthias Brugger , AngeloGioacchino Del Regno , Paul Cercueil , Kees Cook , Andy Shevchenko , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Dong Aisheng , Fabio Estevam , Shawn Guo , Jacky Bai , Pengutronix Kernel Team , NXP S32 Linux Team , Sascha Hauer , Tony Lindgren , Haojian Zhuang , Geert Uytterhoeven , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Neil Armstrong , Mark Brown Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-mips@vger.kernel.org, linux-hardening@vger.kernel.org, linux-mm@kvack.org, imx@lists.linux.dev, linux-omap@vger.kernel.org, linux-renesas-soc@vger.kernel.org, Bartosz Golaszewski X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7303; i=bartosz.golaszewski@linaro.org; h=from:subject:message-id; bh=Ad/7ZtxydbTdpBCeQAT3xe1dzmeABB/N+TQC4QQw00Q=; b=owEBbQKS/ZANAwAKARGnLqAUcddyAcsmYgBottwUnI9ibVpJgIM2CXH34HKUqefNgJQqX111f 6azmjUqEayJAjMEAAEKAB0WIQQWnetsC8PEYBPSx58Rpy6gFHHXcgUCaLbcFAAKCRARpy6gFHHX crI8EACxskT9dEpW5d6LUzgdawqMjxZwRmZyQMOCyV0IKvpVcaQ2Vv3Wr5Hht023kdnijctKCXS Ido3+4GIv8wSJdTZQ56I4KxofnDG2vyYeZPNpDoyiWLkH+yc6UQndbBmcs9JBrl+IY9DsH9KGE/ I4eJI4ZEh7eJ8j56ofq+2BznQPdh9ksHXna1EzYROBLe+wzox6SnIpbHRCCYjjI4DqrN2w0Lsv4 4LBel3uvwjLe/5Ye+Ku/OgrfFEs6SAN+1X51mLsUeCYW+41xXi4lXCOEUoxR5tWmdb7AswqeTan nZ/IaxxY4w2AiOPIGeq4RWgY0Ge5XCUYgxwKgj5SrSjWQ4cmuxOJtznbOquptEloM+cdwFGPrhl +hPVaXlKG7ES6gnoBDPkNzXJkRV5YOKTrNa4YXr623pJEa9WEywx9eeg19elGZ/gMFu0SZhm9ur 8s6tHh7+0t1aqqLPm1w4pdFaLTigqMH3LYRExCoJs5YdGheFHXQ93HqhY2XswD7fr8MfhKExZ97 /3cj20QdCk2vkJvJlzaItZ2Dy6RNKHd70azroEtYTGiKkMQZ5RX8H+I8Y8YuHHiVkMKHWEncfSu V22BPreBipqjNwOdGxc/fGEFSh+Dt9CpW55mvqzwcer+/Fo2Asl9/9tEusw0oLjMWt9BXfiibGC QB1qcz+eP8lWwfQ== X-Developer-Key: i=bartosz.golaszewski@linaro.org; a=openpgp; fpr=169DEB6C0BC3C46013D2C79F11A72EA01471D772 From: Bartosz Golaszewski The name of the pin function has no real meaning to pinctrl core and is there only for human readability of device properties. Some pins are muxed as GPIOs but for "strict" pinmuxers it's impossible to request them as GPIOs if they're bound to a devide - even if their function name explicitly says "gpio". Add a new field to struct pinfunction that allows to pass additional flags to pinctrl core. While we could go with a boolean "is_gpio" field, a flags field is more future-proof. If the PINFUNCTION_FLAG_GPIO is set for a given function, the pin muxed to it can be requested as GPIO even on strict pin controllers. Add a new callback to struct pinmux_ops - function_is_gpio() - that allows pinmux core to inspect a function and see if it's a GPIO one. Provide a generic implementation of this callback. Tested-by: Neil Armstrong Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/pinmux.c | 46 +++++++++++++++++++++++++++++++++++++= +--- drivers/pinctrl/pinmux.h | 3 +++ include/linux/pinctrl/pinctrl.h | 14 +++++++++++++ include/linux/pinctrl/pinmux.h | 2 ++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 07ec93f09334f8ba8f8cbde4c54fd6a894025ae6..3a8dd184ba3d670e01a890427e1= 9af59b65eb813 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -89,13 +89,20 @@ bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pc= tldev, unsigned int pin) { struct pin_desc *desc =3D pin_desc_get(pctldev, pin); const struct pinmux_ops *ops =3D pctldev->desc->pmxops; + const struct pinctrl_setting_mux *mux_setting; + bool func_is_gpio =3D false; =20 /* Can't inspect pin, assume it can be used */ if (!desc || !ops) return true; =20 + mux_setting =3D desc->mux_setting; + guard(mutex)(&desc->mux_lock); - if (ops->strict && desc->mux_usecount) + if (mux_setting && ops->function_is_gpio) + func_is_gpio =3D ops->function_is_gpio(pctldev, mux_setting->func); + + if (ops->strict && desc->mux_usecount && !func_is_gpio) return false; =20 return !(ops->strict && !!desc->gpio_owner); @@ -116,7 +123,9 @@ static int pin_request(struct pinctrl_dev *pctldev, { struct pin_desc *desc; const struct pinmux_ops *ops =3D pctldev->desc->pmxops; + const struct pinctrl_setting_mux *mux_setting; int status =3D -EINVAL; + bool gpio_ok =3D false; =20 desc =3D pin_desc_get(pctldev, pin); if (desc =3D=3D NULL) { @@ -126,11 +135,21 @@ static int pin_request(struct pinctrl_dev *pctldev, goto out; } =20 + mux_setting =3D desc->mux_setting; + dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", pin, desc->name, owner); =20 scoped_guard(mutex, &desc->mux_lock) { - if ((!gpio_range || ops->strict) && + if (mux_setting) { + if (ops->function_is_gpio) + gpio_ok =3D ops->function_is_gpio(pctldev, + mux_setting->func); + } else { + gpio_ok =3D true; + } + + if ((!gpio_range || ops->strict) && !gpio_ok && desc->mux_usecount && strcmp(desc->mux_owner, owner)) { dev_err(pctldev->dev, "pin %s already requested by %s; cannot claim for %s\n", @@ -138,7 +157,7 @@ static int pin_request(struct pinctrl_dev *pctldev, goto out; } =20 - if ((gpio_range || ops->strict) && desc->gpio_owner) { + if ((gpio_range || ops->strict) && !gpio_ok && desc->gpio_owner) { dev_err(pctldev->dev, "pin %s already requested by %s; cannot claim for %s\n", desc->name, desc->gpio_owner, owner); @@ -861,6 +880,27 @@ pinmux_generic_get_function(struct pinctrl_dev *pctlde= v, unsigned int selector) } EXPORT_SYMBOL_GPL(pinmux_generic_get_function); =20 +/** + * pinmux_generic_function_is_gpio() - returns true if given function is a= GPIO + * @pctldev: pin controller device + * @selector: function number + * + * Returns: + * True if given function is a GPIO, false otherwise. + */ +bool pinmux_generic_function_is_gpio(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct function_desc *function; + + function =3D radix_tree_lookup(&pctldev->pin_function_tree, selector); + if (!function) + return false; + + return function->func->flags & PINFUNCTION_FLAG_GPIO; +} +EXPORT_SYMBOL_GPL(pinmux_generic_function_is_gpio); + /** * pinmux_generic_add_function() - adds a function group * @pctldev: pin controller device diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h index 653684290666d78fd725febb5f8bc987b66a1afb..4e826c1a5246cf8b1ac814c8c0d= f24c4e036edd2 100644 --- a/drivers/pinctrl/pinmux.h +++ b/drivers/pinctrl/pinmux.h @@ -169,6 +169,9 @@ int pinmux_generic_remove_function(struct pinctrl_dev *= pctldev, =20 void pinmux_generic_free_functions(struct pinctrl_dev *pctldev); =20 +bool pinmux_generic_function_is_gpio(struct pinctrl_dev *pctldev, + unsigned int selector); + #else =20 static inline void pinmux_generic_free_functions(struct pinctrl_dev *pctld= ev) diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctr= l.h index d138e18156452e008f24ca06358fcab45135632f..1a8084e2940537f8f0862761d3e= 47c56c8783193 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -11,6 +11,7 @@ #ifndef __LINUX_PINCTRL_PINCTRL_H #define __LINUX_PINCTRL_PINCTRL_H =20 +#include #include =20 struct device; @@ -206,16 +207,20 @@ extern int pinctrl_get_group_pins(struct pinctrl_dev = *pctldev, const char *pin_group, const unsigned int **pins, unsigned int *num_pins); =20 +#define PINFUNCTION_FLAG_GPIO BIT(0) + /** * struct pinfunction - Description about a function * @name: Name of the function * @groups: An array of groups for this function * @ngroups: Number of groups in @groups + * @flags: Additional pin function flags */ struct pinfunction { const char *name; const char * const *groups; size_t ngroups; + unsigned long flags; }; =20 /* Convenience macro to define a single named pinfunction */ @@ -226,6 +231,15 @@ struct pinfunction { .ngroups =3D (_ngroups), \ } =20 +/* Same as PINCTRL_PINFUNCTION() but for the GPIO category of functions */ +#define PINCTRL_GPIO_PINFUNCTION(_name, _groups, _ngroups) \ +(struct pinfunction) { \ + .name =3D (_name), \ + .groups =3D (_groups), \ + .ngroups =3D (_ngroups), \ + .flags =3D PINFUNCTION_FLAG_GPIO, \ + } + #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_PINCTRL) extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np); #else diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h index d6f7b58d6ad0cce421aad80463529c9ccc65d68e..6db6c3e1ccc2249d4b4204e6fc1= 9bf7b4397cc81 100644 --- a/include/linux/pinctrl/pinmux.h +++ b/include/linux/pinctrl/pinmux.h @@ -66,6 +66,8 @@ struct pinmux_ops { unsigned int selector, const char * const **groups, unsigned int *num_groups); + bool (*function_is_gpio) (struct pinctrl_dev *pctldev, + unsigned int selector); int (*set_mux) (struct pinctrl_dev *pctldev, unsigned int func_selector, unsigned int group_selector); int (*gpio_request_enable) (struct pinctrl_dev *pctldev, --=20 2.48.1