OFW_GPIOBUS: Add utility functions for easier handling of OFW GPIO pins.
Reviewed by: ian, loos (paritaly)
This commit is contained in:
parent
064094126c
commit
8a4ba03859
@ -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(device_t, const char *, phandle_t);
|
||||
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);
|
||||
|
@ -47,6 +47,166 @@ static void ofw_gpiobus_destroy_devinfo(device_t, struct ofw_gpiobus_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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user