aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/gpio/gpiobus.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/gpio/gpiobus.c')
-rw-r--r--sys/dev/gpio/gpiobus.c142
1 files changed, 81 insertions, 61 deletions
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
index c8fee7d400c1..ab7f13177969 100644
--- a/sys/dev/gpio/gpiobus.c
+++ b/sys/dev/gpio/gpiobus.c
@@ -39,6 +39,7 @@
#include <sys/sbuf.h>
#include <dev/gpio/gpiobusvar.h>
+#include <dev/gpio/gpiobus_internal.h>
#include "gpiobus_if.h"
@@ -52,8 +53,6 @@
static void gpiobus_print_pins(struct gpiobus_ivar *, struct sbuf *);
static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int);
static int gpiobus_probe(device_t);
-static int gpiobus_attach(device_t);
-static int gpiobus_detach(device_t);
static int gpiobus_suspend(device_t);
static int gpiobus_resume(device_t);
static void gpiobus_probe_nomatch(device_t, device_t);
@@ -215,20 +214,40 @@ gpio_pin_is_active(gpio_pin_t pin, bool *active)
return (0);
}
+/*
+ * Note that this function should only
+ * be used in cases where a pre-existing
+ * gpiobus_pin structure exists. In most
+ * cases, the gpio_pin_get_by_* functions
+ * suffice.
+ */
+int
+gpio_pin_acquire(gpio_pin_t gpio)
+{
+ device_t busdev;
+
+ KASSERT(gpio != NULL, ("GPIO pin is NULL."));
+ KASSERT(gpio->dev != NULL, ("GPIO pin device is NULL."));
+
+ busdev = GPIO_GET_BUS(gpio->dev);
+ if (busdev == NULL)
+ return (ENXIO);
+
+ return (gpiobus_acquire_pin(busdev, gpio->pin));
+}
+
void
gpio_pin_release(gpio_pin_t gpio)
{
device_t busdev;
- if (gpio == NULL)
- return;
-
+ KASSERT(gpio != NULL, ("GPIO pin is NULL."));
KASSERT(gpio->dev != NULL, ("GPIO pin device is NULL."));
busdev = GPIO_GET_BUS(gpio->dev);
- if (busdev != NULL)
- gpiobus_release_pin(busdev, gpio->pin);
+ KASSERT(busdev != NULL, ("gpiobus dev is NULL."));
+ gpiobus_release_pin(busdev, gpio->pin);
free(gpio, M_DEVBUF);
}
@@ -295,38 +314,48 @@ gpiobus_print_pins(struct gpiobus_ivar *devi, struct sbuf *sb)
}
device_t
-gpiobus_attach_bus(device_t dev)
+gpiobus_add_bus(device_t dev)
{
device_t busdev;
- busdev = device_add_child(dev, "gpiobus", -1);
+ busdev = device_add_child(dev, "gpiobus", DEVICE_UNIT_ANY);
if (busdev == NULL)
return (NULL);
- if (device_add_child(dev, "gpioc", -1) == NULL) {
+ if (device_add_child(dev, "gpioc", DEVICE_UNIT_ANY) == NULL) {
device_delete_child(dev, busdev);
return (NULL);
}
#ifdef FDT
ofw_gpiobus_register_provider(dev);
#endif
- bus_generic_attach(dev);
+ return (busdev);
+}
+/*
+ * Attach a gpiobus child.
+ * Note that the controller is expected
+ * to be fully initialized at this point.
+ */
+device_t
+gpiobus_attach_bus(device_t dev)
+{
+ device_t busdev;
+
+ busdev = gpiobus_add_bus(dev);
+ if (busdev == NULL)
+ return (NULL);
+
+ bus_attach_children(dev);
return (busdev);
}
int
gpiobus_detach_bus(device_t dev)
{
- int err;
-
#ifdef FDT
ofw_gpiobus_unregister_provider(dev);
#endif
- err = bus_generic_detach(dev);
- if (err != 0)
- return (err);
-
- return (device_delete_children(dev));
+ return (bus_generic_detach(dev));
}
int
@@ -393,14 +422,13 @@ gpiobus_acquire_pin(device_t bus, uint32_t pin)
sc = device_get_softc(bus);
/* Consistency check. */
if (pin >= sc->sc_npins) {
- device_printf(bus,
- "invalid pin %d, max: %d\n", pin, sc->sc_npins - 1);
- return (-1);
+ panic("%s: invalid pin %d, max: %d",
+ device_get_nameunit(bus), pin, sc->sc_npins - 1);
}
/* Mark pin as mapped and give warning if it's already mapped. */
if (sc->sc_pins[pin].mapped) {
device_printf(bus, "warning: pin %d is already mapped\n", pin);
- return (-1);
+ return (EBUSY);
}
sc->sc_pins[pin].mapped = 1;
@@ -408,7 +436,7 @@ gpiobus_acquire_pin(device_t bus, uint32_t pin)
}
/* Release mapped pin */
-int
+void
gpiobus_release_pin(device_t bus, uint32_t pin)
{
struct gpiobus_softc *sc;
@@ -416,19 +444,15 @@ gpiobus_release_pin(device_t bus, uint32_t pin)
sc = device_get_softc(bus);
/* Consistency check. */
if (pin >= sc->sc_npins) {
- device_printf(bus,
- "invalid pin %d, max=%d\n",
- pin, sc->sc_npins - 1);
- return (-1);
+ panic("%s: invalid pin %d, max: %d",
+ device_get_nameunit(bus), pin, sc->sc_npins - 1);
}
- if (!sc->sc_pins[pin].mapped) {
- device_printf(bus, "pin %d is not mapped\n", pin);
- return (-1);
- }
- sc->sc_pins[pin].mapped = 0;
+ if (!sc->sc_pins[pin].mapped)
+ panic("%s: pin %d is not mapped", device_get_nameunit(bus),
+ pin);
- return (0);
+ sc->sc_pins[pin].mapped = 0;
}
static int
@@ -443,8 +467,7 @@ gpiobus_acquire_child_pins(device_t dev, device_t child)
device_printf(child, "cannot acquire pin %d\n",
devi->pins[i]);
while (--i >= 0) {
- (void)gpiobus_release_pin(dev,
- devi->pins[i]);
+ gpiobus_release_pin(dev, devi->pins[i]);
}
gpiobus_free_ivars(devi);
return (EBUSY);
@@ -550,7 +573,7 @@ gpiobus_probe(device_t dev)
return (BUS_PROBE_GENERIC);
}
-static int
+int
gpiobus_attach(device_t dev)
{
int err;
@@ -562,42 +585,31 @@ gpiobus_attach(device_t dev)
/*
* Get parent's pins and mark them as unmapped
*/
- bus_generic_probe(dev);
+ bus_identify_children(dev);
bus_enumerate_hinted_children(dev);
- return (bus_generic_attach(dev));
+ bus_attach_children(dev);
+ return (0);
}
/*
* Since this is not a self-enumerating bus, and since we always add
* children in attach, we have to always delete children here.
*/
-static int
+int
gpiobus_detach(device_t dev)
{
struct gpiobus_softc *sc;
- struct gpiobus_ivar *devi;
- device_t *devlist;
- int i, err, ndevs;
+ int i, err;
sc = GPIOBUS_SOFTC(dev);
KASSERT(mtx_initialized(&sc->sc_mtx),
("gpiobus mutex not initialized"));
GPIOBUS_LOCK_DESTROY(sc);
- if ((err = bus_generic_detach(dev)) != 0)
+ if ((err = bus_detach_children(dev)) != 0)
return (err);
- if ((err = device_get_children(dev, &devlist, &ndevs)) != 0)
- return (err);
- for (i = 0; i < ndevs; i++) {
- devi = GPIOBUS_IVAR(devlist[i]);
- gpiobus_free_ivars(devi);
- resource_list_free(&devi->rl);
- free(devi, M_DEVBUF);
- device_delete_child(dev, devlist[i]);
- }
- free(devlist, M_TEMP);
rman_fini(&sc->sc_intr_rman);
if (sc->sc_pins) {
for (i = 0; i < sc->sc_npins; i++) {
@@ -701,6 +713,19 @@ gpiobus_add_child(device_t dev, u_int order, const char *name, int unit)
return (child);
}
+static void
+gpiobus_child_deleted(device_t dev, device_t child)
+{
+ struct gpiobus_ivar *devi;
+
+ devi = GPIOBUS_IVAR(child);
+ if (devi == NULL)
+ return;
+ gpiobus_free_ivars(devi);
+ resource_list_free(&devi->rl);
+ free(devi, M_DEVBUF);
+}
+
static int
gpiobus_rescan(device_t dev)
{
@@ -712,7 +737,7 @@ gpiobus_rescan(device_t dev)
* hints or drivers have arrived since we last tried.
*/
bus_enumerate_hinted_children(dev);
- bus_generic_attach(dev);
+ bus_attach_children(dev);
return (0);
}
@@ -720,7 +745,6 @@ static void
gpiobus_hinted_child(device_t bus, const char *dname, int dunit)
{
struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus);
- struct gpiobus_ivar *devi;
device_t child;
const char *pins;
int irq, pinmask;
@@ -730,19 +754,14 @@ gpiobus_hinted_child(device_t bus, const char *dname, int dunit)
}
child = BUS_ADD_CHILD(bus, 0, dname, dunit);
- devi = GPIOBUS_IVAR(child);
if (resource_int_value(dname, dunit, "pins", &pinmask) == 0) {
if (gpiobus_parse_pins(sc, child, pinmask)) {
- resource_list_free(&devi->rl);
- free(devi, M_DEVBUF);
device_delete_child(bus, child);
return;
}
}
else if (resource_string_value(dname, dunit, "pin_list", &pins) == 0) {
if (gpiobus_parse_pin_list(sc, child, pins)) {
- resource_list_free(&devi->rl);
- free(devi, M_DEVBUF);
device_delete_child(bus, child);
return;
}
@@ -754,7 +773,7 @@ gpiobus_hinted_child(device_t bus, const char *dname, int dunit)
}
}
-static int
+int
gpiobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct gpiobus_ivar *devi;
@@ -1047,6 +1066,7 @@ static device_method_t gpiobus_methods[] = {
DEVMETHOD(bus_get_resource_list, gpiobus_get_resource_list),
DEVMETHOD(bus_get_rman, gpiobus_get_rman),
DEVMETHOD(bus_add_child, gpiobus_add_child),
+ DEVMETHOD(bus_child_deleted, gpiobus_child_deleted),
DEVMETHOD(bus_rescan, gpiobus_rescan),
DEVMETHOD(bus_probe_nomatch, gpiobus_probe_nomatch),
DEVMETHOD(bus_print_child, gpiobus_print_child),