Move most of the gpio_pin_* functions from ofw_gpiobus.c to gpiobus.c so

that they can be used by drivers on non-FDT-configured systems.  Only the
functions related to acquiring pins by parsing FDT data remain in
ofw_gpiobus.  Also, add two new functions for acquiring gpio pins based on
child device_t and index, or on the bus device_t and pin number.  And
finally, defer reserving pins for gpiobus children until they acquire the
pin, rather than reserving them as soon as the child is added (before it's
even known whether the child will attach).

This will allow drivers configured with hints (or any other mechanism) to
use the same code as drivers configured via FDT data.  Until now, a hinted
driver and an FDT driver had to be two completely different sets of code,
because hinted drivers could only use gpiobus calls to manipulate pins,
while fdt-configured drivers could not use that API (due to not always being
children of the bus that owns the pins) and had to use the newer
gpio_pin_xxxx() functions.  Now drivers can be written in the more
traditional form, where most of the code is shared and only the resource
acquisition code at attachment time changes.
This commit is contained in:
Ian Lepore 2019-12-01 21:27:09 +00:00
parent 3cf38784e2
commit 37045806ce
3 changed files with 127 additions and 84 deletions

View File

@ -77,6 +77,8 @@ static int gpiobus_pin_set(device_t, device_t, uint32_t, unsigned int);
static int gpiobus_pin_get(device_t, device_t, uint32_t, unsigned int*);
static int gpiobus_pin_toggle(device_t, device_t, uint32_t);
#define GPIO_ACTIVE_LOW 1 /* XXX Note that nothing currently sets this flag */
/*
* XXX -> Move me to better place - gpio_subr.c?
* Also, this function must be changed when interrupt configuration
@ -135,6 +137,114 @@ gpio_check_flags(uint32_t caps, uint32_t flags)
return (0);
}
int
gpio_pin_get_by_bus_pinnum(device_t busdev, uint32_t pinnum, gpio_pin_t *ppin)
{
gpio_pin_t pin;
int err;
err = gpiobus_acquire_pin(busdev, pinnum);
if (err != 0)
return (EBUSY);
pin = malloc(sizeof(*pin), M_DEVBUF, M_WAITOK | M_ZERO);
pin->dev = device_get_parent(busdev);
pin->pin = pinnum;
GPIO_PIN_GETFLAGS(pin->dev, pin->pin, &pin->flags);
*ppin = pin;
return (0);
}
int
gpio_pin_get_by_child_index(device_t childdev, uint32_t idx, gpio_pin_t *ppin)
{
struct gpiobus_ivar *devi;
devi = GPIOBUS_IVAR(childdev);
if (idx >= devi->npins)
return (EINVAL);
return (gpio_pin_get_by_bus_pinnum(device_get_parent(childdev),
devi->pins[idx], ppin));
}
int
gpio_pin_getcaps(gpio_pin_t pin, uint32_t *caps)
{
KASSERT(pin != NULL, ("GPIO pin is NULL."));
KASSERT(pin->dev != NULL, ("GPIO pin device is NULL."));
return (GPIO_PIN_GETCAPS(pin->dev, pin->pin, caps));
}
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);
}
if (pin->flags & GPIO_ACTIVE_LOW)
*active = tmp == 0;
else
*active = tmp != 0;
return (0);
}
void
gpio_pin_release(gpio_pin_t gpio)
{
device_t busdev;
if (gpio == NULL)
return;
KASSERT(gpio->dev != NULL, ("GPIO pin device is NULL."));
busdev = GPIO_GET_BUS(gpio->dev);
if (busdev != NULL)
gpiobus_release_pin(busdev, gpio->pin);
free(gpio, M_DEVBUF);
}
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);
}
static void
gpiobus_print_pins(struct gpiobus_ivar *devi, char *buf, size_t buflen)
{
@ -370,8 +480,6 @@ gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
devi->pins[npins++] = i;
}
if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0)
return (EINVAL);
return (0);
}
@ -425,8 +533,6 @@ gpiobus_parse_pin_list(struct gpiobus_softc *sc, device_t child,
p = endp + 1;
}
if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0)
return (EINVAL);
return (0);
}

View File

@ -141,7 +141,7 @@ 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. */
/* Acquire a pin by parsing FDT data. */
int gpio_pin_get_by_ofw_name(device_t consumer, phandle_t node,
char *name, gpio_pin_t *gpio);
int gpio_pin_get_by_ofw_idx(device_t consumer, phandle_t node,
@ -150,14 +150,29 @@ int gpio_pin_get_by_ofw_property(device_t consumer, phandle_t node,
char *name, gpio_pin_t *gpio);
int gpio_pin_get_by_ofw_propidx(device_t consumer, phandle_t node,
char *name, int idx, gpio_pin_t *gpio);
#endif /* FDT */
/* Acquire a pin by bus and pin number. */
int gpio_pin_get_by_bus_pinnum(device_t _bus, uint32_t _pinnum, gpio_pin_t *_gp);
/* Acquire a pin by child and index (used by direct children of gpiobus). */
int gpio_pin_get_by_child_index(device_t _child, uint32_t _idx, gpio_pin_t *_gp);
/* Release a pin acquired via any gpio_pin_get_xxx() function. */
void gpio_pin_release(gpio_pin_t gpio);
/* Work with gpio pins acquired using the functions above. */
int gpio_pin_getcaps(gpio_pin_t pin, uint32_t *caps);
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
struct resource *gpio_alloc_intr_resource(device_t consumer_dev, int *rid,
u_int alloc_flags, gpio_pin_t pin, uint32_t intr_mode);
/*
* Functions shared between gpiobus and other bus classes that derive from it;
* these should not be called directly by other drivers.
*/
int gpio_check_flags(uint32_t, uint32_t);
device_t gpiobus_attach_bus(device_t);
int gpiobus_detach_bus(device_t);

View File

@ -43,8 +43,6 @@ __FBSDID("$FreeBSD$");
#include "gpiobus_if.h"
#define GPIO_ACTIVE_LOW 1
static struct ofw_gpiobus_devinfo *ofw_gpiobus_setup_devinfo(device_t,
device_t, phandle_t);
static void ofw_gpiobus_destroy_devinfo(device_t, struct ofw_gpiobus_devinfo *);
@ -140,82 +138,6 @@ gpio_pin_get_by_ofw_name(device_t consumer, phandle_t node,
return (gpio_pin_get_by_ofw_idx(consumer, node, idx, pin));
}
void
gpio_pin_release(gpio_pin_t gpio)
{
device_t busdev;
if (gpio == NULL)
return;
KASSERT(gpio->dev != NULL, ("invalid pin state"));
busdev = GPIO_GET_BUS(gpio->dev);
if (busdev != NULL)
gpiobus_release_pin(busdev, gpio->pin);
/* XXXX Unreserve pin. */
free(gpio, M_DEVBUF);
}
int
gpio_pin_getcaps(gpio_pin_t pin, uint32_t *caps)
{
KASSERT(pin != NULL, ("GPIO pin is NULL."));
KASSERT(pin->dev != NULL, ("GPIO pin device is NULL."));
return (GPIO_PIN_GETCAPS(pin->dev, pin->pin, caps));
}
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);
}
if (pin->flags & GPIO_ACTIVE_LOW)
*active = tmp == 0;
else
*active = tmp != 0;
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.
*/