summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-10-26 01:15:16 +0000
committerian <ian@FreeBSD.org>2014-10-26 01:15:16 +0000
commitf2e6118a3c27b24dc0f495a9d182542560163d7c (patch)
tree332da4d7d809894b3b7fdb0586629ba01742508f /sys/arm
parent682138b2b9462a4c746e6891426c2d0e4c0e336f (diff)
downloadFreeBSD-src-f2e6118a3c27b24dc0f495a9d182542560163d7c.zip
FreeBSD-src-f2e6118a3c27b24dc0f495a9d182542560163d7c.tar.gz
MFC r257200, r259121, r261410, r265853:
- Remove #include <machine/frame.h>. - Add gpio parse routines according to sys/boot/fdt/dts/bindings-gpio.txt. - Follow r261352 by updating all drivers which are children of simplebus to check the status property in their probe routines. - Rename platform_gpio_init to be SoC specific, and make it static as it's only called from this file. This is mostly catching up on some old MFCs that were done before this file existed in the 10 branch.
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/rockchip/rk30xx_gpio.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/sys/arm/rockchip/rk30xx_gpio.c b/sys/arm/rockchip/rk30xx_gpio.c
index 21c52eb..3ecedda 100644
--- a/sys/arm/rockchip/rk30xx_gpio.c
+++ b/sys/arm/rockchip/rk30xx_gpio.c
@@ -86,6 +86,26 @@ struct rk30_gpio_softc {
struct gpio_pin sc_gpio_pins[RK30_GPIO_PINS];
};
+static struct rk30_gpio_softc *rk30_gpio_sc = NULL;
+
+typedef int (*gpios_phandler_t)(phandle_t, pcell_t *, int);
+
+struct gpio_ctrl_entry {
+ const char *compat;
+ gpios_phandler_t handler;
+};
+
+int rk30_gpios_prop_handle(phandle_t ctrl, pcell_t *gpios, int len);
+static int rk30_gpio_init(void);
+
+struct gpio_ctrl_entry gpio_controllers[] = {
+ { "rockchip,rk30xx-gpio", &rk30_gpios_prop_handle },
+ { "rockchip,rk30xx-gpio", &rk30_gpios_prop_handle },
+ { "rockchip,rk30xx-gpio", &rk30_gpios_prop_handle },
+ { "rockchip,rk30xx-gpio", &rk30_gpios_prop_handle },
+ { NULL, NULL }
+};
+
#define RK30_GPIO_LOCK(_sc) mtx_lock(&_sc->sc_mtx)
#define RK30_GPIO_UNLOCK(_sc) mtx_unlock(&_sc->sc_mtx)
#define RK30_GPIO_LOCK_ASSERT(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED)
@@ -439,6 +459,9 @@ rk30_gpio_attach(device_t dev)
int i, rid;
phandle_t gpio;
+ if (rk30_gpio_sc)
+ return (ENXIO);
+
sc->sc_dev = dev;
mtx_init(&sc->sc_mtx, "rk30 gpio", "gpio", MTX_DEF);
@@ -483,6 +506,11 @@ rk30_gpio_attach(device_t dev)
device_add_child(dev, "gpioc", device_get_unit(dev));
device_add_child(dev, "gpiobus", device_get_unit(dev));
+
+ rk30_gpio_sc = sc;
+
+ rk30_gpio_init();
+
return (bus_generic_attach(dev));
fail:
@@ -528,3 +556,121 @@ static driver_t rk30_gpio_driver = {
};
DRIVER_MODULE(rk30_gpio, simplebus, rk30_gpio_driver, rk30_gpio_devclass, 0, 0);
+
+int
+rk30_gpios_prop_handle(phandle_t ctrl, pcell_t *gpios, int len)
+{
+ struct rk30_gpio_softc *sc;
+ pcell_t gpio_cells;
+ int inc, t, tuples, tuple_size;
+ int dir, flags, pin, i;
+ u_long gpio_ctrl, size;
+
+ sc = rk30_gpio_sc;
+ if (sc == NULL)
+ return ENXIO;
+
+ if (OF_getprop(ctrl, "#gpio-cells", &gpio_cells, sizeof(pcell_t)) < 0)
+ return (ENXIO);
+
+ gpio_cells = fdt32_to_cpu(gpio_cells);
+ if (gpio_cells != 2)
+ return (ENXIO);
+
+ tuple_size = gpio_cells * sizeof(pcell_t) + sizeof(phandle_t);
+ tuples = len / tuple_size;
+
+ if (fdt_regsize(ctrl, &gpio_ctrl, &size))
+ return (ENXIO);
+
+ /*
+ * Skip controller reference, since controller's phandle is given
+ * explicitly (in a function argument).
+ */
+ inc = sizeof(ihandle_t) / sizeof(pcell_t);
+ gpios += inc;
+ for (t = 0; t < tuples; t++) {
+ pin = fdt32_to_cpu(gpios[0]);
+ dir = fdt32_to_cpu(gpios[1]);
+ flags = fdt32_to_cpu(gpios[2]);
+
+ for (i = 0; i < sc->sc_gpio_npins; i++) {
+ if (sc->sc_gpio_pins[i].gp_pin == pin)
+ break;
+ }
+ if (i >= sc->sc_gpio_npins)
+ return (EINVAL);
+
+ rk30_gpio_pin_configure(sc, &sc->sc_gpio_pins[i], flags);
+
+ if (dir == 1) {
+ /* Input. */
+ rk30_gpio_pin_set(sc->sc_dev, pin, RK30_GPIO_INPUT);
+ } else {
+ /* Output. */
+ rk30_gpio_pin_set(sc->sc_dev, pin, RK30_GPIO_OUTPUT);
+ }
+ gpios += gpio_cells + inc;
+ }
+
+ return (0);
+}
+
+#define MAX_PINS_PER_NODE 5
+#define GPIOS_PROP_CELLS 4
+
+static int
+rk30_gpio_init(void)
+{
+ phandle_t child, parent, root, ctrl;
+ pcell_t gpios[MAX_PINS_PER_NODE * GPIOS_PROP_CELLS];
+ struct gpio_ctrl_entry *e;
+ int len, rv;
+
+ root = OF_finddevice("/");
+ len = 0;
+ parent = root;
+
+ /* Traverse through entire tree to find nodes with 'gpios' prop */
+ for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
+
+ /* Find a 'leaf'. Start the search from this node. */
+ while (OF_child(child)) {
+ parent = child;
+ child = OF_child(child);
+ }
+ if ((len = OF_getproplen(child, "gpios")) > 0) {
+
+ if (len > sizeof(gpios))
+ return (ENXIO);
+
+ /* Get 'gpios' property. */
+ OF_getprop(child, "gpios", &gpios, len);
+
+ e = (struct gpio_ctrl_entry *)&gpio_controllers;
+
+ /* Find and call a handler. */
+ for (; e->compat; e++) {
+ /*
+ * First cell of 'gpios' property should
+ * contain a ref. to a node defining GPIO
+ * controller.
+ */
+ ctrl = OF_xref_phandle(fdt32_to_cpu(gpios[0]));
+
+ if (fdt_is_compatible(ctrl, e->compat))
+ /* Call a handler. */
+ if ((rv = e->handler(ctrl,
+ (pcell_t *)&gpios, len)))
+ return (rv);
+ }
+ }
+
+ if (OF_peer(child) == 0) {
+ /* No more siblings. */
+ child = parent;
+ parent = OF_parent(child);
+ }
+ }
+ return (0);
+}
OpenPOWER on IntegriCloud