/* * 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 gpiobus_detach(device_t dev) { struct gpiobus_softc *sc; struct gpiobus_ivar *devi; device_t *devlist; int i, err, ndevs; 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) return (err); if ((err = device_get_children(dev, &devlist, &ndevs)) != 0) return (err); for (i = 0; i < ndevs; i++) { device_delete_child(dev, devlist[i]); devi = GPIOBUS_IVAR(devlist[i]); if (devi->pins) { free(devi->pins, M_DEVBUF); devi->pins = NULL; } } free(devlist, M_TEMP); if (sc->sc_pins_mapped) { free(sc->sc_pins_mapped, M_DEVBUF); sc->sc_pins_mapped = NULL; } return (0); }
static struct resource_list * gpiobus_get_resource_list(device_t bus __unused, device_t child) { struct gpiobus_ivar *ivar; ivar = GPIOBUS_IVAR(child); return (&ivar->rl); }
static int gpiobus_pin_toggle(device_t dev, device_t child, uint32_t pin) { struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); if (pin >= devi->npins) return (EINVAL); return GPIO_PIN_TOGGLE(sc->sc_dev, devi->pins[pin]); }
static int gpiobus_pin_getcaps(device_t dev, device_t child, uint32_t pin, uint32_t *caps) { struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); if (pin >= devi->npins) return (EINVAL); return GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], caps); }
static int gpiobus_pin_get(device_t dev, device_t child, uint32_t pin, unsigned int *value) { struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); if (pin >= devi->npins) return (EINVAL); return GPIO_PIN_GET(sc->sc_dev, devi->pins[pin], value); }
static int gpiobus_child_location_str(device_t bus, device_t child, char *buf, size_t buflen) { struct gpiobus_ivar *devi; devi = GPIOBUS_IVAR(child); strlcpy(buf, "pin(s)=", buflen); gpiobus_print_pins(devi, buf, buflen); return (0); }
static int gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, uint32_t flags) { struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); if (pin >= devi->npins) return (EINVAL); return GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags); }
static int gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) { struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); int i, npins; npins = 0; for (i = 0; i < 32; i++) { if (mask & (1 << i)) npins++; } if (npins == 0) { device_printf(child, "empty pin mask\n"); return (EINVAL); } devi->npins = npins; devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, M_NOWAIT | M_ZERO); if (!devi->pins) return (ENOMEM); npins = 0; for (i = 0; i < 32; i++) { if ((mask & (1 << i)) == 0) continue; if (i >= sc->sc_npins) { device_printf(child, "invalid pin %d, max: %d\n", i, sc->sc_npins - 1); free(devi->pins, M_DEVBUF); return (EINVAL); } devi->pins[npins++] = i; /* * Mark pin as mapped and give warning if it's already mapped */ if (sc->sc_pins_mapped[i]) { device_printf(child, "warning: pin %d is already mapped\n", i); free(devi->pins, M_DEVBUF); return (EINVAL); } sc->sc_pins_mapped[i] = 1; } return (0); }
static int gpiobus_print_child(device_t dev, device_t child) { struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); int retval = 0; retval += bus_print_child_header(dev, child); retval += printf(" at pin(s) "); gpiobus_print_pins(devi); retval += bus_print_child_footer(dev, child); return (retval); }
static void gpiobus_probe_nomatch(device_t dev, device_t child) { char pins[128]; struct gpiobus_ivar *devi; devi = GPIOBUS_IVAR(child); memset(pins, 0, sizeof(pins)); gpiobus_print_pins(devi, pins, sizeof(pins)); device_printf(dev, "<unknown device> at pin(s) %s", pins); resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld"); printf("\n"); }
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; int pins; child = BUS_ADD_CHILD(bus, 0, dname, dunit); devi = GPIOBUS_IVAR(child); resource_int_value(dname, dunit, "pins", &pins); if (gpiobus_parse_pins(sc, child, pins)) device_delete_child(bus, child); }
static int gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, uint32_t flags) { struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); uint32_t caps; if (pin >= devi->npins) return (EINVAL); if (GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], &caps) != 0) return (EINVAL); if (gpio_check_flags(caps, flags) != 0) return (EINVAL); return (GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags)); }
static int gpiobus_set_resource(device_t dev, device_t child, int type, int rid, u_long start, u_long count) { struct gpiobus_ivar *devi; struct resource_list_entry *rle; dprintf("%s: entry (%p, %p, %d, %d, %p, %ld)\n", __func__, dev, child, type, rid, (void *)(intptr_t)start, count); devi = GPIOBUS_IVAR(child); rle = resource_list_add(&devi->rl, type, rid, start, start + count - 1, count); if (rle == NULL) return (ENXIO); return (0); }
static int gpioiic_attach(device_t dev) { device_t bitbang; #ifdef FDT phandle_t node; pcell_t pin; #endif struct gpiobus_ivar *devi; struct gpioiic_softc *sc; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_busdev = device_get_parent(dev); if (resource_int_value(device_get_name(dev), device_get_unit(dev), "scl", &sc->scl_pin)) sc->scl_pin = SCL_PIN_DEFAULT; if (resource_int_value(device_get_name(dev), device_get_unit(dev), "sda", &sc->sda_pin)) sc->sda_pin = SDA_PIN_DEFAULT; #ifdef FDT if ((node = ofw_bus_get_node(dev)) == -1) return (ENXIO); if (OF_getencprop(node, "scl", &pin, sizeof(pin)) > 0) sc->scl_pin = (int)pin; if (OF_getencprop(node, "sda", &pin, sizeof(pin)) > 0) sc->sda_pin = (int)pin; #endif if (sc->scl_pin < 0 || sc->scl_pin > 1) sc->scl_pin = SCL_PIN_DEFAULT; if (sc->sda_pin < 0 || sc->sda_pin > 1) sc->sda_pin = SDA_PIN_DEFAULT; devi = GPIOBUS_IVAR(dev); device_printf(dev, "SCL pin: %d, SDA pin: %d\n", devi->pins[sc->scl_pin], devi->pins[sc->sda_pin]); /* add generic bit-banging code */ bitbang = device_add_child(dev, "iicbb", -1); device_probe_and_attach(bitbang); return (0); }
static int gpiobus_print_child(device_t dev, device_t child) { char pins[128]; int retval = 0; struct gpiobus_ivar *devi; devi = GPIOBUS_IVAR(child); memset(pins, 0, sizeof(pins)); retval += bus_print_child_header(dev, child); retval += printf(" at pin(s) "); gpiobus_print_pins(devi, pins, sizeof(pins)); retval += printf("%s", pins); resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld"); retval += bus_print_child_footer(dev, child); return (retval); }
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; int irq, pins; child = BUS_ADD_CHILD(bus, 0, dname, dunit); devi = GPIOBUS_IVAR(child); resource_int_value(dname, dunit, "pins", &pins); if (gpiobus_parse_pins(sc, child, pins)) device_delete_child(bus, child); if (resource_int_value(dname, dunit, "irq", &irq) == 0) { if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); } }
/* * 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 gpiobus_detach(device_t dev) { struct gpiobus_softc *sc; struct gpiobus_ivar *devi; device_t *devlist; int i, err, ndevs; 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) 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++) { if (sc->sc_pins[i].name != NULL) free(sc->sc_pins[i].name, M_DEVBUF); sc->sc_pins[i].name = NULL; } free(sc->sc_pins, M_DEVBUF); sc->sc_pins = NULL; } return (0); }
static int gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) { struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); int i, npins; npins = 0; for (i = 0; i < 32; i++) { if (mask & (1 << i)) npins++; } if (npins == 0) { device_printf(child, "empty pin mask\n"); return (EINVAL); } devi->npins = npins; if (gpiobus_alloc_ivars(devi) != 0) { device_printf(child, "cannot allocate device ivars\n"); return (EINVAL); } npins = 0; for (i = 0; i < 32; i++) { if ((mask & (1 << i)) == 0) continue; /* Reserve the GPIO pin. */ if (gpiobus_map_pin(sc->sc_busdev, i) != 0) { gpiobus_free_ivars(devi); return (EINVAL); } devi->pins[npins++] = i; /* Use the child name as pin name. */ GPIOBUS_PIN_SETNAME(sc->sc_busdev, i, device_get_nameunit(child)); } return (0); }