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:
parent
25e45560da
commit
6b34b16ea5
@ -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
102
sys/dev/gpio/gpio_if.m
Normal 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
492
sys/dev/gpio/gpiobus.c
Normal 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
121
sys/dev/gpio/gpiobus_if.m
Normal 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
56
sys/dev/gpio/gpiobusvar.h
Normal 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
174
sys/dev/gpio/gpioc.c
Normal 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
245
sys/dev/gpio/gpioiic.c
Normal 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
142
sys/dev/gpio/gpioled.c
Normal 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
97
sys/sys/gpio.h
Normal 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__ */
|
Loading…
Reference in New Issue
Block a user