diff options
| -rw-r--r-- | include/fdtdec.h | 45 | ||||
| -rw-r--r-- | lib/fdtdec.c | 79 | 
2 files changed, 124 insertions, 0 deletions
| diff --git a/include/fdtdec.h b/include/fdtdec.h index a4467000b..2f3842d9a 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -61,6 +61,23 @@ enum fdt_compat_id {  	COMPAT_COUNT,  }; +/* GPIOs are numbered from 0 */ +enum { +	FDT_GPIO_NONE = -1U,	/* an invalid GPIO used to end our list */ + +	FDT_GPIO_ACTIVE_LOW = 1 << 0,	/* input is active low (else high) */ +}; + +/* This is the state of a GPIO pin as defined by the fdt */ +struct fdt_gpio_state { +	const char *name;	/* name of the fdt property defining this */ +	uint gpio;		/* GPIO number, or FDT_GPIO_NONE if none */ +	u8 flags;		/* FDT_GPIO_... flags */ +}; + +/* This tells us whether a fdt_gpio_state record is valid or not */ +#define fdt_gpio_isvalid(x) ((x)->gpio != FDT_GPIO_NONE) +  /**   * Find the next numbered alias for a peripheral. This is used to enumerate   * all the peripherals of a certain type. @@ -227,3 +244,31 @@ int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,   * @return 1 if the properly is present; 0 if it isn't present   */  int fdtdec_get_bool(const void *blob, int node, const char *prop_name); + +/** + * Decode a single GPIOs from an FDT. + * + * If the property is not found, then the GPIO structure will still be + * initialised, with gpio set to FDT_GPIO_NONE. This makes it easy to + * provide optional GPIOs. + * + * @param blob		FDT blob to use + * @param node		Node to look at + * @param prop_name	Node property name + * @param gpio		gpio elements to fill from FDT + * @return 0 if ok, -FDT_ERR_NOTFOUND if the property is missing. + */ +int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, +		struct fdt_gpio_state *gpio); + +/** + * Set up a GPIO pin according to the provided gpio information. At present this + * just requests the GPIO. + * + * If the gpio is FDT_GPIO_NONE, no action is taken. This makes it easy to + * deal with optional GPIOs. + * + * @param gpio		GPIO info to use for set up + * @return 0 if all ok or gpio was FDT_GPIO_NONE; -1 on error + */ +int fdtdec_setup_gpio(struct fdt_gpio_state *gpio); diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 13bb47002..de83226ed 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -24,6 +24,9 @@  #include <libfdt.h>  #include <fdtdec.h> +/* we need the generic GPIO interface here */ +#include <asm-generic/gpio.h> +  DECLARE_GLOBAL_DATA_PTR;  /* @@ -338,3 +341,79 @@ int fdtdec_get_bool(const void *blob, int node, const char *prop_name)  	cell = fdt_getprop(blob, node, prop_name, &len);  	return cell != NULL;  } + +/** + * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no + * terminating item. + * + * @param blob		FDT blob to use + * @param node		Node to look at + * @param prop_name	Node property name + * @param gpio		Array of gpio elements to fill from FDT. This will be + *			untouched if either 0 or an error is returned + * @param max_count	Maximum number of elements allowed + * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would + * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. + */ +static int fdtdec_decode_gpios(const void *blob, int node, +		const char *prop_name, struct fdt_gpio_state *gpio, +		int max_count) +{ +	const struct fdt_property *prop; +	const u32 *cell; +	const char *name; +	int len, i; + +	debug("%s: %s\n", __func__, prop_name); +	assert(max_count > 0); +	prop = fdt_get_property(blob, node, prop_name, &len); +	if (!prop) { +		debug("FDT: %s: property '%s' missing\n", __func__, prop_name); +		return -FDT_ERR_NOTFOUND; +	} + +	/* We will use the name to tag the GPIO */ +	name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); +	cell = (u32 *)prop->data; +	len /= sizeof(u32) * 3;		/* 3 cells per GPIO record */ +	if (len > max_count) { +		debug("FDT: %s: too many GPIOs / cells for " +			"property '%s'\n", __func__, prop_name); +		return -FDT_ERR_BADLAYOUT; +	} + +	/* Read out the GPIO data from the cells */ +	for (i = 0; i < len; i++, cell += 3) { +		gpio[i].gpio = fdt32_to_cpu(cell[1]); +		gpio[i].flags = fdt32_to_cpu(cell[2]); +		gpio[i].name = name; +	} + +	return len; +} + +int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, +		struct fdt_gpio_state *gpio) +{ +	int err; + +	debug("%s: %s\n", __func__, prop_name); +	gpio->gpio = FDT_GPIO_NONE; +	gpio->name = NULL; +	err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1); +	return err == 1 ? 0 : err; +} + +int fdtdec_setup_gpio(struct fdt_gpio_state *gpio) +{ +	/* +	 * Return success if there is no GPIO defined. This is used for +	 * optional GPIOs) +	 */ +	if (!fdt_gpio_isvalid(gpio)) +		return 0; + +	if (gpio_request(gpio->gpio, gpio->name)) +		return -1; +	return 0; +} |