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

Commit 3d0f7cf0 authored by Grant Likely's avatar Grant Likely
Browse files

gpio: Adjust of_xlate API to support multiple GPIO chips



This patch changes the of_xlate API to make it possible for multiple
gpio_chips to refer to the same device tree node.  This is useful for
banked GPIO controllers that use multiple gpio_chips for a single
device.  With this change the core code will try calling of_xlate on
each gpio_chip that references the device_node and will return the
gpio number for the first one to return 'true'.

Tested-by: default avatarRoland Stigge <stigge@antcom.de>
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent 09d71ff1
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -96,8 +96,7 @@ static struct i2c_board_info __initdata i2c_devices_3ds[] = {

static int lcd_power_gpio = -ENXIO;

static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip,
						     const void *data)
static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip, void *data)
{
	return !strcmp(chip->label, data);
}
+38 −42
Original line number Diff line number Diff line
@@ -15,11 +15,39 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>

/* Private data structure for of_gpiochip_is_match */
struct gg_data {
	enum of_gpio_flags *flags;
	struct of_phandle_args gpiospec;

	int out_gpio;
};

/* Private function for resolving node pointer to gpio_chip */
static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
{
	struct gg_data *gg_data = data;
	int ret;

	if ((gc->of_node != gg_data->gpiospec.np) ||
	    (gc->of_gpio_n_cells != gg_data->gpiospec.args_count) ||
	    (!gc->of_xlate))
		return false;

	ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
	if (ret < 0)
		return false;

	gg_data->out_gpio = ret + gc->base;
	return true;
}

/**
 * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API
 * @np:		device node to get GPIO from
@@ -34,46 +62,25 @@
int of_get_named_gpio_flags(struct device_node *np, const char *propname,
                           int index, enum of_gpio_flags *flags)
{
	struct gg_data gg_data = { .flags = flags, .out_gpio = -ENODEV };
	int ret;
	struct gpio_chip *gc;
	struct of_phandle_args gpiospec;

	/* .of_xlate might decide to not fill in the flags, so clear it. */
	if (flags)
		*flags = 0;

	ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
					 &gpiospec);
					 &gg_data.gpiospec);
	if (ret) {
		pr_debug("%s: can't parse gpios property\n", __func__);
		goto err0;
	}

	gc = of_node_to_gpiochip(gpiospec.np);
	if (!gc) {
		pr_debug("%s: gpio controller %s isn't registered\n",
			 np->full_name, gpiospec.np->full_name);
		ret = -ENODEV;
		goto err1;
	}

	if (gpiospec.args_count != gc->of_gpio_n_cells) {
		pr_debug("%s: wrong #gpio-cells for %s\n",
			 np->full_name, gpiospec.np->full_name);
		ret = -EINVAL;
		goto err1;
		return -EINVAL;
	}

	/* .xlate might decide to not fill in the flags, so clear it. */
	if (flags)
		*flags = 0;

	ret = gc->of_xlate(gc, &gpiospec, flags);
	if (ret < 0)
		goto err1;
	gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);

	ret += gc->base;
err1:
	of_node_put(gpiospec.np);
err0:
	of_node_put(gg_data.gpiospec.np);
	pr_debug("%s exited with status %d\n", __func__, ret);
	return ret;
	return gg_data.out_gpio;
}
EXPORT_SYMBOL(of_get_named_gpio_flags);

@@ -227,14 +234,3 @@ void of_gpiochip_remove(struct gpio_chip *chip)
	if (chip->of_node)
		of_node_put(chip->of_node);
}

/* Private function for resolving node pointer to gpio_chip */
static int of_gpiochip_is_match(struct gpio_chip *chip, const void *data)
{
	return chip->of_node == data;
}

struct gpio_chip *of_node_to_gpiochip(struct device_node *np)
{
	return gpiochip_find(np, of_gpiochip_is_match);
}
+1 −1
Original line number Diff line number Diff line
@@ -1156,7 +1156,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
 */
struct gpio_chip *gpiochip_find(const void *data,
				int (*match)(struct gpio_chip *chip,
					     const void *data))
					     void *data))
{
	struct gpio_chip *chip = NULL;
	unsigned long flags;
+1 −1
Original line number Diff line number Diff line
@@ -144,7 +144,7 @@ extern int gpiochip_add(struct gpio_chip *chip);
extern int __must_check gpiochip_remove(struct gpio_chip *chip);
extern struct gpio_chip *gpiochip_find(const void *data,
					int (*match)(struct gpio_chip *chip,
						     const void *data));
						     void *data));


/* Always use the library code for GPIO management calls,
+0 −1
Original line number Diff line number Diff line
@@ -58,7 +58,6 @@ extern int of_mm_gpiochip_add(struct device_node *np,

extern void of_gpiochip_add(struct gpio_chip *gc);
extern void of_gpiochip_remove(struct gpio_chip *gc);
extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
extern int of_gpio_simple_xlate(struct gpio_chip *gc,
				const struct of_phandle_args *gpiospec,
				u32 *flags);