Author: thompsa
Date: Wed Oct 12 20:57:21 2011
New Revision: 226324
URL: http://svn.freebsd.org/changeset/base/226324

Log:
  Dont just set the pin high when turning on output, use the current value. Also
  let this value be set when in input mode.

Modified:
  head/sys/arm/xscale/ixp425/cambria_gpio.c

Modified: head/sys/arm/xscale/ixp425/cambria_gpio.c
==============================================================================
--- head/sys/arm/xscale/ixp425/cambria_gpio.c   Wed Oct 12 20:40:25 2011        
(r226323)
+++ head/sys/arm/xscale/ixp425/cambria_gpio.c   Wed Oct 12 20:57:21 2011        
(r226324)
@@ -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, 
 {
        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, 
        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, uint3
 {
        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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to