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:
parent
3cf38784e2
commit
37045806ce
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user