Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60afe31d authored by Linus Walleij's avatar Linus Walleij
Browse files

Merge branch 'chardev' into devel

parents 42178e2a fe95046e
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
What:		/sys/class/gpio/
Date:		July 2008
KernelVersion:	2.6.27
Contact:	David Brownell <dbrownell@users.sourceforge.net>
Contact:	Linus Walleij <linusw@kernel.org>
Description:

  As a Kconfig option, individual GPIO signals may be accessed from
@@ -26,3 +26,5 @@ Description:
	    /label ... (r/o) descriptive, not necessarily unique
	    /ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)

  This ABI is deprecated and will be removed after 2020. It is
  replaced with the GPIO character device.
+26 −0
Original line number Diff line number Diff line
What:		/dev/gpiochip[0-9]+
Date:		November 2015
KernelVersion:	4.4
Contact:	linux-gpio@vger.kernel.org
Description:
		The character device files /dev/gpiochip* are the interface
		between GPIO chips and userspace.

		The ioctl(2)-based ABI is defined and documented in
		[include/uapi]<linux/gpio.h>.

		The following file operations are supported:

		open(2)
		Currently the only useful flags are O_RDWR.

		ioctl(2)
		Initiate various actions.
		See the inline documentation in [include/uapi]<linux/gpio.h>
		for descriptions of all ioctls.

		close(2)
		Stops and free up the I/O contexts that was associated
		with the file descriptor.

Users:		TBD
+4 −0
Original line number Diff line number Diff line
@@ -4821,10 +4821,14 @@ L: linux-gpio@vger.kernel.org
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
S:	Maintained
F:	Documentation/gpio/
F:	Documentation/ABI/testing/gpio-cdev
F:	Documentation/ABI/obsolete/sysfs-gpio
F:	drivers/gpio/
F:	include/linux/gpio/
F:	include/linux/gpio.h
F:	include/asm-generic/gpio.h
F:	include/uapi/linux/gpio.h
F:	tools/gpio/

GRE DEMULTIPLEXER DRIVER
M:	Dmitry Kozlov <xeb@mail.ru>
+7 −5
Original line number Diff line number Diff line
@@ -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;

	mutex_lock(&sysfs_lock);

@@ -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",
					desc_to_gpio(desc));
@@ -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)
			continue;

		/*
@@ -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);
+290 −71
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/pinctrl/consumer.h>
#include <linux/idr.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <uapi/linux/gpio.h>

#include "gpiolib.h"

@@ -42,6 +47,14 @@
#define	extra_checks	0
#endif

/* Device and char device-related information */
static DEFINE_IDA(gpio_ida);
static dev_t gpio_devt;
#define GPIO_DEV_MAX 256 /* 256 GPIO chip devices supported */
static struct bus_type gpio_bus_type = {
	.name = "gpio",
};

/* gpio_lock prevents conflicts during gpio_desc[] table updates.
 * While any GPIO is requested, its gpio_chip is not removable;
 * each GPIO's "requested" flag serves as a lock and refcount.
@@ -50,8 +63,7 @@ DEFINE_SPINLOCK(gpio_lock);

static DEFINE_MUTEX(gpio_lookup_lock);
static LIST_HEAD(gpio_lookup_list);
LIST_HEAD(gpio_chips);

LIST_HEAD(gpio_devices);

static void gpiochip_free_hogs(struct gpio_chip *chip);
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
@@ -67,15 +79,16 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
 */
struct gpio_desc *gpio_to_desc(unsigned gpio)
{
	struct gpio_chip *chip;
	struct gpio_device *gdev;
	unsigned long flags;

	spin_lock_irqsave(&gpio_lock, flags);

	list_for_each_entry(chip, &gpio_chips, list) {
		if (chip->base <= gpio && chip->base + chip->ngpio > gpio) {
	list_for_each_entry(gdev, &gpio_devices, list) {
		if (gdev->chip->base <= gpio &&
		    gdev->chip->base + gdev->chip->ngpio > gpio) {
			spin_unlock_irqrestore(&gpio_lock, flags);
			return &chip->desc[gpio - chip->base];
			return &gdev->chip->desc[gpio - gdev->chip->base];
		}
	}

@@ -125,16 +138,16 @@ EXPORT_SYMBOL_GPL(gpiod_to_chip);
/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
static int gpiochip_find_base(int ngpio)
{
	struct gpio_chip *chip;
	struct gpio_device *gdev;
	int base = ARCH_NR_GPIOS - ngpio;

	list_for_each_entry_reverse(chip, &gpio_chips, list) {
	list_for_each_entry_reverse(gdev, &gpio_devices, list) {
		/* found a free space? */
		if (chip->base + chip->ngpio <= base)
		if (gdev->chip->base + gdev->chip->ngpio <= base)
			break;
		else
			/* nope, check the space right before the chip */
			base = chip->base - ngpio;
			base = gdev->chip->base - ngpio;
	}

	if (gpio_is_valid(base)) {
@@ -187,18 +200,28 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction);
 * Return -EBUSY if the new chip overlaps with some other chip's integer
 * space.
 */
static int gpiochip_add_to_list(struct gpio_chip *chip)
static int gpiodev_add_to_list(struct gpio_device *gdev)
{
	struct gpio_chip *iterator;
	struct gpio_chip *previous = NULL;
	struct gpio_device *iterator;
	struct gpio_device *previous = NULL;

	if (list_empty(&gpio_chips)) {
		list_add_tail(&chip->list, &gpio_chips);
	if (!gdev->chip)
		return -EINVAL;

	if (list_empty(&gpio_devices)) {
		list_add_tail(&gdev->list, &gpio_devices);
		return 0;
	}

	list_for_each_entry(iterator, &gpio_chips, list) {
		if (iterator->base >= chip->base + chip->ngpio) {
	list_for_each_entry(iterator, &gpio_devices, list) {
		/*
		 * The list may contain dangling GPIO devices with no
		 * live chip assigned.
		 */
		if (!iterator->chip)
			continue;
		if (iterator->chip->base >=
		    gdev->chip->base + gdev->chip->ngpio) {
			/*
			 * Iterator is the first GPIO chip so there is no
			 * previous one
@@ -211,8 +234,8 @@ static int gpiochip_add_to_list(struct gpio_chip *chip)
				 * [base, base + ngpio - 1]) between previous
				 * and iterator chip.
				 */
				if (previous->base + previous->ngpio
						<= chip->base)
				if (previous->chip->base + previous->chip->ngpio
						<= gdev->chip->base)
					goto found;
			}
		}
@@ -225,18 +248,18 @@ static int gpiochip_add_to_list(struct gpio_chip *chip)
	 * Let iterator point to the last chip in the list.
	 */

	iterator = list_last_entry(&gpio_chips, struct gpio_chip, list);
	if (iterator->base + iterator->ngpio <= chip->base) {
		list_add(&chip->list, &iterator->list);
	iterator = list_last_entry(&gpio_devices, struct gpio_device, list);
	if (iterator->chip->base + iterator->chip->ngpio <= gdev->chip->base) {
		list_add(&gdev->list, &iterator->list);
		return 0;
	}

	dev_err(chip->parent,
	dev_err(&gdev->dev,
	       "GPIO integer space overlap, cannot add chip\n");
	return -EBUSY;

found:
	list_add_tail(&chip->list, &iterator->list);
	list_add_tail(&gdev->list, &iterator->list);
	return 0;
}

@@ -245,16 +268,16 @@ static int gpiochip_add_to_list(struct gpio_chip *chip)
 */
static struct gpio_desc *gpio_name_to_desc(const char * const name)
{
	struct gpio_chip *chip;
	struct gpio_device *gdev;
	unsigned long flags;

	spin_lock_irqsave(&gpio_lock, flags);

	list_for_each_entry(chip, &gpio_chips, list) {
	list_for_each_entry(gdev, &gpio_devices, list) {
		int i;

		for (i = 0; i != chip->ngpio; ++i) {
			struct gpio_desc *gpio = &chip->desc[i];
		for (i = 0; i != gdev->chip->ngpio; ++i) {
			struct gpio_desc *gpio = &gdev->chip->desc[i];

			if (!gpio->name || !name)
				continue;
@@ -290,8 +313,8 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)

		gpio = gpio_name_to_desc(gc->names[i]);
		if (gpio)
			dev_warn(gc->parent, "Detected name collision for "
				 "GPIO name '%s'\n",
			dev_warn(&gc->gpiodev->dev,
				 "Detected name collision for GPIO name '%s'\n",
				 gc->names[i]);
	}

@@ -302,6 +325,88 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
	return 0;
}

/**
 * gpio_ioctl() - ioctl handler for the GPIO chardev
 */
static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	struct gpio_device *gdev = filp->private_data;
	struct gpio_chip *chip = gdev->chip;
	int __user *ip = (int __user *)arg;
	struct gpiochip_info chipinfo;

	/* We fail any subsequent ioctl():s when the chip is gone */
	if (!chip)
		return -ENODEV;

	if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
		/* Fill in the struct and pass to userspace */
		strncpy(chipinfo.name, dev_name(&gdev->dev),
			sizeof(chipinfo.name));
		chipinfo.name[sizeof(chipinfo.name)-1] = '\0';
		chipinfo.lines = chip->ngpio;
		if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
			return -EFAULT;
		return 0;
	}
	return -EINVAL;
}

/**
 * gpio_chrdev_open() - open the chardev for ioctl operations
 * @inode: inode for this chardev
 * @filp: file struct for storing private data
 * Returns 0 on success
 */
static int gpio_chrdev_open(struct inode *inode, struct file *filp)
{
	struct gpio_device *gdev = container_of(inode->i_cdev,
					      struct gpio_device, chrdev);

	/* Fail on open if the backing gpiochip is gone */
	if (!gdev || !gdev->chip)
		return -ENODEV;
	get_device(&gdev->dev);
	filp->private_data = gdev;
	return 0;
}

/**
 * gpio_chrdev_release() - close chardev after ioctl operations
 * @inode: inode for this chardev
 * @filp: file struct for storing private data
 * Returns 0 on success
 */
static int gpio_chrdev_release(struct inode *inode, struct file *filp)
{
	struct gpio_device *gdev = container_of(inode->i_cdev,
					      struct gpio_device, chrdev);

	if (!gdev)
		return -ENODEV;
	put_device(&gdev->dev);
	return 0;
}


static const struct file_operations gpio_fileops = {
	.release = gpio_chrdev_release,
	.open = gpio_chrdev_open,
	.owner = THIS_MODULE,
	.llseek = noop_llseek,
	.unlocked_ioctl = gpio_ioctl,
	.compat_ioctl = gpio_ioctl,
};

static void gpiodevice_release(struct device *dev)
{
	struct gpio_device *gdev = dev_get_drvdata(dev);

	cdev_del(&gdev->chrdev);
	list_del(&gdev->list);
	ida_simple_remove(&gpio_ida, gdev->id);
}

/**
 * gpiochip_add_data() - register a gpio_chip
 * @chip: the chip to register, with chip->base initialized
@@ -323,19 +428,61 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
{
	unsigned long	flags;
	int		status = 0;
	unsigned	id;
	unsigned	i;
	int		base = chip->base;
	struct gpio_desc *descs;
	struct gpio_device *gdev;

	descs = kcalloc(chip->ngpio, sizeof(descs[0]), GFP_KERNEL);
	if (!descs)
	/*
	 * First: allocate and populate the internal stat container, and
	 * set up the struct device.
	 */
	gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
	if (!gdev)
		return -ENOMEM;
	gdev->dev.bus = &gpio_bus_type;
	gdev->chip = chip;
	chip->gpiodev = gdev;
	if (chip->parent) {
		gdev->dev.parent = chip->parent;
		gdev->dev.of_node = chip->parent->of_node;
	} else {
#ifdef CONFIG_OF_GPIO
	/* If the gpiochip has an assigned OF node this takes precedence */
		if (chip->of_node)
			gdev->dev.of_node = chip->of_node;
#endif
	}
	gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);
	if (gdev->id < 0) {
		status = gdev->id;
		goto err_free_gdev;
	}
	dev_set_name(&gdev->dev, "gpiochip%d", gdev->id);
	device_initialize(&gdev->dev);
	dev_set_drvdata(&gdev->dev, gdev);
	if (chip->parent && chip->parent->driver)
		gdev->owner = chip->parent->driver->owner;
	else if (chip->owner)
		/* TODO: remove chip->owner */
		gdev->owner = chip->owner;
	else
		gdev->owner = THIS_MODULE;

	/* FIXME: devm_kcalloc() these and move to gpio_device */
	descs = kcalloc(chip->ngpio, sizeof(descs[0]), GFP_KERNEL);
	if (!descs) {
		status = -ENOMEM;
		goto err_free_gdev;
	}

	/* FIXME: move driver data into gpio_device dev_set_drvdata() */
	chip->data = data;

	if (chip->ngpio == 0) {
		chip_err(chip, "tried to insert a GPIO chip with zero lines\n");
		return -EINVAL;
		status = -EINVAL;
		goto err_free_descs;
	}

	spin_lock_irqsave(&gpio_lock, flags);
@@ -350,15 +497,16 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
		chip->base = base;
	}

	status = gpiochip_add_to_list(chip);
	status = gpiodev_add_to_list(gdev);
	if (status) {
		spin_unlock_irqrestore(&gpio_lock, flags);
		goto err_free_descs;
	}

	for (id = 0; id < chip->ngpio; id++) {
		struct gpio_desc *desc = &descs[id];
	for (i = 0; i < chip->ngpio; i++) {
		struct gpio_desc *desc = &descs[i];

		/* REVISIT: maybe a pointer to gpio_device is better */
		desc->chip = chip;

		/* REVISIT: most hardware initializes GPIOs as inputs (often
@@ -369,18 +517,15 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
		 */
		desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
	}

	chip->desc = descs;

	spin_unlock_irqrestore(&gpio_lock, flags);

#ifdef CONFIG_PINCTRL
	/* FIXME: move pin ranges to gpio_device */
	INIT_LIST_HEAD(&chip->pin_ranges);
#endif

	if (!chip->owner && chip->parent && chip->parent->driver)
		chip->owner = chip->parent->driver->owner;

	status = gpiochip_set_desc_names(chip);
	if (status)
		goto err_remove_from_list;
@@ -391,28 +536,58 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)

	acpi_gpiochip_add(chip);

	/*
	 * By first adding the chardev, and then adding the device,
	 * we get a device node entry in sysfs under
	 * /sys/bus/gpio/devices/gpiochipN/dev that can be used for
	 * coldplug of device nodes and other udev business.
	 */
	cdev_init(&gdev->chrdev, &gpio_fileops);
	gdev->chrdev.owner = THIS_MODULE;
	gdev->chrdev.kobj.parent = &gdev->dev.kobj;
	gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id);
	status = cdev_add(&gdev->chrdev, gdev->dev.devt, 1);
	if (status < 0)
		chip_warn(chip, "failed to add char device %d:%d\n",
			  MAJOR(gpio_devt), gdev->id);
	else
		chip_dbg(chip, "added GPIO chardev (%d:%d)\n",
			 MAJOR(gpio_devt), gdev->id);
	status = device_add(&gdev->dev);
	if (status)
		goto err_remove_chardev;

	status = gpiochip_sysfs_register(chip);
	if (status)
		goto err_remove_chip;
		goto err_remove_device;

	/* From this point, the .release() function cleans up gpio_device */
	gdev->dev.release = gpiodevice_release;
	get_device(&gdev->dev);
	pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__,
		chip->base, chip->base + chip->ngpio - 1,
		chip->label ? : "generic");

	return 0;

err_remove_device:
	device_del(&gdev->dev);
err_remove_chardev:
	cdev_del(&gdev->chrdev);
err_remove_chip:
	acpi_gpiochip_remove(chip);
	gpiochip_free_hogs(chip);
	of_gpiochip_remove(chip);
err_remove_from_list:
	spin_lock_irqsave(&gpio_lock, flags);
	list_del(&chip->list);
	list_del(&gdev->list);
	spin_unlock_irqrestore(&gpio_lock, flags);
	chip->desc = NULL;
err_free_descs:
	kfree(descs);

err_free_gdev:
	ida_simple_remove(&gpio_ida, gdev->id);
	kfree(gdev);
	/* failures here can mean systems won't boot... */
	pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,
		chip->base, chip->base + chip->ngpio - 1,
@@ -429,15 +604,18 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data);
 */
void gpiochip_remove(struct gpio_chip *chip)
{
	struct gpio_device *gdev = chip->gpiodev;
	struct gpio_desc *desc;
	unsigned long	flags;
	unsigned	id;
	bool		requested = false;

	gpiochip_sysfs_unregister(chip);
	/* Numb the device, cancelling all outstanding operations */
	gdev->chip = NULL;

	/* FIXME: should the legacy sysfs handling be moved to gpio_device? */
	gpiochip_sysfs_unregister(chip);
	gpiochip_irqchip_remove(chip);

	acpi_gpiochip_remove(chip);
	gpiochip_remove_pin_ranges(chip);
	gpiochip_free_hogs(chip);
@@ -450,15 +628,23 @@ void gpiochip_remove(struct gpio_chip *chip)
		if (test_bit(FLAG_REQUESTED, &desc->flags))
			requested = true;
	}
	list_del(&chip->list);
	spin_unlock_irqrestore(&gpio_lock, flags);

	if (requested)
		dev_crit(chip->parent,
		dev_crit(&chip->gpiodev->dev,
			 "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");

	/* FIXME: need to be moved to gpio_device and held there */
	kfree(chip->desc);
	chip->desc = NULL;

	/*
	 * The gpiochip side puts its use of the device to rest here:
	 * if there are no userspace clients, the chardev and device will
	 * be removed, else it will be dangling until the last user is
	 * gone.
	 */
	put_device(&gdev->dev);
}
EXPORT_SYMBOL_GPL(gpiochip_remove);

@@ -477,17 +663,21 @@ struct gpio_chip *gpiochip_find(void *data,
				int (*match)(struct gpio_chip *chip,
					     void *data))
{
	struct gpio_device *gdev;
	struct gpio_chip *chip;
	unsigned long flags;

	spin_lock_irqsave(&gpio_lock, flags);
	list_for_each_entry(chip, &gpio_chips, list)
		if (match(chip, data))
	list_for_each_entry(gdev, &gpio_devices, list)
		if (match(gdev->chip, data))
			break;

	/* No match? */
	if (&chip->list == &gpio_chips)
	if (&gdev->list == &gpio_devices)
		chip = NULL;
	else
		chip = gdev->chip;

	spin_unlock_irqrestore(&gpio_lock, flags);

	return chip;
@@ -617,14 +807,14 @@ static int gpiochip_irq_reqres(struct irq_data *d)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);

	if (!try_module_get(chip->owner))
	if (!try_module_get(chip->gpiodev->owner))
		return -ENODEV;

	if (gpiochip_lock_as_irq(chip, d->hwirq)) {
		chip_err(chip,
			"unable to lock HW IRQ %lu for IRQ\n",
			d->hwirq);
		module_put(chip->owner);
		module_put(chip->gpiodev->owner);
		return -EINVAL;
	}
	return 0;
@@ -635,7 +825,7 @@ static void gpiochip_irq_relres(struct irq_data *d)
	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);

	gpiochip_unlock_as_irq(chip, d->hwirq);
	module_put(chip->owner);
	module_put(chip->gpiodev->owner);
}

static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -985,10 +1175,10 @@ int gpiod_request(struct gpio_desc *desc, const char *label)
	if (!chip)
		goto done;

	if (try_module_get(chip->owner)) {
	if (try_module_get(chip->gpiodev->owner)) {
		status = __gpiod_request(desc, label);
		if (status < 0)
			module_put(chip->owner);
			module_put(chip->gpiodev->owner);
	}

done:
@@ -1034,7 +1224,7 @@ static bool __gpiod_free(struct gpio_desc *desc)
void gpiod_free(struct gpio_desc *desc)
{
	if (desc && __gpiod_free(desc))
		module_put(desc->chip->owner);
		module_put(desc->chip->gpiodev->owner);
	else
		WARN_ON(extra_checks);
}
@@ -2456,6 +2646,26 @@ void gpiod_put_array(struct gpio_descs *descs)
}
EXPORT_SYMBOL_GPL(gpiod_put_array);

static int __init gpiolib_dev_init(void)
{
	int ret;

	/* Register GPIO sysfs bus */
	ret  = bus_register(&gpio_bus_type);
	if (ret < 0) {
		pr_err("gpiolib: could not register GPIO bus type\n");
		return ret;
	}

	ret = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, "gpiochip");
	if (ret < 0) {
		pr_err("gpiolib: failed to allocate char dev region\n");
		bus_unregister(&gpio_bus_type);
	}
	return ret;
}
core_initcall(gpiolib_dev_init);

#ifdef CONFIG_DEBUG_FS

static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
@@ -2492,16 +2702,16 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
{
	unsigned long flags;
	struct gpio_chip *chip = NULL;
	struct gpio_device *gdev = NULL;
	loff_t index = *pos;

	s->private = "";

	spin_lock_irqsave(&gpio_lock, flags);
	list_for_each_entry(chip, &gpio_chips, list)
	list_for_each_entry(gdev, &gpio_devices, list)
		if (index-- == 0) {
			spin_unlock_irqrestore(&gpio_lock, flags);
			return chip;
			return gdev;
		}
	spin_unlock_irqrestore(&gpio_lock, flags);

@@ -2511,14 +2721,14 @@ static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	unsigned long flags;
	struct gpio_chip *chip = v;
	struct gpio_device *gdev = v;
	void *ret = NULL;

	spin_lock_irqsave(&gpio_lock, flags);
	if (list_is_last(&chip->list, &gpio_chips))
	if (list_is_last(&gdev->list, &gpio_devices))
		ret = NULL;
	else
		ret = list_entry(chip->list.next, struct gpio_chip, list);
		ret = list_entry(gdev->list.next, struct gpio_device, list);
	spin_unlock_irqrestore(&gpio_lock, flags);

	s->private = "\n";
@@ -2533,15 +2743,24 @@ static void gpiolib_seq_stop(struct seq_file *s, void *v)

static int gpiolib_seq_show(struct seq_file *s, void *v)
{
	struct gpio_chip *chip = v;
	struct device *dev;
	struct gpio_device *gdev = v;
	struct gpio_chip *chip = gdev->chip;
	struct device *parent;

	if (!chip) {
		seq_printf(s, "%s%s: (dangling chip)", (char *)s->private,
			   dev_name(&gdev->dev));
		return 0;
	}

	seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,
	seq_printf(s, "%s%s: GPIOs %d-%d", (char *)s->private,
		   dev_name(&gdev->dev),
		   chip->base, chip->base + chip->ngpio - 1);
	dev = chip->parent;
	if (dev)
		seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",
			dev_name(dev));
	parent = chip->parent;
	if (parent)
		seq_printf(s, ", parent: %s/%s",
			   parent->bus ? parent->bus->name : "no-bus",
			   dev_name(parent));
	if (chip->label)
		seq_printf(s, ", %s", chip->label);
	if (chip->can_sleep)
Loading