[PATCH v3 04/11] gpio: Ensure struct gpio_chip for gpiochip_setup_dev()

Tzung-Bi Shih
2026-02-13T09:31:14Z

Ensure struct gpio_chip for gpiochip_setup_dev(). This eliminates a few
checks for struct gpio_chip.

Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
---
v3:
- Pass struct gpio_chip * only.

v2: https://lore.kernel.org/all/20260203061059.975605-5-tzungbi@kernel.org
- No changes.

v1: https://lore.kernel.org/all/20260116081036.352286-10-tzungbi@kernel.org

drivers/gpio/gpiolib-cdev.c | 12 ++----------
drivers/gpio/gpiolib-cdev.h | 2 +-
drivers/gpio/gpiolib-sysfs.c | 13 +++----------
drivers/gpio/gpiolib-sysfs.h | 4 ++--
drivers/gpio/gpiolib.c | 24 +++++++++++++++++-------
5 files changed, 25 insertions(+), 30 deletions(-)

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 2adc3c070908..b028198adba8 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -2782,9 +2782,9 @@ static const struct file_operations gpio_fileops = {
#endif
};

-int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
+int gpiolib_cdev_register(struct gpio_chip *gc, dev_t devt)
{
- struct gpio_chip *gc;
+ struct gpio_device *gdev = gc->gpiodev;
int ret;

cdev_init(&gdev->chrdev, &gpio_fileops);
@@ -2802,14 +2802,6 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
return ret;
}

- guard(srcu)(&gdev->srcu);
- gc = srcu_dereference(gdev->chip, &gdev->srcu);
- if (!gc) {
- cdev_device_del(&gdev->chrdev, &gdev->dev);
- destroy_workqueue(gdev->line_state_wq);
- return -ENODEV;
- }
-
gpiochip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id);

return 0;
diff --git a/drivers/gpio/gpiolib-cdev.h b/drivers/gpio/gpiolib-cdev.h
index b42644cbffb8..4a9cb3335d99 100644
--- a/drivers/gpio/gpiolib-cdev.h
+++ b/drivers/gpio/gpiolib-cdev.h
@@ -7,7 +7,7 @@

struct gpio_device;

-int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt);
+int gpiolib_cdev_register(struct gpio_chip *gc, dev_t devt);
void gpiolib_cdev_unregister(struct gpio_device *gdev);

#endif /* GPIOLIB_CDEV_H */
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 97e269f30945..3fdcfa0c7d42 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -978,10 +978,10 @@ void gpiod_unexport(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_unexport);

-int gpiochip_sysfs_register(struct gpio_device *gdev)
+int gpiochip_sysfs_register(struct gpio_chip *chip)
{
+ struct gpio_device *gdev = chip->gpiodev;
struct gpiodev_data *data;
- struct gpio_chip *chip;
struct device *parent;
int err;

@@ -994,12 +994,6 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
if (!class_is_registered(&gpio_class))
return 0;

- guard(srcu)(&gdev->srcu);
-
- chip = srcu_dereference(gdev->chip, &gdev->srcu);
- if (!chip)
- return -ENODEV;
-
/*
* For sysfs backward compatibility we need to preserve this
* preferred parenting to the gpio_chip parent field, if set.
@@ -1080,10 +1074,9 @@ void gpiochip_sysfs_unregister(struct gpio_chip *chip)
*/
static int gpiofind_sysfs_register(struct gpio_chip *gc, const void *data)
{
- struct gpio_device *gdev = gc->gpiodev;
int ret;

- ret = gpiochip_sysfs_register(gdev);
+ ret = gpiochip_sysfs_register(gc);
if (ret)
gpiochip_err(gc, "failed to register the sysfs entry: %d\n", ret);

diff --git a/drivers/gpio/gpiolib-sysfs.h b/drivers/gpio/gpiolib-sysfs.h
index 9ee2f9dd268f..aacc8e6454a4 100644
--- a/drivers/gpio/gpiolib-sysfs.h
+++ b/drivers/gpio/gpiolib-sysfs.h
@@ -7,12 +7,12 @@ struct gpio_device;

#ifdef CONFIG_GPIO_SYSFS

-int gpiochip_sysfs_register(struct gpio_device *gdev);
+int gpiochip_sysfs_register(struct gpio_chip *chip);
void gpiochip_sysfs_unregister(struct gpio_chip *chip);

#else

-static inline int gpiochip_sysfs_register(struct gpio_device *gdev)
+static inline int gpiochip_sysfs_register(struct gpio_chip *chip)
{
return 0;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 3ff57b1e51bf..74ee7bfb974c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -882,14 +882,14 @@ static const struct device_type gpio_dev_type = {
};

#ifdef CONFIG_GPIO_CDEV
-#define gcdev_register(gdev, devt) gpiolib_cdev_register((gdev), (devt))
+#define gcdev_register(gc, devt) gpiolib_cdev_register((gc), (devt))
#define gcdev_unregister(gdev) gpiolib_cdev_unregister((gdev))
#else
/*
* gpiolib_cdev_register() indirectly calls device_add(), which is still
* required even when cdev is not selected.
*/
-#define gcdev_register(gdev, devt) device_add(&(gdev)->dev)
+#define gcdev_register(gc, devt) device_add(&(gc)->gpiodev->dev)
#define gcdev_unregister(gdev) device_del(&(gdev)->dev)
#endif

@@ -897,8 +897,9 @@ static const struct device_type gpio_dev_type = {
* An initial reference count has been held in gpiochip_add_data_with_key().
* The caller should drop the reference via gpio_device_put() on errors.
*/
-static int gpiochip_setup_dev(struct gpio_device *gdev)
+static int gpiochip_setup_dev(struct gpio_chip *gc)
{
+ struct gpio_device *gdev = gc->gpiodev;
struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
int ret;

@@ -911,11 +912,11 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
if (fwnode && !fwnode->dev)
fwnode_dev_initialized(fwnode, false);

- ret = gcdev_register(gdev, gpio_devt);
+ ret = gcdev_register(gc, gpio_devt);
if (ret)
return ret;

- ret = gpiochip_sysfs_register(gdev);
+ ret = gpiochip_sysfs_register(gc);
if (ret)
goto err_remove_device;

@@ -962,13 +963,22 @@ static void machine_gpiochip_add(struct gpio_chip *gc)
static void gpiochip_setup_devs(void)
{
struct gpio_device *gdev;
+ struct gpio_chip *gc;
int ret;

guard(srcu)(&gpio_devices_srcu);

list_for_each_entry_srcu(gdev, &gpio_devices, list,
srcu_read_lock_held(&gpio_devices_srcu)) {
- ret = gpiochip_setup_dev(gdev);
+ guard(srcu)(&gdev->srcu);
+
+ gc = srcu_dereference(gdev->chip, &gdev->srcu);
+ if (!gc) {
+ dev_err(&gdev->dev, "Underlying GPIO chip is gone\n");
+ continue;
+ }
+
+ ret = gpiochip_setup_dev(gc);
if (ret) {
gpio_device_put(gdev);
dev_err(&gdev->dev,
@@ -1226,7 +1236,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
* (i.e., `gpio_bus_type` is ready). Otherwise, defer until later.
*/
if (gpiolib_initialized) {
- ret = gpiochip_setup_dev(gdev);
+ ret = gpiochip_setup_dev(gc);
if (ret)
goto err_teardown_shared;
}
--
2.53.0.310.g728cabbaf7-goog