summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2012-02-27 10:52:36 +0000
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>2012-03-29 08:12:47 +0200
commited3ee5cd0640979a200710b9eefa210a617b19ff (patch)
tree0fc6bd37d6a15e06add67e2ddb9263e63f0ad64a /lib
parentd17da65560f15f74f8efe321044b9cdf45e24c9b (diff)
downloadu-boot-imx-ed3ee5cd0640979a200710b9eefa210a617b19ff.zip
u-boot-imx-ed3ee5cd0640979a200710b9eefa210a617b19ff.tar.gz
u-boot-imx-ed3ee5cd0640979a200710b9eefa210a617b19ff.tar.bz2
fdt: Add basic support for decoding GPIO definitions
This adds some support into fdtdec for reading GPIO definitions from the fdt. We permit up to FDT_GPIO_MAX GPIOs in the system. Each GPIO is of the form: gpio-function-name = <phandle gpio_num flags>; where: phandle is a pointer to the GPIO node gpio_num is the number of the GPIO (0 to 223) flags is a flag, as follows: bit meaning 0 0=polarity normal, 1=active low (inverted) An example is: enable-propounder-gpios = <&gpio 43 0>; which means that GPIO 43 is used to enable the propounder (setting the GPIO high), or that you can detect that the propounder is enabled by checking if the GPIO is high (the fdt does not indicate input/output). Two main functions are provided: fdtdec_decode_gpio() reads a GPIO property from an fdt node and decodes it into a structure. fdtdec_setup_gpio() sets up the GPIO by calling gpio_request for you. Both functions can cope with the property being missing, which is taken to mean that that GPIO function is not available or is not needed. [For reference, from Stephen Warren <swarren@nvidia.com>. It may be that we add this extra complexity later if needed: The correct way to parse such a GPIO property in general is: * Read the first cell. * Find the node referenced by the phandle (the controller). * Ensure property gpio-controller is present in the controller node. * Read property #gpio-cells from the controller node. * Extract #gpio-cells from the original property. * Keep processing more cells from the original property; there may be multiple GPIOs listed. According to the binding documentation in the Linux kernel, Samsung Exynos4 doesn't use this format, and while all other chips do have a flags cell, about 50% of the controllers indicate the cell is unused. ] Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: Tom Warren <twarren@nvidia.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/fdtdec.c79
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;
+}