Commit ff2b1359 authored by Linus Walleij's avatar Linus Walleij

gpio: make the gpiochip a real device

GPIO chips have been around for years, but were never real devices,
instead they were piggy-backing on a parent device (such as a
platform_device or amba_device) but this was always optional.
GPIO chips could also exist without any device at all, with its
struct device *parent (ex *dev) pointer being set to null.

When sysfs was in use, a mock device would be created, with the
optional parent assigned, or just floating orphaned with NULL
as parent.

If sysfs is active, it will use this device as parent.

We now create a gpio_device struct containing a real
struct device and move the subsystem over to using that. The
list of struct gpio_chip:s is augmented to hold struct
gpio_device:s and we find gpio_chips:s by first looking up
the struct gpio_device.

The struct gpio_device is designed to stay around even if the
gpio_chip is removed, so as to satisfy users in userspace
that need a backing data structure to hold the state of the
session initiated with e.g. a character device even if there is
no physical chip anymore.

From this point on, gpiochips are devices.

Cc: Johan Hovold <>
Cc: Michael Welling <>
Cc: Markus Pargmann <>
Signed-off-by: Linus Walleij's avatarLinus Walleij <>
parent 92e963f5
......@@ -547,6 +547,7 @@ static struct class gpio_class = {
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
struct gpio_chip *chip;
struct gpio_device *gdev;
struct gpiod_data *data;
unsigned long flags;
int status;
......@@ -566,6 +567,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
chip = desc->chip;
gdev = chip->gpiodev;
......@@ -605,7 +607,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
dev = device_create_with_groups(&gpio_class, chip->parent,
dev = device_create_with_groups(&gpio_class, &gdev->dev,
MKDEV(0, 0), data, gpio_groups,
ioname ? ioname : "gpio%u",
......@@ -771,7 +773,7 @@ static int __init gpiolib_sysfs_init(void)
int status;
unsigned long flags;
struct gpio_chip *chip;
struct gpio_device *gdev;
status = class_register(&gpio_class);
if (status < 0)
......@@ -784,8 +786,8 @@ static int __init gpiolib_sysfs_init(void)
* registered, and so arch_initcall() can always gpio_export().
spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) {
if (chip->cdev)
list_for_each_entry(gdev, &gpio_devices, list) {
if (gdev->chip->cdev)
......@@ -798,7 +800,7 @@ static int __init gpiolib_sysfs_init(void)
* gpio_lock prevents us from doing this.
spin_unlock_irqrestore(&gpio_lock, flags);
status = gpiochip_sysfs_register(chip);
status = gpiochip_sysfs_register(gdev->chip);
spin_lock_irqsave(&gpio_lock, flags);
spin_unlock_irqrestore(&gpio_lock, flags);
This diff is collapsed.
......@@ -12,13 +12,38 @@
#ifndef GPIOLIB_H
#define GPIOLIB_H
#include <linux/gpio/driver.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cdev.h>
enum of_gpio_flags;
enum gpiod_flags;
struct acpi_device;
* struct gpio_device - internal state container for GPIO devices
* @id: numerical ID number for the GPIO chip
* @dev: the GPIO device struct
* @owner: helps prevent removal of modules exporting active GPIOs
* @chip: pointer to the corresponding gpiochip, holding static
* data for this device
* @list: links gpio_device:s together for traversal
* This state container holds most of the runtime variable data
* for a GPIO device and can hold references and live on after the
* GPIO chip has been removed, if it is still being used from
* userspace.
struct gpio_device {
int id;
struct device dev;
struct module *owner;
struct gpio_chip *chip;
struct list_head list;
* struct acpi_gpio_info - ACPI GPIO specific information
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
......@@ -90,7 +115,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
extern struct spinlock gpio_lock;
extern struct list_head gpio_chips;
extern struct list_head gpio_devices;
struct gpio_desc {
struct gpio_chip *chip;
#include <linux/device.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/irq.h>
......@@ -10,22 +11,22 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/kconfig.h>
struct device;
struct gpio_desc;
struct of_phandle_args;
struct device_node;
struct seq_file;
struct gpio_device;
* struct gpio_chip - abstract a GPIO controller
* @label: for diagnostics
* @gpiodev: the internal state holder, opaque struct
* @parent: optional parent device providing the GPIOs
* @cdev: class device used by sysfs interface (may be NULL)
* @owner: helps prevent removal of modules exporting active GPIOs
* @data: per-instance data assigned by the driver
* @list: links gpio_chips together for traversal
* @request: optional hook for chip-specific activation, such as
* enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as
......@@ -107,11 +108,11 @@ struct seq_file;
struct gpio_chip {
const char *label;
struct gpio_device *gpiodev;
struct device *parent;
struct device *cdev;
struct module *owner;
void *data;
struct list_head list;
int (*request)(struct gpio_chip *chip,
unsigned offset);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment