summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2004-06-03 18:08:01 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2004-06-03 18:08:01 +0000
commit0818616dddb5e4e298d485cef38fb1162b73e613 (patch)
tree217ae3c95aa0cab46986f8020c655154e2f63d07
parentedf2b906003db25fa338c7290a3c9af35ad157f1 (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@
-rw-r--r--sys/conf/files3
-rw-r--r--sys/dev/gpio/files.gpio7
-rw-r--r--sys/dev/gpio/gpio.c241
-rw-r--r--sys/dev/gpio/gpiovar.h63
-rw-r--r--sys/sys/conf.h10
-rw-r--r--sys/sys/gpio.h58
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_ */