diff options
author | thompsa <thompsa@FreeBSD.org> | 2011-10-12 20:57:21 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2011-10-12 20:57:21 +0000 |
commit | 8d39d95b857991dda0a3ca7e4d7c2b5d2d5ff351 (patch) | |
tree | 34116d4c20c8127786f54dcdc2c5bc3234d9c1d3 /sys/arm/xscale/ixp425 | |
parent | 71169bb7fda87280e5687a6117f4977cfa5b67db (diff) | |
download | FreeBSD-src-8d39d95b857991dda0a3ca7e4d7c2b5d2d5ff351.zip FreeBSD-src-8d39d95b857991dda0a3ca7e4d7c2b5d2d5ff351.tar.gz |
Dont just set the pin high when turning on output, use the current value. Also
let this value be set when in input mode.
Diffstat (limited to 'sys/arm/xscale/ixp425')
-rw-r--r-- | sys/arm/xscale/ixp425/cambria_gpio.c | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/sys/arm/xscale/ixp425/cambria_gpio.c b/sys/arm/xscale/ixp425/cambria_gpio.c index 509cdc3..d428383 100644 --- a/sys/arm/xscale/ixp425/cambria_gpio.c +++ b/sys/arm/xscale/ixp425/cambria_gpio.c @@ -84,6 +84,7 @@ struct cambria_gpio_softc { struct mtx sc_mtx; struct gpio_pin sc_pins[GPIO_PINS]; uint8_t sc_latch; + uint8_t sc_val; }; struct cambria_gpio_pin { @@ -309,6 +310,9 @@ cambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct cambria_gpio_softc *sc = device_get_softc(dev); int error; + uint8_t mask; + + mask = 1 << pin; if (pin >= GPIO_PINS) return (EINVAL); @@ -325,7 +329,16 @@ cambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) GPIO_LOCK(sc); sc->sc_pins[pin].gp_flags = flags; - sc->sc_latch |= (1 << pin); + /* + * Writing a logical one sets the signal high and writing a logical + * zero sets the signal low. To configure a digital I/O signal as an + * input, a logical one must first be written to the data bit to + * three-state the associated output. + */ + if (flags & GPIO_PIN_INPUT || sc->sc_val & mask) + sc->sc_latch |= mask; /* input or output & high */ + else + sc->sc_latch &= ~mask; error = cambria_gpio_write(sc); GPIO_UNLOCK(sc); @@ -337,15 +350,28 @@ cambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct cambria_gpio_softc *sc = device_get_softc(dev); int error; + uint8_t mask; - if (pin >= GPIO_PINS || sc->sc_pins[pin].gp_flags != GPIO_PIN_OUTPUT) - return (EINVAL); + mask = 1 << pin; + if (pin >= GPIO_PINS) + return (EINVAL); GPIO_LOCK(sc); if (value) - sc->sc_latch |= (1 << pin); + sc->sc_val |= mask; else - sc->sc_latch &= ~(1 << pin); + sc->sc_val &= ~mask; + + if (sc->sc_pins[pin].gp_flags != GPIO_PIN_OUTPUT) { + /* just save, altering the latch will disable input */ + GPIO_UNLOCK(sc); + return (0); + } + + if (value) + sc->sc_latch |= mask; + else + sc->sc_latch &= ~mask; error = cambria_gpio_write(sc); GPIO_UNLOCK(sc); @@ -375,14 +401,17 @@ static int cambria_gpio_pin_toggle(device_t dev, uint32_t pin) { struct cambria_gpio_softc *sc = device_get_softc(dev); - int error; + int error = 0; - if (pin >= GPIO_PINS || sc->sc_pins[pin].gp_flags != GPIO_PIN_OUTPUT) + if (pin >= GPIO_PINS) return (EINVAL); GPIO_LOCK(sc); - sc->sc_latch ^= (1 << pin); - error = cambria_gpio_write(sc); + sc->sc_val ^= (1 << pin); + if (sc->sc_pins[pin].gp_flags == GPIO_PIN_OUTPUT) { + sc->sc_latch ^= (1 << pin); + error = cambria_gpio_write(sc); + } GPIO_UNLOCK(sc); return (error); |