aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2020-07-21 07:35:03 +0000
committerAndriy Gapon <avg@FreeBSD.org>2020-07-21 07:35:03 +0000
commite57f9c8a9f9b9dc233428d2f86d71d9c2e6b62eb (patch)
treed6beb0036795d8e65e652e2a163d11bddcfe4776
parentc4cbf1fbabcb84d9d0a49c2444ed398ed9907df5 (diff)
downloadsrc-e57f9c8a9f9b9dc233428d2f86d71d9c2e6b62eb.tar.gz
src-e57f9c8a9f9b9dc233428d2f86d71d9c2e6b62eb.zip
gpioiic: never drive lines active high
I2C communication is done by a combination of driving a line low or letting it float, so that it is either pulled up or driven low by another party. r355276 besides the stated goal of the change -- using the new GPIO API -- also changed the logic, so that active state is signaled by actively driving a line. That worked with iicbb prior to r362042, but stopped working after that commit on at least some hardware. My guess that the breakage was related to getting an ACK bit. A device expected to be able to drive SDA actively low, but controller was actively driving it high for some time. Anyway, this change seems to fix the problem. Tested using gpioiic on Orange Pi PC Plus with HTU21 sensor. Reported by: Nick Kostirya <nikolay.kostirya@i11.co> Reviewed by: manu MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25684
Notes
Notes: svn path=/head/; revision=363382
-rw-r--r--sys/dev/gpio/gpioiic.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c
index 5216f4e8f8a6..6d62a6d04d95 100644
--- a/sys/dev/gpio/gpioiic.c
+++ b/sys/dev/gpio/gpioiic.c
@@ -191,16 +191,14 @@ static void
gpioiic_setsda(device_t dev, int val)
{
struct gpioiic_softc *sc = device_get_softc(dev);
- int err;
- /*
- * Some controllers cannot set an output value while a pin is in input
- * mode; in that case we set the pin again after changing mode.
- */
- err = gpio_pin_set_active(sc->sdapin, val);
- gpio_pin_setflags(sc->sdapin, GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
- if (err != 0)
- gpio_pin_set_active(sc->sdapin, val);
+ if (val) {
+ gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT);
+ } else {
+ gpio_pin_setflags(sc->sdapin,
+ GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
+ gpio_pin_set_active(sc->sdapin, 0);
+ }
}
static void
@@ -208,8 +206,13 @@ gpioiic_setscl(device_t dev, int val)
{
struct gpioiic_softc *sc = device_get_softc(dev);
- gpio_pin_setflags(sc->sclpin, GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
- gpio_pin_set_active(sc->sclpin, val);
+ if (val) {
+ gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT);
+ } else {
+ gpio_pin_setflags(sc->sclpin,
+ GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
+ gpio_pin_set_active(sc->sclpin, 0);
+ }
}
static int