Import general purpose I/O framework from OpenBSD.

This commit is contained in:
jmcneill 2005-09-27 02:34:02 +00:00
parent 70c1989a17
commit bec79ef231
5 changed files with 416 additions and 2 deletions

7
sys/dev/gpio/files.gpio Normal file
View File

@ -0,0 +1,7 @@
# $NetBSD: files.gpio,v 1.1 2005/09/27 02:34:02 jmcneill Exp $
define gpio {pin, mask}
device gpio: gpio
attach gpio at gpiobus
file dev/gpio/gpio.c gpio needs-flag

284
sys/dev/gpio/gpio.c Normal file
View File

@ -0,0 +1,284 @@
/* $NetBSD: gpio.c,v 1.1 2005/09/27 02:34:02 jmcneill Exp $ */
/* $OpenBSD: gpio.c,v 1.4 2004/11/23 21:18:37 grange Exp $ */
/*
* 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.
*/
/*
* General Purpose Input/Output framework.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/gpio.h>
#include <sys/vnode.h>
#include <dev/gpio/gpiovar.h>
struct gpio_softc {
struct device sc_dev;
gpio_chipset_tag_t sc_gc; /* our GPIO controller */
gpio_pin_t *sc_pins; /* pins array */
int sc_npins; /* total number of pins */
int sc_opened;
int sc_dying;
};
int gpio_match(struct device *, struct cfdata *, void *);
void gpio_attach(struct device *, struct device *, void *);
int gpio_detach(struct device *, int);
int gpio_activate(struct device *, enum devact);
int gpio_search(struct device *, struct cfdata *, const int *, void *);
int gpio_print(void *, const char *);
CFATTACH_DECL(gpio, sizeof(struct gpio_softc),
gpio_match, gpio_attach, gpio_detach, gpio_activate);
dev_type_open(gpioopen);
dev_type_close(gpioclose);
dev_type_ioctl(gpioioctl);
const struct cdevsw gpio_cdevsw = {
gpioopen, gpioclose, noread, nowrite, gpioioctl,
nostop, notty, nopoll, nommap, nokqfilter,
};
extern struct cfdriver gpio_cd;
int
gpio_match(struct device *parent, struct cfdata *cf, void *aux)
{
struct gpiobus_attach_args *gba = aux;
if (strcmp(gba->gba_name, cf->cf_name) != 0)
return (0);
return (1);
}
void
gpio_attach(struct device *parent, struct device *self, void *aux)
{
struct gpio_softc *sc = (struct gpio_softc *)self;
struct gpiobus_attach_args *gba = aux;
sc->sc_gc = gba->gba_gc;
sc->sc_pins = gba->gba_pins;
sc->sc_npins = gba->gba_npins;
printf(": %d pins\n", sc->sc_npins);
/*
* Attach all devices that can be connected to the GPIO pins
* described in the kernel configuration file.
*/
config_search_ia(gpio_search, self, "gpio", NULL);
}
int
gpio_detach(struct device *self, int flags)
{
#if 0
int maj, mn;
/* Locate the major number */
for (maj = 0; maj < nchrdev; maj++)
if (cdevsw[maj].d_open == gpioopen)
break;
/* Nuke the vnodes for any open instances (calls close) */
mn = self->dv_unit;
vdevgone(maj, mn, mn, VCHR);
#endif
return (0);
}
int
gpio_activate(struct device *self, enum devact act)
{
struct gpio_softc *sc = (struct gpio_softc *)self;
switch (act) {
case DVACT_ACTIVATE:
return (EOPNOTSUPP);
case DVACT_DEACTIVATE:
sc->sc_dying = 1;
break;
}
return (0);
}
int
gpio_search(struct device *parent, struct cfdata *cf,
const int *ldesc, void *aux)
{
struct gpio_attach_args ga;
ga.ga_pin = cf->cf_loc[0];
ga.ga_mask = cf->cf_loc[1];
if (config_match(parent, cf, &ga) > 0)
config_attach(parent, cf, &ga, gpio_print);
return (0);
}
int
gpio_print(void *aux, const char *pnp)
{
struct gpio_attach_args *ga = aux;
int i;
printf(" pins");
for (i = 0; i < 32; i++)
if (ga->ga_mask & (1 << i))
printf(" %d", ga->ga_pin + i);
return (UNCONF);
}
int
gpiobus_print(void *aux, const char *pnp)
{
struct gpiobus_attach_args *gba = aux;
if (pnp != NULL)
printf("%s at %s", gba->gba_name, pnp);
return (UNCONF);
}
int
gpioopen(dev_t dev, int flag, int mode, struct proc *p)
{
struct gpio_softc *sc;
sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
if (sc == NULL)
return (ENXIO);
if (sc->sc_opened)
return (EBUSY);
sc->sc_opened = 1;
return (0);
}
int
gpioclose(dev_t dev, int flag, int mode, struct proc *p)
{
struct gpio_softc *sc;
sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
sc->sc_opened = 0;
return (0);
}
int
gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
struct gpio_softc *sc;
gpio_chipset_tag_t gc;
struct gpio_info *info;
struct gpio_pin_op *op;
struct gpio_pin_ctl *ctl;
int pin, value, flags;
sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
gc = sc->sc_gc;
switch (cmd) {
case GPIOINFO:
info = (struct gpio_info *)data;
info->gpio_npins = sc->sc_npins;
break;
case GPIOPINREAD:
op = (struct gpio_pin_op *)data;
pin = op->gp_pin;
if (pin < 0 || pin >= sc->sc_npins)
return (EINVAL);
/* return read value */
op->gp_value = gpiobus_pin_read(gc, pin);
break;
case GPIOPINWRITE:
op = (struct gpio_pin_op *)data;
pin = op->gp_pin;
if (pin < 0 || pin >= sc->sc_npins)
return (EINVAL);
value = op->gp_value;
if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
return (EINVAL);
gpiobus_pin_write(gc, pin, value);
/* return old value */
op->gp_value = sc->sc_pins[pin].pin_state;
/* update current value */
sc->sc_pins[pin].pin_state = value;
break;
case GPIOPINTOGGLE:
op = (struct gpio_pin_op *)data;
pin = op->gp_pin;
if (pin < 0 || pin >= sc->sc_npins)
return (EINVAL);
value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
GPIO_PIN_HIGH : GPIO_PIN_LOW);
gpiobus_pin_write(gc, pin, value);
/* return old value */
op->gp_value = sc->sc_pins[pin].pin_state;
/* update current value */
sc->sc_pins[pin].pin_state = value;
break;
case GPIOPINCTL:
ctl = (struct gpio_pin_ctl *)data;
pin = ctl->gp_pin;
if (pin < 0 || pin >= sc->sc_npins)
return (EINVAL);
flags = ctl->gp_flags;
/* check that the controller supports all requested flags */
if ((flags & sc->sc_pins[pin].pin_caps) != flags)
return (ENODEV);
ctl->gp_caps = sc->sc_pins[pin].pin_caps;
/* return old value */
ctl->gp_flags = sc->sc_pins[pin].pin_flags;
if (flags > 0) {
gpiobus_pin_ctl(gc, pin, flags);
/* update current value */
sc->sc_pins[pin].pin_flags = flags;
}
break;
default:
return (ENOTTY);
}
return (0);
}

64
sys/dev/gpio/gpiovar.h Normal file
View File

@ -0,0 +1,64 @@
/* $NetBSD: gpiovar.h,v 1.1 2005/09/27 02:34:02 jmcneill Exp $ */
/* $OpenBSD: gpiovar.h,v 1.1 2004/06/03 18:08:00 grange Exp $ */
/*
* 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 _DEV_GPIO_GPIOVAR_H_
#define _DEV_GPIO_GPIOVAR_H_
/* GPIO controller description */
typedef struct gpio_chipset_tag {
void *gp_cookie;
int (*gp_pin_read)(void *, int);
void (*gp_pin_write)(void *, int, int);
void (*gp_pin_ctl)(void *, int, int);
} *gpio_chipset_tag_t;
/* GPIO pin description */
typedef struct gpio_pin {
int pin_num; /* number */
int pin_caps; /* capabilities */
int pin_flags; /* current configuration */
int pin_state; /* current state */
} gpio_pin_t;
/* Attach GPIO framework to the controller */
struct gpiobus_attach_args {
const char *gba_name; /* bus name */
gpio_chipset_tag_t gba_gc; /* underlying controller */
gpio_pin_t *gba_pins; /* pins array */
int gba_npins; /* total number of pins */
};
int gpiobus_print(void *, const char *);
/* GPIO framework private methods */
#define gpiobus_pin_read(gc, pin) \
((gc)->gp_pin_read((gc)->gp_cookie, (pin)))
#define gpiobus_pin_write(gc, pin, value) \
((gc)->gp_pin_write((gc)->gp_cookie, (pin), (value)))
#define gpiobus_pin_ctl(gc, pin, flags) \
((gc)->gp_pin_ctl((gc)->gp_cookie, (pin), (flags)))
/* Attach devices connected to the GPIO pins */
struct gpio_attach_args {
int ga_pin;
u_int32_t ga_mask;
};
#endif /* !_DEV_GPIO_GPIOVAR_H_ */

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.75 2005/09/19 03:15:22 simonb Exp $
# $NetBSD: Makefile,v 1.76 2005/09/27 02:35:09 jmcneill Exp $
INCSDIR= /usr/include/sys
@ -11,7 +11,7 @@ INCS= acct.h agpio.h ansi.h ataio.h audioio.h \
endian.h envsys.h errno.h event.h exec.h exec_aout.h \
exec_coff.h exec_ecoff.h exec_elf.h exec_script.h extattr.h extent.h \
fcntl.h fd_set.h fdio.h featuretest.h file.h filedesc.h filio.h \
float_ieee754.h fstypes.h gmon.h hash.h \
float_ieee754.h fstypes.h gmon.h gpio.h hash.h \
ieee754.h inttypes.h ioccom.h ioctl.h ioctl_compat.h ipc.h \
joystick.h \
kcore.h kgdb.h ksem.h ksyms.h ktrace.h \

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

@ -0,0 +1,59 @@
/* $NetBSD: gpio.h,v 1.1 2005/09/27 02:35:09 jmcneill Exp $ */
/* $OpenBSD: gpio.h,v 1.1 2004/06/03 18:08:00 grange Exp $ */
/*
* 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 _SYS_GPIO_H_
#define _SYS_GPIO_H_
/* GPIO pin states */
#define GPIO_PIN_LOW 0x00 /* low level (logical 0) */
#define GPIO_PIN_HIGH 0x01 /* high level (logical 1) */
/* GPIO pin configuration flags */
#define GPIO_PIN_INPUT 0x0001 /* input direction */
#define GPIO_PIN_OUTPUT 0x0002 /* output direction */
#define GPIO_PIN_INOUT 0x0004 /* bi-directional */
#define GPIO_PIN_OPENDRAIN 0x0008 /* open-drain output */
#define GPIO_PIN_PUSHPULL 0x0010 /* push-pull output */
#define GPIO_PIN_TRISTATE 0x0020 /* output disabled */
#define GPIO_PIN_PULLUP 0x0040 /* internal pull-up enabled */
/* GPIO controller description */
struct gpio_info {
int gpio_npins; /* total number of pins available */
};
/* GPIO pin operation (read/write/toggle) */
struct gpio_pin_op {
int gp_pin; /* pin number */
int gp_value; /* value */
};
/* GPIO pin control */
struct gpio_pin_ctl {
int gp_pin; /* pin number */
int gp_caps; /* pin capabilities (read-only) */
int gp_flags; /* pin configuration flags */
};
#define GPIOINFO _IOR('G', 0, struct gpio_info)
#define GPIOPINREAD _IOWR('G', 1, struct gpio_pin_op)
#define GPIOPINWRITE _IOWR('G', 2, struct gpio_pin_op)
#define GPIOPINTOGGLE _IOWR('G', 3, struct gpio_pin_op)
#define GPIOPINCTL _IOWR('G', 4, struct gpio_pin_ctl)
#endif /* !_SYS_GPIO_H_ */