Pin order on gpioiic(4)

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Pin order on gpioiic(4)

Matt Dainty
Hi,

I sent some patches at the end of June to get the temperature sensor
working on my Soekris net4826 and after a bit of discussion with Theo,
most of the pieces are now in CVS.

The only part missing is some way to allow gpioiic(4) to assign the SDA
and SCL pins in reverse to match the hardware, (currently it assumes of
the two pins that SDA is the lowest-numbered one, not true here).

Find attached is a patch to gpioiic(4) that adds a flag to allow the
order to be reversed. So for my net4826 kernel, I have the following
config:

gpioiic0 at gpio0 offset 12 mask 0x3 flags 0x0001

which with the patched kernel, produces the following dmesg:

gpio0 at gscpcib0: 64 pins
gpioiic0 at gpio0 pins 12 13 (reversed): SDA[13] open-drain pull-up, SCL[12] open-drain pull-up
iic0 at gpioiic0
lmtemp0 at iic0 addr 0x48: lm75a

I spoke to grange@ about this problem a few weeks ago, where he
mentioned having an idea to fix this, but I haven't heard anything, so I
figured I'd send the patch I had, which is better than my previous fix
of just hardcoding the pin order!

Comments appreciated. It would be really great to get this all fixed for
the 4.0 release.

Matt

--- sys/dev/gpio/gpioiic.c.orig Wed Oct  5 05:43:27 2005
+++ sys/dev/gpio/gpioiic.c Mon Oct 10 15:28:47 2005
@@ -30,8 +30,8 @@
 #include <dev/i2c/i2cvar.h>
 #include <dev/i2c/i2c_bitbang.h>
 
-#define GPIOIIC_PIN_SDA 0
-#define GPIOIIC_PIN_SCL 1
+#define GPIOIIC_CFFLAGS_PIN_REVERSE 0x0001
+
 #define GPIOIIC_NPINS 2
 
 #define GPIOIIC_SDA 0x01
@@ -49,6 +49,9 @@
 
  int sc_sda;
  int sc_scl;
+
+ int sc_pin_sda;
+ int sc_pin_scl;
 };
 
 int gpioiic_match(struct device *, void *, void *);
@@ -116,8 +119,18 @@
  return;
  }
 
+ /* Reverse pin order if necessary */
+ if (sc->sc_dev.dv_cfdata->cf_flags & GPIOIIC_CFFLAGS_PIN_REVERSE) {
+ printf(" (reversed)");
+ sc->sc_pin_sda = 1;
+ sc->sc_pin_scl = 0;
+ } else {
+ sc->sc_pin_sda = 0;
+ sc->sc_pin_scl = 1;
+ }
+
  /* Configure SDA pin */
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA);
+ caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda);
  if (!(caps & GPIO_PIN_OUTPUT)) {
  printf(": SDA pin is unable to drive output\n");
  goto fail;
@@ -126,7 +139,7 @@
  printf(": SDA pin is unable to read input\n");
  goto fail;
  }
- printf(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]);
+ printf(": SDA[%d]", sc->sc_map.pm_map[sc->sc_pin_sda]);
  sc->sc_sda = GPIO_PIN_OUTPUT;
  if (caps & GPIO_PIN_OPENDRAIN) {
  printf(" open-drain");
@@ -139,15 +152,15 @@
  printf(" pull-up");
  sc->sc_sda |= GPIO_PIN_PULLUP;
  }
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda);
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda, sc->sc_sda);
 
  /* Configure SCL pin */
- caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL);
+ caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl);
  if (!(caps & GPIO_PIN_OUTPUT)) {
  printf(": SCL pin is unable to drive output\n");
  goto fail;
  }
- printf(", SCL[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SCL]);
+ printf(", SCL[%d]", sc->sc_map.pm_map[sc->sc_pin_scl]);
  sc->sc_scl = GPIO_PIN_OUTPUT;
  if (caps & GPIO_PIN_OPENDRAIN) {
  printf(" open-drain");
@@ -160,7 +173,7 @@
  printf(" push-pull");
  sc->sc_scl |= GPIO_PIN_PUSHPULL;
  }
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl);
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl, sc->sc_scl);
 
  printf("\n");
 
@@ -249,9 +262,9 @@
 {
  struct gpioiic_softc *sc = cookie;
 
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda,
     bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
- gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL,
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl,
     bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
 }
 
@@ -267,7 +280,7 @@
  sda |= GPIO_PIN_TRISTATE;
  if (sc->sc_sda != sda) {
  sc->sc_sda = sda;
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda,
     sc->sc_sda);
  }
 }
@@ -278,5 +291,5 @@
  struct gpioiic_softc *sc = cookie;
 
  return (gpio_pin_read(sc->sc_gpio, &sc->sc_map,
-    GPIOIIC_PIN_SDA) == GPIO_PIN_HIGH ? GPIOIIC_SDA : 0);
+    sc->sc_pin_sda) == GPIO_PIN_HIGH ? GPIOIIC_SDA : 0);
 }
--- share/man/man4/gpioiic.4.orig Mon Oct 10 15:35:03 2005
+++ share/man/man4/gpioiic.4 Mon Oct 10 15:44:36 2005
@@ -14,21 +14,23 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd January 14, 2006
+.Dd August 19, 2006
 .Dt GPIOIIC 4
 .Os
 .Sh NAME
 .Nm gpioiic
 .Nd I2C bus bit-banging through GPIO pins
 .Sh SYNOPSIS
-.Cd "gpioiic* at gpio? offset 0 mask 0x3"
+.Cd "gpioiic* at gpio? offset 0 mask 0x3 flags 0x0000"
 .Cd "iic* at gpioiic?"
 .Sh DESCRIPTION
 The
 .Nm
 driver allows bit-banging an I2C bus as a master using two GPIO pins.
 The first pin is used as a serial data (SDA) signal and the second as
-a serial clock (SCL).
+a serial clock (SCL), unless the value 0x0001 is passed in the
+.Ar flags
+in which case the order is reversed.
 Both GPIO pins must be able to drive an output and the SDA pin must be
 also able to read an input.
 .Pp