summaryrefslogtreecommitdiff
path: root/sys/dev/gpio
diff options
context:
space:
mode:
authordyoung <dyoung@NetBSD.org>2007-12-14 01:49:23 +0000
committerdyoung <dyoung@NetBSD.org>2007-12-14 01:49:23 +0000
commit417afa7caaf0629bc3e817aef9fcd6be21b3289b (patch)
tree75a3f9f631e227346d12602c2c6fba50a828cc40 /sys/dev/gpio
parente692a6c76aa4426238cded9ce5682f8289bfb560 (diff)
Bug fix: record the new state (high/low) set by gpio_pin_write().
I don't know why we gpio(4) didn't do that before, but it seems harmless. Add naive power handling: when a gpio(4) instance is resumed, write each pin's configuration flags and output state from the softc to the hardware using gpiobus_pin_ctl() and gpiobus_pin_write(). While suspended, fail every ioctl() except for GPIOINFO with EBUSY.
Diffstat (limited to 'sys/dev/gpio')
-rw-r--r--sys/dev/gpio/gpio.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/sys/dev/gpio/gpio.c b/sys/dev/gpio/gpio.c
index d82e49ea5f2..75ce2a7202d 100644
--- a/sys/dev/gpio/gpio.c
+++ b/sys/dev/gpio/gpio.c
@@ -1,4 +1,4 @@
-/* $NetBSD: gpio.c,v 1.12 2007/03/04 06:01:46 christos Exp $ */
+/* $NetBSD: gpio.c,v 1.13 2007/12/14 01:49:23 dyoung Exp $ */
/* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */
/*
@@ -18,7 +18,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.12 2007/03/04 06:01:46 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.13 2007/12/14 01:49:23 dyoung Exp $");
/*
* General Purpose Input/Output framework.
@@ -49,6 +49,7 @@ struct gpio_softc {
int gpio_match(struct device *, struct cfdata *, void *);
void gpio_attach(struct device *, struct device *, void *);
+bool gpio_resume(device_t);
int gpio_detach(struct device *, int);
int gpio_activate(struct device *, enum devact);
int gpio_search(struct device *, struct cfdata *, const int *, void *);
@@ -76,6 +77,19 @@ gpio_match(struct device *parent, struct cfdata *cf,
return (1);
}
+bool
+gpio_resume(device_t self)
+{
+ struct gpio_softc *sc = device_private(self);
+ int pin;
+
+ for (pin = 0; pin < sc->sc_npins; pin++) {
+ gpiobus_pin_ctl(sc->sc_gc, pin, sc->sc_pins[pin].pin_flags);
+ gpiobus_pin_write(sc->sc_gc, pin, sc->sc_pins[pin].pin_state);
+ }
+ return true;
+}
+
void
gpio_attach(struct device *parent, struct device *self, void *aux)
{
@@ -88,6 +102,9 @@ gpio_attach(struct device *parent, struct device *self, void *aux)
printf(": %d pins\n", sc->sc_npins);
+ if (!pmf_device_register(self, NULL, gpio_resume))
+ aprint_error_dev(self, "couldn't establish power handler\n");
+
/*
* Attach all devices that can be connected to the GPIO pins
* described in the kernel configuration file.
@@ -222,7 +239,8 @@ gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value)
{
struct gpio_softc *sc = gpio;
- return (gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value));
+ gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value);
+ sc->sc_pins[map->pm_map[pin]].pin_state = value;
}
void
@@ -296,6 +314,9 @@ gpioioctl(dev_t dev, u_long cmd, void *data, int flag,
sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
gc = sc->sc_gc;
+ if (cmd != GPIOINFO && !device_is_active(&sc->sc_dev))
+ return EBUSY;
+
switch (cmd) {
case GPIOINFO:
info = (struct gpio_info *)data;