diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fdtdec.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 13bb470..de83226 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; +} |