From patchwork Mon Jun 23 08:59:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 899317 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (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 9FF1E1422AB for ; Mon, 23 Jun 2025 09:00:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750669219; cv=none; b=RCLfxbLlFsw13R1Hc0nrmgzRGbSJcfq0eC2Sv8flR8K4Ilg8e5tWOomUNGiMC5+qXGF5MxyidIb9MZhsoddDxJnBxmZUfFsMqRZa77YJ8yEzLxWNokOAexe0QBE0Jx6P2MltoFG+8j5TrEpFcQimm5t52XQJ2rBCHOfbVO0OadM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750669219; c=relaxed/simple; bh=MhU96uRLcWJzzxR6tZN2WX5FSYiJ7nK0M4z5jjqpgHU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MXMJSspQ8gZ8NhvWvqRgEAIsrc90XN43sybrzouqBgCL+7Gi21gejjFBZQHdLS48cnapkOa5cuq6gxXXukNteQfocjOXzegQxCY9LbROMIKOE3TutYIhXINg2HFU4GAeLUXw80AyJZ93PKw3pHp1fOTEnho+nJ49r+NsLKCTwi0= 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=HYwQIwtO; arc=none smtp.client-ip=209.85.128.42 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="HYwQIwtO" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-45377776935so4554365e9.3 for ; Mon, 23 Jun 2025 02:00:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20230601.gappssmtp.com; s=20230601; t=1750669214; x=1751274014; 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=kzv7rEJjpNnX5QUp0Y2Z+jm414eiLT4c5eMO9fLQc/E=; b=HYwQIwtON918CohIJV1JwkS4jPy7GPbQyhFODgR42+85fxETWzX55WOsD8N/8tLV6Y AJp1iHpA0xOZjakxk4veu1Gi86nAjAa9KhW+jBorlknZzlYv12q8O06iC+tyD2lVePpk 1aLEHux8elGX07FhxTLmzWv4KjVQLpT0tf0ipHdMCScletPVUgh7ZsPRYzf5cWjV90O1 D9FsTAyRbMe4FUwJJxbSmaRYrx85W15b0wT9cdcMbEjtsRQy/o4hCzu3CGeJjoBwttTa 5Ys8uRxkRUITe/lm6vaY9JpFBYWctDZ0VRAiWEAoxF1kOZNXAQE3Pr2DC8DCym+4s4sg zb/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750669214; x=1751274014; 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=kzv7rEJjpNnX5QUp0Y2Z+jm414eiLT4c5eMO9fLQc/E=; b=vVTVpJTqqJuigJok+Al3GNOnH9T5GD/jitAUN7Hf5M1G14ZfoxWRPulrSa0ZL4BTU+ vJ7Pp0avWks4eegSbskagb74l+ZDVaVUVdm8ETeLOmMB3GHQ3S65V8FX0W5rDtT4jtM4 /yb6ItC5X2FzC/ynlIug5NrEa+rFCfT761zwnN1cf38ImsvG1GtRW6e6vaT8wXJ9Lr1P U23GuFHRPa0/Q0lb7HupZSQJhlN0MOPHTFtCRKgF51B7ixCfJ2MW9Dyh6bFUon3lWckx l6N9p2+TTDhJGOyNXah3dEW1NLL7DfEm8Ps6HlUP8+E6lGLqRxSmvYDDMTNu0vjQzwhS W3kA== X-Gm-Message-State: AOJu0Yzigq9NdHpotaNsSPzp9okxLzb3/rFa/6LzRkqx7zpVNbfZIyBr XoIYAT5p+LL2IvVbJ0vnXoe2dEeJCpVSNGhG/Pg0zIHR+Gq9WzU4L4g23rnbJnrexn0= X-Gm-Gg: ASbGncv+8FtdUtYGilfjERR1QRPE2pD17+4UcFoLxvoauE+rgqDAcwTsn8BATNljRCD PjJzJhpUaDJWDjBX2euxCBzZyXA+PhcuswtIMS6PEbytCbYZy76Zd5OUj8ovFaS6TP4iZeKpaiJ 2D4JvCzzjFg5s94kolifWNjIirqCS5sQ4kwhT2MgpFGrZ9yUm7EXzBv1tFiMbJEV2vCp0OSJJG7 L5uhuP0M6w50rvwWX+kMZQ3PR5lmNGl5lTbQrDeBryGzzO7pJ5vpdvRwQPXvhtYIabD7ECA83XZ ee20BepuTUpRRwCeIbvwE7WScXL5QXi7JSKE7vyC3uRIHH7W3Mv5wT0= X-Google-Smtp-Source: AGHT+IHSkumK5IdIX+YDtLlhPcb5/NvipdPY8QkB2OX0ajip0iOIR4tNSqyoiKEu/nWy8UPJZq4u1Q== X-Received: by 2002:a05:600c:8b11:b0:441:b19c:96fe with SMTP id 5b1f17b1804b1-4536b4bf64bmr81273415e9.10.1750669213158; Mon, 23 Jun 2025 02:00:13 -0700 (PDT) Received: from [127.0.1.1] ([2a01:cb1d:dc:7e00:5ce:238e:62a6:cbbc]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-453632312a3sm113401145e9.1.2025.06.23.02.00.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Jun 2025 02:00:12 -0700 (PDT) From: Bartosz Golaszewski Date: Mon, 23 Jun 2025 10:59:49 +0200 Subject: [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250623-gpio-sysfs-chip-export-v2-1-d592793f8964@linaro.org> References: <20250623-gpio-sysfs-chip-export-v2-0-d592793f8964@linaro.org> In-Reply-To: <20250623-gpio-sysfs-chip-export-v2-0-d592793f8964@linaro.org> To: Ahmad Fatoum , Kent Gibson , =?utf-8?q?Jan_L=C3=BCbbe?= , Marek Vasut , Geert Uytterhoeven , Linus Walleij , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Bartosz Golaszewski X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=9913; i=bartosz.golaszewski@linaro.org; h=from:subject:message-id; bh=n0E0L9Xpa7/NHeu4WacRTt4t+8eu7AU+P/7e1Mm6w74=; b=owEBbQKS/ZANAwAKARGnLqAUcddyAcsmYgBoWReZYmMGm4GZN8sGJRBVPbq98QfwXtPOWgwh8 dN0ie9SszWJAjMEAAEKAB0WIQQWnetsC8PEYBPSx58Rpy6gFHHXcgUCaFkXmQAKCRARpy6gFHHX cmAXD/4/nTuaRyHWOHB0oqGl3VKcz3T/TNKZ/060gfICot0rES9uO1rkgmBZHfz4CD9Wmw3Knp/ 4drpuIUIhTQ9R4enn2SHfup3ff6xMo+TTgsHqBFqs2PxchhGKHEaY/VX5JL6UC7asGsqOSUBGxb fi05qGEJhoAeAcD0RkMQyqLY1dKtaajkOT1SNfQMroz20ZYJkTpxOqgvSRb7bgbMPJaag5q/QaU 9qWW/DRJFvFflqpsl4D14VkyTFmutswdQIYQsU+oakKH4Bk1whoOn528CX3WnahqP+t0ix41CXn SVjo6HIyw3s/xA3fHTN44DK3ENKGCsyGo9UwzwTSugKSLg/MwALcWLs69KSApfxNaKXTw2VEqO8 QskdBzs7JOWZBCIOFJd0y3NKrQT6qTCLSwKMKH907Z6x994jDtdcu/0wLDDqJGed4S4F5xlezZ1 qBHoIOZbki2HP2vsvAOq7sdxnyEpOTGyk/W9JIBANCFHOAEnAsJSZZOGkDxGvb+4ahLQHH2y1FL ffGG3lQ4mAiMtar8h8Xq4OCVy9ujxem94nYgfH/na2cdqr3b0QIDJi2FqON9RD1gT8z4BL57cat zHI5S024JLtxlpqRlsDyvjSvocU+OEysjxvK9TRGtaCN+X9ihyQJHu7MMWodXTRHw6uXfJsGRTU 5Aas1tkKuvPnLrg== X-Developer-Key: i=bartosz.golaszewski@linaro.org; a=openpgp; fpr=169DEB6C0BC3C46013D2C79F11A72EA01471D772 From: Bartosz Golaszewski In order to enable moving away from the global GPIO numberspace-based exporting of lines over sysfs: add a parallel, per-chip entry under /sys/class/gpio/ for every registered GPIO chip, denoted by device ID in the file name and not its base GPIO number. Compared to the existing chip group: it does not contain the "base" attribute as the goal of this change is to not refer to GPIOs by their global number from user-space anymore. It also contains its own, per-chip export/unexport attribute pair which allow to export lines by their hardware offset within the chip. Caveat #1: the new device cannot be a link to (or be linked to by) the existing "gpiochip" entry as we cannot create links in /sys/class/xyz/. Caveat #2: the new entry cannot be named "gpiochipX" as it could conflict with devices whose base is statically defined to a low number. Let's go with "chipX" instead. While at it: the chip label is unique so update the untrue statement when extending the docs. Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- Documentation/ABI/obsolete/sysfs-gpio | 7 +- drivers/gpio/gpiolib-sysfs.c | 191 +++++++++++++++++++++++++--------- 2 files changed, 149 insertions(+), 49 deletions(-) diff --git a/Documentation/ABI/obsolete/sysfs-gpio b/Documentation/ABI/obsolete/sysfs-gpio index 480316fee6d80fb7a0ed61706559838591ec0932..ff694708a3bef787afa42dedf94faf209c44dbf0 100644 --- a/Documentation/ABI/obsolete/sysfs-gpio +++ b/Documentation/ABI/obsolete/sysfs-gpio @@ -25,8 +25,13 @@ Description: /active_low ... r/w as: 0, 1 /gpiochipN ... for each gpiochip; #N is its first GPIO /base ... (r/o) same as N - /label ... (r/o) descriptive, not necessarily unique + /label ... (r/o) descriptive chip name /ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1) + /chipX ... for each gpiochip; #X is the gpio device ID + /export ... asks the kernel to export a GPIO at HW offset X to userspace + /unexport ... to return a GPIO at HW offset X to the kernel + /label ... (r/o) descriptive chip name + /ngpio ... (r/o) number of GPIOs exposed by the chip This ABI is obsoleted by Documentation/ABI/testing/gpio-cdev and will be removed after 2020. diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index c4c21e25c682b939e4a0517393308343feb6585a..fbe93cda4ca16038a1cffe766f7e5ead55ace5e6 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -46,6 +46,7 @@ struct gpiod_data { struct gpiodev_data { struct gpio_device *gdev; struct device *cdev_base; /* Class device by GPIO base */ + struct device *cdev_id; /* Class device by GPIO device ID */ }; /* @@ -399,6 +400,14 @@ static const struct attribute_group *gpio_groups[] = { * /base ... matching gpio_chip.base (N) * /label ... matching gpio_chip.label * /ngpio ... matching gpio_chip.ngpio + * + * AND + * + * /sys/class/gpio/chipX/ + * /export ... export GPIO at given offset + * /unexport ... unexport GPIO at given offset + * /label ... matching gpio_chip.label + * /ngpio ... matching gpio_chip.ngpio */ static ssize_t base_show(struct device *dev, struct device_attribute *attr, @@ -428,6 +437,111 @@ static ssize_t ngpio_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(ngpio); +static int export_gpio_desc(struct gpio_desc *desc) +{ + int offset, ret; + + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + + offset = gpio_chip_hwgpio(desc); + if (!gpiochip_line_is_valid(guard.gc, offset)) { + pr_debug_ratelimited("%s: GPIO %d masked\n", __func__, + gpio_chip_hwgpio(desc)); + return -EINVAL; + } + + /* + * No extra locking here; FLAG_SYSFS just signifies that the + * request and export were done by on behalf of userspace, so + * they may be undone on its behalf too. + */ + + ret = gpiod_request_user(desc, "sysfs"); + if (ret) + return ret; + + ret = gpiod_set_transitory(desc, false); + if (ret) { + gpiod_free(desc); + return ret; + } + + ret = gpiod_export(desc, true); + if (ret < 0) { + gpiod_free(desc); + } else { + set_bit(FLAG_SYSFS, &desc->flags); + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED); + } + + return ret; +} + +static int unexport_gpio_desc(struct gpio_desc *desc) +{ + /* + * No extra locking here; FLAG_SYSFS just signifies that the + * request and export were done by on behalf of userspace, so + * they may be undone on its behalf too. + */ + if (!test_and_clear_bit(FLAG_SYSFS, &desc->flags)) + return -EINVAL; + + gpiod_unexport(desc); + gpiod_free(desc); + + return 0; +} + +static ssize_t do_chip_export_store(struct device *dev, + struct device_attribute *attr, + const char *buf, ssize_t size, + int (*handler)(struct gpio_desc *desc)) +{ + struct gpiodev_data *data = dev_get_drvdata(dev); + struct gpio_device *gdev = data->gdev; + struct gpio_desc *desc; + unsigned int gpio; + int ret; + + ret = kstrtouint(buf, 0, &gpio); + if (ret) + return ret; + + desc = gpio_device_get_desc(gdev, gpio); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + ret = handler(desc); + if (ret) + return ret; + + return size; +} + +static ssize_t chip_export_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return do_chip_export_store(dev, attr, buf, size, export_gpio_desc); +} + +static struct device_attribute dev_attr_export = __ATTR(export, 0200, NULL, + chip_export_store); + +static ssize_t chip_unexport_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return do_chip_export_store(dev, attr, buf, size, unexport_gpio_desc); +} + +static struct device_attribute dev_attr_unexport = __ATTR(unexport, 0200, + NULL, + chip_unexport_store); + static struct attribute *gpiochip_attrs[] = { &dev_attr_base.attr, &dev_attr_label.attr, @@ -436,6 +550,15 @@ static struct attribute *gpiochip_attrs[] = { }; ATTRIBUTE_GROUPS(gpiochip); +static struct attribute *gpiochip_ext_attrs[] = { + &dev_attr_label.attr, + &dev_attr_ngpio.attr, + &dev_attr_export.attr, + &dev_attr_unexport.attr, + NULL, +}; +ATTRIBUTE_GROUPS(gpiochip_ext); + /* * /sys/class/gpio/export ... write-only * integer N ... number of GPIO to export (full access) @@ -447,7 +570,7 @@ static ssize_t export_store(const struct class *class, const char *buf, size_t len) { struct gpio_desc *desc; - int status, offset; + int status; long gpio; status = kstrtol(buf, 0, &gpio); @@ -461,40 +584,7 @@ static ssize_t export_store(const struct class *class, return -EINVAL; } - CLASS(gpio_chip_guard, guard)(desc); - if (!guard.gc) - return -ENODEV; - - offset = gpio_chip_hwgpio(desc); - if (!gpiochip_line_is_valid(guard.gc, offset)) { - pr_debug_ratelimited("%s: GPIO %ld masked\n", __func__, gpio); - return -EINVAL; - } - - /* No extra locking here; FLAG_SYSFS just signifies that the - * request and export were done by on behalf of userspace, so - * they may be undone on its behalf too. - */ - - status = gpiod_request_user(desc, "sysfs"); - if (status) - goto done; - - status = gpiod_set_transitory(desc, false); - if (status) { - gpiod_free(desc); - goto done; - } - - status = gpiod_export(desc, true); - if (status < 0) { - gpiod_free(desc); - } else { - set_bit(FLAG_SYSFS, &desc->flags); - gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED); - } - -done: + status = export_gpio_desc(desc); if (status) pr_debug("%s: status %d\n", __func__, status); return status ? : len; @@ -511,7 +601,7 @@ static ssize_t unexport_store(const struct class *class, status = kstrtol(buf, 0, &gpio); if (status < 0) - goto done; + return status; desc = gpio_to_desc(gpio); /* reject bogus commands (gpiod_unexport() ignores them) */ @@ -520,18 +610,7 @@ static ssize_t unexport_store(const struct class *class, return -EINVAL; } - status = -EINVAL; - - /* No extra locking here; FLAG_SYSFS just signifies that the - * request and export were done by on behalf of userspace, so - * they may be undone on its behalf too. - */ - if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) { - gpiod_unexport(desc); - gpiod_free(desc); - status = 0; - } -done: + status = unexport_gpio_desc(desc); if (status) pr_debug("%s: status %d\n", __func__, status); return status ? : len; @@ -561,6 +640,11 @@ static int match_gdev(struct device *dev, const void *desc) static struct gpiodev_data * gdev_get_data(struct gpio_device *gdev) __must_hold(&sysfs_lock) { + /* + * Find the first device in GPIO class that matches. Whether that's + * the one indexed by GPIO base or device ID doesn't matter, it has + * the same address set as driver data. + */ struct device *cdev __free(put_device) = class_find_device(&gpio_class, NULL, gdev, match_gdev); @@ -787,6 +871,16 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) return err; } + data->cdev_id = device_create_with_groups(&gpio_class, parent, + MKDEV(0, 0), data, + gpiochip_ext_groups, + "chip%d", gdev->id); + if (IS_ERR(data->cdev_id)) { + device_unregister(data->cdev_base); + kfree(data); + return PTR_ERR(data->cdev_id); + } + return 0; } @@ -802,6 +896,7 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev) return; device_unregister(data->cdev_base); + device_unregister(data->cdev_id); kfree(data); } From patchwork Mon Jun 23 08:59:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 899316 Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52]) (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 849C223184D for ; Mon, 23 Jun 2025 09:00:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750669220; cv=none; b=f2nLC9BTJU/kXPsITt0r4wUk12dBvxRQ4oNGlmr7wIoCi1PVXXLct0QyYgqVB5RlriUJBBSaJtZud609T4Vhthu0zgaB+5NcPQNNnmKDsddAjp1g2TbSr0i3+L+zZblq+9RNB1S2U9x3noR6N6/daUaFlhmE2jEq/LxhGk8/c2I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750669220; c=relaxed/simple; bh=d38zEk5ZaqdAay7/FyuW9ygn6cdXVn5igg9V9CUJrRU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kW4OZWxrbKMWVxibhFrmqdFxRTfLXTK80YmKjrbZgwDkGMHMVTF07RkBhDZ8h4w/yw0gUqMg2TyzA3nTe45QACeHafLPjHzwalQFy2UAc7foW1nPsIo4OZs41snrHXkO7eAYpBuaQSNH8hoRvq7NGv9pZ8LJnHxLV8XhSgmdNYg= 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=f/sGyA8/; arc=none smtp.client-ip=209.85.128.52 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="f/sGyA8/" Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-4535fbe0299so19869485e9.3 for ; Mon, 23 Jun 2025 02:00:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20230601.gappssmtp.com; s=20230601; t=1750669217; x=1751274017; 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=AXrjLqYiHV1UqIkacQ78pU7saslEmRuVemdbUKcNXL0=; b=f/sGyA8/CsQtVGvG0DdPa3hfje8XpM/Iv7Gtw7g3W6B/z+ErcxBVru2h+cbzpaNEN0 GfyEuH7OtPqKEI1BbVKMXlcReQEWNwmUqsavo3o0hBAMKwEOcraYSKYlxgsf+SOuPUuM ZgLv2NIAT+SHPqBqBYvB2XgSGRyRQ7Rwbz7MyZ3qvaol4BYpv3V+SLAZxakpjpmjKc2u df7wsqvBAWHSk7veXk3vnAhcgXpuGhN6OwT1CY+/+QcY06/86NzPxtsbJIkGlDL3XvrZ gcrnCducLRDM62v9Rcq8rabpEPbNhtGRKstTR7/jJgR+J5LzqiS1wCd4QJHVA/DTe/Ux OFAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750669217; x=1751274017; 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=AXrjLqYiHV1UqIkacQ78pU7saslEmRuVemdbUKcNXL0=; b=dtKtg+IJDkr/V6A224RnmVqe/VK6m00s44JqKdJAqFfx9q+2tcjnpKKPQAT/jeQUPS dliJVgaU17BrW0BDpYKS7m4YiZMtrjHHm0GsyyCMip7JjpKQ4YxSmTGIm08wxxK9hZHq r7G2pqSSVVGLc2aYO+frLP2scEwVmxc/yh5w0b4kFJFLg/JjvJVw71G4Yoq05TLSlfc8 MtKIQ/AVoBfIl8t45WKgFjxwro/eIFw6gCAFam6VaTKt6O8eksQGYfzJc8FZU0vbQeh1 VUn8ng3Oo+657pBgfiWNqw018b8607YzK3TA6HFZlkilc3Gm/Pe3NHeh74oxw58LWY/K rUDQ== X-Gm-Message-State: AOJu0Yz8L1lhu+rs53K+2aK+G6/mgY2Z2HcIsMUw/4ESFQCxYiXYBY9g unLSo2GTeUECmOyS3vgm5c7/jy8nf1jXcGr/IBgGc9TJCsm7qxkX6MMmJPzPEHaSmpXnjLb1rVq bIHmGYDQ= X-Gm-Gg: ASbGncse7Fy8A68qaCQxB99k9Dt4e66f3hpSx+yeKFu1nGn9DwIC8DEdiZfzhHIVNjF uWhH0DDhdqEwnYIIP41ue7wIYHNDc35lnjRQsUDta2TOW++l4WIBOMnj/FlXiG1uNWw/uY9K0gy XX8/6ivfmtEWwqXU2jPTPAGtDxd6awcTflbVrIIDbyfnllfgqTS3xnN9UBYRyC23Q7jHu+b/B+V JBfYbtNQx8coh+WTFJZBxdG3JuhGlhJBazlqf0h2G9zzNkjUkRn9yadz4dmcTIddyRAjww5ay5V baIClZs7G18fRizgDDZ8tQ9Kn9xgfnZfNCcphncxc1d9ODU0Mp3lnCU= X-Google-Smtp-Source: AGHT+IFj1OCV8PRKybyL+z12L2wsuEmBhGyO6RABq1Km1Mn/ENvlckiiRHoM5umZFcF/EESy6kYBIA== X-Received: by 2002:a05:600c:4e8a:b0:450:d3b9:4b96 with SMTP id 5b1f17b1804b1-453659c9ca0mr96282455e9.13.1750669216650; Mon, 23 Jun 2025 02:00:16 -0700 (PDT) Received: from [127.0.1.1] ([2a01:cb1d:dc:7e00:5ce:238e:62a6:cbbc]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-453632312a3sm113401145e9.1.2025.06.23.02.00.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Jun 2025 02:00:15 -0700 (PDT) From: Bartosz Golaszewski Date: Mon, 23 Jun 2025 10:59:52 +0200 Subject: [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250623-gpio-sysfs-chip-export-v2-4-d592793f8964@linaro.org> References: <20250623-gpio-sysfs-chip-export-v2-0-d592793f8964@linaro.org> In-Reply-To: <20250623-gpio-sysfs-chip-export-v2-0-d592793f8964@linaro.org> To: Ahmad Fatoum , Kent Gibson , =?utf-8?q?Jan_L=C3=BCbbe?= , Marek Vasut , Geert Uytterhoeven , Linus Walleij , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Bartosz Golaszewski X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=9621; i=bartosz.golaszewski@linaro.org; h=from:subject:message-id; bh=R3AZXpoOp6EIWO/0eo1g3jnJMbaa3WsMdtY3unSTx9g=; b=owEBbQKS/ZANAwAKARGnLqAUcddyAcsmYgBoWReZarv//rd58fVHSACYfkVYYe+Vp7TEbJ+ot DOEdl0eeM2JAjMEAAEKAB0WIQQWnetsC8PEYBPSx58Rpy6gFHHXcgUCaFkXmQAKCRARpy6gFHHX cvxeEACDnrZYIeBF6eByaDw8IjxxUYG0jdB0latSGDg8mSXvqlGzWjIlgXzoVkpPz0jr7Xk4NoK X2lK9PrdOObXpB8cXpYynfbZGiUoax/xIB7W7jzE2gC51exzblrVLOmf++vBAMLKI7pQFS+uQnu LfAU0bsomaHttZXoKPpto8a3Mg8RNZcYb2vlzljLrTrOvtEtuQSnTEV/eDFj+75B3Z1rLwp+R6s HikMt/1pUX0dld9nEgMvlgoT7n1YWDhVnh8vCu355IyvtCdrZUWrzk5G6tCYO2kym8Jd5Dv8+Yf ozdRFBPouXNl3NLzg7omsfsFzp1NkEgFcIoJNghmr82cArjhmQ4yzCLfQ7cgSBUT3XZkSOoU2l8 7Te5DbqlW0i3LkP7VLG9fc/1AD6Ux+Sa8/yqsCpxXEKObHUNnBTnrtYVJnjbrMyZgcwjrVTuTWM yNPplbXAXECld5YoStCHEHLf8X8YYv6qxGAuceMhLl1SOFiJTxYPQfJLyMlQr89xL2JUb5rfD5g ljKdwBaKrQSBUVOoYr3rAJxmi9q15NXuwUvtYSLllQlfvnTRljW6/Phfqj/kjUjS8k03deLDof4 kr+EgD1E8+EblB6y///vEqVFPTGwh6Jw3Ee8gu+/tzRd7GFROqR7j2xpEOv3O4pzb/z95Utz1Y/ qmCevso0ocfe1qg== X-Developer-Key: i=bartosz.golaszewski@linaro.org; a=openpgp; fpr=169DEB6C0BC3C46013D2C79F11A72EA01471D772 From: Bartosz Golaszewski Currently each exported GPIO is represented in sysfs as a separate class device. This allows us to simply use dev_get_drvdata() to retrieve the pointer passed to device_create_with_groups() from sysfs ops callbacks. However, we're preparing to add a parallel set of per-line sysfs attributes that will live inside the associated gpiochip group. They are not registered as class devices and so have the parent device passed as argument to their callbacks (the GPIO chip class device). Put the attribute structs inside the GPIO descriptor data and dereference the relevant ones using container_of() in the callbacks. This way, we'll be able to reuse the same code for both the legacy and new GPIO attributes. Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-sysfs.c | 122 +++++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 40 deletions(-) diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 0e2c6b2d0940b1d4e4ad0a90aa172e7d01908969..2f1df2ceb7360200c718ea95089720ebfa5a513a 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -32,6 +32,15 @@ struct kernfs_node; #define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \ GPIO_IRQF_TRIGGER_RISING) +enum { + GPIO_SYSFS_LINE_ATTR_DIRECTION = 0, + GPIO_SYSFS_LINE_ATTR_VALUE, + GPIO_SYSFS_LINE_ATTR_EDGE, + GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW, + GPIO_SYSFS_LINE_ATTR_SENTINEL, + GPIO_SYSFS_LINE_ATTR_SIZE, +}; + struct gpiod_data { struct gpio_desc *desc; @@ -41,6 +50,14 @@ struct gpiod_data { unsigned char irq_flags; bool direction_can_change; + + struct device_attribute dir_attr; + struct device_attribute val_attr; + struct device_attribute edge_attr; + struct device_attribute active_low_attr; + struct attribute *attrs[GPIO_SYSFS_LINE_ATTR_SIZE]; + struct attribute_group attr_group; + const struct attribute_group *attr_groups[2]; }; struct gpiodev_data { @@ -79,7 +96,8 @@ static DEFINE_MUTEX(sysfs_lock); static ssize_t direction_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct gpiod_data *data = dev_get_drvdata(dev); + struct gpiod_data *data = container_of(attr, struct gpiod_data, + dir_attr); struct gpio_desc *desc = data->desc; int value; @@ -95,7 +113,8 @@ static ssize_t direction_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpiod_data *data = dev_get_drvdata(dev); + struct gpiod_data *data = container_of(attr, struct gpiod_data, + dir_attr); struct gpio_desc *desc = data->desc; ssize_t status; @@ -112,12 +131,12 @@ static ssize_t direction_store(struct device *dev, return status ? : size; } -static DEVICE_ATTR_RW(direction); static ssize_t value_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct gpiod_data *data = dev_get_drvdata(dev); + struct gpiod_data *data = container_of(attr, struct gpiod_data, + val_attr); struct gpio_desc *desc = data->desc; ssize_t status; @@ -133,7 +152,8 @@ static ssize_t value_show(struct device *dev, struct device_attribute *attr, static ssize_t value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpiod_data *data = dev_get_drvdata(dev); + struct gpiod_data *data = container_of(attr, struct gpiod_data, + val_attr); struct gpio_desc *desc = data->desc; ssize_t status; long value; @@ -150,7 +170,6 @@ static ssize_t value_store(struct device *dev, struct device_attribute *attr, return size; } -static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store); static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { @@ -247,7 +266,8 @@ static const char *const trigger_names[] = { static ssize_t edge_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct gpiod_data *data = dev_get_drvdata(dev); + struct gpiod_data *data = container_of(attr, struct gpiod_data, + edge_attr); int flags; scoped_guard(mutex, &data->mutex) @@ -262,7 +282,8 @@ static ssize_t edge_show(struct device *dev, struct device_attribute *attr, static ssize_t edge_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpiod_data *data = dev_get_drvdata(dev); + struct gpiod_data *data = container_of(attr, struct gpiod_data, + edge_attr); ssize_t status = size; int flags; @@ -289,7 +310,6 @@ static ssize_t edge_store(struct device *dev, struct device_attribute *attr, return size; } -static DEVICE_ATTR_RW(edge); /* Caller holds gpiod-data mutex. */ static int gpio_sysfs_set_active_low(struct gpiod_data *data, int value) @@ -318,7 +338,8 @@ static int gpio_sysfs_set_active_low(struct gpiod_data *data, int value) static ssize_t active_low_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct gpiod_data *data = dev_get_drvdata(dev); + struct gpiod_data *data = container_of(attr, struct gpiod_data, + active_low_attr); struct gpio_desc *desc = data->desc; int value; @@ -332,7 +353,8 @@ static ssize_t active_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpiod_data *data = dev_get_drvdata(dev); + struct gpiod_data *data = container_of(attr, struct gpiod_data, + active_low_attr); ssize_t status; long value; @@ -344,48 +366,34 @@ static ssize_t active_low_store(struct device *dev, return gpio_sysfs_set_active_low(data, value) ?: size; } -static DEVICE_ATTR_RW(active_low); static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr, int n) { - struct device *dev = kobj_to_dev(kobj); - struct gpiod_data *data = dev_get_drvdata(dev); - struct gpio_desc *desc = data->desc; + struct device_attribute *dev_attr = container_of(attr, + struct device_attribute, attr); umode_t mode = attr->mode; - bool show_direction = data->direction_can_change; + struct gpiod_data *data; - if (attr == &dev_attr_direction.attr) { - if (!show_direction) + if (strcmp(attr->name, "direction") == 0) { + data = container_of(dev_attr, struct gpiod_data, dir_attr); + + if (!data->direction_can_change) mode = 0; - } else if (attr == &dev_attr_edge.attr) { - if (gpiod_to_irq(desc) < 0) + } else if (strcmp(attr->name, "edge") == 0) { + data = container_of(dev_attr, struct gpiod_data, edge_attr); + + if (gpiod_to_irq(data->desc) < 0) mode = 0; - if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags)) + + if (!data->direction_can_change && + test_bit(FLAG_IS_OUT, &data->desc->flags)) mode = 0; } return mode; } -static struct attribute *gpio_attrs[] = { - &dev_attr_direction.attr, - &dev_attr_edge.attr, - &dev_attr_value.attr, - &dev_attr_active_low.attr, - NULL, -}; - -static const struct attribute_group gpio_group = { - .attrs = gpio_attrs, - .is_visible = gpio_is_visible, -}; - -static const struct attribute_group *gpio_groups[] = { - &gpio_group, - NULL -}; - /* * /sys/class/gpio/gpiochipN/ * /base ... matching gpio_chip.base (N) @@ -645,6 +653,21 @@ gdev_get_data(struct gpio_device *gdev) __must_hold(&sysfs_lock) return dev_get_drvdata(cdev); }; +static void gpiod_attr_init(struct device_attribute *dev_attr, const char *name, + ssize_t (*show)(struct device *dev, + struct device_attribute *attr, + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count)) +{ + sysfs_attr_init(&dev_attr->attr); + dev_attr->attr.name = name; + dev_attr->attr.mode = 0644; + dev_attr->show = show; + dev_attr->store = store; +} + /** * gpiod_export - export a GPIO through sysfs * @desc: GPIO to make available, already requested @@ -664,6 +687,7 @@ gdev_get_data(struct gpio_device *gdev) __must_hold(&sysfs_lock) int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { struct gpio_device *gdev; + struct attribute **attrs; struct gpiod_data *data; struct device *dev; int status; @@ -709,8 +733,26 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) else data->direction_can_change = false; + gpiod_attr_init(&data->dir_attr, "direction", + direction_show, direction_store); + gpiod_attr_init(&data->val_attr, "value", value_show, value_store); + gpiod_attr_init(&data->edge_attr, "edge", edge_show, edge_store); + gpiod_attr_init(&data->active_low_attr, "active_low", + active_low_show, active_low_store); + + attrs = data->attrs; + data->attr_group.is_visible = gpio_is_visible; + attrs[GPIO_SYSFS_LINE_ATTR_DIRECTION] = &data->dir_attr.attr; + attrs[GPIO_SYSFS_LINE_ATTR_VALUE] = &data->val_attr.attr; + attrs[GPIO_SYSFS_LINE_ATTR_EDGE] = &data->edge_attr.attr; + attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] = + &data->active_low_attr.attr; + + data->attr_group.attrs = data->attrs; + data->attr_groups[0] = &data->attr_group; + dev = device_create_with_groups(&gpio_class, &gdev->dev, - MKDEV(0, 0), data, gpio_groups, + MKDEV(0, 0), data, data->attr_groups, "gpio%u", desc_to_gpio(desc)); if (IS_ERR(dev)) { status = PTR_ERR(dev); From patchwork Mon Jun 23 08:59:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 899315 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (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 F401C233D9E for ; Mon, 23 Jun 2025 09:00:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750669222; cv=none; b=oqAhV1C9DCpFknF/g/QgzzEIiDkKiFsnKgqNCdSvrYI9oN6q5lLcmkwYP3Ak/tJBuw8DLoR7d6RL5WpoM2jQAVHFr8+pYjV6+8/5wgf6aqC5gUBdnIiv1UvrVtr1mV8DrY2MIkXcFsK/dVQxb610nzL/DNOKRNuNPXI+g6UyYd0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750669222; c=relaxed/simple; bh=2VmufPqh0O8zob2k65E7xE6hRVRWUfbSQ0bsi4wykUg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EVhgIS9iYpZjIUxaWrdh/9X+r7uUW2OXG0+7nh0c0Yl7QY4S8ExGOCV6MSYv0pZnkSDIUsWYD5iu8LqJFwud1q5ohynsZ/4Yy+UNAsDzib2cBIWZSqVk0mdZmNV/aaz6T9959nUMC194/WcpkGCSwOTt15jYneS0t8/IEt1Dhes= 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=JZQofE3w; arc=none smtp.client-ip=209.85.128.48 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="JZQofE3w" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-43edecbfb46so26191835e9.0 for ; Mon, 23 Jun 2025 02:00:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20230601.gappssmtp.com; s=20230601; t=1750669219; x=1751274019; 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=S+0vM7w6nkRT64n1GtokbFb/+RihdtSIZj9Jo0wZAR4=; b=JZQofE3wn7nmP9NtwCUxp12LbKFEQek1YeFcOA9zdNu2xrD4arz2dLRN3lM80WAtEc gMgw4iAi9Hc/aHAIuRWBGlerdGO+7KOm8S16zRndzanHl7GyRxjYb2W22aM1KSXlSeGf 8wcQtviHrjuuAWRxw1pc1T4yrTgJhINFBkJTjPr0TWq5v80Q/RpzH6wMwnOVNcXyorYb 5QdqTyU6416ffwyjk9UEVdGvsbsxVIz0qXKMu0TQHNY3stw45/PNb9VBafy7OaWZJK4w lksJdjlIRXwaK6GgDNlmKICWbjVY6CJUOv45XI0D9w6GILx3+MbzcNlY14lavE43iMsL p0UA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750669219; x=1751274019; 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=S+0vM7w6nkRT64n1GtokbFb/+RihdtSIZj9Jo0wZAR4=; b=OxzqQm/J7c3OV/u+S8S/LkjlqzyI+3JAPm3lsj4nE88LSW6W5gA/Yyqjp4bVyL8Wk7 G8wcAgb4Yrb0GzNgXizQIFlyUU0iWzKEVtb4gxZasJjODOE/NJfj+GTs/qh/Q8Hn3E6i m0C7al+g+yyVoNUGwK75Qqh/wyO2mXyrBI3Yu1chXj6h4BM89fDAC1EMcz8uEvW4IHNU XuC7Gh7Oxj9dAvw2EQeuLj+oCfFT0nmRPJKVWK8hah9qG8X6NoyBpIt9oTN9i0RxPwzv nmWIdfqvkW+BNpWAsHcRNzZuMXC6OcI+xKTPb+m4WQwCfGJYO7C7tqYunS/QE2YuZ3Kn 2XPQ== X-Gm-Message-State: AOJu0YyyiurSDJMYU8d5w1ywwxD7zXGLyhIxbywa3ZPnolFJ0MlGJT4/ +0J+a9r7SVswEDtdWnDZR9mL5WHzyr4VeL1EnaK7Csri1ikxnAXBbauu9M/zWFiIft4= X-Gm-Gg: ASbGnctRHpl7HoDwnPqJtuOgG4tlhSVHPfyrymHzeGh3EzR37zdpVWNUj4GEBzHaSmP nvg74CVCiCpOlWBvwCwAsz8ahVoHQFuKJKpmZqmrTUBdJlJXTDU99QLkCBkDShNa5TACi4+SVnJ qj05GmSNTy0vHVsJqXZ0nbrhqN3q7MbbPe48cR5RosDiHtIJEiO7WggnG495RPe1YndbdNAIgeS JJAsnRV9tN+ijbnMlt3TdeS9SwohWixXf90FQ0SKNd8FJC+mi8wWU4x5VeyGl9OWjqP624cJnXL zI3SL6m6awCKSbSXJ5v2oPnsTA3o6ki7SJSaKqbJMaL499ovtLK/MT0= X-Google-Smtp-Source: AGHT+IFaA00mQlzYeRtEKnzTDLTtco3gZtnGppI8xwcvEBY8Eay6CEe1tBFIEgHISAmJkVX3QY4cDQ== X-Received: by 2002:a05:6000:1a8f:b0:3a4:f52d:8b05 with SMTP id ffacd0b85a97d-3a6d12d5316mr10971030f8f.35.1750669219164; Mon, 23 Jun 2025 02:00:19 -0700 (PDT) Received: from [127.0.1.1] ([2a01:cb1d:dc:7e00:5ce:238e:62a6:cbbc]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-453632312a3sm113401145e9.1.2025.06.23.02.00.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Jun 2025 02:00:18 -0700 (PDT) From: Bartosz Golaszewski Date: Mon, 23 Jun 2025 10:59:54 +0200 Subject: [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250623-gpio-sysfs-chip-export-v2-6-d592793f8964@linaro.org> References: <20250623-gpio-sysfs-chip-export-v2-0-d592793f8964@linaro.org> In-Reply-To: <20250623-gpio-sysfs-chip-export-v2-0-d592793f8964@linaro.org> To: Ahmad Fatoum , Kent Gibson , =?utf-8?q?Jan_L=C3=BCbbe?= , Marek Vasut , Geert Uytterhoeven , Linus Walleij , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Bartosz Golaszewski X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4839; i=bartosz.golaszewski@linaro.org; h=from:subject:message-id; bh=qH4qu97yZoN50VbMeaJJSPzOabP/6j28qPrt7PTU/qo=; b=owEBbQKS/ZANAwAKARGnLqAUcddyAcsmYgBoWRealUcoRRY0OStafiz3dgD4Xi6PpbdP2Ydn7 5yVnpwrFFSJAjMEAAEKAB0WIQQWnetsC8PEYBPSx58Rpy6gFHHXcgUCaFkXmgAKCRARpy6gFHHX cgMpEACVlJ7OIqJln5Z9luPvKIw8+qN0RAyFHrmMPwFjT7tyyRoVcnTYKcg9OgbENdzKndXVHfr V33Vmj9PWFv4bXBoTvbBeKAE6a3uL6DJaHek5XMqER4o6AXOgcxgdgp0DDCuHw4mJLu+0CjOUxa sYfaRyW8T8rx4DMiW9JnxaVmsjmYorzhVY+Sib0aHQz39Tsv1NrmhFo2MgqFEYEBHLKYls3LIXu 9p0zlG6SXtkx+vMTLm4lwLOZRYNMfYbb1ktbkmkCZaP5e2wrSMrLkNS1KYKAI+34bCoZOnm6D+2 E6tp+Cn0bHj0IMl1oKDVwKBPUk2ViqQjDRbPE8G05Rm+368eNwEXbPx1B7R8MxUYsB8nEGmLX6k j+cQOV5eSg/9sMSDhHZIhSBAOmzY3H8aScjEjuNngVJ1qBLQtse0GP8eR9Tgtgt73x5YBq/1k/n RbXhyEr+w4hJgFLhCWzJT6V5adNUlqiq99iy7GeFrbfzIL+9+NTw8sFIIAeiFf/DH53uZTLCqj9 1xKN/lid9CzrBHZxGdTCrN7uiGVmrMSjEoXOA3t9pgr+wHuyxAUJ5XQzBQ9PplET2DBKMJ3Ttgg 1sRUxRnqP90dd06kaqAEvIDd0GBEfFkH4V4Lv99Rkhc3EmIRQbtDvG6brFH2xmqPv9F3V8CLGf9 u3N4L7L0fLHqfeQ== X-Developer-Key: i=bartosz.golaszewski@linaro.org; a=openpgp; fpr=169DEB6C0BC3C46013D2C79F11A72EA01471D772 From: Bartosz Golaszewski In preparation for adding a parallel, per-chip attribute group for exported GPIO lines, stop using class device APIs to refer to it in the code. When unregistering the chip, don't call class_find_device() but instead store exported lines in a linked list inside the GPIO chip data object and look it up there. Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-sysfs.c | 60 ++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 515fd0d307cf820b036b1ea966b300715992359f..adf030f74eb163f5d8b1092d00418b84354f923f 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -43,6 +43,7 @@ enum { struct gpiod_data { struct gpio_desc *desc; + struct device *dev; struct mutex mutex; struct kernfs_node *value_class_node; @@ -58,12 +59,15 @@ struct gpiod_data { struct attribute *attrs[GPIO_SYSFS_LINE_ATTR_SIZE]; struct attribute_group attr_group; const struct attribute_group *attr_groups[2]; + + struct list_head list; }; struct gpiodev_data { struct gpio_device *gdev; struct device *cdev_base; /* Class device by GPIO base */ struct device *cdev_id; /* Class device by GPIO device ID */ + struct list_head exported_lines; }; /* @@ -686,10 +690,10 @@ static void gpiod_attr_init(struct device_attribute *dev_attr, const char *name, */ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { + struct gpiodev_data *gdev_data; struct gpiod_data *desc_data; struct gpio_device *gdev; struct attribute **attrs; - struct device *dev; int status; /* can't export until sysfs is available ... */ @@ -751,25 +755,40 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) desc_data->attr_group.attrs = desc_data->attrs; desc_data->attr_groups[0] = &desc_data->attr_group; - dev = device_create_with_groups(&gpio_class, &gdev->dev, - MKDEV(0, 0), desc_data, - desc_data->attr_groups, - "gpio%u", desc_to_gpio(desc)); - if (IS_ERR(dev)) { - status = PTR_ERR(dev); + /* + * Note: we need to continue passing desc_data here as there's still + * at least one known user of gpiod_export_link() in the tree. This + * function still uses class_find_device() internally. + */ + desc_data->dev = device_create_with_groups(&gpio_class, &gdev->dev, + MKDEV(0, 0), desc_data, + desc_data->attr_groups, + "gpio%u", + desc_to_gpio(desc)); + if (IS_ERR(desc_data->dev)) { + status = PTR_ERR(desc_data->dev); goto err_free_data; } - desc_data->value_class_node = sysfs_get_dirent(dev->kobj.sd, "value"); + desc_data->value_class_node = sysfs_get_dirent(desc_data->dev->kobj.sd, + "value"); if (!desc_data->value_class_node) { status = -ENODEV; goto err_unregister_device; } + gdev_data = gdev_get_data(gdev); + if (!gdev_data) { + status = -ENODEV; + goto err_unregister_device; + } + + list_add(&desc_data->list, &gdev_data->exported_lines); + return 0; err_unregister_device: - device_unregister(dev); + device_unregister(desc_data->dev); err_free_data: kfree(desc_data); err_clear_bit: @@ -828,8 +847,9 @@ EXPORT_SYMBOL_GPL(gpiod_export_link); */ void gpiod_unexport(struct gpio_desc *desc) { - struct gpiod_data *desc_data; - struct device *dev; + struct gpiod_data *desc_data = NULL; + struct gpiodev_data *gdev_data; + struct gpio_device *gdev; if (!desc) { pr_warn("%s: invalid GPIO\n", __func__); @@ -840,14 +860,22 @@ void gpiod_unexport(struct gpio_desc *desc) if (!test_bit(FLAG_EXPORT, &desc->flags)) return; - dev = class_find_device(&gpio_class, NULL, desc, match_export); - if (!dev) + gdev = gpiod_to_gpio_device(desc); + gdev_data = gdev_get_data(gdev); + if (!gdev_data) return; - desc_data = dev_get_drvdata(dev); + list_for_each_entry(desc_data, &gdev_data->exported_lines, list) + if (desc == desc_data->desc) + break; + + if (!desc_data) + return; + + list_del(&desc_data->list); clear_bit(FLAG_EXPORT, &desc->flags); sysfs_put(desc_data->value_class_node); - device_unregister(dev); + device_unregister(desc_data->dev); /* * Release irq after deregistration to prevent race with @@ -857,7 +885,6 @@ void gpiod_unexport(struct gpio_desc *desc) gpio_sysfs_free_irq(desc_data); } - put_device(dev); mutex_destroy(&desc_data->mutex); kfree(desc_data); } @@ -899,6 +926,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) return -ENOMEM; data->gdev = gdev; + INIT_LIST_HEAD(&data->exported_lines); guard(mutex)(&sysfs_lock); From patchwork Mon Jun 23 08:59:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 899314 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (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 6F7682376FD for ; Mon, 23 Jun 2025 09:00:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750669225; cv=none; b=NOPVxONXj47KPvB4v7xtfvg2dcTMFn1VU4KIcY0mKV6GyjxqpDUwbtRI9vNLb6UaxblGiGSpjdUJZVX1Olv0DZoGKsi0Vb6g0HziUuUXb2tck2GXzX3d+TL4F/r/a6wKpX0t+oSRZnmB9D3FSZ9rx9EE33grfWoHzJflNShCCVw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750669225; c=relaxed/simple; bh=jRBfjkpecc9BUW1w81pSTZlb8j2BdRorFxrrJ6koHpw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XhckgHJw9V92/I3wlhf8NcxvdxwbVKtU591C/HwVUX+KVSwdiUnLFQnhVDRUY0ML0jBAURKRRLOBpJptAwewVkX/CqY5+Ac5lR9K33TdcYxej8RqJy+FuY1yRtjRykSoc4xjsMhTxvwRXHbkmyk9gp+ANYYllD0ElpvBLbQ2c70= 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=jKMP58tT; arc=none smtp.client-ip=209.85.128.54 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="jKMP58tT" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-451d54214adso25627455e9.3 for ; Mon, 23 Jun 2025 02:00:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20230601.gappssmtp.com; s=20230601; t=1750669222; x=1751274022; 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=qiPiKKgelJK0MgrvfIW+YyEedIQhhH0ktmAiH+T8Zkw=; b=jKMP58tTW4gAzixhYCFhL8n0PH+IYJ2kiqK/1VdpQq84/PcGVgCe9tX8kx2TA4Fjz+ 4EcB+HxpoQBsgIA6ZCsN7Oo8M+0PK/rSK1Lr9urlB2rQelaYOV110XjB/2nDLWhNKPy+ BeW3Xnbi/z4zPqg8awTI/TqpJtv8B9easK4nSHsi2WLsxZ3osFYdYIdfouWeu+hCQNP4 fu5z6jT9M8YboEoCVl60rS47JOA5UCzzO75DReItcEaMipJaByHdK6nBi9csVfNxL7ik 6V6npEv3mGUH6kU++pE3jIgIQsGCRmtuFkpW967vVkgmHN7McdA8CwwF/hLTc6mRkAf0 JvyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750669222; x=1751274022; 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=qiPiKKgelJK0MgrvfIW+YyEedIQhhH0ktmAiH+T8Zkw=; b=XF6kG3ZcpqPg3vM2kTIxi4SSzX2AX6DQm/hzubH+0V1Ckdl9SOndhqt/WYXJw7VeLf /2vuO9vabVPQO+4LiOf6KTkptE8HDHC3EkR5xgF294/BRukY5WhPhiWk9jqp9OVkcVDz 9fy9kC7kVmAwIcNJmDSlMdf9dBZLCW+GPDNDFRo1mHGJT6L0buy1+RCAz3zaPpHSgLJG MO/pC3lVqE18tQqoie3ZQVwr+H+auXyLcBbnv3yPnFjL+TUY84p90Fy2Wg5Isxr/zqc8 6UVk0xUUAdmJMrRcT/WFLYA7ulgIz2R5uEx4Ai0lZKRVPtcjdK1pIXx23Qpjn9ZreiHY Ej0A== X-Gm-Message-State: AOJu0YwRIldS9kBEcomOgezffTF4M4UPmXR70qLWlSZLnB0x2Yy+YPPl agGw+yEzFhLULNJfxNOg81TUSGfeXu6JEeH6q4wPHiSaR4d8LF3xlysZpEdRTn2tafQLnI7FJxo gEOKW/Ac= X-Gm-Gg: ASbGncvmj++oMVAVVKo557f6489a4MzpPOr6IjmZJ1sj/Js31jyvpNwnDnJ8nEWwosS VO4BS8S3VHqyKVaPImKiOeilkjVRmP7JkTdplIkvzW+7HkRuHjs/C3eFvHMv6+eIpCEJ84KDBDa APXPQ4WiDzkkWzPCPdz/72KbAtZjc20O7HwgkN7Giip+wqocR1B6HGysd7FVx07NUsqV/q4P81w +Wf6IRCKUJCQUGQCUPqoeyGBgmjwowBA1Fsz8VQdX8NCEdFAZsSYV1HgbmqeqzhZTZMTHxwjSJ2 pFzAsKLKj/jiObvDsBqrbq/SDbZjlbVaWaLl5buuszBsv/soR1WlCrc= X-Google-Smtp-Source: AGHT+IFtsMKXylZBqwYZ6g2XtKGhJ+AdwXOnqsW9qIXy8SogYsUsVo1AlQk5Zr067rnb18l7OgtGOg== X-Received: by 2002:a05:600c:4fc5:b0:442:e03b:58a9 with SMTP id 5b1f17b1804b1-453659edd23mr96036445e9.25.1750669221517; Mon, 23 Jun 2025 02:00:21 -0700 (PDT) Received: from [127.0.1.1] ([2a01:cb1d:dc:7e00:5ce:238e:62a6:cbbc]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-453632312a3sm113401145e9.1.2025.06.23.02.00.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Jun 2025 02:00:20 -0700 (PDT) From: Bartosz Golaszewski Date: Mon, 23 Jun 2025 10:59:56 +0200 Subject: [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250623-gpio-sysfs-chip-export-v2-8-d592793f8964@linaro.org> References: <20250623-gpio-sysfs-chip-export-v2-0-d592793f8964@linaro.org> In-Reply-To: <20250623-gpio-sysfs-chip-export-v2-0-d592793f8964@linaro.org> To: Ahmad Fatoum , Kent Gibson , =?utf-8?q?Jan_L=C3=BCbbe?= , Marek Vasut , Geert Uytterhoeven , Linus Walleij , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Bartosz Golaszewski X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=8023; i=bartosz.golaszewski@linaro.org; h=from:subject:message-id; bh=2di3W2yHM6i5t7LwlUeew0hS2H4VmaMxC0/5eiN8mL0=; b=owEBbQKS/ZANAwAKARGnLqAUcddyAcsmYgBoWReaRzZCBOEPZ+cr1jQF9rq/zdO1N7t39cpCp /lw3/F3eQ6JAjMEAAEKAB0WIQQWnetsC8PEYBPSx58Rpy6gFHHXcgUCaFkXmgAKCRARpy6gFHHX cuJQD/9CRL6ndRy7Z43UUrz4mA1YKdV5BbivNqpcdvytQgmNpXEgdXg9je6ot436b/H0ivUd+ZJ y0EDUN0bGezYbKp6Cs4XurE/x/ZlhVqvD8rRPEGioP7xhVXtVonGmnAPw2CUdMzQX8bTwTNZuzu ZdHxQ/6MYI95+g7r/yRAuJdfb+JflNLRU7DzJ5gINmqjwLEmkGnm6bUf2XaifWMAhE46AlzKSz0 H6MDQAmo/X41nb1uj1muSNWvsZhtUJ1ahcRJx0ZFE9VdKq3zv/YOLYQplhFJ/RsMtlXam1tQifN TkAngA5CB0hG5UGGwyrpBGPLqCpRQBl2IVmmNo49AiJ/W/dUU/upKWpSckZlsXV9uYZYfKxrkI3 5m7mGfrsCUDc6uUfc7Sf1PNzJ5vQ9jeMPRbgSs3R6kbAeE+NjhQ12nzTO6mEOPvWb3C2NLWtLug 9qnauv6FI7kHdSVXXZ6ovyHz8vKRPMTtVGDalh0vgoBsA7Jo03hzUjYoHdGr5cZzpE+cbW1l/3f zrVAHd+WKHUFS6MZH5IB4K7tqpClcXySD6rbLpbGb4J24drF3oZpVkFhNa1FAWBxv/GZ/blKlYS GaWfEM+ol316qWXYXfAUt8+3U7Lrku3L2H5dlPcOO0Z+v+ns75QH2q9Ei8sYFzO8Z6oatgqy4it /+1hiEFCF1zkHgA== X-Developer-Key: i=bartosz.golaszewski@linaro.org; a=openpgp; fpr=169DEB6C0BC3C46013D2C79F11A72EA01471D772 From: Bartosz Golaszewski Add a Kconfig switch allowing to disable the legacy parts of the GPIO sysfs interface. This means that even though we keep the /sys/class/gpio/ directory, it no longer contains the global export/unexport attribute pair (instead, the user should use the per-chip export/unpexport) nor the gpiochip$BASE entries. This option default to y if GPIO sysfs is enabled but we'll default it to n at some point in the future. Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 8 ++++++++ drivers/gpio/gpiolib-sysfs.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 44f922e10db2f8dcbdacf79ccd27b0fd9cd93564..d040fdd95ee4b19851057fbedbb023f277149c9c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -69,6 +69,14 @@ config GPIO_SYSFS use the character device /dev/gpiochipN with the appropriate ioctl() operations instead. +config GPIO_SYSFS_LEGACY + bool "Enable legacy functionalities of the sysfs interface" + depends on GPIO_SYSFS + default y if GPIO_SYSFS + help + Say Y here if you want to enable the legacy, global GPIO + numberspace-based functionalities of the sysfs interface. + config GPIO_CDEV bool "Character device (/dev/gpiochipN) support" if EXPERT default y diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 37d58009a51333f7d6a8d600dbeaeb333df27ac3..0e7605fee3bd9edbe4e90d8e466742df11a8d579 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -46,7 +46,9 @@ struct gpiod_data { struct device *dev; struct mutex mutex; +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) struct kernfs_node *value_class_node; +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ struct kernfs_node *value_chip_node; int irq; unsigned char irq_flags; @@ -67,7 +69,9 @@ struct gpiod_data { struct gpiodev_data { struct gpio_device *gdev; +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) struct device *cdev_base; /* Class device by GPIO base */ +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ struct device *cdev_id; /* Class device by GPIO device ID */ struct list_head exported_lines; }; @@ -181,7 +185,9 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { struct gpiod_data *data = priv; +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) sysfs_notify_dirent(data->value_class_node); +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ kernfs_notify(data->value_chip_node); return IRQ_HANDLED; @@ -416,6 +422,7 @@ static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr, * /ngpio ... matching gpio_chip.ngpio */ +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) static ssize_t base_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -424,6 +431,7 @@ static ssize_t base_show(struct device *dev, struct device_attribute *attr, return sysfs_emit(buf, "%u\n", data->gdev->base); } static DEVICE_ATTR_RO(base); +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ static ssize_t label_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -548,6 +556,7 @@ static struct device_attribute dev_attr_unexport = __ATTR(unexport, 0200, NULL, chip_unexport_store); +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) static struct attribute *gpiochip_attrs[] = { &dev_attr_base.attr, &dev_attr_label.attr, @@ -555,6 +564,7 @@ static struct attribute *gpiochip_attrs[] = { NULL, }; ATTRIBUTE_GROUPS(gpiochip); +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ static struct attribute *gpiochip_ext_attrs[] = { &dev_attr_label.attr, @@ -565,6 +575,7 @@ static struct attribute *gpiochip_ext_attrs[] = { }; ATTRIBUTE_GROUPS(gpiochip_ext); +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) /* * /sys/class/gpio/export ... write-only * integer N ... number of GPIO to export (full access) @@ -629,10 +640,13 @@ static struct attribute *gpio_class_attrs[] = { NULL, }; ATTRIBUTE_GROUPS(gpio_class); +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ static const struct class gpio_class = { .name = "gpio", +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) .class_groups = gpio_class_groups, +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ }; static int match_gdev(struct device *dev, const void *desc) @@ -763,6 +777,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) * at least one known user of gpiod_export_link() in the tree. This * function still uses class_find_device() internally. */ +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) desc_data->dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), desc_data, desc_data->attr_groups, @@ -779,6 +794,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) status = -ENODEV; goto err_unregister_device; } +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ gdev_data = gdev_get_data(gdev); if (!gdev_data) { @@ -822,10 +838,12 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) err_free_name: kfree(desc_data->attr_group.name); err_put_dirent: +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) sysfs_put(desc_data->value_class_node); err_unregister_device: device_unregister(desc_data->dev); err_free_data: +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ kfree(desc_data); err_clear_bit: clear_bit(FLAG_EXPORT, &desc->flags); @@ -834,12 +852,14 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) } EXPORT_SYMBOL_GPL(gpiod_export); +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) static int match_export(struct device *dev, const void *desc) { struct gpiod_data *data = dev_get_drvdata(dev); return data->desc == desc; } +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ /** * gpiod_export_link - create a sysfs link to an exported GPIO node @@ -856,6 +876,7 @@ static int match_export(struct device *dev, const void *desc) int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc) { +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) struct device *cdev; int ret; @@ -872,6 +893,9 @@ int gpiod_export_link(struct device *dev, const char *name, put_device(cdev); return ret; +#else + return -EOPNOTSUPP; +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ } EXPORT_SYMBOL_GPL(gpiod_export_link); @@ -910,8 +934,10 @@ void gpiod_unexport(struct gpio_desc *desc) list_del(&desc_data->list); clear_bit(FLAG_EXPORT, &desc->flags); +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) sysfs_put(desc_data->value_class_node); device_unregister(desc_data->dev); +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ sysfs_remove_groups(desc_data->parent, desc_data->attr_groups); kernfs_put(desc_data->value_chip_node); @@ -968,6 +994,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) guard(mutex)(&sysfs_lock); +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) /* use chip->base for the ID; it's already known to be unique */ data->cdev_base = device_create_with_groups(&gpio_class, parent, MKDEV(0, 0), data, @@ -979,13 +1006,16 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) kfree(data); return err; } +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ data->cdev_id = device_create_with_groups(&gpio_class, parent, MKDEV(0, 0), data, gpiochip_ext_groups, "chip%d", gdev->id); if (IS_ERR(data->cdev_id)) { +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) device_unregister(data->cdev_base); +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ kfree(data); return PTR_ERR(data->cdev_id); } @@ -1004,7 +1034,9 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev) if (!data) return; +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY) device_unregister(data->cdev_base); +#endif /* CONFIG_GPIO_SYSFS_LEGACY */ device_unregister(data->cdev_id); kfree(data); }