Initial GPIO bus support. Includes:

- GPIO bus controller interface
  - GPIO bus interface
  - Implementation of GPIO led(4) compatible device
  - Implementation of iic(4) bus over GPIO (author: Luiz Otavio O Souza)

Tested by: Luiz Otavio O Souza, Alexandr Rybalko
This commit is contained in:
Oleksandr Tymoshenko 2010-09-28 03:24:53 +00:00
parent 25e45560da
commit 6b34b16ea5
9 changed files with 1437 additions and 0 deletions

View File

@ -1010,6 +1010,14 @@ dev/fxp/if_fxp.c optional fxp inet
dev/gem/if_gem.c optional gem
dev/gem/if_gem_pci.c optional gem pci
dev/gem/if_gem_sbus.c optional gem sbus
dev/gpio/gpiobus.c optional gpio \
dependency "gpiobus_if.h"
dev/gpio/gpioc.c optional gpio \
dependency "gpio_if.h"
dev/gpio/gpioiic.c optional gpioiic
dev/gpio/gpioled.c optional gpioled
dev/gpio/gpio_if.m optional gpio
dev/gpio/gpiobus_if.m optional gpio
dev/hatm/if_hatm.c optional hatm pci
dev/hatm/if_hatm_intr.c optional hatm pci
dev/hatm/if_hatm_ioctl.c optional hatm pci

102
sys/dev/gpio/gpio_if.m Normal file
View File

@ -0,0 +1,102 @@
#-
# Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
#include <sys/bus.h>
#include <sys/gpio.h>
INTERFACE gpio;
#
# Get total number of pins
#
METHOD int pin_max {
device_t dev;
int *npins;
};
#
# Set value of pin specifed by pin_num
#
METHOD int pin_set {
device_t dev;
uint32_t pin_num;
uint32_t pin_value;
};
#
# Get value of pin specifed by pin_num
#
METHOD int pin_get {
device_t dev;
uint32_t pin_num;
uint32_t *pin_value;
};
#
# Toggle value of pin specifed by pin_num
#
METHOD int pin_toggle {
device_t dev;
uint32_t pin_num;
};
#
# Get pin capabilities
#
METHOD int pin_getcaps {
device_t dev;
uint32_t pin_num;
uint32_t *caps;
};
#
# Get pin flags
#
METHOD int pin_getflags {
device_t dev;
uint32_t pin_num;
uint32_t *flags;
};
#
# Get pin name
#
METHOD int pin_getname {
device_t dev;
uint32_t pin_num;
char *name;
};
#
# Set current configuration and capabilities
#
METHOD int pin_setflags {
device_t dev;
uint32_t pin_num;
uint32_t flags;
};

492
sys/dev/gpio/gpiobus.c Normal file
View File

@ -0,0 +1,492 @@
/*-
* Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <sys/gpio.h>
#include <dev/gpio/gpiobusvar.h>
#include "gpio_if.h"
#include "gpiobus_if.h"
static void gpiobus_print_pins(struct gpiobus_ivar *);
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 int gpiobus_print_child(device_t, device_t);
static int gpiobus_child_location_str(device_t, device_t, char *, size_t);
static int gpiobus_child_pnpinfo_str(device_t, device_t, char *, size_t);
static device_t gpiobus_add_child(device_t, u_int, const char *, int);
static void gpiobus_hinted_child(device_t, const char *, int);
/*
* GPIOBUS interface
*/
static void gpiobus_lock_bus(device_t);
static void gpiobus_unlock_bus(device_t);
static void gpiobus_acquire_bus(device_t, device_t);
static void gpiobus_release_bus(device_t, device_t);
static int gpiobus_pin_setflags(device_t, device_t, uint32_t, uint32_t);
static int gpiobus_pin_getflags(device_t, device_t, uint32_t, uint32_t*);
static int gpiobus_pin_getcaps(device_t, device_t, uint32_t, uint32_t*);
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 GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define GPIOBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define GPIOBUS_LOCK_INIT(_sc) \
mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
"gpiobus", MTX_DEF)
#define GPIOBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
#define GPIOBUS_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
#define GPIOBUS_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
static void
gpiobus_print_pins(struct gpiobus_ivar *devi)
{
int range_start, range_stop, need_coma;
int i;
if (devi->npins == 0)
return;
need_coma = 0;
range_start = range_stop = devi->pins[0];
for (i = 1; i < devi->npins; i++) {
if (devi->pins[i] != (range_stop + 1)) {
if (need_coma)
printf(",");
if (range_start != range_stop)
printf("%d-%d", range_start, range_stop);
else
printf("%d", range_start);
range_start = range_stop = devi->pins[i];
need_coma = 1;
}
else
range_stop++;
}
if (need_coma)
printf(",");
if (range_start != range_stop)
printf("%d-%d", range_start, range_stop);
else
printf("%d", range_start);
}
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");
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);
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);
return (EINVAL);
}
sc->sc_pins_mapped[i] = 1;
}
return (0);
}
static int
gpiobus_probe(device_t dev)
{
device_set_desc(dev, "GPIO bus");
return (0);
}
static int
gpiobus_attach(device_t dev)
{
struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
int res;
sc->sc_busdev = dev;
sc->sc_dev = device_get_parent(dev);
res = GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins);
if (res)
return (ENXIO);
/*
* Increase to get number of pins
*/
sc->sc_npins++;
KASSERT(sc->sc_npins != 0, ("GPIO device with no pins"));
sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF,
M_NOWAIT | M_ZERO);
if (!sc->sc_pins_mapped)
return (ENOMEM);
/* init bus lock */
GPIOBUS_LOCK_INIT(sc);
/*
* Get parent's pins and mark them as unmapped
*/
bus_enumerate_hinted_children(dev);
return (bus_generic_attach(dev));
}
/*
* 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 = GPIOBUS_SOFTC(dev);
int err, ndevs, i;
device_t *devlist;
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]);
if (sc->sc_pins_mapped) {
free(sc->sc_pins_mapped, M_DEVBUF);
sc->sc_pins_mapped = NULL;
}
free(devlist, M_TEMP);
return (0);
}
static int
gpiobus_suspend(device_t dev)
{
return (bus_generic_suspend(dev));
}
static int
gpiobus_resume(device_t dev)
{
return (bus_generic_resume(dev));
}
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 int
gpiobus_child_location_str(device_t bus, device_t child, char *buf,
size_t buflen)
{
// struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
snprintf(buf, buflen, "pins=?");
return (0);
}
static int
gpiobus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
size_t buflen)
{
*buf = '\0';
return (0);
}
static device_t
gpiobus_add_child(device_t dev, u_int order, const char *name, int unit)
{
device_t child;
struct gpiobus_ivar *devi;
child = device_add_child_ordered(dev, order, name, unit);
if (child == NULL)
return (child);
devi = malloc(sizeof(struct gpiobus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
if (devi == NULL) {
device_delete_child(dev, child);
return (0);
}
device_set_ivars(child, devi);
return (child);
}
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 void
gpiobus_lock_bus(device_t busdev)
{
struct gpiobus_softc *sc;
sc = device_get_softc(busdev);
GPIOBUS_ASSERT_UNLOCKED(sc);
GPIOBUS_LOCK(sc);
}
static void
gpiobus_unlock_bus(device_t busdev)
{
struct gpiobus_softc *sc;
sc = device_get_softc(busdev);
GPIOBUS_ASSERT_LOCKED(sc);
GPIOBUS_UNLOCK(sc);
}
static void
gpiobus_acquire_bus(device_t busdev, device_t child)
{
struct gpiobus_softc *sc;
sc = device_get_softc(busdev);
GPIOBUS_ASSERT_LOCKED(sc);
if (sc->sc_owner)
panic("rb_cpldbus: cannot serialize the access to device.");
sc->sc_owner = child;
}
static void
gpiobus_release_bus(device_t busdev, device_t child)
{
struct gpiobus_softc *sc;
sc = device_get_softc(busdev);
GPIOBUS_ASSERT_LOCKED(sc);
if (!sc->sc_owner)
panic("rb_cpldbus: releasing unowned bus.");
if (sc->sc_owner != child)
panic("rb_cpldbus: you don't own the bus. game over.");
sc->sc_owner = NULL;
}
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_pin_getflags(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_GETFLAGS(sc->sc_dev, devi->pins[pin], flags);
}
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_set(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_SET(sc->sc_dev, devi->pins[pin], value);
}
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_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 device_method_t gpiobus_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, gpiobus_probe),
DEVMETHOD(device_attach, gpiobus_attach),
DEVMETHOD(device_detach, gpiobus_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, gpiobus_suspend),
DEVMETHOD(device_resume, gpiobus_resume),
/* Bus interface */
DEVMETHOD(bus_add_child, gpiobus_add_child),
DEVMETHOD(bus_print_child, gpiobus_print_child),
DEVMETHOD(bus_driver_added, bus_generic_driver_added),
DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str),
DEVMETHOD(bus_child_location_str, gpiobus_child_location_str),
DEVMETHOD(bus_hinted_child, gpiobus_hinted_child),
/* GPIO protocol */
DEVMETHOD(gpiobus_lock_bus, gpiobus_lock_bus),
DEVMETHOD(gpiobus_unlock_bus, gpiobus_unlock_bus),
DEVMETHOD(gpiobus_acquire_bus, gpiobus_acquire_bus),
DEVMETHOD(gpiobus_release_bus, gpiobus_release_bus),
DEVMETHOD(gpiobus_pin_getflags, gpiobus_pin_getflags),
DEVMETHOD(gpiobus_pin_getcaps, gpiobus_pin_getcaps),
DEVMETHOD(gpiobus_pin_setflags, gpiobus_pin_setflags),
DEVMETHOD(gpiobus_pin_get, gpiobus_pin_get),
DEVMETHOD(gpiobus_pin_set, gpiobus_pin_set),
DEVMETHOD(gpiobus_pin_toggle, gpiobus_pin_toggle),
{ 0, 0 }
};
static driver_t gpiobus_driver = {
"gpiobus",
gpiobus_methods,
sizeof(struct gpiobus_softc)
};
devclass_t gpiobus_devclass;
DRIVER_MODULE(gpiobus, gpio, gpiobus_driver, gpiobus_devclass, 0, 0);
MODULE_VERSION(gpiobus, 1);

121
sys/dev/gpio/gpiobus_if.m Normal file
View File

@ -0,0 +1,121 @@
#-
# Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
#include <sys/bus.h>
#include <sys/gpio.h>
INTERFACE gpiobus;
#
# Lock the gpio bus
#
METHOD void lock_bus {
device_t busdev;
};
#
# Unlock the gpio bus
#
METHOD void unlock_bus {
device_t busdev;
};
#
# Dedicate the gpio bus control for a child
#
METHOD void acquire_bus {
device_t busdev;
device_t dev;
};
#
# Release the bus
#
METHOD void release_bus {
device_t busdev;
device_t dev;
};
#
# Set value of pin specifed by pin_num
#
METHOD int pin_set {
device_t dev;
device_t child;
uint32_t pin_num;
uint32_t pin_value;
};
#
# Get value of pin specifed by pin_num
#
METHOD int pin_get {
device_t dev;
device_t child;
uint32_t pin_num;
uint32_t *pin_value;
};
#
# Toggle value of pin specifed by pin_num
#
METHOD int pin_toggle {
device_t dev;
device_t child;
uint32_t pin_num;
};
#
# Get pin capabilities
#
METHOD int pin_getcaps {
device_t dev;
device_t child;
uint32_t pin_num;
uint32_t *caps;
};
#
# Get pin flags
#
METHOD int pin_getflags {
device_t dev;
device_t child;
uint32_t pin_num;
uint32_t *flags;
};
#
# Set current configuration and capabilities
#
METHOD int pin_setflags {
device_t dev;
device_t child;
uint32_t pin_num;
uint32_t flags;
};

56
sys/dev/gpio/gpiobusvar.h Normal file
View File

@ -0,0 +1,56 @@
/*-
* Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*
*/
#ifndef __GPIOBUS_H__
#define __GPIOBUS_H__
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#define GPIOBUS_IVAR(d) (struct gpiobus_ivar *) device_get_ivars(d)
#define GPIOBUS_SOFTC(d) (struct gpiobus_softc *) device_get_softc(d)
struct gpiobus_softc
{
struct mtx sc_mtx; /* bus mutex */
device_t sc_busdev; /* bus device */
device_t sc_owner; /* bus owner */
device_t sc_dev; /* driver device */
int sc_npins; /* total pins on bus */
int *sc_pins_mapped; /* mark mapped pins */
};
struct gpiobus_ivar
{
uint32_t npins; /* pins total */
uint32_t *pins; /* pins map */
};
#endif /* __GPIOBUS_H__ */

174
sys/dev/gpio/gpioc.c Normal file
View File

@ -0,0 +1,174 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/ioccom.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/queue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/gpio.h>
#include "gpio_if.h"
#undef GPIOC_DEBUG
#ifdef GPIOC_DEBUG
#define dprintf printf
#else
#define dprintf(x, arg...)
#endif
static int gpioc_probe(device_t dev);
static int gpioc_attach(device_t dev);
static int gpioc_detach(device_t dev);
static d_ioctl_t gpioc_ioctl;
static struct cdevsw gpioc_cdevsw = {
.d_version = D_VERSION,
.d_ioctl = gpioc_ioctl,
.d_name = "gpioc",
#if __FreeBSD_version >= 800039
.d_flags = D_PSEUDO | D_NEEDMINOR
#endif
};
struct gpioc_softc {
device_t sc_dev; /* gpiocX dev */
device_t sc_pdev; /* gpioX dev */
struct cdev *sc_ctl_dev; /* controller device */
int sc_unit;
};
static int
gpioc_probe(device_t dev)
{
device_set_desc(dev, "GPIO controller");
return (0);
}
static int
gpioc_attach(device_t dev)
{
struct gpioc_softc *sc = device_get_softc(dev);
sc->sc_dev = dev;
sc->sc_pdev = device_get_parent(dev);
sc->sc_unit = device_get_unit(dev);
sc->sc_ctl_dev = make_dev(&gpioc_cdevsw, sc->sc_unit,
UID_ROOT, GID_WHEEL, 0600, "gpioc%d", sc->sc_unit);
if (!sc->sc_ctl_dev) {
printf("Failed to create gpioc%d", sc->sc_unit);
return (ENXIO);
}
sc->sc_ctl_dev->si_drv1 = sc;
return (0);
}
static int
gpioc_detach(device_t dev)
{
struct gpioc_softc *sc = device_get_softc(dev);
int err;
if (sc->sc_ctl_dev);
destroy_dev(sc->sc_ctl_dev);
if ((err = bus_generic_detach(dev)) != 0)
return (err);
return (0);
}
static int
gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
struct thread *td)
{
int max_pin, res;
struct gpioc_softc *sc = cdev->si_drv1;
struct gpio_pin pin;
struct gpio_req req;
switch (cmd) {
case GPIOMAXPIN:
max_pin = -1;
res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin);
bcopy(&max_pin, arg, sizeof(max_pin));
break;
case GPIOGETCONFIG:
bcopy(arg, &pin, sizeof(pin));
dprintf("get config pin %d\n", pin.gp_pin);
res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin,
&pin.gp_flags);
/* Fail early */
if (res)
break;
GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps);
GPIO_PIN_GETNAME(sc->sc_pdev, pin.gp_pin, pin.gp_name);
bcopy(&pin, arg, sizeof(pin));
break;
case GPIOSETCONFIG:
bcopy(arg, &pin, sizeof(pin));
dprintf("set config pin %d\n", pin.gp_pin);
res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin,
pin.gp_flags);
break;
case GPIOGET:
bcopy(arg, &req, sizeof(req));
res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin,
&req.gp_value);
dprintf("read pin %d -> %d\n",
req.gp_pin, req.gp_value);
bcopy(&req, arg, sizeof(req));
break;
case GPIOSET:
bcopy(arg, &req, sizeof(req));
res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin,
req.gp_value);
dprintf("write pin %d -> %d\n",
req.gp_pin, req.gp_value);
break;
case GPIOTOGGLE:
bcopy(arg, &req, sizeof(req));
dprintf("toggle pin %d\n",
req.gp_pin);
res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin);
break;
default:
return (ENOTTY);
break;
}
return (res);
}
static device_method_t gpioc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, gpioc_probe),
DEVMETHOD(device_attach, gpioc_attach),
DEVMETHOD(device_detach, gpioc_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
{ 0, 0 }
};
static driver_t gpioc_driver = {
"gpioc",
gpioc_methods,
sizeof(struct gpioc_softc)
};
devclass_t gpioc_devclass;
DRIVER_MODULE(gpioc, gpio, gpioc_driver, gpioc_devclass, 0, 0);
MODULE_VERSION(gpioc, 1);

245
sys/dev/gpio/gpioiic.c Normal file
View File

@ -0,0 +1,245 @@
/*-
* Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
* Copyright (c) 2010 Luiz Otavio O Souza
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/gpio.h>
#include "gpiobus_if.h"
#include <dev/iicbus/iiconf.h>
#include <dev/iicbus/iicbus.h>
#include "iicbb_if.h"
#define SCL_PIN 0 /* gpiobus mapped pin 6 */
#define SDA_PIN 1 /* gpiobus mapped pin 7 */
struct gpioiic_softc
{
device_t sc_dev;
device_t sc_busdev;
struct mtx sc_mtx;
struct cdev *sc_leddev;
};
static int gpioiic_probe(device_t);
static int gpioiic_attach(device_t);
/* iicbb interface */
static void gpioiic_reset_bus(device_t);
static int gpioiic_callback(device_t, int, caddr_t);
static void gpioiic_setsda(device_t, int);
static void gpioiic_setscl(device_t, int);
static int gpioiic_getsda(device_t);
static int gpioiic_getscl(device_t);
static int gpioiic_reset(device_t, u_char, u_char, u_char *);
static int
gpioiic_probe(device_t dev)
{
device_set_desc(dev, "GPIO I2C bit-banging driver");
return (0);
}
static int
gpioiic_attach(device_t dev)
{
struct gpioiic_softc *sc = device_get_softc(dev);
device_t bitbang;
sc->sc_dev = dev;
sc->sc_busdev = device_get_parent(dev);
/* add generic bit-banging code */
bitbang = device_add_child(dev, "iicbb", -1);
device_probe_and_attach(bitbang);
return (0);
}
/*
* Reset bus by setting SDA first and then SCL.
* Must always be called with gpio bus locked.
*/
static void
gpioiic_reset_bus(device_t dev)
{
struct gpioiic_softc *sc = device_get_softc(dev);
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
GPIO_PIN_INPUT);
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
GPIO_PIN_INPUT);
}
static int
gpioiic_callback(device_t dev, int index, caddr_t data)
{
struct gpioiic_softc *sc = device_get_softc(dev);
int error = 0;
switch (index) {
case IIC_REQUEST_BUS:
GPIOBUS_LOCK_BUS(sc->sc_busdev);
GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
break;
case IIC_RELEASE_BUS:
GPIOBUS_LOCK_BUS(sc->sc_busdev);
GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
break;
default:
error = EINVAL;
}
return(error);
}
static void
gpioiic_setsda(device_t dev, int val)
{
struct gpioiic_softc *sc = device_get_softc(dev);
GPIOBUS_LOCK_BUS(sc->sc_busdev);
if (val == 0) {
GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, SDA_PIN, 0);
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
GPIO_PIN_OUTPUT);
} else {
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
GPIO_PIN_INPUT);
}
GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
}
static void
gpioiic_setscl(device_t dev, int val)
{
struct gpioiic_softc *sc = device_get_softc(dev);
GPIOBUS_LOCK_BUS(sc->sc_busdev);
if (val == 0) {
GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, SCL_PIN, 0);
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
GPIO_PIN_OUTPUT);
} else {
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
GPIO_PIN_INPUT);
}
GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
}
static int
gpioiic_getscl(device_t dev)
{
struct gpioiic_softc *sc = device_get_softc(dev);
unsigned int val;
GPIOBUS_LOCK_BUS(sc->sc_busdev);
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
GPIO_PIN_INPUT);
GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, SCL_PIN, &val);
GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
return ((int)val);
}
static int
gpioiic_getsda(device_t dev)
{
struct gpioiic_softc *sc = device_get_softc(dev);
unsigned int val;
GPIOBUS_LOCK_BUS(sc->sc_busdev);
GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
GPIO_PIN_INPUT);
GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, SDA_PIN, &val);
GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
return ((int)val);
}
static int
gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
{
struct gpioiic_softc *sc = device_get_softc(dev);
GPIOBUS_LOCK_BUS(sc->sc_busdev);
GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
gpioiic_reset_bus(sc->sc_dev);
GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
return (IIC_ENOADDR);
}
static devclass_t gpioiic_devclass;
static device_method_t gpioiic_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, gpioiic_probe),
DEVMETHOD(device_attach, gpioiic_attach),
DEVMETHOD(device_detach, bus_generic_detach),
/* iicbb interface */
DEVMETHOD(iicbb_callback, gpioiic_callback),
DEVMETHOD(iicbb_setsda, gpioiic_setsda),
DEVMETHOD(iicbb_setscl, gpioiic_setscl),
DEVMETHOD(iicbb_getsda, gpioiic_getsda),
DEVMETHOD(iicbb_getscl, gpioiic_getscl),
DEVMETHOD(iicbb_reset, gpioiic_reset),
{ 0, 0 }
};
static driver_t gpioiic_driver = {
"gpioiic",
gpioiic_methods,
sizeof(struct gpioiic_softc),
};
DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0);
DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0);
MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1);

142
sys/dev/gpio/gpioled.c Normal file
View File

@ -0,0 +1,142 @@
/*-
* Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <dev/led/led.h>
#include <sys/gpio.h>
#include "gpiobus_if.h"
/*
* Only one pin for led
*/
#define GPIOLED_PIN 0
#define GPIOLED_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define GPIOLED_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define GPIOLED_LOCK_INIT(_sc) \
mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
"gpioled", MTX_DEF)
#define GPIOLED_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
struct gpioled_softc
{
device_t sc_dev;
device_t sc_busdev;
struct mtx sc_mtx;
struct cdev *sc_leddev;
};
static void gpioled_control(void *, int);
static int gpioled_probe(device_t);
static int gpioled_attach(device_t);
static int gpioled_detach(device_t);
static void
gpioled_control(void *priv, int onoff)
{
struct gpioled_softc *sc = priv;
GPIOLED_LOCK(sc);
GPIOBUS_LOCK_BUS(sc->sc_busdev);
GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
onoff ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
GPIOLED_UNLOCK(sc);
}
static int
gpioled_probe(device_t dev)
{
device_set_desc(dev, "GPIO led");
return (0);
}
static int
gpioled_attach(device_t dev)
{
struct gpioled_softc *sc;
const char *name;
sc = device_get_softc(dev);
sc->sc_dev = dev;
sc->sc_busdev = device_get_parent(dev);
GPIOLED_LOCK_INIT(sc);
if (resource_string_value(device_get_name(dev),
device_get_unit(dev), "name", &name))
name = NULL;
sc->sc_leddev = led_create(gpioled_control, sc, name ? name :
device_get_nameunit(dev));
return (0);
}
static int
gpioled_detach(device_t dev)
{
struct gpioled_softc *sc;
sc = device_get_softc(dev);
if (sc->sc_leddev) {
led_destroy(sc->sc_leddev);
sc->sc_leddev = NULL;
}
GPIOLED_LOCK_DESTROY(sc);
return (0);
}
static devclass_t gpioled_devclass;
static device_method_t gpioled_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, gpioled_probe),
DEVMETHOD(device_attach, gpioled_attach),
DEVMETHOD(device_detach, gpioled_detach),
{ 0, 0 }
};
static driver_t gpioled_driver = {
"gpioled",
gpioled_methods,
sizeof(struct gpioled_softc),
};
DRIVER_MODULE(gpioled, gpiobus, gpioled_driver, gpioled_devclass, 0, 0);

97
sys/sys/gpio.h Normal file
View File

@ -0,0 +1,97 @@
/* $NetBSD: gpio.h,v 1.7 2009/09/25 20:27:50 mbalmer Exp $ */
/* $OpenBSD: gpio.h,v 1.7 2008/11/26 14:51:20 mbalmer Exp $ */
/*-
* Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*
*/
/*
* Copyright (c) 2009 Marc Balmer <marc@msys.ch>
* Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __GPIO_H__
#define __GPIO_H__
#include <sys/ioccom.h>
/* GPIO pin states */
#define GPIO_PIN_LOW 0x00 /* low level (logical 0) */
#define GPIO_PIN_HIGH 0x01 /* high level (logical 1) */
/* Max name length of a pin */
#define GPIOMAXNAME 64
/* GPIO pin configuration flags */
#define GPIO_PIN_INPUT 0x0001 /* input direction */
#define GPIO_PIN_OUTPUT 0x0002 /* output direction */
#define GPIO_PIN_OPENDRAIN 0x0004 /* open-drain output */
#define GPIO_PIN_PUSHPULL 0x0008 /* push-pull output */
#define GPIO_PIN_TRISTATE 0x0010 /* output disabled */
#define GPIO_PIN_PULLUP 0x0020 /* internal pull-up enabled */
#define GPIO_PIN_PULLDOWN 0x0040 /* internal pull-down enabled */
#define GPIO_PIN_INVIN 0x0080 /* invert input */
#define GPIO_PIN_INVOUT 0x0100 /* invert output */
#define GPIO_PIN_PULSATE 0x0200 /* pulsate in hardware */
struct gpio_pin {
uint32_t gp_pin; /* pin number */
char gp_name[GPIOMAXNAME]; /* human-readable name */
uint32_t gp_caps; /* capabilities */
uint32_t gp_flags; /* current flags */
};
/* GPIO pin request (read/write/toggle) */
struct gpio_req {
uint32_t gp_pin; /* pin number */
uint32_t gp_value; /* value */
};
/*
* ioctls
*/
#define GPIOMAXPIN _IOR('G', 0, int)
#define GPIOGETCONFIG _IOWR('G', 1, struct gpio_pin)
#define GPIOSETCONFIG _IOW('G', 2, struct gpio_pin)
#define GPIOGET _IOWR('G', 3, struct gpio_req)
#define GPIOSET _IOW('G', 4, struct gpio_req)
#define GPIOTOGGLE _IOWR('G', 5, struct gpio_req)
#endif /* __GPIO_H__ */