svn commit: r296269 - head/sys/dev/gpio

Michal Meloun mmel at FreeBSD.org
Tue Mar 1 16:10:17 UTC 2016


Author: mmel
Date: Tue Mar  1 16:10:15 2016
New Revision: 296269
URL: https://svnweb.freebsd.org/changeset/base/296269

Log:
  OFW_GPIOBUS: Add utility functions for easier handling of OFW GPIO pins.
  
  Reviewed by: ian, loos (paritaly)

Modified:
  head/sys/dev/gpio/gpiobusvar.h
  head/sys/dev/gpio/ofw_gpiobus.c

Modified: head/sys/dev/gpio/gpiobusvar.h
==============================================================================
--- head/sys/dev/gpio/gpiobusvar.h	Tue Mar  1 15:21:01 2016	(r296268)
+++ head/sys/dev/gpio/gpiobusvar.h	Tue Mar  1 16:10:15 2016	(r296269)
@@ -38,6 +38,7 @@
 
 #ifdef FDT
 #include <dev/ofw/ofw_bus_subr.h>
+#include <gnu/dts/include/dt-bindings/gpio/gpio.h>
 #endif
 
 #include "gpio_if.h"
@@ -83,6 +84,7 @@ struct gpiobus_pin
 	uint32_t	flags;	/* pin flags */
 	uint32_t	pin;	/* pin number */
 };
+typedef struct gpiobus_pin *gpio_pin_t;
 
 struct gpiobus_ivar
 {
@@ -109,6 +111,16 @@ device_t ofw_gpiobus_add_fdt_child(devic
 int ofw_gpiobus_parse_gpios(device_t, char *, struct gpiobus_pin **);
 void ofw_gpiobus_register_provider(device_t);
 void ofw_gpiobus_unregister_provider(device_t);
+
+/* Consumers interface. */
+int gpio_pin_get_by_ofw_name(device_t consumer, char *name, gpio_pin_t *gpio);
+int gpio_pin_get_by_ofw_idx(device_t consumer, int idx, gpio_pin_t *gpio);
+int gpio_pin_get_by_ofw_property(device_t consumer, char *name,
+    gpio_pin_t *gpio);
+void gpio_pin_release(gpio_pin_t gpio);
+int gpio_pin_is_active(gpio_pin_t pin, bool *active);
+int gpio_pin_set_active(gpio_pin_t pin, bool active);
+int gpio_pin_setflags(gpio_pin_t pin, uint32_t flags);
 #endif
 int gpio_check_flags(uint32_t, uint32_t);
 device_t gpiobus_attach_bus(device_t);

Modified: head/sys/dev/gpio/ofw_gpiobus.c
==============================================================================
--- head/sys/dev/gpio/ofw_gpiobus.c	Tue Mar  1 15:21:01 2016	(r296268)
+++ head/sys/dev/gpio/ofw_gpiobus.c	Tue Mar  1 16:10:15 2016	(r296269)
@@ -47,6 +47,166 @@ static void ofw_gpiobus_destroy_devinfo(
 static int ofw_gpiobus_parse_gpios_impl(device_t, phandle_t, char *,
 	struct gpiobus_softc *, struct gpiobus_pin **);
 
+/*
+ * Utility functions for easier handling of OFW GPIO pins.
+ *
+ * !!! BEWARE !!!
+ * GPIOBUS uses children's IVARs, so we cannot use this interface for cross
+ * tree consumers.
+ *
+ */
+static int
+gpio_pin_get_by_ofw_impl(device_t consumer_dev, char *prop_name, int idx,
+    gpio_pin_t *out_pin)
+{
+	phandle_t cnode, xref;
+	pcell_t *cells;
+	device_t busdev;
+	struct gpiobus_pin pin;
+	int ncells, rv;
+
+	cnode = ofw_bus_get_node(consumer_dev);
+	if (cnode <= 0) {
+		device_printf(consumer_dev,
+		    "%s called on not ofw based device\n", __func__);
+		return (ENXIO);
+	}
+
+	rv = ofw_bus_parse_xref_list_alloc(cnode, prop_name, "#gpio-cells",
+	    idx, &xref, &ncells, &cells);
+	if (rv != 0)
+		return (rv);
+
+	/* Translate provider to device. */
+	pin.dev = OF_device_from_xref(xref);
+	if (pin.dev == NULL) {
+		free(cells, M_OFWPROP);
+		return (ENODEV);
+	}
+
+	/* Test if GPIO bus already exist. */
+	busdev = GPIO_GET_BUS(pin.dev);
+	if (busdev == NULL) {
+		free(cells, M_OFWPROP);
+		return (ENODEV);
+	}
+
+	/* Map GPIO pin. */
+	rv = gpio_map_gpios(pin.dev, cnode, OF_node_from_xref(xref), ncells,
+	    cells, &pin.pin, &pin.flags);
+	free(cells, M_OFWPROP);
+	if (rv != 0) {
+		device_printf(consumer_dev, "Cannot map the gpio property.\n");
+		return (ENXIO);
+	}
+
+	/* Reserve GPIO pin. */
+	rv = gpiobus_map_pin(busdev, pin.pin);
+	if (rv != 0) {
+		device_printf(consumer_dev, "Cannot reserve gpio pin.\n");
+		return (EBUSY);
+	}
+
+	*out_pin = malloc(sizeof(struct gpiobus_pin), M_DEVBUF,
+	    M_WAITOK | M_ZERO);
+	**out_pin = pin;
+	return (0);
+}
+
+int
+gpio_pin_get_by_ofw_idx(device_t consumer_dev, int idx, gpio_pin_t *pin)
+{
+
+	return (gpio_pin_get_by_ofw_impl(consumer_dev, "gpios", idx, pin));
+}
+
+int
+gpio_pin_get_by_ofw_property(device_t consumer_dev, char *name, gpio_pin_t *pin)
+{
+
+	return (gpio_pin_get_by_ofw_impl(consumer_dev, name, 0, pin));
+}
+
+int
+gpio_pin_get_by_ofw_name(device_t consumer_dev, char *name, gpio_pin_t *pin)
+{
+	int rv, idx;
+	phandle_t cnode;
+
+	cnode = ofw_bus_get_node(consumer_dev);
+	if (cnode <= 0) {
+		device_printf(consumer_dev,
+		    "%s called on not ofw based device\n",  __func__);
+		return (ENXIO);
+	}
+	rv = ofw_bus_find_string_index(cnode, "gpio-names", name, &idx);
+	if (rv != 0)
+		return (rv);
+	return (gpio_pin_get_by_ofw_idx(consumer_dev, idx, pin));
+}
+
+void
+gpio_pin_release(gpio_pin_t gpio)
+{
+
+	if (gpio == NULL)
+		return;
+
+	/* XXXX Unreserve pin. */
+	free(gpio, M_DEVBUF);
+}
+
+int
+gpio_pin_is_active(gpio_pin_t pin, bool *active)
+{
+	int rv;
+	uint32_t tmp;
+
+	KASSERT(pin != NULL, ("GPIO pin is NULL."));
+	KASSERT(pin->dev != NULL, ("GPIO pin device is NULL."));
+	rv = GPIO_PIN_GET(pin->dev, pin->pin, &tmp);
+	if (rv  != 0) {
+		return (rv);
+	}
+
+	*active = tmp != 0;
+	if (pin->flags & GPIO_ACTIVE_LOW)
+		*active = !(*active);
+	return (0);
+}
+
+int
+gpio_pin_set_active(gpio_pin_t pin, bool active)
+{
+	int rv;
+	uint32_t tmp;
+
+	if (pin->flags & GPIO_ACTIVE_LOW)
+		tmp = active ? 0 : 1;
+	else
+		tmp = active ? 1 : 0;
+
+	KASSERT(pin != NULL, ("GPIO pin is NULL."));
+	KASSERT(pin->dev != NULL, ("GPIO pin device is NULL."));
+	rv = GPIO_PIN_SET(pin->dev, pin->pin, tmp);
+	return (rv);
+}
+
+int
+gpio_pin_setflags(gpio_pin_t pin, uint32_t flags)
+{
+	int rv;
+
+	KASSERT(pin != NULL, ("GPIO pin is NULL."));
+	KASSERT(pin->dev != NULL, ("GPIO pin device is NULL."));
+
+	rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags);
+	return (rv);
+}
+
+/*
+ * OFW_GPIOBUS driver.
+ */
 device_t
 ofw_gpiobus_add_fdt_child(device_t bus, const char *drvname, phandle_t child)
 {


More information about the svn-src-all mailing list