summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2006-01-14 12:54:51 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2006-01-14 12:54:51 +0000
commit302aae9118e574b766cb84bfb85cb1551056f297 (patch)
tree9e93378b2192702784b8d46eb3f2c64523308bc0
parent6853f9a1e6456e59edad87964e51b253a552b6bb (diff)
Some improvements:
- use gpio_pin_caps() while configuring pins - try to deal not only with open-drain outputs
-rw-r--r--sys/dev/gpio/gpioiic.c64
1 files changed, 59 insertions, 5 deletions
diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c
index a6ce1a4c783..1e7fc21983a 100644
--- a/sys/dev/gpio/gpioiic.c
+++ b/sys/dev/gpio/gpioiic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gpioiic.c,v 1.1 2006/01/14 00:14:21 grange Exp $ */
+/* $OpenBSD: gpioiic.c,v 1.2 2006/01/14 12:54:50 grange Exp $ */
/*
* Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
@@ -46,6 +46,9 @@ struct gpioiic_softc {
struct i2c_controller sc_i2c_tag;
struct lock sc_i2c_lock;
+
+ int sc_sda;
+ int sc_scl;
};
int gpioiic_match(struct device *, void *, void *);
@@ -97,12 +100,15 @@ gpioiic_attach(struct device *parent, struct device *self, void *aux)
struct gpioiic_softc *sc = (struct gpioiic_softc *)self;
struct gpio_attach_args *ga = aux;
struct i2cbus_attach_args iba;
+ int caps;
+ /* Check that we have enough pins */
if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) {
printf(": invalid pin mask\n");
return;
}
+ /* Map pins */
sc->sc_gpio = ga->ga_gpio;
sc->sc_map.pm_map = sc->__map;
if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
@@ -111,10 +117,44 @@ gpioiic_attach(struct device *parent, struct device *self, void *aux)
return;
}
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
- GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | GPIO_PIN_PULLUP);
- gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL,
- GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | GPIO_PIN_PULLUP);
+ /* Configure SDA pin */
+ caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA);
+ if (!(caps & GPIO_PIN_OUTPUT)) {
+ printf(": SDA pin is unable to drive output\n");
+ goto fail;
+ }
+ printf(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]);
+ sc->sc_sda = GPIO_PIN_OUTPUT;
+ if (caps & GPIO_PIN_OPENDRAIN) {
+ printf(" open-drain");
+ sc->sc_sda |= GPIO_PIN_OPENDRAIN;
+ if (caps & GPIO_PIN_PULLUP) {
+ printf(" pull-up");
+ sc->sc_sda |= GPIO_PIN_PULLUP;
+ }
+ }
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda);
+
+ /* Configure SCL pin */
+ caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_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]);
+ sc->sc_scl = GPIO_PIN_OUTPUT;
+ if (caps & GPIO_PIN_OPENDRAIN) {
+ printf(" open-drain");
+ sc->sc_scl |= GPIO_PIN_OPENDRAIN;
+ if (caps & GPIO_PIN_PULLUP) {
+ printf(" pull-up");
+ sc->sc_scl |= GPIO_PIN_PULLUP;
+ }
+ } else if (caps & GPIO_PIN_PUSHPULL) {
+ printf(" push-pull");
+ sc->sc_scl |= GPIO_PIN_PUSHPULL;
+ }
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl);
printf("\n");
@@ -133,6 +173,11 @@ gpioiic_attach(struct device *parent, struct device *self, void *aux)
iba.iba_name = "iic";
iba.iba_tag = &sc->sc_i2c_tag;
config_found(self, &iba, iicbus_print);
+
+ return;
+
+fail:
+ gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
}
int
@@ -201,6 +246,15 @@ gpioiic_bb_set_bits(void *cookie, u_int32_t bits)
void
gpioiic_bb_set_dir(void *cookie, u_int32_t bits)
{
+ struct gpioiic_softc *sc = cookie;
+
+ if (!(sc->sc_sda & GPIO_PIN_OPENDRAIN)) {
+ sc->sc_sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
+ sc->sc_sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT :
+ GPIO_PIN_INPUT);
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
+ sc->sc_sda);
+ }
}
u_int32_t