diff options
author | Alexander Yurchenko <grange@cvs.openbsd.org> | 2004-06-03 18:08:01 +0000 |
---|---|---|
committer | Alexander Yurchenko <grange@cvs.openbsd.org> | 2004-06-03 18:08:01 +0000 |
commit | 0818616dddb5e4e298d485cef38fb1162b73e613 (patch) | |
tree | 217ae3c95aa0cab46986f8020c655154e2f63d07 /sys | |
parent | edf2b906003db25fa338c7290a3c9af35ad157f1 (diff) |
A framework for supporting various General Purpose Input/Output (GPIO)
devices. Such devices provide a set of pins that you can use to connect
for example leds to it.
The pins can be accessed either from userland through the /dev/gpio*
device files or from the kernel drivers. The latter is necessary
for implementing timing-sensitive things like i2c or 1-wire master
controller.
ok deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/files | 3 | ||||
-rw-r--r-- | sys/dev/gpio/files.gpio | 7 | ||||
-rw-r--r-- | sys/dev/gpio/gpio.c | 241 | ||||
-rw-r--r-- | sys/dev/gpio/gpiovar.h | 63 | ||||
-rw-r--r-- | sys/sys/conf.h | 10 | ||||
-rw-r--r-- | sys/sys/gpio.h | 58 |
6 files changed, 380 insertions, 2 deletions
diff --git a/sys/conf/files b/sys/conf/files index d4dffc50925..bd6406e43a2 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.302 2004/05/30 08:11:26 grange Exp $ +# $OpenBSD: files,v 1.303 2004/06/03 18:07:59 grange Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -17,6 +17,7 @@ define midibus { } define midisyn define radiobus {} define i2cbus {} +define gpiobus {} # audio device attributes define mulaw diff --git a/sys/dev/gpio/files.gpio b/sys/dev/gpio/files.gpio new file mode 100644 index 00000000000..8f79dfd9170 --- /dev/null +++ b/sys/dev/gpio/files.gpio @@ -0,0 +1,7 @@ +# $OpenBSD: files.gpio,v 1.1 2004/06/03 18:08:00 grange Exp $ + +define gpio { pin, mask } + +device gpio: gpio +attach gpio at gpiobus +file dev/gpio/gpio.c gpio needs-flag diff --git a/sys/dev/gpio/gpio.c b/sys/dev/gpio/gpio.c new file mode 100644 index 00000000000..fa6919745b8 --- /dev/null +++ b/sys/dev/gpio/gpio.c @@ -0,0 +1,241 @@ +/* $OpenBSD: gpio.c,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. + */ + +/* + * General Purpose I/O 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 <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 gpio_match(struct device *, void *, void *); +void gpio_attach(struct device *, struct device *, void *); +int gpio_search(struct device *, void *, void *); +int gpio_print(void *, const char *); + +struct cfattach gpio_ca = { + sizeof (struct gpio_softc), + gpio_match, + gpio_attach +}; + +struct cfdriver gpio_cd = { + NULL, "gpio", DV_DULL +}; + +int +gpio_match(struct device *parent, void *match, void *aux) +{ + struct cfdata *cf = match; + struct gpiobus_attach_args *gba = aux; + + if (strcmp(gba->gba_name, cf->cf_driver->cd_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(gpio_search, self, NULL); +} + +int +gpio_search(struct device *parent, void *arg, void *aux) +{ + struct cfdata *cf = arg; + struct gpio_attach_args ga; + + ga.ga_pin = cf->cf_loc[0]; + ga.ga_mask = cf->cf_loc[1]; + + if (cf->cf_attach->ca_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); +} diff --git a/sys/dev/gpio/gpiovar.h b/sys/dev/gpio/gpiovar.h new file mode 100644 index 00000000000..505f557bc65 --- /dev/null +++ b/sys/dev/gpio/gpiovar.h @@ -0,0 +1,63 @@ +/* $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_ */ diff --git a/sys/sys/conf.h b/sys/sys/conf.h index e85c75f04f1..4707a5c4b26 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.74 2004/05/30 08:11:27 grange Exp $ */ +/* $OpenBSD: conf.h,v 1.75 2004/06/03 18:08:00 grange Exp $ */ /* $NetBSD: conf.h,v 1.33 1996/05/03 20:03:32 christos Exp $ */ /*- @@ -473,6 +473,13 @@ void randomattach(void); (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \ (dev_type_mmap((*))) enodev, D_KQFILTER, dev_init(c,n,kqfilter) } +/* open, close, ioctl */ +#define cdev_gpio_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ + (dev_type_mmap((*))) enodev } + /* symbolic sleep message strings */ extern char devopn[], devio[], devwait[], devin[], devout[]; extern char devioc[], devcls[]; @@ -631,6 +638,7 @@ cdev_decl(uscanner); cdev_decl(urio); cdev_decl(hotplug); +cdev_decl(gpio); #endif diff --git a/sys/sys/gpio.h b/sys/sys/gpio.h new file mode 100644 index 00000000000..dcc38958ecb --- /dev/null +++ b/sys/sys/gpio.h @@ -0,0 +1,58 @@ +/* $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_ */ |