From ab0a20286314b0d538ff04d14df248f820730024 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Fri, 25 Oct 2019 09:37:54 +0000 Subject: [PATCH] gpioiic: set output after switching to output mode if presetting it failed Some controllers cannot preset future output value while the pin is in input mode. This adds a fallback for those controllers. The new code assumes that a controller reports an error in that case. For example, all hardware supported by nctgpio behaves in that way. This is a temporary measure. In the future we will use GPIO_PIN_PRESET_LOW / GPIO_PIN_PRESET_HIGH to preset the output either in hardware, if supported, or in software (e.g., in gpiobus_pin_setflags). While here, I extracted common functionality of gpioiic_set{sda,scl} and gpioiic_get{sda,scl} to gpioiic_setpin and gpioiic_getpin respectively. MFC after: 2 weeks --- sys/dev/gpio/gpioiic.c | 64 ++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c index cad2e1b5c970..d084af82a90b 100644 --- a/sys/dev/gpio/gpioiic.c +++ b/sys/dev/gpio/gpioiic.c @@ -167,19 +167,34 @@ gpioiic_reset_bus(device_t dev) GPIO_PIN_INPUT); } +static void +gpioiic_setpin(struct gpioiic_softc *sc, int pin, int val) +{ + int err; + + if (val == 0) { + err = GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, pin, 0); + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, pin, + GPIO_PIN_OUTPUT); + + /* + * Some controllers cannot set output value while a pin is in + * input mode. + */ + if (err != 0) + GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, pin, 0); + } else { + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, pin, + GPIO_PIN_INPUT); + } +} + static void gpioiic_setsda(device_t dev, int val) { struct gpioiic_softc *sc = device_get_softc(dev); - if (val == 0) { - GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, sc->sda_pin, 0); - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, - GPIO_PIN_OUTPUT); - } else { - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, - GPIO_PIN_INPUT); - } + gpioiic_setpin(sc, sc->sda_pin, val); } static void @@ -187,40 +202,33 @@ gpioiic_setscl(device_t dev, int val) { struct gpioiic_softc *sc = device_get_softc(dev); - if (val == 0) { - GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, sc->scl_pin, 0); - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, - GPIO_PIN_OUTPUT); - } else { - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, - GPIO_PIN_INPUT); - } + gpioiic_setpin(sc, sc->scl_pin, val); +} + +static int +gpioiic_getpin(struct gpioiic_softc *sc, int pin) +{ + unsigned int val; + + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, pin, GPIO_PIN_INPUT); + GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, pin, &val); + return ((int)val); } static int gpioiic_getscl(device_t dev) { struct gpioiic_softc *sc = device_get_softc(dev); - unsigned int val; - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, - GPIO_PIN_INPUT); - GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, sc->scl_pin, &val); - - return ((int)val); + return (gpioiic_getpin(sc, sc->scl_pin)); } static int gpioiic_getsda(device_t dev) { struct gpioiic_softc *sc = device_get_softc(dev); - unsigned int val; - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, - GPIO_PIN_INPUT); - GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, sc->sda_pin, &val); - - return ((int)val); + return (gpioiic_getpin(sc, sc->sda_pin)); } static int