svn commit: r226324 - head/sys/arm/xscale/ixp425
Andrew Thompson
thompsa at FreeBSD.org
Wed Oct 12 20:57:21 UTC 2011
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);
More information about the svn-src-all
mailing list