Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 9 Dec 2013 07:14:59 +0000 (UTC)
From:      Ganbold Tsagaankhuu <ganbold@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r259121 - head/sys/arm/rockchip
Message-ID:  <201312090714.rB97ExFe073313@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ganbold (doc committer)
Date: Mon Dec  9 07:14:59 2013
New Revision: 259121
URL: http://svnweb.freebsd.org/changeset/base/259121

Log:
  Add gpio parse routines according to sys/boot/fdt/dts/bindings-gpio.txt.
  
  Reviewed by: stas@

Modified:
  head/sys/arm/rockchip/rk30xx_gpio.c

Modified: head/sys/arm/rockchip/rk30xx_gpio.c
==============================================================================
--- head/sys/arm/rockchip/rk30xx_gpio.c	Mon Dec  9 07:00:39 2013	(r259120)
+++ head/sys/arm/rockchip/rk30xx_gpio.c	Mon Dec  9 07:14:59 2013	(r259121)
@@ -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);
+int platform_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)
@@ -436,6 +456,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);
@@ -480,6 +503,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;
+
+	platform_gpio_init();
+	
 	return (bus_generic_attach(dev));
 
 fail:
@@ -525,3 +553,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
+
+int
+platform_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);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201312090714.rB97ExFe073313>