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
This commit is contained in:
Andriy Gapon 2019-10-25 09:37:54 +00:00
parent 8c017db747
commit ab0a202863

@ -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